From fd19c6bf8ec5e31407a4836e303813513462572a Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Sat, 7 Nov 2020 17:18:13 +0100 Subject: [PATCH 001/145] Dana-i BLE5 support --- .../nightscout/androidaps/dana/DanaPump.kt | 8 +- .../DanaRS_Packet_Option_Get_User_Option.kt | 68 +++------- .../DanaRS_Packet_Option_Set_User_Option.kt | 12 +- .../danars/encryption/BleEncryption.java | 12 +- .../danars/encryption/EncryptionType.kt | 7 ++ .../androidaps/danars/services/BLEComm.kt | 116 +++++++++++++++--- .../jniLibs/arm64-v8a/libBleEncryption.so | Bin 22680 -> 22776 bytes .../jniLibs/armeabi-v7a/libBleEncryption.so | Bin 26448 -> 26548 bytes .../src/main/jniLibs/x86/libBleEncryption.so | Bin 22296 -> 22396 bytes .../main/jniLibs/x86_64/libBleEncryption.so | Bin 22944 -> 23048 bytes 10 files changed, 147 insertions(+), 76 deletions(-) create mode 100644 danars/src/main/java/info/nightscout/androidaps/danars/encryption/EncryptionType.kt diff --git a/dana/src/main/java/info/nightscout/androidaps/dana/DanaPump.kt b/dana/src/main/java/info/nightscout/androidaps/dana/DanaPump.kt index 2966a25807..a54bf2756e 100644 --- a/dana/src/main/java/info/nightscout/androidaps/dana/DanaPump.kt +++ b/dana/src/main/java/info/nightscout/androidaps/dana/DanaPump.kt @@ -156,7 +156,7 @@ class DanaPump @Inject constructor( // DanaRS specific var rsPassword = "" - var v3RSPump = false + var ignoreUserPassword = false // true if replaced by enhanced encryption // User settings var timeDisplayType24 = false @@ -169,6 +169,7 @@ class DanaPump @Inject constructor( var lowReservoirRate = 0 var cannulaVolume = 0 var refillAmount = 0 + var target = 0 // mgdl 40~400 mmol 2.2~22 => 220~2200 var userOptionsFrompump: ByteArray? = null var initialBolusAmount = 0.0 @@ -274,7 +275,7 @@ class DanaPump @Inject constructor( get() = password == sp.getInt(R.string.key_danar_password, -2) val isRSPasswordOK: Boolean - get() = rsPassword.equals(sp.getString(R.string.key_danars_password, ""), ignoreCase = true) || v3RSPump + get() = rsPassword.equals(sp.getString(R.string.key_danars_password, ""), ignoreCase = true) || ignoreUserPassword fun reset() { aapsLogger.debug(LTag.PUMP, "DanaRPump reset") @@ -293,7 +294,8 @@ class DanaPump @Inject constructor( if (protocol < 10) "DanaRS" else "DanaRS v3" 0x06 -> "DanaRS Korean" - 0x07 -> "Dana-i" + 0x07 -> "Dana-i (BLE4.2)" + 0x09 -> "Dana-i (BLE5)" else -> "Unknown Dana pump" } diff --git a/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_Option_Get_User_Option.kt b/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_Option_Get_User_Option.kt index d96da176ec..7c2a9fa16d 100644 --- a/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_Option_Get_User_Option.kt +++ b/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_Option_Get_User_Option.kt @@ -18,54 +18,24 @@ class DanaRS_Packet_Option_Get_User_Option( } override fun handleMessage(data: ByteArray) { - var dataIndex = DATA_START - var dataSize = 1 - danaPump.timeDisplayType24 = byteArrayToInt(getBytes(data, dataIndex, dataSize)) == 0 - dataIndex += dataSize - dataSize = 1 - danaPump.buttonScrollOnOff = byteArrayToInt(getBytes(data, dataIndex, dataSize)) == 1 - dataIndex += dataSize - dataSize = 1 - danaPump.beepAndAlarm = byteArrayToInt(getBytes(data, dataIndex, dataSize)) - dataIndex += dataSize - dataSize = 1 - danaPump.lcdOnTimeSec = byteArrayToInt(getBytes(data, dataIndex, dataSize)) - dataIndex += dataSize - dataSize = 1 - danaPump.backlightOnTimeSec = byteArrayToInt(getBytes(data, dataIndex, dataSize)) - dataIndex += dataSize - dataSize = 1 - danaPump.selectedLanguage = byteArrayToInt(getBytes(data, dataIndex, dataSize)) - dataIndex += dataSize - dataSize = 1 - danaPump.units = byteArrayToInt(getBytes(data, dataIndex, dataSize)) - dataIndex += dataSize - dataSize = 1 - danaPump.shutdownHour = byteArrayToInt(getBytes(data, dataIndex, dataSize)) - dataIndex += dataSize - dataSize = 1 - danaPump.lowReservoirRate = byteArrayToInt(getBytes(data, dataIndex, dataSize)) - dataIndex += dataSize - dataSize = 2 - danaPump.cannulaVolume = byteArrayToInt(getBytes(data, dataIndex, dataSize)) - dataIndex += dataSize - dataSize = 2 - danaPump.refillAmount = byteArrayToInt(getBytes(data, dataIndex, dataSize)) - dataIndex += dataSize - dataSize = 1 - val selectableLanguage1 = byteArrayToInt(getBytes(data, dataIndex, dataSize)) - dataIndex += dataSize - dataSize = 1 - val selectableLanguage2 = byteArrayToInt(getBytes(data, dataIndex, dataSize)) - dataIndex += dataSize - dataSize = 1 - val selectableLanguage3 = byteArrayToInt(getBytes(data, dataIndex, dataSize)) - dataIndex += dataSize - dataSize = 1 - val selectableLanguage4 = byteArrayToInt(getBytes(data, dataIndex, dataSize)) - dataIndex += dataSize - dataSize = 1 - val selectableLanguage5 = byteArrayToInt(getBytes(data, dataIndex, dataSize)) + danaPump.timeDisplayType24 = intFromBuff(data, 0, 1) == 0 + danaPump.buttonScrollOnOff = intFromBuff(data, 1, 1) == 1 + danaPump.beepAndAlarm = intFromBuff(data, 2, 1) + danaPump.lcdOnTimeSec = intFromBuff(data, 3, 1) + danaPump.backlightOnTimeSec = intFromBuff(data, 4, 1) + danaPump.selectedLanguage = intFromBuff(data, 5, 1) + danaPump.units = intFromBuff(data, 6, 1) + danaPump.shutdownHour = intFromBuff(data, 7, 1) + danaPump.lowReservoirRate = intFromBuff(data, 8, 1) + danaPump.cannulaVolume = intFromBuff(data, 9, 2) + danaPump.refillAmount = intFromBuff(data, 11, 2) + val selectableLanguage1 = intFromBuff(data, 13, 1) + val selectableLanguage2 = intFromBuff(data, 14, 1) + val selectableLanguage3 = intFromBuff(data, 15, 1) + val selectableLanguage4 = intFromBuff(data, 16, 1) + val selectableLanguage5 = intFromBuff(data, 17, 1) + if (data.size >= 22) // hw 7+ + danaPump.target = intFromBuff(data, 18, 2) // Pump's screen on time can't be less than 5 failed = danaPump.lcdOnTimeSec < 5 aapsLogger.debug(LTag.PUMPCOMM, "timeDisplayType24: " + danaPump.timeDisplayType24) @@ -77,12 +47,14 @@ class DanaRS_Packet_Option_Get_User_Option( aapsLogger.debug(LTag.PUMPCOMM, "Pump units: " + if (danaPump.units == DanaPump.UNITS_MGDL) "MGDL" else "MMOL") aapsLogger.debug(LTag.PUMPCOMM, "shutdownHour: " + danaPump.shutdownHour) aapsLogger.debug(LTag.PUMPCOMM, "lowReservoirRate: " + danaPump.lowReservoirRate) + aapsLogger.debug(LTag.PUMPCOMM, "cannulaVolume: " + danaPump.cannulaVolume) aapsLogger.debug(LTag.PUMPCOMM, "refillAmount: " + danaPump.refillAmount) aapsLogger.debug(LTag.PUMPCOMM, "selectableLanguage1: $selectableLanguage1") aapsLogger.debug(LTag.PUMPCOMM, "selectableLanguage2: $selectableLanguage2") aapsLogger.debug(LTag.PUMPCOMM, "selectableLanguage3: $selectableLanguage3") aapsLogger.debug(LTag.PUMPCOMM, "selectableLanguage4: $selectableLanguage4") aapsLogger.debug(LTag.PUMPCOMM, "selectableLanguage5: $selectableLanguage5") + aapsLogger.debug(LTag.PUMPCOMM, "target: ${if (danaPump.units == DanaPump.UNITS_MGDL) danaPump.target else danaPump.target / 100}") } override fun getFriendlyName(): String { diff --git a/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_Option_Set_User_Option.kt b/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_Option_Set_User_Option.kt index 78db5a28c2..ae2e0c03ef 100644 --- a/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_Option_Set_User_Option.kt +++ b/danars/src/main/java/info/nightscout/androidaps/danars/comm/DanaRS_Packet_Option_Set_User_Option.kt @@ -26,8 +26,12 @@ class DanaRS_Packet_Option_Set_User_Option( + "\nlcdOnTimeSec:" + danaPump.lcdOnTimeSec + "\nbacklight:" + danaPump.backlightOnTimeSec + "\ndanaRPumpUnits:" + danaPump.units - + "\nlowReservoir:" + danaPump.lowReservoirRate) - val request = ByteArray(13) + + "\nlowReservoir:" + danaPump.lowReservoirRate + + "\ncannulaVolume:" + danaPump.cannulaVolume + + "\nrefillAmount:" + danaPump.refillAmount + + "\ntarget:" + danaPump.target) + val size = if (danaPump.hwModel >= 7) 15 else 13 + val request = ByteArray(size) request[0] = if (danaPump.timeDisplayType24) 0.toByte() else 1.toByte() request[1] = if (danaPump.buttonScrollOnOff) 1.toByte() else 0.toByte() request[2] = (danaPump.beepAndAlarm and 0xff).toByte() @@ -41,6 +45,10 @@ class DanaRS_Packet_Option_Set_User_Option( request[10] = (danaPump.cannulaVolume ushr 8 and 0xff).toByte() request[11] = (danaPump.refillAmount and 0xff).toByte() request[12] = (danaPump.refillAmount ushr 8 and 0xff).toByte() + if (danaPump.hwModel >= 7) { + request[13] = (danaPump.target and 0xff).toByte() + request[14] = (danaPump.target ushr 8 and 0xff).toByte() + } return request } diff --git a/danars/src/main/java/info/nightscout/androidaps/danars/encryption/BleEncryption.java b/danars/src/main/java/info/nightscout/androidaps/danars/encryption/BleEncryption.java index 83e8e3ed3f..a3fb39a647 100644 --- a/danars/src/main/java/info/nightscout/androidaps/danars/encryption/BleEncryption.java +++ b/danars/src/main/java/info/nightscout/androidaps/danars/encryption/BleEncryption.java @@ -126,7 +126,9 @@ public class BleEncryption { private static native void setPairingKeysJni(byte[] pairingKey, byte[] randomPairingKey, byte randomSyncKey); - private static native void setEnhancedEncryptionJni(boolean isSecurityVersion); + private static native void setBle5KeyJni(byte[] ble5Key); + + private static native void setEnhancedEncryptionJni(int securityVersion); private static native byte[] encryptSecondLevelPacketJni(Object context, byte[] bytes); @@ -144,8 +146,12 @@ public class BleEncryption { setPairingKeysJni(pairingKey, randomPairingKey, randomSyncKey); } - public void setEnhancedEncryption(boolean isSecureVersion) { - setEnhancedEncryptionJni(isSecureVersion); + public void setBle5Key(byte[] ble5Key) { + setBle5KeyJni(ble5Key); + } + + public void setEnhancedEncryption(EncryptionType securityVersion) { + setEnhancedEncryptionJni(securityVersion.ordinal()); } public byte[] encryptSecondLevelPacket(byte[] bytes) { diff --git a/danars/src/main/java/info/nightscout/androidaps/danars/encryption/EncryptionType.kt b/danars/src/main/java/info/nightscout/androidaps/danars/encryption/EncryptionType.kt new file mode 100644 index 0000000000..a0e5a77882 --- /dev/null +++ b/danars/src/main/java/info/nightscout/androidaps/danars/encryption/EncryptionType.kt @@ -0,0 +1,7 @@ +package info.nightscout.androidaps.danars.encryption + +enum class EncryptionType(val type: Int) { + ENCRYPTION_DEFAULT(0), + ENCRYPTION_RSv3(1), + ENCRYPTION_BLE5(2) +} \ No newline at end of file diff --git a/danars/src/main/java/info/nightscout/androidaps/danars/services/BLEComm.kt b/danars/src/main/java/info/nightscout/androidaps/danars/services/BLEComm.kt index 2b6eb98495..5f4d68d791 100644 --- a/danars/src/main/java/info/nightscout/androidaps/danars/services/BLEComm.kt +++ b/danars/src/main/java/info/nightscout/androidaps/danars/services/BLEComm.kt @@ -15,6 +15,7 @@ import info.nightscout.androidaps.danars.comm.DanaRSMessageHashTable import info.nightscout.androidaps.danars.comm.DanaRS_Packet import info.nightscout.androidaps.danars.comm.DanaRS_Packet_Etc_Keep_Connection import info.nightscout.androidaps.danars.encryption.BleEncryption +import info.nightscout.androidaps.danars.encryption.EncryptionType import info.nightscout.androidaps.danars.events.EventDanaRSPairingSuccess import info.nightscout.androidaps.events.EventPumpStatusChanged import info.nightscout.androidaps.logging.AAPSLogger @@ -56,9 +57,13 @@ class BLEComm @Inject internal constructor( private const val WRITE_DELAY_MILLIS: Long = 50 private const val UART_READ_UUID = "0000fff1-0000-1000-8000-00805f9b34fb" private const val UART_WRITE_UUID = "0000fff2-0000-1000-8000-00805f9b34fb" + private const val UART_BLE5_UUID = "00002902-0000-1000-8000-00805f9b34fb" private const val PACKET_START_BYTE = 0xA5.toByte() private const val PACKET_END_BYTE = 0x5A.toByte() + + private const val BLE5_PACKET_START_BYTE = 0x73.toByte() + private const val BLE5_PACKET_END_BYTE = 0xBF.toByte() } private var scheduledDisconnection: ScheduledFuture<*>? = null @@ -69,7 +74,7 @@ class BLEComm @Inject internal constructor( private var connectDeviceName: String? = null private var bluetoothGatt: BluetoothGatt? = null - private var v3Encryption: Boolean = false + private var encryption: EncryptionType = EncryptionType.ENCRYPTION_DEFAULT set(newValue) { bleEncryption.setEnhancedEncryption(newValue) field = newValue @@ -116,7 +121,7 @@ class BLEComm @Inject internal constructor( return false } isConnected = false - v3Encryption = false + encryption = EncryptionType.ENCRYPTION_DEFAULT encryptedDataRead = false encryptedCommandSent = false isConnecting = true @@ -136,7 +141,7 @@ class BLEComm @Inject internal constructor( fun disconnect(from: String) { aapsLogger.debug(LTag.PUMPBTCOMM, "disconnect from: $from") - if (!encryptedDataRead && encryptedCommandSent && v3Encryption) { + if (!encryptedDataRead && encryptedCommandSent && encryption == EncryptionType.ENCRYPTION_RSv3) { // there was no response from pump after started encryption // assume pairing keys are invalid val lastClearRequest = sp.getLong(R.string.key_rs_last_clear_key_request, 0) @@ -185,8 +190,6 @@ class BLEComm @Inject internal constructor( if (status == BluetoothGatt.GATT_SUCCESS) { findCharacteristic() } - sendConnect() - // 1st message sent to pump after connect } override fun onCharacteristicRead(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) { @@ -204,7 +207,7 @@ class BLEComm @Inject internal constructor( override fun onCharacteristicWrite(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) { // for v3 after initial handshake it's encrypted - useless // aapsLogger.debug(LTag.PUMPBTCOMM, "onCharacteristicWrite: " + DanaRS_Packet.toHexString(characteristic.value)) - Thread(Runnable { + Thread { synchronized(mSendQueue) { // after message sent, check if there is the rest of the message waiting and send it if (mSendQueue.size > 0) { @@ -213,7 +216,14 @@ class BLEComm @Inject internal constructor( writeCharacteristicNoResponse(uartWriteBTGattChar, bytes) } } - }).start() + }.start() + } + + override fun onDescriptorWrite(gatt: BluetoothGatt?, descriptor: BluetoothGattDescriptor?, status: Int) { + super.onDescriptorWrite(gatt, descriptor, status) + //aapsLogger.debug(LTag.PUMPBTCOMM, "onDescriptorWrite " + status) + sendConnect() + // 1st message sent to pump after connect } } @@ -229,6 +239,11 @@ class BLEComm @Inject internal constructor( return } bluetoothGatt?.setCharacteristicNotification(characteristic, enabled) + // Dana-i BLE5 specific + characteristic?.getDescriptor(UUID.fromString(UART_BLE5_UUID))?.let { + it.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE + bluetoothGatt?.writeDescriptor(it) + } } @Synchronized @@ -299,7 +314,7 @@ class BLEComm @Inject internal constructor( close() isConnected = false isConnecting = false - v3Encryption = false + encryption = EncryptionType.ENCRYPTION_DEFAULT encryptedDataRead = false encryptedCommandSent = false rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED)) @@ -331,7 +346,7 @@ class BLEComm @Inject internal constructor( var inputBuffer: ByteArray? = null // decrypt 2nd level after successful connection - val incomingBuffer = if (v3Encryption && isConnected) + val incomingBuffer = if (encryption == EncryptionType.ENCRYPTION_RSv3 && isConnected) bleEncryption.decryptSecondLevelPacket(receivedData).also { encryptedDataRead = true sp.putLong(R.string.key_rs_last_clear_key_request, 0L) @@ -342,7 +357,6 @@ class BLEComm @Inject internal constructor( while (isProcessing) { var length = 0 synchronized(readBuffer) { - // Find packet start [A5 A5] if (bufferLength >= 6) { for (idxStartByte in 0 until bufferLength - 2) { @@ -370,6 +384,36 @@ class BLEComm @Inject internal constructor( packetIsValid = true } } + // packet can be BLE5 encrypted too + if (!packetIsValid && encryption == EncryptionType.ENCRYPTION_BLE5) { + var startIndex: Int = -1 + // Find encrypted packet start [73 73] + if (bufferLength >= 6) { + for (idxStartByte in 0 until bufferLength - 2) { + if (readBuffer[idxStartByte] == BLE5_PACKET_START_BYTE && readBuffer[idxStartByte + 1] == BLE5_PACKET_START_BYTE) { + if (idxStartByte > 0) { + // if buffer doesn't start with signature remove the leading trash + aapsLogger.debug(LTag.PUMPBTCOMM, "Shifting the input buffer by $idxStartByte bytes") + System.arraycopy(readBuffer, idxStartByte, readBuffer, 0, bufferLength - idxStartByte) + bufferLength -= idxStartByte + } + startIndex = idxStartByte + break + } + } + } + // 73 73 ENCRYPTED CONTENT BF BF + if (startIndex != -1) { + for (idxEndByte in 5..bufferLength - 2) { + if (readBuffer[idxEndByte] == BLE5_PACKET_END_BYTE && readBuffer[idxEndByte + 1] == BLE5_PACKET_END_BYTE) { + length = idxEndByte - startIndex + 2 - 7 + packetIsValid = true + encryptedDataRead = true + break + } + } + } + } if (packetIsValid) { inputBuffer = ByteArray(length + 7) // copy packet to input buffer @@ -385,7 +429,11 @@ class BLEComm @Inject internal constructor( // now we have encrypted packet in inputBuffer } } + if (packetIsValid && encryptedDataRead && encryption == EncryptionType.ENCRYPTION_BLE5) { + inputBuffer = bleEncryption.decryptSecondLevelPacket(inputBuffer) + } if (packetIsValid) { + // aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< PROCESSING: " + DanaRS_Packet.toHexString(inputBuffer)) // decrypt the packet bleEncryption.getDecryptedPacket(inputBuffer)?.let { decryptedBuffer -> if (decryptedBuffer[0] == BleEncryption.DANAR_PACKET__TYPE_ENCRYPTION_RESPONSE.toByte()) { @@ -453,8 +501,8 @@ class BLEComm @Inject internal constructor( // response OK v1 if (decryptedBuffer.size == 4 && decryptedBuffer[2] == 'O'.toByte() && decryptedBuffer[3] == 'K'.toByte()) { aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__PUMP_CHECK (OK)" + " " + DanaRS_Packet.toHexString(decryptedBuffer)) - v3Encryption = false - danaPump.v3RSPump = false + encryption = EncryptionType.ENCRYPTION_DEFAULT + danaPump.ignoreUserPassword = false // Grab pairing key from preferences if exists val pairingKey = sp.getString(resourceHelper.gs(R.string.key_danars_pairingkey) + danaRSPlugin.mDeviceName, "") aapsLogger.debug(LTag.PUMPBTCOMM, "Using stored pairing key: $pairingKey") @@ -467,8 +515,8 @@ class BLEComm @Inject internal constructor( // response OK v3 } else if (decryptedBuffer.size == 9 && decryptedBuffer[2] == 'O'.toByte() && decryptedBuffer[3] == 'K'.toByte()) { // v3 2nd layer encryption - v3Encryption = true - danaPump.v3RSPump = true + encryption = EncryptionType.ENCRYPTION_RSv3 + danaPump.ignoreUserPassword = true danaPump.hwModel = decryptedBuffer[5].toInt() danaPump.protocol = decryptedBuffer[7].toInt() // grab randomSyncKey @@ -483,6 +531,21 @@ class BLEComm @Inject internal constructor( // Dana RS Easy sendEasyMenuCheck() } + // response OK BLE5 + } else if (decryptedBuffer.size == 14 && decryptedBuffer[2] == 'O'.toByte() && decryptedBuffer[3] == 'K'.toByte()) { + // v3 2nd layer encryption + encryption = EncryptionType.ENCRYPTION_BLE5 + danaPump.ignoreUserPassword = true + danaPump.hwModel = decryptedBuffer[5].toInt() + danaPump.protocol = decryptedBuffer[7].toInt() + val pairingKey = DanaRS_Packet.asciiStringFromBuff(decryptedBuffer, 8, 6) // used while bonding + + if (danaPump.hwModel == 0x09) { + bleEncryption.setBle5Key(pairingKey.encodeToByteArray()) + aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__PUMP_CHECK BLE5 (OK)" + " " + DanaRS_Packet.toHexString(decryptedBuffer)) + // Dana-i BLE5 Pump + sendBLE5PairingInformation() + } // response PUMP : error status } else if (decryptedBuffer.size == 6 && decryptedBuffer[2] == 'P'.toByte() && decryptedBuffer[3] == 'U'.toByte() && decryptedBuffer[4] == 'M'.toByte() && decryptedBuffer[5] == 'P'.toByte()) { aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__PUMP_CHECK (PUMP)" + " " + DanaRS_Packet.toHexString(decryptedBuffer)) @@ -501,8 +564,8 @@ class BLEComm @Inject internal constructor( aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__PUMP_CHECK (ERROR)" + " " + DanaRS_Packet.toHexString(decryptedBuffer)) mSendQueue.clear() rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED, resourceHelper.gs(R.string.connectionerror))) - sp.remove(resourceHelper.gs(R.string.key_danars_pairingkey) + danaRSPlugin.mDeviceName) - val n = Notification(Notification.WRONGSERIALNUMBER, resourceHelper.gs(R.string.wrongpassword), Notification.URGENT) + danaRSPlugin.clearPairing() + val n = Notification(Notification.WRONGSERIALNUMBER, resourceHelper.gs(R.string.password_cleared), Notification.URGENT) rxBus.send(EventNewNotification(n)) } } @@ -544,6 +607,14 @@ class BLEComm @Inject internal constructor( } } + // 2nd packet BLE5 + private fun sendBLE5PairingInformation() { + val params = ByteArray(4) { 0.toByte() } + val bytes: ByteArray = bleEncryption.getEncryptedPacket(BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__TIME_INFORMATION, params, null) + aapsLogger.debug(LTag.PUMPBTCOMM, ">>>>> " + "ENCRYPTION__TIME_INFORMATION BLE5" + " " + DanaRS_Packet.toHexString(bytes)) + writeCharacteristicNoResponse(uartWriteBTGattChar, bytes) + } + private fun sendV3PairingInformation(requestNewPairing: Int) { val params = byteArrayOf(requestNewPairing.toByte()) val bytes: ByteArray = bleEncryption.getEncryptedPacket(BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__TIME_INFORMATION, params, null) @@ -553,8 +624,12 @@ class BLEComm @Inject internal constructor( // 2nd packet response private fun processEncryptionResponse(decryptedBuffer: ByteArray) { - aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__TIME_INFORMATION " + /*message.getMessageName() + " " + */DanaRS_Packet.toHexString(decryptedBuffer)) - if (v3Encryption) { + aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__TIME_INFORMATION " + DanaRS_Packet.toHexString(decryptedBuffer)) + if (encryption == EncryptionType.ENCRYPTION_BLE5) { + isConnected = true + isConnecting = false + aapsLogger.debug(LTag.PUMPBTCOMM, "Connect !!") + } else if (encryption == EncryptionType.ENCRYPTION_RSv3) { // decryptedBuffer[2] : 0x00 OK 0x01 Error, No pairing if (decryptedBuffer[2] == 0x00.toByte()) { val randomPairingKey = sp.getString(resourceHelper.gs(R.string.key_danars_v3_randompairingkey) + danaRSPlugin.mDeviceName, "") @@ -656,7 +731,7 @@ class BLEComm @Inject internal constructor( isUnitUD = decryptedBuffer[3] == 0x01.toByte() // request time information - if (v3Encryption) sendV3PairingInformation() + if (encryption == EncryptionType.ENCRYPTION_RSv3) sendV3PairingInformation() else sendTimeInfo() } @@ -668,7 +743,8 @@ class BLEComm @Inject internal constructor( val params = message.requestParams aapsLogger.debug(LTag.PUMPBTCOMM, ">>>>> " + message.friendlyName + " " + DanaRS_Packet.toHexString(command) + " " + DanaRS_Packet.toHexString(params)) var bytes = bleEncryption.getEncryptedPacket(message.opCode, params, null) - if (v3Encryption) + // aapsLogger.debug(LTag.PUMPBTCOMM, ">>>>> " + DanaRS_Packet.toHexString(bytes)) + if (encryption != EncryptionType.ENCRYPTION_DEFAULT) bytes = bleEncryption.encryptSecondLevelPacket(bytes) // If there is another message not completely sent, add to queue only if (mSendQueue.size > 0) { diff --git a/danars/src/main/jniLibs/arm64-v8a/libBleEncryption.so b/danars/src/main/jniLibs/arm64-v8a/libBleEncryption.so index c5fddf892520595d9446ce1510db2b6ceee93afd..ce5fff9e71687fb48223208e7022670d9f54989d 100644 GIT binary patch delta 7407 zcmc&(dvsLQx!-3dGt8MhCnV%WX7b`OlaL`KBr|~~lLSLDBF_laDg=m{nSh$EE^DxM zf^oShrAplN!cwZiYcUzb1vj*2SctK?bct0i^s4niEkUgWu%egh90kt(ediHE#C7le z>z=hv_TIn!?QehYz2{`-0U>%o*p_Z%iA;HXYQv)4PLEix4p!E82aCm`7)A!mc-$Uj%^{Pr{v*zgwc z8HO~Q9lZ>K@TB6+=eHV4#T@iv@n-RELt#lCdI@;5@rroqG2%_aYoY-jO(*6+e=^@K zOmyTbxVo1GebR|qp@!A6&Urk|cuPESq!mP)&)bcQV$#d=ZG6x;m+u#1%tjI-ksD&F zgt@#uCQUf3{CysO-AnSpFo}I353a%DG0!vTCu3nlr3xMt)V5s1w@*>Wm(_-)Xnb1u z7cprWm*=SPVQrOVbT-$N7P>S;o!zdjE&d)E%D)GH5oROVULdpMN!NC%L`!%}nTmg` zne|=_2|tyq;J2|sZ9%s|oygI`ph#WE&T06-4^-f=hTo!XoTF{LRl|i*^=#&}&|J-n zACtH7yo8sw-<7Wn*=Dt2pK9W6E>?k4nz(h^?mwwg@d8cSC$!ynR;##0!$&YA{@bQ1 zc!;%3PzmzB$9~H-M$I)U-JsgArD%!K#R3(0PQ&lf=zDxBFsR{=q9ytQjs6VJl%)>`kA zVvo5z;h~iSev#P%wLC8=Kcm(s1!Z|hPhI*0y~|d5`i5>BaN1aVu%53 zql`(~N}rU2u?sx>FY`Ug72;hiLOj;p#ebfam)C1tF(72K_GS>i1V%k|DNv}%(+6Bp zsEWHLl0tV)oG(=I7bi}#2MjEwx9;`<%T31iVJmAQd8dQ_h|%E^1N_WHp1qbu+KQQU zhr-bIK;N<@o^ai=0Y5C%TFjqFA%@3OsvFn(A}z%}sadFgr?+cyv=^r8?OGZ|Jai}N zyO>z}rqpY@IAIwP2Bh8k>XHU}yM7dHFz~Ax_D~NEjjN)f;FFxgwbE`(oiRGXq;3wj zX#PEubYaC!H4&%C+G~s|>(<}|E*;tbUzV z6n$Q&DYIg9ff(=ey0Azg!a~}#w{G!(WePlWmk?>as|NC0T<46eJNP26%FHr{nFN%t z&di&*he^FDol6@8=4~KpK+G?sIzujm$W$in)g(R(1GLr)5n|k0D@16M*7}-AptdGr z5yUpX;hJWF`c0ARg4(49brAGQP*3$qg$Qz;hs8vJFGMcLa+-ochL92_Al!dN-qF0# z(9!zUJZ}IKN|=CQ!!f6)bz^OZg2l6TWsG?X%-k5;xwP@vbPp*5=Izv9gMK06W-a3Q zw9y(4gKrq_yBY3ld$m@gdBQ0=nxAB)(&%JOowVjjpR^7HAHxbnbjBFtYJm_$9K;-D z9ZYLa%g;ctxP;E7!D1m2EUt;1HCkQgVfeNu_>uH9(_>5u7W4Ph9kwk@3d8O}*gXil z1GQ%4hp?gs`ElA97Y@`TtnEx%P6o&{bOg%hfeIF+u(l(9V8K9UZHI!v0LmEi6lZ=I zzzPEeXbb~Te+~NA3}6W_249NbSls}aucY8rEbuVGLZ2i9JPZSXK&c1y$Rh|qbgjTC zk6NGL52s&K{wj+EullYjzmb$T-w)-l`uGRw_T(Rr(;jeaMqUVOM%6Ee`jeP+O8w{>S{1QT2o4)DJ>^5Gd-G zLwyLKs1ICGf1^*LGO{08p=8Q&7U@GhXymyzM_w~VN?afJMU)6PYUemygpZxwOj?glB)@0aut}8tKdz!O6KFQCC4SN1*6m0 zv^hbm_6ex=`5~yNWHDH*B`;PA9j*7*dIP|fEXGz!)>hVZD43qbn7=NIX{={4`q#W@ z4c`vFblNnaz&04zY%=p2(9j7{VmJyfVG}oqbkJ~2#p=gmZ>pG+FPWS|Qj?n%WBS!F zP)a;yfgfRjd6apS0ZX_A%!#fQxDp0y)i59_db{q3HlCRCwlkH=!>TB%^Z8Z-lZKgE zD4PvF>6JQm^2&oXeU}&gp?A=@`kf326_V=&fH8enj6yf=+!rk+Vz1-mCdW@^1!xMedh>=M~EIb`c!mf^5kk6Li)~fTdKIx1RhctvdJpqxD=#z#g z_@oJ-?__NDbR2KJLyiI5{Zd{*+cUJfVBpGw^ZFn}H%WB8Fr9y<+kx{{6aUxjI}LyT zmRs%b8(i`H@Ae;Bw<#_V-~xWY;qcagBb=~JIr-qcP1-r4U;!LRjFpj@^f9GrjR4co zYQEJ`;LX)%;aW=S|0{Hpo-&^N+fOgbhe!?*sSF_I?rGl$JH|G_> zaOj)c|3>!?%~oDx9|XWPJK#vh##GL zw@}tUV_Jc56XtMdzwVyr#CmvgTh5!KSCnlc?u9M^R}0{USVISs1(+3Akm+yof0ZACIWt3>l2kV-vYG~QnPTn3i7KYM zgRnK)m4-0ONz^J$W@Y@gPkN21R;96iPsC3MC8Qg*dn1Lz-5RD{0!!P6wK!22z4yOi z#1mYuS*ynJR+b|~bf3JY-QsuXwmiy%t~tU{zQ^UrM%d_d`fa~Mr#r^afbJN#7dmX9 zqbTri$XM#42sp+U7H0C6!bcnhAeW6)n~Z%|h8X>dJyE+$?8Z;16YJg;`Gg`Vn?$lA zU;QxOtCKY|qb7+0%*@3ZhlP{;k24&G;d=h*jN)tu0(>!)EmwKD26pPR!mR`#>X3%oT7Uts4D3p#7ksx~Pt4sop1fgjIG@%TSrBOR{6Y|88v}(N9cv7n_Y`fIysRiY zrgQ;t`c z^(E=EUeCHFnqKiCzaq~qLu`>D-saDi6vAl7OY-se%aUrcw=0$Zd{zcu zG|Q}vZ2ZGn4%mF-EX5lxQJ)2Nyd=*cp5#|&P0P?c{Q|bw5LoXC<2O?YMV**32!dz@yr}2wLUo- zl|K|pc55|D!A!_zV7#-e#L>t~^g>B<6r)r;#bYBLC+7HxvY9a?5ygs-$ZZvK_|Dn! z@Z6r+N*(y1Vn&{lj4;7@Tut`XJu|KlAhkq(q+$~9sYtggq^JnvNVST<4^?CmnS<)J z6(!*;IPL|=vWvQ(qQ_1*LZO05q zdZ;1`f8VJnRc1(*G`)0<6GJIo&Xc^>Q))*zj%d3Vsk^tiu=_cq&uhij+~YNrUgF0+ zY1U2VZYy%ZzuU||_q6BaU6Oa0VX?E%_`D);=dihZI%@IR|H4(EYju=&W={?&6R(=P z{rIgJ3!*k5raKPpR@8&BH^qJM$v)f&_u&hLeq%g?tLsQ2ekUN6&*N5j!HC-=Zir`b zJH$sZd=}CUfmd1kKalqRhZ3>~bHhcS1M>@sq1X`=PUk~DP8J9V;xFmc7{OJOPK`Ja zZ$YU0i5QD%{5YJZEsni_wOg@vy%6`yEm-HmL9VPpf?l@<9=!1yCl=v!Cv%Lwu3G5W z)l8oO zybS#Y1-`I)(!#?S?t+?|(Xx37In>}oEPD%Y+-cQ3z)@dRoXj)`T=~SS(N6|O1!BQ4 z4_4Vt(_x(!{;R4i!}<{(uCkj?kI3>V6F**+Y2NiYv@r31RAm~P|H-Y@cEhEwxU1T3 z+7^}N!;1JZ(7yF2Hc+H?oYY&*(z}&IO*sH&stGHKF$!^~Ck)-FF$j>;GMK z*MyM%0a*XI-yAolPs?NHKN>g2N1^NHquN;ed~alPV)&t3s!A*x zu6?Fwi?z?}s1V9?QJY7&D^C-5E?ktn619LHjhH3H@huA%3K#i%3mw99Tv`|koyN6? zp8uz||LaAf(7f(vKYj4awtJ7x6z(p(`j@@;ufMNh@s-aa@2^U&U-A5}e)GsnSNPQO z>aX7@`|T%Rw7*-DI{%Bz_H5_TU)=lB+JtcWku0&RC^PGx+j^GHd8gm`k^7NlCwo52 zxqRS9!9N}G`WLMHkN(Sx-xc_~OPhsL+`G(e)2*quAM*~Nx()TVnMZ)?me$)QE-iD5 z&!O7V^Bh0Wl*SvHa>R=oa*?+;RalcW%fsUT)>LlQ9kDWwf7w(njvAYn+**;W$ClnM zDCHY(Ew(MFRkzUFY96`OZTrrD3%LZ;SEthIZ726GpDEs?f`d2p|9Cn64bj3QE8Mo$ gH7eS&L~U1cX+;I*N>)}|Gw8oCc>c=xH_Pn*4Xq%&bpQYW delta 6012 zcmc&&YjjiBl|EOpgsy~*8(jvt^X+@D zjPXq7@7%Sn_SxUrXPUL zhX(ts%hd9zNy%Npyn>%CRpIIKmEXfG#n0%M8ujS2CyA#d)EoY!V=RSS z2|M|kgiK)re=MPV&A*}7WcDBO>MpdK^1O(03L1A-so>89RaR^G?}}9Yx+>VOG(U_B zhRm$A8WldNwR&r^w$hLpyfR;{eMW0L{xvaN{2IIyIK}pTVj9nEtrr(0;a4hDd@u2Y zXBS?==jM~fHnLM%gGQnR6=~YcyOnyzp4agA94c^9!(|P>KxE?ytAY(r4zIwN89b>a zV~Hl;gcbF2p+Gh7(^~ye3%6&13T)THZHf=isp2Lr+DlN$&&P9BJZ*+5KfIl$po-$x zq&aG@RiRT_O&cURaulh+%Nm}q*+1h_fm0g(T}ZOuUZ?_RG~A)tzf5_Dr$-5N*gK<7 zH$2z;D}i6Jm|FfGMwHd`Y)z!x)-gdFspFdp%=DVxA794PaAdG+rd`P6-4R zgj*UKJrupH7ws0m-{DDTR-e}`Sx(y>k zL!%p`rB=2(;N|C%YlSCxw)M^|wCog?eH7`vCl=|=jYaeuV;uqueXir*vF4!nA6WnS zjwjtxcMFqtG%!gN*c%`yt(En(jq6SJ6!xTSpPcKGl-$>*ikh!3$5^0DKHIu%nIJE8?TD!&(Xi`l@?grN0eV7mur-Rh+j%!q<8LcI+&CiCa4#rermiXq&%I%>LuS;P9|Xjs2G zdI|hp*0WIH1dn9o%y^wigz_^P1*tzlIjyIyRbb9m19KAobY^LA5hkIGN!>cNyRd$9 zOcdNw=|qDx*!zvxxZW1&v};pf2eFvg&Ipry5w~O(+)m#j$aLoPm$@ao$ec=0aINqQ z><>5OXFHGR_WP=vokPGCe$l4&bg9F4q+x$h0TbD70w^Yv$ab%=^t7!wU83sXg35!a z!}fT53o>9_Z;qUW;|PMi3&D2(0>Pr5aLT;SmzXqJx4cp6ddV&Q5cLahBx1q&T@Cvc45TPJ>Ptb22c(!mlAm;tLgg-$Z;@h(1mTxv(4vt-^)AYMg_Q%8 z4O%6!a=Te^2^f)0XPbFmDbV5+SW|ELS z(+JrELSUc}QV&89fIEy(~aN#ng(J7aGC>x@F{7IZ&lMf%40Z*qzfsX0c|oq>g!!f)o-f=Sx) zOVXC#W+q)m_kj~^BmnEc>srSr+#~+i(OM9@J=${iZFWok6Fnoh?d%!q&K`ihva_eS zrTIuaC3s-y-RgtyE3%wP`NCUMXQpg{BkTqC&J1lU&A?V#6vX(Hl@1r7>zKlg!hYY0 z2B#mmveMC&veGv$->+cWLML9PE_6lL7J3)zZcU*%@;&&at-Q6X$=Rx7H54Y<(DobD zg)l|vWHXH7pzffGJvbFRtYYhdsauq`&0*)Db~NSrv~#qnDWPnEv_{&H5~x3~>>Q@Z zHuObyKHx|Reasi&=W=a9BaYu`=^c^3yqFcFF0A?7v z(I|vWjJ;=CQyIby_r218tPGi1&j$l~TWqj5FZPl?FLp7LNtaTYG@$Q@4Ppu|&tOtH ze2mYc@H%29tZ&mR4NCpQEVtx7KLckV;u^OgS2EqwgvBi_MuP#ymW-#WIyvZJtf~a3 zNqE#2#hoqf9ms*vjwtul&zV7oZfQXRAIC{oDp)3a*gj))h9 zj6Di++7wrA;A||?>9+X$$R3Y30@8)R{wZ#4W9}xv_4~ar!PNGi$l|$$_A03B# z(_^)8MuFfjm~*IiU91503_(=I@kH&Ur(lIsPTG!zB<%)4m;o5pb64WzC5EP`(dpMs z=1{-sC^iRe6cmJM&@H{oRGvwX-+FL0rkv|vq1=La$^!c$T!W`T0__F;CQNml+;_FB zWGtplQ;6?eP%DIZWPvRg(;v5sUpdF(b_e;V3u+r-;rEv)8)CTko+xdI;oi*XRcwgV zlZbknXwQzUHakr+beiN>ac}Sl77ww?eGB_+--TOQPs?6EbYql-u;Pw4EL{}B&Hwn; zeT(?4GD)Q6YzBoMetOYdzM}k4A!s4*L#TLl^o8gGf4Ad+VD{Mk^Bt60_JU@vuPDof zS%5l)*^gni-M@p(ECK&Qhvg{uRxDO5Flo~)x;2XzDi#~bN4lGTQIW1Ew_j9bq!NVQ zKf}FeA$t2U&O82mWtMQ1*DoqGTBus&d5g061C@CO(h{NBl#*4!S5+ExrlWkU(q$yF zEQ36IQIRl+=0yg~uvz5iDoe7v9rgl)dRrXbtTH^B7hM5{`9){0n5mvJ=QDYdt2&|O zEBRU8SJuNXESW7_=GLk?@K;tfAHN%`$oHdF%Mjq(RYeqs-O4vtj4S z?V_S}R2yNuv8qrf9_0tBi**?JzgDN~z}ml5FGkhP>Ky!L*HGD8L*+otVzPR%CIiZe z8e8W768oJLd!J)~CoI{dEB!0KR_o$Du0%9=%4MV0KXsKsIp-pW*IeYhtd`22S}H$U zn?pv=)fVas4E&v1r|#rm;NuB`UnczY?ezUIm%C8>@a zKIO{hO?6q+vZF4W+&x_9EL!=O>1R;S2jsMLA_3A%mn_kpdu9^6~j)ph>^_dmGf{;j)q?%lI%JHNNV9t`8}a~fXL z2eSN2$ck}Uz5w|#WCHfAA_8G zQI^j@I=+zQE0AX(XJR!wzLez!kjG-O{5O!D*JOFSjuo>x*Jb(p06vC1204BMfj|!2 zl;z)%p)AW^>Ue!);T=ogmu2OPNc+s(d0re=V_&n6P=Vkd6U)h}LJxP@qT^}TCO3EiejC_c9$pwstfTkqn zgAn0Y@LmM|vWn-En1h$t+WQIjH02pqgOoJBqbWz%^f^D!lxK{7j?pIYpEP9~6aFmA zdlUF?nzD84|H>~n<>{_`#m&um#y&}wPcrUp&d5!`xaWc(Y`&8Zbv*}o8h@-g)vyGm zlT;Fk%x&P#J^V&1c&Zy@ncnyuQmkhr%8v8&P(*Mrk^`rb0N{@^tI=rlc| z>Ds3kJ^NhG-&$E;$uyk4*w9m=eQm;;QJ!(F9_vAQjJ(vlDg`O7Jen~(WZ?(AUSS_U z>$M4GT=E8kor$W+|C1d4YLzGqZ(H-Bz>fG)Q#>*$gC}a-7R;?$!%npJz54c12md8qZ^#_Ti<->)N`Km@A-Is^Iq1w z-u1rkx_lSTe!;bV$(hyMriR2>vSarWa_ruQ>X?At5<*TlY+DzaUrxvn9POA^6})Bj-}h1%S73UY+_}QQ?uVbDi^*^K$)S)Fr9-WRu=bok z$P)wZv@`o$KbhH={$4hbMZZ^&o#^aXA=^IK*C5cX@UJ;iU?t5 zOr8#T#Z*FOi*hpTua6-l1qNZn6igmNhHV8XlxXk}=qebPMR_~gulu$4Kt3>qkTS7- z8U}7FBm}h<22^0cK|lM?(NKf{V#W67(QcgufypLB*a`=y;6Tq5kiUX_2p#n3$mB%O zjhTdu5Hnl@2MI-ls73o}$mD6rN>NThfN6Pz)QPek{npMvz{s5WD~Em6dP1Nkrce?= zI>5Y^N{B)1@DT?1UW;WU%AdgDGf9Lj5#=Wl&=Cxf0Q1q_00%>Jo`v@HMR(*Y=r(aLuZ_=B?UDt%2H>LHQBMh|%b$ z5}^PMIz^tR9ZF+4rcJms_)P=G0+@S}1+Z%ZFcCntgbVA6VDSsrH2h-W5=<>Y@WNF@ zw*@~aiOxx;&fq7f>7W}26bNm;A7mj|$AR7jFc0ivlM*9vzMl+wV0gkzHU_&`oWp=r zCWsfC4R*2d*)<#(34{VTa!5RoNdrRCkW{C{VVM*@X%J z-Noi)JiLU{O{yl^p$ekv&|a>J28WfHGO)eY5fTZXk1~pwjEn{nvWZdDq?XYX95jq# zPPa0O%{dqe zsUvL61WeZ%CSi%3WfYTtj!~r9#V98HJ4O=-u`!xW3&ZD{s_sLkAOGc2z-RTBs{VcQ z@({nwkFW6KOZ<4PAD{2XPx9k4{P+|u+H7NafsUJUZ^Gn=n!v0+1CsSYzqAN zWqy2xA7A3fYyJ3qKYo%Qp8;Mui++RqksgX(6>{;%#U72aQ&Zr2w$|JI35|<+ zgL{R36!U;-k|OnpRiV18 zYt6;1eMoPEo+Q7CmKa^jS_|6DN^kcD_`*$JlhDaLn3bx;nFdC`Puwif!-=O1i%n3> zG;VgqaK6UP;5#^ExKjq!yxw;=*i&(du0XC@S01xn7X;02 zq3weNwJVVH>YAOn$Ls2#-vivTj`18;j`SR2A;z+voJXph4Bg_DP%u#kV-9lyj)$9bst6xKf45Si>g6ivGSyDhOZfv1Xt(e~YzOcivM$ zH^)YstVkyoHWuYGx{6C|G5m@tf2~$&BkfDEk}fU64Fx!}5a%5*y#fajn?NiE1xnJ2 zzOBk?_-oFJS@nKgk}HsBRp$AZbX`@fZSR#pC98eE?x;}v4?MFwN?iw(TRfy=i_F7y zz=)b66CVLR(+uMWZq^U1uUetYuJXFCImUS2M}Q&mNih zNQ{;j=Hmi2#gE~%^o{s?xoFBIyvmi)*Anu$DEe(ey8P%pg!C^Ugv!)flivQi=Q#OK z&)bAK396o0?Q?P*+8}|KDCN~r+NDXD&kV*P*bGJWWFgcjo!4Drzl+ruTPzkE1YQVN zojvz)ZJ0i*+UqW}`!t!iH6@}ZooQr((OmkC`Z<%*PTDsiu20Jexll^TdEisvU7#7b zRf1dFTkCXNtuk{!gLFqIhLxCQ7HK2u-ot}qdwYKv-$as01KY!7m!+69ODr5LdU}XP zf&e*npqaN3{Cc|sEplsZ+ZH@Bz%O+t=5agdgrotZunmeCn7_g>#2p$A<)CNj07Z>agT+s#9oS47RbeY9yz zJU5QMGiDt(pQdTbxlid6nje!-h*1P$WL|yCeWLd*)JR_G?Pl?DdWErtZcZCzsuChw zqcq>(RGAY<+A_!o|Iqiv-u+_V#hx|F&BlEgJX{}bIAsjemm6LcYEROlJ40;+sE-40 zB|iXP0Pg}PfP+92P!F(ZR`*h$M{V~GF`Nd`DbW`gL-n(9zO$fsQV+u*eX++F8>+kI zF6)IpcB`S`hJ-Bk7&Aikx7<3qVr+!zFm89gKAeh6D{$?D{J4+^rx}T)jABy5z&|GP z0pK5HZd*Tc+qxRlm_kpF4UgMmdr;J_6#KC9 z%aHI7&gJyR*wNe~nvfn5UhdZ_OpbFtElwYuRW$Dj?I?Xr1xma#i3g?n7Oo4MrDx6DFoJ+$+eMgwQNdm0|wt?o$LV?&*O#Wu1 zIc402ksk|HP#A|d1@8*;NIEtmLnpMty zL@#H(iigH$CfHY}+N#7tsZl7lb~hVUO(A}Do_SklwNN#N{H_+nC}@^N#jxDjUkLIK zF@N!MnHbA>HUY-$WuvFsa>SwTf=XpE-ymdB7SXVq2a`A^(HF8u#fL%5Hm=GN)F{`g zZg5Jb8Q#g+4kBrKGCPWg&;QOI%Z1Rv?2%&!-M9K{@Dg1OT!4iV)QI;n1NhBA6mS&p zWfyW=GACwnss;UKyg(mkFLc0DlUr&gP2yD6zOu>ahu7XEz?2+%?5^de`o2KhNKb@P z#ttpRp!@kgZ@0n{gxd>gPlXc|a0}hoOgw9qnk5bV4ym}@*=?8;mOF>#9w{7qay@S> zF!IhVJaHD1Fr0iUZRu~Wd%pb5`=^d&Atjr%YJ*&F_V67YMy0cUyplLeh)UbBtP*N& zW5GtwxtSx*nSySwA;2QTQaOPDqJYN9G$*H8wg_zDWcqr}T-ncf{Xd&Sf6JMh^deY> zIxBDH8psY}kq8k;+C+yefBlg8%d^Cz8jX`Y%t?4+CWrt@`9dNMCZsdutIA?Rap(p!0v zK~r!}arl^7H<89q(Zo!5M%ZS#q$EJ2=;YD^Izz?@u^=cJEK$%)Hy zs-eqv4!U!kFOS3_gs(H7MB+0ezE(Ks=_zU1*Bp_*_mdIOr9q!-4v8%xgZqY82ieZs zaqwKPUC;C~Crz1}lhEa0j=ysZx@`{9Zih=HT(ggb9|8Gv*yFy$S!y#LOlH(;$nd)?)q?737Zz|N*HWpQ;gL?7{W5OIkM~K>1IYGzb z4s+CiP7pX+F>Q9_WA@Gd(v`Z|Bie>hexNh3&jWvw{u&qWxPBJ}5O7#PIDQ*0vrJ z;%XaoOYO9FdTMeuJYXv9gYGGKR;?R{XHc}AEA7S_!0^UVWPanlkx6_}eXXo7P zVdeupgKlCUgu#3m-UqrKcnV;W4LOhX&n|b~=AXRD!uj3FH6GV4#Q7 zakP9!g!HkVu5|j!j7a`$4?RAkQhl;VdZmn%UTa)G=st;|Ng{ELy+PDx+jg@^(^_&0 zUgu>4?sNSoH1txTK4HLZ>sRXr+?V1&7%H2A-1MZuB zr2R*XQGgrf-Ab%u@DpfJQSw-I|Mzw-nbR>#b$^;((zGpxYnSI*Z`QgB6jH0a-P$(b z-qhzAO?MROXI$ztzA4%D$eY1)vvf0cUwh={$F&3QANr&gbMlhM3*F$^~pxJJf$n-_^Mv|esR{s`d$`o0g8bl;K5<^ zsgfAQB(M{JOnRtfVp=%3P#^>d28IC&Kmu@p7qJflU(vpjseILkbnM+pCd-Fj6G!m2 z3_1WNx6^Bq*S%bO?VQ(SwMuHW|70|vwppOkS`R2|uRZTIb-{l3cV5$Xpw~cc%+W=! z=_gRtWuKj@$EP=gTCLVvi{0n985CwFvLDPDa6f^ve_d#My{2=ZJ)mp=bDwX3u6~~b zMwy=c;*;f|%ziH@(_39WeKRQ2E3f$Uxu7i2Do_@P9#mdudbxH380g7v&`-g92g(AH zU-bnv8QJ~HD5;+qtMravJSnVCqT{Dy{40(+TXmU4$!TjAA;@#WeIeEvIL^szJMw~SpwHQ zz63Nke3j6H2CxYC)1uN+YA98<>@3~IwUm}O%ITT=l|?V%LHK2$5qJYQ0<-`h0H=X3 zfn*()ATSwV-~ZPG{{+4TdT21*K zx4i4*I6I_}KV)YS=yHJ3=h4pSPLblo736)Qe3-T^AD`&L$u!{guG@qG@R@NP>v0Rz z0@(}7)6RwWm~80$|A_eid+?UQ2PE982RHr46IUNu_fZ!2Q2MQ}|N7V(!|bxbzIQGx zkI*fCWBZ=Ew+Crz&J6dNNe3=pS>H7wqWDV8`na@@wyk@6VY@!tN#4GytySyzO+{SJ#uFYx8lEeu96;jFhRj4g5hoY4@hhp z7*5jbkl17}WYD;(1O+QHLp?33N(f-3-b5d+N)BK}w$KJ}UEsRtJK)%)@1+;P2?eK$ zRmnl;*pdMBQ)$ksc*X61jnn&AB`CD_U{M3-=rfR_7GenlP4vjBPdGjO^Xdcz`>&sV p1^&rI_pDBa?$qirym}>dtWM?gSJJSDQlqL@;s9h*FJ43J{{XN~ybDqyR_7Cpd=bTB&MK!7leLsJQkk21#To>(=D- z-#z+Osi!v~%zwa3Xa1be-FE0k;{R&{X}U*0bdTPCk6ywiSU0t35mlmlo*4E8XZ5&BgEhBumhq`v}?W*7qRZ3$u_gX3qLcSZQhrfteUX z$avBPpCb!acx6=$YAs zXx+LD`~oJh5_T5<65`!Z5z@-mpBWl4U`oN=HTw@Z9zjA&+#UXk4l_`4Pl5}O`goLh zpS%5O=&G4wKr!CKh_?{&!rkph(f{oPLUNG^8}AGFAI1`3{auFn=x_}N&nB6Q5=l`a zb|}a-=OzTW>9yw5(LTki9jixbrx8-*9^gg9+n~K0FA4+BKzz7}2`JEh9PPOnUo`v) z4xeEL7Pmg>o&?xpy^R2#HNJuX8! z;*IlUbPgS=3aHL^J5~6FQ@gLy|EX%jlWVK%R<{NFaeUhf*?W=*LM9`C!VMWX;1t>M=pLbVew!ajg?Rf6awrhqE~|+r)A@wpM5_x z>>h%2?;LX>G0%wrn*!_24r~e%ElRGRsnjPpzJSH|9N4oY$)kXAqKSvr&Evq4KnRct z!~tovDtPKdoKhqfm;tca;S9KQ6wt%L6*JfzQCJe?woh;~n=9%|u#4^-tVZkz19Ip> zE@phNsNby$Q!`jg0nVj62dg1FaFUZLqC`jx7$>-R6uH?$Y(3HuC5&1XO&p=W54nNg z+R(DhsW_o(2#G+%I>yMTp0OVx&okB%(!dzoYBS?BIvg4~4`c3Rnm-|C#_5E-!5Hhh zk1;mcLB=@US{S2Rt&C9{3uDyv7~@&=!LZ~^tV}o4uoKQP#yX#8j2T^EjJ5riaXcYb z#+kG^tkihsH<;8XuU+vuyY0%EUrt{2$X#A?yO(V7l3TpweO|KJOE!7QTfO84muwUV zuJ>v%c*%M%d8L=U%u6o!l1sc~t(TnZC2PE7^)JS|Ggf*vM0v>yFWKKqCSI~|>uwyo zm)z$iTfO899@&VppYtee3B2SkFS*@Iws^@cUh+OK+3Y2oAWO+xR|$E|y4mR*D94p8 z&YAJgG04<5ULB-_!G2uw!2^P{qmQa07IU=i>4-fX|F@HEp;3!C&Ooasyvv=YLD5yg z^j{T%THd49+P5?~dza|K^i0-HL zCM3{;0Iuw`VHHA4Dw^{)S!}wmgk{!lfmj#ViTp@qi0-$rlyq5(c?-Pc#X>Cl?UcW$ zE55?k;oqn>ZID?Xt{~*fQe3=&?uYPHw1klBNP}PnWLSY#^lFu_(-j*9OX}%~33fmJ z30+h4>nQ0lvFX>P{z_==>J~~g?<9s97Ne}KC^kj0zjPNnOe{9Desi?8a)K_a(&;Ed z%}$_ZAF_C{S?fJDJ0a?xnq{`4P@bYO*;TaG*t25MH0zy?q+b=Sl{UsrsieJt}Q;G5|u8bZ~ z&fvo7W#v?=P!+|V=uZ}Iq3=zxZ@{|jb)LSr7gaAAAMPie(TK2m5pD|Q zxIqAwz*3+DxQ(}thT}E5S1kS}zee935g6ac#D1kFf3xpyrz5{#0*P(xgQ1cplE^h; zW9zs*=3?IDW9H#8t)Hm<&N+LfqLvCx(&Oyqlrj?^W+fnJugn}^Y3TSv1|E1b=%s{w z?mV54_}GLi590O#v;s{4%VdisK&PXPi79;5CHmLIxiP7CN|J;@QkaJG+ZS>&oik}R zFSk`C-AIIC~?7adJ-MhhN&;0ZZV#XNzQdnckWJ7$KdH%*SoEv`v?EkPG>ESTheduo7f_od002 zQOw=qUyZ9*NTj_Llf$_Lknr))YsRQ7{PNNE8QtSufI^A~YhEuH`+n?OF zyy5rmOgYx8&pYn+{9#Xz{cg+5JC?mJi^P#TOa*lu7fB;iYPfFtQp!T^D7~2Suf)Ud z%={3USKf9^8#;vQ_^)*KwxEU6%j(~y-%p7#R*568mz!>Kiu6p9@+kB-?&&KZ+U@RJ zA*`2gtlx#v!}Jpjr|LuX3k^HPs*{xHo=_|4+=r_Di0WMe&H{f1jsg3Doxm1=<#WaM z5{qd>LR;Jkz32{0^xFCmeF-iREG?ciz%f8yEY!z_=x#f@ZLr5~H8kFokP4wbHAH{g zaay#UF|fk3K19K%uxpq{=M)_DKSHl&Qxi|TNbIa9N>r|G7KmA|bSbnIlj0y_%@k}{Y`T5ieU|v;fmoSUNL-d#Te(dcZK>lNnw@3 z*Uv;(XU0)JV@c!=R$OeraZN#cLIp|J#sN9kv*cB}A>(UqIlW)=AvcveHOq~z;My?1 zCjUK`h1{-T-RA=7V)rm4hkMv%L5_QvpII($K$$)mr#)|C7bV`Tu$=3-?Fbzpoy+hp zQjICDWWdw!S)dZ{Dr`bKET_tzFFKE?-vXZrMP1`eL5=bqfpnaiqldE=M2=z4D9pjT zwU77-Y4U?&<}cSDpsMVJ+-vly?6){Q4V%^<;Oq@HbDCh&*pKwL_dP;$bJScQU6m6V zecSPeJ~f8hiN|$4I0w8JoS)aWKS#qUE{#a>ko^f>jM{;pX0~0KK8;i4j(m(q?#*b? z1MknENi$X?g^&1IBZcvDUv}ac#vGv|o+~ct%)$GG5(t<@vu3XI9YF6(GwJ@BrM}NW z)X$_p%`8n%f|$VKTEcX^iEG?0NR)31cvb;(B^&$FXo?8CHkfcee3sQ|aE)CJg_u zbp7mnzI2GT&d!mii+zI8CufKb&yENnL!^_#SDm`)bX>kVS~@h|T8NK9K5AJHH`S*n zIL+sRMmOeA4AJuZa9%z{SLf$U{Mn|2O|XqQMr{Z18u;EceDaDQWGY_iex@Jhr(~V5 zMf^HWs?P;A`kb&ytnsPbMP3fNN^dmOGJCg;hR?}~-zx^*kHF0~(s=_RNAXrS z8QcSu(6w{2`9(ImcTN^xXQN-tN#K)g^yfJmzQjh=+F0H?NOf8zFAP$>R#PqvvNUfE zjyY}*S`g=5yo_Z=&zfLapcwH!0eCj9ZA$tEKGNq-1 z#koF6`?PbTFAN48CQ9qdOdZSn!eBKxQvtmbR-d9)dXJI-y5Dq z_ZKAbra^kPASrsg&R|PN9|^X1j5*E@P{Z7$L}7rrj1G)B$RO#g!~6J^FuX@<@VzM% z&x?>p>4$S;cP?w<_E(3lU$HE?_Zcm-gm>H9y!avbtQUQ%;qzo)JnXyhqTU&VFPxAM(9epu!zV)YiGojT-=Sc9X2olH7<@KE zcF<=_-i&V_QR+q=Cr3sdU3mH!!5A9&ESF;+L!M3Vo0mA{$C1nZTq37qopEz;-G!(mj7l^X!w+4OU(Ebs)3+Mn&1kmOMapMm_d>hye>;foYq8As$ zhdc}EcfixYQ$Q`{$_qnl5M~jy1wa`vFMzHnj}EyHVm6QoWB_S&V|jK+Fr*+L5Rd`i z)63CXJ^uh$=q%%$v{?CTZUptK!i=^Sa$UY5u7nm+>*a~Lt zii=Jo`vhzM&S^XkF8SVRyZ|;_aT>n`Z@cR9+t$bWSsHfsyW$-KqnWgVyEuIMv_be7 zmNJ{ucm`|-cZ1DCt^usWt^kag-G9WTE5OXZ1YDWGwQKZsPd#4q zbY1$YRfeYwPj4_hUQ=E7WX<}vtcRNX+q#zjAferl%I|-t0M~oq5bzhE1NaE|61WI_ z4`kz+qyQ)e9so81SAjubGwu%tI&np0NFFYUxKW6oI`LVK)Y1D_WX#k0;<5y7E%?T5 zXH6^4IVto?TsAoH3V?AQ+8OKIjO(qaFLCRS(2f-us%^MvjXIq*Q5XQuNxF(6eu!=sjCW-TiqIG{m!PsvsN_ z1tC_564s!1{U|{=2uSTa05hfw!ru-2m*B8sIXdx+7S3rR`nx9x!k^J5`tN|R>WANf z{;Fg_C;%Pd9|0`O7KC?0^!7Uz!6W1)34&%YIEbZn%oKz)qwOS-a|Pjy(LO>9A_bu* zMrW`V__9Pns5S7X2ME}S{*IA?u-d@Kga39gHw7q_JXirHFa@XugYFqvwIT5cz`RsJ zcp*%mumX&_Qv`^uw;u<+0D;?#c0FJr@P9JezXjfv--mw%?L3zt%z_}K5uvupvQG+| z`N+zNx2=4#HZ$}wF-s7zIw2IrW)vZRHs%n7hyD!U5-?V9MGBH_^62wJo|zdUvF5Ps zs5tb-ql`egfrZ#+S>tj>#;|!d*BEF>7>Y6k#r#E}G8_e_;J*YsZ(!B7qI_aNKVoP{ zAt{ET(6lrG{h${9BPr<@tpomavKzy1VR_*ZY)$x+V{X9W?-PVDSgoC)6&4}r5QNhN zFk_ z^B#etKywLvRd=-96|HzLQr$}^#hRjWlrlTTs&WKsHkGqfp6>ynGVGw@@21MOE_&__ z(DT4)_LoSfWQk$NB1a^V0D&EsHBD}gmNz>DyZ2+rtaCYBR>MM~)_OYluy#CEciS}g z3A-P@Y0#*?Jw#v9R_TmU3)iMMdszP99MQ&}7(8VLmu*8z zv_4Gnw}F|~DmS}ScZ=fgQr)MO=FV>i3qtv3M=PYZdz0bpee3HUJQ18y?W-KbTYj^i zd`Q_wwp8}EvhDVvL%BTC4_qGAPc5aqo*lJkb8!@J3k!)(*G2Q~Vbh|MlW4ThI#?~J zk((s-Kr3(B^|9*j>)EF0dB)fy>{xX2DB?*%N2~5;Q!6y+Dy^{Cm=y5@n-tThhV?O| zhF4;y#Bh20siB#ji*Y0z9>mvuoUfaFv2Wc;v87@o+ZLOO=l)oIDQfi|_Fe2`u*?`T zWnm);P~4~4{b(DSeTHlHIcPQ)8y0RO+Pwj6#2|Z2MS48!_TdSFIKf_VKieGd;>zSp z&3s#N`{3xRpq8-?d!mOc)?aVT60Nu^barz6e(;j)-q~QKx+@OliO>^(^brS^odEWR zd7^wS!8cFjjY6sXd?Uzxg%WSCwa~@hBpKC`GWiRux|dHJ zIn2Iq8==cjaopxI`D=^Mk*iWgI%Lhgo7Y66rtdnBs!|Z30F|AhY)Y{zx2M9;G%K9VF97YscaE@CNS+Olvqq9_>+3AK-mUF~()EK8zSgi&mDTMCvjt z8o1r(Uj!2S zzP$vRuGrv*pK{Iar8(uZR`tNEWMAhbgGM=Ln8hHl_#!8%MjZy2bhp`n4a|lSS*lGd zOix*=Y=9YxQ*6qyz_;hGF+_>Y-~wAXQiyhdEpCT!{cS-5c;5jMn=Kp?$8L#_F!t<= zeM%=9u5_-+=FV~)^Ky}xJF$%k8~TR*(a1YQ7eaSK`3*WgvHPmHvba@w5~Ef( z>OouG%Z-81jZD&TQo&$>72iqPB{xy4o3B5h<14;!T}386U5rRqKQck%SFFl8bQ)hU zygo7o6PrPZG9fw;B5BeAUeEiu0?6wNS&8oX=r5Z&Ewp!9X z<+$Rl0IA)J%n&X_b^pqqd+)nv=|Nqwfk(Q~RR^r#f0Ldi%4bD)E|$BdoB4cdJ}z8p zL9|*DiKEJ2zvNT+!{#n^vrS#fxBL=l^PuAHPzu_Wk~XFEMBokZq`W6!tm;KN6tR~} z14a}!Pd9ZbMzw0Kiu*L=RtrueEY7zo68ZxbU?N|HL2-9sBN9g?`1jw`U%>IEfUELY zQQ~|T9SWePd(&ZS3Nk{0xIFnKbX(A&l<#2&60^iTtUJ+(XH=3~oWY8c(#4}pPFfab zcn^zkrH@SnBjnS1K8B3%*Tjn2{6w`^&}~a^vryNvvA;E&M*8+|$!F$T?fVMO>PKHw zuchgv6n=zyGMiQ@1!sAl)Av}Vy3gWf@I|HjE34>pf7O}FUUX$iO9QMtW%wYcseoa( z)LwAqh?3<@?YQKZMJZ=0dw1mP(qB%4%q6Xw!d^(3m$2|OcU)7W$XUA}xX>wvv5-;A zJXfu)Mqew|K3-p(S`bi6YSh1)2d^~+sgD)ssZDt|&;o~mCwK1t8MNDVTGfpyjQv_l z!#r>RV-91t;@;P9j^CT(f@H=Xy_)Pd*N_=o^J=n(4T&)`S<>E+#~w%>E>^OqQa4E} zPqE(A)#9IOm){g6ibvSV(Q)bDbm+UjphhVtj*wsV(G{vPM)gsL50JMPis)c4*>JEvTwoD5*7ujqDBI zo9FSt!1tdR@>lutrOJGZT3Vwv1PR*|r=HGU2plIu4=!j0pu`QL%HCj;dvPh@w`FSL z{?QA^_y=E$VMVm{OdstQAg~RSxoXjF)!X#S3tH3DQtIl&>zBSB1PGzC)Zm$I-h{Gs z61o1wPcvcZW5+t~*E#635Kp9)t=bN<~=f6Atge?rV;voc@B?XE2tWHupJVfReflGLX9NQIbIE$KqUv^Px8Qhvxh z=5uD*>wIlYOq-pc6D$(dQiNepMCOXeeUZ6pRSUZ>ZH|H7Xi*WR3xIam$DH>$>|o5^ zOq(-8AH6Z851mP9&fS&nh%%!4Y(!)@T&Kk}VGbW+-R=Nw% zrXVIPV?h{M+g_K$TGHdi*5IgCK5AD+>`iUJtL^}QK@#Yc@IIz9n|B$SfTty)4Nauj zaNq61C3q*>GGVgktbRVook$IAXAisEVG(d@pN8%0-^S~0Si$=kY+m=Ey>?xDB56-8 z=u%725gF6eYn4yhxq8udWHp_#mY?bdkMQGqr!Nw^uKIv@>DR;3d?=d6=8hpn1NmV; zq>0PqMsTQU~nA3sj}n~Ulm!m^BLV3!Pgm& z2aQ8I`!S~`MfdL)Sxj0MDVeNk&SR*)PoaHoboV97pZfL^&B)GY|0?Y|vUJ%S1o`4l zyBBXqNzaJ?BHC=w#N^>;?cNN%7ug8B&E8Tsn@m5k7JDD>yw9=6Y<*{E(N^|c0ho)8e zH>3vhu;3}baU^?T($pLH4l2b928ivG`56==uEPI@<9>5hZEzH*uf*ZC7IZ0b~}r(Y&o z=YqM+L^M-Vm)g`3>K{9>St$R-+hs~P@j?x`WPn~9)_0 zpO{oBrxQlyPkWsp2QnURj8Lo5>48cR>A%PjTPrKX+d<_k=WabXxA)CarYu);L9e1z+;it*)4$$G5`;r#q#ePucsMo* zbzn1dX!hSK+Ush#9xovFJxev(>HvD|Gq6pcTgyM^f$yA;W7QhdJM4A!e7vVOb0E%Q z;(EszD3je4tNc065k9i%jJ5m>@m9`-_YUB04RSDGbZpB+cz!!nd$>D$n4iGSCynzD#ka@v$41LJ;1@sucp|i-j zT0kz;PjTQ3bf@<3!3RBl&AfAQp=qeMo&9z;z8NVz1618TaOgSAbQ{NL{+2Q`6`x=`~X}g#?Gtlvao}`s<%Zn*rMP9!)#OcH}zPjd?>t z%D&aKzw=f>-ViC}BD+5?RqDEkMJI-nKy4V&%#^&5Ap#PV7PcF;(Wq6h_w$m{T%agK zYdTI}eAMleb=K3?Etb_>mBeKOXaWaWa(=338A$0{X7fQ!JAv$I>sy+(34L4trD?AM z7PsN02Eq3=?IPfdA8J|(a>Sl?O)CUk@sXyj2ecwz-wId(SPxi?Tgz$cKci{US2S%8 z;AFt9cv-Uoa06aaTaY%t70acsyIEF2_~weX&I-pv zRcHf*frU%J6AVQsK|1*eI*hi{fMcvI>yEVe=fW{W)7G^CVukC76oRkoVNc#Mm$l!K z62BO)I#!`fjB_T4{tXI#UGaCv;fh_!cb zUo`E#+A*J|R}>xJ{*~*}?t30O)-YxM?RULXd#P}}gwK|b79~Z{+Noq&+3$)H!}-#& z>=W!jQBpW5fJ!s_3@ut0mFX<1I4Oiy*Tyo7M~3vE*28{LJTlZl`i)?}DNYV0RgaHg zJByP;YEZ3V$BRcsG-8cZ3Ma8E#fjn3v+x}pWd<8nk`!Ku8kOf*0b0R-X|U3guf-K? p<>I7p`X|MTh2YEli$|hw_u`u*=OXsO;?%gwi(o=hwDB{m{}1n}34Z_p delta 7582 zcma)B4_K8|nm^y=g7*^mUErz+S3yKmBM`*D7y-0uF~^L_X7$C~Co z&-vbS&im)Q=Xc)op7Y)B$_vV4FDT8ameaSiq!mS7DrD?ZVaq*9Q4d-ed&1Jvv>~n- zeWB9E7;9@8zThl+;Mx_J9v!(g$9dD4Ew}x&W$)v@Ux`trAnu_Eh?u{4&__g}CBfaZ zl(FLqWAQAO)u6X$E@MYQseLnO^K!=CH2F`Eg>5MKIoSE2g8tF#7<&qBlK(CE^TzQH zqyKa&V`Y#d{!Y-v*^C{q8tuji=4J)684H>QYB9Bf8yH(+w%Xg zXHh6{f?*uyC}b-RFlMXj9{tg?sj+Dy*OnVQ1B^tJBovpZwXG4a*iw~Q;(gnUxasJN zM4{hI6qks!Z<<4r^dn6b#fF0EFw9w6Vxr!jtR#zH+HX*p_@n*jic4&XPFV@Pz#Z@e zqm2-SOQS@i8M{anBV8hjQLhlC5#{g5zeJ}gmY-CJx31Y>xu!zQj+q_z*(Sz3BUZoX zm7V+jP7*=gF&v@bZ-nQ zcOG^^RM$pjk4>^5W0e($XT+g<8P&bS(yi%Svh?C~E0+w^Y+RbupSS{N^yx=+|0Sv% zyhzXXQF?Zbh*_~NOQl2P#U`ha1A)W;7Yus(9G-e7Q@tO+XT!>|hV`O0_C9w&stw`E zwZS~?r0UOypN0(gm6LqsV3RA3mkoM)Bl$s+_qn2F)5675D!kxnIhrh<>JMu%M^zQOkH`S z^leYN!%)-xr(rBO;OR@{+8eqy!nGm2Z@6?SV~zFB0eG!?(-5Fz^Q%^u!qTJa4ky|6 z{6_`FkACnJ`P4or9FA$zq(7E#q(9tGExoZqta9W^cXaPbQR~PuT=SKS=NxG%r0ug# zDBaTv2cR=LDrOhLoULqN9Kj^M9%DynxCHeDE23`IB|(|qC{^}5{f{B+I7HJ_)) zu50_awogB!mo@0Uo?g{+W>i1B@OAy9?ybWx;EA|t2`e5%z2EXof06PGx&V!@$kJaF zq4Y;7yv*sl$?DsncZS&l8y)NCVuTQrHb{M1bG8?yZy@x=q zwUKgI%utq7%zjPx?!>6bADqSWh5`z8h`y2l3(EiHb>yfx57002y?>1XwW+r|0BgeleJgTF=;%$Pp43ibY|XZlO9 zgy_nenXJ@^h8Z*5tr#~j`(g;xEs#@RZYR?Ftxdns_>n}eoh*C4u<|aF_qmpvGWvNF zcT*t37qgt3bpX74OQ->iLk)8Swn&&Y0Ju6`-vgX0(rx&(K3b@F-Fx{l&ZRF+nUGw}Hx+F&Edbd-hZ@3Z13;@0e09EgI16&SC17NBV z!0RQzrD$<~xdgZv^)SHY65w(G>~e4VGK6grM1UKS3D}ZRiS4stY)NJeTSLIW)~K7< z8VwU$YD~aZLR&Bn+jq`?C$`ec_hGwQV!N7bcVVVU$)Y(idVz!d^FKX?DhWtb*Hfi$ zxC1eN%)3JPlQK(4SmssTy8<;XpOk&Pxw1)5zfsU%6eN4lkZU1)RJnFF6Pk5Pznik5 z*)kHMZ2X0s*!zVMP4X=MbK{SZk8l7rOR(g^N(OJKGSVq;my3ai#<~-hRhVwjMR$ z3?zMyuD#6v%C(SSmHNkM0V`wB0422A>?;P$nPD6VpGaZsg&4} zOX(%zm^B@jAB=T6U>^aV7^SgXbfx4daO~*yTiezll{}6~VEDyi< zSIC|oGPar4`sW67kJXZzdu$AIhv8jh+!*hK^un%~`)Z=te_kbKZl{T2&lzI$UQ4r6 zy9-3Zf*DGoxNbq6<(ZGfZx`I9Y(5gVFji5vi?^c16-MydR^A;J9MoOL;=W=DB?6}g40Z! z6;XY?d)EFBChx*Xb}t;%~AZPC3PWgfBei zl_R`1pmwj$(Z9()?sMg+9lqTnZgFvvA#jVrYe#rJBx3TF6TX;y-drPgEiN(Hdn0%~ z(j?eUb>WvjrwYU3?ZqX@hW6gbF?KewrS-+x&RBDJwc~(oJrmj43AlN;ES)LToGGa7 zUOGc$<}63;zq3>EoU<&%nUS+$3Wb8&u}qxGo~i5%YweU;-8u2`yTPaRr#Je*umyi0 zh~(TwYflAFaP9PjBT4I2y)qSRou0lb<1j*|FL`J3>QsetLUm;{kZ|4mqGv&ZxlQM>zDnBE?kKd4) zlyCy5>`MUh9EE$j8TB1A?WjfkA5{QB3a00SHla>g7eT_5_UgfMO z#Jl+}cL?3v<}udaKs*+juU+ks3xxnM7R=nM>lC%4Ra&{A9QQp&H3|=q-pf|c8SE{| z?LB90JU0q^_VYf;<*gxX)Q(Q6e>vMdnHLe}Ei_pnbKhD$=U`iE_I_e*{Df@l=k1p# zS+|BQWdE=Q_jj6zyvl^!lE#%PgxEs-Av|f`5~kj>*2c4P-X~1YnvFyeKL*<$La@0F zm9MRyvsdHxrHOm1p}!Znhj9DhnN6ISX~7b`h?(=bkY=C zx@9$Kk;aCkR` zZtM;94yGRbuZE8m-?MaMiKk{L#Cn6#YPt zj?B{3Eu(1BcaW|)4vekJy6i!4?DD_#O&m&FGf z{jGX^$=s+xum`>t|4=g9PChaGIpGuaB`J$sXe>ah;7TyKgg7B^iuOm`3vWoe6#UfJ z#Oo#V-3K5x4P94W4F++D1mAc)7>n;X^_%}2=xc<-hw+-5VvNcmyZGIP%$s^JSA2e9L!e)M8{G9YR+!-5j(DTkc>(=IJ55SipW6Lq`z@2c z7a?+P&YYQ!Q2@uTYEVpb7m33AU3KE`ZeE+T86)jL*^9CtJVy}{ke*?C<3L;E~ZwdMHax10q5o zoQSmtpAV_rA@s@=`$^QO>=rMg75-K#l+6iZr1BKLgT1yn#V)^TZp61saenh$^i8|< WT1)3fk$>y_#FOZbCfnvORQ-ReZSqS1 diff --git a/danars/src/main/jniLibs/x86_64/libBleEncryption.so b/danars/src/main/jniLibs/x86_64/libBleEncryption.so index 48d5708f6004dcf5f95ee257b9daef65b17a3b86..00e47ca4d38eb16e46e204ef0dcb5a695d455af7 100644 GIT binary patch delta 8468 zcmZWv3tUvy)<5SkBLjj56huK_R3Kggqw=sEoza;(Dk!O_S^0uY&6G;3Yk5Z+r)Hcm zZD-m2tgy$e?A|_$#OgDHBH)@|Vp*CuYcwA-rlw^Erq2DZea--O&+m6;?e$-ez4uz{ z?7h!{x_Z(5p12`XQl@RpUKZ(71b+FHjW6d#OxLO0KQ?~*#NaEpsLY?~aTOMh*Vl+Q zh;hf-KK881j!&*$HsE#NUDd`(0}JhJt2l^ln4x3eNx9;kY;ahD*v5a4&@U?wGfWU} zQr#FOmCgj|D?|&vbd~>DCBhgDH=0!-Rnz||Ob}v(3&AS3H7sFZ^)OZXm}d36Cf&vM zhb1_Kp(TAtNm4C38O83Ev@bjrE|CLIFchM)|?c-G-MZJl8~X{z=j&7DE(UdU5{N3`KqX}C}8{(`1o zul3@ys6e4M?MQ7{br~w&r1^OOEKP5o8hVHDS5+=Nq&Yf2P6ZBV`0JWMqc+f&H2f(| z->B*D3+ZckyHN#lF>rp(om=_v{JHa2-1YF{6+-ERapQ%hixZ^{ED{XcB~2*wB!vNDX9f70{7QSn@JRodBnjF-j0JM@OFT=bpEdIU)+92S9Bg z?j+pFtSMsrtpkdN#vVMo^3f?ZY~{(fcfEOU=i6&OnKUo+VDYcz5ij1q6^gtkN^(5z zegtS&BxnL|y~ZbkCbP20Y3byjF6xi6PUGv3n`TP=(mq$tLdE}HnQh?KOiQv=%~4361z7lK^(|jQ4fg;>}pg3TN)L$@kxUtSoq){RXMz+gV~#!pL<`&8XX21I zAy>Ss&nw=QKE+$n=wA#~=jsE3?0OHuY1RKf)5(w9Gs%JHBO{2{zU3zSX1NxX1WSDh zI#DXiwycXYcvo(5w&<107R6gj2JSeKLlTERGO~SgvS?&ymqMfx6Yt= zqqj0!-^F4Kd%JI*IDj4LJ6_zy2KSqY_R@YyaXKUh!`sh?_acu}5&NHhTSNmZi5r36 zrEwK~l1eE=9~t1(|GypV*2MnoM4ahn;%UOJ0if!fT_wEP9Jmbyf$)p6>oTA7`bl^i z&`GN+4jO0(igR_FAg`Uq?ubuvnEvJ2 z!(A?QX;p{STzV6j#a$id<>PZUMtEF0^y}rno+ia}Oz~{$xW?qzfd(p260o@gQ)EAw zmR_&5+$_Gvv7-q|4(CUF{+Lh4RbGncLFDzc{A_|*aM))I{PktUBHp<4VJd9yjN4VwkxcM;uun;`h}rJbr(L6!9a{ zGk&U3D1KxUiXUlq$4}Mk89xo_89xo`jvoPtUz453kG%UUe&O*Wi59Y zv6)FJ{mB7s9*58`_Oo^ndHq3_+<%BefvDAGBL!SGwKJQ?WdY*l_)WaswV03r78A1I ziwQNl78B}#FD5FgEhf~TI}U3JM`;sT~6W z))OK<))THCT2H87Z9O5i(0amkdaNfZ-(xvZ0lu6#)CGnRq%?NCx}LoGGX`bu3l7zc zjYIJ6&@{q<;h~|P{q@l55?mVBE!fsmaH5A`D+Ji{v3J4Anl;$F`qJj5ItjM(2d{t% zXGj4C*+Th-Vj*`z5c$ zVH_rhLgya;#dE3I~uPkg*>QeDz_I~Q!;ZAd;1)9ua%pVek4c%#O zAB&w`cC7&FG`|G~n>wB5oaPtDGP7~+kjFVQ1rlu1s#9-wKojoix7+Rv$zOuJ8#+qRmY$Fy{u{!cKgqsM&%lB9 zO8R=~u@mgcjQgZwU41a4muP;mm^<%2AND`aQ}qOJ#jBqOvJR&`{X=NDsWF)lI^O83 zirKi#d`DjZ7+$xBZ9j4ke-x1i*CN#6It3@6_|pK~k?WK&w7;kJL{V{?e?{v$^LteD z@3^^s2M8a)Ub3J8yg~>czy}1~%8y!Iy%eqnDDUp{7m^$ACK9;EN$bX;*TVT+*5M!6 zQw9Maq`ceU>_jE)X4b5Jj%~aKO)x;pD2o{CcyJhMvdWoNj@}*C?-jEuF>eYXhGl0qR5)Jq*g3CqzII)kjt0nm;UsG&3)`+S7 zVObkJyFXi>)7BqpAFe(OI0ImHYvaLZb8}hBy%3-;0+q^&W_kC>7}FORRgByay?8i_ z88$@{hO_y@QY4>=)eM_0tu?VD!v;wUP3#YFktQ}XFEvLrseZ|YP2QawV>ey3xpQ%N z*MCuf-AisLv3WX_+IV9=+nSdwZ7pDpdFj%s0(L5Ij+9uyZpj}k{hrU3fE>tYwfQro zwfXEszEN6`&%z4^OJnm{cEPY=#(XUF_GTWg=D?~ec#fy?lz)LQEJ(QpOwakHMBq)q z-iG&xZS3(}o8ugD-m)#u0JfI>ExMR65#W(XmaZbTy}FNs8zQ!ERlw++dD@$C|09diq45bg|Z~ z4x6fRei$_VtPmAzHFetDQLz{xpY@Z0sVK1SC6uizTowM?x3pl|*tvq|OxZ}W(>xEw zk07)el~m4lq^|uS(|C7G$@yyHQg@l%wZFU zr%4-gSoQD>X>ktQJbZzq&tX@<9m!^CBhsXu*=!=no7t>-M1u5iHuH?AkOpTn--skh zm(8w@m?G6@vB@J7rRTEPl95v!bF#XJf@m7VZxBsdV1_{;H=tCg0?ViZ4JIzLtXuh% z#a);Vd0;a_>NFqCbQ8O(QhEl#}VN;^s%Jw3FBMny5_cpZv zvQ;tmxGwQ%d^h~Trn>Asl)W;lB6;tSo?XTnY+0w>afWpj|L2Z>X9$bGu}CuQV`Vog zQo<1S+>Oau0`$>Q#X+m{G8S>#DE!C2z@yU#t#$T;ZvDBzfR28_j@+2wP@HE9OpSDS z$G0cXO26W%@ZtLtj)6G-JstXlfy0*%l0yp4X5O+xLA);N*TV}Y{sagLMX);k1@?Oy zBLS^YAw|T?QGs1-n^4(^2kvbn6xYRxHh26Ts%hz9VHw$4q#nj4nsHdSv1XO2S|z9o z7F`dcFwIE+Uq%%K$?O&=P4QD_#q^2I)*3onEHesw7AXD0O96bDvy1+ z4vNX0VC<%^Z0_WrRXF|>sI}=b0(A^SO+Ey+=|^2o&5z{B8gUqz_zV~v{T&2_s)wJ# zcgc!swD65omNI&vqn7OWf{)RzA?B#A<|z4yXmjhA1HeIR7Kq#s3Hv!{@o-geD0(tT zSGcUi^bA)40GJQtx~oJCK%b1Z8m@kXIvUJTpj{D(zJ~AIR*b=_4#F0(4-p9fgr6@# z;A0}iJ^pJj_N+aa=I3bL`RRrV#d89){UDeOLTzfuc8m}P+gr8{~U z+I%IA9;%}HBv32DY{kY(gYV7xuDshL+EG83l3BZXP@bpaxYvH%qu-1pA{Fi*@6tL9ffz{ZTpV2j2W9o2h+!6>9Hbj6{8qm-}+ zxEKOK2`|Mx4>;ZfyDq}3aL)p6=t5QfN5Pi^$MLJ{!dfXjgPZj6_oVTdV4s-BrSZ|d z!fuF(3O87zdc|<%LHON;yZUf2_!uD}J!v)61cBt=;r1P76UU}x*Zn&f2(=eeoj9rm2V2|`->n#ZbtGe}YtPn~i{NVNVK`xD-d%g5gNXsv>)0RBRa)~8c z^Q;9O!Qk^S>FQW|rfaHKpuHXP3)jida5>FwP#FG}!WLVH>TPJf!8Tfx^i^ohV((a! zGS;Fs00%_WPq+8mxUoRiuR?z4Gxm!$!%+Y=`ZLgbIJ+Of>8iN}@ASY9fL4JX2YnRu zBIq-qy4GOuAE0TV&7f5WgTXT-2aUoT{((bC45$tXnhrYsJJ^FZgKhz>IuZ=-0zD4; z-PPdy;H%$586OT-oPZ&y?j!~Py7mkViT@QHf~Nfj15n%V=m-Nn4w_38Q7Q#Zy9^(o z7eSu^J%E$Qd!Y3f#ueyTOqn6VN4p=cMmD%Ce{iPu7*IviMSmTlD@1+lzOuQF4O;Qj z7E0G}ol1YZ7FU^!$iAEo619b9!;aE{)s8MpYC?_%zPP{!&pK87hs;DE47RQN(uo+Jb94>#Qj5 z+o(k-L<?qy9t|LcDf>cyE3QLJJ$v+`pX%~wsT fZdK`Y)- zr2UWfWNStC>~8H=k7ZK3CBf#3shO0OTdbj(&X^_DKSLM2|KEG=y?pe)&vWNJ@9+IM z@A;i`&;1zR8)EZ*aYv@qea92o4@UHq3jF9PePVBJcu$z3O?%?skBy5~O}~^~ijUB> zzd@WJMqm1`?yk!*7G zY>eAHPJt^$Mcxg``^s1JSiK?}5Jh-%lA?dC2;n~TNqDzS0n%0cpo&-CssOuH{7p6g zj*%S578aTmON!b-Poko~pawjtmMgF)bYtB2q$==A)oM_?IjIgZQZ4s>Et}eXp*p+> zwflW)ot|MzqK6@975(siUab3K)Gq9C+`>v5zL(V==-cB6wR0;tAN9e0QzoyHWphwBpQ;iOk`{rY_9 z#BHdA>pzfw3+ee>zeM^7(o?v8j&vjGX0CruI#C!B|GBuSVu`8gz2c5WTEA})-8v^V0cn<4bwTE4SCJOLHiyV?TbTFSSGbf7q zY>PQlw6Z^&OT<^%MYAKDT;-FlfYaylJA;t>T>e8L2_tLRa_S^{F?rv|ymaUbSXJb{ z2~WK|e`QNOm`n2YGv>%k^~frE?DkEa6#e&`DD zaG!3ZhN8v~%L87@X7}j~u7L4d7mPSlaymWXos9FjL|%H(xXXF9}B@ z#^EJ*hp$AB>7@{d&n_uxJ;C7^CQsAS6a49_EU)l;zoV>gHj!w*W@tDoBY$8QRqnZ@ zbJbo4+mz7m8(}rQxr^Ky&T*du+~+%6n5*`t-4|^Qr~szurv0$ax<~`Wp@1t8GitUV zl>0k^o~x|K9Ao5x@<*1BTz+pi%a4mq>qa+$Ch9=#o)(^$P<2KOGHZ*COPPgYadddQ zV4`a@z*`#IC)q;@aS=x-8OJ%>ZBYB!rZ{5T?Fckc+wKVscbZx{!MXs|;r}#P{S)V@ z6{_jY10>pS8X7JT2adolCFqiFR_#$&U>C)d_zEH%po%>03RjN6Gm76gVY6zFIegI( z1Be9Vux?_+q5(+cPy`61DDbt~#TO`L51#&Cwk&4!2(rkXoU(mHS?WFj${0Wyd2-4K zRVh2keiav=ay#)wjJ*tt!WgwQ#+o@}PXP&V56;*QsQrwQx5gN?2Qk)rLt*T1KXS$% zhZT&G7|fUwq%lS@8e`-+z?kAUm@yR@%$N!dFh&3vYrl;%M%jate&mdiMP;m>7|X8* z5NIM8jFBg2j8K)aX5Ks$lIddiZf0o-IjNf|$VDY?E@(2gdS!*wzd-HO0_dXY7*O&YGR916QfoH zoL5))o#z{!7j&Y}c_DOyb);JKotI^K$Lne3qE!FQ{<-NDl4J?7XELl~9tbLBdnu!< z!`TBNgd}!3;|}*L)6v%YYKDR-r)N`)t}U?cI9A0@fWhHN5n4I~-%R+Gi?megmAGj` z>}$y`!#*X2DhQ2uLea};_^9zIAubWE%T_iyJJ0Ls0V0jy%yX> zX#%^bdta&4Sc+Z?Lq%lk4Q?E4gMo*eS`D6SlF3`oEE7kStj1&3RsG))fQ3WvUMTe# zG>nv9Q=t7z(de1CL%)t3(F)Nsb%%aM5j!|Bd!m&;s};aTkBf*YS7P`RBt5+?{9pvUn&3*2eVbFKd*vLq$J$AEgttT?q{-MC#absF3CGoW#MGMaxyjlmC$WFz zu9Hd&m?bYxnp(gr^5#jOOkvOFB}oUSu-3dq(!wb$Em|kIIkfU_`(pbN`%?Qd?1gd{a&?wOGjG9;vftwc zPOAp@F<;eoRI)dZYORy}J>a`4my`l5SgLsoaiz1`#U6)GXNB+jJa&I!nlwL;H5T42 zUCw0}3)7{;xy(2Cd3_-dZMwvYBmqob;b;ws879X>&IF>+~dPaW*?TeNl>#&8NQx7ZG;y+N$HG z)&#R7>kD53P4Kxa<|tkyJ(|Uui<6~wS**P{O{&ad7mBA!`#xbwwmI>~GC668tw3zC z!SZv7ub8HAZzkJntCnVGvMyVal#Mqb+g&A{6NtbXnsgok0t*aw%Nd61)8 zd>J&x)~e6!p6j?Q=?V`zKE{qs@4t=C&wTm^;Sscd%s!Yo#%-^@^RRw40JMP0*1x~qg=^BKP% z&*MLbz*Q&V3e%rK+ivM~`1Gg73vSAOP_c%=YHTNK)-{LE_$Ehf`ykq7o#&zn=9s-? zZa=5PBP(^`2>-0aXKMn8H0vSYQ>nvG;zlS=%f}91;u-~xc>vPheqCqxoI|OJHBj5X z%F#7^MTzX;pF4apPGCrs3xR3VBTwOEilP}S%pA`~mX38BDXv%N=|&QxK+0KN!&yGw zBR>6=bjlFZ4Pk1DK>QiBI9;D`$an&xpRRUN2Gd2K#}NKJ_uV9-0R1y)D|9hJ-7U6l zko}Ap|3G%sU{{K8gntM|RslqwMG(j_n|P0@g5u0Nieb({Ysq^%s$BlBG1@|CrWTh3 zm&s^~nDuN98Pg!NS_?;$azR(zaDk8Yd!JDc1o2nXD83GB!}cSZbVb-Majftwi1wR0 z&jp%0{U>Q`dD*D)Hh>6w4FV{g##hjGX0>C|Uro4b5@ z-NSY3ep6Sw=E1eUU9*}+I5KdvW4Vr0_lqCOGCe+OM>HA*IGcgf%~CrEFUR>5aJ>dX z5`G`f9l-I?qW>U#Gfp3H+MKlm^a(q0l0Ux2x-sIB=0~M6&%zBK7y)(Rtoc%w`S;;|`w4ERj{0!McFXd18i{5P^NIugVCdwS z4u|@)Y>_j={UYwaD*^TUOSS#|(E~>>?9UCcKizNN2Kxp)2k;NNT7S~U{(4@9{WR?F z4v9Z7P!1+Vc80s_@a)4s7Hc`eHVzx?L}TxxT$g0|ks-OZ@V;=v5E3xMu5V0wx1Y~$_mdIwsSZ1?T)8TX-O#*K|U`-xx1gZcby zg+2cm`~3C{cO~5Dv+{^zvV01+`-J1Nyc$>z5%G2%dai!2t zr^w6|hH&i*IKFsSe}tS5fFs`_jCTffk?FaMhT@KF0G;lxlt_#%wmJ9lYhx7rWpfY*`0I_D) Date: Wed, 14 Apr 2021 16:06:33 +0100 Subject: [PATCH 002/145] - starting pumpSync changes --- .../pump/common/PumpPluginAbstract.java | 39 ++++++++++++++++++- .../plugins/pump/common/data/PumpDbEntry.java | 21 ++++++++++ .../pump/medtronic/MedtronicPumpPlugin.java | 27 ++++++++++--- 3 files changed, 80 insertions(+), 7 deletions(-) create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpDbEntry.java diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java index b6bc68a47a..b9e1f4f387 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java @@ -10,6 +10,8 @@ import org.json.JSONException; import org.json.JSONObject; import java.util.Date; +import java.util.HashMap; +import java.util.Map; import dagger.android.HasAndroidInjector; import info.nightscout.androidaps.core.R; @@ -27,11 +29,13 @@ import info.nightscout.androidaps.interfaces.PluginDescription; import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpPluginBase; +import info.nightscout.androidaps.interfaces.PumpSync; import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.common.ManufacturerType; import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress; +import info.nightscout.androidaps.plugins.pump.common.data.PumpDbEntry; import info.nightscout.androidaps.plugins.pump.common.data.PumpStatus; import info.nightscout.androidaps.plugins.pump.common.defs.PumpDriverState; import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; @@ -69,6 +73,7 @@ public abstract class PumpPluginAbstract extends PumpPluginBase implements PumpI protected boolean displayConnectionMessages = false; protected PumpType pumpType; protected AapsSchedulers aapsSchedulers; + protected PumpSync pumpSync; protected PumpPluginAbstract( @@ -84,7 +89,8 @@ public abstract class PumpPluginAbstract extends PumpPluginBase implements PumpI Context context, FabricPrivacy fabricPrivacy, DateUtil dateUtil, - AapsSchedulers aapsSchedulers + AapsSchedulers aapsSchedulers, + PumpSync pumpSync ) { super(pluginDescription, injector, aapsLogger, resourceHelper, commandQueue); @@ -101,6 +107,7 @@ public abstract class PumpPluginAbstract extends PumpPluginBase implements PumpI this.pumpType = pumpType; this.dateUtil = dateUtil; this.aapsSchedulers = aapsSchedulers; + this.pumpSync = pumpSync; } @@ -335,6 +342,7 @@ public abstract class PumpPluginAbstract extends PumpPluginBase implements PumpI } catch (Exception ignored) { } + // TODO fix TemporaryBasal tb = activePlugin.getActiveTreatments().getTempBasalFromHistory(System.currentTimeMillis()); if (tb != null) { extended.put("TempBasalAbsoluteRate", @@ -343,6 +351,7 @@ public abstract class PumpPluginAbstract extends PumpPluginBase implements PumpI extended.put("TempBasalRemaining", tb.getPlannedRemainingMinutes()); } + // TODO fix ExtendedBolus eb = activePlugin.getActiveTreatments().getExtendedBolusFromHistory(System.currentTimeMillis()); if (eb != null) { extended.put("ExtendedBolusAbsoluteRate", eb.absoluteRate()); @@ -377,10 +386,12 @@ public abstract class PumpPluginAbstract extends PumpPluginBase implements PumpI ret += "LastBolus: " + DecimalFormatter.INSTANCE.to2Decimal(getPumpStatusData().lastBolusAmount) + "U @" + // android.text.format.DateFormat.format("HH:mm", getPumpStatusData().lastBolusTime) + "\n"; } + // TODO fix TemporaryBasal activeTemp = activePlugin.getActiveTreatments().getRealTempBasalFromHistory(System.currentTimeMillis()); if (activeTemp != null) { ret += "Temp: " + activeTemp.toStringFull() + "\n"; } + // TODO fix ExtendedBolus activeExtendedBolus = activePlugin.getActiveTreatments().getExtendedBolusFromHistory( System.currentTimeMillis()); if (activeExtendedBolus != null) { @@ -413,6 +424,7 @@ public abstract class PumpPluginAbstract extends PumpPluginBase implements PumpI //if (MedtronicHistoryData.doubleBolusDebug) // aapsLogger.debug("DoubleBolusDebug: deliverTreatment::(carb only entry)"); + // TODO fix // no bolus required, carb only treatment activePlugin.getActiveTreatments().addToHistoryTreatment(detailedBolusInfo, true); @@ -471,4 +483,29 @@ public abstract class PumpPluginAbstract extends PumpPluginBase implements PumpI private PumpEnactResult getOperationNotSupportedWithCustomText(int resourceId) { return new PumpEnactResult(getInjector()).success(false).enacted(false).comment(resourceId); } + + // PumpSync + + Map driverHistory = new HashMap<>(); + + public abstract long generateTempId(long timeMillis); + + public boolean addBolusWithTempId(DetailedBolusInfo detailedBolusInfo, boolean writeToInternalHistory) { + long temporaryId = generateTempId(detailedBolusInfo.timestamp); + boolean response = pumpSync.addBolusWithTempId(detailedBolusInfo.timestamp, detailedBolusInfo.insulin, + generateTempId(detailedBolusInfo.timestamp), detailedBolusInfo.getBolusType(), + getPumpType(), serialNumber()); + + if (response && writeToInternalHistory) { + driverHistory.put(temporaryId, new PumpDbEntry(temporaryId, model(), serialNumber(), detailedBolusInfo)); + } + + return response; + } + + public void removeTemporaryId(long temporaryId) { + driverHistory.remove(temporaryId); + } + + } diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpDbEntry.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpDbEntry.java new file mode 100644 index 0000000000..f67a9741f8 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpDbEntry.java @@ -0,0 +1,21 @@ +package info.nightscout.androidaps.plugins.pump.common.data; + +import info.nightscout.androidaps.data.DetailedBolusInfo; +import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; + +public class PumpDbEntry { + + long temporaryId; + PumpType pumpType; + String serialNumber; + DetailedBolusInfo detailedBolusInfo; + + public PumpDbEntry(long temporaryId, PumpType pumpType, String serialNumber, DetailedBolusInfo detailedBolusInfo) { + this.temporaryId = temporaryId; + this.pumpType = pumpType; + this.serialNumber = serialNumber; + this.detailedBolusInfo = detailedBolusInfo; + } + + +} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java index 48cdc84322..efc0a8c117 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java @@ -40,6 +40,7 @@ import info.nightscout.androidaps.interfaces.CommandQueueProvider; import info.nightscout.androidaps.interfaces.PluginDescription; import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.PumpInterface; +import info.nightscout.androidaps.interfaces.PumpSync; import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.plugins.bus.RxBusWrapper; @@ -98,7 +99,6 @@ import info.nightscout.androidaps.utils.sharedPreferences.SP; @Singleton public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInterface, RileyLinkPumpDevice { - private final SP sp; private final MedtronicUtil medtronicUtil; private final MedtronicPumpStatus medtronicPumpStatus; private final MedtronicHistoryData medtronicHistoryData; @@ -117,7 +117,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter public static boolean isBusy = false; private final List busyTimestamps = new ArrayList<>(); private boolean hasTimeDateOrTimeZoneChanged = false; - + private boolean usePumpSync = false; @Inject public MedtronicPumpPlugin( @@ -136,7 +136,8 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter RileyLinkServiceData rileyLinkServiceData, ServiceTaskExecutor serviceTaskExecutor, DateUtil dateUtil, - AapsSchedulers aapsSchedulers + AapsSchedulers aapsSchedulers, + PumpSync pumpSync ) { super(new PluginDescription() // @@ -148,11 +149,10 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter .preferencesId(R.xml.pref_medtronic) .description(R.string.description_pump_medtronic), // PumpType.MEDTRONIC_522_722, // we default to most basic model, correct model from config is loaded later - injector, resourceHelper, aapsLogger, commandQueue, rxBus, activePlugin, sp, context, fabricPrivacy, dateUtil, aapsSchedulers + injector, resourceHelper, aapsLogger, commandQueue, rxBus, activePlugin, sp, context, fabricPrivacy, dateUtil, aapsSchedulers, pumpSync ); this.medtronicUtil = medtronicUtil; - this.sp = sp; this.medtronicPumpStatus = medtronicPumpStatus; this.medtronicHistoryData = medtronicHistoryData; this.rileyLinkServiceData = rileyLinkServiceData; @@ -733,6 +733,14 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter rxBus.send(new EventMedtronicPumpValuesChanged()); } + @Override public long generateTempId(long timeMillis) { + return 0; + } + + @Override public String getSerial() { + return null; + } + private BolusDeliveryType bolusDeliveryType = BolusDeliveryType.Idle; private enum BolusDeliveryType { @@ -878,7 +886,12 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter detailedBolusInfo.timestamp = now; detailedBolusInfo.deliverAtTheLatest = now; // not sure about that one - activePlugin.getActiveTreatments().addToHistoryTreatment(detailedBolusInfo, true); + // TODO fix + if (usePumpSync) { + addBolusWithTempId(detailedBolusInfo, true); + } else { + activePlugin.getActiveTreatments().addToHistoryTreatment(detailedBolusInfo, true); + } // we subtract insulin, exact amount will be visible with next remainingInsulin update. medtronicPumpStatus.reservoirRemainingUnits -= detailedBolusInfo.insulin; @@ -1044,6 +1057,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter .absolute(absoluteRate) // .source(Source.USER); + // TODO fix activePlugin.getActiveTreatments().addToHistoryTempBasal(tempStart); incrementStatistics(MedtronicConst.Statistics.TBRsSet); @@ -1391,6 +1405,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter .duration(0) // .source(Source.USER); + // TODO fix activePlugin.getActiveTreatments().addToHistoryTempBasal(tempBasal); return new PumpEnactResult(getInjector()).success(true).enacted(true) // From 769ab218d4c5228093883efeb9f7057697533cd9 Mon Sep 17 00:00:00 2001 From: Andy Rozman Date: Fri, 16 Apr 2021 17:11:00 +0100 Subject: [PATCH 003/145] - kotlinizing mdt --- .../pump/common/PumpPluginAbstract.java.orig | 535 +++++++++++++ .../comm/history/MedtronicHistoryDecoder.java | 182 ----- .../comm/history/MedtronicHistoryDecoder.kt | 132 ++++ .../MedtronicHistoryDecoderInterface.java | 15 - .../MedtronicHistoryDecoderInterface.kt | 10 + .../comm/history/MedtronicHistoryEntry.java | 316 -------- .../comm/history/MedtronicHistoryEntry.kt | 222 ++++++ .../MedtronicHistoryEntryInterface.java | 16 - .../history/MedtronicHistoryEntryInterface.kt | 11 + .../comm/history/RawHistoryPage.java | 87 --- .../medtronic/comm/history/RawHistoryPage.kt | 61 ++ .../comm/history/RecordDecodeStatus.java | 30 - .../comm/history/RecordDecodeStatus.kt | 19 + .../comm/history/cgms/CGMSHistoryEntry.java | 92 --- .../comm/history/cgms/CGMSHistoryEntry.kt | 55 ++ .../history/cgms/CGMSHistoryEntryType.java | 135 ---- .../comm/history/cgms/CGMSHistoryEntryType.kt | 62 ++ .../cgms/MedtronicCGMSHistoryDecoder.java | 469 ------------ .../cgms/MedtronicCGMSHistoryDecoder.kt | 269 +++++++ .../pump/MedtronicPumpHistoryDecoder.java | 724 ------------------ .../pump/MedtronicPumpHistoryDecoder.kt | 502 ++++++++++++ .../comm/history/pump/PumpHistoryEntry.java | 174 ----- .../comm/history/pump/PumpHistoryEntry.kt | 117 +++ .../history/pump/PumpHistoryEntryType.java | 378 --------- .../comm/history/pump/PumpHistoryEntryType.kt | 323 ++++++++ .../comm/history/pump/PumpHistoryResult.java | 177 ----- .../comm/history/pump/PumpHistoryResult.kt | 144 ++++ .../medtronic/data/dto/DailyTotalsDTO.java | 16 +- .../dialog/MedtronicHistoryActivity.java | 4 +- .../common/defs/PumpHistoryEntryGroup.java | 66 -- .../pump/common/defs/PumpHistoryEntryGroup.kt | 50 ++ .../plugins/pump/common/utils/ByteUtil.java | 69 +- 32 files changed, 2590 insertions(+), 2872 deletions(-) create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java.orig delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoder.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoder.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoderInterface.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoderInterface.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntry.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntry.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntryInterface.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntryInterface.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/RawHistoryPage.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/RawHistoryPage.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/RecordDecodeStatus.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/RecordDecodeStatus.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/CGMSHistoryEntry.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/CGMSHistoryEntry.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/CGMSHistoryEntryType.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/CGMSHistoryEntryType.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/MedtronicCGMSHistoryDecoder.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/MedtronicCGMSHistoryDecoder.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/MedtronicPumpHistoryDecoder.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/MedtronicPumpHistoryDecoder.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntryType.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntryType.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryResult.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryResult.kt delete mode 100644 rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpHistoryEntryGroup.java create mode 100644 rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpHistoryEntryGroup.kt diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java.orig b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java.orig new file mode 100644 index 0000000000..a0bffe268a --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java.orig @@ -0,0 +1,535 @@ +package info.nightscout.androidaps.plugins.pump.common; + +import static info.nightscout.androidaps.extensions.PumpStateExtensionKt.convertedToAbsolute; +import static info.nightscout.androidaps.extensions.PumpStateExtensionKt.getPlannedRemainingMinutes; + +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; + +import androidx.annotation.NonNull; + +import org.json.JSONException; +import org.json.JSONObject; + +<<<<<<< HEAD +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +======= +>>>>>>> meallink +import dagger.android.HasAndroidInjector; +import info.nightscout.androidaps.core.R; +import info.nightscout.androidaps.data.DetailedBolusInfo; +import info.nightscout.androidaps.data.Profile; +import info.nightscout.androidaps.data.PumpEnactResult; +import info.nightscout.androidaps.events.EventAppExit; +import info.nightscout.androidaps.events.EventCustomActionsChanged; +import info.nightscout.androidaps.extensions.PumpStateExtensionKt; +import info.nightscout.androidaps.interfaces.ActivePluginProvider; +import info.nightscout.androidaps.interfaces.CommandQueueProvider; +import info.nightscout.androidaps.interfaces.ConstraintsInterface; +import info.nightscout.androidaps.interfaces.PluginDescription; +import info.nightscout.androidaps.interfaces.PumpDescription; +import info.nightscout.androidaps.interfaces.PumpInterface; +import info.nightscout.androidaps.interfaces.PumpPluginBase; +import info.nightscout.androidaps.interfaces.PumpSync; +import info.nightscout.androidaps.logging.AAPSLogger; +import info.nightscout.androidaps.logging.LTag; +import info.nightscout.androidaps.plugins.bus.RxBusWrapper; +import info.nightscout.androidaps.plugins.common.ManufacturerType; +import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress; +import info.nightscout.androidaps.plugins.pump.common.data.PumpDbEntry; +import info.nightscout.androidaps.plugins.pump.common.data.PumpStatus; +import info.nightscout.androidaps.plugins.pump.common.defs.PumpDriverState; +import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; +import info.nightscout.androidaps.utils.DateUtil; +import info.nightscout.androidaps.utils.DecimalFormatter; +import info.nightscout.androidaps.utils.FabricPrivacy; +import info.nightscout.androidaps.utils.resources.ResourceHelper; +import info.nightscout.androidaps.utils.rx.AapsSchedulers; +import info.nightscout.androidaps.utils.sharedPreferences.SP; +import io.reactivex.disposables.CompositeDisposable; + +/** + * Created by andy on 23.04.18. + */ + +// When using this class, make sure that your first step is to create mConnection (see MedtronicPumpPlugin) + +public abstract class PumpPluginAbstract extends PumpPluginBase implements PumpInterface, ConstraintsInterface { + private final CompositeDisposable disposable = new CompositeDisposable(); + + protected HasAndroidInjector injector; + protected AAPSLogger aapsLogger; + protected RxBusWrapper rxBus; + protected ActivePluginProvider activePlugin; + protected Context context; + protected FabricPrivacy fabricPrivacy; + protected ResourceHelper resourceHelper; + protected CommandQueueProvider commandQueue; + protected SP sp; + protected DateUtil dateUtil; + protected PumpDescription pumpDescription = new PumpDescription(); + protected ServiceConnection serviceConnection; + protected boolean serviceRunning = false; + protected PumpDriverState pumpState = PumpDriverState.NotInitialized; + protected boolean displayConnectionMessages = false; + protected PumpType pumpType; + protected AapsSchedulers aapsSchedulers; + protected PumpSync pumpSync; +<<<<<<< HEAD + +======= +>>>>>>> meallink + + protected PumpPluginAbstract( + PluginDescription pluginDescription, + PumpType pumpType, + HasAndroidInjector injector, + ResourceHelper resourceHelper, + AAPSLogger aapsLogger, + CommandQueueProvider commandQueue, + RxBusWrapper rxBus, + ActivePluginProvider activePlugin, + SP sp, + Context context, + FabricPrivacy fabricPrivacy, + DateUtil dateUtil, + AapsSchedulers aapsSchedulers, + PumpSync pumpSync + ) { + + super(pluginDescription, injector, aapsLogger, resourceHelper, commandQueue); + this.aapsLogger = aapsLogger; + this.rxBus = rxBus; + this.activePlugin = activePlugin; + this.context = context; + this.fabricPrivacy = fabricPrivacy; + this.resourceHelper = resourceHelper; + this.sp = sp; + this.commandQueue = commandQueue; + + pumpDescription.setPumpDescription(pumpType); + this.pumpType = pumpType; + this.dateUtil = dateUtil; + this.aapsSchedulers = aapsSchedulers; + this.pumpSync = pumpSync; + } + + + public abstract void initPumpStatusData(); + + + @Override + protected void onStart() { + super.onStart(); + + initPumpStatusData(); + + Intent intent = new Intent(context, getServiceClass()); + context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); + + serviceRunning = true; + + disposable.add(rxBus + .toObservable(EventAppExit.class) + .observeOn(aapsSchedulers.getIo()) + .subscribe(event -> context.unbindService(serviceConnection), fabricPrivacy::logException) + ); + onStartCustomActions(); + } + + + @Override + protected void onStop() { + aapsLogger.debug(LTag.PUMP, this.deviceID() + " onStop()"); + + context.unbindService(serviceConnection); + + serviceRunning = false; + + disposable.clear(); + super.onStop(); + } + + + /** + * If we need to run any custom actions in onStart (triggering events, etc) + */ + public abstract void onStartCustomActions(); + + /** + * Service class (same one you did serviceConnection for) + * + * @return Class + */ + public abstract Class getServiceClass(); + + public abstract PumpStatus getPumpStatusData(); + + + public boolean isInitialized() { + return pumpState.isInitialized(); + } + + + public boolean isSuspended() { + return pumpState == PumpDriverState.Suspended; + } + + + public boolean isBusy() { + return pumpState == PumpDriverState.Busy; + } + + + public boolean isConnected() { + if (displayConnectionMessages) + aapsLogger.debug(LTag.PUMP, "isConnected [PumpPluginAbstract]."); + return pumpState.isConnected(); + } + + + public boolean isConnecting() { + if (displayConnectionMessages) + aapsLogger.debug(LTag.PUMP, "isConnecting [PumpPluginAbstract]."); + return pumpState == PumpDriverState.Connecting; + } + + + public void connect(@NonNull String reason) { + if (displayConnectionMessages) + aapsLogger.debug(LTag.PUMP, "connect (reason={}) [PumpPluginAbstract] - default (empty) implementation." + reason); + } + + + public void disconnect(@NonNull String reason) { + if (displayConnectionMessages) + aapsLogger.debug(LTag.PUMP, "disconnect (reason={}) [PumpPluginAbstract] - default (empty) implementation." + reason); + } + + + public void stopConnecting() { + if (displayConnectionMessages) + aapsLogger.debug(LTag.PUMP, "stopConnecting [PumpPluginAbstract] - default (empty) implementation."); + } + + + @Override + public boolean isHandshakeInProgress() { + if (displayConnectionMessages) + aapsLogger.debug(LTag.PUMP, "isHandshakeInProgress [PumpPluginAbstract] - default (empty) implementation."); + return false; + } + + + @Override + public void finishHandshaking() { + if (displayConnectionMessages) + aapsLogger.debug(LTag.PUMP, "finishHandshaking [PumpPluginAbstract] - default (empty) implementation."); + } + + // Upload to pump new basal profile + @NonNull public PumpEnactResult setNewBasalProfile(@NonNull Profile profile) { + aapsLogger.debug(LTag.PUMP, "setNewBasalProfile [PumpPluginAbstract] - Not implemented."); + return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); + } + + + public boolean isThisProfileSet(@NonNull Profile profile) { + aapsLogger.debug(LTag.PUMP, "isThisProfileSet [PumpPluginAbstract] - Not implemented."); + return true; + } + + + public long lastDataTime() { + aapsLogger.debug(LTag.PUMP, "lastDataTime [PumpPluginAbstract]."); + return getPumpStatusData().lastConnection; + } + + + public double getBaseBasalRate() { + aapsLogger.debug(LTag.PUMP, "getBaseBasalRate [PumpPluginAbstract] - Not implemented."); + return 0.0d; + } // base basal rate, not temp basal + + + public void stopBolusDelivering() { + aapsLogger.debug(LTag.PUMP, "stopBolusDelivering [PumpPluginAbstract] - Not implemented."); + } + + + @NonNull @Override + public PumpEnactResult setTempBasalAbsolute(double absoluteRate, int durationInMinutes, @NonNull Profile profile, boolean enforceNew, @NonNull PumpSync.TemporaryBasalType tbrType) { + aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute [PumpPluginAbstract] - Not implemented."); + return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); + } + + + @NonNull @Override + public PumpEnactResult setTempBasalPercent(int percent, int durationInMinutes, @NonNull Profile profile, boolean enforceNew, @NonNull PumpSync.TemporaryBasalType tbrType) { + aapsLogger.debug(LTag.PUMP, "setTempBasalPercent [PumpPluginAbstract] - Not implemented."); + return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); + } + + + @NonNull public PumpEnactResult setExtendedBolus(double insulin, int durationInMinutes) { + aapsLogger.debug(LTag.PUMP, "setExtendedBolus [PumpPluginAbstract] - Not implemented."); + return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); + } + + + // some pumps might set a very short temp close to 100% as cancelling a temp can be noisy + // when the cancel request is requested by the user (forced), the pump should always do a real cancel + + @NonNull public PumpEnactResult cancelTempBasal(boolean enforceNew) { + aapsLogger.debug(LTag.PUMP, "cancelTempBasal [PumpPluginAbstract] - Not implemented."); + return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); + } + + + @NonNull public PumpEnactResult cancelExtendedBolus() { + aapsLogger.debug(LTag.PUMP, "cancelExtendedBolus [PumpPluginAbstract] - Not implemented."); + return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); + } + + + // Status to be passed to NS + + // public JSONObject getJSONStatus(Profile profile, String profileName) { + // return pumpDriver.getJSONStatus(profile, profileName); + // } + + public String deviceID() { + aapsLogger.debug(LTag.PUMP, "deviceID [PumpPluginAbstract] - Not implemented."); + return "FakeDevice"; + } + + + // Pump capabilities + + @NonNull public PumpDescription getPumpDescription() { + return pumpDescription; + } + + + // Short info for SMS, Wear etc + + public boolean isFakingTempsByExtendedBoluses() { + aapsLogger.debug(LTag.PUMP, "isFakingTempsByExtendedBoluses [PumpPluginAbstract] - Not implemented."); + return false; + } + + + @NonNull @Override + public PumpEnactResult loadTDDs() { + aapsLogger.debug(LTag.PUMP, "loadTDDs [PumpPluginAbstract] - Not implemented."); + return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); + } + + + @NonNull @Override + public JSONObject getJSONStatus(@NonNull Profile profile, @NonNull String profileName, @NonNull String version) { + + if ((getPumpStatusData().lastConnection + 60 * 60 * 1000L) < System.currentTimeMillis()) { + return new JSONObject(); + } + + long now = System.currentTimeMillis(); + JSONObject pump = new JSONObject(); + JSONObject battery = new JSONObject(); + JSONObject status = new JSONObject(); + JSONObject extended = new JSONObject(); + try { + battery.put("percent", getPumpStatusData().batteryRemaining); + status.put("status", getPumpStatusData().pumpStatusType != null ? getPumpStatusData().pumpStatusType.getStatus() : "normal"); + extended.put("Version", version); + try { + extended.put("ActiveProfile", profileName); + } catch (Exception ignored) { + } + +<<<<<<< HEAD + // TODO fix + TemporaryBasal tb = activePlugin.getActiveTreatments().getTempBasalFromHistory(System.currentTimeMillis()); +======= + PumpSync.PumpState.TemporaryBasal tb = pumpSync.expectedPumpState().getTemporaryBasal(); +>>>>>>> meallink + if (tb != null) { + extended.put("TempBasalAbsoluteRate", convertedToAbsolute(tb, now, profile)); + extended.put("TempBasalStart", dateUtil.dateAndTimeString(tb.getTimestamp())); + extended.put("TempBasalRemaining", getPlannedRemainingMinutes(tb)); + } + +<<<<<<< HEAD + // TODO fix + ExtendedBolus eb = activePlugin.getActiveTreatments().getExtendedBolusFromHistory(System.currentTimeMillis()); +======= + PumpSync.PumpState.ExtendedBolus eb = pumpSync.expectedPumpState().getExtendedBolus(); +>>>>>>> meallink + if (eb != null) { + extended.put("ExtendedBolusAbsoluteRate", eb.getRate()); + extended.put("ExtendedBolusStart", dateUtil.dateAndTimeString(eb.getTimestamp())); + extended.put("ExtendedBolusRemaining", getPlannedRemainingMinutes(eb)); + } + + status.put("timestamp", dateUtil.toISOString(dateUtil.now())); + + pump.put("battery", battery); + pump.put("status", status); + pump.put("extended", extended); + pump.put("reservoir", getPumpStatusData().reservoirRemainingUnits); + pump.put("clock", dateUtil.toISOString(dateUtil.now())); + } catch (JSONException e) { + aapsLogger.error("Unhandled exception", e); + } + return pump; + } + + + // FIXME i18n, null checks: iob, TDD + @NonNull @Override + public String shortStatus(boolean veryShort) { + String ret = ""; + if (getPumpStatusData().lastConnection != 0) { + long agoMsec = System.currentTimeMillis() - getPumpStatusData().lastConnection; + int agoMin = (int) (agoMsec / 60d / 1000d); + ret += "LastConn: " + agoMin + " min ago\n"; + } + if (getPumpStatusData().lastBolusTime != null && getPumpStatusData().lastBolusTime.getTime() != 0) { + ret += "LastBolus: " + DecimalFormatter.INSTANCE.to2Decimal(getPumpStatusData().lastBolusAmount) + "U @" + // + android.text.format.DateFormat.format("HH:mm", getPumpStatusData().lastBolusTime) + "\n"; + } +<<<<<<< HEAD + // TODO fix + TemporaryBasal activeTemp = activePlugin.getActiveTreatments().getRealTempBasalFromHistory(System.currentTimeMillis()); +======= + PumpSync.PumpState.TemporaryBasal activeTemp = pumpSync.expectedPumpState().getTemporaryBasal(); +>>>>>>> meallink + if (activeTemp != null) { + ret += "Temp: " + PumpStateExtensionKt.toStringFull(activeTemp, dateUtil) + "\n"; + } +<<<<<<< HEAD + // TODO fix + ExtendedBolus activeExtendedBolus = activePlugin.getActiveTreatments().getExtendedBolusFromHistory( + System.currentTimeMillis()); +======= + PumpSync.PumpState.ExtendedBolus activeExtendedBolus = pumpSync.expectedPumpState().getExtendedBolus(); +>>>>>>> meallink + if (activeExtendedBolus != null) { + ret += "Extended: " + PumpStateExtensionKt.toStringFull(activeExtendedBolus, dateUtil) + "\n"; + } + // if (!veryShort) { + // ret += "TDD: " + DecimalFormatter.to0Decimal(pumpStatus.dailyTotalUnits) + " / " + // + pumpStatus.maxDailyTotalUnits + " U\n"; + // } + ret += "IOB: " + getPumpStatusData().iob + "U\n"; + ret += "Reserv: " + DecimalFormatter.INSTANCE.to0Decimal(getPumpStatusData().reservoirRemainingUnits) + "U\n"; + ret += "Batt: " + getPumpStatusData().batteryRemaining + "\n"; + return ret; + } + + + @NonNull @Override + public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) { + + try { + if (detailedBolusInfo.insulin == 0 && detailedBolusInfo.carbs == 0) { + // neither carbs nor bolus requested + aapsLogger.error("deliverTreatment: Invalid input"); + return new PumpEnactResult(getInjector()).success(false).enacted(false).bolusDelivered(0d).carbsDelivered(0d) + .comment(R.string.invalidinput); + } else if (detailedBolusInfo.insulin > 0) { + // bolus needed, ask pump to deliver it + return deliverBolus(detailedBolusInfo); + } else { + //if (MedtronicHistoryData.doubleBolusDebug) + // aapsLogger.debug("DoubleBolusDebug: deliverTreatment::(carb only entry)"); + + // TODO fix + // no bolus required, carb only treatment + activePlugin.getActiveTreatments().addToHistoryTreatment(detailedBolusInfo, true); + + EventOverviewBolusProgress bolusingEvent = EventOverviewBolusProgress.INSTANCE; + bolusingEvent.setT(new EventOverviewBolusProgress.Treatment(0, 0, detailedBolusInfo.getBolusType() == DetailedBolusInfo.BolusType.SMB)); + bolusingEvent.setPercent(100); + rxBus.send(bolusingEvent); + + aapsLogger.debug(LTag.PUMP, "deliverTreatment: Carb only treatment."); + + return new PumpEnactResult(getInjector()).success(true).enacted(true).bolusDelivered(0d) + .carbsDelivered(detailedBolusInfo.carbs).comment(R.string.common_resultok); + } + } finally { + triggerUIChange(); + } + + } + + + protected void refreshCustomActionsList() { + rxBus.send(new EventCustomActionsChanged()); + } + + + @NonNull public ManufacturerType manufacturer() { + return pumpType.getManufacturer(); + } + + @NonNull + public PumpType model() { + return pumpType; + } + + + public PumpType getPumpType() { + return pumpType; + } + + + public void setPumpType(PumpType pumpType) { + this.pumpType = pumpType; + this.pumpDescription.setPumpDescription(pumpType); + } + + + public boolean canHandleDST() { + return false; + } + + + protected abstract PumpEnactResult deliverBolus(DetailedBolusInfo detailedBolusInfo); + + protected abstract void triggerUIChange(); + + private PumpEnactResult getOperationNotSupportedWithCustomText(int resourceId) { + return new PumpEnactResult(getInjector()).success(false).enacted(false).comment(resourceId); + } + + // PumpSync + + Map driverHistory = new HashMap<>(); + + public abstract long generateTempId(long timeMillis); + + public boolean addBolusWithTempId(DetailedBolusInfo detailedBolusInfo, boolean writeToInternalHistory) { + long temporaryId = generateTempId(detailedBolusInfo.timestamp); + boolean response = pumpSync.addBolusWithTempId(detailedBolusInfo.timestamp, detailedBolusInfo.insulin, + generateTempId(detailedBolusInfo.timestamp), detailedBolusInfo.getBolusType(), + getPumpType(), serialNumber()); + + if (response && writeToInternalHistory) { + driverHistory.put(temporaryId, new PumpDbEntry(temporaryId, model(), serialNumber(), detailedBolusInfo)); + } + + return response; + } + + public void removeTemporaryId(long temporaryId) { + driverHistory.remove(temporaryId); + } + + +} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoder.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoder.java deleted file mode 100644 index 2b33249503..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoder.java +++ /dev/null @@ -1,182 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.history; - -import org.apache.commons.lang3.StringUtils; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -import javax.inject.Inject; - -import info.nightscout.androidaps.logging.AAPSLogger; -import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil; -import info.nightscout.androidaps.plugins.pump.common.utils.StringUtil; -import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil; - - -/** - * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes - * management and modified/extended for AAPS. - *

- * Author: Andy {andy.rozman@gmail.com} - */ - -public abstract class MedtronicHistoryDecoder implements MedtronicHistoryDecoderInterface { - - @Inject protected AAPSLogger aapsLogger; - @Inject protected MedtronicUtil medtronicUtil; - - protected ByteUtil bitUtils; - - // STATISTICS (remove at later time or not) - protected boolean statisticsEnabled = true; - protected Map unknownOpCodes; - protected Map> mapStatistics; - - - public MedtronicHistoryDecoder() { - } - - - // public abstract Class getHistoryEntryClass(); - - // public abstract RecordDecodeStatus decodeRecord(T record); - - public abstract void postProcess(); - - - protected abstract void runPostDecodeTasks(); - - - // TODO_ extend this to also use bigger pages (for now we support only 1024 pages) - private List checkPage(RawHistoryPage page, boolean partial) throws RuntimeException { - List byteList = new ArrayList(); - - // if (!partial && page.getData().length != 1024 /* page.commandType.getRecordLength() */) { - // LOG.error("Page size is not correct. Size should be {}, but it was {} instead.", 1024, - // page.getData().length); - // // throw exception perhaps - // return byteList; - // } - - if (medtronicUtil.getMedtronicPumpModel() == null) { - aapsLogger.error(LTag.PUMPCOMM, "Device Type is not defined."); - return byteList; - } - - if (page.getData().length != 1024) { - return ByteUtil.getListFromByteArray(page.getData()); - } else if (page.isChecksumOK()) { - return ByteUtil.getListFromByteArray(page.getOnlyData()); - } else { - return null; - } - } - - - public List processPageAndCreateRecords(RawHistoryPage rawHistoryPage) { - return processPageAndCreateRecords(rawHistoryPage, false); - } - - - protected void prepareStatistics() { - if (!statisticsEnabled) - return; - - unknownOpCodes = new HashMap<>(); - mapStatistics = new HashMap<>(); - - for (RecordDecodeStatus stat : RecordDecodeStatus.values()) { - mapStatistics.put(stat, new HashMap<>()); - } - } - - - protected void addToStatistics(MedtronicHistoryEntryInterface pumpHistoryEntry, RecordDecodeStatus status, Integer opCode) { - if (!statisticsEnabled) - return; - - if (opCode != null) { - if (!unknownOpCodes.containsKey(opCode)) { - unknownOpCodes.put(opCode, opCode); - } - return; - } - - if (!mapStatistics.get(status).containsKey(pumpHistoryEntry.getEntryTypeName())) { - mapStatistics.get(status).put(pumpHistoryEntry.getEntryTypeName(), ""); - } - } - - - protected void showStatistics() { - StringBuilder sb = new StringBuilder(); - - for (Map.Entry unknownEntry : unknownOpCodes.entrySet()) { - StringUtil.appendToStringBuilder(sb, "" + unknownEntry.getKey(), ", "); - } - - aapsLogger.info(LTag.PUMPCOMM, "STATISTICS OF PUMP DECODE"); - - if (unknownOpCodes.size() > 0) { - aapsLogger.warn(LTag.PUMPCOMM, "Unknown Op Codes: " + sb.toString()); - } - - for (Map.Entry> entry : mapStatistics.entrySet()) { - sb = new StringBuilder(); - - if (entry.getKey() != RecordDecodeStatus.OK) { - if (entry.getValue().size() == 0) - continue; - - for (Map.Entry entrysub : entry.getValue().entrySet()) { - StringUtil.appendToStringBuilder(sb, entrysub.getKey(), ", "); - } - - String spaces = StringUtils.repeat(" ", 14 - entry.getKey().name().length()); - - aapsLogger.info(LTag.PUMPCOMM, String.format(Locale.ENGLISH, " %s%s - %d. Elements: %s", entry.getKey().name(), spaces, entry.getValue().size(), sb.toString())); - } else { - aapsLogger.info(LTag.PUMPCOMM, String.format(Locale.ENGLISH, " %s - %d", entry.getKey().name(), entry.getValue().size())); - } - } - } - - - private int getUnsignedByte(byte value) { - if (value < 0) - return value + 256; - else - return value; - } - - - protected int getUnsignedInt(int value) { - if (value < 0) - return value + 256; - else - return value; - } - - - public String getFormattedFloat(float value, int decimals) { - return StringUtil.getFormatedValueUS(value, decimals); - } - - - private List processPageAndCreateRecords(RawHistoryPage rawHistoryPage, boolean partial) { - List dataClear = checkPage(rawHistoryPage, partial); - List records = createRecords(dataClear); - - for (T record : records) { - decodeRecord(record); - } - - runPostDecodeTasks(); - - return records; - } -} 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 new file mode 100644 index 0000000000..a6a8744299 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoder.kt @@ -0,0 +1,132 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.history + +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil +import info.nightscout.androidaps.plugins.pump.common.utils.StringUtil +import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil +import org.apache.commons.lang3.StringUtils +import java.util.* +import javax.inject.Inject +import kotlin.jvm.Throws + +/** + * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes + * management and modified/extended for AAPS. + * + * + * Author: Andy {andy.rozman@gmail.com} + */ +abstract class MedtronicHistoryDecoder : MedtronicHistoryDecoderInterface { + + @JvmField @Inject + var aapsLogger: AAPSLogger? = null + + @JvmField @Inject + var medtronicUtil: MedtronicUtil? = null + protected var bitUtils: ByteUtil? = null + + // STATISTICS (remove at later time or not) + protected var statisticsEnabled = true + @JvmField protected var unknownOpCodes: MutableMap? = null + protected var mapStatistics: MutableMap>? = null + + // public abstract Class getHistoryEntryClass(); + // public abstract RecordDecodeStatus decodeRecord(T record); + abstract fun postProcess() + protected abstract fun runPostDecodeTasks() + + // 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() + + if (medtronicUtil!!.medtronicPumpModel == null) { + aapsLogger!!.error(LTag.PUMPCOMM, "Device Type is not defined.") + return byteList + } + return if (page.data.size != 1024) { + ByteUtil.getListFromByteArray(page.data) + } else if (page.isChecksumOK) { + ByteUtil.getListFromByteArray(page.onlyData) + } else { + byteList + } + } + + fun processPageAndCreateRecords(rawHistoryPage: RawHistoryPage): List? { + return processPageAndCreateRecords(rawHistoryPage, false) + } + + protected fun prepareStatistics() { + if (!statisticsEnabled) return + unknownOpCodes = HashMap() + mapStatistics = HashMap() + for (stat in RecordDecodeStatus.values()) { + (mapStatistics as HashMap>)[stat] = HashMap() + } + } + + protected fun addToStatistics(pumpHistoryEntry: MedtronicHistoryEntryInterface, status: RecordDecodeStatus?, opCode: Int?) { + if (!statisticsEnabled) return + if (opCode != null) { + if (!unknownOpCodes!!.containsKey(opCode)) { + unknownOpCodes!![opCode] = opCode + } + return + } + if (!mapStatistics!![status]!!.containsKey(pumpHistoryEntry.entryTypeName)) { + mapStatistics!![status]!!.put(pumpHistoryEntry.entryTypeName!!, "") + } + } + + protected fun showStatistics() { + var sb = StringBuilder() + for ((key) in unknownOpCodes!!) { + StringUtil.appendToStringBuilder(sb, "" + key, ", ") + } + aapsLogger!!.info(LTag.PUMPCOMM, "STATISTICS OF PUMP DECODE") + if (unknownOpCodes!!.size > 0) { + aapsLogger!!.warn(LTag.PUMPCOMM, "Unknown Op Codes: $sb") + } + for ((key, value) in mapStatistics!!) { + sb = StringBuilder() + if (key !== RecordDecodeStatus.OK) { + if (value.size == 0) continue + for ((key1) in value) { + StringUtil.appendToStringBuilder(sb, key1, ", ") + } + val spaces = StringUtils.repeat(" ", 14 - key.name.length) + aapsLogger!!.info(LTag.PUMPCOMM, String.format(Locale.ENGLISH, " %s%s - %d. Elements: %s", key.name, spaces, value.size, sb.toString())) + } else { + aapsLogger!!.info(LTag.PUMPCOMM, String.format(Locale.ENGLISH, " %s - %d", key.name, value.size)) + } + } + } + + private fun getUnsignedByte(value: Byte): Int { + return if (value < 0) value + 256 else value.toInt() + } + + protected fun getUnsignedInt(value: Int): Int { + return if (value < 0) value + 256 else value + } + + protected fun getUnsignedInt(value: Byte): Int { + return if (value < 0) value + 256 else value.toInt() + } + + fun getFormattedFloat(value: Float, decimals: Int): String { + return StringUtil.getFormatedValueUS(value, decimals) + } + + private fun processPageAndCreateRecords(rawHistoryPage: RawHistoryPage, partial: Boolean): List { + val dataClear = checkPage(rawHistoryPage, partial) + val records: List = createRecords(dataClear) + for (record in records!!) { + decodeRecord(record) + } + runPostDecodeTasks() + return records + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoderInterface.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoderInterface.java deleted file mode 100644 index b98b2d7d33..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoderInterface.java +++ /dev/null @@ -1,15 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.history; - -import java.util.List; - -/** - * Created by andy on 3/10/19. - */ - -public interface MedtronicHistoryDecoderInterface { - - RecordDecodeStatus decodeRecord(T record); - - List createRecords(List dataClear); - -} 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 new file mode 100644 index 0000000000..1137371843 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoderInterface.kt @@ -0,0 +1,10 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.history + +/** + * Created by andy on 3/10/19. + */ +interface MedtronicHistoryDecoderInterface { + + fun decodeRecord(record: T): RecordDecodeStatus? + fun createRecords(dataClear: List): List +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntry.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntry.java deleted file mode 100644 index b5d41f6bfa..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntry.java +++ /dev/null @@ -1,316 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.history; - -import com.google.gson.annotations.Expose; - -import org.slf4j.Logger; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import info.nightscout.androidaps.logging.StacktraceLoggerWrapper; -import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil; -import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil; -import info.nightscout.androidaps.plugins.pump.common.utils.StringUtil; - -/** - * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes - * management and modified/extended for AAPS. - *

- * Author: Andy {andy.rozman@gmail.com} - */ - -public abstract class MedtronicHistoryEntry implements MedtronicHistoryEntryInterface { - - protected List rawData; - - public static final Logger LOG = StacktraceLoggerWrapper.getLogger(MedtronicHistoryEntry.class); - - protected int[] sizes = new int[3]; - - protected byte[] head; - protected byte[] datetime; - protected byte[] body; - - // protected LocalDateTime dateTime; - - public long id; - - @Expose - public String DT; - - @Expose - public Long atechDateTime; - - @Expose - protected Map decodedData; - - public long phoneDateTime; // time on phone - - /** - * Pump id that will be used with AAPS object (time * 1000 + historyType (max is FF = 255) - */ - protected Long pumpId; - - /** - * if history object is already linked to AAPS object (either Treatment, TempBasal or TDD (tdd's - * are not actually - * linked)) - */ - public boolean linked = false; - - /** - * Linked object, see linked - */ - public Object linkedObject = null; - - - public void setLinkedObject(Object linkedObject) { - this.linked = true; - this.linkedObject = linkedObject; - } - - - public void setData(List listRawData, boolean doNotProcess) { - this.rawData = listRawData; - - // System.out.println("Head: " + sizes[0] + ", dates: " + sizes[1] + - // ", body=" + sizes[2]); - - if (doNotProcess) - return; - - head = new byte[getHeadLength() - 1]; - for (int i = 1; i < (getHeadLength()); i++) { - head[i - 1] = listRawData.get(i); - } - - if (getDateTimeLength() > 0) { - datetime = new byte[getDateTimeLength()]; - - for (int i = getHeadLength(), j = 0; j < getDateTimeLength(); i++, j++) { - datetime[j] = listRawData.get(i); - } - } - - if (getBodyLength() > 0) { - body = new byte[getBodyLength()]; - - for (int i = (getHeadLength() + getDateTimeLength()), j = 0; j < getBodyLength(); i++, j++) { - body[j] = listRawData.get(i); - } - - } - - } - - - public String getDateTimeString() { - return this.DT == null ? "Unknown" : this.DT; - } - - - public String getDecodedDataAsString() { - if (decodedData == null) - if (isNoDataEntry()) - return "No data"; - else - return ""; - else - return decodedData.toString(); - } - - - public boolean hasData() { - return (decodedData != null) || (isNoDataEntry()) || getEntryTypeName().equals("UnabsorbedInsulin"); - } - - - public boolean isNoDataEntry() { - return (sizes[0] == 2 && sizes[1] == 5 && sizes[2] == 0); - } - - - public Map getDecodedData() { - return this.decodedData; - } - - - public Object getDecodedDataEntry(String key) { - return this.decodedData != null ? this.decodedData.get(key) : null; - } - - - public boolean hasDecodedDataEntry(String key) { - return this.decodedData.containsKey(key); - } - - - public boolean showRaw() { - return getEntryTypeName().equals("EndResultTotals"); - } - - - public int getHeadLength() { - return sizes[0]; - } - - - public int getDateTimeLength() { - return sizes[1]; - } - - - public int getBodyLength() { - return sizes[2]; - } - - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - - if (this.DT == null) { - LOG.error("DT is null. RawData=" + ByteUtil.getHex(this.rawData)); - } - - sb.append(getToStringStart()); - sb.append(", DT: " + (this.DT == null ? "null" : StringUtil.getStringInLength(this.DT, 19))); - sb.append(", length="); - sb.append(getHeadLength()); - sb.append(","); - sb.append(getDateTimeLength()); - sb.append(","); - sb.append(getBodyLength()); - sb.append("("); - sb.append((getHeadLength() + getDateTimeLength() + getBodyLength())); - sb.append(")"); - - boolean hasData = hasData(); - - if (hasData) { - sb.append(", data=" + getDecodedDataAsString()); - } - - if (hasData && !showRaw()) { - sb.append("]"); - return sb.toString(); - } - - if (head != null) { - sb.append(", head="); - sb.append(ByteUtil.shortHexString(this.head)); - } - - if (datetime != null) { - sb.append(", datetime="); - sb.append(ByteUtil.shortHexString(this.datetime)); - } - - if (body != null) { - sb.append(", body="); - sb.append(ByteUtil.shortHexString(this.body)); - } - - sb.append(", rawData="); - sb.append(ByteUtil.shortHexString(this.rawData)); - sb.append("]"); - - // sb.append(" DT: "); - // sb.append(this.dateTime == null ? " - " : this.dateTime.toString("dd.MM.yyyy HH:mm:ss")); - - // sb.append(" Ext: "); - - return sb.toString(); - } - - - public abstract int getOpCode(); - - - public abstract String getToStringStart(); - - - public List getRawData() { - return rawData; - } - - - public byte getRawDataByIndex(int index) { - return rawData.get(index); - } - - - public int getUnsignedRawDataByIndex(int index) { - return ByteUtil.convertUnsignedByteToInt(rawData.get(index)); - } - - - public void setRawData(List rawData) { - this.rawData = rawData; - } - - - public byte[] getHead() { - return head; - } - - - public void setHead(byte[] head) { - this.head = head; - } - - - public byte[] getDatetime() { - return datetime; - } - - - public void setDatetime(byte[] datetime) { - this.datetime = datetime; - } - - - public byte[] getBody() { - return body; - } - - - public void setBody(byte[] body) { - this.body = body; - } - - - public void setAtechDateTime(long dt) { - this.atechDateTime = dt; - this.DT = DateTimeUtil.toString(this.atechDateTime); - } - - - public void addDecodedData(String key, Object value) { - if (decodedData == null) - decodedData = new HashMap<>(); - - decodedData.put(key, value); - } - - - public String toShortString() { - if (head == null) { - return "Unidentified record. "; - } else { - return "HistoryRecord: head=[" + ByteUtil.shortHexString(this.head) + "]"; - } - } - - public boolean containsDecodedData(String key) { - if (decodedData == null) - return false; - - return decodedData.containsKey(key); - } - - // if we extend to CGMS this need to be changed back - // public abstract PumpHistoryEntryType getEntryType(); - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntry.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntry.kt new file mode 100644 index 0000000000..72e3174178 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntry.kt @@ -0,0 +1,222 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.history + +import android.util.Log +import com.google.gson.annotations.Expose +import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil +import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil +import info.nightscout.androidaps.plugins.pump.common.utils.StringUtil +import java.util.* + +/** + * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes + * management and modified/extended for AAPS. + * + * + * Author: Andy {andy.rozman@gmail.com} + */ +abstract class MedtronicHistoryEntry : MedtronicHistoryEntryInterface { + + @JvmField var rawData: List? = null + @JvmField protected var sizes = IntArray(3) + var head: ByteArray? = null + var datetime: ByteArray? = null + var body: ByteArray? = null + + // protected LocalDateTime dateTime; + @JvmField var id: Long = 0 + + @JvmField @Expose + var DT: String? = null + + @JvmField @Expose + var atechDateTime: Long? = null + + @Expose + protected var decodedData: MutableMap? = null + var phoneDateTime // time on phone + : Long = 0 + + /** + * Pump id that will be used with AAPS object (time * 1000 + historyType (max is FF = 255) + */ + protected open var pumpId: Long? = null + + /** + * if history object is already linked to AAPS object (either Treatment, TempBasal or TDD (tdd's + * are not actually + * linked)) + */ + var linked = false + + /** + * Linked object, see linked + */ + var linkedObject: Any? = null + get() = field //= linkedObject + set(value) { + linked = true + field = value + } + + // fun setLinkedObject(linkedObject: Any?) { + // linked = true + // this.linkedObject = linkedObject + // } + + override fun setData(listRawData: List?, doNotProcess: Boolean) { + rawData = listRawData + + // System.out.println("Head: " + sizes[0] + ", dates: " + sizes[1] + + // ", body=" + sizes[2]); + if (!doNotProcess) { + head = ByteArray(headLength - 1) + for (i in 1 until headLength) { + head!![i - 1] = listRawData!![i]!! + } + if (dateTimeLength > 0) { + datetime = ByteArray(dateTimeLength) + var i = headLength + var j = 0 + while (j < dateTimeLength) { + datetime!![j] = listRawData!![i]!! + i++ + j++ + } + } + if (bodyLength > 0) { + body = ByteArray(bodyLength) + var i = headLength + dateTimeLength + var j = 0 + while (j < bodyLength) { + body!![j] = listRawData!![i]!! + i++ + j++ + } + } + } + return + } + + val dateTimeString: String + get() = if (DT == null) "Unknown" else DT!! + + val decodedDataAsString: String + get() = if (decodedData == null) if (isNoDataEntry) "No data" else "" else decodedData.toString() + + fun hasData(): Boolean { + return decodedData != null || isNoDataEntry || entryTypeName == "UnabsorbedInsulin" + } + + val isNoDataEntry: Boolean + get() = sizes[0] == 2 && sizes[1] == 5 && sizes[2] == 0 + + // fun getDecodedData(): Map? { + // return decodedData + // } + + fun getDecodedDataEntry(key: String?): Any? { + return if (decodedData != null) decodedData!![key] else null + } + + fun hasDecodedDataEntry(key: String?): Boolean { + return decodedData!!.containsKey(key) + } + + fun showRaw(): Boolean { + return entryTypeName == "EndResultTotals" + } + + val headLength: Int + get() = sizes[0] + + val dateTimeLength: Int + get() = sizes[1] + + val bodyLength: Int + get() = sizes[2] + + override fun toString(): String { + val sb = StringBuilder() + if (DT == null) { + Log.e("", "DT is null. RawData=" + ByteUtil.getHex(rawData)) + } + sb.append(toStringStart) + sb.append(", DT: " + if (DT == null) "null" else StringUtil.getStringInLength(DT, 19)) + sb.append(", length=") + sb.append(headLength) + sb.append(",") + sb.append(dateTimeLength) + sb.append(",") + sb.append(bodyLength) + sb.append("(") + sb.append(headLength + dateTimeLength + bodyLength) + sb.append(")") + val hasData = hasData() + if (hasData) { + sb.append(", data=$decodedDataAsString") + } + if (hasData && !showRaw()) { + sb.append("]") + return sb.toString() + } + if (head != null) { + sb.append(", head=") + sb.append(ByteUtil.shortHexString(head)) + } + if (datetime != null) { + sb.append(", datetime=") + sb.append(ByteUtil.shortHexString(datetime)) + } + if (body != null) { + sb.append(", body=") + sb.append(ByteUtil.shortHexString(body)) + } + sb.append(", rawData=") + sb.append(ByteUtil.shortHexString(rawData)) + sb.append("]") + + // sb.append(" DT: "); + // sb.append(this.dateTime == null ? " - " : this.dateTime.toString("dd.MM.yyyy HH:mm:ss")); + + // sb.append(" Ext: "); + return sb.toString() + } + + abstract val opCode: Byte? + abstract val toStringStart: String? + + fun getRawDataByIndex(index: Int): Byte { + return rawData!![index] + } + + fun getRawDataByIndexInt(index: Int): Int { + return rawData!![index].toInt() + } + + fun getUnsignedRawDataByIndex(index: Int): Int { + return ByteUtil.convertUnsignedByteToInt(rawData!![index]) + } + + fun setAtechDateTime(dt: Long) { + atechDateTime = dt + DT = DateTimeUtil.toString(atechDateTime!!) + } + + fun addDecodedData(key: String, value: Any?) { + if (decodedData == null) decodedData = HashMap() + decodedData!![key] = value + } + + fun toShortString(): String { + return if (head == null) { + "Unidentified record. " + } else { + "HistoryRecord: head=[" + ByteUtil.shortHexString(head) + "]" + } + } + + fun containsDecodedData(key: String?): Boolean { + return if (decodedData == null) false else decodedData!!.containsKey(key) + } // if we extend to CGMS this need to be changed back + // public abstract PumpHistoryEntryType getEntryType(); +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntryInterface.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntryInterface.java deleted file mode 100644 index 38b7e1dbeb..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntryInterface.java +++ /dev/null @@ -1,16 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.history; - -import java.util.List; - -/** - * Created by andy on 7/24/18. - */ -public interface MedtronicHistoryEntryInterface { - - String getEntryTypeName(); - - void setData(List listRawData, boolean doNotProcess); - - int getDateLength(); - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntryInterface.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntryInterface.kt new file mode 100644 index 0000000000..32f6d4458a --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntryInterface.kt @@ -0,0 +1,11 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.history + +/** + * Created by andy on 7/24/18. + */ +interface MedtronicHistoryEntryInterface { + + val entryTypeName: String? + fun setData(listRawData: List?, doNotProcess: Boolean) + val dateLength: Int +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/RawHistoryPage.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/RawHistoryPage.java deleted file mode 100644 index 182e09b1bd..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/RawHistoryPage.java +++ /dev/null @@ -1,87 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.history; - -import java.util.Arrays; -import java.util.Locale; - -import info.nightscout.androidaps.logging.AAPSLogger; -import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil; -import info.nightscout.androidaps.plugins.pump.common.utils.CRC; -import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil; - -/** - * Created by geoff on 6/4/16. - */ -public class RawHistoryPage { - - private final AAPSLogger aapsLogger; - - private byte[] data = new byte[0]; - - - public RawHistoryPage(AAPSLogger aapsLogger) { - this.aapsLogger = aapsLogger; - } - - - public void appendData(byte[] newdata) { - data = ByteUtil.concat(data, newdata); - } - - - public byte[] getData() { - return data; - } - - - byte[] getOnlyData() { - return Arrays.copyOfRange(data, 0, 1022); - } - - - public int getLength() { - return data.length; - } - - - public boolean isChecksumOK() { - if (getLength() != 1024) { - return false; - } - byte[] computedCRC = CRC.calculate16CCITT(ByteUtil.substring(data, 0, 1022)); - - int crcCalculated = ByteUtil.toInt(computedCRC[0], computedCRC[1]); - int crcStored = ByteUtil.toInt(data[1022], data[1023]); - - if (crcCalculated != crcStored) { - aapsLogger.error(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, "Stored CRC (%d) is different than calculated (%d), but ignored for now.", crcStored, - crcCalculated)); - } else { - if (MedtronicUtil.isLowLevelDebug()) - aapsLogger.debug(LTag.PUMPBTCOMM, "CRC ok."); - } - - return crcCalculated == crcStored; - } - - - public void dumpToDebug() { - int linesize = 80; - int offset = 0; - - StringBuilder sb = new StringBuilder(); - - while (offset < data.length) { - int bytesToLog = linesize; - if (offset + linesize > data.length) { - bytesToLog = data.length - offset; - } - sb.append(ByteUtil.shortHexString(ByteUtil.substring(data, offset, bytesToLog)) + " "); - // sb.append("\n"); - - offset += linesize; - } - - aapsLogger.info(LTag.PUMPBTCOMM, "History Page Data:\n" + sb.toString()); - } -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/RawHistoryPage.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/RawHistoryPage.kt new file mode 100644 index 0000000000..792120b688 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/RawHistoryPage.kt @@ -0,0 +1,61 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.history + +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil +import info.nightscout.androidaps.plugins.pump.common.utils.CRC +import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil +import java.util.* + +/** + * Created by geoff on 6/4/16. + */ +class RawHistoryPage(private val aapsLogger: AAPSLogger) { + + var data = ByteArray(0) + private set + + fun appendData(newdata: ByteArray?) { + data = ByteUtil.concat(data, newdata) + } + + val onlyData: ByteArray + get() = Arrays.copyOfRange(data, 0, 1022) + + val length: Int + get() = data.size + + val isChecksumOK: Boolean + get() { + if (length != 1024) { + return false + } + val computedCRC = CRC.calculate16CCITT(ByteUtil.substring(data, 0, 1022)) + val crcCalculated = ByteUtil.toInt(computedCRC[0].toInt(), computedCRC[1].toInt()) + val crcStored = ByteUtil.toInt(data[1022].toInt(), data[1023].toInt()) + if (crcCalculated != crcStored) { + aapsLogger.error(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, "Stored CRC (%d) is different than calculated (%d), but ignored for now.", crcStored, + crcCalculated)) + } else { + if (MedtronicUtil.isLowLevelDebug()) aapsLogger.debug(LTag.PUMPBTCOMM, "CRC ok.") + } + return crcCalculated == crcStored + } + + fun dumpToDebug() { + val linesize = 80 + var offset = 0 + val sb = StringBuilder() + while (offset < data.size) { + var bytesToLog = linesize + if (offset + linesize > data.size) { + bytesToLog = data.size - offset + } + sb.append(ByteUtil.shortHexString(ByteUtil.substring(data, offset, bytesToLog)) + " ") + // sb.append("\n"); + offset += linesize + } + aapsLogger.info(LTag.PUMPBTCOMM, "History Page Data:\n$sb") + } + +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/RecordDecodeStatus.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/RecordDecodeStatus.java deleted file mode 100644 index 18cb02cfad..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/RecordDecodeStatus.java +++ /dev/null @@ -1,30 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.history; - -/** - * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes - * management and modified/extended for AAPS. - * - * Author: Andy {andy.rozman@gmail.com} - */ - -public enum RecordDecodeStatus { - OK("OK "), // - Ignored("IGNORE "), // - NotSupported("N/A YET"), // - Error("ERROR "), // - WIP("WIP "), // - Unknown("UNK "); - - String description; - - - RecordDecodeStatus(String description) { - this.description = description; - - } - - - public String getDescription() { - return description; - } -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/RecordDecodeStatus.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/RecordDecodeStatus.kt new file mode 100644 index 0000000000..82194b1f03 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/RecordDecodeStatus.kt @@ -0,0 +1,19 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.history + +/** + * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes + * management and modified/extended for AAPS. + * + * + * Author: Andy {andy.rozman@gmail.com} + */ +enum class RecordDecodeStatus(var description: String) { + + OK("OK "), // + Ignored("IGNORE "), // + NotSupported("N/A YET"), // + Error("ERROR "), // + WIP("WIP "), // + Unknown("UNK "); + +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/CGMSHistoryEntry.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/CGMSHistoryEntry.java deleted file mode 100644 index 4d35426fb8..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/CGMSHistoryEntry.java +++ /dev/null @@ -1,92 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.history.cgms; - -import org.apache.commons.lang3.StringUtils; -import org.joda.time.LocalDateTime; - -import java.util.List; - -import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil; -import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.MedtronicHistoryEntry; - -/** - * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes - * management and modified/extended for AAPS. - * - * Author: Andy {andy.rozman@gmail.com} - */ - -public class CGMSHistoryEntry extends MedtronicHistoryEntry { - - private CGMSHistoryEntryType entryType; - private Integer opCode; // this is set only when we have unknown entry... - - - public CGMSHistoryEntryType getEntryType() { - return entryType; - } - - - public void setEntryType(CGMSHistoryEntryType entryType) { - this.entryType = entryType; - - this.sizes[0] = entryType.getHeadLength(); - this.sizes[1] = entryType.getDateLength(); - this.sizes[2] = entryType.getBodyLength(); - } - - - @Override - public String getEntryTypeName() { - return this.entryType.name(); - } - - - public void setData(List listRawData, boolean doNotProcess) { - if (this.entryType.schemaSet) { - super.setData(listRawData, doNotProcess); - } else { - this.rawData = listRawData; - } - } - - - @Override - public int getDateLength() { - return this.entryType.getDateLength(); - } - - - @Override - public int getOpCode() { - if (opCode == null) - return entryType.getOpCode(); - else - return opCode; - } - - - public void setOpCode(Integer opCode) { - this.opCode = opCode; - } - - - public boolean hasTimeStamp() { - return (this.entryType.hasDate()); - } - - - @Override - public String getToStringStart() { - - return "CGMSHistoryEntry [type=" + StringUtils.rightPad(entryType.name(), 18) + " [" - + StringUtils.leftPad("" + getOpCode(), 3) + ", 0x" + ByteUtil.getCorrectHexValue(getOpCode()) + "]"; - } - - - public void setDateTime(LocalDateTime timeStamp, int getIndex) { - - setAtechDateTime(DateTimeUtil.toATechDate(timeStamp.plusMinutes(getIndex * 5))); - - } -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/CGMSHistoryEntry.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/CGMSHistoryEntry.kt new file mode 100644 index 0000000000..2ede3d65c1 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/CGMSHistoryEntry.kt @@ -0,0 +1,55 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.history.cgms + +import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil +import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.MedtronicHistoryEntry +import org.apache.commons.lang3.StringUtils +import org.joda.time.LocalDateTime + +/** + * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes + * management and modified/extended for AAPS. + * + * Author: Andy {andy.rozman@gmail.com} + */ +class CGMSHistoryEntry : MedtronicHistoryEntry() { + + var entryType: CGMSHistoryEntryType? = null + private set + + override var opCode: Byte? = null // this is set only when we have unknown entry... + get() = if (field == null) entryType!!.code.toByte() else field + + fun setEntryType(entryType: CGMSHistoryEntryType) { + this.entryType = entryType + sizes[0] = entryType.headLength + sizes[1] = entryType.dateLength + sizes[2] = entryType.bodyLength + } + + override val entryTypeName: String + get() = entryType!!.name + + override fun setData(listRawData: List?, doNotProcess: Boolean) { + if (entryType!!.schemaSet) { + super.setData(listRawData, doNotProcess) + } else { + rawData = listRawData + } + } + + override val dateLength: Int + get() = entryType!!.dateLength + + fun hasTimeStamp(): Boolean { + return entryType!!.hasDate() + } + + override val toStringStart: String + get() = ("CGMSHistoryEntry [type=" + StringUtils.rightPad(entryType!!.name, 18) + " [" + + StringUtils.leftPad("" + opCode, 3) + ", 0x" + ByteUtil.getCorrectHexValue(opCode!!) + "]") + + fun setDateTime(timeStamp: LocalDateTime, getIndex: Int) { + setAtechDateTime(DateTimeUtil.toATechDate(timeStamp.plusMinutes(getIndex * 5))) + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/CGMSHistoryEntryType.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/CGMSHistoryEntryType.java deleted file mode 100644 index 64161c720a..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/CGMSHistoryEntryType.java +++ /dev/null @@ -1,135 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.history.cgms; - -import java.util.HashMap; -import java.util.Map; - -/** - * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes - * management and modified/extended for AAPS. - * - * Author: Andy {andy.rozman@gmail.com} - */ - -public enum CGMSHistoryEntryType { - - None(0, "None", 1, 0, 0, DateType.None), // - - DataEnd(0x01, "DataEnd", 1, 0, 0, DateType.PreviousTimeStamp), // - SensorWeakSignal(0x02, "SensorWeakSignal", 1, 0, 0, DateType.PreviousTimeStamp), // - SensorCal(0x03, "SensorCal", 1, 0, 1, DateType.PreviousTimeStamp), // - SensorPacket(0x04, "SensorPacket", 1, 0, 1, DateType.PreviousTimeStamp), - SensorError(0x05, "SensorError", 1, 0, 1, DateType.PreviousTimeStamp), - SensorDataLow(0x06, "SensorDataLow", 1, 0, 1, DateType.PreviousTimeStamp), - SensorDataHigh(0x07, "SensorDataHigh", 1, 0, 1, DateType.PreviousTimeStamp), - SensorTimestamp(0x08, "SensorTimestamp", 1, 4, 0, DateType.MinuteSpecific), // - BatteryChange(0x0a, "BatteryChange", 1, 4, 0, DateType.MinuteSpecific), // - SensorStatus(0x0b, "SensorStatus", 1, 4, 0, DateType.MinuteSpecific), // - DateTimeChange(0x0c, "DateTimeChange", 1, 4, 0, DateType.SecondSpecific), // - SensorSync(0x0d, "SensorSync',packet_size=4", 1, 4, 0, DateType.MinuteSpecific), // - CalBGForGH(0x0e, "CalBGForGH',packet_size=5", 1, 4, 1, DateType.MinuteSpecific), // - SensorCalFactor(0x0f, "SensorCalFactor", 1, 4, 2, DateType.MinuteSpecific), // - Something10(0x10, "10-Something", 1, 4, 0, DateType.MinuteSpecific), // - Something19(0x13, "19-Something", 1, 0, 0, DateType.PreviousTimeStamp), - GlucoseSensorData(0xFF, "GlucoseSensorData", 1, 0, 0, DateType.PreviousTimeStamp); - - private static final Map opCodeMap = new HashMap<>(); - - static { - for (CGMSHistoryEntryType type : values()) { - opCodeMap.put(type.opCode, type); - } - } - - public boolean schemaSet; - private final int opCode; - private final String description; - private final int headLength; - private final int dateLength; - private final int bodyLength; - private final int totalLength; - private final DateType dateType; - - - CGMSHistoryEntryType(int opCode, String name, int head, int date, int body, DateType dateType) { - this.opCode = opCode; - this.description = name; - this.headLength = head; - this.dateLength = date; - this.bodyLength = body; - this.totalLength = (head + date + body); - this.schemaSet = true; - this.dateType = dateType; - } - - - // private CGMSHistoryEntryType(int opCode, String name, int length) - // { - // this.opCode = opCode; - // this.description = name; - // this.headLength = 0; - // this.dateLength = 0; - // this.bodyLength = 0; - // this.totalLength = length + 1; // opCode - // } - - public static CGMSHistoryEntryType getByCode(int opCode) { - if (opCodeMap.containsKey(opCode)) { - return opCodeMap.get(opCode); - } else - return CGMSHistoryEntryType.None; - } - - - public int getCode() { - return this.opCode; - } - - - public int getTotalLength() { - return totalLength; - } - - - public int getOpCode() { - return opCode; - } - - - public String getDescription() { - return description; - } - - - public int getHeadLength() { - return headLength; - } - - - public int getDateLength() { - return dateLength; - } - - - public int getBodyLength() { - return bodyLength; - } - - - public DateType getDateType() { - return dateType; - } - - - public boolean hasDate() { - return (this.dateType == DateType.MinuteSpecific) || (this.dateType == DateType.SecondSpecific); - } - - public enum DateType { - None, // - MinuteSpecific, // - SecondSpecific, // - PreviousTimeStamp // - - } - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/CGMSHistoryEntryType.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/CGMSHistoryEntryType.kt new file mode 100644 index 0000000000..a0cc7573c7 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/CGMSHistoryEntryType.kt @@ -0,0 +1,62 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.history.cgms + +import java.util.* + +/** + * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes + * management and modified/extended for AAPS. + * + * Author: Andy {andy.rozman@gmail.com} + */ +enum class CGMSHistoryEntryType(val code: Int, val description: String, val headLength: Int, val dateLength: Int, val bodyLength: Int, dateType: DateType) { + + None(0, "None", 1, 0, 0, DateType.None), // + DataEnd(0x01, "DataEnd", 1, 0, 0, DateType.PreviousTimeStamp), // + SensorWeakSignal(0x02, "SensorWeakSignal", 1, 0, 0, DateType.PreviousTimeStamp), // + SensorCal(0x03, "SensorCal", 1, 0, 1, DateType.PreviousTimeStamp), // + SensorPacket(0x04, "SensorPacket", 1, 0, 1, DateType.PreviousTimeStamp), SensorError(0x05, "SensorError", 1, 0, 1, DateType.PreviousTimeStamp), SensorDataLow(0x06, "SensorDataLow", 1, 0, 1, DateType.PreviousTimeStamp), SensorDataHigh(0x07, "SensorDataHigh", 1, 0, 1, DateType.PreviousTimeStamp), SensorTimestamp(0x08, "SensorTimestamp", 1, 4, 0, DateType.MinuteSpecific), // + BatteryChange(0x0a, "BatteryChange", 1, 4, 0, DateType.MinuteSpecific), // + SensorStatus(0x0b, "SensorStatus", 1, 4, 0, DateType.MinuteSpecific), // + DateTimeChange(0x0c, "DateTimeChange", 1, 4, 0, DateType.SecondSpecific), // + SensorSync(0x0d, "SensorSync',packet_size=4", 1, 4, 0, DateType.MinuteSpecific), // + CalBGForGH(0x0e, "CalBGForGH',packet_size=5", 1, 4, 1, DateType.MinuteSpecific), // + SensorCalFactor(0x0f, "SensorCalFactor", 1, 4, 2, DateType.MinuteSpecific), // + Something10(0x10, "10-Something", 1, 4, 0, DateType.MinuteSpecific), // + Something19(0x13, "19-Something", 1, 0, 0, DateType.PreviousTimeStamp), GlucoseSensorData(0xFF, "GlucoseSensorData", 1, 0, 0, DateType.PreviousTimeStamp); + + companion object { + private val opCodeMap: MutableMap = HashMap() + @JvmStatic fun getByCode(opCode: Int): CGMSHistoryEntryType? { + return if (opCodeMap.containsKey(opCode)) { + opCodeMap[opCode] + } else None + } + + init { + for (type in values()) { + opCodeMap[type.code] = type + } + } + } + + @JvmField var schemaSet: Boolean + val totalLength: Int + val dateType: DateType + + fun hasDate(): Boolean { + return dateType == DateType.MinuteSpecific || dateType == DateType.SecondSpecific + } + + enum class DateType { + None, // + MinuteSpecific, // + SecondSpecific, // + PreviousTimeStamp // + } + + init { + totalLength = headLength + dateLength + bodyLength + schemaSet = true + this.dateType = dateType + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/MedtronicCGMSHistoryDecoder.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/MedtronicCGMSHistoryDecoder.java deleted file mode 100644 index 9d040fc105..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/MedtronicCGMSHistoryDecoder.java +++ /dev/null @@ -1,469 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.history.cgms; - -import org.joda.time.LocalDateTime; -import org.slf4j.Logger; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.logging.StacktraceLoggerWrapper; -import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.MedtronicHistoryDecoder; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.RecordDecodeStatus; - -/** - * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes - * management and modified/extended for AAPS. - *

- * Author: Andy {andy.rozman@gmail.com} - */ - -public class MedtronicCGMSHistoryDecoder extends MedtronicHistoryDecoder { - - private static final Logger LOG = StacktraceLoggerWrapper.getLogger(LTag.PUMPCOMM); - - - // CGMSValuesWriter cgmsValuesWriter = null; - - public MedtronicCGMSHistoryDecoder() { - } - - - public RecordDecodeStatus decodeRecord(CGMSHistoryEntry record) { - try { - return decodeRecord(record, false); - } catch (Exception ex) { - LOG.error(" Error decoding: type={}, ex={}", record.getEntryType().name(), ex.getMessage(), ex); - return RecordDecodeStatus.Error; - } - } - - - public RecordDecodeStatus decodeRecord(CGMSHistoryEntry entry, boolean x) { - - if (entry.getDateTimeLength() > 0) { - parseDate(entry); - } - - switch (entry.getEntryType()) { - - case SensorPacket: - decodeSensorPacket(entry); - break; - - case SensorError: - decodeSensorError(entry); - break; - - case SensorDataLow: - decodeDataHighLow(entry, 40); - break; - - case SensorDataHigh: - decodeDataHighLow(entry, 400); - break; - - case SensorTimestamp: - decodeSensorTimestamp(entry); - break; - - case SensorCal: - decodeSensorCal(entry); - break; - - case SensorCalFactor: - decodeSensorCalFactor(entry); - break; - - case SensorSync: - decodeSensorSync(entry); - break; - - case SensorStatus: - decodeSensorStatus(entry); - break; - - case CalBGForGH: - decodeCalBGForGH(entry); - break; - - case GlucoseSensorData: - decodeGlucoseSensorData(entry); - break; - - // just timestamp - case BatteryChange: - case Something10: - case DateTimeChange: - break; - - // just relative timestamp - case Something19: - case DataEnd: - case SensorWeakSignal: - break; - - case None: - break; - - } - - return RecordDecodeStatus.NotSupported; - } - - - @Override - public void postProcess() { - - } - - - public List createRecords(List dataClearInput) { - - List dataClear = reverseList(dataClearInput, Byte.class); - - prepareStatistics(); - - int counter = 0; - - List outList = new ArrayList(); - - // create CGMS entries (without dates) - do { - int opCode = getUnsignedInt(dataClear.get(counter)); - counter++; - - CGMSHistoryEntryType entryType; - - if (opCode == 0) { - // continue; - } else if ((opCode > 0) && (opCode < 20)) { - entryType = CGMSHistoryEntryType.getByCode(opCode); - - if (entryType == CGMSHistoryEntryType.None) { - this.unknownOpCodes.put(opCode, opCode); - LOG.warn("GlucoseHistoryEntry with unknown code: " + opCode); - - CGMSHistoryEntry pe = new CGMSHistoryEntry(); - pe.setEntryType(CGMSHistoryEntryType.None); - pe.setOpCode(opCode); - - pe.setData(Arrays.asList((byte) opCode), false); - - outList.add(pe); - } else { - // System.out.println("OpCode: " + opCode); - - List listRawData = new ArrayList(); - listRawData.add((byte) opCode); - - for (int j = 0; j < (entryType.getTotalLength() - 1); j++) { - listRawData.add(dataClear.get(counter)); - counter++; - } - - CGMSHistoryEntry pe = new CGMSHistoryEntry(); - pe.setEntryType(entryType); - - pe.setOpCode(opCode); - pe.setData(listRawData, false); - - // System.out.println("Record: " + pe); - - outList.add(pe); - } - } else { - CGMSHistoryEntry pe = new CGMSHistoryEntry(); - pe.setEntryType(CGMSHistoryEntryType.GlucoseSensorData); - - pe.setData(Arrays.asList((byte) opCode), false); - - outList.add(pe); - } - - } while (counter < dataClear.size()); - - List reversedOutList = reverseList(outList, CGMSHistoryEntry.class); - - Long timeStamp = null; - LocalDateTime dateTime = null; - int getIndex = 0; - - for (CGMSHistoryEntry entry : reversedOutList) { - - decodeRecord(entry); - - if (entry.hasTimeStamp()) { - timeStamp = entry.atechDateTime; - dateTime = DateTimeUtil.toLocalDateTime(timeStamp); - getIndex = 0; - } else if (entry.getEntryType() == CGMSHistoryEntryType.GlucoseSensorData) { - getIndex++; - if (dateTime != null) - entry.setDateTime(dateTime, getIndex); - } else { - if (dateTime != null) - entry.setDateTime(dateTime, getIndex); - } - - LOG.debug("Record: {}", entry); - } - - return reversedOutList; - - } - - - private List reverseList(List dataClearInput, Class clazz) { - - List outList = new ArrayList(); - - for (int i = dataClearInput.size() - 1; i > 0; i--) { - outList.add(dataClearInput.get(i)); - } - - return outList; - } - - - private int parseMinutes(int one) { - return (one & Integer.parseInt("0111111", 2)); - } - - - private int parseHours(int one) { - return (one & 0x1F); - } - - - private int parseDay(int one) { - return one & 0x1F; - } - - - private int parseMonths(int first_byte, int second_byte) { - - int first_two_bits = first_byte >> 6; - int second_two_bits = second_byte >> 6; - - return (first_two_bits << 2) + second_two_bits; - } - - - private int parseYear(int year) { - return (year & 0x0F) + 2000; - } - - - private Long parseDate(CGMSHistoryEntry entry) { - - if (!entry.getEntryType().hasDate()) - return null; - - byte[] data = entry.getDatetime(); - - if (entry.getEntryType().getDateType() == CGMSHistoryEntryType.DateType.MinuteSpecific) { - - Long atechDateTime = DateTimeUtil.toATechDate(parseYear(data[3]), parseMonths(data[0], data[1]), - parseDay(data[2]), parseHours(data[0]), parseMinutes(data[1]), 0); - - entry.setAtechDateTime(atechDateTime); - - return atechDateTime; - - } else if (entry.getEntryType().getDateType() == CGMSHistoryEntryType.DateType.SecondSpecific) { - LOG.warn("parseDate for SecondSpecific type is not implemented."); - throw new RuntimeException(); - // return null; - } else - return null; - - } - - - private void decodeGlucoseSensorData(CGMSHistoryEntry entry) { - int sgv = entry.getUnsignedRawDataByIndex(0) * 2; - entry.addDecodedData("sgv", sgv); - } - - - private void decodeCalBGForGH(CGMSHistoryEntry entry) { - - int amount = ((entry.getRawDataByIndex(3) & 0b00100000) << 3) | entry.getRawDataByIndex(5); - // - String originType; - - switch (entry.getRawDataByIndex(3) >> 5 & 0b00000011) { - case 0x00: - originType = "rf"; - break; - - default: - originType = "unknown"; - - } - - entry.addDecodedData("amount", amount); - entry.addDecodedData("originType", originType); - - } - - - private void decodeSensorSync(CGMSHistoryEntry entry) { - - String syncType; - - switch (entry.getRawDataByIndex(3) >> 5 & 0b00000011) { - case 0x01: - syncType = "new"; - break; - - case 0x02: - syncType = "old"; - break; - - default: - syncType = "find"; - break; - - } - - entry.addDecodedData("syncType", syncType); - } - - - private void decodeSensorStatus(CGMSHistoryEntry entry) { - - String statusType; - - switch (entry.getRawDataByIndex(3) >> 5 & 0b00000011) { - case 0x00: - statusType = "off"; - break; - - case 0x01: - statusType = "on"; - break; - - case 0x02: - statusType = "lost"; - break; - - default: - statusType = "unknown"; - } - - entry.addDecodedData("statusType", statusType); - - } - - - private void decodeSensorCalFactor(CGMSHistoryEntry entry) { - - double factor = (entry.getRawDataByIndex(5) << 8 | entry.getRawDataByIndex(6)) / 1000.0d; - - entry.addDecodedData("factor", factor); - } - - - private void decodeSensorCal(CGMSHistoryEntry entry) { - - String calibrationType; - - switch (entry.getRawDataByIndex(1)) { - case 0x00: - calibrationType = "meter_bg_now"; - break; - - case 0x01: - calibrationType = "waiting"; - break; - - case 0x02: - calibrationType = "cal_error"; - break; - - default: - calibrationType = "unknown"; - } - - entry.addDecodedData("calibrationType", calibrationType); - - } - - - private void decodeSensorTimestamp(CGMSHistoryEntry entry) { - - String sensorTimestampType; - - switch (entry.getRawDataByIndex(3) >> 5 & 0b00000011) { - - case 0x00: - sensorTimestampType = "LastRf"; - break; - - case 0x01: - sensorTimestampType = "PageEnd"; - break; - - case 0x02: - sensorTimestampType = "Gap"; - break; - - default: - sensorTimestampType = "Unknown"; - break; - - } - - entry.addDecodedData("sensorTimestampType", sensorTimestampType); - } - - - private void decodeSensorPacket(CGMSHistoryEntry entry) { - - String packetType; - - switch (entry.getRawDataByIndex(1)) { - case 0x02: - packetType = "init"; - break; - - default: - packetType = "unknown"; - } - - entry.addDecodedData("packetType", packetType); - } - - - private void decodeSensorError(CGMSHistoryEntry entry) { - - String errorType; - - switch (entry.getRawDataByIndex(1)) { - case 0x01: - errorType = "end"; - break; - - default: - errorType = "unknown"; - } - - entry.addDecodedData("errorType", errorType); - } - - - private void decodeDataHighLow(CGMSHistoryEntry entry, int sgv) { - entry.addDecodedData("sgv", sgv); - } - - - @Override - protected void runPostDecodeTasks() { - this.showStatistics(); - } - -} 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 new file mode 100644 index 0000000000..d56798dd3a --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/MedtronicCGMSHistoryDecoder.kt @@ -0,0 +1,269 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.history.cgms + +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.logging.StacktraceLoggerWrapper.Companion.getLogger +import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.MedtronicHistoryDecoder +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.RecordDecodeStatus +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.cgms.CGMSHistoryEntryType +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.cgms.CGMSHistoryEntryType.Companion.getByCode +import okhttp3.internal.and +import org.joda.time.LocalDateTime +import org.slf4j.Logger +import java.util.* + +/** + * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes + * management and modified/extended for AAPS. + * + * + * Author: Andy {andy.rozman@gmail.com} + */ +class MedtronicCGMSHistoryDecoder : MedtronicHistoryDecoder() { + + override fun decodeRecord(record: CGMSHistoryEntry): RecordDecodeStatus? { + return try { + decodeRecord(record, false) + } catch (ex: Exception) { + LOG.error(" Error decoding: type={}, ex={}", record.entryType!!.name, ex.message, ex) + RecordDecodeStatus.Error + } + } + + fun decodeRecord(entry: CGMSHistoryEntry, ignore: Boolean): RecordDecodeStatus { + if (entry.dateTimeLength > 0) { + parseDate(entry) + } + when (entry.entryType) { + CGMSHistoryEntryType.SensorPacket -> decodeSensorPacket(entry) + CGMSHistoryEntryType.SensorError -> decodeSensorError(entry) + CGMSHistoryEntryType.SensorDataLow -> decodeDataHighLow(entry, 40) + CGMSHistoryEntryType.SensorDataHigh -> decodeDataHighLow(entry, 400) + CGMSHistoryEntryType.SensorTimestamp -> decodeSensorTimestamp(entry) + CGMSHistoryEntryType.SensorCal -> decodeSensorCal(entry) + CGMSHistoryEntryType.SensorCalFactor -> decodeSensorCalFactor(entry) + CGMSHistoryEntryType.SensorSync -> decodeSensorSync(entry) + CGMSHistoryEntryType.SensorStatus -> decodeSensorStatus(entry) + CGMSHistoryEntryType.CalBGForGH -> decodeCalBGForGH(entry) + CGMSHistoryEntryType.GlucoseSensorData -> decodeGlucoseSensorData(entry) + + CGMSHistoryEntryType.BatteryChange, CGMSHistoryEntryType.Something10, CGMSHistoryEntryType.DateTimeChange -> { + } + + CGMSHistoryEntryType.Something19, CGMSHistoryEntryType.DataEnd, CGMSHistoryEntryType.SensorWeakSignal -> { + } + + CGMSHistoryEntryType.None -> { + } + } + return RecordDecodeStatus.NotSupported + } + + override fun postProcess() {} + override fun createRecords(dataClearInput: List): List { + val dataClear = reverseList(dataClearInput, Byte::class.java) + prepareStatistics() + var counter = 0 + val outList: MutableList = ArrayList() + + // create CGMS entries (without dates) + do { + val opCode = getUnsignedInt(dataClear[counter]) + counter++ + var entryType: CGMSHistoryEntryType? + if (opCode == 0) { + // continue; + } else if (opCode > 0 && opCode < 20) { + entryType = getByCode(opCode) + if (entryType === CGMSHistoryEntryType.None) { + unknownOpCodes!![opCode] = opCode + LOG.warn("GlucoseHistoryEntry with unknown code: $opCode") + val pe = CGMSHistoryEntry() + pe.setEntryType(CGMSHistoryEntryType.None) + pe.opCode = opCode.toByte() + pe.setData(Arrays.asList(opCode.toByte()), false) + outList.add(pe) + } else { + // System.out.println("OpCode: " + opCode); + val listRawData: MutableList = ArrayList() + listRawData.add(opCode.toByte()) + for (j in 0 until entryType!!.totalLength - 1) { + listRawData.add(dataClear[counter]) + counter++ + } + val pe = CGMSHistoryEntry() + pe.setEntryType(entryType) + pe.opCode = opCode.toByte() + pe.setData(listRawData, false) + + // System.out.println("Record: " + pe); + outList.add(pe) + } + } else { + val pe = CGMSHistoryEntry() + pe.setEntryType(CGMSHistoryEntryType.GlucoseSensorData) + pe.setData(Arrays.asList(opCode.toByte()), false) + outList.add(pe) + } + } while (counter < dataClear.size) + val reversedOutList = reverseList(outList, CGMSHistoryEntry::class.java) + var timeStamp: Long? = null + var dateTime: LocalDateTime? = null + var getIndex = 0 + for (entry in reversedOutList) { + decodeRecord(entry) + if (entry.hasTimeStamp()) { + timeStamp = entry.atechDateTime + dateTime = DateTimeUtil.toLocalDateTime(timeStamp!!) + getIndex = 0 + } else if (entry.entryType === CGMSHistoryEntryType.GlucoseSensorData) { + getIndex++ + if (dateTime != null) entry.setDateTime(dateTime, getIndex) + } else { + if (dateTime != null) entry.setDateTime(dateTime, getIndex) + } + LOG.debug("Record: {}", entry) + } + 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 parseMinutes(one: Int): Int { + return one and "0111111".toInt(2) + } + + private fun parseHours(one: Int): Int { + return one and 0x1F + } + + private fun parseDay(one: Int): Int { + return one and 0x1F + } + + private fun parseMonths(first_byte: Int, second_byte: Int): Int { + val first_two_bits = first_byte shr 6 + val second_two_bits = second_byte shr 6 + return (first_two_bits shl 2) + second_two_bits + } + + private fun parseYear(year: Int): Int { + return (year and 0x0F) + 2000 + } + + private fun parseDate(entry: CGMSHistoryEntry): Long? { + if (!entry.entryType!!.hasDate()) return null + val data = entry.datetime + return if (entry.entryType!!.dateType === CGMSHistoryEntryType.DateType.MinuteSpecific) { + val atechDateTime = DateTimeUtil.toATechDate(parseYear(data!![3].toInt()), parseMonths(data[0].toInt(), data[1].toInt()), + parseDay(data[2].toInt()), parseHours(data[0].toInt()), parseMinutes(data[1].toInt()), 0) + entry.setAtechDateTime(atechDateTime) + atechDateTime + } else if (entry.entryType!!.dateType === CGMSHistoryEntryType.DateType.SecondSpecific) { + LOG.warn("parseDate for SecondSpecific type is not implemented.") + throw RuntimeException() + // return null; + } else null + } + + private fun decodeGlucoseSensorData(entry: CGMSHistoryEntry) { + val sgv = entry.getUnsignedRawDataByIndex(0) * 2 + entry.addDecodedData("sgv", sgv) + } + + private fun decodeCalBGForGH(entry: CGMSHistoryEntry) { + val amount: Int = entry.getRawDataByIndex(3) and 32 shl 3 or entry.getRawDataByIndexInt(5) + // + val originType: String + originType = when (entry.getRawDataByIndexInt(3) shr 5 and 3) { + 0x00 -> "rf" + else -> "unknown" + } + entry.addDecodedData("amount", amount) + entry.addDecodedData("originType", originType) + } + + private fun decodeSensorSync(entry: CGMSHistoryEntry) { + val syncType: String + syncType = when (entry.getRawDataByIndexInt(3) shr 5 and 3) { + 0x01 -> "new" + 0x02 -> "old" + else -> "find" + } + entry.addDecodedData("syncType", syncType) + } + + private fun decodeSensorStatus(entry: CGMSHistoryEntry) { + val statusType: String + statusType = when (entry.getRawDataByIndexInt(3) shr 5 and 3) { + 0x00 -> "off" + 0x01 -> "on" + 0x02 -> "lost" + else -> "unknown" + } + entry.addDecodedData("statusType", statusType) + } + + private fun decodeSensorCalFactor(entry: CGMSHistoryEntry) { + val factor: Double = (entry.getRawDataByIndexInt(5) shl 8 or entry.getRawDataByIndexInt(6)) / 1000.0 + entry.addDecodedData("factor", factor) + } + + private fun decodeSensorCal(entry: CGMSHistoryEntry) { + val calibrationType: String + calibrationType = when (entry.getRawDataByIndexInt(1)) { + 0x00 -> "meter_bg_now" + 0x01 -> "waiting" + 0x02 -> "cal_error" + else -> "unknown" + } + entry.addDecodedData("calibrationType", calibrationType) + } + + private fun decodeSensorTimestamp(entry: CGMSHistoryEntry) { + val sensorTimestampType: String + sensorTimestampType = when (entry.getRawDataByIndex(3).toInt() shr 5 and 3) { + 0x00 -> "LastRf" + 0x01 -> "PageEnd" + 0x02 -> "Gap" + else -> "Unknown" + } + entry.addDecodedData("sensorTimestampType", sensorTimestampType) + } + + private fun decodeSensorPacket(entry: CGMSHistoryEntry) { + val packetType: String + packetType = when (entry.getRawDataByIndex(1)) { + 0x02.toByte() -> "init" + else -> "unknown" + } + entry.addDecodedData("packetType", packetType) + } + + private fun decodeSensorError(entry: CGMSHistoryEntry) { + val errorType: String + errorType = when (entry.getRawDataByIndexInt(1)) { + 0x01 -> "end" + else -> "unknown" + } + entry.addDecodedData("errorType", errorType) + } + + private fun decodeDataHighLow(entry: CGMSHistoryEntry, sgv: Int) { + entry.addDecodedData("sgv", sgv) + } + + override fun runPostDecodeTasks() { + showStatistics() + } + + companion object { + private val LOG: Logger = getLogger(LTag.PUMPCOMM) + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/MedtronicPumpHistoryDecoder.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/MedtronicPumpHistoryDecoder.java deleted file mode 100644 index b8d57edb7c..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/MedtronicPumpHistoryDecoder.java +++ /dev/null @@ -1,724 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -import javax.inject.Inject; -import javax.inject.Singleton; - -import info.nightscout.androidaps.logging.AAPSLogger; -import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil; -import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.MedtronicHistoryDecoder; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.RecordDecodeStatus; -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.DailyTotalsDTO; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.TempBasalPair; -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.util.MedtronicUtil; - -/** - * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes - * management and modified/extended for AAPS. - *

- * Author: Andy {andy.rozman@gmail.com} - */ - -@Singleton -public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder { - - private PumpHistoryEntry tbrPreviousRecord; - private PumpHistoryEntry changeTimeRecord; - - @Inject - public MedtronicPumpHistoryDecoder( - AAPSLogger aapsLogger, - MedtronicUtil medtronicUtil - ) { - super.aapsLogger = aapsLogger; - this.medtronicUtil = medtronicUtil; - } - - - public List createRecords(List dataClear) { - prepareStatistics(); - - int counter = 0; - int record = 0; - boolean incompletePacket; - - List outList = new ArrayList<>(); - String skipped = null; - - if (dataClear.size() == 0) { - aapsLogger.error(LTag.PUMPBTCOMM, "Empty page."); - return outList; - } - - do { - int opCode = dataClear.get(counter); - boolean special = false; - incompletePacket = false; - boolean skippedRecords = false; - - if (opCode == 0) { - counter++; - if (skipped == null) - skipped = "0x00"; - else - skipped += " 0x00"; - continue; - } else { - if (skipped != null) { - aapsLogger.warn(LTag.PUMPBTCOMM, " ... Skipped " + skipped); - skipped = null; - skippedRecords = true; - } - } - - if (skippedRecords) { - aapsLogger.error(LTag.PUMPBTCOMM, "We had some skipped bytes, which might indicate error in pump history. Please report this problem."); - } - - PumpHistoryEntryType entryType = PumpHistoryEntryType.getByCode(opCode); - - PumpHistoryEntry pe = new PumpHistoryEntry(); - pe.setEntryType(medtronicUtil.getMedtronicPumpModel(), entryType); - pe.setOffset(counter); - - counter++; - - if (counter >= 1022) { - break; - } - - List listRawData = new ArrayList<>(); - listRawData.add((byte) opCode); - - if (entryType == PumpHistoryEntryType.UnabsorbedInsulin - || entryType == PumpHistoryEntryType.UnabsorbedInsulin512) { - int elements = dataClear.get(counter); - listRawData.add((byte) elements); - counter++; - - int els = getUnsignedInt(elements); - - for (int k = 0; k < (els - 2); k++) { - if (counter < 1022) { - listRawData.add(dataClear.get(counter)); - counter++; - } - } - - special = true; - } else { - - for (int j = 0; j < (entryType.getTotalLength(medtronicUtil.getMedtronicPumpModel()) - 1); j++) { - - try { - listRawData.add(dataClear.get(counter)); - counter++; - } catch (Exception ex) { - aapsLogger.error(LTag.PUMPBTCOMM, "OpCode: " + ByteUtil.shortHexString((byte) opCode) + ", Invalid package: " - + ByteUtil.getHex(listRawData)); - // throw ex; - incompletePacket = true; - break; - } - - } - - if (incompletePacket) - break; - - } - - if (entryType == PumpHistoryEntryType.None) { - aapsLogger.error(LTag.PUMPBTCOMM, "Error in code. We should have not come into this branch."); - } else { - - if (pe.getEntryType() == PumpHistoryEntryType.UnknownBasePacket) { - pe.setOpCode(opCode); - } - - if (entryType.getHeadLength(medtronicUtil.getMedtronicPumpModel()) == 0) - special = true; - - pe.setData(listRawData, special); - - RecordDecodeStatus decoded = decodeRecord(pe); - - if ((decoded == RecordDecodeStatus.OK) || (decoded == RecordDecodeStatus.Ignored)) { - //Log.i(TAG, "#" + record + " " + decoded.getDescription() + " " + pe); - } else { - aapsLogger.warn(LTag.PUMPBTCOMM, "#" + record + " " + decoded.getDescription() + " " + pe); - } - - addToStatistics(pe, decoded, null); - - record++; - - if (decoded == RecordDecodeStatus.OK) // we add only OK records, all others are ignored - { - outList.add(pe); - } - } - - } while (counter < dataClear.size()); - - return outList; - } - - - public RecordDecodeStatus decodeRecord(PumpHistoryEntry record) { - try { - return decodeRecord(record, false); - } catch (Exception ex) { - aapsLogger.error(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, " Error decoding: type=%s, ex=%s", record.getEntryType().name(), ex.getMessage(), ex)); - return RecordDecodeStatus.Error; - } - } - - - private RecordDecodeStatus decodeRecord(PumpHistoryEntry entry, boolean x) { - - if (entry.getDateTimeLength() > 0) { - decodeDateTime(entry); - } - - switch (entry.getEntryType()) { - - // Valid entries, but not processed - case ChangeBasalPattern: - case CalBGForPH: - case ChangeRemoteId: - case ClearAlarm: - case ChangeAlarmNotifyMode: // ChangeUtility: - case EnableDisableRemote: - case BGReceived: // Ian3F: CGMS - case SensorAlert: // Ian08 CGMS - case ChangeTimeFormat: - case ChangeReservoirWarningTime: - case ChangeBolusReminderEnable: - case SetBolusReminderTime: - case ChangeChildBlockEnable: - case BolusWizardEnabled: - case ChangeBGReminderOffset: - case ChangeAlarmClockTime: - case ChangeMeterId: - case ChangeParadigmID: - case JournalEntryMealMarker: - case JournalEntryExerciseMarker: - case DeleteBolusReminderTime: - case SetAutoOff: - case SelfTest: - case JournalEntryInsulinMarker: - case JournalEntryOtherMarker: - case BolusWizardSetup512: - case ChangeSensorSetup2: - case ChangeSensorAlarmSilenceConfig: - case ChangeSensorRateOfChangeAlertSetup: - case ChangeBolusScrollStepSize: - case BolusWizardSetup: - case ChangeVariableBolus: - case ChangeAudioBolus: - case ChangeBGReminderEnable: - case ChangeAlarmClockEnable: - case BolusReminder: - case DeleteAlarmClockTime: - case ChangeCarbUnits: - case ChangeWatchdogEnable: - case ChangeOtherDeviceID: - case ReadOtherDevicesIDs: - case BGReceived512: - case SensorStatus: - case ReadCaptureEventEnabled: - case ChangeCaptureEventEnable: - case ReadOtherDevicesStatus: - return RecordDecodeStatus.OK; - - case Sensor_0x54: - case Sensor_0x55: - case Sensor_0x51: - case Sensor_0x52: -// case EventUnknown_MM522_0x45: -// case EventUnknown_MM522_0x46: -// case EventUnknown_MM522_0x47: -// case EventUnknown_MM522_0x48: -// case EventUnknown_MM522_0x49: -// case EventUnknown_MM522_0x4a: -// case EventUnknown_MM522_0x4b: -// case EventUnknown_MM522_0x4c: -// case EventUnknown_MM512_0x10: - case EventUnknown_MM512_0x2e: -// case EventUnknown_MM512_0x37: -// case EventUnknown_MM512_0x38: -// case EventUnknown_MM512_0x4e: -// case EventUnknown_MM522_0x70: -// case EventUnknown_MM512_0x88: -// case EventUnknown_MM512_0x94: -// case EventUnknown_MM522_0xE8: -// case EventUnknown_0x4d: -// case EventUnknown_MM522_0x25: -// case EventUnknown_MM522_0x05: - aapsLogger.debug(LTag.PUMPBTCOMM, " -- ignored Unknown Pump Entry: " + entry); - return RecordDecodeStatus.Ignored; - - case UnabsorbedInsulin: - case UnabsorbedInsulin512: - return RecordDecodeStatus.Ignored; - - // **** Implemented records **** - - case DailyTotals522: - case DailyTotals523: - case DailyTotals515: - case EndResultTotals: - return decodeDailyTotals(entry); - - case ChangeBasalProfile_OldProfile: - case ChangeBasalProfile_NewProfile: - return decodeBasalProfile(entry); - - case BasalProfileStart: - return decodeBasalProfileStart(entry); - - case ChangeTime: - changeTimeRecord = entry; - return RecordDecodeStatus.OK; - - case NewTimeSet: - decodeChangeTime(entry); - return RecordDecodeStatus.OK; - - case TempBasalDuration: - // decodeTempBasal(entry); - return RecordDecodeStatus.OK; - - case TempBasalRate: - // decodeTempBasal(entry); - return RecordDecodeStatus.OK; - - case Bolus: - decodeBolus(entry); - return RecordDecodeStatus.OK; - - case BatteryChange: - decodeBatteryActivity(entry); - return RecordDecodeStatus.OK; - - case LowReservoir: - decodeLowReservoir(entry); - return RecordDecodeStatus.OK; - - case LowBattery: - case SuspendPump: - case ResumePump: - case Rewind: - case NoDeliveryAlarm: - case ChangeTempBasalType: - case ChangeMaxBolus: - case ChangeMaxBasal: - case ClearSettings: - case SaveSettings: - return RecordDecodeStatus.OK; - - case BolusWizard: - return decodeBolusWizard(entry); - - case BolusWizard512: - return decodeBolusWizard512(entry); - - case Prime: - decodePrime(entry); - return RecordDecodeStatus.OK; - - case TempBasalCombined: - return RecordDecodeStatus.Ignored; - - case None: - case UnknownBasePacket: - return RecordDecodeStatus.Error; - - default: { - aapsLogger.debug(LTag.PUMPBTCOMM, "Not supported: " + entry.getEntryType()); - return RecordDecodeStatus.NotSupported; - } - - } - - // return RecordDecodeStatus.Error; - - } - - - private RecordDecodeStatus decodeDailyTotals(PumpHistoryEntry entry) { - - entry.addDecodedData("Raw Data", ByteUtil.getHex(entry.getRawData())); - - DailyTotalsDTO totals = new DailyTotalsDTO(entry); - - entry.addDecodedData("Object", totals); - - return RecordDecodeStatus.OK; - } - - - private RecordDecodeStatus decodeBasalProfile(PumpHistoryEntry entry) { - - // LOG.debug("decodeBasalProfile: {}", entry); - - BasalProfile basalProfile = new BasalProfile(aapsLogger); - basalProfile.setRawDataFromHistory(entry.getBody()); - - // LOG.debug("decodeBasalProfile BasalProfile: {}", basalProfile); - - entry.addDecodedData("Object", basalProfile); - - return RecordDecodeStatus.OK; - } - - - private void decodeChangeTime(PumpHistoryEntry entry) { - if (changeTimeRecord == null) - return; - - entry.setDisplayableValue(entry.getDateTimeString()); - - this.changeTimeRecord = null; - } - - - private void decodeBatteryActivity(PumpHistoryEntry entry) { - // this.writeData(PumpBaseType.Event, entry.getHead()[0] == 0 ? PumpEventType.BatteryRemoved : - // PumpEventType.BatteryReplaced, entry.getATechDate()); - - entry.setDisplayableValue(entry.getHead()[0] == 0 ? "Battery Removed" : "Battery Replaced"); - } - - - private static String getFormattedValue(float value, int decimals) { - return String.format(Locale.ENGLISH, "%." + decimals + "f", value); - } - - - private RecordDecodeStatus decodeBasalProfileStart(PumpHistoryEntry entry) { - byte[] body = entry.getBody(); - // int bodyOffset = headerSize + timestampSize; - int offset = body[0] * 1000 * 30 * 60; - Float rate = null; - int index = entry.getHead()[0]; - - if (MedtronicDeviceType.isSameDevice(medtronicUtil.getMedtronicPumpModel(), MedtronicDeviceType.Medtronic_523andHigher)) { - rate = body[1] * 0.025f; - } - - //LOG.info("Basal Profile Start: offset={}, rate={}, index={}, body_raw={}", offset, rate, index, body); - - if (rate == null) { - aapsLogger.warn(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, "Basal Profile Start (ERROR): offset=%d, rate=%.3f, index=%d, body_raw=%s", offset, rate, index, ByteUtil.getHex(body))); - return RecordDecodeStatus.Error; - } else { - entry.addDecodedData("Value", getFormattedFloat(rate, 3)); - entry.setDisplayableValue(getFormattedFloat(rate, 3)); - return RecordDecodeStatus.OK; - } - - } - - - private RecordDecodeStatus decodeBolusWizard(PumpHistoryEntry entry) { - byte[] body = entry.getBody(); - - BolusWizardDTO dto = new BolusWizardDTO(); - - float bolusStrokes = 10.0f; - - if (MedtronicDeviceType.isSameDevice(medtronicUtil.getMedtronicPumpModel(), MedtronicDeviceType.Medtronic_523andHigher)) { - // https://github.com/ps2/minimed_rf/blob/master/lib/minimed_rf/log_entries/bolus_wizard.rb#L102 - bolusStrokes = 40.0f; - - dto.carbs = ((body[1] & 0x0c) << 6) + body[0]; - - dto.bloodGlucose = ((body[1] & 0x03) << 8) + entry.getHead()[0]; - dto.carbRatio = body[1] / 10.0f; - // carb_ratio (?) = (((self.body[2] & 0x07) << 8) + self.body[3]) / - // 10.0s - dto.insulinSensitivity = new Float(body[4]); - dto.bgTargetLow = (int) body[5]; - dto.bgTargetHigh = (int) body[14]; - dto.correctionEstimate = (((body[9] & 0x38) << 5) + body[6]) / bolusStrokes; - dto.foodEstimate = ((body[7] << 8) + body[8]) / bolusStrokes; - dto.unabsorbedInsulin = ((body[10] << 8) + body[11]) / bolusStrokes; - dto.bolusTotal = ((body[12] << 8) + body[13]) / bolusStrokes; - } else { - dto.bloodGlucose = (((body[1] & 0x0F) << 8) | entry.getHead()[0]); - dto.carbs = (int) body[0]; - dto.carbRatio = Float.valueOf(body[2]); - dto.insulinSensitivity = new Float(body[3]); - dto.bgTargetLow = (int) body[4]; - dto.bgTargetHigh = (int) body[12]; - dto.bolusTotal = body[11] / bolusStrokes; - dto.foodEstimate = body[6] / bolusStrokes; - dto.unabsorbedInsulin = body[9] / bolusStrokes; - dto.bolusTotal = body[11] / bolusStrokes; - dto.correctionEstimate = (body[7] + (body[5] & 0x0F)) / bolusStrokes; - } - - if (dto.bloodGlucose != null && dto.bloodGlucose < 0) { - dto.bloodGlucose = ByteUtil.convertUnsignedByteToInt(dto.bloodGlucose.byteValue()); - } - - dto.atechDateTime = entry.atechDateTime; - entry.addDecodedData("Object", dto); - entry.setDisplayableValue(dto.getDisplayableValue()); - - return RecordDecodeStatus.OK; - } - - - private RecordDecodeStatus decodeBolusWizard512(PumpHistoryEntry entry) { - byte[] body = entry.getBody(); - - BolusWizardDTO dto = new BolusWizardDTO(); - - float bolusStrokes = 10.0f; - - dto.bloodGlucose = ((body[1] & 0x03 << 8) | entry.getHead()[0]); - dto.carbs = (body[1] & 0xC) << 6 | body[0]; // (int)body[0]; - dto.carbRatio = Float.valueOf(body[2]); - dto.insulinSensitivity = new Float(body[3]); - dto.bgTargetLow = (int) body[4]; - dto.foodEstimate = body[6] / 10.0f; - dto.correctionEstimate = (body[7] + (body[5] & 0x0F)) / bolusStrokes; - dto.unabsorbedInsulin = body[9] / bolusStrokes; - dto.bolusTotal = body[11] / bolusStrokes; - dto.bgTargetHigh = dto.bgTargetLow; - - if (dto.bloodGlucose != null && dto.bloodGlucose < 0) { - dto.bloodGlucose = ByteUtil.convertUnsignedByteToInt(dto.bloodGlucose.byteValue()); - } - - dto.atechDateTime = entry.atechDateTime; - entry.addDecodedData("Object", dto); - entry.setDisplayableValue(dto.getDisplayableValue()); - - return RecordDecodeStatus.OK; - } - - - private void decodeLowReservoir(PumpHistoryEntry entry) { - float amount = (getUnsignedInt(entry.getHead()[0]) * 1.0f / 10.0f) * 2; - - entry.setDisplayableValue(getFormattedValue(amount, 1)); - } - - - private void decodePrime(PumpHistoryEntry entry) { - float amount = ByteUtil.toInt(entry.getHead()[2], entry.getHead()[3]) / 10.0f; - float fixed = ByteUtil.toInt(entry.getHead()[0], entry.getHead()[1]) / 10.0f; - -// amount = (double)(asUINT8(data[4]) << 2) / 40.0; -// programmedAmount = (double)(asUINT8(data[2]) << 2) / 40.0; -// primeType = programmedAmount == 0 ? "manual" : "fixed"; - - entry.addDecodedData("Amount", amount); - entry.addDecodedData("FixedAmount", fixed); - - entry.setDisplayableValue("Amount=" + getFormattedValue(amount, 2) + ", Fixed Amount=" - + getFormattedValue(fixed, 2)); - } - - - private void decodeChangeTempBasalType(PumpHistoryEntry entry) { - entry.addDecodedData("isPercent", ByteUtil.asUINT8(entry.getRawDataByIndex(0)) == 1); // index moved from 1 -> 0 - } - - - private void decodeBgReceived(PumpHistoryEntry entry) { - entry.addDecodedData("amount", (ByteUtil.asUINT8(entry.getRawDataByIndex(0)) << 3) + (ByteUtil.asUINT8(entry.getRawDataByIndex(3)) >> 5)); - entry.addDecodedData("meter", ByteUtil.substring(entry.getRawData(), 6, 3)); // index moved from 1 -> 0 - } - - - private void decodeCalBGForPH(PumpHistoryEntry entry) { - entry.addDecodedData("amount", ((ByteUtil.asUINT8(entry.getRawDataByIndex(5)) & 0x80) << 1) + ByteUtil.asUINT8(entry.getRawDataByIndex(0))); // index moved from 1 -> 0 - } - - - private void decodeNoDeliveryAlarm(PumpHistoryEntry entry) { - //rawtype = asUINT8(data[1]); - // not sure if this is actually NoDelivery Alarm? - } - - - @Override - public void postProcess() { - } - - - @Override - protected void runPostDecodeTasks() { - this.showStatistics(); - } - - - private void decodeBolus(PumpHistoryEntry entry) { - BolusDTO bolus = new BolusDTO(); - - byte[] data = entry.getHead(); - - if (MedtronicDeviceType.isSameDevice(medtronicUtil.getMedtronicPumpModel(), MedtronicDeviceType.Medtronic_523andHigher)) { - bolus.setRequestedAmount(ByteUtil.toInt(data[0], data[1]) / 40.0d); - bolus.setDeliveredAmount(ByteUtil.toInt(data[2], data[3]) / 40.0d); - bolus.setInsulinOnBoard(ByteUtil.toInt(data[4], data[5]) / 40.0d); - bolus.setDuration(data[6] * 30); - } else { - bolus.setRequestedAmount(ByteUtil.asUINT8(data[0]) / 10.0d); - bolus.setDeliveredAmount(ByteUtil.asUINT8(data[1]) / 10.0d); - bolus.setDuration(ByteUtil.asUINT8(data[2]) * 30); - } - - bolus.setBolusType((bolus.getDuration() != null && (bolus.getDuration() > 0)) ? PumpBolusType.Extended - : PumpBolusType.Normal); - bolus.setAtechDateTime(entry.atechDateTime); - - entry.addDecodedData("Object", bolus); - entry.setDisplayableValue(bolus.getDisplayableValue()); - - } - - - private void decodeTempBasal(PumpHistoryEntry entry) { - - if (this.tbrPreviousRecord == null) { - // LOG.debug(this.tbrPreviousRecord.toString()); - this.tbrPreviousRecord = entry; - return; - } - - decodeTempBasal(this.tbrPreviousRecord, entry); - - tbrPreviousRecord = null; - } - - - public void decodeTempBasal(PumpHistoryEntry tbrPreviousRecord, PumpHistoryEntry entry) { - - PumpHistoryEntry tbrRate = null, tbrDuration = null; - - if (entry.getEntryType() == PumpHistoryEntryType.TempBasalRate) { - tbrRate = entry; - } else { - tbrDuration = entry; - } - - if (tbrRate != null) { - tbrDuration = tbrPreviousRecord; - } else { - tbrRate = tbrPreviousRecord; - } - -// TempBasalPair tbr = new TempBasalPair( -// tbrRate.getHead()[0], -// tbrDuration.getHead()[0], -// (ByteUtil.asUINT8(tbrRate.getDatetime()[4]) >> 3) == 0); - - TempBasalPair tbr = new TempBasalPair( - tbrRate.getHead()[0], - tbrRate.getBody()[0], - tbrDuration.getHead()[0], - (ByteUtil.asUINT8(tbrRate.getDatetime()[4]) >> 3) == 0); - - // System.out.println("TBR: amount=" + tbr.getInsulinRate() + ", duration=" + tbr.getDurationMinutes() - // // + " min. Packed: " + tbr.getValue() - // ); - - entry.addDecodedData("Object", tbr); - entry.setDisplayableValue(tbr.getDescription()); - - } - - - private void decodeDateTime(PumpHistoryEntry entry) { - byte[] dt = entry.getDatetime(); - - if (dt == null) { - aapsLogger.warn(LTag.PUMPBTCOMM, "DateTime not set."); - } - - if (entry.getDateTimeLength() == 5) { - - int seconds = dt[0] & 0x3F; - int minutes = dt[1] & 0x3F; - int hour = dt[2] & 0x1F; - - int month = ((dt[0] >> 4) & 0x0c) + ((dt[1] >> 6) & 0x03); - // ((dt[0] & 0xC0) >> 6) | ((dt[1] & 0xC0) >> 4); - - int dayOfMonth = dt[3] & 0x1F; - int year = fix2DigitYear(dt[4] & 0x3F); // Assuming this is correct, need to verify. Otherwise this will be - // a problem in 2016. - - entry.setAtechDateTime(DateTimeUtil.toATechDate(year, month, dayOfMonth, hour, minutes, seconds)); - - } else if (entry.getDateTimeLength() == 2) { - int low = ByteUtil.asUINT8(dt[0]) & 0x1F; - int mhigh = (ByteUtil.asUINT8(dt[0]) & 0xE0) >> 4; - int mlow = (ByteUtil.asUINT8(dt[1]) & 0x80) >> 7; - int month = mhigh + mlow; - // int dayOfMonth = low + 1; - int dayOfMonth = dt[0] & 0x1F; - int year = 2000 + (ByteUtil.asUINT8(dt[1]) & 0x7F); - - int hour = 0; - int minutes = 0; - int seconds = 0; - - //LOG.debug("DT: {} {} {}", year, month, dayOfMonth); - - if (dayOfMonth == 32) { - aapsLogger.warn(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, "Entry: Day 32 %s = [%s] %s", entry.getEntryType().name(), - ByteUtil.getHex(entry.getRawData()), entry)); - } - - if (isEndResults(entry.getEntryType())) { - hour = 23; - minutes = 59; - seconds = 59; - } - - entry.setAtechDateTime(DateTimeUtil.toATechDate(year, month, dayOfMonth, hour, minutes, seconds)); - - } else { - aapsLogger.warn(LTag.PUMPBTCOMM, "Unknown datetime format: " + entry.getDateTimeLength()); - } - - } - - - private boolean isEndResults(PumpHistoryEntryType entryType) { - - return (entryType == PumpHistoryEntryType.EndResultTotals || - entryType == PumpHistoryEntryType.DailyTotals515 || - entryType == PumpHistoryEntryType.DailyTotals522 || - entryType == PumpHistoryEntryType.DailyTotals523); - } - - - private int fix2DigitYear(int year) { - if (year > 90) { - year += 1900; - } else { - year += 2000; - } - - return year; - } - -} 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 new file mode 100644 index 0000000000..e0613567d8 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/MedtronicPumpHistoryDecoder.kt @@ -0,0 +1,502 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump + +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil +import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.MedtronicHistoryDecoder +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.RecordDecodeStatus +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntryType +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntryType.Companion.getByCode +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.DailyTotalsDTO +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.TempBasalPair +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.util.MedtronicUtil +import java.util.* +import javax.inject.Inject +import javax.inject.Singleton + +/** + * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes + * management and modified/extended for AAPS. + * + * + * Author: Andy {andy.rozman@gmail.com} + */ +@Singleton +class MedtronicPumpHistoryDecoder @Inject constructor( + aapsLogger: AAPSLogger?, + medtronicUtil: MedtronicUtil? +) : MedtronicHistoryDecoder() { + + private var tbrPreviousRecord: PumpHistoryEntry? = null + private var changeTimeRecord: PumpHistoryEntry? = null + override fun createRecords(dataClear: List): List { + prepareStatistics() + var counter = 0 + var record = 0 + var incompletePacket: Boolean + val outList: MutableList = ArrayList() + var skipped: String? = null + if (dataClear!!.size == 0) { + aapsLogger!!.error(LTag.PUMPBTCOMM, "Empty page.") + return outList + } + do { + val opCode: Int = dataClear[counter]!!.toInt() + var special = false + incompletePacket = false + var skippedRecords = false + if (opCode == 0) { + counter++ + if (skipped == null) skipped = "0x00" else skipped += " 0x00" + continue + } else { + if (skipped != null) { + aapsLogger!!.warn(LTag.PUMPBTCOMM, " ... Skipped $skipped") + skipped = null + skippedRecords = true + } + } + if (skippedRecords) { + aapsLogger!!.error(LTag.PUMPBTCOMM, "We had some skipped bytes, which might indicate error in pump history. Please report this problem.") + } + val entryType = getByCode(opCode.toByte()) + val pe = PumpHistoryEntry() + pe.setEntryType(medtronicUtil!!.medtronicPumpModel, entryType!!) + pe.offset = counter + counter++ + if (counter >= 1022) { + break + } + val listRawData: MutableList = ArrayList() + listRawData.add(opCode.toByte()) + if (entryType === PumpHistoryEntryType.UnabsorbedInsulin + || entryType === PumpHistoryEntryType.UnabsorbedInsulin512) { + val elements: Int = dataClear[counter]!!.toInt() + listRawData.add(elements.toByte()) + counter++ + val els = getUnsignedInt(elements) + for (k in 0 until els - 2) { + if (counter < 1022) { + listRawData.add(dataClear[counter]) + counter++ + } + } + special = true + } else { + for (j in 0 until entryType.getTotalLength(medtronicUtil!!.medtronicPumpModel) - 1) { + try { + listRawData.add(dataClear[counter]) + counter++ + } catch (ex: Exception) { + aapsLogger!!.error(LTag.PUMPBTCOMM, "OpCode: " + ByteUtil.shortHexString(opCode.toByte()) + ", Invalid package: " + + ByteUtil.getHex(listRawData)) + // throw ex; + incompletePacket = true + break + } + } + if (incompletePacket) break + } + if (entryType === PumpHistoryEntryType.None) { + aapsLogger!!.error(LTag.PUMPBTCOMM, "Error in code. We should have not come into this branch.") + } else { + if (pe.entryType === PumpHistoryEntryType.UnknownBasePacket) { + pe.opCode = opCode.toByte() + } + if (entryType.getHeadLength(medtronicUtil!!.medtronicPumpModel) == 0) special = true + pe.setData(listRawData as List, special) + val decoded = decodeRecord(pe) + if (decoded === RecordDecodeStatus.OK || decoded === RecordDecodeStatus.Ignored) { + //Log.i(TAG, "#" + record + " " + decoded.getDescription() + " " + pe); + } else { + aapsLogger!!.warn(LTag.PUMPBTCOMM, "#" + record + " " + decoded!!.description + " " + pe) + } + addToStatistics(pe, decoded, null) + record++ + if (decoded === RecordDecodeStatus.OK) // we add only OK records, all others are ignored + { + outList.add(pe) + } + } + } while (counter < dataClear.size) + return outList + } + + override fun decodeRecord(record: PumpHistoryEntry): RecordDecodeStatus? { + return try { + decodeRecord(record, false) + } catch (ex: Exception) { + aapsLogger!!.error(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, " Error decoding: type=%s, ex=%s", record.entryType!!.name, ex.message, ex)) + RecordDecodeStatus.Error + } + } + + private fun decodeRecord(entry: PumpHistoryEntry, x: Boolean): RecordDecodeStatus { + if (entry.dateTimeLength > 0) { + decodeDateTime(entry) + } + return when (entry.entryType) { + PumpHistoryEntryType.ChangeBasalPattern, PumpHistoryEntryType.CalBGForPH, PumpHistoryEntryType.ChangeRemoteId, PumpHistoryEntryType.ClearAlarm, PumpHistoryEntryType.ChangeAlarmNotifyMode, PumpHistoryEntryType.EnableDisableRemote, PumpHistoryEntryType.BGReceived, PumpHistoryEntryType.SensorAlert, PumpHistoryEntryType.ChangeTimeFormat, PumpHistoryEntryType.ChangeReservoirWarningTime, PumpHistoryEntryType.ChangeBolusReminderEnable, PumpHistoryEntryType.SetBolusReminderTime, PumpHistoryEntryType.ChangeChildBlockEnable, PumpHistoryEntryType.BolusWizardEnabled, PumpHistoryEntryType.ChangeBGReminderOffset, PumpHistoryEntryType.ChangeAlarmClockTime, PumpHistoryEntryType.ChangeMeterId, PumpHistoryEntryType.ChangeParadigmID, PumpHistoryEntryType.JournalEntryMealMarker, PumpHistoryEntryType.JournalEntryExerciseMarker, PumpHistoryEntryType.DeleteBolusReminderTime, PumpHistoryEntryType.SetAutoOff, PumpHistoryEntryType.SelfTest, PumpHistoryEntryType.JournalEntryInsulinMarker, PumpHistoryEntryType.JournalEntryOtherMarker, PumpHistoryEntryType.BolusWizardSetup512, PumpHistoryEntryType.ChangeSensorSetup2, PumpHistoryEntryType.ChangeSensorAlarmSilenceConfig, PumpHistoryEntryType.ChangeSensorRateOfChangeAlertSetup, PumpHistoryEntryType.ChangeBolusScrollStepSize, PumpHistoryEntryType.BolusWizardSetup, PumpHistoryEntryType.ChangeVariableBolus, PumpHistoryEntryType.ChangeAudioBolus, PumpHistoryEntryType.ChangeBGReminderEnable, PumpHistoryEntryType.ChangeAlarmClockEnable, PumpHistoryEntryType.BolusReminder, PumpHistoryEntryType.DeleteAlarmClockTime, PumpHistoryEntryType.ChangeCarbUnits, PumpHistoryEntryType.ChangeWatchdogEnable, PumpHistoryEntryType.ChangeOtherDeviceID, PumpHistoryEntryType.ReadOtherDevicesIDs, PumpHistoryEntryType.BGReceived512, PumpHistoryEntryType.SensorStatus, PumpHistoryEntryType.ReadCaptureEventEnabled, PumpHistoryEntryType.ChangeCaptureEventEnable, PumpHistoryEntryType.ReadOtherDevicesStatus -> RecordDecodeStatus.OK + + PumpHistoryEntryType.Sensor_0x54, PumpHistoryEntryType.Sensor_0x55, PumpHistoryEntryType.Sensor_0x51, PumpHistoryEntryType.Sensor_0x52, PumpHistoryEntryType.EventUnknown_MM512_0x2e -> { + // case EventUnknown_MM512_0x37: +// case EventUnknown_MM512_0x38: +// case EventUnknown_MM512_0x4e: +// case EventUnknown_MM522_0x70: +// case EventUnknown_MM512_0x88: +// case EventUnknown_MM512_0x94: +// case EventUnknown_MM522_0xE8: +// case EventUnknown_0x4d: +// case EventUnknown_MM522_0x25: +// case EventUnknown_MM522_0x05: + aapsLogger!!.debug(LTag.PUMPBTCOMM, " -- ignored Unknown Pump Entry: $entry") + RecordDecodeStatus.Ignored + } + + PumpHistoryEntryType.UnabsorbedInsulin, PumpHistoryEntryType.UnabsorbedInsulin512 -> RecordDecodeStatus.Ignored + PumpHistoryEntryType.DailyTotals522, PumpHistoryEntryType.DailyTotals523, PumpHistoryEntryType.DailyTotals515, PumpHistoryEntryType.EndResultTotals -> decodeDailyTotals(entry) + PumpHistoryEntryType.ChangeBasalProfile_OldProfile, PumpHistoryEntryType.ChangeBasalProfile_NewProfile -> decodeBasalProfile(entry) + PumpHistoryEntryType.BasalProfileStart -> decodeBasalProfileStart(entry) + + PumpHistoryEntryType.ChangeTime -> { + changeTimeRecord = entry + RecordDecodeStatus.OK + } + + PumpHistoryEntryType.NewTimeSet -> { + decodeChangeTime(entry) + RecordDecodeStatus.OK + } + + PumpHistoryEntryType.TempBasalDuration -> // decodeTempBasal(entry); + RecordDecodeStatus.OK + PumpHistoryEntryType.TempBasalRate -> // decodeTempBasal(entry); + RecordDecodeStatus.OK + + PumpHistoryEntryType.Bolus -> { + decodeBolus(entry) + RecordDecodeStatus.OK + } + + PumpHistoryEntryType.BatteryChange -> { + decodeBatteryActivity(entry) + RecordDecodeStatus.OK + } + + PumpHistoryEntryType.LowReservoir -> { + decodeLowReservoir(entry) + RecordDecodeStatus.OK + } + + PumpHistoryEntryType.LowBattery, PumpHistoryEntryType.SuspendPump, PumpHistoryEntryType.ResumePump, PumpHistoryEntryType.Rewind, PumpHistoryEntryType.NoDeliveryAlarm, PumpHistoryEntryType.ChangeTempBasalType, PumpHistoryEntryType.ChangeMaxBolus, PumpHistoryEntryType.ChangeMaxBasal, PumpHistoryEntryType.ClearSettings, PumpHistoryEntryType.SaveSettings -> RecordDecodeStatus.OK + PumpHistoryEntryType.BolusWizard -> decodeBolusWizard(entry) + PumpHistoryEntryType.BolusWizard512 -> decodeBolusWizard512(entry) + + PumpHistoryEntryType.Prime -> { + decodePrime(entry) + RecordDecodeStatus.OK + } + + PumpHistoryEntryType.TempBasalCombined -> RecordDecodeStatus.Ignored + PumpHistoryEntryType.None, PumpHistoryEntryType.UnknownBasePacket -> RecordDecodeStatus.Error + + else -> { + aapsLogger!!.debug(LTag.PUMPBTCOMM, "Not supported: " + entry.entryType) + RecordDecodeStatus.NotSupported + } + } + + // return RecordDecodeStatus.Error; + } + + private fun decodeDailyTotals(entry: PumpHistoryEntry): RecordDecodeStatus { + entry.addDecodedData("Raw Data", ByteUtil.getHex(entry.rawData)) + val totals = DailyTotalsDTO(entry) + entry.addDecodedData("Object", totals) + return RecordDecodeStatus.OK + } + + private fun decodeBasalProfile(entry: PumpHistoryEntry): RecordDecodeStatus { + + // LOG.debug("decodeBasalProfile: {}", entry); + val basalProfile = BasalProfile(aapsLogger) + basalProfile.setRawDataFromHistory(entry.body) + + // LOG.debug("decodeBasalProfile BasalProfile: {}", basalProfile); + entry.addDecodedData("Object", basalProfile) + return RecordDecodeStatus.OK + } + + private fun decodeChangeTime(entry: PumpHistoryEntry) { + if (changeTimeRecord == null) return + entry.displayableValue = entry.dateTimeString + changeTimeRecord = null + } + + private fun decodeBatteryActivity(entry: PumpHistoryEntry) { + // this.writeData(PumpBaseType.Event, entry.getHead()[0] == 0 ? PumpEventType.BatteryRemoved : + // PumpEventType.BatteryReplaced, entry.getATechDate()); + entry.displayableValue = if (entry.head!![0] == 0.toByte()) "Battery Removed" else "Battery Replaced" + } + + private fun decodeBasalProfileStart(entry: PumpHistoryEntry): RecordDecodeStatus { + val body = entry.body + // int bodyOffset = headerSize + timestampSize; + val offset = body!![0] * 1000 * 30 * 60 + var rate: Float? = null + val index = entry.head!![0].toInt() + if (MedtronicDeviceType.isSameDevice(medtronicUtil!!.medtronicPumpModel, MedtronicDeviceType.Medtronic_523andHigher)) { + rate = body[1] * 0.025f + } + + //LOG.info("Basal Profile Start: offset={}, rate={}, index={}, body_raw={}", offset, rate, index, body); + return if (rate == null) { + aapsLogger!!.warn(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, "Basal Profile Start (ERROR): offset=%d, rate=%.3f, index=%d, body_raw=%s", offset, rate, index, ByteUtil.getHex(body))) + RecordDecodeStatus.Error + } else { + entry.addDecodedData("Value", getFormattedFloat(rate, 3)) + entry.displayableValue = getFormattedFloat(rate, 3) + RecordDecodeStatus.OK + } + } + + private fun decodeBolusWizard(entry: PumpHistoryEntry): RecordDecodeStatus { + val body = entry.body as IntArray + val dto = BolusWizardDTO() + var bolusStrokes = 10.0f + if (MedtronicDeviceType.isSameDevice(medtronicUtil!!.medtronicPumpModel, MedtronicDeviceType.Medtronic_523andHigher)) { + // https://github.com/ps2/minimed_rf/blob/master/lib/minimed_rf/log_entries/bolus_wizard.rb#L102 + bolusStrokes = 40.0f + dto.carbs = (body[1] and 0x0c shl 6) + body[0] + dto.bloodGlucose = (body[1] and 0x03 shl 8) + entry.head!![0] + dto.carbRatio = body[1] / 10.0f + // carb_ratio (?) = (((self.body[2] & 0x07) << 8) + self.body[3]) / + // 10.0s + dto.insulinSensitivity = body[4].toFloat() + dto.bgTargetLow = body[5] as Int + dto.bgTargetHigh = body[14] as Int + dto.correctionEstimate = ((body[9] and 0x38 shl 5) + body[6]) / bolusStrokes + dto.foodEstimate = ((body[7] shl 8) + body[8]) / bolusStrokes + dto.unabsorbedInsulin = ((body[10] shl 8) + body[11]) / bolusStrokes + dto.bolusTotal = ((body[12] shl 8) + body[13]) / bolusStrokes + } else { + dto.bloodGlucose = body.get(1) and 0x0F shl 8 or entry.head!!.get(0).toInt() + dto.carbs = body.get(0) as Int + dto.carbRatio = body.get(2).toFloat() + dto.insulinSensitivity = body.get(3).toFloat() + dto.bgTargetLow = body.get(4) as Int + dto.bgTargetHigh = body.get(12) as Int + dto.bolusTotal = body.get(11) / bolusStrokes + dto.foodEstimate = body.get(6) / bolusStrokes + dto.unabsorbedInsulin = body.get(9) / bolusStrokes + dto.bolusTotal = body.get(11) / bolusStrokes + dto.correctionEstimate = (body.get(7) + (body.get(5) and 0x0F)) / bolusStrokes + } + if (dto.bloodGlucose != null && dto.bloodGlucose < 0) { + dto.bloodGlucose = ByteUtil.convertUnsignedByteToInt(dto.bloodGlucose.toByte()) + } + dto.atechDateTime = entry.atechDateTime!! + entry.addDecodedData("Object", dto) + entry.displayableValue = dto.displayableValue + return RecordDecodeStatus.OK + } + + private fun decodeBolusWizard512(entry: PumpHistoryEntry): RecordDecodeStatus { + val body = entry.body as IntArray + val dto = BolusWizardDTO() + val bolusStrokes = 10.0f + dto.bloodGlucose = body.get(1) and 0x03 shl 8 or entry.head!!.get(0).toInt() + dto.carbs = body!!.get(1).toInt() and 0xC shl 6 or body.get(0).toInt() // (int)body[0]; + dto.carbRatio = body!!.get(2).toFloat() + dto.insulinSensitivity = body!!.get(3).toFloat() + dto.bgTargetLow = body.get(4) + dto.foodEstimate = body.get(6) / 10.0f + dto.correctionEstimate = (body.get(7) + (body.get(5) and 0x0F)) / bolusStrokes + dto.unabsorbedInsulin = body.get(9) / bolusStrokes + dto.bolusTotal = body.get(11) / bolusStrokes + dto.bgTargetHigh = dto.bgTargetLow + if (dto.bloodGlucose != null && dto.bloodGlucose < 0) { + dto.bloodGlucose = ByteUtil.convertUnsignedByteToInt(dto.bloodGlucose.toByte()) + } + dto.atechDateTime = entry.atechDateTime!! + entry.addDecodedData("Object", dto) + entry.displayableValue = dto.displayableValue + return RecordDecodeStatus.OK + } + + private fun decodeLowReservoir(entry: PumpHistoryEntry) { + val amount = getUnsignedInt(entry.head!!.get(0)) * 1.0f / 10.0f * 2 + entry.displayableValue = getFormattedValue(amount, 1) + } + + private fun decodePrime(entry: PumpHistoryEntry) { + val amount = ByteUtil.toInt(entry.head!!.get(2), entry.head!!.get(3)) / 10.0f + val fixed = ByteUtil.toInt(entry.head!!.get(0), entry.head!!.get(1)) / 10.0f + +// amount = (double)(asUINT8(data[4]) << 2) / 40.0; +// programmedAmount = (double)(asUINT8(data[2]) << 2) / 40.0; +// primeType = programmedAmount == 0 ? "manual" : "fixed"; + entry.addDecodedData("Amount", amount) + entry.addDecodedData("FixedAmount", fixed) + entry.displayableValue = ("Amount=" + getFormattedValue(amount, 2) + ", Fixed Amount=" + + getFormattedValue(fixed, 2)) + } + + private fun decodeChangeTempBasalType(entry: PumpHistoryEntry) { + entry.addDecodedData("isPercent", ByteUtil.asUINT8(entry.getRawDataByIndex(0)) == 1) // index moved from 1 -> 0 + } + + private fun decodeBgReceived(entry: PumpHistoryEntry) { + entry.addDecodedData("amount", (ByteUtil.asUINT8(entry.getRawDataByIndex(0)) shl 3) + (ByteUtil.asUINT8(entry.getRawDataByIndex(3)) shr 5)) + entry.addDecodedData("meter", ByteUtil.substring(entry.rawData, 6, 3)) // index moved from 1 -> 0 + } + + private fun decodeCalBGForPH(entry: PumpHistoryEntry) { + entry.addDecodedData("amount", (ByteUtil.asUINT8(entry.getRawDataByIndex(5)) and 0x80 shl 1) + ByteUtil.asUINT8(entry.getRawDataByIndex(0))) // index moved from 1 -> 0 + } + + private fun decodeNoDeliveryAlarm(entry: PumpHistoryEntry) { + //rawtype = asUINT8(data[1]); + // not sure if this is actually NoDelivery Alarm? + } + + override fun postProcess() {} + + override fun runPostDecodeTasks() { + showStatistics() + } + + private fun decodeBolus(entry: PumpHistoryEntry) { + val bolus = BolusDTO() + val data = entry.head as IntArray + if (MedtronicDeviceType.isSameDevice(medtronicUtil!!.getMedtronicPumpModel(), MedtronicDeviceType.Medtronic_523andHigher)) { + bolus.requestedAmount = ByteUtil.toInt(data.get(0), data.get(1)) / 40.0 + bolus.deliveredAmount = ByteUtil.toInt(data.get(2), data.get(3)) / 40.0 + bolus.insulinOnBoard = ByteUtil.toInt(data.get(4), data.get(5)) / 40.0 + bolus.duration = data.get(6) * 30 + } else { + bolus.requestedAmount = ByteUtil.asUINT8(data.get(0)) / 10.0 + bolus.deliveredAmount = ByteUtil.asUINT8(data.get(1)) / 10.0 + bolus.duration = ByteUtil.asUINT8(data.get(2)) * 30 + } + bolus.bolusType = if (bolus.duration != null && bolus.duration > 0) PumpBolusType.Extended else PumpBolusType.Normal + bolus.setAtechDateTime(entry.atechDateTime!!) + entry.addDecodedData("Object", bolus) + entry.displayableValue = bolus.displayableValue + } + + // private fun decodeTempBasal(entry: PumpHistoryEntry) { + // if (tbrPreviousRecord == null) { + // // LOG.debug(this.tbrPreviousRecord.toString()); + // tbrPreviousRecord = entry + // return + // } + // decodeTempBasal(tbrPreviousRecord, entry) + // tbrPreviousRecord = null + // } + + fun decodeTempBasal(tbrPreviousRecord: PumpHistoryEntry, entry: PumpHistoryEntry) { + var tbrRate: PumpHistoryEntry? = null + var tbrDuration: PumpHistoryEntry? = null + if (entry.entryType === PumpHistoryEntryType.TempBasalRate) { + tbrRate = entry + } else { + tbrDuration = entry + } + if (tbrRate != null) { + tbrDuration = tbrPreviousRecord + } else { + tbrRate = tbrPreviousRecord + } + +// TempBasalPair tbr = new TempBasalPair( +// tbrRate.getHead()[0], +// tbrDuration.getHead()[0], +// (ByteUtil.asUINT8(tbrRate.getDatetime()[4]) >> 3) == 0); + val tbr = TempBasalPair( + tbrRate!!.head!!.get(0), + tbrRate!!.body!!.get(0), + tbrDuration!!.head!!.get(0).toInt(), + ByteUtil.asUINT8(tbrRate!!.datetime!!.get(4)) shr 3 == 0) + + // System.out.println("TBR: amount=" + tbr.getInsulinRate() + ", duration=" + tbr.getDurationMinutes() + // // + " min. Packed: " + tbr.getValue() + // ); + entry.addDecodedData("Object", tbr) + entry.displayableValue = tbr.description + } + + private fun decodeDateTime(entry: PumpHistoryEntry) { + val dt = entry.datetime as IntArray + if (dt == null) { + aapsLogger!!.warn(LTag.PUMPBTCOMM, "DateTime not set.") + } + if (entry.dateTimeLength == 5) { + val seconds: Int = (dt!!.get(0) and 0x3F).toInt() + val minutes: Int = (dt!!.get(1) and 0x3F).toInt() + val hour: Int = (dt.get(2) and 0x1F).toInt() + val month: Int = (dt.get(0) shr 4 and 0x0c) + (dt.get(1) shr 6 and 0x03) + // ((dt[0] & 0xC0) >> 6) | ((dt[1] & 0xC0) >> 4); + val dayOfMonth: Int = dt.get(3) and 0x1F + val year = fix2DigitYear(dt.get(4) and 0x3F) // Assuming this is correct, need to verify. Otherwise this will be + // a problem in 2016. + entry.setAtechDateTime(DateTimeUtil.toATechDate(year, month, dayOfMonth, hour, minutes, seconds)) + } else if (entry.dateTimeLength == 2) { + val low = ByteUtil.asUINT8(dt.get(0)) and 0x1F + val mhigh = ByteUtil.asUINT8(dt.get(0)) and 0xE0 shr 4 + val mlow = ByteUtil.asUINT8(dt.get(1)) and 0x80 shr 7 + val month = mhigh + mlow + // int dayOfMonth = low + 1; + val dayOfMonth: Int = dt.get(0) and 0x1F + val year = 2000 + (ByteUtil.asUINT8(dt.get(1)) and 0x7F) + var hour = 0 + var minutes = 0 + var seconds = 0 + + //LOG.debug("DT: {} {} {}", year, month, dayOfMonth); + if (dayOfMonth == 32) { + aapsLogger!!.warn(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, "Entry: Day 32 %s = [%s] %s", entry.entryType!!.name, + ByteUtil.getHex(entry.rawData), entry)) + } + if (isEndResults(entry.entryType)) { + hour = 23 + minutes = 59 + seconds = 59 + } + entry.setAtechDateTime(DateTimeUtil.toATechDate(year, month, dayOfMonth, hour, minutes, seconds)) + } else { + aapsLogger!!.warn(LTag.PUMPBTCOMM, "Unknown datetime format: " + entry.dateTimeLength) + } + } + + private fun isEndResults(entryType: PumpHistoryEntryType?): Boolean { + return entryType === PumpHistoryEntryType.EndResultTotals || entryType === PumpHistoryEntryType.DailyTotals515 || entryType === PumpHistoryEntryType.DailyTotals522 || entryType === PumpHistoryEntryType.DailyTotals523 + } + + private fun fix2DigitYear(year: Int): Int { + var year = year + year += if (year > 90) { + 1900 + } else { + 2000 + } + return year + } + + companion object { + private fun getFormattedValue(value: Float, decimals: Int): String { + return String.format(Locale.ENGLISH, "%." + decimals + "f", value) + } + } + + init { + super.aapsLogger = aapsLogger + this.medtronicUtil = medtronicUtil + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.java deleted file mode 100644 index 3866e3e6ba..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.java +++ /dev/null @@ -1,174 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump; - -import com.google.gson.annotations.Expose; - -import java.util.Objects; - -import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil; -import info.nightscout.androidaps.plugins.pump.common.utils.StringUtil; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.MedtronicHistoryEntry; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicDeviceType; - -/** - * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes - * management and modified/extended for AAPS. - *

- * Author: Andy {andy.rozman@gmail.com} - */ - -public class PumpHistoryEntry extends MedtronicHistoryEntry { - - @Expose - private PumpHistoryEntryType entryType; - private Integer opCode; // this is set only when we have unknown entry... - private int offset; - private String displayableValue = ""; - - - public PumpHistoryEntryType getEntryType() { - return entryType; - } - - - public void setEntryType(MedtronicDeviceType medtronicDeviceType, PumpHistoryEntryType entryType) { - this.entryType = entryType; - - this.sizes[0] = entryType.getHeadLength(medtronicDeviceType); - this.sizes[1] = entryType.getDateLength(); - this.sizes[2] = entryType.getBodyLength(medtronicDeviceType); - - if (this.entryType != null && this.atechDateTime != null) - setPumpId(); - } - - - private void setPumpId() { - this.pumpId = this.entryType.getCode() + (this.atechDateTime * 1000L); - } - - - @Override - public int getOpCode() { - if (opCode == null) - return entryType.getOpCode(); - else - return opCode; - } - - - public void setOpCode(Integer opCode) { - this.opCode = opCode; - } - - - @Override - public String getToStringStart() { - return "PumpHistoryEntry [type=" + StringUtil.getStringInLength(entryType.name(), 20) + " [" - + StringUtil.getStringInLength("" + getOpCode(), 3) + ", 0x" - + ByteUtil.shortHexString((byte) getOpCode()) + "]"; - } - - - public String toString() { - return super.toString(); -// Object object = this.getDecodedDataEntry("Object"); -// -// if (object == null) { -// return super.toString(); -// } else { -// return super.toString() + "PumpHistoryEntry [type=" + StringUtil.getStringInLength(entryType.name(), 20) + ", DT: " + DT + ", Object=" + object.toString() + "]"; -// } - } - - - public int getOffset() { - return offset; - } - - - public void setOffset(int offset) { - this.offset = offset; - } - - - @Override - public String getEntryTypeName() { - return this.entryType.name(); - } - - - @Override - public int getDateLength() { - return this.entryType.getDateLength(); - } - - - @Override - public boolean equals(Object o) { - if (this == o) - return true; - - if (!(o instanceof PumpHistoryEntry)) - return false; - - PumpHistoryEntry that = (PumpHistoryEntry) o; - - return entryType == that.entryType && // - this.atechDateTime == that.atechDateTime; // && // - // Objects.equals(this.decodedData, that.decodedData); - } - - - @Override - public int hashCode() { - return Objects.hash(entryType, opCode, offset); - } - - - // public boolean isAfter(LocalDateTime dateTimeIn) { - // // LOG.debug("Entry: " + this.dateTime); - // // LOG.debug("Datetime: " + dateTimeIn); - // // LOG.debug("Item after: " + this.dateTime.isAfter(dateTimeIn)); - // return this.dateTime.isAfter(dateTimeIn); - // } - - public boolean isAfter(long atechDateTime) { - if (this.atechDateTime == null) { - LOG.error("Date is null. Show object: " + toString()); - return false; // FIXME shouldn't happen - } - - return atechDateTime < this.atechDateTime; - } - - - public void setDisplayableValue(String displayableValue) { - this.displayableValue = displayableValue; - } - - - public String getDisplayableValue() { - return displayableValue; - } - - public static class Comparator implements java.util.Comparator { - - @Override - public int compare(PumpHistoryEntry o1, PumpHistoryEntry o2) { - int data = (int) (o2.atechDateTime - o1.atechDateTime); - - if (data != 0) - return data; - - return o2.getEntryType().getCode() - o1.getEntryType().getCode(); - } - } - - - public Long getPumpId() { - setPumpId(); - - return pumpId; - } - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.kt new file mode 100644 index 0000000000..e1c0daf2ea --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.kt @@ -0,0 +1,117 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump + +import android.util.Log +import com.google.gson.annotations.Expose +import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil +import info.nightscout.androidaps.plugins.pump.common.utils.StringUtil +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.MedtronicHistoryEntry +import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicDeviceType +import java.util.* + +/** + * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes + * management and modified/extended for AAPS. + * + * + * Author: Andy {andy.rozman@gmail.com} + */ +class PumpHistoryEntry : MedtronicHistoryEntry() { + + @Expose var entryType: PumpHistoryEntryType? = null + private set + + override var opCode: Byte? = null + // this is set only when we have unknown entry... + get() = if (field == null) entryType!!.code else field + set(value) { + field = value + } + + // // override fun getOpCode(): Int { + // // return + // // } + // + // fun setOpCode(opCode: Int?) { + // this.opCode = opCode + // } + + var offset = 0 + var displayableValue = "" + + fun setEntryType(medtronicDeviceType: MedtronicDeviceType?, entryType: PumpHistoryEntryType) { + this.entryType = entryType + sizes[0] = entryType.getHeadLength(medtronicDeviceType) + sizes[1] = entryType.dateLength + sizes[2] = entryType.getBodyLength(medtronicDeviceType) + if (this.entryType != null && atechDateTime != null) setPumpId() + } + + private fun setPumpId() { + pumpId = entryType!!.code + atechDateTime!! * 1000L + } + + override val toStringStart: String + get() = ("PumpHistoryEntry [type=" + StringUtil.getStringInLength(entryType!!.name, 20) + " [" + + StringUtil.getStringInLength("" + opCode, 3) + ", 0x" + + ByteUtil.shortHexString(opCode!!) + "]") + + override fun toString(): String { + return super.toString() + // Object object = this.getDecodedDataEntry("Object"); +// +// if (object == null) { +// return super.toString(); +// } else { +// return super.toString() + "PumpHistoryEntry [type=" + StringUtil.getStringInLength(entryType.name(), 20) + ", DT: " + DT + ", Object=" + object.toString() + "]"; +// } + } + + override val entryTypeName: String + get() = entryType!!.name + + override val dateLength: Int + get() = entryType!!.dateLength + + override fun equals(o: Any?): Boolean { + if (this === o) return true + if (o !is PumpHistoryEntry) return false + val that = o + return entryType == that.entryType && // + atechDateTime === that.atechDateTime // && // + // Objects.equals(this.decodedData, that.decodedData); + } + + override fun hashCode(): Int { + return Objects.hash(entryType, opCode, offset) + } + + // public boolean isAfter(LocalDateTime dateTimeIn) { + // // LOG.debug("Entry: " + this.dateTime); + // // LOG.debug("Datetime: " + dateTimeIn); + // // LOG.debug("Item after: " + this.dateTime.isAfter(dateTimeIn)); + // return this.dateTime.isAfter(dateTimeIn); + // } + fun isAfter(atechDateTime: Long): Boolean { + if (this.atechDateTime == null) { + Log.e("PumpHistoryEntry", "Date is null. Show object: " + toString()) + return false // FIXME shouldn't happen + } + return atechDateTime < this.atechDateTime!! + } + + class Comparator : java.util.Comparator { + override fun compare(o1: PumpHistoryEntry, o2: PumpHistoryEntry): Int { + val data = (o2.atechDateTime!! - o1.atechDateTime!!).toInt() + return if (data != 0) data else o2.entryType!!.code - o1.entryType!!.code + } + } + + override var pumpId: Long? = null + get() { + setPumpId() + return field + } + set(pumpId) { + super.pumpId = pumpId + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntryType.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntryType.java deleted file mode 100644 index becfcfbcd2..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntryType.java +++ /dev/null @@ -1,378 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import info.nightscout.androidaps.plugins.pump.common.defs.PumpHistoryEntryGroup; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicDeviceType; - -/** - * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes - * management and modified/extended for AAPS. - *

- * Author: Andy {andy.rozman@gmail.com} - */ - -public enum PumpHistoryEntryType // implements CodeEnum -{ - // all commented out are probably not the real items - None(0, "None", PumpHistoryEntryGroup.Unknown, 1, 0, 0), - Bolus(0x01, "Bolus", PumpHistoryEntryGroup.Bolus, 4, 5, 0), // 523+[H=8] 9/13 - Prime(0x03, "Prime", PumpHistoryEntryGroup.Prime, 5, 5, 0), // - // /**/EventUnknown_MM522_0x05((byte) 0x05, "Unknown Event 0x05", PumpHistoryEntryGroup.Unknown, 2, 5, 28), // - NoDeliveryAlarm(0x06, "No Delivery", PumpHistoryEntryGroup.Alarm, 4, 5, 0), // - EndResultTotals(0x07, "End Result Totals", PumpHistoryEntryGroup.Statistic, 5, 2, 0), - ChangeBasalProfile_OldProfile(0x08, "Change Basal Profile (Old)", PumpHistoryEntryGroup.Basal, 2, 5, 145), - ChangeBasalProfile_NewProfile(0x09, "Change Basal Profile (New)", PumpHistoryEntryGroup.Basal, 2, 5, 145), // - // /**/EventUnknown_MM512_0x10(0x10, "Unknown Event 0x10", PumpHistoryEntryGroup.Unknown), // 29, 5, 0 - CalBGForPH(0x0a, "BG Capture", PumpHistoryEntryGroup.Glucose), // - SensorAlert(0x0b, "Sensor Alert", PumpHistoryEntryGroup.Alarm, 3, 5, 0), // Ian08 - ClearAlarm(0x0c, "Clear Alarm", PumpHistoryEntryGroup.Alarm, 2, 5, 0), // 2,5,4 - ChangeBasalPattern(0x14, "Change Basal Pattern", PumpHistoryEntryGroup.Basal), // - TempBasalDuration(0x16, "TBR Duration", PumpHistoryEntryGroup.Basal), // - ChangeTime(0x17, "Change Time", PumpHistoryEntryGroup.Configuration), // - NewTimeSet(0x18, "New Time Set", PumpHistoryEntryGroup.Notification), // - LowBattery(0x19, "LowBattery", PumpHistoryEntryGroup.Notification), // - BatteryChange(0x1a, "Battery Change", PumpHistoryEntryGroup.Notification), // - SetAutoOff(0x1b, "Set Auto Off", PumpHistoryEntryGroup.Configuration), // - SuspendPump(0x1e, "Suspend", PumpHistoryEntryGroup.Basal), // - ResumePump(0x1f, "Resume", PumpHistoryEntryGroup.Basal), // - SelfTest(0x20, "Self Test", PumpHistoryEntryGroup.Statistic), // - Rewind(0x21, "Rewind", PumpHistoryEntryGroup.Prime), // - ClearSettings(0x22, "Clear Settings", PumpHistoryEntryGroup.Configuration), // - ChangeChildBlockEnable(0x23, "Change Child Block Enable", PumpHistoryEntryGroup.Configuration), // - ChangeMaxBolus(0x24, "Change Max Bolus", PumpHistoryEntryGroup.Configuration), // - // /**/EventUnknown_MM522_0x25(0x25, "Unknown Event 0x25", PumpHistoryEntryGroup.Unknown), // 8? - EnableDisableRemote(0x26, "Enable/Disable Remote", PumpHistoryEntryGroup.Configuration, 2, 5, 14), // 2, 5, 14 V6:2,5,14 - ChangeRemoteId(0x27, "Change Remote ID", PumpHistoryEntryGroup.Configuration), // ?? - ChangeMaxBasal(0x2c, "Change Max Basal", PumpHistoryEntryGroup.Configuration), // - BolusWizardEnabled(0x2d, "Bolus Wizard Enabled", PumpHistoryEntryGroup.Configuration), // V3 ? - /* TODO */EventUnknown_MM512_0x2e(0x2e, "Unknown Event 0x2e", PumpHistoryEntryGroup.Unknown, 2, 5, 100), // - BolusWizard512(0x2f, "Bolus Wizard (512)", PumpHistoryEntryGroup.Bolus, 2, 5, 12), // - UnabsorbedInsulin512(0x30, "Unabsorbed Insulin (512)", PumpHistoryEntryGroup.Statistic, 5, 0, 0), // FIXME - ChangeBGReminderOffset(0x31, "Change BG Reminder Offset", PumpHistoryEntryGroup.Configuration), // - ChangeAlarmClockTime(0x32, "Change Alarm Clock Time", PumpHistoryEntryGroup.Configuration), // - TempBasalRate(0x33, "TBR Rate", PumpHistoryEntryGroup.Basal, 2, 5, 1), // - LowReservoir(0x34, "Low Reservoir", PumpHistoryEntryGroup.Notification), // - ChangeAlarmClock(0x35, "Change Alarm Clock", PumpHistoryEntryGroup.Configuration), // - ChangeMeterId(0x36, "Change Meter ID", PumpHistoryEntryGroup.Configuration), // - // /**/EventUnknown_MM512_0x37(0x37, "Unknown Event 0x37", PumpHistoryEntryGroup.Unknown), // V:MM512 -// /**/EventUnknown_MM512_0x38(0x38, "Unknown Event 0x38", PumpHistoryEntryGroup.Unknown), // - BGReceived512(0x39, "BG Received (512)", PumpHistoryEntryGroup.Glucose, 2, 5, 3), // - /* TODO */ConfirmInsulinChange(0x3a, "Confirm Insulin Change", PumpHistoryEntryGroup.Unknown), // - SensorStatus(0x3b, "Sensor Status", PumpHistoryEntryGroup.Glucose), // - ChangeParadigmID(0x3c, "Change Paradigm ID", PumpHistoryEntryGroup.Configuration, 2, 5, 14), // V3 ? V6: 2,5,14 ?? is it this length or just 7 - // EventUnknown_MM512_0x3D(0x3d, "Unknown Event 0x3D", PumpHistoryEntryGroup.Unknown), // -// EventUnknown_MM512_0x3E(0x3e, "Unknown Event 0x3E", PumpHistoryEntryGroup.Unknown), // - BGReceived(0x3f, "BG Received", PumpHistoryEntryGroup.Glucose, 2, 5, 3), // Ian3F - JournalEntryMealMarker(0x40, "Meal Marker", PumpHistoryEntryGroup.Bolus, 2, 5, 2), // is size just 7??? V6 - JournalEntryExerciseMarker(0x41, "Exercise Marker", PumpHistoryEntryGroup.Bolus, 2, 5, 1), // ?? - JournalEntryInsulinMarker(0x42, "Insulin Marker", PumpHistoryEntryGroup.Bolus, 2, 5, 0), // V6 = body(0)/was=1 - JournalEntryOtherMarker(0x43, "Other Marker", PumpHistoryEntryGroup.Bolus, 2, 5, 1), // V6 = body(1)/was=0 - EnableSensorAutoCal(0x44, "Enable Sensor AutoCal", PumpHistoryEntryGroup.Glucose), // - // /**/EventUnknown_MM522_0x45(0x45, "Unknown Event 0x45", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // -// /**/EventUnknown_MM522_0x46(0x46, "Unknown Event 0x46", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // -// /**/EventUnknown_MM522_0x47(0x47, "Unknown Event 0x47", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // -// /**/EventUnknown_MM522_0x48(0x48, "Unknown Event 0x48", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // -// /**/EventUnknown_MM522_0x49(0x49, "Unknown Event 0x49", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // -// /**/EventUnknown_MM522_0x4a(0x4a, "Unknown Event 0x4a", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // -// /**/EventUnknown_MM522_0x4b(0x4b, "Unknown Event 0x4b", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // -// /**/EventUnknown_MM522_0x4c(0x4c, "Unknown Event 0x4c", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // -// /**/EventUnknown_0x4d(0x4d, "Unknown Event 0x4d", PumpHistoryEntryGroup.Unknown), // V5: 512: 7, 522: 8 ????NS -// /**/EventUnknown_MM512_0x4e(0x4e, "Unknown Event 0x4e", PumpHistoryEntryGroup.Unknown), // /**/ - BolusWizardSetup512(0x4f, "Bolus Wizard Setup (512)", PumpHistoryEntryGroup.Configuration, 2, 5, 32), // - ChangeSensorSetup2(0x50, "Sensor Setup2", PumpHistoryEntryGroup.Configuration, 2, 5, 30), // Ian50 - /* TODO */Sensor_0x51(0x51, "Unknown Event 0x51", PumpHistoryEntryGroup.Unknown), // - /* TODO */Sensor_0x52(0x52, "Unknown Event 0x52", PumpHistoryEntryGroup.Unknown), // - ChangeSensorAlarmSilenceConfig(0x53, "Sensor Alarm Silence Config", PumpHistoryEntryGroup.Configuration, 2, 5, 1), // 8 - /* TODO */Sensor_0x54(0x54, "Unknown Event 0x54", PumpHistoryEntryGroup.Unknown), // Ian54 - /* TODO */Sensor_0x55(0x55, "Unknown Event 0x55", PumpHistoryEntryGroup.Unknown), // - ChangeSensorRateOfChangeAlertSetup(0x56, "Sensor Rate Of Change Alert Setup", PumpHistoryEntryGroup.Configuration, 2, 5, 5), // 12 - ChangeBolusScrollStepSize(0x57, "Change Bolus Scroll Step Size", PumpHistoryEntryGroup.Configuration), // - BolusWizardSetup(0x5a, "Bolus Wizard Setup (522)", PumpHistoryEntryGroup.Configuration, 2, 5, 117), - // V2: 522+[B=143]; V6: 124, v6: 137, v7: 117/137 [523] - BolusWizard(0x5b, "Bolus Wizard Estimate", PumpHistoryEntryGroup.Configuration, 2, 5, 13), // 15 // - UnabsorbedInsulin(0x5c, "Unabsorbed Insulin", PumpHistoryEntryGroup.Statistic, 5, 0, 0), // head[1] -> body - SaveSettings(0x5d, "Save Settings", PumpHistoryEntryGroup.Configuration), // - ChangeVariableBolus(0x5e, "Change Variable Bolus", PumpHistoryEntryGroup.Configuration), // - ChangeAudioBolus(0x5f, "Easy Bolus Enabled", PumpHistoryEntryGroup.Configuration), // V3 ? - ChangeBGReminderEnable(0x60, "BG Reminder Enable", PumpHistoryEntryGroup.Configuration), // questionable60 - ChangeAlarmClockEnable(0x61, "Alarm Clock Enable", PumpHistoryEntryGroup.Configuration), // - ChangeTempBasalType((byte) 0x62, "Change Basal Type", PumpHistoryEntryGroup.Configuration), // ChangeTempBasalTypePumpEvent - ChangeAlarmNotifyMode(0x63, "Change Alarm Notify Mode", PumpHistoryEntryGroup.Configuration), // - ChangeTimeFormat(0x64, "Change Time Format", PumpHistoryEntryGroup.Configuration), // - ChangeReservoirWarningTime((byte) 0x65, "Change Reservoir Warning Time", PumpHistoryEntryGroup.Configuration), // - ChangeBolusReminderEnable(0x66, "Change Bolus Reminder Enable", PumpHistoryEntryGroup.Configuration), // 9 - SetBolusReminderTime((byte) 0x67, "Change Bolus Reminder Time", PumpHistoryEntryGroup.Configuration, 2, 5, 2), // 9 - DeleteBolusReminderTime((byte) 0x68, "Delete Bolus Reminder Time", PumpHistoryEntryGroup.Configuration, 2, 5, 2), // 9 - BolusReminder(0x69, "Bolus Reminder", PumpHistoryEntryGroup.Configuration, 2, 5, 0), // Ian69 - DeleteAlarmClockTime(0x6a, "Delete Alarm Clock Time", PumpHistoryEntryGroup.Configuration, 2, 5, 7), // 14 - DailyTotals515(0x6c, "Daily Totals (515)", PumpHistoryEntryGroup.Statistic, 1, 2, 35), // v4: 0,0,36. v5: 1,2,33 - DailyTotals522(0x6d, "Daily Totals (522)", PumpHistoryEntryGroup.Statistic, 1, 2, 41), // - DailyTotals523(0x6e, "Daily Totals (523)", PumpHistoryEntryGroup.Statistic, 1, 2, 49), // 1102014-03-17T00:00:00 - ChangeCarbUnits((byte) 0x6f, "Change Carb Units", PumpHistoryEntryGroup.Configuration), // - // /**/EventUnknown_MM522_0x70((byte) 0x70, "Unknown Event 0x70", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // - BasalProfileStart(0x7b, "Basal Profile Start", PumpHistoryEntryGroup.Basal, 2, 5, 3), // // 722 - ChangeWatchdogEnable((byte) 0x7c, "Change Watchdog Enable", PumpHistoryEntryGroup.Configuration), // - ChangeOtherDeviceID((byte) 0x7d, "Change Other Device ID", PumpHistoryEntryGroup.Configuration, 2, 5, 30), // - ChangeWatchdogMarriageProfile(0x81, "Change Watchdog Marriage Profile", PumpHistoryEntryGroup.Configuration, 2, 5, 5), // 12 - DeleteOtherDeviceID(0x82, "Delete Other Device ID", PumpHistoryEntryGroup.Configuration, 2, 5, 5), // - ChangeCaptureEventEnable(0x83, "Change Capture Event Enable", PumpHistoryEntryGroup.Configuration), // - // /**/EventUnknown_MM512_0x88(0x88, "Unknown Event 0x88", PumpHistoryEntryGroup.Unknown), // -// /**/EventUnknown_MM512_0x94(0x94, "Unknown Event 0x94", PumpHistoryEntryGroup.Unknown), // - /**/ IanA8(0xA8, "Ian A8 (Unknown)", PumpHistoryEntryGroup.Unknown, 10, 5, 0), // - // /**/EventUnknown_MM522_0xE8(0xe8, "Unknown Event 0xE8", PumpHistoryEntryGroup.Unknown, 2, 5, 25), // - // F0 - F3 are not in go code, but they are in GGC one and thet are used - ReadOtherDevicesIDs(0xf0, "Read Other Devices IDs", PumpHistoryEntryGroup.Configuration), // ? - ReadCaptureEventEnabled(0xf1, "Read Capture Event Enabled", PumpHistoryEntryGroup.Configuration), // ? - ChangeCaptureEventEnable2(0xf2, "Change Capture Event Enable2", PumpHistoryEntryGroup.Configuration), // ? - ReadOtherDevicesStatus(0xf3, "Read Other Devices Status", PumpHistoryEntryGroup.Configuration), // ? - - TempBasalCombined(0xfe, "TBR", PumpHistoryEntryGroup.Basal), // - UnknownBasePacket(0xff, "Unknown Base Packet", PumpHistoryEntryGroup.Unknown); - - private static final Map opCodeMap = new HashMap<>(); - - static { - for (PumpHistoryEntryType type : values()) { - opCodeMap.put(type.opCode, type); - } - - setSpecialRulesForEntryTypes(); - } - - private final int opCode; - private final String description; - private final int headLength; - private final int dateLength; - // private MinimedDeviceType deviceType; - private final int bodyLength; - private final int totalLength; - // special rules need to be put in list from highest to lowest (e.g.: - // 523andHigher=12, 515andHigher=10 and default (set in cnstr) would be 8) - private List specialRulesHead; - private List specialRulesBody; - private boolean hasSpecialRules = false; - private final PumpHistoryEntryGroup group; - - - PumpHistoryEntryType(int opCode, String name, PumpHistoryEntryGroup group) { - this(opCode, name, group, 2, 5, 0); - } - - - PumpHistoryEntryType(int opCode, PumpHistoryEntryGroup group) { - this(opCode, null, group, 2, 5, 0); - } - - - PumpHistoryEntryType(int opCode, PumpHistoryEntryGroup group, int head, int date, int body) { - this(opCode, null, group, head, date, body); - } - - - PumpHistoryEntryType(int opCode, String name, PumpHistoryEntryGroup group, int head, int date, int body) { - this.opCode = (byte) opCode; - this.description = name; - this.headLength = head; - this.dateLength = date; - this.bodyLength = body; - this.totalLength = (head + date + body); - this.group = group; - } - - - static void setSpecialRulesForEntryTypes() { - EndResultTotals.addSpecialRuleBody(new SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 3)); - Bolus.addSpecialRuleHead(new SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 8)); - BolusWizardSetup.addSpecialRuleBody(new SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 137)); - BolusWizard.addSpecialRuleBody(new SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 15)); - BolusReminder.addSpecialRuleBody(new SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 2)); - ChangeSensorSetup2.addSpecialRuleBody(new SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 34)); - } - - - public static PumpHistoryEntryType getByCode(int opCode) { - if (opCodeMap.containsKey(opCode)) { - return opCodeMap.get(opCode); - } else { - return PumpHistoryEntryType.UnknownBasePacket; - } - } - - - // - // private PumpHistoryEntryType(int opCode, String name, int head, int date, - // int body) - // { - // this.opCode = (byte) opCode; - // this.description = name; - // this.headLength = head; - // this.dateLength = date; - // this.bodyLength = body; - // this.totalLength = (head + date + body); - // } - // - - public static boolean isAAPSRelevantEntry(PumpHistoryEntryType entryType) { - return (entryType == PumpHistoryEntryType.Bolus || // Treatments - entryType == PumpHistoryEntryType.TempBasalRate || // - entryType == PumpHistoryEntryType.TempBasalDuration || // - - entryType == PumpHistoryEntryType.Prime || // Pump Status Change - entryType == PumpHistoryEntryType.SuspendPump || // - entryType == PumpHistoryEntryType.ResumePump || // - entryType == PumpHistoryEntryType.Rewind || // - entryType == PumpHistoryEntryType.NoDeliveryAlarm || // no delivery - entryType == PumpHistoryEntryType.BasalProfileStart || // - - entryType == PumpHistoryEntryType.ChangeTime || // Time Change - entryType == PumpHistoryEntryType.NewTimeSet || // - - entryType == PumpHistoryEntryType.ChangeBasalPattern || // Configuration - entryType == PumpHistoryEntryType.ClearSettings || // - entryType == PumpHistoryEntryType.SaveSettings || // - entryType == PumpHistoryEntryType.ChangeMaxBolus || // - entryType == PumpHistoryEntryType.ChangeMaxBasal || // - entryType == PumpHistoryEntryType.ChangeTempBasalType || // - - entryType == PumpHistoryEntryType.ChangeBasalProfile_NewProfile || // Basal profile - - entryType == PumpHistoryEntryType.DailyTotals515 || // Daily Totals - entryType == PumpHistoryEntryType.DailyTotals522 || // - entryType == PumpHistoryEntryType.DailyTotals523 || // - entryType == PumpHistoryEntryType.EndResultTotals); - } - - - public static boolean isRelevantEntry() { - return true; - } - - - public int getCode() { - return this.opCode; - } - - - public int getTotalLength(MedtronicDeviceType medtronicDeviceType) { - if (hasSpecialRules()) { - return getHeadLength(medtronicDeviceType) + getBodyLength(medtronicDeviceType) + getDateLength(); - } else { - return totalLength; - } - } - - - private boolean hasSpecialRules() { - return hasSpecialRules; - } - - - void addSpecialRuleHead(SpecialRule rule) { - if (isEmpty(specialRulesHead)) { - specialRulesHead = new ArrayList<>(); - } - - specialRulesHead.add(rule); - hasSpecialRules = true; - } - - - void addSpecialRuleBody(SpecialRule rule) { - if (isEmpty(specialRulesBody)) { - specialRulesBody = new ArrayList<>(); - } - - specialRulesBody.add(rule); - hasSpecialRules = true; - } - - - public int getOpCode() { - return opCode; - } - - - public String getDescription() { - return this.description == null ? name() : this.description; - } - - - public int getHeadLength(MedtronicDeviceType medtronicDeviceType) { - if (hasSpecialRules) { - if (isNotEmpty(specialRulesHead)) { - return determineSizeByRule(medtronicDeviceType, headLength, specialRulesHead); - } else { - return headLength; - } - } else { - return headLength; - } - } - - - public int getDateLength() { - return dateLength; - } - - - public int getBodyLength(MedtronicDeviceType medtronicDeviceType) { - if (hasSpecialRules) { - if (isNotEmpty(specialRulesBody)) { - return determineSizeByRule(medtronicDeviceType, bodyLength, specialRulesBody); - } else { - return bodyLength; - } - } else { - return bodyLength; - } - } - - - private boolean isNotEmpty(List list) { - return list != null && !list.isEmpty(); - } - - - private boolean isEmpty(List list) { - return list == null || list.isEmpty(); - } - - - // byte[] dh = { 2, 3 }; - - private int determineSizeByRule(MedtronicDeviceType medtronicDeviceType, int defaultValue, List rules) { - int size = defaultValue; - - for (SpecialRule rule : rules) { - if (MedtronicDeviceType.isSameDevice(medtronicDeviceType, rule.deviceType)) { - size = rule.size; - break; - } - } - - return size; - } - - - public PumpHistoryEntryGroup getGroup() { - - return group; - } - - public static class SpecialRule { - - MedtronicDeviceType deviceType; - int size; - - - SpecialRule(MedtronicDeviceType deviceType, int size) { - this.deviceType = deviceType; - this.size = size; - } - } - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntryType.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntryType.kt new file mode 100644 index 0000000000..3f2a4a0c40 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntryType.kt @@ -0,0 +1,323 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump + +import info.nightscout.androidaps.plugins.pump.common.defs.PumpHistoryEntryGroup +import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicDeviceType +import java.util.* + +/** + * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes + * management and modified/extended for AAPS. + * + * + * Author: Andy {andy.rozman@gmail.com} + */ +enum class PumpHistoryEntryType // implements CodeEnum +@JvmOverloads constructor(opCode: Byte, name: String?, group: PumpHistoryEntryGroup, head: Int = 2, date: Int = 5, body: Int = 0) { + + // all commented out are probably not the real items + None(0, "None", PumpHistoryEntryGroup.Unknown, 1, 0, 0), Bolus(0x01, "Bolus", PumpHistoryEntryGroup.Bolus, 4, 5, 0), // 523+[H=8] 9/13 + Prime(0x03, "Prime", PumpHistoryEntryGroup.Prime, 5, 5, 0), // + + // /**/EventUnknown_MM522_0x05((byte) 0x05, "Unknown Event 0x05", PumpHistoryEntryGroup.Unknown, 2, 5, 28), // + NoDeliveryAlarm(0x06, "No Delivery", PumpHistoryEntryGroup.Alarm, 4, 5, 0), // + EndResultTotals(0x07, "End Result Totals", PumpHistoryEntryGroup.Statistic, 5, 2, 0), ChangeBasalProfile_OldProfile(0x08, "Change Basal Profile (Old)", PumpHistoryEntryGroup.Basal, 2, 5, 145), ChangeBasalProfile_NewProfile(0x09, "Change Basal Profile (New)", PumpHistoryEntryGroup.Basal, 2, 5, 145), // + + // /**/EventUnknown_MM512_0x10(0x10, "Unknown Event 0x10", PumpHistoryEntryGroup.Unknown), // 29, 5, 0 + CalBGForPH(0x0a, "BG Capture", PumpHistoryEntryGroup.Glucose), // + SensorAlert(0x0b, "Sensor Alert", PumpHistoryEntryGroup.Alarm, 3, 5, 0), // Ian08 + ClearAlarm(0x0c, "Clear Alarm", PumpHistoryEntryGroup.Alarm, 2, 5, 0), // 2,5,4 + ChangeBasalPattern(0x14, "Change Basal Pattern", PumpHistoryEntryGroup.Basal), // + TempBasalDuration(0x16, "TBR Duration", PumpHistoryEntryGroup.Basal), // + ChangeTime(0x17, "Change Time", PumpHistoryEntryGroup.Configuration), // + NewTimeSet(0x18, "New Time Set", PumpHistoryEntryGroup.Notification), // + LowBattery(0x19, "LowBattery", PumpHistoryEntryGroup.Notification), // + BatteryChange(0x1a, "Battery Change", PumpHistoryEntryGroup.Notification), // + SetAutoOff(0x1b, "Set Auto Off", PumpHistoryEntryGroup.Configuration), // + SuspendPump(0x1e, "Suspend", PumpHistoryEntryGroup.Basal), // + ResumePump(0x1f, "Resume", PumpHistoryEntryGroup.Basal), // + SelfTest(0x20, "Self Test", PumpHistoryEntryGroup.Statistic), // + Rewind(0x21, "Rewind", PumpHistoryEntryGroup.Prime), // + ClearSettings(0x22, "Clear Settings", PumpHistoryEntryGroup.Configuration), // + ChangeChildBlockEnable(0x23, "Change Child Block Enable", PumpHistoryEntryGroup.Configuration), // + ChangeMaxBolus(0x24, "Change Max Bolus", PumpHistoryEntryGroup.Configuration), // + + // /**/EventUnknown_MM522_0x25(0x25, "Unknown Event 0x25", PumpHistoryEntryGroup.Unknown), // 8? + EnableDisableRemote(0x26, "Enable/Disable Remote", PumpHistoryEntryGroup.Configuration, 2, 5, 14), // 2, 5, 14 V6:2,5,14 + ChangeRemoteId(0x27, "Change Remote ID", PumpHistoryEntryGroup.Configuration), // ?? + ChangeMaxBasal(0x2c, "Change Max Basal", PumpHistoryEntryGroup.Configuration), // + BolusWizardEnabled(0x2d, "Bolus Wizard Enabled", PumpHistoryEntryGroup.Configuration), // V3 ? + + /* TODO */ + EventUnknown_MM512_0x2e(0x2e, "Unknown Event 0x2e", PumpHistoryEntryGroup.Unknown, 2, 5, 100), // + BolusWizard512(0x2f, "Bolus Wizard (512)", PumpHistoryEntryGroup.Bolus, 2, 5, 12), // + UnabsorbedInsulin512(0x30, "Unabsorbed Insulin (512)", PumpHistoryEntryGroup.Statistic, 5, 0, 0), // FIXME + ChangeBGReminderOffset(0x31, "Change BG Reminder Offset", PumpHistoryEntryGroup.Configuration), // + ChangeAlarmClockTime(0x32, "Change Alarm Clock Time", PumpHistoryEntryGroup.Configuration), // + TempBasalRate(0x33, "TBR Rate", PumpHistoryEntryGroup.Basal, 2, 5, 1), // + LowReservoir(0x34, "Low Reservoir", PumpHistoryEntryGroup.Notification), // + ChangeAlarmClock(0x35, "Change Alarm Clock", PumpHistoryEntryGroup.Configuration), // + ChangeMeterId(0x36, "Change Meter ID", PumpHistoryEntryGroup.Configuration), // + + // /**/EventUnknown_MM512_0x37(0x37, "Unknown Event 0x37", PumpHistoryEntryGroup.Unknown), // V:MM512 + // /**/EventUnknown_MM512_0x38(0x38, "Unknown Event 0x38", PumpHistoryEntryGroup.Unknown), // + BGReceived512(0x39, "BG Received (512)", PumpHistoryEntryGroup.Glucose, 2, 5, 3), // + + /* TODO */ + ConfirmInsulinChange(0x3a, "Confirm Insulin Change", PumpHistoryEntryGroup.Unknown), // + SensorStatus(0x3b, "Sensor Status", PumpHistoryEntryGroup.Glucose), // + ChangeParadigmID(0x3c, "Change Paradigm ID", PumpHistoryEntryGroup.Configuration, 2, 5, 14), // V3 ? V6: 2,5,14 ?? is it this length or just 7 + + // EventUnknown_MM512_0x3D(0x3d, "Unknown Event 0x3D", PumpHistoryEntryGroup.Unknown), // + // EventUnknown_MM512_0x3E(0x3e, "Unknown Event 0x3E", PumpHistoryEntryGroup.Unknown), // + BGReceived(0x3f, "BG Received", PumpHistoryEntryGroup.Glucose, 2, 5, 3), // Ian3F + JournalEntryMealMarker(0x40, "Meal Marker", PumpHistoryEntryGroup.Bolus, 2, 5, 2), // is size just 7??? V6 + JournalEntryExerciseMarker(0x41, "Exercise Marker", PumpHistoryEntryGroup.Bolus, 2, 5, 1), // ?? + JournalEntryInsulinMarker(0x42, "Insulin Marker", PumpHistoryEntryGroup.Bolus, 2, 5, 0), // V6 = body(0)/was=1 + JournalEntryOtherMarker(0x43, "Other Marker", PumpHistoryEntryGroup.Bolus, 2, 5, 1), // V6 = body(1)/was=0 + EnableSensorAutoCal(0x44, "Enable Sensor AutoCal", PumpHistoryEntryGroup.Glucose), // + + // /**/EventUnknown_MM522_0x45(0x45, "Unknown Event 0x45", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // + // /**/EventUnknown_MM522_0x46(0x46, "Unknown Event 0x46", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // + // /**/EventUnknown_MM522_0x47(0x47, "Unknown Event 0x47", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // + // /**/EventUnknown_MM522_0x48(0x48, "Unknown Event 0x48", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // + // /**/EventUnknown_MM522_0x49(0x49, "Unknown Event 0x49", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // + // /**/EventUnknown_MM522_0x4a(0x4a, "Unknown Event 0x4a", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // + // /**/EventUnknown_MM522_0x4b(0x4b, "Unknown Event 0x4b", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // + // /**/EventUnknown_MM522_0x4c(0x4c, "Unknown Event 0x4c", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // + // /**/EventUnknown_0x4d(0x4d, "Unknown Event 0x4d", PumpHistoryEntryGroup.Unknown), // V5: 512: 7, 522: 8 ????NS + // /**/EventUnknown_MM512_0x4e(0x4e, "Unknown Event 0x4e", PumpHistoryEntryGroup.Unknown), // /**/ + BolusWizardSetup512(0x4f, "Bolus Wizard Setup (512)", PumpHistoryEntryGroup.Configuration, 2, 5, 32), // + ChangeSensorSetup2(0x50, "Sensor Setup2", PumpHistoryEntryGroup.Configuration, 2, 5, 30), // Ian50 + + /* TODO */ + Sensor_0x51(0x51, "Unknown Event 0x51", PumpHistoryEntryGroup.Unknown), // + + /* TODO */ + Sensor_0x52(0x52, "Unknown Event 0x52", PumpHistoryEntryGroup.Unknown), // + ChangeSensorAlarmSilenceConfig(0x53, "Sensor Alarm Silence Config", PumpHistoryEntryGroup.Configuration, 2, 5, 1), // 8 + + /* TODO */ + Sensor_0x54(0x54, "Unknown Event 0x54", PumpHistoryEntryGroup.Unknown), // Ian54 + + /* TODO */ + Sensor_0x55(0x55, "Unknown Event 0x55", PumpHistoryEntryGroup.Unknown), // + ChangeSensorRateOfChangeAlertSetup(0x56, "Sensor Rate Of Change Alert Setup", PumpHistoryEntryGroup.Configuration, 2, 5, 5), // 12 + ChangeBolusScrollStepSize(0x57, "Change Bolus Scroll Step Size", PumpHistoryEntryGroup.Configuration), // + BolusWizardSetup(0x5a, "Bolus Wizard Setup (522)", PumpHistoryEntryGroup.Configuration, 2, 5, 117), // V2: 522+[B=143]; V6: 124, v6: 137, v7: 117/137 [523] + BolusWizard(0x5b, "Bolus Wizard Estimate", PumpHistoryEntryGroup.Configuration, 2, 5, 13), // 15 // + UnabsorbedInsulin(0x5c, "Unabsorbed Insulin", PumpHistoryEntryGroup.Statistic, 5, 0, 0), // head[1] -> body + SaveSettings(0x5d, "Save Settings", PumpHistoryEntryGroup.Configuration), // + ChangeVariableBolus(0x5e, "Change Variable Bolus", PumpHistoryEntryGroup.Configuration), // + ChangeAudioBolus(0x5f, "Easy Bolus Enabled", PumpHistoryEntryGroup.Configuration), // V3 ? + ChangeBGReminderEnable(0x60, "BG Reminder Enable", PumpHistoryEntryGroup.Configuration), // questionable60 + ChangeAlarmClockEnable(0x61, "Alarm Clock Enable", PumpHistoryEntryGroup.Configuration), // + ChangeTempBasalType(0x62.toByte(), "Change Basal Type", PumpHistoryEntryGroup.Configuration), // ChangeTempBasalTypePumpEvent + ChangeAlarmNotifyMode(0x63, "Change Alarm Notify Mode", PumpHistoryEntryGroup.Configuration), // + ChangeTimeFormat(0x64, "Change Time Format", PumpHistoryEntryGroup.Configuration), // + ChangeReservoirWarningTime(0x65.toByte(), "Change Reservoir Warning Time", PumpHistoryEntryGroup.Configuration), // + ChangeBolusReminderEnable(0x66, "Change Bolus Reminder Enable", PumpHistoryEntryGroup.Configuration), // 9 + SetBolusReminderTime(0x67.toByte(), "Change Bolus Reminder Time", PumpHistoryEntryGroup.Configuration, 2, 5, 2), // 9 + DeleteBolusReminderTime(0x68.toByte(), "Delete Bolus Reminder Time", PumpHistoryEntryGroup.Configuration, 2, 5, 2), // 9 + BolusReminder(0x69, "Bolus Reminder", PumpHistoryEntryGroup.Configuration, 2, 5, 0), // Ian69 + DeleteAlarmClockTime(0x6a, "Delete Alarm Clock Time", PumpHistoryEntryGroup.Configuration, 2, 5, 7), // 14 + DailyTotals515(0x6c, "Daily Totals (515)", PumpHistoryEntryGroup.Statistic, 1, 2, 35), // v4: 0,0,36. v5: 1,2,33 + DailyTotals522(0x6d, "Daily Totals (522)", PumpHistoryEntryGroup.Statistic, 1, 2, 41), // + DailyTotals523(0x6e, "Daily Totals (523)", PumpHistoryEntryGroup.Statistic, 1, 2, 49), // 1102014-03-17T00:00:00 + ChangeCarbUnits(0x6f.toByte(), "Change Carb Units", PumpHistoryEntryGroup.Configuration), // + + // /**/EventUnknown_MM522_0x70((byte) 0x70, "Unknown Event 0x70", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // + BasalProfileStart(0x7b, "Basal Profile Start", PumpHistoryEntryGroup.Basal, 2, 5, 3), // // 722 + ChangeWatchdogEnable(0x7c, "Change Watchdog Enable", PumpHistoryEntryGroup.Configuration), // + ChangeOtherDeviceID(0x7d, "Change Other Device ID", PumpHistoryEntryGroup.Configuration, 2, 5, 30), // + ChangeWatchdogMarriageProfile(0x81.toByte(), "Change Watchdog Marriage Profile", PumpHistoryEntryGroup.Configuration, 2, 5, 5), // 12 + DeleteOtherDeviceID(0x82.toByte(), "Delete Other Device ID", PumpHistoryEntryGroup.Configuration, 2, 5, 5), // + ChangeCaptureEventEnable(0x83.toByte(), "Change Capture Event Enable", PumpHistoryEntryGroup.Configuration), // + + // /**/EventUnknown_MM512_0x88(0x88, "Unknown Event 0x88", PumpHistoryEntryGroup.Unknown), // + // /**/EventUnknown_MM512_0x94(0x94, "Unknown Event 0x94", PumpHistoryEntryGroup.Unknown), // + /**/ + IanA8(0xA8.toByte(), "Ian A8 (Unknown)", PumpHistoryEntryGroup.Unknown, 10, 5, 0), // + + // /**/EventUnknown_MM522_0xE8(0xe8, "Unknown Event 0xE8", PumpHistoryEntryGroup.Unknown, 2, 5, 25), // + // F0 - F3 are not in go code, but they are in GGC one and thet are used + ReadOtherDevicesIDs(0xf0.toByte(), "Read Other Devices IDs", PumpHistoryEntryGroup.Configuration), // ? + ReadCaptureEventEnabled(0xf1.toByte(), "Read Capture Event Enabled", PumpHistoryEntryGroup.Configuration), // ? + ChangeCaptureEventEnable2(0xf2.toByte(), "Change Capture Event Enable2", PumpHistoryEntryGroup.Configuration), // ? + ReadOtherDevicesStatus(0xf3.toByte(), "Read Other Devices Status", PumpHistoryEntryGroup.Configuration), // ? + TempBasalCombined(0xfe.toByte(), "TBR", PumpHistoryEntryGroup.Basal), // + UnknownBasePacket(0xff.toByte(), "Unknown Base Packet", PumpHistoryEntryGroup.Unknown); + + companion object { + private val opCodeMap: MutableMap = HashMap() + fun setSpecialRulesForEntryTypes() { + EndResultTotals.addSpecialRuleBody(SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 3)) + Bolus.addSpecialRuleHead(SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 8)) + BolusWizardSetup.addSpecialRuleBody(SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 137)) + BolusWizard.addSpecialRuleBody(SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 15)) + BolusReminder.addSpecialRuleBody(SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 2)) + ChangeSensorSetup2.addSpecialRuleBody(SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 34)) + } + + @JvmStatic fun getByCode(opCode: Byte): PumpHistoryEntryType? { + return if (opCodeMap.containsKey(opCode)) { + opCodeMap[opCode] + } else { + UnknownBasePacket + } + } + + // + // private PumpHistoryEntryType(int opCode, String name, int head, int date, + // int body) + // { + // this.opCode = (byte) opCode; + // this.description = name; + // this.headLength = head; + // this.dateLength = date; + // this.bodyLength = body; + // this.totalLength = (head + date + body); + // } + // + fun isAAPSRelevantEntry(entryType: PumpHistoryEntryType): Boolean { + return entryType == Bolus || // Treatments + entryType == TempBasalRate || // + entryType == TempBasalDuration || // + entryType == Prime || // Pump Status Change + entryType == SuspendPump || // + entryType == ResumePump || // + entryType == Rewind || // + entryType == NoDeliveryAlarm || // no delivery + entryType == BasalProfileStart || // + entryType == ChangeTime || // Time Change + entryType == NewTimeSet || // + entryType == ChangeBasalPattern || // Configuration + entryType == ClearSettings || // + entryType == SaveSettings || // + entryType == ChangeMaxBolus || // + entryType == ChangeMaxBasal || // + entryType == ChangeTempBasalType || // + entryType == ChangeBasalProfile_NewProfile || // Basal profile + entryType == DailyTotals515 || // Daily Totals + entryType == DailyTotals522 || // + entryType == DailyTotals523 || // + entryType == EndResultTotals + } + + val isRelevantEntry: Boolean + get() = true + + init { + for (type in values()) { + opCodeMap[type.code] = type + } + setSpecialRulesForEntryTypes() + } + } + + val code: Byte + private val description: String? + private val headLength: Int + val dateLength: Int + + // private MinimedDeviceType deviceType; + private val bodyLength: Int + private val totalLength: Int + + // special rules need to be put in list from highest to lowest (e.g.: + // 523andHigher=12, 515andHigher=10 and default (set in cnstr) would be 8) + private var specialRulesHead: MutableList? = null + private var specialRulesBody: MutableList? = null + private var hasSpecialRules = false + val group: PumpHistoryEntryGroup + + private constructor(opCode: Byte, group: PumpHistoryEntryGroup) : this(opCode, null, group, 2, 5, 0) {} + private constructor(opCode: Byte, group: PumpHistoryEntryGroup, head: Int, date: Int, body: Int) : this(opCode, null, group, head, date, body) {} + + fun getTotalLength(medtronicDeviceType: MedtronicDeviceType?): Int { + return if (hasSpecialRules()) { + getHeadLength(medtronicDeviceType) + getBodyLength(medtronicDeviceType) + dateLength + } else { + totalLength + } + } + + private fun hasSpecialRules(): Boolean { + return hasSpecialRules + } + + fun addSpecialRuleHead(rule: SpecialRule) { + if (isEmpty(specialRulesHead)) { + specialRulesHead = ArrayList() + } + specialRulesHead!!.add(rule) + hasSpecialRules = true + } + + fun addSpecialRuleBody(rule: SpecialRule) { + if (isEmpty(specialRulesBody)) { + specialRulesBody = ArrayList() + } + specialRulesBody!!.add(rule) + hasSpecialRules = true + } + + fun getDescription(): String { + return description ?: name + } + + fun getHeadLength(medtronicDeviceType: MedtronicDeviceType?): Int { + return if (hasSpecialRules) { + if (isNotEmpty(specialRulesHead)) { + determineSizeByRule(medtronicDeviceType, headLength, specialRulesHead) + } else { + headLength + } + } else { + headLength + } + } + + fun getBodyLength(medtronicDeviceType: MedtronicDeviceType?): Int { + return if (hasSpecialRules) { + if (isNotEmpty(specialRulesBody)) { + determineSizeByRule(medtronicDeviceType, bodyLength, specialRulesBody) + } else { + bodyLength + } + } else { + bodyLength + } + } + + private fun isNotEmpty(list: List<*>?): Boolean { + return list != null && !list.isEmpty() + } + + private fun isEmpty(list: List<*>?): Boolean { + return list == null || list.isEmpty() + } + + // byte[] dh = { 2, 3 }; + private fun determineSizeByRule(medtronicDeviceType: MedtronicDeviceType?, defaultValue: Int, rules: List?): Int { + var size = defaultValue + for (rule in rules!!) { + if (MedtronicDeviceType.isSameDevice(medtronicDeviceType, rule.deviceType)) { + size = rule.size + break + } + } + return size + } + + class SpecialRule internal constructor(var deviceType: MedtronicDeviceType, var size: Int) + + init { + this.code = opCode //as Byte.toInt() + description = name + headLength = head + dateLength = date + bodyLength = body + totalLength = head + date + body + this.group = group + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryResult.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryResult.java deleted file mode 100644 index 4bb67cfb3e..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryResult.java +++ /dev/null @@ -1,177 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import info.nightscout.androidaps.logging.AAPSLogger; -import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil; - -/** - * History page contains data, sorted from newest to oldest (0=newest..n=oldest) - *

- * Created by andy on 9/23/18. - */ -public class PumpHistoryResult { - - private final AAPSLogger aapsLogger; - - private boolean searchFinished = false; - private final PumpHistoryEntry searchEntry = null; - private Long searchDate = null; - private SearchType searchType = SearchType.None; - public List unprocessedEntries; - public List validEntries; - - - public PumpHistoryResult(AAPSLogger aapsLogger, PumpHistoryEntry searchEntry, Long targetDate) { - this.aapsLogger = aapsLogger; - if (searchEntry != null) { - /* - * this.searchEntry = searchEntry; - * this.searchType = SearchType.LastEntry; - * aapsLogger.debug(LTag.PUMPCOMM,"PumpHistoryResult. Search parameters: Last Entry: " + searchEntry.atechDateTime + " type=" - * + searchEntry.getEntryType().name()); - */ - this.searchDate = searchEntry.atechDateTime; - this.searchType = SearchType.Date; - aapsLogger.debug(LTag.PUMPCOMM, "PumpHistoryResult. Search parameters: Date(with searchEntry): " + targetDate); - } else if (targetDate != null) { - this.searchDate = targetDate; - this.searchType = SearchType.Date; - aapsLogger.debug(LTag.PUMPCOMM, "PumpHistoryResult. Search parameters: Date: " + targetDate); - } - - // this.unprocessedEntries = new ArrayList<>(); - this.validEntries = new ArrayList<>(); - } - - - public void addHistoryEntries(List entries, int page) { - this.unprocessedEntries = entries; - //aapsLogger.debug(LTag.PUMPCOMM,"PumpHistoryResult. Unprocessed entries: {}", MedtronicUtil.getGsonInstance().toJson(entries)); - processEntries(); - } - - // TODO Bug #145 need to check if we had timeChange that went -1, that situation needs to be evaluated separately - public void processEntries() { - int olderEntries = 0; - - Collections.reverse(this.unprocessedEntries); - - switch (searchType) { - case None: - //aapsLogger.debug(LTag.PUMPCOMM,"PE. None search"); - this.validEntries.addAll(this.unprocessedEntries); - break; - - case LastEntry: { - aapsLogger.debug(LTag.PUMPCOMM, "PE. Last entry search"); - - //Collections.sort(this.unprocessedEntries, new PumpHistoryEntry.Comparator()); - - aapsLogger.debug(LTag.PUMPCOMM, "PE. PumpHistoryResult. Search entry date: " + searchEntry.atechDateTime); - - Long date = searchEntry.atechDateTime; - - for (PumpHistoryEntry unprocessedEntry : unprocessedEntries) { - - if (unprocessedEntry.equals(searchEntry)) { - //aapsLogger.debug(LTag.PUMPCOMM,"PE. Item found {}.", unprocessedEntry); - searchFinished = true; - break; - } - - //aapsLogger.debug(LTag.PUMPCOMM,"PE. Entry {} added.", unprocessedEntry); - this.validEntries.add(unprocessedEntry); - } - } - break; - case Date: { - aapsLogger.debug(LTag.PUMPCOMM, "PE. Date search: Search date: " + this.searchDate); - - - for (PumpHistoryEntry unprocessedEntry : unprocessedEntries) { - - if (unprocessedEntry.atechDateTime == null || unprocessedEntry.atechDateTime == 0) { - aapsLogger.debug(LTag.PUMPCOMM, "PE. PumpHistoryResult. Search entry date: Entry with no date: " + unprocessedEntry); - continue; - } - - if (unprocessedEntry.isAfter(this.searchDate)) { - this.validEntries.add(unprocessedEntry); - } else { -// aapsLogger.debug(LTag.PUMPCOMM,"PE. PumpHistoryResult. Not after.. Unprocessed Entry [year={},entry={}]", -// DateTimeUtil.getYear(unprocessedEntry.atechDateTime), unprocessedEntry); - if (DateTimeUtil.getYear(unprocessedEntry.atechDateTime) > 2015) - olderEntries++; - } - } - - if (olderEntries > 0) { - //Collections.sort(this.validEntries, new PumpHistoryEntry.Comparator()); - - searchFinished = true; - } - } - break; - - } // switch - - //aapsLogger.debug(LTag.PUMPCOMM,"PE. Valid Entries: {}", validEntries); - } - - - public String toString() { - return "PumpHistoryResult [unprocessed=" + (unprocessedEntries != null ? "" + unprocessedEntries.size() : "0") + // - ", valid=" + (validEntries != null ? "" + validEntries.size() : "0") + // - ", searchEntry=" + searchEntry + // - ", searchDate=" + searchDate + // - ", searchType=" + searchType + // - ", searchFinished=" + searchFinished + // - "]"; - - } - - - /** - * Return latest entry (entry with highest date time) - * - * @return - */ - public PumpHistoryEntry getLatestEntry() { - if (this.validEntries == null || this.validEntries.size() == 0) - return null; - else { - return this.validEntries.get(0); - // PumpHistoryEntry pumpHistoryEntry = this.validEntries.get(0); - // - // if (pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.EndResultTotals) - // return pumpHistoryEntry; - // else - // return this.validEntries.get(1); - } - } - - - public boolean isSearchRequired() { - return searchType != SearchType.None; - } - - - public boolean isSearchFinished() { - return searchFinished; - } - - - public List getValidEntries() { - return validEntries; - } - - enum SearchType { - None, // - LastEntry, // - Date - } -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryResult.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryResult.kt new file mode 100644 index 0000000000..0ab0e7e05e --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryResult.kt @@ -0,0 +1,144 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump + +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil +import java.util.* + +/** + * History page contains data, sorted from newest to oldest (0=newest..n=oldest) + * + * + * Created by andy on 9/23/18. + */ +class PumpHistoryResult(private val aapsLogger: AAPSLogger, searchEntry: PumpHistoryEntry?, targetDate: Long?) { + + var isSearchFinished = false + private set + private val searchEntry: PumpHistoryEntry? = null + private var searchDate: Long? = null + private var searchType = SearchType.None + @JvmField var unprocessedEntries: List? = null + @JvmField var validEntries: MutableList? + fun addHistoryEntries(entries: List?, page: Int) { + unprocessedEntries = entries + //aapsLogger.debug(LTag.PUMPCOMM,"PumpHistoryResult. Unprocessed entries: {}", MedtronicUtil.getGsonInstance().toJson(entries)); + processEntries() + } + + // TODO Bug #145 need to check if we had timeChange that went -1, that situation needs to be evaluated separately + fun processEntries() { + var olderEntries = 0 + Collections.reverse(unprocessedEntries) + when (searchType) { + SearchType.None -> //aapsLogger.debug(LTag.PUMPCOMM,"PE. None search"); + validEntries!!.addAll(unprocessedEntries!!) + + SearchType.LastEntry -> { + aapsLogger.debug(LTag.PUMPCOMM, "PE. Last entry search") + + //Collections.sort(this.unprocessedEntries, new PumpHistoryEntry.Comparator()); + aapsLogger.debug(LTag.PUMPCOMM, "PE. PumpHistoryResult. Search entry date: " + searchEntry!!.atechDateTime) + val date = searchEntry.atechDateTime + for (unprocessedEntry in unprocessedEntries!!) { + if (unprocessedEntry!!.equals(searchEntry)) { + //aapsLogger.debug(LTag.PUMPCOMM,"PE. Item found {}.", unprocessedEntry); + isSearchFinished = true + break + } + + //aapsLogger.debug(LTag.PUMPCOMM,"PE. Entry {} added.", unprocessedEntry); + validEntries!!.add(unprocessedEntry) + } + } + + SearchType.Date -> { + aapsLogger.debug(LTag.PUMPCOMM, "PE. Date search: Search date: " + searchDate) + for (unprocessedEntry in unprocessedEntries!!) { + if (unprocessedEntry!!.atechDateTime == null || unprocessedEntry.atechDateTime == 0L) { + aapsLogger.debug(LTag.PUMPCOMM, "PE. PumpHistoryResult. Search entry date: Entry with no date: $unprocessedEntry") + continue + } + if (unprocessedEntry.isAfter(searchDate!!)) { + validEntries!!.add(unprocessedEntry) + } else { +// aapsLogger.debug(LTag.PUMPCOMM,"PE. PumpHistoryResult. Not after.. Unprocessed Entry [year={},entry={}]", +// DateTimeUtil.getYear(unprocessedEntry.atechDateTime), unprocessedEntry); + if (DateTimeUtil.getYear(unprocessedEntry.atechDateTime) > 2015) olderEntries++ + } + } + if (olderEntries > 0) { + //Collections.sort(this.validEntries, new PumpHistoryEntry.Comparator()); + isSearchFinished = true + } + } + } + + //aapsLogger.debug(LTag.PUMPCOMM,"PE. Valid Entries: {}", validEntries); + } + + override fun toString(): String { + return "PumpHistoryResult [unprocessed=" + (if (unprocessedEntries != null) "" + unprocessedEntries!!.size else "0") + // + ", valid=" + (if (validEntries != null) "" + validEntries!!.size else "0") + // + ", searchEntry=" + searchEntry + // + ", searchDate=" + searchDate + // + ", searchType=" + searchType + // + ", searchFinished=" + isSearchFinished + // + "]" + }// PumpHistoryEntry pumpHistoryEntry = this.validEntries.get(0); + // + // if (pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.EndResultTotals) + // return pumpHistoryEntry; + // else + // return this.validEntries.get(1); + + /** + * Return latest entry (entry with highest date time) + * + * @return + */ + val latestEntry: PumpHistoryEntry? + get() = if (validEntries == null || validEntries!!.size == 0) null else { + validEntries!![0] + // PumpHistoryEntry pumpHistoryEntry = this.validEntries.get(0); + // + // if (pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.EndResultTotals) + // return pumpHistoryEntry; + // else + // return this.validEntries.get(1); + } + + val isSearchRequired: Boolean + get() = searchType != SearchType.None + + fun getValidEntries(): List? { + return validEntries + } + + internal enum class SearchType { + None, // + LastEntry, // + Date + } + + init { + if (searchEntry != null) { + /* + * this.searchEntry = searchEntry; + * this.searchType = SearchType.LastEntry; + * aapsLogger.debug(LTag.PUMPCOMM,"PumpHistoryResult. Search parameters: Last Entry: " + searchEntry.atechDateTime + " type=" + * + searchEntry.getEntryType().name()); + */ + searchDate = searchEntry.atechDateTime + searchType = SearchType.Date + aapsLogger.debug(LTag.PUMPCOMM, "PumpHistoryResult. Search parameters: Date(with searchEntry): $targetDate") + } else if (targetDate != null) { + searchDate = targetDate + searchType = SearchType.Date + aapsLogger.debug(LTag.PUMPCOMM, "PumpHistoryResult. Search parameters: Date: $targetDate") + } + + // this.unprocessedEntries = new ArrayList<>(); + validEntries = ArrayList() + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/DailyTotalsDTO.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/DailyTotalsDTO.java index 697b74aa74..ae15a51c07 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/DailyTotalsDTO.java +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/DailyTotalsDTO.java @@ -74,15 +74,15 @@ public class DailyTotalsDTO { break; case DailyTotals515: - decodeDailyTotals515(entry.getBody()); + decodeDailyTotals515(entry.body); break; case DailyTotals522: - decodeDailyTotals522(entry.getBody()); + decodeDailyTotals522(entry.body); break; case DailyTotals523: - decodeDailyTotals523(entry.getBody()); + decodeDailyTotals523(entry.body); break; default: @@ -96,18 +96,18 @@ public class DailyTotalsDTO { private void setDisplayable() { if (this.insulinBasal == null) { - this.entry.setDisplayableValue("Total Insulin: " + StringUtil.getFormatedValueUS(this.insulinTotal, 2)); + this.entry.displayableValue = "Total Insulin: " + StringUtil.getFormatedValueUS(this.insulinTotal, 2); } else { - this.entry.setDisplayableValue("Basal Insulin: " + StringUtil.getFormatedValueUS(this.insulinBasal, 2) - + ", Total Insulin: " + StringUtil.getFormatedValueUS(this.insulinTotal, 2)); + this.entry.displayableValue = "Basal Insulin: " + StringUtil.getFormatedValueUS(this.insulinBasal, 2) + + ", Total Insulin: " + StringUtil.getFormatedValueUS(this.insulinTotal, 2); } } private void decodeEndResultsTotals(PumpHistoryEntry entry) { - double totals = ByteUtil.toInt((int) entry.getHead()[0], (int) entry.getHead()[1], (int) entry.getHead()[2], - (int) entry.getHead()[3], ByteUtil.BitConversion.BIG_ENDIAN) * 0.025d; + double totals = ByteUtil.toInt((int) entry.head[0], (int) entry.head[1], (int) entry.head[2], + (int) entry.head[3], ByteUtil.BitConversion.BIG_ENDIAN) * 0.025d; this.insulinTotal = totals; diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/MedtronicHistoryActivity.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/MedtronicHistoryActivity.java index fc986f4f83..a2ce6c00e7 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/MedtronicHistoryActivity.java +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/MedtronicHistoryActivity.java @@ -59,7 +59,7 @@ public class MedtronicHistoryActivity extends NoSplashAppCompatActivity { this.filteredHistoryList.addAll(list); } else { for (PumpHistoryEntry pumpHistoryEntry : list) { - if (pumpHistoryEntry.getEntryType().getGroup() == group) { + if (pumpHistoryEntry.getEntryType().group == group) { this.filteredHistoryList.add(pumpHistoryEntry); } } @@ -214,7 +214,7 @@ public class MedtronicHistoryActivity extends NoSplashAppCompatActivity { if (record != null) { holder.timeView.setText(record.getDateTimeString()); holder.typeView.setText(record.getEntryType().getDescription()); - holder.valueView.setText(record.getDisplayableValue()); + holder.valueView.setText(record.displayableValue); } } diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpHistoryEntryGroup.java b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpHistoryEntryGroup.java deleted file mode 100644 index 70a484d5d6..0000000000 --- a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpHistoryEntryGroup.java +++ /dev/null @@ -1,66 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.common.defs; - -import java.util.ArrayList; -import java.util.List; - - -import info.nightscout.androidaps.core.R; -import info.nightscout.androidaps.utils.resources.ResourceHelper; - - -/** - * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes - * management and modified/extended for AAPS. - *

- * Author: Andy {andy.rozman@gmail.com} - */ - -public enum PumpHistoryEntryGroup { - - All(R.string.history_group_all), - Bolus(R.string.history_group_bolus), - Basal(R.string.history_group_basal), - Prime(R.string.history_group_prime), - Configuration(R.string.history_group_configuration), - Alarm(R.string.history_group_alarm), - Glucose(R.string.history_group_glucose), - Notification(R.string.history_group_notification), - Statistic(R.string.history_group_statistic), - Unknown(R.string.history_group_unknown), - ; - - private final int resourceId; - private String translated; - - private static List translatedList; - - PumpHistoryEntryGroup(int resourceId) { - this.resourceId = resourceId; - } - - private static void doTranslation(ResourceHelper resourceHelper) { - translatedList = new ArrayList<>(); - - for (PumpHistoryEntryGroup pumpHistoryEntryGroup : values()) { - pumpHistoryEntryGroup.translated = resourceHelper.gs(pumpHistoryEntryGroup.resourceId); - translatedList.add(pumpHistoryEntryGroup); - } - } - - public static List getTranslatedList(ResourceHelper resourceHelper) { - if (translatedList == null) doTranslation(resourceHelper); - return translatedList; - } - - public int getResourceId() { - return resourceId; - } - - public String getTranslated() { - return translated; - } - - public String toString() { - return this.translated; - } -} diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpHistoryEntryGroup.kt b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpHistoryEntryGroup.kt new file mode 100644 index 0000000000..8b856d7036 --- /dev/null +++ b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpHistoryEntryGroup.kt @@ -0,0 +1,50 @@ +package info.nightscout.androidaps.plugins.pump.common.defs + +import info.nightscout.androidaps.core.R +import info.nightscout.androidaps.utils.resources.ResourceHelper +import java.util.* + +/** + * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes + * management and modified/extended for AAPS. + * + * + * Author: Andy {andy.rozman@gmail.com} + */ +enum class PumpHistoryEntryGroup(val resourceId: Int) { + + All(R.string.history_group_all), + Bolus(R.string.history_group_bolus), + Basal(R.string.history_group_basal), + Prime(R.string.history_group_prime), + Configuration(R.string.history_group_configuration), + Alarm(R.string.history_group_alarm), + Glucose(R.string.history_group_glucose), + Notification(R.string.history_group_notification), + Statistic(R.string.history_group_statistic), + Unknown(R.string.history_group_unknown); + + var translated: String? = null + private set + + override fun toString(): String { + return translated!! + } + + companion object { + private var translatedList: MutableList? = null + private fun doTranslation(resourceHelper: ResourceHelper) { + translatedList = ArrayList() + for (pumpHistoryEntryGroup in values()) { + pumpHistoryEntryGroup.translated = resourceHelper.gs(pumpHistoryEntryGroup.resourceId) + (translatedList as ArrayList).add(pumpHistoryEntryGroup) + } + } + + @JvmStatic fun getTranslatedList(resourceHelper: ResourceHelper): List? { + if (translatedList == null) doTranslation(resourceHelper) + return translatedList + } + } + +} \ No newline at end of file diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/ByteUtil.java b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/ByteUtil.java index 6273ff5203..da5e99596c 100644 --- a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/ByteUtil.java +++ b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/ByteUtil.java @@ -29,9 +29,13 @@ public class ByteUtil { return (b < 0) ? b + 256 : b; } + public static int asUINT8(Integer b) { + return (b < 0) ? b + 256 : b; + } + public static byte[] getBytesFromInt16(int value) { byte[] array = getBytesFromInt(value); - return new byte[] {array[2], array[3]}; + return new byte[]{array[2], array[3]}; } public static byte[] getBytesFromInt(int value) { @@ -283,10 +287,54 @@ public class ByteUtil { } + /** + * Converts 4 (or less) ints into int. (Shorts are objects, so you can send null if you have less parameters) + * + * @param b1 short 1 + * @param b2 short 2 + * @param b3 short 3 + * @param b4 short 4 + * @param flag Conversion Flag (Big Endian, Little endian) + * @return int value + */ + public static int toInt(Byte b1, Byte b2, Byte b3, Byte b4, BitConversion flag) { + switch (flag) { + case LITTLE_ENDIAN: { + if (b4 != null) { + return (b4 & 0xff) << 24 | (b3 & 0xff) << 16 | (b2 & 0xff) << 8 | b1 & 0xff; + } else if (b3 != null) { + return (b3 & 0xff) << 16 | (b2 & 0xff) << 8 | b1 & 0xff; + } else if (b2 != null) { + return (b2 & 0xff) << 8 | b1 & 0xff; + } else { + return b1 & 0xff; + } + } + + default: + case BIG_ENDIAN: { + if (b4 != null) { + return (b1 & 0xff) << 24 | (b2 & 0xff) << 16 | (b3 & 0xff) << 8 | b4 & 0xff; + } else if (b3 != null) { + return (b1 & 0xff) << 16 | (b2 & 0xff) << 8 | b3 & 0xff; + } else if (b2 != null) { + return (b1 & 0xff) << 8 | b2 & 0xff; + } else { + return b1 & 0xff; + } + } + } + } + + public static int toInt(int b1, int b2) { return toInt(b1, b2, null, null, BitConversion.BIG_ENDIAN); } + public static int toInt(Byte b1, Byte b2) { + return toInt(b1, b2, null, null, BitConversion.BIG_ENDIAN); + } + public static int toInt(int b1, int b2, int b3) { return toInt(b1, b2, b3, null, BitConversion.BIG_ENDIAN); @@ -329,6 +377,25 @@ public class ByteUtil { } + public static String getCorrectHexValue(byte inp) { + String hx = Integer.toHexString((char) inp); + + if (hx.length() == 0) + return "00"; + else if (hx.length() == 1) + return "0" + hx; + else if (hx.length() == 2) + return hx; + else if (hx.length() == 4) + return hx.substring(2); + else { + System.out.println("Hex Error: " + inp); + } + + return null; + } + + public static String getHex(byte[] abyte0) { return abyte0 != null ? getHex(abyte0, abyte0.length) : null; } From 05a07c190466445b840ef3d0bbb708c01cf834a5 Mon Sep 17 00:00:00 2001 From: Andy Rozman Date: Fri, 16 Apr 2021 21:40:25 +0100 Subject: [PATCH 004/145] - kotlinlize: info/nightscout/androidaps/plugins/pump/medtronic/comm/message --- .../pump/medtronic/MedtronicPumpPlugin.java | 2 +- .../comm/MedtronicCommunicationManager.java | 17 +- .../comm/history/MedtronicHistoryDecoder.kt | 11 +- .../comm/history/MedtronicHistoryEntry.kt | 47 ++-- .../history/MedtronicHistoryEntryInterface.kt | 2 +- .../comm/history/cgms/CGMSHistoryEntry.kt | 2 +- .../pump/MedtronicPumpHistoryDecoder.kt | 104 ++++----- .../comm/history/pump/PumpHistoryEntry.kt | 15 +- .../comm/history/pump/PumpHistoryEntryType.kt | 69 ++---- .../comm/message/CarelinkLongMessageBody.java | 49 ---- .../comm/message/CarelinkLongMessageBody.kt | 46 ++++ .../message/CarelinkShortMessageBody.java | 53 ----- .../comm/message/CarelinkShortMessageBody.kt | 38 ++++ .../GetHistoryPageCarelinkMessageBody.java | 59 ----- .../GetHistoryPageCarelinkMessageBody.kt | 45 ++++ .../medtronic/comm/message/MessageBody.java | 34 --- .../medtronic/comm/message/MessageBody.kt | 27 +++ .../medtronic/comm/message/PacketType.java | 47 ---- .../pump/medtronic/comm/message/PacketType.kt | 37 +++ .../comm/message/PumpAckMessageBody.java | 16 -- .../comm/message/PumpAckMessageBody.kt | 15 ++ .../medtronic/comm/message/PumpMessage.java | 214 ------------------ .../medtronic/comm/message/PumpMessage.kt | 183 +++++++++++++++ .../comm/message/UnknownMessageBody.java | 46 ---- .../comm/message/UnknownMessageBody.kt | 15 ++ .../medtronic/data/MedtronicHistoryData.java | 62 ++--- .../medtronic/data/dto/DailyTotalsDTO.java | 18 +- .../data/dto/TempBasalProcessDTO.java | 2 +- .../pump/medtronic/di/MedtronicModule.kt | 7 + .../dialog/MedtronicHistoryActivity.java | 4 +- .../history/pump/PumpHistoryEntryUTest.java | 2 +- 31 files changed, 575 insertions(+), 713 deletions(-) delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/CarelinkLongMessageBody.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/CarelinkLongMessageBody.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/CarelinkShortMessageBody.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/CarelinkShortMessageBody.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/GetHistoryPageCarelinkMessageBody.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/GetHistoryPageCarelinkMessageBody.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/MessageBody.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/MessageBody.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/PacketType.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/PacketType.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/PumpAckMessageBody.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/PumpAckMessageBody.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/PumpMessage.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/PumpMessage.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/UnknownMessageBody.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/UnknownMessageBody.kt diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java index 48ee038ad5..d1fede9118 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java @@ -1223,7 +1223,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter return; this.lastPumpHistoryEntry = latestEntry; - sp.putLong(MedtronicConst.Statistics.LastPumpHistoryEntry, latestEntry.atechDateTime); + sp.putLong(MedtronicConst.Statistics.LastPumpHistoryEntry, latestEntry.getAtechDateTime()); if (debugHistory) aapsLogger.debug(LTag.PUMP, "HST: History: valid=" + historyResult.validEntries.size() + ", unprocessed=" + historyResult.unprocessedEntries.size()); diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicCommunicationManager.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicCommunicationManager.java index 32963e8d9a..4b8f885701 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicCommunicationManager.java +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicCommunicationManager.java @@ -237,10 +237,10 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager aapsLogger.debug(LTag.PUMPCOMM, "Run command with Args: "); PumpMessage rval; - PumpMessage shortMessage = makePumpMessage(msg.commandType, new CarelinkShortMessageBody(new byte[]{0})); + PumpMessage shortMessage = makePumpMessage(msg.getCommandType(), new CarelinkShortMessageBody(new byte[]{0})); // look for ack from short message PumpMessage shortResponse = sendAndListen(shortMessage); - if (shortResponse.commandType == MedtronicCommandType.CommandACK) { + if (shortResponse.getCommandType() == MedtronicCommandType.CommandACK) { if (debugSetCommands) aapsLogger.debug(LTag.PUMPCOMM, "Run command with Args: Got ACK response"); @@ -266,7 +266,7 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager // look for ack from short message PumpMessage shortResponse = sendAndListen(shortMessage); - if (shortResponse.commandType != MedtronicCommandType.CommandACK) { + if (shortResponse.getCommandType() != MedtronicCommandType.CommandACK) { aapsLogger.error(LTag.PUMPCOMM, "runCommandWithFrames: Pump did not ack Attention packet"); return new PumpMessage(aapsLogger, "No ACK after start message."); @@ -288,7 +288,7 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager // aapsLogger.debug(LTag.PUMPCOMM,"PumpResponse: " + rval); - if (rval.commandType != MedtronicCommandType.CommandACK) { + if (rval.getCommandType() != MedtronicCommandType.CommandACK) { aapsLogger.error(LTag.PUMPCOMM, "runCommandWithFrames: Pump did not ACK frame #" + frameNr); aapsLogger.error(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Run command with Frames FAILED (command=%s, response=%s)", commandType.name(), @@ -356,8 +356,7 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager // aapsLogger.info(LTag.PUMPCOMM,"getPumpHistoryPage("+pageNumber+"): " + ByteUtil.shortHexString(firstResponse.getContents())); PumpMessage ackMsg = makePumpMessage(MedtronicCommandType.CommandACK, new PumpAckMessageBody()); - GetHistoryPageCarelinkMessageBody currentResponse = new GetHistoryPageCarelinkMessageBody(firstResponse - .getMessageBody().getTxData()); + GetHistoryPageCarelinkMessageBody currentResponse = new GetHistoryPageCarelinkMessageBody(firstResponse.getMessageBody().getTxData()); int expectedFrameNum = 1; boolean done = false; // while (expectedFrameNum == currentResponse.getFrameNumber()) { @@ -861,7 +860,7 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager if (debugSetCommands) aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "%s: %s", commandType.getCommandDescription(), pumpMessage.getResponseContent())); - if (pumpMessage.commandType == MedtronicCommandType.CommandACK) { + if (pumpMessage.getCommandType() == MedtronicCommandType.CommandACK) { return true; } else { aapsLogger.warn(LTag.PUMPCOMM, "We received non-ACK response from pump: " + pumpMessage.getResponseContent()); @@ -900,7 +899,7 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager responseMessage = runCommandWithFrames(MedtronicCommandType.SetBasalProfileSTD, basalProfileFrames); - if (responseMessage.commandType == MedtronicCommandType.CommandACK) + if (responseMessage.getCommandType() == MedtronicCommandType.CommandACK) return true; } catch (RileyLinkCommunicationException e) { @@ -908,7 +907,7 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager } if (responseMessage != null) - aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Set Basal Profile: Invalid response: commandType=%s,rawData=%s", responseMessage.commandType, ByteUtil.shortHexString(responseMessage.getRawContent()))); + aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Set Basal Profile: Invalid response: commandType=%s,rawData=%s", responseMessage.getCommandType(), ByteUtil.shortHexString(responseMessage.getRawContent()))); else aapsLogger.warn(LTag.PUMPCOMM, "Set Basal Profile: Null response."); } 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 a6a8744299..181177d54f 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 @@ -19,16 +19,13 @@ import kotlin.jvm.Throws */ abstract class MedtronicHistoryDecoder : MedtronicHistoryDecoderInterface { - @JvmField @Inject - var aapsLogger: AAPSLogger? = null - - @JvmField @Inject - var medtronicUtil: MedtronicUtil? = null - protected var bitUtils: ByteUtil? = null + @Inject lateinit var aapsLogger: AAPSLogger + @Inject lateinit var medtronicUtil: MedtronicUtil + @Inject lateinit var bitUtils: ByteUtil // STATISTICS (remove at later time or not) protected var statisticsEnabled = true - @JvmField protected var unknownOpCodes: MutableMap? = null + protected var unknownOpCodes: MutableMap? = null protected var mapStatistics: MutableMap>? = null // public abstract Class getHistoryEntryClass(); diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntry.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntry.kt index 72e3174178..6f2228b29c 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntry.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntry.kt @@ -16,30 +16,41 @@ import java.util.* */ abstract class MedtronicHistoryEntry : MedtronicHistoryEntryInterface { - @JvmField var rawData: List? = null - @JvmField protected var sizes = IntArray(3) + var rawData: List? = null + get() = field + + protected var sizes = IntArray(3) + get() = field + var head: ByteArray? = null + get() = field + var datetime: ByteArray? = null var body: ByteArray? = null - - // protected LocalDateTime dateTime; - @JvmField var id: Long = 0 - - @JvmField @Expose - var DT: String? = null - - @JvmField @Expose - var atechDateTime: Long? = null + var id: Long = 0 + set(value) { + field = value + } @Expose - protected var decodedData: MutableMap? = null - var phoneDateTime // time on phone - : Long = 0 + var DT: String? = null + get() = field + + @Expose + var atechDateTime: Long? = null + get() = field + set(value) { + field = value + } + + @Expose + var decodedData: MutableMap? = null + get() = field /** * Pump id that will be used with AAPS object (time * 1000 + historyType (max is FF = 255) */ - protected open var pumpId: Long? = null + open var pumpId: Long? = null /** * if history object is already linked to AAPS object (either Treatment, TempBasal or TDD (tdd's @@ -52,7 +63,7 @@ abstract class MedtronicHistoryEntry : MedtronicHistoryEntryInterface { * Linked object, see linked */ var linkedObject: Any? = null - get() = field //= linkedObject + get() = field set(value) { linked = true field = value @@ -63,7 +74,7 @@ abstract class MedtronicHistoryEntry : MedtronicHistoryEntryInterface { // this.linkedObject = linkedObject // } - override fun setData(listRawData: List?, doNotProcess: Boolean) { + override fun setData(listRawData: List, doNotProcess: Boolean) { rawData = listRawData // System.out.println("Head: " + sizes[0] + ", dates: " + sizes[1] + @@ -78,7 +89,7 @@ abstract class MedtronicHistoryEntry : MedtronicHistoryEntryInterface { var i = headLength var j = 0 while (j < dateTimeLength) { - datetime!![j] = listRawData!![i]!! + datetime!![j] = listRawData[i] i++ j++ } diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntryInterface.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntryInterface.kt index 32f6d4458a..4467f68d7e 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntryInterface.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntryInterface.kt @@ -6,6 +6,6 @@ package info.nightscout.androidaps.plugins.pump.medtronic.comm.history interface MedtronicHistoryEntryInterface { val entryTypeName: String? - fun setData(listRawData: List?, doNotProcess: Boolean) + fun setData(listRawData: List, doNotProcess: Boolean) val dateLength: Int } \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/CGMSHistoryEntry.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/CGMSHistoryEntry.kt index 2ede3d65c1..670a17ee91 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/CGMSHistoryEntry.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/CGMSHistoryEntry.kt @@ -30,7 +30,7 @@ class CGMSHistoryEntry : MedtronicHistoryEntry() { override val entryTypeName: String get() = entryType!!.name - override fun setData(listRawData: List?, doNotProcess: Boolean) { + override fun setData(listRawData: List, doNotProcess: Boolean) { if (entryType!!.schemaSet) { super.setData(listRawData, doNotProcess) } else { 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 e0613567d8..c8e38e7fcb 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 @@ -19,6 +19,7 @@ import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil import java.util.* import javax.inject.Inject import javax.inject.Singleton +import kotlin.experimental.and /** * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes @@ -29,12 +30,13 @@ import javax.inject.Singleton */ @Singleton class MedtronicPumpHistoryDecoder @Inject constructor( - aapsLogger: AAPSLogger?, - medtronicUtil: MedtronicUtil? + aapsLogger: AAPSLogger, + medtronicUtil: MedtronicUtil ) : MedtronicHistoryDecoder() { private var tbrPreviousRecord: PumpHistoryEntry? = null private var changeTimeRecord: PumpHistoryEntry? = null + override fun createRecords(dataClear: List): List { prepareStatistics() var counter = 0 @@ -42,8 +44,8 @@ class MedtronicPumpHistoryDecoder @Inject constructor( var incompletePacket: Boolean val outList: MutableList = ArrayList() var skipped: String? = null - if (dataClear!!.size == 0) { - aapsLogger!!.error(LTag.PUMPBTCOMM, "Empty page.") + if (dataClear.size == 0) { + aapsLogger.error(LTag.PUMPBTCOMM, "Empty page.") return outList } do { @@ -57,13 +59,13 @@ class MedtronicPumpHistoryDecoder @Inject constructor( continue } else { if (skipped != null) { - aapsLogger!!.warn(LTag.PUMPBTCOMM, " ... Skipped $skipped") + aapsLogger.warn(LTag.PUMPBTCOMM, " ... Skipped $skipped") skipped = null skippedRecords = true } } if (skippedRecords) { - aapsLogger!!.error(LTag.PUMPBTCOMM, "We had some skipped bytes, which might indicate error in pump history. Please report this problem.") + aapsLogger.error(LTag.PUMPBTCOMM, "We had some skipped bytes, which might indicate error in pump history. Please report this problem.") } val entryType = getByCode(opCode.toByte()) val pe = PumpHistoryEntry() @@ -89,12 +91,12 @@ class MedtronicPumpHistoryDecoder @Inject constructor( } special = true } else { - for (j in 0 until entryType.getTotalLength(medtronicUtil!!.medtronicPumpModel) - 1) { + for (j in 0 until entryType.getTotalLength(medtronicUtil.medtronicPumpModel) - 1) { try { listRawData.add(dataClear[counter]) counter++ } catch (ex: Exception) { - aapsLogger!!.error(LTag.PUMPBTCOMM, "OpCode: " + ByteUtil.shortHexString(opCode.toByte()) + ", Invalid package: " + aapsLogger.error(LTag.PUMPBTCOMM, "OpCode: " + ByteUtil.shortHexString(opCode.toByte()) + ", Invalid package: " + ByteUtil.getHex(listRawData)) // throw ex; incompletePacket = true @@ -115,7 +117,7 @@ class MedtronicPumpHistoryDecoder @Inject constructor( if (decoded === RecordDecodeStatus.OK || decoded === RecordDecodeStatus.Ignored) { //Log.i(TAG, "#" + record + " " + decoded.getDescription() + " " + pe); } else { - aapsLogger!!.warn(LTag.PUMPBTCOMM, "#" + record + " " + decoded!!.description + " " + pe) + aapsLogger.warn(LTag.PUMPBTCOMM, "#" + record + " " + decoded!!.description + " " + pe) } addToStatistics(pe, decoded, null) record++ @@ -132,7 +134,8 @@ class MedtronicPumpHistoryDecoder @Inject constructor( return try { decodeRecord(record, false) } catch (ex: Exception) { - aapsLogger!!.error(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, " Error decoding: type=%s, ex=%s", record.entryType!!.name, ex.message, ex)) + aapsLogger.error(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, " Error decoding: type=%s, ex=%s", record.entryType!!.name, ex.message, ex)) + //ex.printStackTrace() RecordDecodeStatus.Error } } @@ -145,17 +148,7 @@ class MedtronicPumpHistoryDecoder @Inject constructor( PumpHistoryEntryType.ChangeBasalPattern, PumpHistoryEntryType.CalBGForPH, PumpHistoryEntryType.ChangeRemoteId, PumpHistoryEntryType.ClearAlarm, PumpHistoryEntryType.ChangeAlarmNotifyMode, PumpHistoryEntryType.EnableDisableRemote, PumpHistoryEntryType.BGReceived, PumpHistoryEntryType.SensorAlert, PumpHistoryEntryType.ChangeTimeFormat, PumpHistoryEntryType.ChangeReservoirWarningTime, PumpHistoryEntryType.ChangeBolusReminderEnable, PumpHistoryEntryType.SetBolusReminderTime, PumpHistoryEntryType.ChangeChildBlockEnable, PumpHistoryEntryType.BolusWizardEnabled, PumpHistoryEntryType.ChangeBGReminderOffset, PumpHistoryEntryType.ChangeAlarmClockTime, PumpHistoryEntryType.ChangeMeterId, PumpHistoryEntryType.ChangeParadigmID, PumpHistoryEntryType.JournalEntryMealMarker, PumpHistoryEntryType.JournalEntryExerciseMarker, PumpHistoryEntryType.DeleteBolusReminderTime, PumpHistoryEntryType.SetAutoOff, PumpHistoryEntryType.SelfTest, PumpHistoryEntryType.JournalEntryInsulinMarker, PumpHistoryEntryType.JournalEntryOtherMarker, PumpHistoryEntryType.BolusWizardSetup512, PumpHistoryEntryType.ChangeSensorSetup2, PumpHistoryEntryType.ChangeSensorAlarmSilenceConfig, PumpHistoryEntryType.ChangeSensorRateOfChangeAlertSetup, PumpHistoryEntryType.ChangeBolusScrollStepSize, PumpHistoryEntryType.BolusWizardSetup, PumpHistoryEntryType.ChangeVariableBolus, PumpHistoryEntryType.ChangeAudioBolus, PumpHistoryEntryType.ChangeBGReminderEnable, PumpHistoryEntryType.ChangeAlarmClockEnable, PumpHistoryEntryType.BolusReminder, PumpHistoryEntryType.DeleteAlarmClockTime, PumpHistoryEntryType.ChangeCarbUnits, PumpHistoryEntryType.ChangeWatchdogEnable, PumpHistoryEntryType.ChangeOtherDeviceID, PumpHistoryEntryType.ReadOtherDevicesIDs, PumpHistoryEntryType.BGReceived512, PumpHistoryEntryType.SensorStatus, PumpHistoryEntryType.ReadCaptureEventEnabled, PumpHistoryEntryType.ChangeCaptureEventEnable, PumpHistoryEntryType.ReadOtherDevicesStatus -> RecordDecodeStatus.OK PumpHistoryEntryType.Sensor_0x54, PumpHistoryEntryType.Sensor_0x55, PumpHistoryEntryType.Sensor_0x51, PumpHistoryEntryType.Sensor_0x52, PumpHistoryEntryType.EventUnknown_MM512_0x2e -> { - // case EventUnknown_MM512_0x37: -// case EventUnknown_MM512_0x38: -// case EventUnknown_MM512_0x4e: -// case EventUnknown_MM522_0x70: -// case EventUnknown_MM512_0x88: -// case EventUnknown_MM512_0x94: -// case EventUnknown_MM522_0xE8: -// case EventUnknown_0x4d: -// case EventUnknown_MM522_0x25: -// case EventUnknown_MM522_0x05: - aapsLogger!!.debug(LTag.PUMPBTCOMM, " -- ignored Unknown Pump Entry: $entry") + aapsLogger.debug(LTag.PUMPBTCOMM, " -- ignored Unknown Pump Entry: $entry") RecordDecodeStatus.Ignored } @@ -207,12 +200,10 @@ class MedtronicPumpHistoryDecoder @Inject constructor( PumpHistoryEntryType.None, PumpHistoryEntryType.UnknownBasePacket -> RecordDecodeStatus.Error else -> { - aapsLogger!!.debug(LTag.PUMPBTCOMM, "Not supported: " + entry.entryType) + aapsLogger.debug(LTag.PUMPBTCOMM, "Not supported: " + entry.entryType) RecordDecodeStatus.NotSupported } } - - // return RecordDecodeStatus.Error; } private fun decodeDailyTotals(entry: PumpHistoryEntry): RecordDecodeStatus { @@ -223,12 +214,8 @@ class MedtronicPumpHistoryDecoder @Inject constructor( } private fun decodeBasalProfile(entry: PumpHistoryEntry): RecordDecodeStatus { - - // LOG.debug("decodeBasalProfile: {}", entry); val basalProfile = BasalProfile(aapsLogger) basalProfile.setRawDataFromHistory(entry.body) - - // LOG.debug("decodeBasalProfile BasalProfile: {}", basalProfile); entry.addDecodedData("Object", basalProfile) return RecordDecodeStatus.OK } @@ -240,24 +227,21 @@ class MedtronicPumpHistoryDecoder @Inject constructor( } private fun decodeBatteryActivity(entry: PumpHistoryEntry) { - // this.writeData(PumpBaseType.Event, entry.getHead()[0] == 0 ? PumpEventType.BatteryRemoved : - // PumpEventType.BatteryReplaced, entry.getATechDate()); entry.displayableValue = if (entry.head!![0] == 0.toByte()) "Battery Removed" else "Battery Replaced" } private fun decodeBasalProfileStart(entry: PumpHistoryEntry): RecordDecodeStatus { val body = entry.body - // int bodyOffset = headerSize + timestampSize; val offset = body!![0] * 1000 * 30 * 60 var rate: Float? = null val index = entry.head!![0].toInt() - if (MedtronicDeviceType.isSameDevice(medtronicUtil!!.medtronicPumpModel, MedtronicDeviceType.Medtronic_523andHigher)) { + if (MedtronicDeviceType.isSameDevice(medtronicUtil.medtronicPumpModel, MedtronicDeviceType.Medtronic_523andHigher)) { rate = body[1] * 0.025f } //LOG.info("Basal Profile Start: offset={}, rate={}, index={}, body_raw={}", offset, rate, index, body); return if (rate == null) { - aapsLogger!!.warn(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, "Basal Profile Start (ERROR): offset=%d, rate=%.3f, index=%d, body_raw=%s", offset, rate, index, ByteUtil.getHex(body))) + aapsLogger.warn(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, "Basal Profile Start (ERROR): offset=%d, rate=%.3f, index=%d, body_raw=%s", offset, rate, index, ByteUtil.getHex(body))) RecordDecodeStatus.Error } else { entry.addDecodedData("Value", getFormattedFloat(rate, 3)) @@ -267,26 +251,26 @@ class MedtronicPumpHistoryDecoder @Inject constructor( } private fun decodeBolusWizard(entry: PumpHistoryEntry): RecordDecodeStatus { - val body = entry.body as IntArray + val body = entry.body!! val dto = BolusWizardDTO() var bolusStrokes = 10.0f if (MedtronicDeviceType.isSameDevice(medtronicUtil!!.medtronicPumpModel, MedtronicDeviceType.Medtronic_523andHigher)) { // https://github.com/ps2/minimed_rf/blob/master/lib/minimed_rf/log_entries/bolus_wizard.rb#L102 bolusStrokes = 40.0f - dto.carbs = (body[1] and 0x0c shl 6) + body[0] - dto.bloodGlucose = (body[1] and 0x03 shl 8) + entry.head!![0] + dto.carbs = ((body[1] and 0x0c.toByte()).toInt() shl 6) + body[0] + dto.bloodGlucose = ((body[1] and 0x03).toInt() shl 8) + entry.head!![0] dto.carbRatio = body[1] / 10.0f // carb_ratio (?) = (((self.body[2] & 0x07) << 8) + self.body[3]) / // 10.0s dto.insulinSensitivity = body[4].toFloat() dto.bgTargetLow = body[5] as Int dto.bgTargetHigh = body[14] as Int - dto.correctionEstimate = ((body[9] and 0x38 shl 5) + body[6]) / bolusStrokes - dto.foodEstimate = ((body[7] shl 8) + body[8]) / bolusStrokes - dto.unabsorbedInsulin = ((body[10] shl 8) + body[11]) / bolusStrokes - dto.bolusTotal = ((body[12] shl 8) + body[13]) / bolusStrokes + dto.correctionEstimate = (((body[9] and 0x38).toInt() shl 5) + body[6]) / bolusStrokes + dto.foodEstimate = ((body[7].toInt() shl 8) + body[8]) / bolusStrokes + dto.unabsorbedInsulin = ((body[10].toInt() shl 8) + body[11]) / bolusStrokes + dto.bolusTotal = ((body[12].toInt() shl 8) + body[13]) / bolusStrokes } else { - dto.bloodGlucose = body.get(1) and 0x0F shl 8 or entry.head!!.get(0).toInt() + dto.bloodGlucose = (body.get(1) and 0x0F).toInt() shl 8 or entry.head!!.get(0).toInt() dto.carbs = body.get(0) as Int dto.carbRatio = body.get(2).toFloat() dto.insulinSensitivity = body.get(3).toFloat() @@ -308,14 +292,14 @@ class MedtronicPumpHistoryDecoder @Inject constructor( } private fun decodeBolusWizard512(entry: PumpHistoryEntry): RecordDecodeStatus { - val body = entry.body as IntArray + val body = entry.body!! val dto = BolusWizardDTO() val bolusStrokes = 10.0f - dto.bloodGlucose = body.get(1) and 0x03 shl 8 or entry.head!!.get(0).toInt() - dto.carbs = body!!.get(1).toInt() and 0xC shl 6 or body.get(0).toInt() // (int)body[0]; - dto.carbRatio = body!!.get(2).toFloat() - dto.insulinSensitivity = body!!.get(3).toFloat() - dto.bgTargetLow = body.get(4) + dto.bloodGlucose = (body.get(1) and 0x03).toInt() shl 8 or entry.head!!.get(0).toInt() + dto.carbs = body.get(1).toInt() and 0xC shl 6 or body.get(0).toInt() // (int)body[0]; + dto.carbRatio = body.get(2).toFloat() + dto.insulinSensitivity = body.get(3).toFloat() + dto.bgTargetLow = body.get(4).toInt() dto.foodEstimate = body.get(6) / 10.0f dto.correctionEstimate = (body.get(7) + (body.get(5) and 0x0F)) / bolusStrokes dto.unabsorbedInsulin = body.get(9) / bolusStrokes @@ -374,8 +358,8 @@ class MedtronicPumpHistoryDecoder @Inject constructor( private fun decodeBolus(entry: PumpHistoryEntry) { val bolus = BolusDTO() - val data = entry.head as IntArray - if (MedtronicDeviceType.isSameDevice(medtronicUtil!!.getMedtronicPumpModel(), MedtronicDeviceType.Medtronic_523andHigher)) { + val data = entry.head!! + if (MedtronicDeviceType.isSameDevice(medtronicUtil.getMedtronicPumpModel(), MedtronicDeviceType.Medtronic_523andHigher)) { bolus.requestedAmount = ByteUtil.toInt(data.get(0), data.get(1)) / 40.0 bolus.deliveredAmount = ByteUtil.toInt(data.get(2), data.get(3)) / 40.0 bolus.insulinOnBoard = ByteUtil.toInt(data.get(4), data.get(5)) / 40.0 @@ -433,18 +417,18 @@ class MedtronicPumpHistoryDecoder @Inject constructor( } private fun decodeDateTime(entry: PumpHistoryEntry) { - val dt = entry.datetime as IntArray - if (dt == null) { - aapsLogger!!.warn(LTag.PUMPBTCOMM, "DateTime not set.") + if (entry.datetime==null) { + aapsLogger.warn(LTag.PUMPBTCOMM, "DateTime not set.") } + val dt = entry.datetime!! if (entry.dateTimeLength == 5) { - val seconds: Int = (dt!!.get(0) and 0x3F).toInt() - val minutes: Int = (dt!!.get(1) and 0x3F).toInt() + val seconds: Int = (dt.get(0) and 0x3F.toByte()).toInt() + val minutes: Int = (dt.get(1) and 0x3F.toByte()).toInt() val hour: Int = (dt.get(2) and 0x1F).toInt() - val month: Int = (dt.get(0) shr 4 and 0x0c) + (dt.get(1) shr 6 and 0x03) + val month: Int = (dt.get(0).toInt() shr 4 and 0x0c) + (dt.get(1).toInt() shr 6 and 0x03) // ((dt[0] & 0xC0) >> 6) | ((dt[1] & 0xC0) >> 4); - val dayOfMonth: Int = dt.get(3) and 0x1F - val year = fix2DigitYear(dt.get(4) and 0x3F) // Assuming this is correct, need to verify. Otherwise this will be + val dayOfMonth: Int = (dt.get(3) and 0x1F).toInt() + val year = fix2DigitYear((dt.get(4) and 0x3F.toByte()).toInt()) // Assuming this is correct, need to verify. Otherwise this will be // a problem in 2016. entry.setAtechDateTime(DateTimeUtil.toATechDate(year, month, dayOfMonth, hour, minutes, seconds)) } else if (entry.dateTimeLength == 2) { @@ -453,7 +437,7 @@ class MedtronicPumpHistoryDecoder @Inject constructor( val mlow = ByteUtil.asUINT8(dt.get(1)) and 0x80 shr 7 val month = mhigh + mlow // int dayOfMonth = low + 1; - val dayOfMonth: Int = dt.get(0) and 0x1F + val dayOfMonth: Int = (dt.get(0) and 0x1F).toInt() val year = 2000 + (ByteUtil.asUINT8(dt.get(1)) and 0x7F) var hour = 0 var minutes = 0 @@ -461,7 +445,7 @@ class MedtronicPumpHistoryDecoder @Inject constructor( //LOG.debug("DT: {} {} {}", year, month, dayOfMonth); if (dayOfMonth == 32) { - aapsLogger!!.warn(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, "Entry: Day 32 %s = [%s] %s", entry.entryType!!.name, + aapsLogger.warn(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, "Entry: Day 32 %s = [%s] %s", entry.entryType!!.name, ByteUtil.getHex(entry.rawData), entry)) } if (isEndResults(entry.entryType)) { @@ -471,7 +455,7 @@ class MedtronicPumpHistoryDecoder @Inject constructor( } entry.setAtechDateTime(DateTimeUtil.toATechDate(year, month, dayOfMonth, hour, minutes, seconds)) } else { - aapsLogger!!.warn(LTag.PUMPBTCOMM, "Unknown datetime format: " + entry.dateTimeLength) + aapsLogger.warn(LTag.PUMPBTCOMM, "Unknown datetime format: " + entry.dateTimeLength) } } diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.kt index e1c0daf2ea..289cb113ed 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.kt @@ -17,7 +17,8 @@ import java.util.* */ class PumpHistoryEntry : MedtronicHistoryEntry() { - @Expose var entryType: PumpHistoryEntryType? = null + @Expose + var entryType: PumpHistoryEntryType? = null private set override var opCode: Byte? = null @@ -27,16 +28,12 @@ class PumpHistoryEntry : MedtronicHistoryEntry() { field = value } - // // override fun getOpCode(): Int { - // // return - // // } - // - // fun setOpCode(opCode: Int?) { - // this.opCode = opCode - // } - var offset = 0 var displayableValue = "" + get() = field + set(value) { + field = value + } fun setEntryType(medtronicDeviceType: MedtronicDeviceType?, entryType: PumpHistoryEntryType) { this.entryType = entryType diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntryType.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntryType.kt index 3f2a4a0c40..9ddb18b996 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntryType.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntryType.kt @@ -12,7 +12,7 @@ import java.util.* * Author: Andy {andy.rozman@gmail.com} */ enum class PumpHistoryEntryType // implements CodeEnum -@JvmOverloads constructor(opCode: Byte, name: String?, group: PumpHistoryEntryGroup, head: Int = 2, date: Int = 5, body: Int = 0) { + constructor(opCode: Byte, name: String?, group: PumpHistoryEntryGroup, head: Int = 2, date: Int = 5, body: Int = 0) { // all commented out are probably not the real items None(0, "None", PumpHistoryEntryGroup.Unknown, 1, 0, 0), Bolus(0x01, "Bolus", PumpHistoryEntryGroup.Bolus, 4, 5, 0), // 523+[H=8] 9/13 @@ -40,15 +40,12 @@ enum class PumpHistoryEntryType // implements CodeEnum ClearSettings(0x22, "Clear Settings", PumpHistoryEntryGroup.Configuration), // ChangeChildBlockEnable(0x23, "Change Child Block Enable", PumpHistoryEntryGroup.Configuration), // ChangeMaxBolus(0x24, "Change Max Bolus", PumpHistoryEntryGroup.Configuration), // - // /**/EventUnknown_MM522_0x25(0x25, "Unknown Event 0x25", PumpHistoryEntryGroup.Unknown), // 8? EnableDisableRemote(0x26, "Enable/Disable Remote", PumpHistoryEntryGroup.Configuration, 2, 5, 14), // 2, 5, 14 V6:2,5,14 ChangeRemoteId(0x27, "Change Remote ID", PumpHistoryEntryGroup.Configuration), // ?? ChangeMaxBasal(0x2c, "Change Max Basal", PumpHistoryEntryGroup.Configuration), // BolusWizardEnabled(0x2d, "Bolus Wizard Enabled", PumpHistoryEntryGroup.Configuration), // V3 ? - - /* TODO */ - EventUnknown_MM512_0x2e(0x2e, "Unknown Event 0x2e", PumpHistoryEntryGroup.Unknown, 2, 5, 100), // + /* TODO */ EventUnknown_MM512_0x2e(0x2e, "Unknown Event 0x2e", PumpHistoryEntryGroup.Unknown, 2, 5, 100), // BolusWizard512(0x2f, "Bolus Wizard (512)", PumpHistoryEntryGroup.Bolus, 2, 5, 12), // UnabsorbedInsulin512(0x30, "Unabsorbed Insulin (512)", PumpHistoryEntryGroup.Statistic, 5, 0, 0), // FIXME ChangeBGReminderOffset(0x31, "Change BG Reminder Offset", PumpHistoryEntryGroup.Configuration), // @@ -57,13 +54,10 @@ enum class PumpHistoryEntryType // implements CodeEnum LowReservoir(0x34, "Low Reservoir", PumpHistoryEntryGroup.Notification), // ChangeAlarmClock(0x35, "Change Alarm Clock", PumpHistoryEntryGroup.Configuration), // ChangeMeterId(0x36, "Change Meter ID", PumpHistoryEntryGroup.Configuration), // - // /**/EventUnknown_MM512_0x37(0x37, "Unknown Event 0x37", PumpHistoryEntryGroup.Unknown), // V:MM512 // /**/EventUnknown_MM512_0x38(0x38, "Unknown Event 0x38", PumpHistoryEntryGroup.Unknown), // BGReceived512(0x39, "BG Received (512)", PumpHistoryEntryGroup.Glucose, 2, 5, 3), // - - /* TODO */ - ConfirmInsulinChange(0x3a, "Confirm Insulin Change", PumpHistoryEntryGroup.Unknown), // + /* TODO */ ConfirmInsulinChange(0x3a, "Confirm Insulin Change", PumpHistoryEntryGroup.Unknown), // SensorStatus(0x3b, "Sensor Status", PumpHistoryEntryGroup.Glucose), // ChangeParadigmID(0x3c, "Change Paradigm ID", PumpHistoryEntryGroup.Configuration, 2, 5, 14), // V3 ? V6: 2,5,14 ?? is it this length or just 7 @@ -73,9 +67,8 @@ enum class PumpHistoryEntryType // implements CodeEnum JournalEntryMealMarker(0x40, "Meal Marker", PumpHistoryEntryGroup.Bolus, 2, 5, 2), // is size just 7??? V6 JournalEntryExerciseMarker(0x41, "Exercise Marker", PumpHistoryEntryGroup.Bolus, 2, 5, 1), // ?? JournalEntryInsulinMarker(0x42, "Insulin Marker", PumpHistoryEntryGroup.Bolus, 2, 5, 0), // V6 = body(0)/was=1 - JournalEntryOtherMarker(0x43, "Other Marker", PumpHistoryEntryGroup.Bolus, 2, 5, 1), // V6 = body(1)/was=0 + JournalEntryOtherMarker(0x43, "Other Marker", PumpHistoryEntryGroup.Bolus, 2, 5, 1), // V6 = body(1) was=0 EnableSensorAutoCal(0x44, "Enable Sensor AutoCal", PumpHistoryEntryGroup.Glucose), // - // /**/EventUnknown_MM522_0x45(0x45, "Unknown Event 0x45", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // // /**/EventUnknown_MM522_0x46(0x46, "Unknown Event 0x46", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // // /**/EventUnknown_MM522_0x47(0x47, "Unknown Event 0x47", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // @@ -89,18 +82,11 @@ enum class PumpHistoryEntryType // implements CodeEnum BolusWizardSetup512(0x4f, "Bolus Wizard Setup (512)", PumpHistoryEntryGroup.Configuration, 2, 5, 32), // ChangeSensorSetup2(0x50, "Sensor Setup2", PumpHistoryEntryGroup.Configuration, 2, 5, 30), // Ian50 - /* TODO */ - Sensor_0x51(0x51, "Unknown Event 0x51", PumpHistoryEntryGroup.Unknown), // - - /* TODO */ - Sensor_0x52(0x52, "Unknown Event 0x52", PumpHistoryEntryGroup.Unknown), // + /* TODO */ Sensor_0x51(0x51, "Unknown Event 0x51", PumpHistoryEntryGroup.Unknown), // + /* TODO */ Sensor_0x52(0x52, "Unknown Event 0x52", PumpHistoryEntryGroup.Unknown), // ChangeSensorAlarmSilenceConfig(0x53, "Sensor Alarm Silence Config", PumpHistoryEntryGroup.Configuration, 2, 5, 1), // 8 - - /* TODO */ - Sensor_0x54(0x54, "Unknown Event 0x54", PumpHistoryEntryGroup.Unknown), // Ian54 - - /* TODO */ - Sensor_0x55(0x55, "Unknown Event 0x55", PumpHistoryEntryGroup.Unknown), // + /* TODO */ Sensor_0x54(0x54, "Unknown Event 0x54", PumpHistoryEntryGroup.Unknown), // Ian54 + /* TODO */ Sensor_0x55(0x55, "Unknown Event 0x55", PumpHistoryEntryGroup.Unknown), // ChangeSensorRateOfChangeAlertSetup(0x56, "Sensor Rate Of Change Alert Setup", PumpHistoryEntryGroup.Configuration, 2, 5, 5), // 12 ChangeBolusScrollStepSize(0x57, "Change Bolus Scroll Step Size", PumpHistoryEntryGroup.Configuration), // BolusWizardSetup(0x5a, "Bolus Wizard Setup (522)", PumpHistoryEntryGroup.Configuration, 2, 5, 117), // V2: 522+[B=143]; V6: 124, v6: 137, v7: 117/137 [523] @@ -124,7 +110,6 @@ enum class PumpHistoryEntryType // implements CodeEnum DailyTotals522(0x6d, "Daily Totals (522)", PumpHistoryEntryGroup.Statistic, 1, 2, 41), // DailyTotals523(0x6e, "Daily Totals (523)", PumpHistoryEntryGroup.Statistic, 1, 2, 49), // 1102014-03-17T00:00:00 ChangeCarbUnits(0x6f.toByte(), "Change Carb Units", PumpHistoryEntryGroup.Configuration), // - // /**/EventUnknown_MM522_0x70((byte) 0x70, "Unknown Event 0x70", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // BasalProfileStart(0x7b, "Basal Profile Start", PumpHistoryEntryGroup.Basal, 2, 5, 3), // // 722 ChangeWatchdogEnable(0x7c, "Change Watchdog Enable", PumpHistoryEntryGroup.Configuration), // @@ -158,7 +143,7 @@ enum class PumpHistoryEntryType // implements CodeEnum ChangeSensorSetup2.addSpecialRuleBody(SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 34)) } - @JvmStatic fun getByCode(opCode: Byte): PumpHistoryEntryType? { + fun getByCode(opCode: Byte): PumpHistoryEntryType? { return if (opCodeMap.containsKey(opCode)) { opCodeMap[opCode] } else { @@ -166,18 +151,6 @@ enum class PumpHistoryEntryType // implements CodeEnum } } - // - // private PumpHistoryEntryType(int opCode, String name, int head, int date, - // int body) - // { - // this.opCode = (byte) opCode; - // this.description = name; - // this.headLength = head; - // this.dateLength = date; - // this.bodyLength = body; - // this.totalLength = (head + date + body); - // } - // fun isAAPSRelevantEntry(entryType: PumpHistoryEntryType): Boolean { return entryType == Bolus || // Treatments entryType == TempBasalRate || // @@ -215,8 +188,11 @@ enum class PumpHistoryEntryType // implements CodeEnum } val code: Byte - private val description: String? - private val headLength: Int + + val description: String? + get() = field + + val headLength: Int val dateLength: Int // private MinimedDeviceType deviceType; @@ -228,22 +204,25 @@ enum class PumpHistoryEntryType // implements CodeEnum private var specialRulesHead: MutableList? = null private var specialRulesBody: MutableList? = null private var hasSpecialRules = false + get() = field + val group: PumpHistoryEntryGroup + get() = field private constructor(opCode: Byte, group: PumpHistoryEntryGroup) : this(opCode, null, group, 2, 5, 0) {} private constructor(opCode: Byte, group: PumpHistoryEntryGroup, head: Int, date: Int, body: Int) : this(opCode, null, group, head, date, body) {} fun getTotalLength(medtronicDeviceType: MedtronicDeviceType?): Int { - return if (hasSpecialRules()) { + return if (hasSpecialRules) { getHeadLength(medtronicDeviceType) + getBodyLength(medtronicDeviceType) + dateLength } else { totalLength } } - private fun hasSpecialRules(): Boolean { - return hasSpecialRules - } + // private fun hasSpecialRules(): Boolean { + // return hasSpecialRules + // } fun addSpecialRuleHead(rule: SpecialRule) { if (isEmpty(specialRulesHead)) { @@ -261,9 +240,9 @@ enum class PumpHistoryEntryType // implements CodeEnum hasSpecialRules = true } - fun getDescription(): String { - return description ?: name - } + // fun getDescription(): String { + // return description ?: name + // } fun getHeadLength(medtronicDeviceType: MedtronicDeviceType?): Int { return if (hasSpecialRules) { diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/CarelinkLongMessageBody.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/CarelinkLongMessageBody.java deleted file mode 100644 index 7f2c51e032..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/CarelinkLongMessageBody.java +++ /dev/null @@ -1,49 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.message; - -/** - * Created by geoff on 6/2/16. - */ -public class CarelinkLongMessageBody extends MessageBody { - - private static final int LONG_MESSAGE_BODY_LENGTH = 65; - protected byte[] data; - - - CarelinkLongMessageBody() { - init(new byte[0]); - } - - - public CarelinkLongMessageBody(byte[] payload) { - init(payload); - } - - @Override - public void init(byte[] rxData) { - - if (rxData != null && rxData.length == LONG_MESSAGE_BODY_LENGTH) { - data = rxData; - } else { - data = new byte[LONG_MESSAGE_BODY_LENGTH]; - if (rxData != null) { - int size = rxData.length < LONG_MESSAGE_BODY_LENGTH ? rxData.length : LONG_MESSAGE_BODY_LENGTH; - for (int i = 0; i < size; i++) { - data[i] = rxData[i]; - } - } - } - } - - - @Override - public int getLength() { - return LONG_MESSAGE_BODY_LENGTH; - } - - - @Override - public byte[] getTxData() { - return data; - } - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/CarelinkLongMessageBody.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/CarelinkLongMessageBody.kt new file mode 100644 index 0000000000..e46e8feb6a --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/CarelinkLongMessageBody.kt @@ -0,0 +1,46 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.message + +/** + * Created by geoff on 6/2/16. + */ +open class CarelinkLongMessageBody : MessageBody { + + //protected var data: ByteArray? = null + + internal constructor() { + init(ByteArray(0)) + } + + constructor(payload: ByteArray) { + init(payload) + } + + override fun init(rxData: ByteArray?) { + if (rxData != null && rxData.size == LONG_MESSAGE_BODY_LENGTH) { + data = rxData + } else { + data = ByteArray(LONG_MESSAGE_BODY_LENGTH) + if (rxData != null) { + val size = if (rxData.size < LONG_MESSAGE_BODY_LENGTH) rxData.size else LONG_MESSAGE_BODY_LENGTH + for (i in 0 until size) { + data!![i] = rxData[i] + } + } + } + } + + override val length: Int + get() = LONG_MESSAGE_BODY_LENGTH + + // { + // return LONG_MESSAGE_BODY_LENGTH + // } + + // override fun getTxData(): ByteArray { + // return data + // } + + companion object { + private const val LONG_MESSAGE_BODY_LENGTH = 65 + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/CarelinkShortMessageBody.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/CarelinkShortMessageBody.java deleted file mode 100644 index e2ebbff085..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/CarelinkShortMessageBody.java +++ /dev/null @@ -1,53 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.message; - -/** - * Created by geoff on 5/29/16. - */ -// Andy: See comments in message body -public class CarelinkShortMessageBody extends MessageBody { - - byte[] body; - - - public CarelinkShortMessageBody() { - init(new byte[] { 0 }); - } - - - public CarelinkShortMessageBody(byte[] data) { - init(data); - } - - - @Override - public int getLength() { - return body.length; - } - - - @Override - public void init(byte[] rxData) { - body = rxData; - } - - - public byte[] getRxData() { - return body; - } - - - public void setRxData(byte[] rxData) { - init(rxData); - } - - - @Override - public byte[] getTxData() { - return body; - } - - - public void setTxData(byte[] txData) { - init(txData); - } -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/CarelinkShortMessageBody.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/CarelinkShortMessageBody.kt new file mode 100644 index 0000000000..7d99b45ae2 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/CarelinkShortMessageBody.kt @@ -0,0 +1,38 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.message + +/** + * Created by geoff on 5/29/16. + */ +// Andy: See comments in message body +open class CarelinkShortMessageBody : MessageBody { + + //var body: ByteArray? + + constructor() { + init(byteArrayOf(0)) + } + + constructor(data: ByteArray?) { + init(data) + } + + override val length: Int + get() = data!!.size + + override fun init(rxData: ByteArray?) { + data = rxData + } + + var rxData: ByteArray? + get() = data + set(rxData) { + init(rxData) + } + + // override var txData: ByteArray? + // get() = body + // set(txData) { + // init(txData) + // } + +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/GetHistoryPageCarelinkMessageBody.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/GetHistoryPageCarelinkMessageBody.java deleted file mode 100644 index 25e8aa087c..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/GetHistoryPageCarelinkMessageBody.java +++ /dev/null @@ -1,59 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.message; - -import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil; - -/** - * Created by geoff on 6/2/16. - */ -public class GetHistoryPageCarelinkMessageBody extends CarelinkLongMessageBody { - - // public boolean wasLastFrame = false; - // public int frameNumber = 0; - // public byte[] frame = new byte[] {}; - - public GetHistoryPageCarelinkMessageBody(byte[] frameData) { - init(frameData); - } - - - public GetHistoryPageCarelinkMessageBody(int pageNum) { - init(pageNum); - } - - - @Override - public int getLength() { - return data.length; - } - - - @Override - public void init(byte[] rxData) { - super.init(rxData); - } - - - public void init(int pageNum) { - byte numArgs = 1; - super.init(new byte[] { numArgs, (byte)pageNum }); - } - - - public int getFrameNumber() { - if (data.length > 0) { - return data[0] & 0x7f; - } - return 255; - } - - - public boolean wasLastFrame() { - return (data[0] & 0x80) != 0; - } - - - public byte[] getFrameData() { - return ByteUtil.substring(data, 1, data.length - 1); - } - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/GetHistoryPageCarelinkMessageBody.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/GetHistoryPageCarelinkMessageBody.kt new file mode 100644 index 0000000000..b2836d4f77 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/GetHistoryPageCarelinkMessageBody.kt @@ -0,0 +1,45 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.message + +import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil +import kotlin.experimental.and + +/** + * Created by geoff on 6/2/16. + */ +class GetHistoryPageCarelinkMessageBody : CarelinkLongMessageBody { + + // public boolean wasLastFrame = false; + // public int frameNumber = 0; + // public byte[] frame = new byte[] {}; + constructor(frameData: ByteArray?) { + init(frameData) + } + + constructor(pageNum: Int) { + init(pageNum) + } + + override val length: Int + get() = data!!.size + + override fun init(rxData: ByteArray?) { + super.init(rxData) + } + + fun init(pageNum: Int) { + val numArgs: Byte = 1 + super.init(byteArrayOf(numArgs, pageNum.toByte())) + } + + val frameNumber: Int + get() = if (data!!.size > 0) { + (data!![0] and 0x7f.toByte()).toInt() + } else 255 + + fun wasLastFrame(): Boolean { + return (data!![0] and 0x80.toByte()).toInt() != 0 + } + + val frameData: ByteArray + get() = ByteUtil.substring(data!!, 1, data!!.size - 1) +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/MessageBody.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/MessageBody.java deleted file mode 100644 index fa4a3817be..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/MessageBody.java +++ /dev/null @@ -1,34 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.message; - -import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil; - -/** - * Created by geoff on 5/29/16. - */ -public class MessageBody { - - public int getLength() { - return 0; - } - - - public void init(byte[] rxData) { - } - - - public byte[] getTxData() { - return new byte[]{}; - } - - - public String toString() { - StringBuilder sb = new StringBuilder(getClass().getSimpleName()); - - sb.append(" [txData="); - sb.append(ByteUtil.shortHexString(getTxData())); - sb.append("]"); - - return sb.toString(); - } - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/MessageBody.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/MessageBody.kt new file mode 100644 index 0000000000..0dd03de7dd --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/MessageBody.kt @@ -0,0 +1,27 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.message + +import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil + +/** + * Created by geoff on 5/29/16. + */ +open class MessageBody { + + protected var data: ByteArray? = null + + open val length: Int + get() = 0 + + open fun init(rxData: ByteArray?) {} + + open val txData: ByteArray? + get() = if (data==null) byteArrayOf() else data + + override fun toString(): String { + val sb = StringBuilder(javaClass.simpleName) + sb.append(" [txData=") + sb.append(ByteUtil.shortHexString(txData)) + sb.append("]") + return sb.toString() + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/PacketType.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/PacketType.java deleted file mode 100644 index f153dd8cac..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/PacketType.java +++ /dev/null @@ -1,47 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.message; - -import java.util.HashMap; -import java.util.Map; - -/** - * Created by geoff on 5/29/16. - * refactored into enum - */ -public enum PacketType { - Invalid(0x00), // - MySentry(0xa2), // - Meter(0xa5), // - Carelink(0xa7), // - Sensor(0xa8) // - ; - - public static Map mapByValue; - - static { - mapByValue = new HashMap<>(); - - for (PacketType packetType : values()) { - mapByValue.put(packetType.value, packetType); - } - } - - private final byte value; - - - PacketType(int value) { - this.value = (byte)value; - } - - - public static PacketType getByValue(short value) { - if (mapByValue.containsKey(value)) - return mapByValue.get(value); - else - return PacketType.Invalid; - } - - - public byte getValue() { - return value; - } -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/PacketType.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/PacketType.kt new file mode 100644 index 0000000000..68769944b1 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/PacketType.kt @@ -0,0 +1,37 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.message + +import java.util.* + +/** + * Created by geoff on 5/29/16. + * refactored into enum + */ +enum class PacketType(value: Int) { + + Invalid(0x00), // + MySentry(0xa2), // + Meter(0xa5), // + Carelink(0xa7), // + Sensor(0xa8 // + ); + + companion object { + var mapByValue: MutableMap = HashMap() + + fun getByValue(value: Short): PacketType? { + return if (mapByValue.containsKey(value.toByte())) mapByValue.get(value.toByte()) else Invalid + } + + init { + for (packetType in values()) { + mapByValue[packetType.value] = packetType + } + } + } + + val value: Byte + + init { + this.value = value.toByte() + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/PumpAckMessageBody.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/PumpAckMessageBody.java deleted file mode 100644 index 4cfda08975..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/PumpAckMessageBody.java +++ /dev/null @@ -1,16 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.message; - -/** - * Created by geoff on 5/29/16. - */ -public class PumpAckMessageBody extends CarelinkShortMessageBody { - - public PumpAckMessageBody() { - init(new byte[] { 0 }); - } - - - public PumpAckMessageBody(byte[] bodyData) { - init(bodyData); - } -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/PumpAckMessageBody.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/PumpAckMessageBody.kt new file mode 100644 index 0000000000..39d85deb44 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/PumpAckMessageBody.kt @@ -0,0 +1,15 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.message + +/** + * Created by geoff on 5/29/16. + */ +class PumpAckMessageBody : CarelinkShortMessageBody { + + constructor() { + init(byteArrayOf(0)) + } + + constructor(bodyData: ByteArray?) { + init(bodyData) + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/PumpMessage.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/PumpMessage.java deleted file mode 100644 index 71d50c4691..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/PumpMessage.java +++ /dev/null @@ -1,214 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.message; - -import info.nightscout.androidaps.logging.AAPSLogger; -import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.data.RLMessage; -import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicCommandType; - -/** - * Created by geoff on 5/29/16. - */ -public class PumpMessage implements RLMessage { - - private final AAPSLogger aapsLogger; - - private PacketType packetType = PacketType.Carelink; - public byte[] address = new byte[]{0, 0, 0}; - public MedtronicCommandType commandType; - public Byte invalidCommandType; - public MessageBody messageBody = new MessageBody(); - public String error = null; - - public static final int FRAME_DATA_LENGTH = 64; - - - public PumpMessage(AAPSLogger aapsLogger, String error) { - this.error = error; - this.aapsLogger = aapsLogger; - } - - - public PumpMessage(AAPSLogger aapsLogger, byte[] rxData) { - this.aapsLogger = aapsLogger; - init(rxData); - } - - - public PumpMessage(AAPSLogger aapsLogger) { - this.aapsLogger = aapsLogger; - } - - - public boolean isErrorResponse() { - return (this.error != null); - } - - - public void init(PacketType packetType, byte[] address, MedtronicCommandType commandType, MessageBody messageBody) { - this.packetType = packetType; - this.address = address; - this.commandType = commandType; - this.messageBody = messageBody; - } - - - public void init(byte[] rxData) { - if (rxData == null) { - return; - } - if (rxData.length > 0) { - this.packetType = PacketType.getByValue(rxData[0]); - } - if (rxData.length > 3) { - this.address = ByteUtil.substring(rxData, 1, 3); - } - if (rxData.length > 4) { - this.commandType = MedtronicCommandType.getByCode(rxData[4]); - if (this.commandType == MedtronicCommandType.InvalidCommand) { - aapsLogger.error(LTag.PUMPCOMM, "PumpMessage - Unknown commandType " + rxData[4]); - } - } - if (rxData.length > 5) { - this.messageBody = MedtronicCommandType.constructMessageBody(commandType, - ByteUtil.substring(rxData, 5, rxData.length - 5)); - } - } - - - @Override - public byte[] getTxData() { - byte[] rval = ByteUtil.concat(new byte[]{packetType.getValue()}, address); - rval = ByteUtil.concat(rval, commandType.getCommandCode()); - rval = ByteUtil.concat(rval, messageBody.getTxData()); - return rval; - } - - - public byte[] getContents() { - return ByteUtil.concat(new byte[]{commandType.getCommandCode()}, messageBody.getTxData()); - } - - - // rawContent = just response without code (contents-2, messageBody.txData-1); - public byte[] getRawContent() { - - if ((messageBody == null) || (messageBody.getTxData() == null) || (messageBody.getTxData().length == 0)) - return null; - - byte[] data = messageBody.getTxData(); - - int length = ByteUtil.asUINT8(data[0]); // length is not always correct so, we check whole array if we have - // data, after length - int originalLength = length; - - // check if displayed length is invalid - if (length > data.length - 1) { - return data; - } - - // check Old Way - boolean oldWay = false; - for (int i = (length + 1); i < data.length; i++) { - if (data[i] != 0x00) { - oldWay = true; - } - } - - if (oldWay) { - length = data.length - 1; - } - - byte[] arrayOut = new byte[length]; - - System.arraycopy(messageBody.getTxData(), 1, arrayOut, 0, length); - -// if (isLogEnabled()) -// LOG.debug("PumpMessage - Length: " + length + ", Original Length: " + originalLength + ", CommandType: " -// + commandType); - - return arrayOut; - } - - - public byte[] getRawContentOfFrame() { - byte[] raw = messageBody.getTxData(); - if (raw==null || raw.length==0) { - return new byte[0]; - } else { - return ByteUtil.substring(raw, 1, Math.min(FRAME_DATA_LENGTH, raw.length - 1)); - } - } - - - public boolean isValid() { - if (packetType == null) - return false; - if (address == null) - return false; - if (commandType == null) - return false; - return messageBody != null; - } - - - public MessageBody getMessageBody() { - return messageBody; - } - - - public String getResponseContent() { - StringBuilder sb = new StringBuilder("PumpMessage [response="); - boolean showData = true; - - if (commandType != null) { - if (commandType == MedtronicCommandType.CommandACK) { - sb.append("Acknowledged"); - showData = false; - } else if (commandType == MedtronicCommandType.CommandNAK) { - sb.append("NOT Acknowledged"); - showData = false; - } else { - sb.append(commandType.name()); - } - } else { - sb.append("Unknown_Type"); - sb.append(" (" + invalidCommandType + ")"); - } - - if (showData) { - sb.append(", rawResponse="); - sb.append(ByteUtil.shortHexString(getRawContent())); - } - - sb.append("]"); - - return sb.toString(); - } - - - public String toString() { - StringBuilder sb = new StringBuilder("PumpMessage ["); - - sb.append("packetType="); - sb.append(packetType == null ? "null" : packetType.name()); - - sb.append(", address=("); - sb.append(ByteUtil.shortHexString(this.address)); - - sb.append("), commandType="); - sb.append(commandType == null ? "null" : commandType.name()); - - if (invalidCommandType != null) { - sb.append(", invalidCommandType="); - sb.append(invalidCommandType); - } - - sb.append(", messageBody=("); - sb.append(this.messageBody == null ? "null" : this.messageBody); - - sb.append(")]"); - - return sb.toString(); - } -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/PumpMessage.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/PumpMessage.kt new file mode 100644 index 0000000000..3683f4e7c5 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/PumpMessage.kt @@ -0,0 +1,183 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.message + +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.data.RLMessage +import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil +import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicCommandType + +/** + * Created by geoff on 5/29/16. + */ +class PumpMessage : RLMessage { + + private val aapsLogger: AAPSLogger + private var packetType: PacketType? = PacketType.Carelink + var address: ByteArray? = byteArrayOf(0, 0, 0) + var commandType: MedtronicCommandType? = null + var invalidCommandType: Byte? = null + var messageBody: MessageBody? = MessageBody() + var error: String? = null + + constructor(aapsLogger: AAPSLogger, error: String?) { + this.error = error + this.aapsLogger = aapsLogger + } + + constructor(aapsLogger: AAPSLogger, rxData: ByteArray?) { + this.aapsLogger = aapsLogger + init(rxData) + } + + constructor(aapsLogger: AAPSLogger) { + this.aapsLogger = aapsLogger + } + + val isErrorResponse: Boolean + get() = error != null + + fun init(packetType: PacketType?, address: ByteArray?, commandType: MedtronicCommandType?, messageBody: MessageBody?) { + this.packetType = packetType + this.address = address + this.commandType = commandType + this.messageBody = messageBody + } + + fun init(rxData: ByteArray?) { + if (rxData == null) { + return + } + if (rxData.size > 0) { + packetType = PacketType.getByValue(rxData[0].toShort()) + } + if (rxData.size > 3) { + address = ByteUtil.substring(rxData, 1, 3) + } + if (rxData.size > 4) { + commandType = MedtronicCommandType.getByCode(rxData[4]) + if (commandType == MedtronicCommandType.InvalidCommand) { + aapsLogger.error(LTag.PUMPCOMM, "PumpMessage - Unknown commandType " + rxData[4]) + } + } + if (rxData.size > 5) { + messageBody = MedtronicCommandType.constructMessageBody(commandType, + ByteUtil.substring(rxData, 5, rxData.size - 5)) + } + } + + override fun getTxData(): ByteArray { + var rval = ByteUtil.concat(byteArrayOf(packetType!!.value), address) + rval = ByteUtil.concat(rval, commandType!!.getCommandCode()) + rval = ByteUtil.concat(rval, messageBody!!.txData) + return rval + } + + val contents: ByteArray + get() = ByteUtil.concat(byteArrayOf(commandType!!.getCommandCode()), messageBody!!.txData)// length is not always correct so, we check whole array if we have + // data, after length + + // check if displayed length is invalid + + // check Old Way + +// if (isLogEnabled()) +// LOG.debug("PumpMessage - Length: " + length + ", Original Length: " + originalLength + ", CommandType: " +// + commandType); + + // rawContent = just response without code (contents-2, messageBody.txData-1); + val rawContent: ByteArray? + get() { + if (messageBody == null || messageBody!!.txData == null || messageBody!!.txData!!.size == 0) return null + val data = messageBody!!.txData + var length = ByteUtil.asUINT8(data!![0]) // length is not always correct so, we check whole array if we have + // data, after length + val originalLength = length + + // check if displayed length is invalid + if (length > data.size - 1) { + return data + } + + // check Old Way + var oldWay = false + for (i in length + 1 until data.size) { + if (data[i] != 0x00.toByte()) { + oldWay = true + } + } + if (oldWay) { + length = data.size - 1 + } + val arrayOut = ByteArray(length) + System.arraycopy(messageBody!!.txData, 1, arrayOut, 0, length) + +// if (isLogEnabled()) +// LOG.debug("PumpMessage - Length: " + length + ", Original Length: " + originalLength + ", CommandType: " +// + commandType); + return arrayOut + } + + val rawContentOfFrame: ByteArray + get() { + val raw = messageBody!!.txData + return if (raw == null || raw.size == 0) { + ByteArray(0) + } else { + ByteUtil.substring(raw, 1, Math.min(FRAME_DATA_LENGTH, raw.size - 1)) + } + } + + override fun isValid(): Boolean { + if (packetType == null) return false + if (address == null) return false + return if (commandType == null) false else messageBody != null + } + + val responseContent: String + get() { + val sb = StringBuilder("PumpMessage [response=") + var showData = true + if (commandType != null) { + if (commandType == MedtronicCommandType.CommandACK) { + sb.append("Acknowledged") + showData = false + } else if (commandType == MedtronicCommandType.CommandNAK) { + sb.append("NOT Acknowledged") + showData = false + } else { + sb.append(commandType!!.name) + } + } else { + sb.append("Unknown_Type") + sb.append(" ($invalidCommandType)") + } + if (showData) { + sb.append(", rawResponse=") + sb.append(ByteUtil.shortHexString(rawContent)) + } + sb.append("]") + return sb.toString() + } + + override fun toString(): String { + val sb = StringBuilder("PumpMessage [") + sb.append("packetType=") + sb.append(if (packetType == null) "null" else packetType!!.name) + sb.append(", address=(") + sb.append(ByteUtil.shortHexString(address)) + sb.append("), commandType=") + sb.append(if (commandType == null) "null" else commandType!!.name) + if (invalidCommandType != null) { + sb.append(", invalidCommandType=") + sb.append(invalidCommandType) + } + sb.append(", messageBody=(") + sb.append(if (messageBody == null) "null" else messageBody) + sb.append(")]") + return sb.toString() + } + + companion object { + const val FRAME_DATA_LENGTH = 64 + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/UnknownMessageBody.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/UnknownMessageBody.java deleted file mode 100644 index 675a794bd8..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/UnknownMessageBody.java +++ /dev/null @@ -1,46 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.message; - -/** - * Created by geoff on 5/29/16. - */ -public class UnknownMessageBody extends MessageBody { - - public byte[] rxData; - - - public UnknownMessageBody(byte[] data) { - this.rxData = data; - } - - - @Override - public int getLength() { - return 0; - } - - - @Override - public void init(byte[] rxData) { - } - - - public byte[] getRxData() { - return rxData; - } - - - public void setRxData(byte[] rxData) { - this.rxData = rxData; - } - - - @Override - public byte[] getTxData() { - return rxData; - } - - - public void setTxData(byte[] txData) { - this.rxData = txData; - } -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/UnknownMessageBody.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/UnknownMessageBody.kt new file mode 100644 index 0000000000..ba3c998d9e --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/UnknownMessageBody.kt @@ -0,0 +1,15 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.message + +/** + * Created by geoff on 5/29/16. + */ +class UnknownMessageBody(override var txData: ByteArray) : MessageBody() { + + override val length: Int + get() = 0 + + override fun init(rxData: ByteArray?) { + data = rxData + } + +} \ No newline at end of file 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 index 0d0f5ce006..580f0f8252 100644 --- 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 @@ -204,7 +204,7 @@ public class MedtronicHistoryData { } else { if (type == PumpHistoryEntryType.EndResultTotals) { - if (!DateTimeUtil.isSameDay(atechDate, pumpHistoryEntry.atechDateTime)) { + if (!DateTimeUtil.isSameDay(atechDate, pumpHistoryEntry.getAtechDateTime())) { newHistory2.add(pumpHistoryEntry); } } else { @@ -239,7 +239,7 @@ public class MedtronicHistoryData { for (PumpHistoryEntry bolusEstimate : bolusEstimates) { for (PumpHistoryEntry bolus : boluses) { - if (bolusEstimate.atechDateTime.equals(bolus.atechDateTime)) { + if (bolusEstimate.getAtechDateTime().equals(bolus.getAtechDateTime())) { bolus.addDecodedData("Estimate", bolusEstimate.getDecodedData().get("Object")); } } @@ -256,7 +256,7 @@ public class MedtronicHistoryData { // find last entry for (PumpHistoryEntry pumpHistoryEntry : newHistory) { - if (pumpHistoryEntry.atechDateTime != null && pumpHistoryEntry.isAfter(pheLast.atechDateTime)) { + if (pumpHistoryEntry.getAtechDateTime() != null && pumpHistoryEntry.isAfter(pheLast.getAtechDateTime())) { pheLast = pumpHistoryEntry; } } @@ -268,7 +268,7 @@ public class MedtronicHistoryData { if (!this.allHistory.contains(pumpHistoryEntry)) { lastIdUsed++; - pumpHistoryEntry.id = lastIdUsed; + pumpHistoryEntry.setId(lastIdUsed); this.allHistory.add(pumpHistoryEntry); } @@ -278,13 +278,13 @@ public class MedtronicHistoryData { if (pheLast == null) // if we don't have any valid record we don't do the filtering and setting return; - this.setLastHistoryRecordTime(pheLast.atechDateTime); - sp.putLong(MedtronicConst.Statistics.LastPumpHistoryEntry, pheLast.atechDateTime); + this.setLastHistoryRecordTime(pheLast.getAtechDateTime()); + sp.putLong(MedtronicConst.Statistics.LastPumpHistoryEntry, pheLast.getAtechDateTime()); LocalDateTime dt = null; try { - dt = DateTimeUtil.toLocalDateTime(pheLast.atechDateTime); + dt = DateTimeUtil.toLocalDateTime(pheLast.getAtechDateTime()); } catch (Exception ex) { aapsLogger.error("Problem decoding date from last record: " + pheLast); } @@ -537,9 +537,9 @@ public class MedtronicHistoryData { continue; } - if (primeRecord.atechDateTime > maxAllowedTimeInPast) { - if (lastPrimeRecord < primeRecord.atechDateTime) { - lastPrimeRecord = primeRecord.atechDateTime; + if (primeRecord.getAtechDateTime() > maxAllowedTimeInPast) { + if (lastPrimeRecord < primeRecord.getAtechDateTime()) { + lastPrimeRecord = primeRecord.getAtechDateTime(); } } } @@ -560,9 +560,9 @@ public class MedtronicHistoryData { long lastRewindRecord = 0L; for (PumpHistoryEntry rewindRecord : rewindRecords) { - if (rewindRecord.atechDateTime > maxAllowedTimeInPast) { - if (lastRewindRecord < rewindRecord.atechDateTime) { - lastRewindRecord = rewindRecord.atechDateTime; + if (rewindRecord.getAtechDateTime() > maxAllowedTimeInPast) { + if (lastRewindRecord < rewindRecord.getAtechDateTime()) { + lastRewindRecord = rewindRecord.getAtechDateTime(); } } } @@ -593,7 +593,7 @@ public class MedtronicHistoryData { for (PumpHistoryEntry tdd : tdds) { - TDD tddDbEntry = findTDD(tdd.atechDateTime, tddsDb); + TDD tddDbEntry = findTDD(tdd.getAtechDateTime(), tddsDb); DailyTotalsDTO totalsDTO = (DailyTotalsDTO) tdd.getDecodedData().get("Object"); @@ -839,7 +839,7 @@ public class MedtronicHistoryData { */ private DbObjectBase findDbEntry(PumpHistoryEntry treatment, List entriesFromHistory) { - long proposedTime = DateTimeUtil.toMillisFromATD(treatment.atechDateTime); + long proposedTime = DateTimeUtil.toMillisFromATD(treatment.getAtechDateTime()); //proposedTime += (this.pumpTime.timeDifference * 1000); @@ -856,10 +856,10 @@ public class MedtronicHistoryData { // TODO: Fix db code // if difference is bigger than 2 minutes we discard entry - long maxMillisAllowed = DateTimeUtil.getMillisFromATDWithAddedMinutes(treatment.atechDateTime, 2); + 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.atechDateTime)); + 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) @@ -970,7 +970,7 @@ public class MedtronicHistoryData { case Normal: { DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo(); - detailedBolusInfo.setBolusTimestamp(tryToGetByLocalTime(bolus.atechDateTime)); + detailedBolusInfo.setBolusTimestamp(tryToGetByLocalTime(bolus.getAtechDateTime())); detailedBolusInfo.setPumpType(PumpType.MEDTRONIC_512_712); // TODO grab real model detailedBolusInfo.setPumpSerial(medtronicPumpStatus.serialNumber); detailedBolusInfo.setBolusPumpId(bolus.getPumpId()); @@ -993,7 +993,7 @@ public class MedtronicHistoryData { case Audio: case Extended: { ExtendedBolus extendedBolus = new ExtendedBolus(injector); - extendedBolus.date = tryToGetByLocalTime(bolus.atechDateTime); + extendedBolus.date = tryToGetByLocalTime(bolus.getAtechDateTime()); extendedBolus.source = Source.PUMP; extendedBolus.insulin = bolusDTO.getDeliveredAmount(); extendedBolus.pumpId = bolus.getPumpId(); @@ -1060,7 +1060,7 @@ public class MedtronicHistoryData { if (temporaryBasalDb == null) { temporaryBasalDb = new TemporaryBasal(injector); - temporaryBasalDb.date = tryToGetByLocalTime(treatment.atechDateTime); + temporaryBasalDb.date = tryToGetByLocalTime(treatment.getAtechDateTime()); operation = "addTBR"; } @@ -1094,7 +1094,7 @@ public class MedtronicHistoryData { if (tempBasal == null) { // add tempBasal = new TemporaryBasal(injector); - tempBasal.date = tryToGetByLocalTime(tempBasalProcess.itemOne.atechDateTime); + tempBasal.date = tryToGetByLocalTime(tempBasalProcess.itemOne.getAtechDateTime()); tempBasal.source = Source.PUMP; tempBasal.pumpId = tempBasalProcess.itemOne.getPumpId(); @@ -1346,8 +1346,8 @@ public class MedtronicHistoryData { for (PumpHistoryEntry treatment : treatments) { - if (treatment.atechDateTime < dt) { - dt = treatment.atechDateTime; + if (treatment.getAtechDateTime() < dt) { + dt = treatment.getAtechDateTime(); currentTreatment = treatment; } } @@ -1386,8 +1386,8 @@ public class MedtronicHistoryData { for (PumpHistoryEntry treatment : treatments) { - if (treatment.atechDateTime < dt) { - dt = treatment.atechDateTime; + if (treatment.getAtechDateTime() < dt) { + dt = treatment.getAtechDateTime(); currentTreatment = treatment; } } @@ -1469,9 +1469,9 @@ public class MedtronicHistoryData { for (PumpHistoryEntry filteredItem : filteredItems) { - if (lastDate == null || lastDate < filteredItem.atechDateTime) { + if (lastDate == null || lastDate < filteredItem.getAtechDateTime()) { newProfile = filteredItem; - lastDate = newProfile.atechDateTime; + lastDate = newProfile.getAtechDateTime(); } } } @@ -1517,13 +1517,13 @@ public class MedtronicHistoryData { Map map = new HashMap<>(); for (PumpHistoryEntry pumpHistoryEntry : TBRs_Input) { - if (map.containsKey(pumpHistoryEntry.DT)) { - medtronicPumpHistoryDecoder.decodeTempBasal(map.get(pumpHistoryEntry.DT), pumpHistoryEntry); + if (map.containsKey(pumpHistoryEntry.getDT())) { + medtronicPumpHistoryDecoder.decodeTempBasal(map.get(pumpHistoryEntry.getDT()), pumpHistoryEntry); pumpHistoryEntry.setEntryType(medtronicUtil.getMedtronicPumpModel(), PumpHistoryEntryType.TempBasalCombined); TBRs.add(pumpHistoryEntry); - map.remove(pumpHistoryEntry.DT); + map.remove(pumpHistoryEntry.getDT()); } else { - map.put(pumpHistoryEntry.DT, pumpHistoryEntry); + map.put(pumpHistoryEntry.getDT(), pumpHistoryEntry); } } diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/DailyTotalsDTO.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/DailyTotalsDTO.java index ae15a51c07..f32464b105 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/DailyTotalsDTO.java +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/DailyTotalsDTO.java @@ -74,15 +74,15 @@ public class DailyTotalsDTO { break; case DailyTotals515: - decodeDailyTotals515(entry.body); + decodeDailyTotals515(entry.getBody()); break; case DailyTotals522: - decodeDailyTotals522(entry.body); + decodeDailyTotals522(entry.getBody()); break; case DailyTotals523: - decodeDailyTotals523(entry.body); + decodeDailyTotals523(entry.getBody()); break; default: @@ -96,18 +96,18 @@ public class DailyTotalsDTO { private void setDisplayable() { if (this.insulinBasal == null) { - this.entry.displayableValue = "Total Insulin: " + StringUtil.getFormatedValueUS(this.insulinTotal, 2); + this.entry.setDisplayableValue("Total Insulin: " + StringUtil.getFormatedValueUS(this.insulinTotal, 2)); } else { - this.entry.displayableValue = "Basal Insulin: " + StringUtil.getFormatedValueUS(this.insulinBasal, 2) - + ", Total Insulin: " + StringUtil.getFormatedValueUS(this.insulinTotal, 2); + this.entry.setDisplayableValue("Basal Insulin: " + StringUtil.getFormatedValueUS(this.insulinBasal, 2) + + ", Total Insulin: " + StringUtil.getFormatedValueUS(this.insulinTotal, 2)); } } private void decodeEndResultsTotals(PumpHistoryEntry entry) { - double totals = ByteUtil.toInt((int) entry.head[0], (int) entry.head[1], (int) entry.head[2], - (int) entry.head[3], ByteUtil.BitConversion.BIG_ENDIAN) * 0.025d; + double totals = ByteUtil.toInt((int) entry.getHead()[0], (int) entry.getHead()[1], (int) entry.getHead()[2], + (int) entry.getHead()[3], ByteUtil.BitConversion.BIG_ENDIAN) * 0.025d; this.insulinTotal = totals; @@ -241,7 +241,7 @@ public class DailyTotalsDTO { } public void setTDD(TDD tdd) { - tdd.date = DateTimeUtil.toMillisFromATD(this.entry.atechDateTime); + tdd.date = DateTimeUtil.toMillisFromATD(this.entry.getAtechDateTime()); tdd.basal = insulinBasal; tdd.bolus = insulinBolus; tdd.total = insulinTotal; diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/TempBasalProcessDTO.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/TempBasalProcessDTO.java index 86cba28184..f35a5b43c0 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/TempBasalProcessDTO.java +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/TempBasalProcessDTO.java @@ -15,7 +15,7 @@ public class TempBasalProcessDTO { TempBasalPair tbr = (TempBasalPair) itemOne.getDecodedDataEntry("Object"); return tbr.getDurationMinutes(); } else { - int difference = DateTimeUtil.getATechDateDiferenceAsMinutes(itemOne.atechDateTime, itemTwo.atechDateTime); + int difference = DateTimeUtil.getATechDateDiferenceAsMinutes(itemOne.getAtechDateTime(), itemTwo.getAtechDateTime()); return difference; } } 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 0a324648e8..5e9958fee9 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 @@ -1,7 +1,9 @@ package info.nightscout.androidaps.plugins.pump.medtronic.di import dagger.Module +import dagger.Provides 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.MedtronicUITask @@ -20,4 +22,9 @@ abstract class MedtronicModule { @ContributesAndroidInjector abstract fun medtronicCommunicationManagerProvider(): MedtronicCommunicationManager @ContributesAndroidInjector abstract fun medtronicUITaskProvider(): MedtronicUITask @ContributesAndroidInjector abstract fun contributesRileyLinkStatusDeviceMedtronic(): RileyLinkStatusDeviceMedtronic + + companion object { + @Provides + fun byteUtilProvider(): ByteUtil = ByteUtil(); + } } \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/MedtronicHistoryActivity.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/MedtronicHistoryActivity.java index a2ce6c00e7..fc986f4f83 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/MedtronicHistoryActivity.java +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/MedtronicHistoryActivity.java @@ -59,7 +59,7 @@ public class MedtronicHistoryActivity extends NoSplashAppCompatActivity { this.filteredHistoryList.addAll(list); } else { for (PumpHistoryEntry pumpHistoryEntry : list) { - if (pumpHistoryEntry.getEntryType().group == group) { + if (pumpHistoryEntry.getEntryType().getGroup() == group) { this.filteredHistoryList.add(pumpHistoryEntry); } } @@ -214,7 +214,7 @@ public class MedtronicHistoryActivity extends NoSplashAppCompatActivity { if (record != null) { holder.timeView.setText(record.getDateTimeString()); holder.typeView.setText(record.getEntryType().getDescription()); - holder.valueView.setText(record.displayableValue); + holder.valueView.setText(record.getDisplayableValue()); } } diff --git a/medtronic/src/test/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntryUTest.java b/medtronic/src/test/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntryUTest.java index af8c7b0d0a..043a2fdd86 100644 --- a/medtronic/src/test/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntryUTest.java +++ b/medtronic/src/test/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntryUTest.java @@ -16,7 +16,7 @@ public class PumpHistoryEntryUTest { long queryObject = 20191009000000L; PumpHistoryEntry phe = new PumpHistoryEntry(); - phe.atechDateTime = dateObject; + phe.setAtechDateTime(dateObject); Assert.assertTrue(phe.isAfter(queryObject)); } From bb657a249833a28be46c1e2e00d35df188e6dac8 Mon Sep 17 00:00:00 2001 From: Andy Rozman Date: Fri, 16 Apr 2021 23:41:24 +0100 Subject: [PATCH 005/145] - kotlin changes - disabled problem in Fragment for now --- .../pump/medtronic/MedtronicFragment.kt | 20 +- .../pump/medtronic/MedtronicPumpPlugin.java | 6 +- .../medtronic/comm/MedtronicConverter.java | 444 ------------------ .../pump/medtronic/comm/MedtronicConverter.kt | 314 +++++++++++++ .../cgms/MedtronicCGMSHistoryDecoder.kt | 4 +- .../pump/medtronic/data/dto/BasalProfile.java | 384 --------------- .../pump/medtronic/data/dto/BasalProfile.kt | 315 +++++++++++++ .../medtronic/data/dto/BasalProfileEntry.java | 81 ---- .../medtronic/data/dto/BasalProfileEntry.kt | 74 +++ .../medtronic/defs/MedtronicCommandType.java | 60 --- 10 files changed, 723 insertions(+), 979 deletions(-) delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicConverter.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicConverter.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BasalProfile.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BasalProfile.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BasalProfileEntry.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BasalProfileEntry.kt diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicFragment.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicFragment.kt index d9124ec15e..43a75631bf 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicFragment.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicFragment.kt @@ -311,13 +311,21 @@ class MedtronicFragment : DaggerFragment() { binding.lastBolus.text = "" } - val pumpState = pumpSync.expectedPumpState() - // base basal rate - binding.baseBasalRate.text = ("(" + medtronicPumpStatus.activeProfileName + ") " - + resourceHelper.gs(R.string.pump_basebasalrate, medtronicPumpPlugin.baseBasalRate)) + if (true) { + // base basal rate + binding.baseBasalRate.text = ("(" + medtronicPumpStatus.activeProfileName + ") " + + resourceHelper.gs(R.string.pump_basebasalrate, medtronicPumpPlugin.baseBasalRate)) - binding.tempBasal.text = pumpState.temporaryBasal?.toStringFull(dateUtil) - ?: "" + binding.tempBasal.text = "??" + } else { + val pumpState = pumpSync.expectedPumpState() + // base basal rate + binding.baseBasalRate.text = ("(" + medtronicPumpStatus.activeProfileName + ") " + + resourceHelper.gs(R.string.pump_basebasalrate, medtronicPumpPlugin.baseBasalRate)) + + binding.tempBasal.text = pumpState.temporaryBasal?.toStringFull(dateUtil) + ?: "" + } // battery if (medtronicPumpStatus.batteryType == BatteryType.None || medtronicPumpStatus.batteryVoltage == null) { diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java index f41fb04348..b514ec7d3a 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java @@ -1499,10 +1499,10 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements Pump, Ril for (BasalProfileEntry profileEntry : basalProfile.getEntries()) { - if (profileEntry.rate > medtronicPumpStatus.maxBasal) { - stringBuilder.append(profileEntry.startTime.toString("HH:mm")); + if (profileEntry.getRate() > medtronicPumpStatus.maxBasal) { + stringBuilder.append(profileEntry.getStartTime().toString("HH:mm")); stringBuilder.append("="); - stringBuilder.append(profileEntry.rate); + stringBuilder.append(profileEntry.getRate()); } } diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicConverter.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicConverter.java deleted file mode 100644 index f9ad49b723..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicConverter.java +++ /dev/null @@ -1,444 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm; - -import org.joda.time.IllegalFieldValueException; -import org.joda.time.LocalDateTime; - -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; - -import javax.inject.Inject; -import javax.inject.Singleton; - -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.ByteUtil; -import info.nightscout.androidaps.plugins.pump.common.utils.StringUtil; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BasalProfile; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BatteryStatusDTO; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.PumpSettingDTO; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.TempBasalPair; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicCommandType; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicDeviceType; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.PumpConfigurationGroup; -import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil; - -/** - * Created by andy on 5/9/18. - * High level decoder for data returned through MedtroniUIComm - */ - -@Singleton -public class MedtronicConverter { - - private final AAPSLogger aapsLogger; - private final MedtronicUtil medtronicUtil; - - @Inject - public MedtronicConverter( - AAPSLogger aapsLogger, - MedtronicUtil medtronicUtil - ) { - this.aapsLogger = aapsLogger; - this.medtronicUtil = medtronicUtil; - } - - Object convertResponse(PumpType pumpType, MedtronicCommandType commandType, byte[] rawContent) { - - if ((rawContent == null || rawContent.length < 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 == null ? "-" : rawContent.length)); - return null; - } - - aapsLogger.debug(LTag.PUMPCOMM, "Raw response before convert: " + ByteUtil.shortHexString(rawContent)); - - switch (commandType) { - - case PumpModel: { - return decodeModel(rawContent); - } - - case GetRealTimeClock: { - return decodeTime(rawContent); - } - - case GetRemainingInsulin: { - return decodeRemainingInsulin(rawContent); - } - - case GetBatteryStatus: { - return decodeBatteryStatus(rawContent); // 1 - } - - case GetBasalProfileSTD: - case GetBasalProfileA: - case GetBasalProfileB: { - return decodeBasalProfile(pumpType, rawContent); - - } - - case ReadTemporaryBasal: { - return new TempBasalPair(aapsLogger, rawContent); // 5 - } - - case Settings_512: { - return decodeSettingsLoop(rawContent); - } - - case Settings: { - return decodeSettingsLoop(rawContent); - } - - case SetBolus: { - return rawContent; // 1 - } - - default: { - throw new RuntimeException("Unsupported command Type: " + commandType); - } - - } - - } - - - private BasalProfile decodeBasalProfile(PumpType pumpType, byte[] rawContent) { - - BasalProfile basalProfile = new BasalProfile(aapsLogger, rawContent); - - return basalProfile.verify(pumpType) ? basalProfile : null; - } - - - private MedtronicDeviceType decodeModel(byte[] rawContent) { - - if ((rawContent == null || rawContent.length < 4)) { - aapsLogger.warn(LTag.PUMPCOMM, "Error reading PumpModel, returning Unknown_Device"); - return MedtronicDeviceType.Unknown_Device; - } - - String rawModel = StringUtil.fromBytes(ByteUtil.substring(rawContent, 1, 3)); - MedtronicDeviceType pumpModel = MedtronicDeviceType.getByDescription(rawModel); - aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "PumpModel: [raw=%s, resolved=%s]", rawModel, pumpModel.name())); - - if (pumpModel != MedtronicDeviceType.Unknown_Device) { - if (!medtronicUtil.isModelSet()) { - medtronicUtil.setMedtronicPumpModel(pumpModel); - } - } - - return pumpModel; - } - - - private BatteryStatusDTO decodeBatteryStatus(byte[] rawData) { - // 00 7C 00 00 - - BatteryStatusDTO batteryStatus = new BatteryStatusDTO(); - - int status = rawData[0]; - - if (status == 0) { - batteryStatus.batteryStatusType = BatteryStatusDTO.BatteryStatusType.Normal; - } else if (status == 1) { - batteryStatus.batteryStatusType = BatteryStatusDTO.BatteryStatusType.Low; - } else if (status == 2) { - batteryStatus.batteryStatusType = BatteryStatusDTO.BatteryStatusType.Unknown; - } - - if (rawData.length > 1) { - - Double d = null; - - // if response in 3 bytes then we add additional information - if (rawData.length == 2) { - d = (rawData[1] * 1.0d) / 100.0d; - } else { - d = (ByteUtil.toInt(rawData[1], rawData[2]) * 1.0d) / 100.0d; - } - - batteryStatus.voltage = d; - batteryStatus.extendedDataReceived = true; - } - - return batteryStatus; - } - - - private Float decodeRemainingInsulin(byte[] rawData) { - int startIdx = 0; - - MedtronicDeviceType pumpModel = medtronicUtil.getMedtronicPumpModel(); - - int strokes = pumpModel == null ? 10 : pumpModel.getBolusStrokes(); - - if (strokes == 40) { - startIdx = 2; - } - - int reqLength = startIdx + 1; - float value = 0; - - if (reqLength >= rawData.length) { - value = rawData[startIdx] / (1.0f * strokes); - } else { - value = ByteUtil.toInt(rawData[startIdx], rawData[startIdx + 1]) / (1.0f * strokes); - } - - aapsLogger.debug(LTag.PUMPCOMM, "Remaining insulin: " + value); - return value; - } - - - private LocalDateTime decodeTime(byte[] rawContent) { - - int hours = ByteUtil.asUINT8(rawContent[0]); - int minutes = ByteUtil.asUINT8(rawContent[1]); - int seconds = ByteUtil.asUINT8(rawContent[2]); - int year = (ByteUtil.asUINT8(rawContent[4]) & 0x3f) + 1984; - int month = ByteUtil.asUINT8(rawContent[5]); - int day = ByteUtil.asUINT8(rawContent[6]); - try { - LocalDateTime pumpTime = new LocalDateTime(year, month, day, hours, minutes, seconds); - return pumpTime; - } catch (IllegalFieldValueException e) { - aapsLogger.error(LTag.PUMPCOMM, - String.format(Locale.ENGLISH, "decodeTime: Failed to parse pump time value: year=%d, month=%d, hours=%d, minutes=%d, seconds=%d", - year, month, day, hours, minutes, seconds)); - return null; - } - - } - - - private Map decodeSettingsLoop(byte[] rd) { - - Map map = new HashMap<>(); - - addSettingToMap("PCFG_MAX_BOLUS", "" + decodeMaxBolus(rd), PumpConfigurationGroup.Bolus, map); - addSettingToMap( - "PCFG_MAX_BASAL", - "" - + decodeBasalInsulin(ByteUtil.makeUnsignedShort(rd[getSettingIndexMaxBasal()], - rd[getSettingIndexMaxBasal() + 1])), PumpConfigurationGroup.Basal, map); - addSettingToMap("CFG_BASE_CLOCK_MODE", rd[getSettingIndexTimeDisplayFormat()] == 0 ? "12h" : "24h", - PumpConfigurationGroup.General, map); - - addSettingToMap("PCFG_BASAL_PROFILES_ENABLED", parseResultEnable(rd[10]), PumpConfigurationGroup.Basal, map); - - if (rd[10] == 1) { - String patt; - switch (rd[11]) { - case 0: - patt = "STD"; - break; - - case 1: - patt = "A"; - break; - - case 2: - patt = "B"; - break; - - default: - patt = "???"; - break; - } - - addSettingToMap("PCFG_ACTIVE_BASAL_PROFILE", patt, PumpConfigurationGroup.Basal, map); - - } else { - addSettingToMap("PCFG_ACTIVE_BASAL_PROFILE", "STD", PumpConfigurationGroup.Basal, map); - } - - addSettingToMap("PCFG_TEMP_BASAL_TYPE", rd[14] != 0 ? "Percent" : "Units", PumpConfigurationGroup.Basal, map); - - return map; - } - - - private Map decodeSettings512(byte[] rd) { - - Map map = new HashMap<>(); - - addSettingToMap("PCFG_AUTOOFF_TIMEOUT", "" + rd[0], PumpConfigurationGroup.General, map); - - if (rd[1] == 4) { - addSettingToMap("PCFG_ALARM_MODE", "Silent", PumpConfigurationGroup.Sound, map); - } else { - addSettingToMap("PCFG_ALARM_MODE", "Normal", PumpConfigurationGroup.Sound, map); - addSettingToMap("PCFG_ALARM_BEEP_VOLUME", "" + rd[1], PumpConfigurationGroup.Sound, map); - } - - addSettingToMap("PCFG_AUDIO_BOLUS_ENABLED", parseResultEnable(rd[2]), PumpConfigurationGroup.Bolus, map); - - if (rd[2] == 1) { - addSettingToMap("PCFG_AUDIO_BOLUS_STEP_SIZE", "" + decodeBolusInsulin(ByteUtil.asUINT8(rd[3])), - PumpConfigurationGroup.Bolus, map); - } - - addSettingToMap("PCFG_VARIABLE_BOLUS_ENABLED", parseResultEnable(rd[4]), PumpConfigurationGroup.Bolus, map); - addSettingToMap("PCFG_MAX_BOLUS", "" + decodeMaxBolus(rd), PumpConfigurationGroup.Bolus, map); - addSettingToMap( - "PCFG_MAX_BASAL", - "" - + decodeBasalInsulin(ByteUtil.makeUnsignedShort(rd[getSettingIndexMaxBasal()], - rd[getSettingIndexMaxBasal() + 1])), PumpConfigurationGroup.Basal, map); - addSettingToMap("CFG_BASE_CLOCK_MODE", rd[getSettingIndexTimeDisplayFormat()] == 0 ? "12h" : "24h", - PumpConfigurationGroup.General, map); - - if (MedtronicDeviceType.isSameDevice(medtronicUtil.getMedtronicPumpModel(), MedtronicDeviceType.Medtronic_523andHigher)) { - addSettingToMap("PCFG_INSULIN_CONCENTRATION", "" + (rd[9] == 0 ? 50 : 100), PumpConfigurationGroup.Insulin, - map); -// LOG.debug("Insulin concentration: " + rd[9]); - } else { - addSettingToMap("PCFG_INSULIN_CONCENTRATION", "" + (rd[9] != 0 ? 50 : 100), PumpConfigurationGroup.Insulin, - map); -// LOG.debug("Insulin concentration: " + rd[9]); - } - addSettingToMap("PCFG_BASAL_PROFILES_ENABLED", parseResultEnable(rd[10]), PumpConfigurationGroup.Basal, map); - - if (rd[10] == 1) { - String patt; - switch (rd[11]) { - case 0: - patt = "STD"; - break; - - case 1: - patt = "A"; - break; - - case 2: - patt = "B"; - break; - - default: - patt = "???"; - break; - } - - addSettingToMap("PCFG_ACTIVE_BASAL_PROFILE", patt, PumpConfigurationGroup.Basal, map); - - } - - addSettingToMap("CFG_MM_RF_ENABLED", parseResultEnable(rd[12]), PumpConfigurationGroup.General, map); - addSettingToMap("CFG_MM_BLOCK_ENABLED", parseResultEnable(rd[13]), PumpConfigurationGroup.General, map); - - addSettingToMap("PCFG_TEMP_BASAL_TYPE", rd[14] != 0 ? "Percent" : "Units", PumpConfigurationGroup.Basal, map); - - if (rd[14] == 1) { - addSettingToMap("PCFG_TEMP_BASAL_PERCENT", "" + rd[15], PumpConfigurationGroup.Basal, map); - } - - addSettingToMap("CFG_PARADIGM_LINK_ENABLE", parseResultEnable(rd[16]), PumpConfigurationGroup.General, map); - - decodeInsulinActionSetting(rd, map); - - return map; - } - - - private void addSettingToMap(String key, String value, PumpConfigurationGroup group, Map map) { - map.put(key, new PumpSettingDTO(key, value, group)); - } - - - public Map decodeSettings(byte[] rd) { - Map map = decodeSettings512(rd); - - addSettingToMap("PCFG_MM_RESERVOIR_WARNING_TYPE_TIME", rd[18] != 0 ? "PCFG_MM_RESERVOIR_WARNING_TYPE_TIME" - : "PCFG_MM_RESERVOIR_WARNING_TYPE_UNITS", PumpConfigurationGroup.Other, map); - - addSettingToMap("PCFG_MM_SRESERVOIR_WARNING_POINT", "" + ByteUtil.asUINT8(rd[19]), - PumpConfigurationGroup.Other, map); - - addSettingToMap("CFG_MM_KEYPAD_LOCKED", parseResultEnable(rd[20]), PumpConfigurationGroup.Other, map); - - if (MedtronicDeviceType.isSameDevice(medtronicUtil.getMedtronicPumpModel(), MedtronicDeviceType.Medtronic_523andHigher)) { - - addSettingToMap("PCFG_BOLUS_SCROLL_STEP_SIZE", "" + rd[21], PumpConfigurationGroup.Bolus, map); - addSettingToMap("PCFG_CAPTURE_EVENT_ENABLE", parseResultEnable(rd[22]), PumpConfigurationGroup.Other, map); - addSettingToMap("PCFG_OTHER_DEVICE_ENABLE", parseResultEnable(rd[23]), PumpConfigurationGroup.Other, map); - addSettingToMap("PCFG_OTHER_DEVICE_PAIRED_STATE", parseResultEnable(rd[24]), PumpConfigurationGroup.Other, - map); - } - - return map; - } - - - private String parseResultEnable(int i) { - switch (i) { - case 0: - return "No"; - case 1: - return "Yes"; - default: - return "???"; - } - } - - - private float getStrokesPerUnit(boolean isBasal) { - return isBasal ? 40.0f : 10; // pumpModel.getBolusStrokes(); - } - - - // 512 - private void decodeInsulinActionSetting(byte[] ai, Map map) { - if (MedtronicDeviceType.isSameDevice(medtronicUtil.getMedtronicPumpModel(), MedtronicDeviceType.Medtronic_512_712)) { - addSettingToMap("PCFG_INSULIN_ACTION_TYPE", (ai[17] != 0 ? "Regular" : "Fast"), - PumpConfigurationGroup.Insulin, map); - } else { - int i = ai[17]; - String s; - - if ((i == 0) || (i == 1)) { - s = ai[17] != 0 ? "Regular" : "Fast"; - } else { - if (i == 15) - s = "Unset"; - else - s = "Curve: " + i; - } - - addSettingToMap("PCFG_INSULIN_ACTION_TYPE", s, PumpConfigurationGroup.Insulin, map); - } - } - - - private double decodeBasalInsulin(int i) { - return (double) i / (double) getStrokesPerUnit(true); - } - - - private double decodeBolusInsulin(int i) { - - return (double) i / (double) getStrokesPerUnit(false); - } - - - private int getSettingIndexMaxBasal() { - return is523orHigher() ? 7 : 6; - } - - - private int getSettingIndexTimeDisplayFormat() { - return is523orHigher() ? 9 : 8; - } - - - private double decodeMaxBolus(byte[] ai) { - return is523orHigher() ? decodeBolusInsulin(ByteUtil.toInt(ai[5], ai[6])) : decodeBolusInsulin(ByteUtil - .asUINT8(ai[5])); - } - - - private boolean is523orHigher() { - return (MedtronicDeviceType.isSameDevice(medtronicUtil.getMedtronicPumpModel(), MedtronicDeviceType.Medtronic_523andHigher)); - } -} 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 new file mode 100644 index 0000000000..3796661ef5 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicConverter.kt @@ -0,0 +1,314 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm + +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.ByteUtil +import info.nightscout.androidaps.plugins.pump.common.utils.StringUtil +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BasalProfile +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BatteryStatusDTO +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.PumpSettingDTO +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.TempBasalPair +import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicCommandType +import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicDeviceType +import info.nightscout.androidaps.plugins.pump.medtronic.defs.PumpConfigurationGroup +import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil +import org.joda.time.IllegalFieldValueException +import org.joda.time.LocalDateTime +import java.util.* +import javax.inject.Inject +import javax.inject.Singleton + +/** + * Created by andy on 5/9/18. + * High level decoder for data returned through MedtroniUIComm + */ +@Singleton +class MedtronicConverter @Inject constructor( + private val aapsLogger: AAPSLogger, + 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) + } + + 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? { + val basalProfile = BasalProfile(aapsLogger, rawContent!!) + return if (basalProfile.verify(pumpType)) basalProfile else null + } + + private 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 + } + val rawModel = StringUtil.fromBytes(ByteUtil.substring(rawContent, 1, 3)) + val pumpModel = MedtronicDeviceType.getByDescription(rawModel) + aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "PumpModel: [raw=%s, resolved=%s]", rawModel, pumpModel.name)) + if (pumpModel != MedtronicDeviceType.Unknown_Device) { + if (!medtronicUtil.isModelSet) { + medtronicUtil.medtronicPumpModel = pumpModel + } + } + return pumpModel + } + + private fun decodeBatteryStatus(rawData: ByteArray?): BatteryStatusDTO { + // 00 7C 00 00 + val batteryStatus = BatteryStatusDTO() + val status = rawData!![0].toInt() + if (status == 0) { + batteryStatus.batteryStatusType = BatteryStatusDTO.BatteryStatusType.Normal + } else if (status == 1) { + batteryStatus.batteryStatusType = BatteryStatusDTO.BatteryStatusType.Low + } else if (status == 2) { + batteryStatus.batteryStatusType = BatteryStatusDTO.BatteryStatusType.Unknown + } + if (rawData.size > 1) { + var d: Double? = null + + // if response in 3 bytes then we add additional information + d = if (rawData.size == 2) { + rawData[1] * 1.0 / 100.0 + } else { + ByteUtil.toInt(rawData[1], rawData[2]) * 1.0 / 100.0 + } + batteryStatus.voltage = d + batteryStatus.extendedDataReceived = true + } + return batteryStatus + } + + private fun decodeRemainingInsulin(rawData: ByteArray?): Float { + var startIdx = 0 + val pumpModel = medtronicUtil.medtronicPumpModel + val strokes = pumpModel?.bolusStrokes ?: 10 + if (strokes == 40) { + startIdx = 2 + } + val reqLength = startIdx + 1 + var value = 0f + value = if (reqLength >= rawData!!.size) { + rawData[startIdx] / (1.0f * strokes) + } else { + ByteUtil.toInt(rawData[startIdx], rawData[startIdx + 1]) / (1.0f * strokes) + } + aapsLogger.debug(LTag.PUMPCOMM, "Remaining insulin: $value") + return value + } + + private fun decodeTime(rawContent: ByteArray?): LocalDateTime? { + val hours = ByteUtil.asUINT8(rawContent!![0]) + val minutes = ByteUtil.asUINT8(rawContent[1]) + val seconds = ByteUtil.asUINT8(rawContent[2]) + val year = (ByteUtil.asUINT8(rawContent[4]) and 0x3f) + 1984 + val month = ByteUtil.asUINT8(rawContent[5]) + val day = ByteUtil.asUINT8(rawContent[6]) + return try { + LocalDateTime(year, month, day, hours, minutes, seconds) + } catch (e: IllegalFieldValueException) { + aapsLogger.error(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "decodeTime: Failed to parse pump time value: year=%d, month=%d, hours=%d, minutes=%d, seconds=%d", + year, month, day, hours, minutes, seconds)) + null + } + } + + private fun decodeSettingsLoop(rd: ByteArray?): Map { + val map: MutableMap = HashMap() + addSettingToMap("PCFG_MAX_BOLUS", "" + decodeMaxBolus(rd), PumpConfigurationGroup.Bolus, map) + addSettingToMap( + "PCFG_MAX_BASAL", "" + + decodeBasalInsulin(ByteUtil.makeUnsignedShort(rd!![settingIndexMaxBasal].toInt(), + rd[settingIndexMaxBasal + 1].toInt())), PumpConfigurationGroup.Basal, map) + addSettingToMap("CFG_BASE_CLOCK_MODE", if (rd[settingIndexTimeDisplayFormat].toInt() == 0) "12h" else "24h", + PumpConfigurationGroup.General, map) + addSettingToMap("PCFG_BASAL_PROFILES_ENABLED", parseResultEnable(rd[10].toInt()), PumpConfigurationGroup.Basal, map) + if (rd[10].toInt() == 1) { + val patt: String + patt = when (rd[11].toInt()) { + 0 -> "STD" + 1 -> "A" + 2 -> "B" + else -> "???" + } + addSettingToMap("PCFG_ACTIVE_BASAL_PROFILE", patt, PumpConfigurationGroup.Basal, map) + } else { + addSettingToMap("PCFG_ACTIVE_BASAL_PROFILE", "STD", PumpConfigurationGroup.Basal, map) + } + addSettingToMap("PCFG_TEMP_BASAL_TYPE", if (rd[14].toInt() != 0) "Percent" else "Units", PumpConfigurationGroup.Basal, map) + return map + } + + private fun decodeSettings512(rd: ByteArray): MutableMap { + val map: MutableMap = HashMap() + addSettingToMap("PCFG_AUTOOFF_TIMEOUT", "" + rd[0], PumpConfigurationGroup.General, map) + if (rd[1].toInt() == 4) { + addSettingToMap("PCFG_ALARM_MODE", "Silent", PumpConfigurationGroup.Sound, map) + } else { + addSettingToMap("PCFG_ALARM_MODE", "Normal", PumpConfigurationGroup.Sound, map) + addSettingToMap("PCFG_ALARM_BEEP_VOLUME", "" + rd[1], PumpConfigurationGroup.Sound, map) + } + addSettingToMap("PCFG_AUDIO_BOLUS_ENABLED", parseResultEnable(rd[2].toInt()), PumpConfigurationGroup.Bolus, map) + if (rd[2].toInt() == 1) { + addSettingToMap("PCFG_AUDIO_BOLUS_STEP_SIZE", "" + decodeBolusInsulin(ByteUtil.asUINT8(rd[3])), + PumpConfigurationGroup.Bolus, map) + } + addSettingToMap("PCFG_VARIABLE_BOLUS_ENABLED", parseResultEnable(rd[4].toInt()), PumpConfigurationGroup.Bolus, map) + addSettingToMap("PCFG_MAX_BOLUS", "" + decodeMaxBolus(rd), PumpConfigurationGroup.Bolus, map) + addSettingToMap( + "PCFG_MAX_BASAL", "" + + decodeBasalInsulin(ByteUtil.makeUnsignedShort(rd[settingIndexMaxBasal].toInt(), + rd[settingIndexMaxBasal + 1].toInt())), PumpConfigurationGroup.Basal, map) + addSettingToMap("CFG_BASE_CLOCK_MODE", if (rd[settingIndexTimeDisplayFormat].toInt() == 0) "12h" else "24h", + PumpConfigurationGroup.General, map) + if (MedtronicDeviceType.isSameDevice(medtronicUtil.medtronicPumpModel, MedtronicDeviceType.Medtronic_523andHigher)) { + addSettingToMap("PCFG_INSULIN_CONCENTRATION", "" + if (rd[9].toInt() == 0) 50 else 100, PumpConfigurationGroup.Insulin, + map) + // LOG.debug("Insulin concentration: " + rd[9]); + } else { + addSettingToMap("PCFG_INSULIN_CONCENTRATION", "" + if (rd[9].toInt() != 0) 50 else 100, PumpConfigurationGroup.Insulin, + map) + // LOG.debug("Insulin concentration: " + rd[9]); + } + addSettingToMap("PCFG_BASAL_PROFILES_ENABLED", parseResultEnable(rd[10].toInt()), PumpConfigurationGroup.Basal, map) + if (rd[10].toInt() == 1) { + val patt: String + patt = when (rd[11].toInt()) { + 0 -> "STD" + 1 -> "A" + 2 -> "B" + else -> "???" + } + addSettingToMap("PCFG_ACTIVE_BASAL_PROFILE", patt, PumpConfigurationGroup.Basal, map) + } + addSettingToMap("CFG_MM_RF_ENABLED", parseResultEnable(rd[12].toInt()), PumpConfigurationGroup.General, map) + addSettingToMap("CFG_MM_BLOCK_ENABLED", parseResultEnable(rd[13].toInt()), PumpConfigurationGroup.General, map) + addSettingToMap("PCFG_TEMP_BASAL_TYPE", if (rd[14].toInt() != 0) "Percent" else "Units", PumpConfigurationGroup.Basal, map) + if (rd[14].toInt() == 1) { + addSettingToMap("PCFG_TEMP_BASAL_PERCENT", "" + rd[15], PumpConfigurationGroup.Basal, map) + } + addSettingToMap("CFG_PARADIGM_LINK_ENABLE", parseResultEnable(rd[16].toInt()), PumpConfigurationGroup.General, map) + decodeInsulinActionSetting(rd, map) + return map + } + + private fun addSettingToMap(key: String, value: String, group: PumpConfigurationGroup, map: MutableMap) { + map[key] = PumpSettingDTO(key, value, group) + } + + fun decodeSettings(rd: ByteArray): Map { + val map = decodeSettings512(rd) + addSettingToMap("PCFG_MM_RESERVOIR_WARNING_TYPE_TIME", if (rd[18].toInt() != 0) "PCFG_MM_RESERVOIR_WARNING_TYPE_TIME" else "PCFG_MM_RESERVOIR_WARNING_TYPE_UNITS", PumpConfigurationGroup.Other, map) + addSettingToMap("PCFG_MM_SRESERVOIR_WARNING_POINT", "" + ByteUtil.asUINT8(rd[19]), + PumpConfigurationGroup.Other, map) + addSettingToMap("CFG_MM_KEYPAD_LOCKED", parseResultEnable(rd[20].toInt()), PumpConfigurationGroup.Other, map) + if (MedtronicDeviceType.isSameDevice(medtronicUtil.medtronicPumpModel, MedtronicDeviceType.Medtronic_523andHigher)) { + addSettingToMap("PCFG_BOLUS_SCROLL_STEP_SIZE", "" + rd[21], PumpConfigurationGroup.Bolus, map) + addSettingToMap("PCFG_CAPTURE_EVENT_ENABLE", parseResultEnable(rd[22].toInt()), PumpConfigurationGroup.Other, map) + addSettingToMap("PCFG_OTHER_DEVICE_ENABLE", parseResultEnable(rd[23].toInt()), PumpConfigurationGroup.Other, map) + addSettingToMap("PCFG_OTHER_DEVICE_PAIRED_STATE", parseResultEnable(rd[24].toInt()), PumpConfigurationGroup.Other, + map) + } + return map + } + + private fun parseResultEnable(i: Int): String { + return when (i) { + 0 -> "No" + 1 -> "Yes" + else -> "???" + } + } + + private fun getStrokesPerUnit(isBasal: Boolean): Float { + return if (isBasal) 40.0f else 10.0f // pumpModel.getBolusStrokes(); + } + + // 512 + private fun decodeInsulinActionSetting(ai: ByteArray, map: MutableMap) { + if (MedtronicDeviceType.isSameDevice(medtronicUtil.medtronicPumpModel, MedtronicDeviceType.Medtronic_512_712)) { + addSettingToMap("PCFG_INSULIN_ACTION_TYPE", if (ai[17].toInt() != 0) "Regular" else "Fast", + PumpConfigurationGroup.Insulin, map) + } else { + val i = ai[17].toInt() + val s: String + s = if (i == 0 || i == 1) { + if (ai[17].toInt() != 0) "Regular" else "Fast" + } else { + if (i == 15) "Unset" else "Curve: $i" + } + addSettingToMap("PCFG_INSULIN_ACTION_TYPE", s, PumpConfigurationGroup.Insulin, map) + } + } + + private fun decodeBasalInsulin(i: Int): Double { + return i.toDouble() / getStrokesPerUnit(true).toDouble() + } + + private fun decodeBolusInsulin(i: Int): Double { + return i.toDouble() / getStrokesPerUnit(false).toDouble() + } + + private val settingIndexMaxBasal: Int + private get() = if (is523orHigher()) 7 else 6 + + private val settingIndexTimeDisplayFormat: Int + private get() = if (is523orHigher()) 9 else 8 + + private fun decodeMaxBolus(ai: ByteArray?): Double { + return if (is523orHigher()) decodeBolusInsulin(ByteUtil.toInt(ai!![5], ai[6])) else decodeBolusInsulin(ByteUtil + .asUINT8(ai!![5])) + } + + private fun is523orHigher(): Boolean { + return MedtronicDeviceType.isSameDevice(medtronicUtil.medtronicPumpModel, MedtronicDeviceType.Medtronic_523andHigher) + } + +} \ 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 d56798dd3a..77f1ee32c1 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 @@ -10,7 +10,9 @@ import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.cgms.CGMSH import okhttp3.internal.and import org.joda.time.LocalDateTime import org.slf4j.Logger +import org.slf4j.LoggerFactory import java.util.* +import org.slf4j.LoggerFactory.getLogger as getLogger1 /** * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes @@ -264,6 +266,6 @@ class MedtronicCGMSHistoryDecoder : MedtronicHistoryDecoder() } companion object { - private val LOG: Logger = getLogger(LTag.PUMPCOMM) + private val LOG: Logger = getLogger1("MedtronicCGMSHistoryDecoder") } } \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BasalProfile.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BasalProfile.java deleted file mode 100644 index 3cbd03f20d..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BasalProfile.java +++ /dev/null @@ -1,384 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.data.dto; - -import androidx.annotation.NonNull; - -import com.google.gson.annotations.Expose; - -import org.joda.time.Instant; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -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.ByteUtil; -import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil; - -/** - * Created by geoff on 6/1/15. - *

- * There are three basal profiles stored on the pump. (722 only?) They are all parsed the same, the user just has 3 to - * choose from: Standard, A, and B - *

- * The byte array is 48 times three byte entries long, plus a zero? If the profile is completely empty, it should have - * one entry: [0,0,0x3F]. The first entry of [0,0,0] marks the end of the used entries. - *

- * Each entry is assumed to span from the specified start time to the start time of the next entry, or to midnight if - * there are no more entries. - *

- * Individual entries are of the form [r,z,m] where r is the rate (in 0.025 U increments) z is zero (?) m is the start - * time-of-day for the basal rate period (in 30 minute increments) - */ -public class BasalProfile { - - private final AAPSLogger aapsLogger; - - public static final int MAX_RAW_DATA_SIZE = (48 * 3) + 1; - private static final boolean DEBUG_BASALPROFILE = false; - @Expose - private byte[] mRawData; // store as byte array to make transport (via parcel) easier - private List listEntries; - - - public BasalProfile(AAPSLogger aapsLogger) { - this.aapsLogger = aapsLogger; - init(); - } - - - public BasalProfile(AAPSLogger aapsLogger, byte[] data) { - this.aapsLogger = aapsLogger; - setRawData(data); - } - - - // this asUINT8 should be combined with Record.asUINT8, and placed in a new util class. - private static int readUnsignedByte(byte b) { - return (b < 0) ? b + 256 : b; - } - - - public void init() { - mRawData = new byte[MAX_RAW_DATA_SIZE]; - mRawData[0] = 0; - mRawData[1] = 0; - mRawData[2] = 0x3f; - } - - - private boolean setRawData(byte[] data) { - if (data == 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 (data.length == 1) { - data = MedtronicUtil.createByteArray(data[0], (byte) 0, (byte) 0); - } - - if (data.length == MAX_RAW_DATA_SIZE) { - mRawData = data; - } else { - int len = Math.min(MAX_RAW_DATA_SIZE, data.length); - mRawData = new byte[MAX_RAW_DATA_SIZE]; - System.arraycopy(data, 0, mRawData, 0, len); - } - - return true; - } - - - public boolean setRawDataFromHistory(byte[] data) { - if (data == null) { - aapsLogger.error(LTag.PUMPCOMM, "setRawData: buffer is null!"); - return false; - } - - mRawData = new byte[MAX_RAW_DATA_SIZE]; - int item = 0; - - for (int i = 0; i < data.length - 2; i += 3) { - - if ((data[i] == 0) && (data[i + 1] == 0) && (data[i + 2] == 0)) { - mRawData[i] = 0; - mRawData[i + 1] = 0; - mRawData[i + 2] = 0; - } - - mRawData[i] = data[i + 1]; - mRawData[i + 1] = data[i + 2]; - mRawData[i + 2] = data[i]; - } - - return true; - } - - - public void dumpBasalProfile() { - aapsLogger.debug(LTag.PUMPCOMM, "Basal Profile entries:"); - List entries = getEntries(); - for (int i = 0; i < entries.size(); i++) { - BasalProfileEntry entry = entries.get(i); - String startString = entry.startTime.toString("HH:mm"); - // this doesn't work - aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Entry %d, rate=%.3f (%s), start=%s (0x%02X)", i + 1, entry.rate, - ByteUtil.getHex(entry.rate_raw), startString, entry.startTime_raw)); - - } - } - - - public String getBasalProfileAsString() { - StringBuffer sb = new StringBuffer("Basal Profile entries:\n"); - List entries = getEntries(); - for (int i = 0; i < entries.size(); i++) { - BasalProfileEntry entry = entries.get(i); - String startString = entry.startTime.toString("HH:mm"); - - sb.append(String.format(Locale.ENGLISH, "Entry %d, rate=%.3f, start=%s\n", i + 1, entry.rate, startString)); - } - - return sb.toString(); - } - - public String basalProfileToStringError() { - return "Basal Profile [rawData=" + ByteUtil.shortHexString(this.getRawData()) + "]"; - } - - - public String basalProfileToString() { - StringBuffer sb = new StringBuffer("Basal Profile ["); - List entries = getEntries(); - for (int i = 0; i < entries.size(); i++) { - BasalProfileEntry entry = entries.get(i); - String startString = entry.startTime.toString("HH:mm"); - - sb.append(String.format(Locale.ENGLISH, "%s=%.3f, ", startString, entry.rate)); - } - - sb.append("]"); - - return sb.toString(); - } - - - // TODO: this function must be expanded to include changes in which profile is in use. - // and changes to the profiles themselves. - public BasalProfileEntry getEntryForTime(Instant when) { - BasalProfileEntry rval = new BasalProfileEntry(); - List entries = getEntries(); - if (entries.size() == 0) { - aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "getEntryForTime(%s): table is empty", - when.toDateTime().toLocalTime().toString("HH:mm"))); - return rval; - } - // Log.w(TAG,"Assuming first entry"); - rval = entries.get(0); - if (entries.size() == 1) { - aapsLogger.debug(LTag.PUMPCOMM, "getEntryForTime: Only one entry in profile"); - return rval; - } - - int localMillis = when.toDateTime().toLocalTime().getMillisOfDay(); - boolean done = false; - int i = 1; - while (!done) { - BasalProfileEntry entry = entries.get(i); - if (DEBUG_BASALPROFILE) { - aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Comparing 'now'=%s to entry 'start time'=%s", when.toDateTime().toLocalTime() - .toString("HH:mm"), entry.startTime.toString("HH:mm"))); - } - if (localMillis >= entry.startTime.getMillisOfDay()) { - rval = entry; - if (DEBUG_BASALPROFILE) - aapsLogger.debug(LTag.PUMPCOMM, "Accepted Entry"); - } else { - // entry at i has later start time, keep older entry - if (DEBUG_BASALPROFILE) - aapsLogger.debug(LTag.PUMPCOMM, "Rejected Entry"); - done = true; - } - i++; - if (i >= entries.size()) { - done = true; - } - } - if (DEBUG_BASALPROFILE) { - aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "getEntryForTime(%s): Returning entry: rate=%.3f (%s), start=%s (%d)", when - .toDateTime().toLocalTime().toString("HH:mm"), rval.rate, ByteUtil.getHex(rval.rate_raw), - rval.startTime.toString("HH:mm"), rval.startTime_raw)); - } - return rval; - } - - - public List getEntries() { - List entries = new ArrayList<>(); - - if (mRawData == null || mRawData[2] == 0x3f) { - aapsLogger.warn(LTag.PUMPCOMM, "Raw Data is empty."); - return entries; // an empty list - } - int r, st; - - for (int i = 0; i < mRawData.length - 2; i += 3) { - - if ((mRawData[i] == 0) && (mRawData[i + 1] == 0) && (mRawData[i + 2] == 0)) - break; - - if ((mRawData[i] == 0) && (mRawData[i + 1] == 0) && (mRawData[i + 2] == 0x3f)) - break; - - r = MedtronicUtil.makeUnsignedShort(mRawData[i + 1], mRawData[i]); // readUnsignedByte(mRawData[i]); - st = readUnsignedByte(mRawData[i + 2]); - - try { - entries.add(new BasalProfileEntry(aapsLogger, r, st)); - } catch (Exception ex) { - aapsLogger.error(LTag.PUMPCOMM, "Error decoding basal profile from bytes: " + ByteUtil.shortHexString(mRawData)); - throw ex; - } - - } - - return entries; - } - - - /** - * This is used to prepare new profile - * - * @param entry - */ - public void addEntry(BasalProfileEntry entry) { - if (listEntries == null) - listEntries = new ArrayList<>(); - - listEntries.add(entry); - } - - - public void generateRawDataFromEntries() { - - List outData = new ArrayList<>(); - - for (BasalProfileEntry profileEntry : listEntries) { - - byte[] strokes = MedtronicUtil.getBasalStrokes(profileEntry.rate, true); - - outData.add(profileEntry.rate_raw[0]); - outData.add(profileEntry.rate_raw[1]); - outData.add(profileEntry.startTime_raw); - } - - this.setRawData(MedtronicUtil.createByteArray(outData)); - - // return this.mRawData; - } - - - public Double[] getProfilesByHour(PumpType pumpType) { - - List entries = null; - - try { - entries = getEntries(); - } catch (Exception ex) { - aapsLogger.error(LTag.PUMPCOMM, "============================================================================="); - aapsLogger.error(LTag.PUMPCOMM, " Error generating entries. Ex.: " + ex, ex); - aapsLogger.error(LTag.PUMPCOMM, " rawBasalValues: " + ByteUtil.shortHexString(this.getRawData())); - aapsLogger.error(LTag.PUMPCOMM, "============================================================================="); - - //FabricUtil.createEvent("MedtronicBasalProfileGetByHourError", null); - } - - if (entries == null || entries.size() == 0) { - Double[] basalByHour = new Double[24]; - - for (int i = 0; i < 24; i++) { - basalByHour[i] = 0.0d; - } - - return basalByHour; - } - - Double[] basalByHour = new Double[24]; - - for (int i = 0; i < entries.size(); i++) { - BasalProfileEntry current = entries.get(i); - - int currentTime = (current.startTime_raw % 2 == 0) ? current.startTime_raw : current.startTime_raw - 1; - - currentTime = (currentTime * 30) / 60; - - int lastHour; - if ((i + 1) == entries.size()) { - lastHour = 24; - } else { - BasalProfileEntry basalProfileEntry = entries.get(i + 1); - - int rawTime = (basalProfileEntry.startTime_raw % 2 == 0) ? basalProfileEntry.startTime_raw - : basalProfileEntry.startTime_raw - 1; - - lastHour = (rawTime * 30) / 60; - } - - // System.out.println("Current time: " + currentTime + " Next Time: " + lastHour); - - for (int j = currentTime; j < lastHour; j++) { - if (pumpType == null) - basalByHour[j] = current.rate; - else - basalByHour[j] = pumpType.determineCorrectBasalSize(current.rate); - } - } - - return basalByHour; - } - - - public static String getProfilesByHourToString(Double[] data) { - - StringBuilder stringBuilder = new StringBuilder(); - - for (Double value : data) { - stringBuilder.append(String.format("%.3f", value)); - stringBuilder.append(" "); - } - - return stringBuilder.toString(); - - } - - - public byte[] getRawData() { - return this.mRawData; - } - - - @NonNull public String toString() { - return basalProfileToString(); - } - - - public boolean verify(PumpType pumpType) { - - try { - getEntries(); - } catch (Exception ex) { - return false; - } - - Double[] profilesByHour = getProfilesByHour(pumpType); - - for (Double aDouble : profilesByHour) { - if (aDouble > 35.0d) - return false; - } - - return true; - } -} 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 new file mode 100644 index 0000000000..3777c30559 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BasalProfile.kt @@ -0,0 +1,315 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.data.dto + +import com.google.gson.annotations.Expose +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.ByteUtil +import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil +import org.joda.time.Instant +import java.util.* + +/** + * Created by geoff on 6/1/15. + * + * + * There are three basal profiles stored on the pump. (722 only?) They are all parsed the same, the user just has 3 to + * choose from: Standard, A, and B + * + * + * The byte array is 48 times three byte entries long, plus a zero? If the profile is completely empty, it should have + * one entry: [0,0,0x3F]. The first entry of [0,0,0] marks the end of the used entries. + * + * + * Each entry is assumed to span from the specified start time to the start time of the next entry, or to midnight if + * there are no more entries. + * + * + * Individual entries are of the form [r,z,m] where r is the rate (in 0.025 U increments) z is zero (?) m is the start + * time-of-day for the basal rate period (in 30 minute increments) + */ +class BasalProfile { + + private val aapsLogger: AAPSLogger + + @Expose var rawData : ByteArray? = null // store as byte array to make transport (via parcel) easier + private set + + private var listEntries: MutableList? = null + + constructor(aapsLogger: AAPSLogger) { + this.aapsLogger = aapsLogger + init() + } + + constructor(aapsLogger: AAPSLogger, data: ByteArray) { + this.aapsLogger = aapsLogger + setRawData(data) + } + + fun init() { + rawData = ByteArray(MAX_RAW_DATA_SIZE) + rawData!![0] = 0 + rawData!![1] = 0 + rawData!![2] = 0x3f + } + + private fun setRawData(data: ByteArray): Boolean { + var data: ByteArray? = data + if (data == 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 (data.size == 1) { + data = MedtronicUtil.createByteArray(data[0], 0.toByte(), 0.toByte()) + } + if (data!!.size == MAX_RAW_DATA_SIZE) { + rawData = data + } else { + val len = Math.min(MAX_RAW_DATA_SIZE, data.size) + rawData = ByteArray(MAX_RAW_DATA_SIZE) + System.arraycopy(data, 0, rawData, 0, len) + } + return true + } + + fun setRawDataFromHistory(data: ByteArray?): Boolean { + if (data == null) { + aapsLogger.error(LTag.PUMPCOMM, "setRawData: buffer is null!") + return false + } + rawData = ByteArray(MAX_RAW_DATA_SIZE) + val item = 0 + var i = 0 + while (i < data.size - 2) { + if (data[i] == 0.toByte() && data[i + 1] == 0.toByte() && data[i + 2] == 0.toByte()) { + rawData!![i] = 0 + rawData!![i + 1] = 0 + rawData!![i + 2] = 0 + } + rawData!![i] = data[i + 1] + rawData!![i + 1] = data[i + 2] + rawData!![i + 2] = data[i] + i += 3 + } + return true + } + + fun dumpBasalProfile() { + aapsLogger.debug(LTag.PUMPCOMM, "Basal Profile entries:") + val entries = entries + for (i in entries.indices) { + val entry = entries[i] + val startString = entry.startTime!!.toString("HH:mm") + // this doesn't work + aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Entry %d, rate=%.3f (%s), start=%s (0x%02X)", i + 1, entry.rate, + ByteUtil.getHex(entry.rate_raw), startString, entry.startTime_raw)) + } + } + + val basalProfileAsString: String + get() { + val sb = StringBuffer("Basal Profile entries:\n") + val entries = entries + for (i in entries.indices) { + val entry = entries[i] + val startString = entry.startTime!!.toString("HH:mm") + sb.append(String.format(Locale.ENGLISH, "Entry %d, rate=%.3f, start=%s\n", i + 1, entry.rate, startString)) + } + return sb.toString() + } + + fun basalProfileToStringError(): String { + return "Basal Profile [rawData=" + ByteUtil.shortHexString(rawData) + "]" + } + + fun basalProfileToString(): String { + val sb = StringBuffer("Basal Profile [") + val entries = entries + for (i in entries.indices) { + val entry = entries[i] + val startString = entry.startTime!!.toString("HH:mm") + sb.append(String.format(Locale.ENGLISH, "%s=%.3f, ", startString, entry.rate)) + } + sb.append("]") + return sb.toString() + } + + // TODO: this function must be expanded to include changes in which profile is in use. + // and changes to the profiles themselves. + fun getEntryForTime(`when`: Instant): BasalProfileEntry { + var rval = BasalProfileEntry() + val entries = entries + if (entries.size == 0) { + aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "getEntryForTime(%s): table is empty", + `when`.toDateTime().toLocalTime().toString("HH:mm"))) + return rval + } + // Log.w(TAG,"Assuming first entry"); + rval = entries[0] + if (entries.size == 1) { + aapsLogger.debug(LTag.PUMPCOMM, "getEntryForTime: Only one entry in profile") + return rval + } + val localMillis = `when`.toDateTime().toLocalTime().millisOfDay + var done = false + var i = 1 + while (!done) { + val entry = entries[i] + if (DEBUG_BASALPROFILE) { + aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Comparing 'now'=%s to entry 'start time'=%s", `when`.toDateTime().toLocalTime() + .toString("HH:mm"), entry.startTime!!.toString("HH:mm"))) + } + if (localMillis >= entry.startTime!!.millisOfDay) { + rval = entry + if (DEBUG_BASALPROFILE) aapsLogger.debug(LTag.PUMPCOMM, "Accepted Entry") + } else { + // entry at i has later start time, keep older entry + if (DEBUG_BASALPROFILE) aapsLogger.debug(LTag.PUMPCOMM, "Rejected Entry") + done = true + } + i++ + if (i >= entries.size) { + done = true + } + } + if (DEBUG_BASALPROFILE) { + aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "getEntryForTime(%s): Returning entry: rate=%.3f (%s), start=%s (%d)", `when` + .toDateTime().toLocalTime().toString("HH:mm"), rval.rate, ByteUtil.getHex(rval.rate_raw), + rval.startTime!!.toString("HH:mm"), rval.startTime_raw)) + } + return rval + }// readUnsignedByte(mRawData[i]); + + // an empty list + val entries: List + get() { + val entries: MutableList = ArrayList() + if (rawData == null || rawData!![2] == 0x3f.toByte()) { + aapsLogger.warn(LTag.PUMPCOMM, "Raw Data is empty.") + return entries // an empty list + } + var r: Int + var st: Int + var i = 0 + while (i < rawData!!.size - 2) { + if (rawData!![i] == 0.toByte() && rawData!![i + 1] == 0.toByte() && rawData!![i + 2] == 0.toByte()) break + if (rawData!![i] == 0.toByte() && rawData!![i + 1] == 0.toByte() && rawData!![i + 2] == 0x3f.toByte()) break + r = MedtronicUtil.makeUnsignedShort(rawData!![i + 1].toInt(), rawData!![i].toInt()) // readUnsignedByte(mRawData[i]); + st = readUnsignedByte(rawData!![i + 2]) + try { + entries.add(BasalProfileEntry(aapsLogger, r, st)) + } catch (ex: Exception) { + aapsLogger.error(LTag.PUMPCOMM, "Error decoding basal profile from bytes: " + ByteUtil.shortHexString(rawData)) + throw ex + } + i += 3 + } + return entries + } + + /** + * This is used to prepare new profile + * + * @param entry + */ + fun addEntry(entry: BasalProfileEntry) { + if (listEntries == null) listEntries = ArrayList() + listEntries!!.add(entry) + } + + fun generateRawDataFromEntries() { + val outData: MutableList = ArrayList() + for (profileEntry in listEntries!!) { + val strokes = MedtronicUtil.getBasalStrokes(profileEntry.rate, true) + outData.add(profileEntry.rate_raw[0]) + outData.add(profileEntry.rate_raw[1]) + outData.add(profileEntry.startTime_raw) + } + setRawData(MedtronicUtil.createByteArray(outData)) + + // return this.mRawData; + } + + fun getProfilesByHour(pumpType: PumpType?): Array { + var entries: List? = null + try { + entries = entries + } catch (ex: Exception) { + aapsLogger.error(LTag.PUMPCOMM, "=============================================================================") + 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); + } + if (entries == null || entries.size == 0) { + val basalByHour = arrayOfNulls(24) + for (i in 0..23) { + basalByHour[i] = 0.0 + } + return basalByHour + } + val basalByHour = arrayOfNulls(24) + for (i in entries.indices) { + val current = entries[i] + var currentTime = if (current.startTime_raw % 2 == 0) current.startTime_raw.toInt() else current.startTime_raw - 1 + currentTime = currentTime * 30 / 60 + var lastHour: Int + lastHour = if (i + 1 == entries.size) { + 24 + } else { + val basalProfileEntry = entries[i + 1] + val rawTime = if (basalProfileEntry.startTime_raw % 2 == 0) basalProfileEntry.startTime_raw.toInt() else basalProfileEntry.startTime_raw - 1 + rawTime * 30 / 60 + } + + // System.out.println("Current time: " + currentTime + " Next Time: " + lastHour); + for (j in currentTime until lastHour) { + if (pumpType == null) basalByHour[j] = current.rate else basalByHour[j] = pumpType.determineCorrectBasalSize(current.rate) + } + } + return basalByHour + } + + override fun toString(): String { + return basalProfileToString() + } + + fun verify(pumpType: PumpType?): Boolean { + try { + entries + } catch (ex: Exception) { + return false + } + val profilesByHour = getProfilesByHour(pumpType) + for (aDouble in profilesByHour) { + if (aDouble!! > 35.0) return false + } + return true + } + + + + companion object { + 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() + } + + @JvmStatic + fun getProfilesByHourToString(data: Array): String { + val stringBuilder = StringBuilder() + for (value in data) { + stringBuilder.append(String.format("%.3f", value)) + stringBuilder.append(" ") + } + return stringBuilder.toString() + } + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BasalProfileEntry.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BasalProfileEntry.java deleted file mode 100644 index da2a7181c0..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BasalProfileEntry.java +++ /dev/null @@ -1,81 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.data.dto; - -import org.joda.time.LocalTime; - -import java.util.Locale; - -import info.nightscout.androidaps.logging.AAPSLogger; -import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil; - -/** - * Created by geoff on 6/1/15. - * This is a helper class for BasalProfile, only used for interpreting the contents of BasalProfile - * - fixed rate is not one bit but two - */ -public class BasalProfileEntry { - - byte[] rate_raw; - public double rate; - byte startTime_raw; - public LocalTime startTime; // Just a "time of day" - - public BasalProfileEntry() { - rate = -9.999E6; - rate_raw = MedtronicUtil.getByteArrayFromUnsignedShort(0xFF, true); - startTime = new LocalTime(0); - startTime_raw = (byte) 0xFF; - } - - public BasalProfileEntry(double rate, int hour, int minutes) { - byte[] data = MedtronicUtil.getBasalStrokes(rate, true); - - rate_raw = new byte[2]; - rate_raw[0] = data[1]; - rate_raw[1] = data[0]; - - int interval = hour * 2; - - if (minutes == 30) { - interval++; - } - - startTime_raw = (byte) interval; - startTime = new LocalTime(hour, minutes == 30 ? 30 : 0); - } - - BasalProfileEntry(AAPSLogger aapsLogger, int rateStrokes, int startTimeInterval) { - // rateByte is insulin delivery rate, U/hr, in 0.025 U increments - // startTimeByte is time-of-day, in 30 minute increments - rate_raw = MedtronicUtil.getByteArrayFromUnsignedShort(rateStrokes, true); - rate = rateStrokes * 0.025; - startTime_raw = (byte) startTimeInterval; - - try { - startTime = new LocalTime(startTimeInterval / 2, (startTimeInterval % 2) * 30); - } catch (Exception ex) { - aapsLogger.error(LTag.PUMPCOMM, - String.format(Locale.ENGLISH, "Error creating BasalProfileEntry: startTimeInterval=%d, startTime_raw=%d, hours=%d, rateStrokes=%d", - startTimeInterval, startTime_raw, startTimeInterval / 2, rateStrokes)); - throw ex; - } - - } - - BasalProfileEntry(byte rateByte, int startTimeByte) { - // rateByte is insulin delivery rate, U/hr, in 0.025 U increments - // startTimeByte is time-of-day, in 30 minute increments - rate_raw = MedtronicUtil.getByteArrayFromUnsignedShort(rateByte, true); - rate = rateByte * 0.025; - startTime_raw = (byte) startTimeByte; - startTime = new LocalTime(startTimeByte / 2, (startTimeByte % 2) * 30); - } - - public void setStartTime(LocalTime localTime) { - this.startTime = localTime; - } - - public void setRate(double rate) { - this.rate = rate; - } -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BasalProfileEntry.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BasalProfileEntry.kt new file mode 100644 index 0000000000..6ffbefcf2d --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BasalProfileEntry.kt @@ -0,0 +1,74 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.data.dto + +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil +import org.joda.time.LocalTime +import java.util.* + +/** + * Created by geoff on 6/1/15. + * This is a helper class for BasalProfile, only used for interpreting the contents of BasalProfile + * - fixed rate is not one bit but two + */ +class BasalProfileEntry { + + var rate_raw: ByteArray + var rate = 0.0 + set(value) { + field = value + } + + var startTime_raw: Byte + var startTime : LocalTime? = null // Just a "time of day" + set(value) { + field = value + } + + + constructor() { + rate = -9.999E6 + rate_raw = MedtronicUtil.getByteArrayFromUnsignedShort(0xFF, true) + startTime = LocalTime(0) + startTime_raw = 0xFF.toByte() + } + + constructor(rate: Double, hour: Int, minutes: Int) { + val data = MedtronicUtil.getBasalStrokes(rate, true) + rate_raw = ByteArray(2) + rate_raw[0] = data[1] + rate_raw[1] = data[0] + var interval = hour * 2 + if (minutes == 30) { + interval++ + } + startTime_raw = interval.toByte() + startTime = LocalTime(hour, if (minutes == 30) 30 else 0) + } + + internal constructor(aapsLogger: AAPSLogger, rateStrokes: Int, startTimeInterval: Int) { + // rateByte is insulin delivery rate, U/hr, in 0.025 U increments + // startTimeByte is time-of-day, in 30 minute increments + rate_raw = MedtronicUtil.getByteArrayFromUnsignedShort(rateStrokes, true) + rate = rateStrokes * 0.025 + startTime_raw = startTimeInterval.toByte() + startTime = try { + LocalTime(startTimeInterval / 2, startTimeInterval % 2 * 30) + } catch (ex: Exception) { + aapsLogger.error(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Error creating BasalProfileEntry: startTimeInterval=%d, startTime_raw=%d, hours=%d, rateStrokes=%d", + startTimeInterval, startTime_raw, startTimeInterval / 2, rateStrokes)) + throw ex + } + } + + internal constructor(rateByte: Byte, startTimeByte: Int) { + // rateByte is insulin delivery rate, U/hr, in 0.025 U increments + // startTimeByte is time-of-day, in 30 minute increments + rate_raw = MedtronicUtil.getByteArrayFromUnsignedShort(rateByte.toInt(), true) + rate = rateByte * 0.025 + startTime_raw = startTimeByte.toByte() + startTime = LocalTime(startTimeByte / 2, startTimeByte % 2 * 30) + } + + +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicCommandType.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicCommandType.java index 0c14ac42f8..dfa4e83867 100755 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicCommandType.java +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicCommandType.java @@ -215,32 +215,6 @@ public enum MedtronicCommandType implements Serializable // , MinimedCommandType } - // MedtronicCommandType(int code, String description, MedtronicDeviceType devices, -// MinimedCommandParameterType parameterType) { -// this(code, description, devices, parameterType, 64, 1, 0, 0, 0, 0); -// } -// -// -// MedtronicCommandType(int code, String description, MedtronicDeviceType devices, -// MinimedCommandParameterType parameterType, int expectedLength) { -// this(code, description, devices, parameterType, 64, 1, 0, 0, 0, expectedLength); -// } -// -// -// MedtronicCommandType(int code, String description, MedtronicDeviceType devices, -// MinimedCommandParameterType parameterType, int recordLength, int maxRecords, int commandType) { -// this(code, description, devices, parameterType, recordLength, maxRecords, 0, 0, commandType, 0); -// } -// -// -// MedtronicCommandType(int code, String description, MedtronicDeviceType devices, -// MinimedCommandParameterType parameterType, int recordLength, int maxRecords, int commandType, -// int expectedLength) { -// this(code, description, devices, parameterType, recordLength, maxRecords, 0, 0, commandType, -// expectedLength); -// } -// -// MedtronicCommandType(int code, String description, MedtronicDeviceType devices, MinimedCommandParameterType parameterType, byte[] cmd_params) { this(code, description, devices, parameterType, 0, 1, 0, 0, 11, 0); @@ -256,14 +230,6 @@ public enum MedtronicCommandType implements Serializable // , MinimedCommandType this(code, description, devices, parameterType, 64, 1, 0, null); } - - // NEW - MedtronicCommandType(int code, String description, MedtronicDeviceType devices, - MinimedCommandParameterType parameterType, int recordLength, int maxRecords, int commandType) { - this(code, description, devices, parameterType, recordLength, maxRecords, 0, null); - } - - // NEW MedtronicCommandType(int code, String description, MedtronicDeviceType devices, // MinimedCommandParameterType parameterType, int expectedLength) { @@ -390,22 +356,6 @@ public enum MedtronicCommandType implements Serializable // , MinimedCommandType } - public boolean canReturnData() { - System.out.println("CanReturnData: ]id=" + this.name() + "max=" + this.maxRecords + "recLen=" + recordLength); - return (this.maxRecords * this.recordLength) > 0; - } - - - public int getRecordLength() { - return recordLength; - } - - - public int getMaxRecords() { - return maxRecords; - } - - public byte getCommandCode() { return commandCode; } @@ -420,16 +370,6 @@ public enum MedtronicCommandType implements Serializable // , MinimedCommandType } - public byte[] getCommandParameters() { - return commandParameters; - } - - - public boolean hasCommandParameters() { - return (getCommandParametersCount() > 0); - } - - public String toString() { return name(); } From a202178426feadc5fa038bcd6a544453008338de Mon Sep 17 00:00:00 2001 From: Andy Rozman Date: Sun, 18 Apr 2021 15:30:05 +0100 Subject: [PATCH 006/145] - kotlin changes to most of the classes, most of it is tested --- .../general/actions/defs/CustomActionType.kt | 2 +- .../pump/common/PumpPluginAbstract.java | 29 +- .../pump/common/PumpPluginAbstract.java.orig | 535 ------------------ .../plugins/pump/common/data/PumpStatus.java | 71 --- .../plugins/pump/common/data/PumpStatus.kt | 52 ++ .../pump/medtronic/MedtronicFragment.kt | 33 +- .../pump/medtronic/MedtronicPumpPlugin.java | 103 ++-- .../comm/MedtronicCommunicationManager.java | 22 +- .../pump/medtronic/comm/MedtronicConverter.kt | 24 +- .../comm/history/MedtronicHistoryDecoder.kt | 12 +- .../comm/history/MedtronicHistoryEntry.kt | 4 +- .../medtronic/comm/history/RawHistoryPage.kt | 2 +- .../pump/MedtronicPumpHistoryDecoder.kt | 40 +- .../comm/history/pump/PumpHistoryEntry.kt | 10 +- .../comm/history/pump/PumpHistoryEntryType.kt | 12 +- .../comm/history/pump/PumpHistoryResult.kt | 51 +- .../medtronic/comm/message/PumpMessage.kt | 6 +- .../medtronic/comm/ui/MedtronicUIComm.java | 58 -- .../pump/medtronic/comm/ui/MedtronicUIComm.kt | 44 ++ .../comm/ui/MedtronicUIPostprocessor.java | 252 --------- .../comm/ui/MedtronicUIPostprocessor.kt | 188 ++++++ .../medtronic/comm/ui/MedtronicUITask.java | 234 -------- .../pump/medtronic/comm/ui/MedtronicUITask.kt | 178 ++++++ .../medtronic/data/MedtronicHistoryData.java | 11 +- .../pump/medtronic/data/dto/BasalProfile.kt | 39 +- .../medtronic/data/dto/BatteryStatusDTO.java | 60 -- .../medtronic/data/dto/BatteryStatusDTO.kt | 46 ++ .../pump/medtronic/data/dto/BolusDTO.java | 160 ------ .../pump/medtronic/data/dto/BolusDTO.kt | 90 +++ .../medtronic/data/dto/BolusWizardDTO.java | 50 -- .../pump/medtronic/data/dto/BolusWizardDTO.kt | 44 ++ .../pump/medtronic/data/dto/ClockDTO.java | 16 - .../pump/medtronic/data/dto/ClockDTO.kt | 12 + .../medtronic/data/dto/DailyTotalsDTO.java | 255 --------- .../pump/medtronic/data/dto/DailyTotalsDTO.kt | 202 +++++++ .../medtronic/data/dto/PumpSettingDTO.java | 29 - .../pump/medtronic/data/dto/PumpSettingDTO.kt | 14 + .../data/dto/PumpTimeStampedRecord.java | 28 - .../data/dto/PumpTimeStampedRecord.kt | 16 + .../data/dto/RLHistoryItemMedtronic.java | 28 - .../data/dto/RLHistoryItemMedtronic.kt | 18 + .../medtronic/data/dto/TempBasalPair.java | 145 ----- .../pump/medtronic/data/dto/TempBasalPair.kt | 110 ++++ .../data/dto/TempBasalProcessDTO.java | 31 - .../medtronic/data/dto/TempBasalProcessDTO.kt | 21 + .../medtronic/defs/BasalProfileStatus.java | 14 - .../pump/medtronic/defs/BasalProfileStatus.kt | 12 + .../pump/medtronic/defs/BatteryType.java | 34 -- .../pump/medtronic/defs/BatteryType.kt | 18 + .../defs/CommandValueDefinitionMDTType.java | 33 -- .../medtronic/defs/MedtronicCommandType.java | 393 ------------- .../medtronic/defs/MedtronicCommandType.kt | 285 ++++++++++ .../defs/MedtronicCustomActionType.java | 20 - .../defs/MedtronicCustomActionType.kt | 19 + .../medtronic/defs/MedtronicDeviceType.java | 140 ----- .../medtronic/defs/MedtronicDeviceType.kt | 100 ++++ .../defs/MedtronicNotificationType.java | 65 --- .../defs/MedtronicNotificationType.kt | 23 + .../defs/MedtronicStatusRefreshType.java | 37 -- .../defs/MedtronicStatusRefreshType.kt | 23 + .../defs/MedtronicUIResponseType.java | 13 - .../medtronic/defs/MedtronicUIResponseType.kt | 9 + .../pump/medtronic/defs/PumpBolusType.java | 129 ----- .../pump/medtronic/defs/PumpBolusType.kt | 54 ++ .../defs/PumpConfigurationGroup.java | 58 -- .../medtronic/defs/PumpConfigurationGroup.kt | 20 + .../medtronic/driver/MedtronicPumpStatus.java | 180 ------ .../medtronic/driver/MedtronicPumpStatus.kt | 139 +++++ .../service/RileyLinkMedtronicService.java | 388 ------------- .../service/RileyLinkMedtronicService.kt | 289 ++++++++++ .../pump/medtronic/util/MedtronicConst.java | 40 -- .../pump/medtronic/util/MedtronicConst.kt | 37 ++ .../pump/medtronic/util/MedtronicUtil.java | 456 --------------- .../pump/medtronic/util/MedtronicUtil.kt | 314 ++++++++++ medtronic/src/main/res/values/strings.xml | 6 +- .../plugins/pump/common/utils/ByteUtil.java | 19 +- 76 files changed, 2581 insertions(+), 4173 deletions(-) delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java.orig delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpStatus.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpStatus.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUIComm.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUIComm.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUIPostprocessor.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUIPostprocessor.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUITask.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUITask.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BatteryStatusDTO.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BatteryStatusDTO.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BolusDTO.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BolusDTO.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BolusWizardDTO.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BolusWizardDTO.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/ClockDTO.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/ClockDTO.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/DailyTotalsDTO.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/DailyTotalsDTO.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/PumpSettingDTO.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/PumpSettingDTO.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/PumpTimeStampedRecord.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/PumpTimeStampedRecord.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/RLHistoryItemMedtronic.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/RLHistoryItemMedtronic.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/TempBasalPair.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/TempBasalPair.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/TempBasalProcessDTO.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/TempBasalProcessDTO.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/BasalProfileStatus.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/BasalProfileStatus.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/BatteryType.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/BatteryType.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/CommandValueDefinitionMDTType.java delete mode 100755 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicCommandType.java create mode 100755 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicCommandType.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicCustomActionType.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicCustomActionType.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicDeviceType.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicDeviceType.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicNotificationType.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicNotificationType.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicStatusRefreshType.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicStatusRefreshType.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicUIResponseType.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicUIResponseType.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/PumpBolusType.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/PumpBolusType.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/PumpConfigurationGroup.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/PumpConfigurationGroup.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/driver/MedtronicPumpStatus.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/driver/MedtronicPumpStatus.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/service/RileyLinkMedtronicService.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/service/RileyLinkMedtronicService.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/util/MedtronicConst.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/util/MedtronicConst.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/util/MedtronicUtil.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/util/MedtronicUtil.kt diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/general/actions/defs/CustomActionType.kt b/core/src/main/java/info/nightscout/androidaps/plugins/general/actions/defs/CustomActionType.kt index fb472d5592..5ffbb25b6b 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/general/actions/defs/CustomActionType.kt +++ b/core/src/main/java/info/nightscout/androidaps/plugins/general/actions/defs/CustomActionType.kt @@ -1,5 +1,5 @@ package info.nightscout.androidaps.plugins.general.actions.defs interface CustomActionType { - val key: String? + fun getKey(): String } \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java index a36e76cf57..ca9100a086 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java @@ -244,7 +244,7 @@ public abstract class PumpPluginAbstract extends PumpPluginBase implements Pump, public long lastDataTime() { aapsLogger.debug(LTag.PUMP, "lastDataTime [PumpPluginAbstract]."); - return getPumpStatusData().lastConnection; + return getPumpStatusData().getLastConnection(); } @@ -308,7 +308,8 @@ public abstract class PumpPluginAbstract extends PumpPluginBase implements Pump, // Pump capabilities - @NonNull public PumpDescription getPumpDescription() { + + public PumpDescription getPumpDescription() { return pumpDescription; } @@ -331,7 +332,7 @@ public abstract class PumpPluginAbstract extends PumpPluginBase implements Pump, @NonNull @Override public JSONObject getJSONStatus(@NonNull Profile profile, @NonNull String profileName, @NonNull String version) { - if ((getPumpStatusData().lastConnection + 60 * 60 * 1000L) < System.currentTimeMillis()) { + if ((getPumpStatusData().getLastConnection() + 60 * 60 * 1000L) < System.currentTimeMillis()) { return new JSONObject(); } @@ -341,8 +342,8 @@ public abstract class PumpPluginAbstract extends PumpPluginBase implements Pump, JSONObject status = new JSONObject(); JSONObject extended = new JSONObject(); try { - battery.put("percent", getPumpStatusData().batteryRemaining); - status.put("status", getPumpStatusData().pumpStatusType != null ? getPumpStatusData().pumpStatusType.getStatus() : "normal"); + battery.put("percent", getPumpStatusData().getBatteryRemaining()); + status.put("status", getPumpStatusData().getPumpStatusType() != null ? getPumpStatusData().getPumpStatusType().getStatus() : "normal"); extended.put("Version", version); try { extended.put("ActiveProfile", profileName); @@ -368,7 +369,7 @@ public abstract class PumpPluginAbstract extends PumpPluginBase implements Pump, pump.put("battery", battery); pump.put("status", status); pump.put("extended", extended); - pump.put("reservoir", getPumpStatusData().reservoirRemainingUnits); + pump.put("reservoir", getPumpStatusData().getReservoirRemainingUnits()); pump.put("clock", dateUtil.toISOString(dateUtil.now())); } catch (JSONException e) { aapsLogger.error("Unhandled exception", e); @@ -381,14 +382,14 @@ public abstract class PumpPluginAbstract extends PumpPluginBase implements Pump, @NonNull @Override public String shortStatus(boolean veryShort) { String ret = ""; - if (getPumpStatusData().lastConnection != 0) { - long agoMsec = System.currentTimeMillis() - getPumpStatusData().lastConnection; + if (getPumpStatusData().getLastConnection() != 0) { + long agoMsec = System.currentTimeMillis() - getPumpStatusData().getLastConnection(); int agoMin = (int) (agoMsec / 60d / 1000d); ret += "LastConn: " + agoMin + " min ago\n"; } - if (getPumpStatusData().lastBolusTime != null && getPumpStatusData().lastBolusTime.getTime() != 0) { - ret += "LastBolus: " + DecimalFormatter.INSTANCE.to2Decimal(getPumpStatusData().lastBolusAmount) + "U @" + // - android.text.format.DateFormat.format("HH:mm", getPumpStatusData().lastBolusTime) + "\n"; + if (getPumpStatusData().getLastBolusTime() != null && getPumpStatusData().getLastBolusTime().getTime() != 0) { + ret += "LastBolus: " + DecimalFormatter.INSTANCE.to2Decimal(getPumpStatusData().getLastBolusAmount()) + "U @" + // + android.text.format.DateFormat.format("HH:mm", getPumpStatusData().getLastBolusTime()) + "\n"; } PumpSync.PumpState.TemporaryBasal activeTemp = pumpSync.expectedPumpState().getTemporaryBasal(); if (activeTemp != null) { @@ -402,9 +403,9 @@ public abstract class PumpPluginAbstract extends PumpPluginBase implements Pump, // ret += "TDD: " + DecimalFormatter.to0Decimal(pumpStatus.dailyTotalUnits) + " / " // + pumpStatus.maxDailyTotalUnits + " U\n"; // } - ret += "IOB: " + getPumpStatusData().iob + "U\n"; - ret += "Reserv: " + DecimalFormatter.INSTANCE.to0Decimal(getPumpStatusData().reservoirRemainingUnits) + "U\n"; - ret += "Batt: " + getPumpStatusData().batteryRemaining + "\n"; + ret += "IOB: " + getPumpStatusData().getIob() + "U\n"; + ret += "Reserv: " + DecimalFormatter.INSTANCE.to0Decimal(getPumpStatusData().getReservoirRemainingUnits()) + "U\n"; + ret += "Batt: " + getPumpStatusData().getBatteryRemaining() + "\n"; return ret; } diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java.orig b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java.orig deleted file mode 100644 index a0bffe268a..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java.orig +++ /dev/null @@ -1,535 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.common; - -import static info.nightscout.androidaps.extensions.PumpStateExtensionKt.convertedToAbsolute; -import static info.nightscout.androidaps.extensions.PumpStateExtensionKt.getPlannedRemainingMinutes; - -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; - -import androidx.annotation.NonNull; - -import org.json.JSONException; -import org.json.JSONObject; - -<<<<<<< HEAD -import java.util.Date; -import java.util.HashMap; -import java.util.Map; - -======= ->>>>>>> meallink -import dagger.android.HasAndroidInjector; -import info.nightscout.androidaps.core.R; -import info.nightscout.androidaps.data.DetailedBolusInfo; -import info.nightscout.androidaps.data.Profile; -import info.nightscout.androidaps.data.PumpEnactResult; -import info.nightscout.androidaps.events.EventAppExit; -import info.nightscout.androidaps.events.EventCustomActionsChanged; -import info.nightscout.androidaps.extensions.PumpStateExtensionKt; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; -import info.nightscout.androidaps.interfaces.CommandQueueProvider; -import info.nightscout.androidaps.interfaces.ConstraintsInterface; -import info.nightscout.androidaps.interfaces.PluginDescription; -import info.nightscout.androidaps.interfaces.PumpDescription; -import info.nightscout.androidaps.interfaces.PumpInterface; -import info.nightscout.androidaps.interfaces.PumpPluginBase; -import info.nightscout.androidaps.interfaces.PumpSync; -import info.nightscout.androidaps.logging.AAPSLogger; -import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.plugins.bus.RxBusWrapper; -import info.nightscout.androidaps.plugins.common.ManufacturerType; -import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress; -import info.nightscout.androidaps.plugins.pump.common.data.PumpDbEntry; -import info.nightscout.androidaps.plugins.pump.common.data.PumpStatus; -import info.nightscout.androidaps.plugins.pump.common.defs.PumpDriverState; -import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; -import info.nightscout.androidaps.utils.DateUtil; -import info.nightscout.androidaps.utils.DecimalFormatter; -import info.nightscout.androidaps.utils.FabricPrivacy; -import info.nightscout.androidaps.utils.resources.ResourceHelper; -import info.nightscout.androidaps.utils.rx.AapsSchedulers; -import info.nightscout.androidaps.utils.sharedPreferences.SP; -import io.reactivex.disposables.CompositeDisposable; - -/** - * Created by andy on 23.04.18. - */ - -// When using this class, make sure that your first step is to create mConnection (see MedtronicPumpPlugin) - -public abstract class PumpPluginAbstract extends PumpPluginBase implements PumpInterface, ConstraintsInterface { - private final CompositeDisposable disposable = new CompositeDisposable(); - - protected HasAndroidInjector injector; - protected AAPSLogger aapsLogger; - protected RxBusWrapper rxBus; - protected ActivePluginProvider activePlugin; - protected Context context; - protected FabricPrivacy fabricPrivacy; - protected ResourceHelper resourceHelper; - protected CommandQueueProvider commandQueue; - protected SP sp; - protected DateUtil dateUtil; - protected PumpDescription pumpDescription = new PumpDescription(); - protected ServiceConnection serviceConnection; - protected boolean serviceRunning = false; - protected PumpDriverState pumpState = PumpDriverState.NotInitialized; - protected boolean displayConnectionMessages = false; - protected PumpType pumpType; - protected AapsSchedulers aapsSchedulers; - protected PumpSync pumpSync; -<<<<<<< HEAD - -======= ->>>>>>> meallink - - protected PumpPluginAbstract( - PluginDescription pluginDescription, - PumpType pumpType, - HasAndroidInjector injector, - ResourceHelper resourceHelper, - AAPSLogger aapsLogger, - CommandQueueProvider commandQueue, - RxBusWrapper rxBus, - ActivePluginProvider activePlugin, - SP sp, - Context context, - FabricPrivacy fabricPrivacy, - DateUtil dateUtil, - AapsSchedulers aapsSchedulers, - PumpSync pumpSync - ) { - - super(pluginDescription, injector, aapsLogger, resourceHelper, commandQueue); - this.aapsLogger = aapsLogger; - this.rxBus = rxBus; - this.activePlugin = activePlugin; - this.context = context; - this.fabricPrivacy = fabricPrivacy; - this.resourceHelper = resourceHelper; - this.sp = sp; - this.commandQueue = commandQueue; - - pumpDescription.setPumpDescription(pumpType); - this.pumpType = pumpType; - this.dateUtil = dateUtil; - this.aapsSchedulers = aapsSchedulers; - this.pumpSync = pumpSync; - } - - - public abstract void initPumpStatusData(); - - - @Override - protected void onStart() { - super.onStart(); - - initPumpStatusData(); - - Intent intent = new Intent(context, getServiceClass()); - context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); - - serviceRunning = true; - - disposable.add(rxBus - .toObservable(EventAppExit.class) - .observeOn(aapsSchedulers.getIo()) - .subscribe(event -> context.unbindService(serviceConnection), fabricPrivacy::logException) - ); - onStartCustomActions(); - } - - - @Override - protected void onStop() { - aapsLogger.debug(LTag.PUMP, this.deviceID() + " onStop()"); - - context.unbindService(serviceConnection); - - serviceRunning = false; - - disposable.clear(); - super.onStop(); - } - - - /** - * If we need to run any custom actions in onStart (triggering events, etc) - */ - public abstract void onStartCustomActions(); - - /** - * Service class (same one you did serviceConnection for) - * - * @return Class - */ - public abstract Class getServiceClass(); - - public abstract PumpStatus getPumpStatusData(); - - - public boolean isInitialized() { - return pumpState.isInitialized(); - } - - - public boolean isSuspended() { - return pumpState == PumpDriverState.Suspended; - } - - - public boolean isBusy() { - return pumpState == PumpDriverState.Busy; - } - - - public boolean isConnected() { - if (displayConnectionMessages) - aapsLogger.debug(LTag.PUMP, "isConnected [PumpPluginAbstract]."); - return pumpState.isConnected(); - } - - - public boolean isConnecting() { - if (displayConnectionMessages) - aapsLogger.debug(LTag.PUMP, "isConnecting [PumpPluginAbstract]."); - return pumpState == PumpDriverState.Connecting; - } - - - public void connect(@NonNull String reason) { - if (displayConnectionMessages) - aapsLogger.debug(LTag.PUMP, "connect (reason={}) [PumpPluginAbstract] - default (empty) implementation." + reason); - } - - - public void disconnect(@NonNull String reason) { - if (displayConnectionMessages) - aapsLogger.debug(LTag.PUMP, "disconnect (reason={}) [PumpPluginAbstract] - default (empty) implementation." + reason); - } - - - public void stopConnecting() { - if (displayConnectionMessages) - aapsLogger.debug(LTag.PUMP, "stopConnecting [PumpPluginAbstract] - default (empty) implementation."); - } - - - @Override - public boolean isHandshakeInProgress() { - if (displayConnectionMessages) - aapsLogger.debug(LTag.PUMP, "isHandshakeInProgress [PumpPluginAbstract] - default (empty) implementation."); - return false; - } - - - @Override - public void finishHandshaking() { - if (displayConnectionMessages) - aapsLogger.debug(LTag.PUMP, "finishHandshaking [PumpPluginAbstract] - default (empty) implementation."); - } - - // Upload to pump new basal profile - @NonNull public PumpEnactResult setNewBasalProfile(@NonNull Profile profile) { - aapsLogger.debug(LTag.PUMP, "setNewBasalProfile [PumpPluginAbstract] - Not implemented."); - return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); - } - - - public boolean isThisProfileSet(@NonNull Profile profile) { - aapsLogger.debug(LTag.PUMP, "isThisProfileSet [PumpPluginAbstract] - Not implemented."); - return true; - } - - - public long lastDataTime() { - aapsLogger.debug(LTag.PUMP, "lastDataTime [PumpPluginAbstract]."); - return getPumpStatusData().lastConnection; - } - - - public double getBaseBasalRate() { - aapsLogger.debug(LTag.PUMP, "getBaseBasalRate [PumpPluginAbstract] - Not implemented."); - return 0.0d; - } // base basal rate, not temp basal - - - public void stopBolusDelivering() { - aapsLogger.debug(LTag.PUMP, "stopBolusDelivering [PumpPluginAbstract] - Not implemented."); - } - - - @NonNull @Override - public PumpEnactResult setTempBasalAbsolute(double absoluteRate, int durationInMinutes, @NonNull Profile profile, boolean enforceNew, @NonNull PumpSync.TemporaryBasalType tbrType) { - aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute [PumpPluginAbstract] - Not implemented."); - return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); - } - - - @NonNull @Override - public PumpEnactResult setTempBasalPercent(int percent, int durationInMinutes, @NonNull Profile profile, boolean enforceNew, @NonNull PumpSync.TemporaryBasalType tbrType) { - aapsLogger.debug(LTag.PUMP, "setTempBasalPercent [PumpPluginAbstract] - Not implemented."); - return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); - } - - - @NonNull public PumpEnactResult setExtendedBolus(double insulin, int durationInMinutes) { - aapsLogger.debug(LTag.PUMP, "setExtendedBolus [PumpPluginAbstract] - Not implemented."); - return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); - } - - - // some pumps might set a very short temp close to 100% as cancelling a temp can be noisy - // when the cancel request is requested by the user (forced), the pump should always do a real cancel - - @NonNull public PumpEnactResult cancelTempBasal(boolean enforceNew) { - aapsLogger.debug(LTag.PUMP, "cancelTempBasal [PumpPluginAbstract] - Not implemented."); - return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); - } - - - @NonNull public PumpEnactResult cancelExtendedBolus() { - aapsLogger.debug(LTag.PUMP, "cancelExtendedBolus [PumpPluginAbstract] - Not implemented."); - return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); - } - - - // Status to be passed to NS - - // public JSONObject getJSONStatus(Profile profile, String profileName) { - // return pumpDriver.getJSONStatus(profile, profileName); - // } - - public String deviceID() { - aapsLogger.debug(LTag.PUMP, "deviceID [PumpPluginAbstract] - Not implemented."); - return "FakeDevice"; - } - - - // Pump capabilities - - @NonNull public PumpDescription getPumpDescription() { - return pumpDescription; - } - - - // Short info for SMS, Wear etc - - public boolean isFakingTempsByExtendedBoluses() { - aapsLogger.debug(LTag.PUMP, "isFakingTempsByExtendedBoluses [PumpPluginAbstract] - Not implemented."); - return false; - } - - - @NonNull @Override - public PumpEnactResult loadTDDs() { - aapsLogger.debug(LTag.PUMP, "loadTDDs [PumpPluginAbstract] - Not implemented."); - return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); - } - - - @NonNull @Override - public JSONObject getJSONStatus(@NonNull Profile profile, @NonNull String profileName, @NonNull String version) { - - if ((getPumpStatusData().lastConnection + 60 * 60 * 1000L) < System.currentTimeMillis()) { - return new JSONObject(); - } - - long now = System.currentTimeMillis(); - JSONObject pump = new JSONObject(); - JSONObject battery = new JSONObject(); - JSONObject status = new JSONObject(); - JSONObject extended = new JSONObject(); - try { - battery.put("percent", getPumpStatusData().batteryRemaining); - status.put("status", getPumpStatusData().pumpStatusType != null ? getPumpStatusData().pumpStatusType.getStatus() : "normal"); - extended.put("Version", version); - try { - extended.put("ActiveProfile", profileName); - } catch (Exception ignored) { - } - -<<<<<<< HEAD - // TODO fix - TemporaryBasal tb = activePlugin.getActiveTreatments().getTempBasalFromHistory(System.currentTimeMillis()); -======= - PumpSync.PumpState.TemporaryBasal tb = pumpSync.expectedPumpState().getTemporaryBasal(); ->>>>>>> meallink - if (tb != null) { - extended.put("TempBasalAbsoluteRate", convertedToAbsolute(tb, now, profile)); - extended.put("TempBasalStart", dateUtil.dateAndTimeString(tb.getTimestamp())); - extended.put("TempBasalRemaining", getPlannedRemainingMinutes(tb)); - } - -<<<<<<< HEAD - // TODO fix - ExtendedBolus eb = activePlugin.getActiveTreatments().getExtendedBolusFromHistory(System.currentTimeMillis()); -======= - PumpSync.PumpState.ExtendedBolus eb = pumpSync.expectedPumpState().getExtendedBolus(); ->>>>>>> meallink - if (eb != null) { - extended.put("ExtendedBolusAbsoluteRate", eb.getRate()); - extended.put("ExtendedBolusStart", dateUtil.dateAndTimeString(eb.getTimestamp())); - extended.put("ExtendedBolusRemaining", getPlannedRemainingMinutes(eb)); - } - - status.put("timestamp", dateUtil.toISOString(dateUtil.now())); - - pump.put("battery", battery); - pump.put("status", status); - pump.put("extended", extended); - pump.put("reservoir", getPumpStatusData().reservoirRemainingUnits); - pump.put("clock", dateUtil.toISOString(dateUtil.now())); - } catch (JSONException e) { - aapsLogger.error("Unhandled exception", e); - } - return pump; - } - - - // FIXME i18n, null checks: iob, TDD - @NonNull @Override - public String shortStatus(boolean veryShort) { - String ret = ""; - if (getPumpStatusData().lastConnection != 0) { - long agoMsec = System.currentTimeMillis() - getPumpStatusData().lastConnection; - int agoMin = (int) (agoMsec / 60d / 1000d); - ret += "LastConn: " + agoMin + " min ago\n"; - } - if (getPumpStatusData().lastBolusTime != null && getPumpStatusData().lastBolusTime.getTime() != 0) { - ret += "LastBolus: " + DecimalFormatter.INSTANCE.to2Decimal(getPumpStatusData().lastBolusAmount) + "U @" + // - android.text.format.DateFormat.format("HH:mm", getPumpStatusData().lastBolusTime) + "\n"; - } -<<<<<<< HEAD - // TODO fix - TemporaryBasal activeTemp = activePlugin.getActiveTreatments().getRealTempBasalFromHistory(System.currentTimeMillis()); -======= - PumpSync.PumpState.TemporaryBasal activeTemp = pumpSync.expectedPumpState().getTemporaryBasal(); ->>>>>>> meallink - if (activeTemp != null) { - ret += "Temp: " + PumpStateExtensionKt.toStringFull(activeTemp, dateUtil) + "\n"; - } -<<<<<<< HEAD - // TODO fix - ExtendedBolus activeExtendedBolus = activePlugin.getActiveTreatments().getExtendedBolusFromHistory( - System.currentTimeMillis()); -======= - PumpSync.PumpState.ExtendedBolus activeExtendedBolus = pumpSync.expectedPumpState().getExtendedBolus(); ->>>>>>> meallink - if (activeExtendedBolus != null) { - ret += "Extended: " + PumpStateExtensionKt.toStringFull(activeExtendedBolus, dateUtil) + "\n"; - } - // if (!veryShort) { - // ret += "TDD: " + DecimalFormatter.to0Decimal(pumpStatus.dailyTotalUnits) + " / " - // + pumpStatus.maxDailyTotalUnits + " U\n"; - // } - ret += "IOB: " + getPumpStatusData().iob + "U\n"; - ret += "Reserv: " + DecimalFormatter.INSTANCE.to0Decimal(getPumpStatusData().reservoirRemainingUnits) + "U\n"; - ret += "Batt: " + getPumpStatusData().batteryRemaining + "\n"; - return ret; - } - - - @NonNull @Override - public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) { - - try { - if (detailedBolusInfo.insulin == 0 && detailedBolusInfo.carbs == 0) { - // neither carbs nor bolus requested - aapsLogger.error("deliverTreatment: Invalid input"); - return new PumpEnactResult(getInjector()).success(false).enacted(false).bolusDelivered(0d).carbsDelivered(0d) - .comment(R.string.invalidinput); - } else if (detailedBolusInfo.insulin > 0) { - // bolus needed, ask pump to deliver it - return deliverBolus(detailedBolusInfo); - } else { - //if (MedtronicHistoryData.doubleBolusDebug) - // aapsLogger.debug("DoubleBolusDebug: deliverTreatment::(carb only entry)"); - - // TODO fix - // no bolus required, carb only treatment - activePlugin.getActiveTreatments().addToHistoryTreatment(detailedBolusInfo, true); - - EventOverviewBolusProgress bolusingEvent = EventOverviewBolusProgress.INSTANCE; - bolusingEvent.setT(new EventOverviewBolusProgress.Treatment(0, 0, detailedBolusInfo.getBolusType() == DetailedBolusInfo.BolusType.SMB)); - bolusingEvent.setPercent(100); - rxBus.send(bolusingEvent); - - aapsLogger.debug(LTag.PUMP, "deliverTreatment: Carb only treatment."); - - return new PumpEnactResult(getInjector()).success(true).enacted(true).bolusDelivered(0d) - .carbsDelivered(detailedBolusInfo.carbs).comment(R.string.common_resultok); - } - } finally { - triggerUIChange(); - } - - } - - - protected void refreshCustomActionsList() { - rxBus.send(new EventCustomActionsChanged()); - } - - - @NonNull public ManufacturerType manufacturer() { - return pumpType.getManufacturer(); - } - - @NonNull - public PumpType model() { - return pumpType; - } - - - public PumpType getPumpType() { - return pumpType; - } - - - public void setPumpType(PumpType pumpType) { - this.pumpType = pumpType; - this.pumpDescription.setPumpDescription(pumpType); - } - - - public boolean canHandleDST() { - return false; - } - - - protected abstract PumpEnactResult deliverBolus(DetailedBolusInfo detailedBolusInfo); - - protected abstract void triggerUIChange(); - - private PumpEnactResult getOperationNotSupportedWithCustomText(int resourceId) { - return new PumpEnactResult(getInjector()).success(false).enacted(false).comment(resourceId); - } - - // PumpSync - - Map driverHistory = new HashMap<>(); - - public abstract long generateTempId(long timeMillis); - - public boolean addBolusWithTempId(DetailedBolusInfo detailedBolusInfo, boolean writeToInternalHistory) { - long temporaryId = generateTempId(detailedBolusInfo.timestamp); - boolean response = pumpSync.addBolusWithTempId(detailedBolusInfo.timestamp, detailedBolusInfo.insulin, - generateTempId(detailedBolusInfo.timestamp), detailedBolusInfo.getBolusType(), - getPumpType(), serialNumber()); - - if (response && writeToInternalHistory) { - driverHistory.put(temporaryId, new PumpDbEntry(temporaryId, model(), serialNumber(), detailedBolusInfo)); - } - - return response; - } - - public void removeTemporaryId(long temporaryId) { - driverHistory.remove(temporaryId); - } - - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpStatus.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpStatus.java deleted file mode 100644 index 505cd1388f..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpStatus.java +++ /dev/null @@ -1,71 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.common.data; - -import java.util.Date; - -import info.nightscout.androidaps.interfaces.ProfileStore; -import info.nightscout.androidaps.plugins.pump.common.defs.PumpStatusType; -import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; -import info.nightscout.androidaps.utils.DateUtil; - -/** - * Created by andy on 4/28/18. - */ - -public abstract class PumpStatus { - - // connection - public long lastDataTime; - public long lastConnection = 0L; - public long previousConnection = 0L; // here should be stored last connection of previous session (so needs to be - // read before lastConnection is modified for first time). - - // last bolus - public Date lastBolusTime; - public Double lastBolusAmount; - - // other pump settings - public String activeProfileName = "0"; - public double reservoirRemainingUnits = 0.0d; - public int reservoirFullUnits = 0; - public int batteryRemaining = 0; // percent, so 0-100 - public Double batteryVoltage = null; - - - // iob - public String iob = null; - - // TDD - public Double dailyTotalUnits; - public String maxDailyTotalUnits; - public boolean validBasalRateProfileSelectedOnPump = true; - public ProfileStore profileStore; - public String units; // Constants.MGDL or Constants.MMOL - public PumpStatusType pumpStatusType = PumpStatusType.Running; - public Double[] basalsByHour; - public double currentBasal = 0; - public int tempBasalInProgress = 0; - public int tempBasalRatio = 0; - public int tempBasalRemainMin = 0; - public Date tempBasalStart; - public PumpType pumpType; - //protected PumpDescription pumpDescription; - - - public PumpStatus(PumpType pumpType) { - // public PumpStatus(PumpDescription pumpDescription) { - // this.pumpDescription = pumpDescription; - -// this.initSettings(); - this.pumpType = pumpType; - } - - public abstract void initSettings(); - - public void setLastCommunicationToNow() { - this.lastDataTime = System.currentTimeMillis(); - this.lastConnection = System.currentTimeMillis(); - } - - public abstract String getErrorInfo(); - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpStatus.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpStatus.kt new file mode 100644 index 0000000000..061465c354 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpStatus.kt @@ -0,0 +1,52 @@ +package info.nightscout.androidaps.plugins.pump.common.data + +import info.nightscout.androidaps.plugins.pump.common.defs.PumpStatusType +import info.nightscout.androidaps.plugins.pump.common.defs.PumpType +import java.util.* + +/** + * Created by andy on 4/28/18. + */ +abstract class PumpStatus(var pumpType: PumpType) { + + // connection + var lastDataTime: Long = 0 + var lastConnection = 0L + var previousConnection = 0L // here should be stored last connection of previous session (so needs to be + + // read before lastConnection is modified for first time). + // last bolus + var lastBolusTime: Date? = null + var lastBolusAmount: Double? = null + + // other pump settings + var activeProfileName = "0" + var reservoirRemainingUnits = 0.0 + var reservoirFullUnits = 0 + var batteryRemaining = 0 // percent, so 0-100 + var batteryVoltage: Double? = null + + // iob + var iob: String? = null + + // TDD + var dailyTotalUnits: Double? = null + var maxDailyTotalUnits: String? = null + var units : String? = null // Constants.MGDL or Constants.MMOL + var pumpStatusType = PumpStatusType.Running + var basalsByHour: Array? = null + var tempBasalStart: Date? = null + var tempBasalAmount: Double? = 0.0 + var tempBasalLength: Int? = 0 + var tempBasalEnd: Long? = null + + abstract fun initSettings() + + fun setLastCommunicationToNow() { + lastDataTime = System.currentTimeMillis() + lastConnection = System.currentTimeMillis() + } + + abstract val errorInfo: String? + +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicFragment.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicFragment.kt index 43a75631bf..49b2415264 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicFragment.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicFragment.kt @@ -220,12 +220,12 @@ class MedtronicFragment : DaggerFragment() { PumpDeviceState.InvalidConfiguration -> binding.pumpStatusIcon.text = " " + resourceHelper.gs(medtronicPumpStatus.pumpDeviceState.resourceId) PumpDeviceState.Active -> { - val cmd = medtronicUtil.currentCommand + val cmd = medtronicUtil.getCurrentCommand() if (cmd == null) binding.pumpStatusIcon.text = " " + resourceHelper.gs(medtronicPumpStatus.pumpDeviceState.resourceId) else { aapsLogger.debug(LTag.PUMP, "Command: $cmd") - val cmdResourceId = cmd.resourceId + val cmdResourceId = cmd.resourceId!! if (cmd == MedtronicCommandType.GetHistoryData) { binding.pumpStatusIcon.text = medtronicUtil.frameNumber?.let { resourceHelper.gs(cmdResourceId, medtronicUtil.pageNumber, medtronicUtil.frameNumber) @@ -233,7 +233,7 @@ class MedtronicFragment : DaggerFragment() { ?: resourceHelper.gs(R.string.medtronic_cmd_desc_get_history_request, medtronicUtil.pageNumber) } else { binding.pumpStatusIcon.text = " " + (cmdResourceId?.let { resourceHelper.gs(it) } - ?: cmd.getCommandDescription()) + ?: cmd.commandDescription) } } } @@ -298,34 +298,31 @@ class MedtronicFragment : DaggerFragment() { val bolus = medtronicPumpStatus.lastBolusAmount val bolusTime = medtronicPumpStatus.lastBolusTime if (bolus != null && bolusTime != null) { - val agoMsc = System.currentTimeMillis() - medtronicPumpStatus.lastBolusTime.time + val agoMsc = System.currentTimeMillis() - medtronicPumpStatus.lastBolusTime!!.time val bolusMinAgo = agoMsc.toDouble() / 60.0 / 1000.0 val unit = resourceHelper.gs(R.string.insulin_unit_shortname) val ago = when { agoMsc < 60 * 1000 -> resourceHelper.gs(R.string.medtronic_pump_connected_now) - bolusMinAgo < 60 -> dateUtil.minAgo(resourceHelper, medtronicPumpStatus.lastBolusTime.time) - else -> dateUtil.hourAgo(medtronicPumpStatus.lastBolusTime.time, resourceHelper) + bolusMinAgo < 60 -> dateUtil.minAgo(resourceHelper, medtronicPumpStatus.lastBolusTime!!.time) + else -> dateUtil.hourAgo(medtronicPumpStatus.lastBolusTime!!.time, resourceHelper) } binding.lastBolus.text = resourceHelper.gs(R.string.mdt_last_bolus, bolus, unit, ago) } else { binding.lastBolus.text = "" } - if (true) { - // base basal rate - binding.baseBasalRate.text = ("(" + medtronicPumpStatus.activeProfileName + ") " - + resourceHelper.gs(R.string.pump_basebasalrate, medtronicPumpPlugin.baseBasalRate)) + // base basal rate + binding.baseBasalRate.text = ("(" + medtronicPumpStatus.activeProfileName + ") " + + resourceHelper.gs(R.string.pump_basebasalrate, medtronicPumpPlugin.baseBasalRate)) - binding.tempBasal.text = "??" - } else { - val pumpState = pumpSync.expectedPumpState() - // base basal rate - binding.baseBasalRate.text = ("(" + medtronicPumpStatus.activeProfileName + ") " - + resourceHelper.gs(R.string.pump_basebasalrate, medtronicPumpPlugin.baseBasalRate)) + // TBR + var tbrStr = "" + var tbrRemainingTime: Int? = medtronicPumpStatus.tbrRemainingTime - binding.tempBasal.text = pumpState.temporaryBasal?.toStringFull(dateUtil) - ?: "" + if (tbrRemainingTime!=null) { + tbrStr = resourceHelper.gs(R.string.mdt_tbr_remaining, medtronicPumpStatus.tempBasalAmount, tbrRemainingTime); } + binding.tempBasal.text = tbrStr // battery if (medtronicPumpStatus.batteryType == BatteryType.None || medtronicPumpStatus.batteryVoltage == null) { diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java index b514ec7d3a..c86e7c95a3 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java @@ -40,6 +40,7 @@ import info.nightscout.androidaps.interfaces.CommandQueueProvider; import info.nightscout.androidaps.interfaces.PluginDescription; import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.Pump; +import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpSync; import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.LTag; @@ -210,19 +211,24 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements Pump, Ril return "MedtronicPumpPlugin::"; } +// public PumpDescription getPumpDescription() { +// return super.pumpDescription; +// } + + @Override public void initPumpStatusData() { - medtronicPumpStatus.lastConnection = sp.getLong(RileyLinkConst.Prefs.LastGoodDeviceCommunicationTime, 0L); - medtronicPumpStatus.lastDataTime = medtronicPumpStatus.lastConnection; - medtronicPumpStatus.previousConnection = medtronicPumpStatus.lastConnection; + medtronicPumpStatus.setLastConnection(sp.getLong(RileyLinkConst.Prefs.LastGoodDeviceCommunicationTime, 0L)); + medtronicPumpStatus.setLastDataTime(medtronicPumpStatus.getLastConnection()); + medtronicPumpStatus.setPreviousConnection( medtronicPumpStatus.getLastConnection()); //if (rileyLinkMedtronicService != null) rileyLinkMedtronicService.verifyConfiguration(); aapsLogger.debug(LTag.PUMP, "initPumpStatusData: " + this.medtronicPumpStatus); // this is only thing that can change, by being configured - pumpDescription.setMaxTempAbsolute((medtronicPumpStatus.maxBasal != null) ? medtronicPumpStatus.maxBasal : 35.0d); + pumpDescription.setMaxTempAbsolute((medtronicPumpStatus.getMaxBasal() != null) ? medtronicPumpStatus.getMaxBasal() : 35.0d); // set first Medtronic Pump Start if (!sp.contains(MedtronicConst.Statistics.FirstPumpStart)) { @@ -321,15 +327,16 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements Pump, Ril return rileyLinkMedtronicService; } - @Override public RileyLinkPumpInfo getPumpInfo() { - String frequency = resourceHelper.gs(medtronicPumpStatus.pumpFrequency.equals("medtronic_pump_frequency_us_ca") ? R.string.medtronic_pump_frequency_us_ca : R.string.medtronic_pump_frequency_worldwide); - String model = medtronicPumpStatus.medtronicDeviceType == null ? "???" : "Medtronic " + medtronicPumpStatus.medtronicDeviceType.getPumpModel(); - String serialNumber = medtronicPumpStatus.serialNumber; + @Override + public RileyLinkPumpInfo getPumpInfo() { + String frequency = resourceHelper.gs(medtronicPumpStatus.getPumpFrequency().equals("medtronic_pump_frequency_us_ca") ? R.string.medtronic_pump_frequency_us_ca : R.string.medtronic_pump_frequency_worldwide); + String model = medtronicPumpStatus.getMedtronicDeviceType() == null ? "???" : "Medtronic " + medtronicPumpStatus.getMedtronicDeviceType().getPumpModel(); + String serialNumber = medtronicPumpStatus.getSerialNumber(); return new RileyLinkPumpInfo(frequency, model, serialNumber); } @Override public long getLastConnectionTimeMillis() { - return medtronicPumpStatus.lastConnection; + return medtronicPumpStatus.getLastConnection(); } @Override public void setLastCommunicationToNow() { @@ -580,7 +587,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements Pump, Ril if (medtronicUtil.getMedtronicPumpModel() == null) { rileyLinkMedtronicService.getMedtronicUIComm().executeCommand(MedtronicCommandType.PumpModel); } else { - if (medtronicPumpStatus.medtronicDeviceType != medtronicUtil.getMedtronicPumpModel()) { + if (medtronicPumpStatus.getMedtronicDeviceType() != medtronicUtil.getMedtronicPumpModel()) { aapsLogger.warn(LTag.PUMP, getLogPrefix() + "Configured pump is not the same as one detected."); medtronicUtil.sendNotification(MedtronicNotificationType.PumpTypeNotSame, getResourceHelper(), rxBus); } @@ -643,27 +650,27 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements Pump, Ril @Override public boolean isThisProfileSet(@NonNull Profile profile) { - aapsLogger.debug(LTag.PUMP, "isThisProfileSet: basalInitalized=" + medtronicPumpStatus.basalProfileStatus); + aapsLogger.debug(LTag.PUMP, "isThisProfileSet: basalInitalized=" + medtronicPumpStatus.getBasalProfileStatus()); if (!isInitialized) return true; - if (medtronicPumpStatus.basalProfileStatus == BasalProfileStatus.NotInitialized) { + if (medtronicPumpStatus.getBasalProfileStatus() == BasalProfileStatus.NotInitialized) { // this shouldn't happen, but if there was problem we try again getBasalProfiles(); return isProfileSame(profile); - } else if (medtronicPumpStatus.basalProfileStatus == BasalProfileStatus.ProfileChanged) { + } else if (medtronicPumpStatus.getBasalProfileStatus() == BasalProfileStatus.ProfileChanged) { return false; } - return (medtronicPumpStatus.basalProfileStatus != BasalProfileStatus.ProfileOK) || isProfileSame(profile); + return (medtronicPumpStatus.getBasalProfileStatus() != BasalProfileStatus.ProfileOK) || isProfileSame(profile); } private boolean isProfileSame(Profile profile) { boolean invalid = false; - Double[] basalsByHour = medtronicPumpStatus.basalsByHour; + Double[] basalsByHour = medtronicPumpStatus.getBasalsByHour(); aapsLogger.debug(LTag.PUMP, "Current Basals (h): " + (basalsByHour == null ? "null" : BasalProfile.getProfilesByHourToString(basalsByHour))); @@ -704,8 +711,8 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements Pump, Ril @Override public long lastDataTime() { - if (medtronicPumpStatus.lastConnection != 0) { - return medtronicPumpStatus.lastConnection; + if (medtronicPumpStatus.getLastConnection() != 0) { + return medtronicPumpStatus.getLastConnection(); } return System.currentTimeMillis(); @@ -720,13 +727,13 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements Pump, Ril @Override public double getReservoirLevel() { - return medtronicPumpStatus.reservoirRemainingUnits; + return medtronicPumpStatus.getReservoirRemainingUnits(); } @Override public int getBatteryLevel() { - return medtronicPumpStatus.batteryRemaining; + return medtronicPumpStatus.getBatteryRemaining(); } protected void triggerUIChange() { @@ -778,22 +785,22 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements Pump, Ril if (clock == null) return; - int timeDiff = Math.abs(clock.timeDifference); + int timeDiff = Math.abs(clock.getTimeDifference()); if (timeDiff > 20) { - if ((clock.localDeviceTime.getYear() <= 2015) || (timeDiff <= 24 * 60 * 60)) { + if ((clock.getLocalDeviceTime().getYear() <= 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.getMedtronicUIComm().executeCommand(MedtronicCommandType.SetRealTimeClock); - if (clock.timeDifference == 0) { + if (clock.getTimeDifference() == 0) { Notification notification = new Notification(Notification.INSIGHT_DATE_TIME_UPDATED, getResourceHelper().gs(R.string.pump_time_updated), Notification.INFO, 60); rxBus.send(new EventNewNotification(notification)); } } else { - if ((clock.localDeviceTime.getYear() > 2015)) { + if ((clock.getLocalDeviceTime().getYear() > 2015)) { aapsLogger.error(String.format(Locale.ENGLISH, "MedtronicPumpPlugin::checkTimeAndOptionallySetTime - Time difference over 24h requested [diff=%d s]. Doing nothing.", timeDiff)); medtronicUtil.sendNotification(MedtronicNotificationType.TimeChangeOver24h, getResourceHelper(), rxBus); } @@ -814,12 +821,12 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements Pump, Ril setRefreshButtonEnabled(false); - if (detailedBolusInfo.insulin > medtronicPumpStatus.reservoirRemainingUnits) { + if (detailedBolusInfo.insulin > medtronicPumpStatus.getReservoirRemainingUnits()) { return new PumpEnactResult(getInjector()) // .success(false) // .enacted(false) // .comment(getResourceHelper().gs(R.string.medtronic_cmd_bolus_could_not_be_delivered_no_insulin, - medtronicPumpStatus.reservoirRemainingUnits, + medtronicPumpStatus.getReservoirRemainingUnits(), detailedBolusInfo.insulin)); } @@ -857,9 +864,9 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements Pump, Ril // LOG.debug("MedtronicPumpPlugin::deliverBolus - Start delivery"); MedtronicUITask responseTask = rileyLinkMedtronicService.getMedtronicUIComm().executeCommand(MedtronicCommandType.SetBolus, - detailedBolusInfo.insulin); + Arrays.asList(detailedBolusInfo.insulin)); - Boolean response = (Boolean) responseTask.returnData; + Boolean response = (Boolean) responseTask.getResult(); setRefreshButtonEnabled(true); @@ -894,7 +901,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements Pump, Ril } // we subtract insulin, exact amount will be visible with next remainingInsulin update. - medtronicPumpStatus.reservoirRemainingUnits -= detailedBolusInfo.insulin; + medtronicPumpStatus.setReservoirRemainingUnits(medtronicPumpStatus.getReservoirRemainingUnits() - detailedBolusInfo.insulin); incrementStatistics(detailedBolusInfo.getBolusType() == DetailedBolusInfo.BolusType.SMB ? MedtronicConst.Statistics.SMBBoluses : MedtronicConst.Statistics.StandardBoluses); @@ -1022,7 +1029,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements Pump, Ril MedtronicUITask responseTask2 = rileyLinkMedtronicService.getMedtronicUIComm().executeCommand(MedtronicCommandType.CancelTBR); - Boolean response = (Boolean) responseTask2.returnData; + Boolean response = (Boolean) responseTask2.getResult(); if (response) { aapsLogger.info(LTag.PUMP, getLogPrefix() + "setTempBasalAbsolute - Current TBR cancelled."); @@ -1038,17 +1045,17 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements Pump, Ril // now start new TBR MedtronicUITask responseTask = rileyLinkMedtronicService.getMedtronicUIComm().executeCommand(MedtronicCommandType.SetTemporaryBasal, - absoluteRate, durationInMinutes); + Arrays.asList(absoluteRate, durationInMinutes)); - Boolean response = (Boolean) responseTask.returnData; + Boolean response = (Boolean) responseTask.getResult(); aapsLogger.info(LTag.PUMP, getLogPrefix() + "setTempBasalAbsolute - setTBR. Response: " + response); if (response) { // FIXME put this into UIPostProcessor - medtronicPumpStatus.tempBasalStart = new Date(); - medtronicPumpStatus.tempBasalAmount = absoluteRate; - medtronicPumpStatus.tempBasalLength = durationInMinutes; + medtronicPumpStatus.setTempBasalStart(new Date()); + medtronicPumpStatus.setTempBasalAmount(absoluteRate); + medtronicPumpStatus.setTempBasalLength(durationInMinutes); TemporaryBasal tempStart = new TemporaryBasal(getInjector()) // .date(System.currentTimeMillis()) // @@ -1122,7 +1129,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements Pump, Ril scheduleNextRefresh(MedtronicStatusRefreshType.PumpTime, -1); } - if (this.medtronicPumpStatus.basalProfileStatus != BasalProfileStatus.NotInitialized + if (this.medtronicPumpStatus.getBasalProfileStatus() != BasalProfileStatus.NotInitialized && medtronicHistoryData.hasBasalProfileChanged()) { medtronicHistoryData.processLastBasalProfileChange(pumpDescription.getPumpType(), medtronicPumpStatus); } @@ -1194,7 +1201,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements Pump, Ril } } else { if (debugHistory) - aapsLogger.debug(LTag.PUMP, getLogPrefix() + "readPumpHistoryLogic(): lastPumpHistoryEntry: not null - " + medtronicUtil.gsonInstance.toJson(lastPumpHistoryEntry)); + aapsLogger.debug(LTag.PUMP, getLogPrefix() + "readPumpHistoryLogic(): lastPumpHistoryEntry: not null - " + medtronicUtil.getGsonInstance().toJson(lastPumpHistoryEntry)); medtronicHistoryData.setIsInInit(false); // medtronicHistoryData.setLastHistoryRecordTime(lastPumpHistoryEntry.atechDateTime); @@ -1204,12 +1211,12 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements Pump, Ril //aapsLogger.debug(LTag.PUMP, "HST: Target Date: " + targetDate); MedtronicUITask responseTask2 = rileyLinkMedtronicService.getMedtronicUIComm().executeCommand(MedtronicCommandType.GetHistoryData, - lastPumpHistoryEntry, targetDate); + Arrays.asList(lastPumpHistoryEntry, targetDate)); if (debugHistory) aapsLogger.debug(LTag.PUMP, "HST: After task"); - PumpHistoryResult historyResult = (PumpHistoryResult) responseTask2.returnData; + PumpHistoryResult historyResult = (PumpHistoryResult) responseTask2.getResult(); if (debugHistory) aapsLogger.debug(LTag.PUMP, "HST: History Result: " + historyResult.toString()); @@ -1226,7 +1233,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements Pump, Ril sp.putLong(MedtronicConst.Statistics.LastPumpHistoryEntry, latestEntry.getAtechDateTime()); if (debugHistory) - aapsLogger.debug(LTag.PUMP, "HST: History: valid=" + historyResult.validEntries.size() + ", unprocessed=" + historyResult.unprocessedEntries.size()); + aapsLogger.debug(LTag.PUMP, "HST: History: valid=" + historyResult.getValidEntries().size() + ", unprocessed=" + historyResult.getUnprocessedEntries().size()); this.medtronicHistoryData.addNewHistory(historyResult); this.medtronicHistoryData.filterNewEntries(); @@ -1281,7 +1288,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements Pump, Ril switch (refreshType) { case RemainingInsulin: { - double remaining = medtronicPumpStatus.reservoirRemainingUnits; + double remaining = medtronicPumpStatus.getReservoirRemainingUnits(); int min; if (remaining > 50) min = 4 * 60; @@ -1348,7 +1355,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements Pump, Ril MedtronicUITask responseTask = rileyLinkMedtronicService.getMedtronicUIComm().executeCommand(MedtronicCommandType.ReadTemporaryBasal); if (responseTask.hasData()) { - TempBasalPair tbr = (TempBasalPair) responseTask.returnData; + TempBasalPair tbr = (TempBasalPair) responseTask.getResult(); // we sometimes get rate returned even if TBR is no longer running if (tbr.getDurationMinutes() == 0) { @@ -1397,7 +1404,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements Pump, Ril MedtronicUITask responseTask2 = rileyLinkMedtronicService.getMedtronicUIComm().executeCommand(MedtronicCommandType.CancelTBR); - Boolean response = (Boolean) responseTask2.returnData; + Boolean response = (Boolean) responseTask2.getResult(); finishAction("TBR"); @@ -1434,7 +1441,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements Pump, Ril @NonNull @Override public String serialNumber() { - return medtronicPumpStatus.serialNumber; + return medtronicPumpStatus.getSerialNumber(); } @NonNull @Override @@ -1465,6 +1472,8 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements Pump, Ril BasalProfile basalProfile = convertProfileToMedtronicProfile(profile); + aapsLogger.debug("Basal Profile: " + basalProfile); + String profileInvalid = isProfileValid(basalProfile); if (profileInvalid != null) { @@ -1475,9 +1484,9 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements Pump, Ril } MedtronicUITask responseTask = rileyLinkMedtronicService.getMedtronicUIComm().executeCommand(MedtronicCommandType.SetBasalProfileSTD, - basalProfile); + Arrays.asList(basalProfile)); - Boolean response = (Boolean) responseTask.returnData; + Boolean response = (Boolean) responseTask.getResult(); aapsLogger.info(LTag.PUMP, getLogPrefix() + "Basal Profile was set: " + response); @@ -1494,12 +1503,12 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements Pump, Ril StringBuilder stringBuilder = new StringBuilder(); - if (medtronicPumpStatus.maxBasal == null) + if (medtronicPumpStatus.getMaxBasal() == null) return null; for (BasalProfileEntry profileEntry : basalProfile.getEntries()) { - if (profileEntry.getRate() > medtronicPumpStatus.maxBasal) { + if (profileEntry.getRate() > medtronicPumpStatus.getMaxBasal()) { stringBuilder.append(profileEntry.getStartTime().toString("HH:mm")); stringBuilder.append("="); stringBuilder.append(profileEntry.getRate()); diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicCommunicationManager.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicCommunicationManager.java index 4b8f885701..7773f28ba7 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicCommunicationManager.java +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicCommunicationManager.java @@ -80,8 +80,8 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager @Inject public void onInit() { // 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); + medtronicPumpStatus.setPreviousConnection(sp.getLong( + RileyLinkConst.Prefs.LastGoodDeviceCommunicationTime, 0L)); } @Override @@ -136,7 +136,7 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager if (!canPreventTuneUp) { - long diff = System.currentTimeMillis() - medtronicPumpStatus.lastConnection; + long diff = System.currentTimeMillis() - medtronicPumpStatus.getLastConnection(); if (diff > RILEYLINK_TIMEOUT) { serviceTaskExecutor.startTask(new WakeAndTuneTask(injector)); @@ -278,7 +278,7 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager for (List frame : frames) { - byte[] frameData = MedtronicUtil.createByteArray(frame); + byte[] frameData = medtronicUtil.createByteArray(frame); // aapsLogger.debug(LTag.PUMPCOMM,"Frame {} data:\n{}", frameNr, ByteUtil.getCompactString(frameData)); @@ -570,7 +570,7 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager try { PumpMessage response = sendAndGetResponse(commandType, bodyData, DEFAULT_TIMEOUT + (DEFAULT_TIMEOUT * retries)); - String check = checkResponseContent(response, commandType.commandDescription, commandType.expectedLength); + String check = checkResponseContent(response, commandType.getCommandDescription(), commandType.getExpectedLength()); if (check == null) { @@ -632,11 +632,11 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager // PUMP SPECIFIC COMMANDS - public Float getRemainingInsulin() { + public Double getRemainingInsulin() { Object responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.GetRemainingInsulin); - return responseObject == null ? null : (Float) responseObject; + return responseObject == null ? null : (Double) responseObject; } @@ -677,7 +677,7 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager // aapsLogger.debug(LTag.PUMPCOMM,"1st Response: " + HexDump.toHexStringDisplayable(response.getRawContent())); // aapsLogger.debug(LTag.PUMPCOMM,"1st Response: " + HexDump.toHexStringDisplayable(response.getMessageBody().getTxData())); - String check = checkResponseContent(response, commandType.commandDescription, 1); + String check = checkResponseContent(response, commandType.getCommandDescription(), 1); byte[] data = null; @@ -695,7 +695,7 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager // aapsLogger.debug(LTag.PUMPCOMM,"{} Response: {}", runs, // HexDump.toHexStringDisplayable(response2.getMessageBody().getTxData())); - String check2 = checkResponseContent(response, commandType.commandDescription, 1); + String check2 = checkResponseContent(response, commandType.getCommandDescription(), 1); if (check2 == null) { @@ -765,12 +765,12 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager public ClockDTO getPumpTime() { ClockDTO clockDTO = new ClockDTO(); - clockDTO.localDeviceTime = new LocalDateTime(); + clockDTO.setLocalDeviceTime(new LocalDateTime()); Object responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.GetRealTimeClock); if (responseObject != null) { - clockDTO.pumpTime = (LocalDateTime) responseObject; + clockDTO.setPumpTime((LocalDateTime) responseObject); return clockDTO; } 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 3796661ef5..a15fb131b7 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 @@ -58,7 +58,7 @@ class MedtronicConverter @Inject constructor( } MedtronicCommandType.ReadTemporaryBasal -> { - TempBasalPair(aapsLogger, rawContent) // 5 + TempBasalPair(aapsLogger, rawContent!!) // 5 } MedtronicCommandType.Settings_512 -> { @@ -112,7 +112,7 @@ class MedtronicConverter @Inject constructor( batteryStatus.batteryStatusType = BatteryStatusDTO.BatteryStatusType.Unknown } if (rawData.size > 1) { - var d: Double? = null + var d: Double? //= null // if response in 3 bytes then we add additional information d = if (rawData.size == 2) { @@ -126,7 +126,7 @@ class MedtronicConverter @Inject constructor( return batteryStatus } - private fun decodeRemainingInsulin(rawData: ByteArray?): Float { + private fun decodeRemainingInsulin(rawData: ByteArray?): Double { var startIdx = 0 val pumpModel = medtronicUtil.medtronicPumpModel val strokes = pumpModel?.bolusStrokes ?: 10 @@ -134,11 +134,11 @@ class MedtronicConverter @Inject constructor( startIdx = 2 } val reqLength = startIdx + 1 - var value = 0f + var value = 0.0 value = if (reqLength >= rawData!!.size) { - rawData[startIdx] / (1.0f * strokes) + rawData[startIdx] / (1.0 * strokes) } else { - ByteUtil.toInt(rawData[startIdx], rawData[startIdx + 1]) / (1.0f * strokes) + ByteUtil.toInt(rawData[startIdx], rawData[startIdx + 1]) / (1.0 * strokes) } aapsLogger.debug(LTag.PUMPCOMM, "Remaining insulin: $value") return value @@ -208,7 +208,7 @@ class MedtronicConverter @Inject constructor( rd[settingIndexMaxBasal + 1].toInt())), PumpConfigurationGroup.Basal, map) addSettingToMap("CFG_BASE_CLOCK_MODE", if (rd[settingIndexTimeDisplayFormat].toInt() == 0) "12h" else "24h", PumpConfigurationGroup.General, map) - if (MedtronicDeviceType.isSameDevice(medtronicUtil.medtronicPumpModel, MedtronicDeviceType.Medtronic_523andHigher)) { + if (MedtronicDeviceType.isSameDevice(medtronicUtil.medtronicPumpModel!!, MedtronicDeviceType.Medtronic_523andHigher)) { addSettingToMap("PCFG_INSULIN_CONCENTRATION", "" + if (rd[9].toInt() == 0) 50 else 100, PumpConfigurationGroup.Insulin, map) // LOG.debug("Insulin concentration: " + rd[9]); @@ -249,7 +249,7 @@ class MedtronicConverter @Inject constructor( addSettingToMap("PCFG_MM_SRESERVOIR_WARNING_POINT", "" + ByteUtil.asUINT8(rd[19]), PumpConfigurationGroup.Other, map) addSettingToMap("CFG_MM_KEYPAD_LOCKED", parseResultEnable(rd[20].toInt()), PumpConfigurationGroup.Other, map) - if (MedtronicDeviceType.isSameDevice(medtronicUtil.medtronicPumpModel, MedtronicDeviceType.Medtronic_523andHigher)) { + if (MedtronicDeviceType.isSameDevice(medtronicUtil.medtronicPumpModel!!, MedtronicDeviceType.Medtronic_523andHigher)) { addSettingToMap("PCFG_BOLUS_SCROLL_STEP_SIZE", "" + rd[21], PumpConfigurationGroup.Bolus, map) addSettingToMap("PCFG_CAPTURE_EVENT_ENABLE", parseResultEnable(rd[22].toInt()), PumpConfigurationGroup.Other, map) addSettingToMap("PCFG_OTHER_DEVICE_ENABLE", parseResultEnable(rd[23].toInt()), PumpConfigurationGroup.Other, map) @@ -273,7 +273,7 @@ class MedtronicConverter @Inject constructor( // 512 private fun decodeInsulinActionSetting(ai: ByteArray, map: MutableMap) { - if (MedtronicDeviceType.isSameDevice(medtronicUtil.medtronicPumpModel, MedtronicDeviceType.Medtronic_512_712)) { + if (MedtronicDeviceType.isSameDevice(medtronicUtil.medtronicPumpModel!!, MedtronicDeviceType.Medtronic_512_712)) { addSettingToMap("PCFG_INSULIN_ACTION_TYPE", if (ai[17].toInt() != 0) "Regular" else "Fast", PumpConfigurationGroup.Insulin, map) } else { @@ -297,10 +297,10 @@ class MedtronicConverter @Inject constructor( } private val settingIndexMaxBasal: Int - private get() = if (is523orHigher()) 7 else 6 + get() = if (is523orHigher()) 7 else 6 private val settingIndexTimeDisplayFormat: Int - private get() = if (is523orHigher()) 9 else 8 + get() = if (is523orHigher()) 9 else 8 private fun decodeMaxBolus(ai: ByteArray?): Double { return if (is523orHigher()) decodeBolusInsulin(ByteUtil.toInt(ai!![5], ai[6])) else decodeBolusInsulin(ByteUtil @@ -308,7 +308,7 @@ class MedtronicConverter @Inject constructor( } private fun is523orHigher(): Boolean { - return MedtronicDeviceType.isSameDevice(medtronicUtil.medtronicPumpModel, MedtronicDeviceType.Medtronic_523andHigher) + return MedtronicDeviceType.isSameDevice(medtronicUtil.medtronicPumpModel!!, MedtronicDeviceType.Medtronic_523andHigher) } } \ No newline at end of file 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 181177d54f..57bc0eab11 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 @@ -38,8 +38,8 @@ abstract class MedtronicHistoryDecoder : MedtronicHi private fun checkPage(page: RawHistoryPage, partial: Boolean): List { val byteList: List = ArrayList() - if (medtronicUtil!!.medtronicPumpModel == null) { - aapsLogger!!.error(LTag.PUMPCOMM, "Device Type is not defined.") + if (medtronicUtil.medtronicPumpModel == null) { + aapsLogger.error(LTag.PUMPCOMM, "Device Type is not defined.") return byteList } return if (page.data.size != 1024) { @@ -82,9 +82,9 @@ abstract class MedtronicHistoryDecoder : MedtronicHi for ((key) in unknownOpCodes!!) { StringUtil.appendToStringBuilder(sb, "" + key, ", ") } - aapsLogger!!.info(LTag.PUMPCOMM, "STATISTICS OF PUMP DECODE") + aapsLogger.info(LTag.PUMPCOMM, "STATISTICS OF PUMP DECODE") if (unknownOpCodes!!.size > 0) { - aapsLogger!!.warn(LTag.PUMPCOMM, "Unknown Op Codes: $sb") + aapsLogger.warn(LTag.PUMPCOMM, "Unknown Op Codes: $sb") } for ((key, value) in mapStatistics!!) { sb = StringBuilder() @@ -94,9 +94,9 @@ abstract class MedtronicHistoryDecoder : MedtronicHi StringUtil.appendToStringBuilder(sb, key1, ", ") } val spaces = StringUtils.repeat(" ", 14 - key.name.length) - aapsLogger!!.info(LTag.PUMPCOMM, String.format(Locale.ENGLISH, " %s%s - %d. Elements: %s", key.name, spaces, value.size, sb.toString())) + aapsLogger.info(LTag.PUMPCOMM, String.format(Locale.ENGLISH, " %s%s - %d. Elements: %s", key.name, spaces, value.size, sb.toString())) } else { - aapsLogger!!.info(LTag.PUMPCOMM, String.format(Locale.ENGLISH, " %s - %d", key.name, value.size)) + aapsLogger.info(LTag.PUMPCOMM, String.format(Locale.ENGLISH, " %s - %d", key.name, value.size)) } } } diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntry.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntry.kt index 6f2228b29c..e8b69a46ff 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntry.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntry.kt @@ -82,7 +82,7 @@ abstract class MedtronicHistoryEntry : MedtronicHistoryEntryInterface { if (!doNotProcess) { head = ByteArray(headLength - 1) for (i in 1 until headLength) { - head!![i - 1] = listRawData!![i]!! + head!![i - 1] = listRawData[i] } if (dateTimeLength > 0) { datetime = ByteArray(dateTimeLength) @@ -99,7 +99,7 @@ abstract class MedtronicHistoryEntry : MedtronicHistoryEntryInterface { var i = headLength + dateTimeLength var j = 0 while (j < bodyLength) { - body!![j] = listRawData!![i]!! + body!![j] = listRawData[i] i++ j++ } diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/RawHistoryPage.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/RawHistoryPage.kt index 792120b688..c4036ea46e 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/RawHistoryPage.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/RawHistoryPage.kt @@ -37,7 +37,7 @@ class RawHistoryPage(private val aapsLogger: AAPSLogger) { aapsLogger.error(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, "Stored CRC (%d) is different than calculated (%d), but ignored for now.", crcStored, crcCalculated)) } else { - if (MedtronicUtil.isLowLevelDebug()) aapsLogger.debug(LTag.PUMPBTCOMM, "CRC ok.") + if (MedtronicUtil.isLowLevelDebug) aapsLogger.debug(LTag.PUMPBTCOMM, "CRC ok.") } return crcCalculated == crcStored } 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 c8e38e7fcb..0a2da5b5be 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 @@ -49,7 +49,7 @@ class MedtronicPumpHistoryDecoder @Inject constructor( return outList } do { - val opCode: Int = dataClear[counter]!!.toInt() + val opCode: Int = dataClear[counter].toInt() var special = false incompletePacket = false var skippedRecords = false @@ -69,7 +69,7 @@ class MedtronicPumpHistoryDecoder @Inject constructor( } val entryType = getByCode(opCode.toByte()) val pe = PumpHistoryEntry() - pe.setEntryType(medtronicUtil!!.medtronicPumpModel, entryType!!) + pe.setEntryType(medtronicUtil.medtronicPumpModel!!, entryType!!) pe.offset = counter counter++ if (counter >= 1022) { @@ -91,7 +91,7 @@ class MedtronicPumpHistoryDecoder @Inject constructor( } special = true } else { - for (j in 0 until entryType.getTotalLength(medtronicUtil.medtronicPumpModel) - 1) { + for (j in 0 until entryType.getTotalLength(medtronicUtil.medtronicPumpModel!!) - 1) { try { listRawData.add(dataClear[counter]) counter++ @@ -111,7 +111,7 @@ class MedtronicPumpHistoryDecoder @Inject constructor( if (pe.entryType === PumpHistoryEntryType.UnknownBasePacket) { pe.opCode = opCode.toByte() } - if (entryType.getHeadLength(medtronicUtil!!.medtronicPumpModel) == 0) special = true + if (entryType.getHeadLength(medtronicUtil!!.medtronicPumpModel!!) == 0) special = true pe.setData(listRawData as List, special) val decoded = decodeRecord(pe) if (decoded === RecordDecodeStatus.OK || decoded === RecordDecodeStatus.Ignored) { @@ -235,7 +235,7 @@ class MedtronicPumpHistoryDecoder @Inject constructor( val offset = body!![0] * 1000 * 30 * 60 var rate: Float? = null val index = entry.head!![0].toInt() - if (MedtronicDeviceType.isSameDevice(medtronicUtil.medtronicPumpModel, MedtronicDeviceType.Medtronic_523andHigher)) { + if (MedtronicDeviceType.isSameDevice(medtronicUtil.medtronicPumpModel!!, MedtronicDeviceType.Medtronic_523andHigher)) { rate = body[1] * 0.025f } @@ -254,7 +254,7 @@ class MedtronicPumpHistoryDecoder @Inject constructor( val body = entry.body!! val dto = BolusWizardDTO() var bolusStrokes = 10.0f - if (MedtronicDeviceType.isSameDevice(medtronicUtil!!.medtronicPumpModel, MedtronicDeviceType.Medtronic_523andHigher)) { + if (MedtronicDeviceType.isSameDevice(medtronicUtil!!.medtronicPumpModel!!, MedtronicDeviceType.Medtronic_523andHigher)) { // https://github.com/ps2/minimed_rf/blob/master/lib/minimed_rf/log_entries/bolus_wizard.rb#L102 bolusStrokes = 40.0f dto.carbs = ((body[1] and 0x0c.toByte()).toInt() shl 6) + body[0] @@ -263,19 +263,19 @@ class MedtronicPumpHistoryDecoder @Inject constructor( // carb_ratio (?) = (((self.body[2] & 0x07) << 8) + self.body[3]) / // 10.0s dto.insulinSensitivity = body[4].toFloat() - dto.bgTargetLow = body[5] as Int - dto.bgTargetHigh = body[14] as Int + dto.bgTargetLow = body[5].toInt() + dto.bgTargetHigh = body[14].toInt() dto.correctionEstimate = (((body[9] and 0x38).toInt() shl 5) + body[6]) / bolusStrokes dto.foodEstimate = ((body[7].toInt() shl 8) + body[8]) / bolusStrokes dto.unabsorbedInsulin = ((body[10].toInt() shl 8) + body[11]) / bolusStrokes dto.bolusTotal = ((body[12].toInt() shl 8) + body[13]) / bolusStrokes } else { dto.bloodGlucose = (body.get(1) and 0x0F).toInt() shl 8 or entry.head!!.get(0).toInt() - dto.carbs = body.get(0) as Int + dto.carbs = body.get(0).toInt() dto.carbRatio = body.get(2).toFloat() dto.insulinSensitivity = body.get(3).toFloat() - dto.bgTargetLow = body.get(4) as Int - dto.bgTargetHigh = body.get(12) as Int + dto.bgTargetLow = body.get(4).toInt() + dto.bgTargetHigh = body.get(12).toInt() dto.bolusTotal = body.get(11) / bolusStrokes dto.foodEstimate = body.get(6) / bolusStrokes dto.unabsorbedInsulin = body.get(9) / bolusStrokes @@ -359,7 +359,7 @@ class MedtronicPumpHistoryDecoder @Inject constructor( private fun decodeBolus(entry: PumpHistoryEntry) { val bolus = BolusDTO() val data = entry.head!! - if (MedtronicDeviceType.isSameDevice(medtronicUtil.getMedtronicPumpModel(), MedtronicDeviceType.Medtronic_523andHigher)) { + if (MedtronicDeviceType.isSameDevice(medtronicUtil.medtronicPumpModel!!, MedtronicDeviceType.Medtronic_523andHigher)) { bolus.requestedAmount = ByteUtil.toInt(data.get(0), data.get(1)) / 40.0 bolus.deliveredAmount = ByteUtil.toInt(data.get(2), data.get(3)) / 40.0 bolus.insulinOnBoard = ByteUtil.toInt(data.get(4), data.get(5)) / 40.0 @@ -369,8 +369,8 @@ class MedtronicPumpHistoryDecoder @Inject constructor( bolus.deliveredAmount = ByteUtil.asUINT8(data.get(1)) / 10.0 bolus.duration = ByteUtil.asUINT8(data.get(2)) * 30 } - bolus.bolusType = if (bolus.duration != null && bolus.duration > 0) PumpBolusType.Extended else PumpBolusType.Normal - bolus.setAtechDateTime(entry.atechDateTime!!) + bolus.bolusType = if (bolus.duration != null && bolus.duration!! > 0) PumpBolusType.Extended else PumpBolusType.Normal + bolus.atechDateTime = entry.atechDateTime!! entry.addDecodedData("Object", bolus) entry.displayableValue = bolus.displayableValue } @@ -404,10 +404,10 @@ class MedtronicPumpHistoryDecoder @Inject constructor( // tbrDuration.getHead()[0], // (ByteUtil.asUINT8(tbrRate.getDatetime()[4]) >> 3) == 0); val tbr = TempBasalPair( - tbrRate!!.head!!.get(0), - tbrRate!!.body!!.get(0), + tbrRate.head!!.get(0), + tbrRate.body!!.get(0), tbrDuration!!.head!!.get(0).toInt(), - ByteUtil.asUINT8(tbrRate!!.datetime!!.get(4)) shr 3 == 0) + ByteUtil.asUINT8(tbrRate.datetime!!.get(4)) shr 3 == 0) // System.out.println("TBR: amount=" + tbr.getInsulinRate() + ", duration=" + tbr.getDurationMinutes() // // + " min. Packed: " + tbr.getValue() @@ -464,13 +464,13 @@ class MedtronicPumpHistoryDecoder @Inject constructor( } private fun fix2DigitYear(year: Int): Int { - var year = year - year += if (year > 90) { + var yearInternal = year + yearInternal += if (yearInternal > 90) { 1900 } else { 2000 } - return year + return yearInternal } companion object { diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.kt index 289cb113ed..7cb40c46e6 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.kt @@ -35,16 +35,16 @@ class PumpHistoryEntry : MedtronicHistoryEntry() { field = value } - fun setEntryType(medtronicDeviceType: MedtronicDeviceType?, entryType: PumpHistoryEntryType) { + fun setEntryType(medtronicDeviceType: MedtronicDeviceType, entryType: PumpHistoryEntryType) { this.entryType = entryType sizes[0] = entryType.getHeadLength(medtronicDeviceType) sizes[1] = entryType.dateLength sizes[2] = entryType.getBodyLength(medtronicDeviceType) - if (this.entryType != null && atechDateTime != null) setPumpId() + if (this.entryType != null && atechDateTime != null) generatePumpId() } - private fun setPumpId() { - pumpId = entryType!!.code + atechDateTime!! * 1000L + private fun generatePumpId() : Long { + return entryType!!.code + atechDateTime!! * 1000L } override val toStringStart: String @@ -105,7 +105,7 @@ class PumpHistoryEntry : MedtronicHistoryEntry() { override var pumpId: Long? = null get() { - setPumpId() + field = generatePumpId() return field } set(pumpId) { diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntryType.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntryType.kt index 9ddb18b996..796ec828db 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntryType.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntryType.kt @@ -212,7 +212,7 @@ enum class PumpHistoryEntryType // implements CodeEnum private constructor(opCode: Byte, group: PumpHistoryEntryGroup) : this(opCode, null, group, 2, 5, 0) {} private constructor(opCode: Byte, group: PumpHistoryEntryGroup, head: Int, date: Int, body: Int) : this(opCode, null, group, head, date, body) {} - fun getTotalLength(medtronicDeviceType: MedtronicDeviceType?): Int { + fun getTotalLength(medtronicDeviceType: MedtronicDeviceType): Int { return if (hasSpecialRules) { getHeadLength(medtronicDeviceType) + getBodyLength(medtronicDeviceType) + dateLength } else { @@ -220,10 +220,6 @@ enum class PumpHistoryEntryType // implements CodeEnum } } - // private fun hasSpecialRules(): Boolean { - // return hasSpecialRules - // } - fun addSpecialRuleHead(rule: SpecialRule) { if (isEmpty(specialRulesHead)) { specialRulesHead = ArrayList() @@ -244,7 +240,7 @@ enum class PumpHistoryEntryType // implements CodeEnum // return description ?: name // } - fun getHeadLength(medtronicDeviceType: MedtronicDeviceType?): Int { + fun getHeadLength(medtronicDeviceType: MedtronicDeviceType): Int { return if (hasSpecialRules) { if (isNotEmpty(specialRulesHead)) { determineSizeByRule(medtronicDeviceType, headLength, specialRulesHead) @@ -256,7 +252,7 @@ enum class PumpHistoryEntryType // implements CodeEnum } } - fun getBodyLength(medtronicDeviceType: MedtronicDeviceType?): Int { + fun getBodyLength(medtronicDeviceType: MedtronicDeviceType): Int { return if (hasSpecialRules) { if (isNotEmpty(specialRulesBody)) { determineSizeByRule(medtronicDeviceType, bodyLength, specialRulesBody) @@ -277,7 +273,7 @@ enum class PumpHistoryEntryType // implements CodeEnum } // byte[] dh = { 2, 3 }; - private fun determineSizeByRule(medtronicDeviceType: MedtronicDeviceType?, defaultValue: Int, rules: List?): Int { + private fun determineSizeByRule(medtronicDeviceType: MedtronicDeviceType, defaultValue: Int, rules: List?): Int { var size = defaultValue for (rule in rules!!) { if (MedtronicDeviceType.isSameDevice(medtronicDeviceType, rule.deviceType)) { diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryResult.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryResult.kt index 0ab0e7e05e..b772119de8 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryResult.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryResult.kt @@ -4,6 +4,7 @@ import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil import java.util.* +import kotlin.collections.ArrayList /** * History page contains data, sorted from newest to oldest (0=newest..n=oldest) @@ -18,9 +19,11 @@ class PumpHistoryResult(private val aapsLogger: AAPSLogger, searchEntry: PumpHis private val searchEntry: PumpHistoryEntry? = null private var searchDate: Long? = null private var searchType = SearchType.None - @JvmField var unprocessedEntries: List? = null - @JvmField var validEntries: MutableList? - fun addHistoryEntries(entries: List?, page: Int) { + var unprocessedEntries: List = ArrayList() + var validEntries: MutableList = ArrayList() + + + fun addHistoryEntries(entries: List, page: Int) { unprocessedEntries = entries //aapsLogger.debug(LTag.PUMPCOMM,"PumpHistoryResult. Unprocessed entries: {}", MedtronicUtil.getGsonInstance().toJson(entries)); processEntries() @@ -32,7 +35,7 @@ class PumpHistoryResult(private val aapsLogger: AAPSLogger, searchEntry: PumpHis Collections.reverse(unprocessedEntries) when (searchType) { SearchType.None -> //aapsLogger.debug(LTag.PUMPCOMM,"PE. None search"); - validEntries!!.addAll(unprocessedEntries!!) + validEntries.addAll(unprocessedEntries) SearchType.LastEntry -> { aapsLogger.debug(LTag.PUMPCOMM, "PE. Last entry search") @@ -40,27 +43,27 @@ class PumpHistoryResult(private val aapsLogger: AAPSLogger, searchEntry: PumpHis //Collections.sort(this.unprocessedEntries, new PumpHistoryEntry.Comparator()); aapsLogger.debug(LTag.PUMPCOMM, "PE. PumpHistoryResult. Search entry date: " + searchEntry!!.atechDateTime) val date = searchEntry.atechDateTime - for (unprocessedEntry in unprocessedEntries!!) { - if (unprocessedEntry!!.equals(searchEntry)) { + for (unprocessedEntry in unprocessedEntries) { + if (unprocessedEntry.equals(searchEntry)) { //aapsLogger.debug(LTag.PUMPCOMM,"PE. Item found {}.", unprocessedEntry); isSearchFinished = true break } //aapsLogger.debug(LTag.PUMPCOMM,"PE. Entry {} added.", unprocessedEntry); - validEntries!!.add(unprocessedEntry) + validEntries.add(unprocessedEntry) } } SearchType.Date -> { aapsLogger.debug(LTag.PUMPCOMM, "PE. Date search: Search date: " + searchDate) - for (unprocessedEntry in unprocessedEntries!!) { - if (unprocessedEntry!!.atechDateTime == null || unprocessedEntry.atechDateTime == 0L) { + for (unprocessedEntry in unprocessedEntries) { + if (unprocessedEntry.atechDateTime == null || unprocessedEntry.atechDateTime == 0L) { aapsLogger.debug(LTag.PUMPCOMM, "PE. PumpHistoryResult. Search entry date: Entry with no date: $unprocessedEntry") continue } if (unprocessedEntry.isAfter(searchDate!!)) { - validEntries!!.add(unprocessedEntry) + validEntries.add(unprocessedEntry) } else { // aapsLogger.debug(LTag.PUMPCOMM,"PE. PumpHistoryResult. Not after.. Unprocessed Entry [year={},entry={}]", // DateTimeUtil.getYear(unprocessedEntry.atechDateTime), unprocessedEntry); @@ -85,35 +88,19 @@ class PumpHistoryResult(private val aapsLogger: AAPSLogger, searchEntry: PumpHis ", searchType=" + searchType + // ", searchFinished=" + isSearchFinished + // "]" - }// PumpHistoryEntry pumpHistoryEntry = this.validEntries.get(0); - // - // if (pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.EndResultTotals) - // return pumpHistoryEntry; - // else - // return this.validEntries.get(1); + } /** * Return latest entry (entry with highest date time) - * * @return */ val latestEntry: PumpHistoryEntry? - get() = if (validEntries == null || validEntries!!.size == 0) null else { - validEntries!![0] - // PumpHistoryEntry pumpHistoryEntry = this.validEntries.get(0); - // - // if (pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.EndResultTotals) - // return pumpHistoryEntry; - // else - // return this.validEntries.get(1); - } + get() = if (validEntries.size == 0) null else validEntries[0] - val isSearchRequired: Boolean - get() = searchType != SearchType.None - fun getValidEntries(): List? { - return validEntries - } + // val isSearchRequired: Boolean + // get() = searchType != SearchType.None + internal enum class SearchType { None, // @@ -139,6 +126,6 @@ class PumpHistoryResult(private val aapsLogger: AAPSLogger, searchEntry: PumpHis } // this.unprocessedEntries = new ArrayList<>(); - validEntries = ArrayList() + //validEntries = ArrayList() } } \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/PumpMessage.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/PumpMessage.kt index 3683f4e7c5..166a668d3e 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/PumpMessage.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/message/PumpMessage.kt @@ -67,13 +67,13 @@ class PumpMessage : RLMessage { override fun getTxData(): ByteArray { var rval = ByteUtil.concat(byteArrayOf(packetType!!.value), address) - rval = ByteUtil.concat(rval, commandType!!.getCommandCode()) + rval = ByteUtil.concat(rval, commandType!!.commandCode) rval = ByteUtil.concat(rval, messageBody!!.txData) return rval } val contents: ByteArray - get() = ByteUtil.concat(byteArrayOf(commandType!!.getCommandCode()), messageBody!!.txData)// length is not always correct so, we check whole array if we have + get() = ByteUtil.concat(byteArrayOf(commandType!!.commandCode), messageBody!!.txData)// length is not always correct so, we check whole array if we have // data, after length // check if displayed length is invalid @@ -91,7 +91,7 @@ class PumpMessage : RLMessage { val data = messageBody!!.txData var length = ByteUtil.asUINT8(data!![0]) // length is not always correct so, we check whole array if we have // data, after length - val originalLength = length + //val originalLength = length // check if displayed length is invalid if (length > data.size - 1) { diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUIComm.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUIComm.java deleted file mode 100644 index 0eed54e71f..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUIComm.java +++ /dev/null @@ -1,58 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.ui; - -import dagger.android.HasAndroidInjector; -import info.nightscout.androidaps.logging.AAPSLogger; -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; - -/** - * Created by andy on 6/14/18. - */ -public class MedtronicUIComm { - - private final HasAndroidInjector injector; - private final AAPSLogger aapsLogger; - private final MedtronicUtil medtronicUtil; - private final MedtronicCommunicationManager medtronicCommunicationManager; - private final MedtronicUIPostprocessor medtronicUIPostprocessor; - - public MedtronicUIComm( - HasAndroidInjector injector, - AAPSLogger aapsLogger, - MedtronicUtil medtronicUtil, - MedtronicUIPostprocessor medtronicUIPostprocessor, - MedtronicCommunicationManager medtronicCommunicationManager - ) { - this.injector = injector; - this.aapsLogger = aapsLogger; - this.medtronicUtil = medtronicUtil; - this.medtronicUIPostprocessor = medtronicUIPostprocessor; - this.medtronicCommunicationManager = medtronicCommunicationManager; - } - - public synchronized MedtronicUITask executeCommand(MedtronicCommandType commandType, Object... parameters) { - - aapsLogger.info(LTag.PUMP, "Execute Command: " + commandType.name()); - - MedtronicUITask task = new MedtronicUITask(injector, commandType, parameters); - - medtronicUtil.setCurrentCommand(commandType); - - task.execute(medtronicCommunicationManager); - - if (!task.isReceived()) { - aapsLogger.warn(LTag.PUMP, "Reply not received for " + commandType); - } - - task.postProcess(medtronicUIPostprocessor); - - return task; - - } - - public int getInvalidResponsesCount() { - return medtronicCommunicationManager.getNotConnectedCount(); - } -} \ No newline at end of file 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 new file mode 100644 index 0000000000..4cdb5766ec --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUIComm.kt @@ -0,0 +1,44 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.ui + +import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.logging.AAPSLogger +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 + +/** + * 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 +) { + + fun executeCommand(commandType: MedtronicCommandType): MedtronicUITask { + return executeCommand(commandType, null) + } + + @Synchronized + fun executeCommand(commandType: MedtronicCommandType, parameters: List?): MedtronicUITask { + + aapsLogger.info(LTag.PUMP, "Execute Command: " + commandType.name) + val task = MedtronicUITask(injector, commandType, parameters) + medtronicUtil.setCurrentCommand(commandType) + task.execute(medtronicCommunicationManager) + + if (!task.isReceived) { + aapsLogger.warn(LTag.PUMP, "Reply not received for $commandType") + } + + task.postProcess(medtronicUIPostprocessor) + return task + } + + val invalidResponsesCount: Int + get() = medtronicCommunicationManager.notConnectedCount + +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUIPostprocessor.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUIPostprocessor.java deleted file mode 100644 index 8022384731..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUIPostprocessor.java +++ /dev/null @@ -1,252 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.ui; - -import org.joda.time.DateTimeZone; -import org.joda.time.Duration; - -import java.util.Date; -import java.util.Locale; -import java.util.Map; - -import javax.inject.Inject; -import javax.inject.Singleton; - -import info.nightscout.androidaps.logging.AAPSLogger; -import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.plugins.bus.RxBusWrapper; -import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicPumpPlugin; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BasalProfile; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BatteryStatusDTO; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.ClockDTO; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.PumpSettingDTO; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.BasalProfileStatus; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicNotificationType; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicUIResponseType; -import info.nightscout.androidaps.plugins.pump.medtronic.driver.MedtronicPumpStatus; -import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil; -import info.nightscout.androidaps.utils.resources.ResourceHelper; - - -/** - * Created by andy on 6/15/18. - */ - -@Singleton -public class MedtronicUIPostprocessor { - - private final AAPSLogger aapsLogger; - private final RxBusWrapper rxBus; - private final ResourceHelper resourceHelper; - private final MedtronicUtil medtronicUtil; - private final MedtronicPumpStatus medtronicPumpStatus; - private final MedtronicPumpPlugin medtronicPumpPlugin; - - @Inject - public MedtronicUIPostprocessor( - AAPSLogger aapsLogger, - RxBusWrapper rxBus, - ResourceHelper resourceHelper, - MedtronicUtil medtronicUtil, - MedtronicPumpStatus medtronicPumpStatus, - MedtronicPumpPlugin medtronicPumpPlugin) { - this.aapsLogger = aapsLogger; - this.rxBus = rxBus; - this.resourceHelper = resourceHelper; - this.medtronicUtil = medtronicUtil; - this.medtronicPumpStatus = medtronicPumpStatus; - this.medtronicPumpPlugin = medtronicPumpPlugin; - } - - - // this is mostly intended for command that return certain statuses (Remaining Insulin, ...), and - // where responses won't be directly used - void postProcessData(MedtronicUITask uiTask) { - - switch (uiTask.commandType) { - - case SetBasalProfileSTD: { - Boolean response = (Boolean) uiTask.returnData; - - if (response) { - BasalProfile basalProfile = (BasalProfile) uiTask.getParameter(0); - - medtronicPumpStatus.basalsByHour = basalProfile.getProfilesByHour(medtronicPumpPlugin.getPumpDescription().getPumpType()); - } - } - break; - - case GetBasalProfileSTD: { - BasalProfile basalProfile = (BasalProfile) uiTask.returnData; - - try { - Double[] profilesByHour = basalProfile.getProfilesByHour(medtronicPumpPlugin.getPumpDescription().getPumpType()); - - if (profilesByHour != null) { - medtronicPumpStatus.basalsByHour = profilesByHour; - medtronicPumpStatus.basalProfileStatus = BasalProfileStatus.ProfileOK; - } else { - uiTask.responseType = MedtronicUIResponseType.Error; - uiTask.errorDescription = "No profile found."; - aapsLogger.error(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Basal Profile was NOT valid. [%s]", basalProfile.basalProfileToStringError())); - } - } catch (Exception ex) { - aapsLogger.error(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Basal Profile was returned, but was invalid. [%s]", basalProfile.basalProfileToStringError())); - uiTask.responseType = MedtronicUIResponseType.Error; - uiTask.errorDescription = "No profile found."; - } - } - break; - - case SetBolus: { - medtronicPumpStatus.lastBolusAmount = uiTask.getDoubleFromParameters(0); - medtronicPumpStatus.lastBolusTime = new Date(); - } - break; - - case GetRemainingInsulin: { - medtronicPumpStatus.reservoirRemainingUnits = (Float) uiTask.returnData; - } - break; - - case CancelTBR: { - medtronicPumpStatus.tempBasalStart = null; - medtronicPumpStatus.tempBasalAmount = null; - medtronicPumpStatus.tempBasalLength = null; - } - break; - - case GetRealTimeClock: { - processTime(uiTask); - } - break; - - case SetRealTimeClock: { - boolean response = (Boolean) uiTask.returnData; - - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "New time was %s set.", response ? "" : "NOT")); - - if (response) { - medtronicUtil.getPumpTime().timeDifference = 0; - } - } - break; - - - case GetBatteryStatus: { - BatteryStatusDTO batteryStatusDTO = (BatteryStatusDTO) uiTask.returnData; - - medtronicPumpStatus.batteryRemaining = batteryStatusDTO.getCalculatedPercent(medtronicPumpStatus.batteryType); - - if (batteryStatusDTO.voltage != null) { - medtronicPumpStatus.batteryVoltage = batteryStatusDTO.voltage; - } - - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "BatteryStatus: %s", batteryStatusDTO.toString())); - - } - break; - - case PumpModel: { - if (medtronicPumpStatus.medtronicDeviceType != medtronicUtil.getMedtronicPumpModel()) { - aapsLogger.warn(LTag.PUMP, "Configured pump is different then pump detected !"); - medtronicUtil.sendNotification(MedtronicNotificationType.PumpTypeNotSame, resourceHelper, rxBus); - } - } - break; - - case Settings_512: - case Settings: { - postProcessSettings(uiTask); - } - break; - - // no postprocessing - - default: - break; - //aapsLogger.error(LTag.PUMP, "Post-processing not implemented for {}.", uiTask.commandType.name()); - - } - - } - - - private void processTime(MedtronicUITask uiTask) { - - ClockDTO clockDTO = (ClockDTO) uiTask.returnData; - - Duration dur = new Duration(clockDTO.pumpTime.toDateTime(DateTimeZone.UTC), - clockDTO.localDeviceTime.toDateTime(DateTimeZone.UTC)); - - clockDTO.timeDifference = (int) dur.getStandardSeconds(); - - medtronicUtil.setPumpTime(clockDTO); - - aapsLogger.debug(LTag.PUMP, "Pump Time: " + clockDTO.localDeviceTime + ", DeviceTime=" + clockDTO.pumpTime + // - ", diff: " + dur.getStandardSeconds() + " s"); - -// if (dur.getStandardMinutes() >= 10) { -// if (isLogEnabled()) -// LOG.warn("Pump clock needs update, pump time: " + clockDTO.pumpTime.toString("HH:mm:ss") + " (difference: " -// + dur.getStandardSeconds() + " s)"); -// sendNotification(MedtronicNotificationType.PumpWrongTimeUrgent); -// } else if (dur.getStandardMinutes() >= 4) { -// if (isLogEnabled()) -// LOG.warn("Pump clock needs update, pump time: " + clockDTO.pumpTime.toString("HH:mm:ss") + " (difference: " -// + dur.getStandardSeconds() + " s)"); -// sendNotification(MedtronicNotificationType.PumpWrongTimeNormal); -// } - - } - - - private void postProcessSettings(MedtronicUITask uiTask) { - - Map settings = (Map) uiTask.returnData; - - medtronicUtil.setSettings(settings); - - PumpSettingDTO checkValue; - - medtronicPumpPlugin.getRileyLinkService().verifyConfiguration(); - - // check profile - if (!"Yes".equals(settings.get("PCFG_BASAL_PROFILES_ENABLED").value)) { - aapsLogger.error(LTag.PUMP, "Basal profiles are not enabled on pump."); - medtronicUtil.sendNotification(MedtronicNotificationType.PumpBasalProfilesNotEnabled, resourceHelper, rxBus); - - } else { - checkValue = settings.get("PCFG_ACTIVE_BASAL_PROFILE"); - - if (!"STD".equals(checkValue.value)) { - aapsLogger.error("Basal profile set on pump is incorrect (must be STD)."); - medtronicUtil.sendNotification(MedtronicNotificationType.PumpIncorrectBasalProfileSelected, resourceHelper, rxBus); - } - } - - // TBR - - checkValue = settings.get("PCFG_TEMP_BASAL_TYPE"); - - if (!"Units".equals(checkValue.value)) { - aapsLogger.error("Wrong TBR type set on pump (must be Absolute)."); - medtronicUtil.sendNotification(MedtronicNotificationType.PumpWrongTBRTypeSet, resourceHelper, rxBus); - } - - // MAXes - - checkValue = settings.get("PCFG_MAX_BOLUS"); - - if (!MedtronicUtil.isSame(Double.parseDouble(checkValue.value), medtronicPumpStatus.maxBolus)) { - aapsLogger.error(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Wrong Max Bolus set on Pump (current=%s, required=%.2f).", checkValue.value, medtronicPumpStatus.maxBolus)); - medtronicUtil.sendNotification(MedtronicNotificationType.PumpWrongMaxBolusSet, resourceHelper, rxBus, medtronicPumpStatus.maxBolus); - } - - checkValue = settings.get("PCFG_MAX_BASAL"); - - if (!MedtronicUtil.isSame(Double.parseDouble(checkValue.value), medtronicPumpStatus.maxBasal)) { - aapsLogger.error(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Wrong Max Basal set on Pump (current=%s, required=%.2f).", checkValue.value, medtronicPumpStatus.maxBasal)); - medtronicUtil.sendNotification(MedtronicNotificationType.PumpWrongMaxBasalSet, resourceHelper, rxBus, medtronicPumpStatus.maxBasal); - } - - } -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUIPostprocessor.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUIPostprocessor.kt new file mode 100644 index 0000000000..21945e1707 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUIPostprocessor.kt @@ -0,0 +1,188 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.ui + +import info.nightscout.androidaps.interfaces.PumpDescription +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.bus.RxBusWrapper +import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicPumpPlugin +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BasalProfile +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BatteryStatusDTO +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.ClockDTO +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.PumpSettingDTO +import info.nightscout.androidaps.plugins.pump.medtronic.defs.BasalProfileStatus +import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicCommandType +import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicNotificationType +import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicUIResponseType +import info.nightscout.androidaps.plugins.pump.medtronic.driver.MedtronicPumpStatus +import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil +import info.nightscout.androidaps.utils.resources.ResourceHelper +import org.joda.time.DateTimeZone +import org.joda.time.Duration +import java.util.* +import javax.inject.Inject +import javax.inject.Singleton + +/** + * Created by andy on 6/15/18. + */ +@Singleton +class MedtronicUIPostprocessor @Inject constructor( + private val aapsLogger: AAPSLogger, + private val rxBus: RxBusWrapper, + private val resourceHelper: ResourceHelper, + private val medtronicUtil: MedtronicUtil, + private val medtronicPumpStatus: MedtronicPumpStatus, + private val medtronicPumpPlugin: MedtronicPumpPlugin) { + + // this is mostly intended for command that return certain statuses (Remaining Insulin, ...), and + // where responses won't be directly used + fun postProcessData(uiTask: MedtronicUITask) { + when (uiTask.commandType) { + MedtronicCommandType.SetBasalProfileSTD -> { + val response = uiTask.result as Boolean? + if (response!!) { + val basalProfile = uiTask.getParameter(0) as BasalProfile + aapsLogger.debug("D: basal profile returned after set: $basalProfile") + + //var desc: PumpDescription = medtronicPumpPlugin.getP.getPumpDescription() + + medtronicPumpStatus.basalsByHour = basalProfile.getProfilesByHour(medtronicPumpPlugin.pumpDescription.pumpType) + } + } + + MedtronicCommandType.GetBasalProfileSTD -> { + val basalProfile = uiTask.result as BasalProfile? + + //aapsLogger.debug("D: basal profile on read: " + basalProfile); + try { + val profilesByHour = basalProfile!!.getProfilesByHour(medtronicPumpPlugin.pumpDescription.pumpType) + if (profilesByHour != null) { + medtronicPumpStatus.basalsByHour = profilesByHour + medtronicPumpStatus.basalProfileStatus = BasalProfileStatus.ProfileOK + //aapsLogger.debug("D: basal profile on read: basalsByHour: " + BasalProfile.getProfilesByHourToString(medtronicPumpStatus.basalsByHour)); + } else { + uiTask.responseType = MedtronicUIResponseType.Error + uiTask.errorDescription = "No profile found." + aapsLogger.error(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Basal Profile was NOT valid. [%s]", basalProfile.basalProfileToStringError())) + } + } catch (ex: Exception) { + aapsLogger.error(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Basal Profile was returned, but was invalid. [%s]", basalProfile!!.basalProfileToStringError())) + uiTask.responseType = MedtronicUIResponseType.Error + uiTask.errorDescription = "No profile found." + } + } + + MedtronicCommandType.SetBolus -> { + medtronicPumpStatus.lastBolusAmount = uiTask.getDoubleFromParameters(0) + medtronicPumpStatus.lastBolusTime = Date() + } + + MedtronicCommandType.GetRemainingInsulin -> { + medtronicPumpStatus.reservoirRemainingUnits = uiTask.result as Double + } + + MedtronicCommandType.CancelTBR -> { + medtronicPumpStatus.tempBasalStart = null + medtronicPumpStatus.tempBasalAmount = null + medtronicPumpStatus.tempBasalLength = null + } + + MedtronicCommandType.GetRealTimeClock -> { + processTime(uiTask) + } + + MedtronicCommandType.SetRealTimeClock -> { + val response = uiTask.result as Boolean + aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "New time was %s set.", if (response) "" else "NOT")) + if (response) { + medtronicUtil.pumpTime!!.timeDifference = 0 + } + } + + MedtronicCommandType.GetBatteryStatus -> { + val batteryStatusDTO = uiTask.result as BatteryStatusDTO? + medtronicPumpStatus.batteryRemaining = batteryStatusDTO!!.getCalculatedPercent(medtronicPumpStatus.batteryType) + if (batteryStatusDTO.voltage != null) { + medtronicPumpStatus.batteryVoltage = batteryStatusDTO.voltage + } + aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "BatteryStatus: %s", batteryStatusDTO.toString())) + } + + MedtronicCommandType.PumpModel -> { + if (medtronicPumpStatus.medtronicDeviceType !== medtronicUtil.medtronicPumpModel) { + aapsLogger.warn(LTag.PUMP, "Configured pump is different then pump detected !") + medtronicUtil.sendNotification(MedtronicNotificationType.PumpTypeNotSame, resourceHelper, rxBus) + } + } + + MedtronicCommandType.Settings_512, + MedtronicCommandType.Settings -> { + postProcessSettings(uiTask) + } + + else -> { + } + } + } + + private fun processTime(uiTask: MedtronicUITask) { + val clockDTO = uiTask.result as ClockDTO? + val dur = Duration(clockDTO!!.pumpTime!!.toDateTime(DateTimeZone.UTC), + clockDTO.localDeviceTime!!.toDateTime(DateTimeZone.UTC)) + clockDTO.timeDifference = dur.standardSeconds.toInt() + medtronicUtil.pumpTime = clockDTO + aapsLogger.debug(LTag.PUMP, "Pump Time: " + clockDTO.localDeviceTime + ", DeviceTime=" + clockDTO.pumpTime + // + ", diff: " + dur.standardSeconds + " s") + +// if (dur.getStandardMinutes() >= 10) { +// if (isLogEnabled()) +// LOG.warn("Pump clock needs update, pump time: " + clockDTO.pumpTime.toString("HH:mm:ss") + " (difference: " +// + dur.getStandardSeconds() + " s)"); +// sendNotification(MedtronicNotificationType.PumpWrongTimeUrgent); +// } else if (dur.getStandardMinutes() >= 4) { +// if (isLogEnabled()) +// LOG.warn("Pump clock needs update, pump time: " + clockDTO.pumpTime.toString("HH:mm:ss") + " (difference: " +// + dur.getStandardSeconds() + " s)"); +// sendNotification(MedtronicNotificationType.PumpWrongTimeNormal); +// } + } + + private fun postProcessSettings(uiTask: MedtronicUITask) { + val settings = uiTask.result as Map? + medtronicUtil.settings = settings + var checkValue: PumpSettingDTO? + medtronicPumpPlugin.rileyLinkService!!.verifyConfiguration() + + // check profile + if ("Yes" != settings!!["PCFG_BASAL_PROFILES_ENABLED"]!!.value) { + aapsLogger.error(LTag.PUMP, "Basal profiles are not enabled on pump.") + medtronicUtil.sendNotification(MedtronicNotificationType.PumpBasalProfilesNotEnabled, resourceHelper, rxBus) + } else { + checkValue = settings["PCFG_ACTIVE_BASAL_PROFILE"] + if ("STD" != checkValue!!.value) { + aapsLogger.error("Basal profile set on pump is incorrect (must be STD).") + medtronicUtil.sendNotification(MedtronicNotificationType.PumpIncorrectBasalProfileSelected, resourceHelper, rxBus) + } + } + + // TBR + checkValue = settings["PCFG_TEMP_BASAL_TYPE"] + if ("Units" != checkValue!!.value) { + aapsLogger.error("Wrong TBR type set on pump (must be Absolute).") + medtronicUtil.sendNotification(MedtronicNotificationType.PumpWrongTBRTypeSet, resourceHelper, rxBus) + } + + // MAXes + checkValue = settings["PCFG_MAX_BOLUS"] + if (!MedtronicUtil.isSame(checkValue!!.value.toDouble(), medtronicPumpStatus.maxBolus!!)) { + aapsLogger.error(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Wrong Max Bolus set on Pump (current=%s, required=%.2f).", checkValue.value, medtronicPumpStatus.maxBolus)) + medtronicUtil.sendNotification(MedtronicNotificationType.PumpWrongMaxBolusSet, resourceHelper, rxBus, medtronicPumpStatus.maxBolus) + } + checkValue = settings["PCFG_MAX_BASAL"] + if (!MedtronicUtil.isSame(checkValue!!.value.toDouble(), medtronicPumpStatus.maxBasal!!)) { + aapsLogger.error(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Wrong Max Basal set on Pump (current=%s, required=%.2f).", checkValue.value, medtronicPumpStatus.maxBasal)) + medtronicUtil.sendNotification(MedtronicNotificationType.PumpWrongMaxBasalSet, resourceHelper, rxBus, medtronicPumpStatus.maxBasal) + } + } + +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUITask.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUITask.java deleted file mode 100644 index f8ef1ee190..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUITask.java +++ /dev/null @@ -1,234 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.ui; - -import org.joda.time.LocalDateTime; - -import java.util.Locale; - -import javax.inject.Inject; - -import dagger.android.HasAndroidInjector; -import info.nightscout.androidaps.logging.AAPSLogger; -import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.plugins.bus.RxBusWrapper; -import info.nightscout.androidaps.plugins.pump.common.defs.PumpDeviceState; -import info.nightscout.androidaps.plugins.pump.common.events.EventRileyLinkDeviceStatusChange; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.MedtronicCommunicationManager; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntry; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BasalProfile; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.TempBasalPair; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicCommandType; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicUIResponseType; -import info.nightscout.androidaps.plugins.pump.medtronic.driver.MedtronicPumpStatus; -import info.nightscout.androidaps.plugins.pump.medtronic.events.EventMedtronicPumpValuesChanged; -import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil; - -/** - * Created by andy on 6/14/18. - */ - -public class MedtronicUITask { - - @Inject RxBusWrapper rxBus; - @Inject AAPSLogger aapsLogger; - @Inject MedtronicPumpStatus medtronicPumpStatus; - @Inject MedtronicUtil medtronicUtil; - - private final HasAndroidInjector injector; - - public MedtronicCommandType commandType; - public Object returnData; - String errorDescription; - // boolean invalid = false; - private Object[] parameters; - // private boolean received; - MedtronicUIResponseType responseType; - - - public MedtronicUITask(HasAndroidInjector injector, MedtronicCommandType commandType) { - this.injector = injector; - this.injector.androidInjector().inject(this); - this.commandType = commandType; - } - - - public MedtronicUITask(HasAndroidInjector injector, MedtronicCommandType commandType, Object... parameters) { - this.injector = injector; - this.injector.androidInjector().inject(this); - this.commandType = commandType; - this.parameters = parameters; - } - - - public void execute(MedtronicCommunicationManager communicationManager) { - - aapsLogger.debug(LTag.PUMP, "MedtronicUITask: @@@ In execute. " + commandType); - - switch (commandType) { - case PumpModel: { - returnData = communicationManager.getPumpModel(); - } - break; - - case GetBasalProfileSTD: { - returnData = communicationManager.getBasalProfile(); - } - break; - - case GetRemainingInsulin: { - returnData = communicationManager.getRemainingInsulin(); - } - break; - - case GetRealTimeClock: { - returnData = communicationManager.getPumpTime(); - medtronicUtil.setPumpTime(null); - } - break; - - case SetRealTimeClock: { - returnData = communicationManager.setPumpTime(); - } - break; - - case GetBatteryStatus: { - returnData = communicationManager.getRemainingBattery(); - } - break; - - case SetTemporaryBasal: { - TempBasalPair tbr = getTBRSettings(); - if (tbr != null) { - returnData = communicationManager.setTBR(tbr); - } - } - break; - - case ReadTemporaryBasal: { - returnData = communicationManager.getTemporaryBasal(); - } - break; - - - case Settings: - case Settings_512: { - returnData = communicationManager.getPumpSettings(); - } - break; - - case SetBolus: { - Double amount = getDoubleFromParameters(0); - - if (amount != null) - returnData = communicationManager.setBolus(amount); - } - break; - - case CancelTBR: { - returnData = communicationManager.cancelTBR(); - } - break; - - case SetBasalProfileSTD: - case SetBasalProfileA: { - BasalProfile profile = (BasalProfile) parameters[0]; - - returnData = communicationManager.setBasalProfile(profile); - } - break; - - case GetHistoryData: { - returnData = communicationManager.getPumpHistory((PumpHistoryEntry) parameters[0], - (LocalDateTime) parameters[1]); - } - break; - - default: { - aapsLogger.warn(LTag.PUMP, String.format(Locale.ENGLISH, "This commandType is not supported (yet) - %s.", commandType)); - // invalid = true; - responseType = MedtronicUIResponseType.Invalid; - } - - } - - if (responseType == null) { - if (returnData == null) { - errorDescription = communicationManager.getErrorResponse(); - this.responseType = MedtronicUIResponseType.Error; - } else { - this.responseType = MedtronicUIResponseType.Data; - } - } - - } - - - private TempBasalPair getTBRSettings() { - return new TempBasalPair(getDoubleFromParameters(0), // - false, // - getIntegerFromParameters(1)); - } - - - private Float getFloatFromParameters(int index) { - return (Float) parameters[index]; - } - - - Double getDoubleFromParameters(int index) { - return (Double) parameters[index]; - } - - - private Integer getIntegerFromParameters(int index) { - return (Integer) parameters[index]; - } - - - public Object getResult() { - return returnData; - } - - - public boolean isReceived() { - return (returnData != null || errorDescription != null); - } - - - void postProcess(MedtronicUIPostprocessor postprocessor) { - - aapsLogger.debug(LTag.PUMP, "MedtronicUITask: @@@ In execute. " + commandType); - - if (responseType == MedtronicUIResponseType.Data) { - postprocessor.postProcessData(this); - } - - if (responseType == MedtronicUIResponseType.Invalid) { - rxBus.send(new EventRileyLinkDeviceStatusChange(PumpDeviceState.ErrorWhenCommunicating, - "Unsupported command in MedtronicUITask")); - } else if (responseType == MedtronicUIResponseType.Error) { - rxBus.send(new EventRileyLinkDeviceStatusChange(PumpDeviceState.ErrorWhenCommunicating, - errorDescription)); - } else { - rxBus.send(new EventMedtronicPumpValuesChanged()); - medtronicPumpStatus.setLastCommunicationToNow(); - } - - medtronicUtil.setCurrentCommand(null); - } - - - public boolean hasData() { - return (responseType == MedtronicUIResponseType.Data); - } - - - Object getParameter(int index) { - return parameters[index]; - } - - - public MedtronicUIResponseType getResponseType() { - return this.responseType; - } - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUITask.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUITask.kt new file mode 100644 index 0000000000..815ca14549 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUITask.kt @@ -0,0 +1,178 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.ui + +import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.bus.RxBusWrapper +import info.nightscout.androidaps.plugins.pump.common.defs.PumpDeviceState +import info.nightscout.androidaps.plugins.pump.common.events.EventRileyLinkDeviceStatusChange +import info.nightscout.androidaps.plugins.pump.medtronic.comm.MedtronicCommunicationManager +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntry +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BasalProfile +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.TempBasalPair +import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicCommandType +import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicUIResponseType +import info.nightscout.androidaps.plugins.pump.medtronic.driver.MedtronicPumpStatus +import info.nightscout.androidaps.plugins.pump.medtronic.events.EventMedtronicPumpValuesChanged +import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil +import org.joda.time.LocalDateTime +import java.util.* +import javax.inject.Inject + +/** + * Created by andy on 6/14/18. + */ +class MedtronicUITask { + + @Inject lateinit var rxBus: RxBusWrapper + @Inject lateinit var aapsLogger: AAPSLogger + @Inject lateinit var medtronicPumpStatus: MedtronicPumpStatus + @Inject lateinit var medtronicUtil: MedtronicUtil + + private val injector: HasAndroidInjector + var commandType: MedtronicCommandType + var result: Any? = null + var errorDescription: String? = null + var parameters: List? = null + var responseType: MedtronicUIResponseType? = null + + constructor(injector: HasAndroidInjector, commandType: MedtronicCommandType) { + this.injector = injector + this.injector.androidInjector().inject(this) + this.commandType = commandType + } + + constructor(injector: HasAndroidInjector, commandType: MedtronicCommandType, parameters: List?) { + this.injector = injector + this.injector.androidInjector().inject(this) + this.commandType = commandType + this.parameters = parameters //as Array + } + + fun execute(communicationManager: MedtronicCommunicationManager) { + aapsLogger.debug(LTag.PUMP, "MedtronicUITask: @@@ In execute. $commandType") + when (commandType) { + MedtronicCommandType.PumpModel -> { + result = communicationManager.pumpModel + } + + MedtronicCommandType.GetBasalProfileSTD -> { + result = communicationManager.basalProfile + } + + MedtronicCommandType.GetRemainingInsulin -> { + result = communicationManager.remainingInsulin + } + + MedtronicCommandType.GetRealTimeClock -> { + result = communicationManager.pumpTime + medtronicUtil.pumpTime = null + } + + MedtronicCommandType.SetRealTimeClock -> { + result = communicationManager.setPumpTime() + } + + MedtronicCommandType.GetBatteryStatus -> { + result = communicationManager.remainingBattery + } + + MedtronicCommandType.SetTemporaryBasal -> { + val tbr = tBRSettings + if (tbr != null) { + result = communicationManager.setTBR(tbr) + } + } + + MedtronicCommandType.ReadTemporaryBasal -> { + result = communicationManager.temporaryBasal + } + + MedtronicCommandType.Settings, MedtronicCommandType.Settings_512 -> { + result = communicationManager.pumpSettings + } + + MedtronicCommandType.SetBolus -> { + val amount = getDoubleFromParameters(0) + if (amount != null) result = communicationManager.setBolus(amount) + } + + MedtronicCommandType.CancelTBR -> { + result = communicationManager.cancelTBR() + } + + MedtronicCommandType.SetBasalProfileSTD, MedtronicCommandType.SetBasalProfileA -> { + val profile = parameters!![0] as BasalProfile + result = communicationManager.setBasalProfile(profile) + } + + MedtronicCommandType.GetHistoryData -> { + result = communicationManager.getPumpHistory(parameters!![0] as PumpHistoryEntry?, + parameters!![1] as LocalDateTime?) + } + + else -> { + aapsLogger.warn(LTag.PUMP, String.format(Locale.ENGLISH, "This commandType is not supported (yet) - %s.", commandType)) + // invalid = true; + responseType = MedtronicUIResponseType.Invalid + } + } + if (responseType == null) { + if (result == null) { + errorDescription = communicationManager.errorResponse + responseType = MedtronicUIResponseType.Error + } else { + responseType = MedtronicUIResponseType.Data + } + } + } + + // + // + private val tBRSettings: TempBasalPair + private get() = TempBasalPair(getDoubleFromParameters(0), // + false, // + getIntegerFromParameters(1)) + + private fun getFloatFromParameters(index: Int): Float { + return parameters!![index] as Float + } + + fun getDoubleFromParameters(index: Int): Double { + return parameters!![index] as Double + } + + private fun getIntegerFromParameters(index: Int): Int { + return parameters!![index] as Int + } + + val isReceived: Boolean + get() = result != null || errorDescription != null + + fun postProcess(postprocessor: MedtronicUIPostprocessor) { + aapsLogger.debug(LTag.PUMP, "MedtronicUITask: @@@ In execute. $commandType") + if (responseType === MedtronicUIResponseType.Data) { + postprocessor.postProcessData(this) + } + if (responseType === MedtronicUIResponseType.Invalid) { + rxBus.send(EventRileyLinkDeviceStatusChange(PumpDeviceState.ErrorWhenCommunicating, + "Unsupported command in MedtronicUITask")) + } else if (responseType === MedtronicUIResponseType.Error) { + rxBus.send(EventRileyLinkDeviceStatusChange(PumpDeviceState.ErrorWhenCommunicating, + errorDescription)) + } else { + rxBus.send(EventMedtronicPumpValuesChanged()) + medtronicPumpStatus.setLastCommunicationToNow() + } + medtronicUtil.setCurrentCommand(null) + } + + fun hasData(): Boolean { + return responseType === MedtronicUIResponseType.Data + } + + fun getParameter(index: Int): Any? { + return parameters!![index] + } + +} \ No newline at end of file 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 index 9b3315e838..070bfb1a38 100644 --- 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 @@ -580,7 +580,8 @@ public class MedtronicHistoryData { private void uploadCareportalEvent(long date, DetailedBolusInfo.EventType event) { - pumpSync.insertTherapyEventIfNewWithTimestamp(date, event, null, null, medtronicPumpStatus.pumpType, medtronicPumpStatus.serialNumber); + pumpSync.insertTherapyEventIfNewWithTimestamp(date, event, null, null, + medtronicPumpStatus.getPumpType(), medtronicPumpStatus.getSerialNumber()); } private void processTDDs(List tddsIn) { @@ -972,7 +973,7 @@ public class MedtronicHistoryData { detailedBolusInfo.setBolusTimestamp(tryToGetByLocalTime(bolus.getAtechDateTime())); detailedBolusInfo.setPumpType(PumpType.MEDTRONIC_512_712); // TODO grab real model - detailedBolusInfo.setPumpSerial(medtronicPumpStatus.serialNumber); + detailedBolusInfo.setPumpSerial(medtronicPumpStatus.getSerialNumber()); detailedBolusInfo.setBolusPumpId(bolus.getPumpId()); detailedBolusInfo.insulin = bolusDTO.getDeliveredAmount(); @@ -1046,7 +1047,7 @@ public class MedtronicHistoryData { if (doubleBolusDebug) aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "DoubleBolusDebug: addCarbsFromEstimate: Bolus=%s, BolusWizardDTO=%s", bolus, bolusWizard)); - detailedBolusInfo.carbs = bolusWizard.carbs; + detailedBolusInfo.carbs = bolusWizard.getCarbs(); } } @@ -1373,7 +1374,7 @@ public class MedtronicHistoryData { // 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.timeDifference, oldestEntryTime, now, minutes.getMinutes())); + this.pumpTime.getTimeDifference(), oldestEntryTime, now, minutes.getMinutes())); return minutes.getMinutes(); } @@ -1480,7 +1481,7 @@ public class MedtronicHistoryData { aapsLogger.debug(LTag.PUMP, "processLastBasalProfileChange. item found, setting new basalProfileLocally: " + newProfile); BasalProfile basalProfile = (BasalProfile) newProfile.getDecodedData().get("Object"); - mdtPumpStatus.basalsByHour = basalProfile.getProfilesByHour(pumpType); + mdtPumpStatus.setBasalsByHour( basalProfile.getProfilesByHour(pumpType)); } } 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 3777c30559..489e2b2c36 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 @@ -55,18 +55,18 @@ class BasalProfile { } private fun setRawData(data: ByteArray): Boolean { - var data: ByteArray? = data - if (data == null) { + var dataInternal: ByteArray? = data + 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 (data.size == 1) { - data = MedtronicUtil.createByteArray(data[0], 0.toByte(), 0.toByte()) + if (dataInternal.size == 1) { + dataInternal = byteArrayOf(dataInternal[0], 0, 0) } - if (data!!.size == MAX_RAW_DATA_SIZE) { - rawData = data + if (dataInternal.size == MAX_RAW_DATA_SIZE) { + rawData = dataInternal } else { val len = Math.min(MAX_RAW_DATA_SIZE, data.size) rawData = ByteArray(MAX_RAW_DATA_SIZE) @@ -233,10 +233,10 @@ class BasalProfile { // return this.mRawData; } - fun getProfilesByHour(pumpType: PumpType?): Array { - var entries: List? = null + fun getProfilesByHour(pumpType: PumpType): Array { + var entriesCopy: List? = null try { - entries = entries + entriesCopy = entries } catch (ex: Exception) { aapsLogger.error(LTag.PUMPCOMM, "=============================================================================") aapsLogger.error(LTag.PUMPCOMM, " Error generating entries. Ex.: $ex", ex) @@ -245,40 +245,43 @@ class BasalProfile { //FabricUtil.createEvent("MedtronicBasalProfileGetByHourError", null); } - if (entries == null || entries.size == 0) { + if (entriesCopy == null || entriesCopy.size == 0) { val basalByHour = arrayOfNulls(24) for (i in 0..23) { basalByHour[i] = 0.0 } - return basalByHour + return basalByHour as Array } val basalByHour = arrayOfNulls(24) - for (i in entries.indices) { - val current = entries[i] + 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 currentTime = currentTime * 30 / 60 var lastHour: Int - lastHour = if (i + 1 == entries.size) { + lastHour = if (i + 1 == entriesCopy.size) { 24 } else { - val basalProfileEntry = entries[i + 1] + val basalProfileEntry = entriesCopy[i + 1] val rawTime = if (basalProfileEntry.startTime_raw % 2 == 0) basalProfileEntry.startTime_raw.toInt() else basalProfileEntry.startTime_raw - 1 rawTime * 30 / 60 } // System.out.println("Current time: " + currentTime + " Next Time: " + lastHour); for (j in currentTime until lastHour) { - if (pumpType == null) basalByHour[j] = current.rate else basalByHour[j] = pumpType.determineCorrectBasalSize(current.rate) + if (pumpType == null) + basalByHour[j] = current.rate + else + basalByHour[j] = pumpType.determineCorrectBasalSize(current.rate) } } - return basalByHour + return basalByHour as Array } override fun toString(): String { return basalProfileToString() } - fun verify(pumpType: PumpType?): Boolean { + fun verify(pumpType: PumpType): Boolean { try { entries } catch (ex: Exception) { diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BatteryStatusDTO.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BatteryStatusDTO.java deleted file mode 100644 index 835d43c072..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BatteryStatusDTO.java +++ /dev/null @@ -1,60 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.data.dto; - -import com.google.gson.annotations.Expose; - -import androidx.annotation.NonNull; - -import java.util.Locale; - -import info.nightscout.androidaps.plugins.pump.medtronic.defs.BatteryType; - -/** - * Created by andy on 6/14/18. - */ - -public class BatteryStatusDTO { - - @Expose - public BatteryStatusType batteryStatusType; - @Expose - public Double voltage; - - public boolean extendedDataReceived = false; - - - public int getCalculatedPercent(BatteryType batteryType) { - if (voltage == null || batteryType == BatteryType.None) { - return (batteryStatusType == BatteryStatusType.Low || batteryStatusType == BatteryStatusType.Unknown) ? 18 : 70; - } - - double percent = (voltage - batteryType.lowVoltage) / (batteryType.highVoltage - batteryType.lowVoltage); - - int percentInt = (int) (percent * 100.0d); - - if (percentInt < 0) - percentInt = 1; - - if (percentInt > 100) - percentInt = 100; - - return percentInt; - } - - - @NonNull public String toString() { - return String.format(Locale.ENGLISH, "BatteryStatusDTO [voltage=%.2f, alkaline=%d, lithium=%d, niZn=%d, nimh=%d]", - voltage == null ? 0.0f : voltage, - getCalculatedPercent(BatteryType.Alkaline), - getCalculatedPercent(BatteryType.Lithium), - getCalculatedPercent(BatteryType.NiZn), - getCalculatedPercent(BatteryType.NiMH)); - } - - - public enum BatteryStatusType { - Normal, - Low, - Unknown - } - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BatteryStatusDTO.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BatteryStatusDTO.kt new file mode 100644 index 0000000000..60128d51a5 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BatteryStatusDTO.kt @@ -0,0 +1,46 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.data.dto + +import com.google.gson.annotations.Expose +import info.nightscout.androidaps.plugins.pump.medtronic.defs.BatteryType +import java.util.* + +/** + * Created by andy on 6/14/18. + */ +class BatteryStatusDTO { + + @Expose + var batteryStatusType: BatteryStatusType? = null + @Expose + var voltage: Double? = null + + var extendedDataReceived = false + + + fun getCalculatedPercent(batteryType: BatteryType): Int { + if (voltage == null || batteryType === BatteryType.None) { + return if (batteryStatusType == BatteryStatusType.Low || batteryStatusType == BatteryStatusType.Unknown) 18 else 70 + } + val percent = (voltage!! - batteryType.lowVoltage) / (batteryType.highVoltage - batteryType.lowVoltage) + var percentInt = (percent * 100.0).toInt() + if (percentInt < 0) percentInt = 1 + if (percentInt > 100) percentInt = 100 + return percentInt + } + + + override fun toString(): String { + return String.format(Locale.ENGLISH, "BatteryStatusDTO [voltage=%.2f, alkaline=%d, lithium=%d, niZn=%d, nimh=%d]", + if (voltage == null) 0.0f else voltage, + getCalculatedPercent(BatteryType.Alkaline), + getCalculatedPercent(BatteryType.Lithium), + getCalculatedPercent(BatteryType.NiZn), + getCalculatedPercent(BatteryType.NiMH)) + } + + enum class BatteryStatusType { + Normal, + Low, + Unknown + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BolusDTO.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BolusDTO.java deleted file mode 100644 index 8574bd831a..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BolusDTO.java +++ /dev/null @@ -1,160 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.data.dto; - -import com.google.gson.annotations.Expose; - -import info.nightscout.androidaps.plugins.pump.common.utils.StringUtil; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.PumpBolusType; - -/** - * Application: GGC - GNU Gluco Control - * Plug-in: Pump Tool (support for Pump devices) - *

- * See AUTHORS for copyright information. - *

- * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later - * version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - *

- * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free - * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - *

- * Filename: BolusDTO Description: Bolus DTO - *

- * Author: Andy {andy@atech-software.com} - */ - -public class BolusDTO extends PumpTimeStampedRecord { - - @Expose - private Double requestedAmount; - @Expose - private Double deliveredAmount; - @Expose - private Double immediateAmount; // when Multiwave this is used - @Expose - private Integer duration; - @Expose - private PumpBolusType bolusType; - private Double insulinOnBoard; - - - public BolusDTO() { - // this.decimalPrecission = 2; - } - - - public Double getRequestedAmount() { - return requestedAmount; - } - - - public void setRequestedAmount(Double requestedAmount) { - this.requestedAmount = requestedAmount; - } - - - public Double getDeliveredAmount() { - return deliveredAmount; - } - - - public void setDeliveredAmount(Double deliveredAmount) { - this.deliveredAmount = deliveredAmount; - } - - - public Integer getDuration() { - return duration; - } - - - public void setDuration(Integer duration) { - this.duration = duration; - } - - - public PumpBolusType getBolusType() { - return bolusType; - } - - - public void setBolusType(PumpBolusType bolusType) { - this.bolusType = bolusType; - } - - - public Double getInsulinOnBoard() { - return insulinOnBoard; - } - - - public void setInsulinOnBoard(Double insulinOnBoard) { - this.insulinOnBoard = insulinOnBoard; - } - - - private String getDurationString() { - int minutes = this.duration; - - int h = minutes / 60; - - minutes -= (h * 60); - - return StringUtil.getLeadingZero(h, 2) + ":" + StringUtil.getLeadingZero(minutes, 2); - } - - - public String getValue() { - if ((bolusType == PumpBolusType.Normal) || (bolusType == PumpBolusType.Audio)) { - return getFormattedDecimal(this.deliveredAmount); - } else if (bolusType == PumpBolusType.Extended) { - return String.format("AMOUNT_SQUARE=%s;DURATION=%s", getFormattedDecimal(this.deliveredAmount), - getDurationString()); - } else { - return String.format("AMOUNT=%s;AMOUNT_SQUARE=%s;DURATION=%s", getFormattedDecimal(this.immediateAmount), - getFormattedDecimal(this.deliveredAmount), getDurationString()); - } - } - - - public String getDisplayableValue() { - String value = getValue(); - - value = value.replace("AMOUNT_SQUARE=", "Amount Square: "); - value = value.replace("AMOUNT=", "Amount: "); - value = value.replace("DURATION=", "Duration: "); - - return value; - } - - - public Double getImmediateAmount() { - return immediateAmount; - } - - - public void setImmediateAmount(Double immediateAmount) { - this.immediateAmount = immediateAmount; - } - - - public String getFormattedDecimal(double value) { - return StringUtil.getFormatedValueUS(value, 2); - } - - - public String getBolusKey() { - return "Bolus_" + this.bolusType.name(); - - } - - - @Override - public String toString() { - return "BolusDTO [type=" + bolusType.name() + ", " + getValue() + "]"; - } - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BolusDTO.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BolusDTO.kt new file mode 100644 index 0000000000..671aae39a5 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BolusDTO.kt @@ -0,0 +1,90 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.data.dto + +import com.google.gson.annotations.Expose +import info.nightscout.androidaps.plugins.pump.common.utils.StringUtil +import info.nightscout.androidaps.plugins.pump.medtronic.defs.PumpBolusType + +/** + * Application: GGC - GNU Gluco Control + * Plug-in: Pump Tool (support for Pump devices) + * + * + * See AUTHORS for copyright information. + * + * + * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * + * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * Filename: BolusDTO Description: Bolus DTO + * + * + * Author: Andy {andy@atech-software.com} + */ +class BolusDTO : PumpTimeStampedRecord() { + + @Expose + var requestedAmount: Double? = null + + @Expose + var deliveredAmount: Double? = null + + @Expose + var immediateAmount: Double? = null // when Multiwave this is used + + @Expose + var duration: Int? = null + + @Expose + var bolusType: PumpBolusType? = null + + var insulinOnBoard: Double? = null + + private val durationString: String + get() { + var minutes = duration!! + val h = minutes / 60 + minutes -= h * 60 + return StringUtil.getLeadingZero(h, 2) + ":" + StringUtil.getLeadingZero(minutes, 2) + } + + val value: String? + get() = if (bolusType === PumpBolusType.Normal || bolusType === PumpBolusType.Audio) { + getFormattedDecimal(deliveredAmount!!) + } else if (bolusType === PumpBolusType.Extended) { + String.format("AMOUNT_SQUARE=%s;DURATION=%s", getFormattedDecimal(deliveredAmount!!), + durationString) + } else { + String.format("AMOUNT=%s;AMOUNT_SQUARE=%s;DURATION=%s", getFormattedDecimal(immediateAmount!!), + getFormattedDecimal(deliveredAmount!!), durationString) + } + + val displayableValue: String + get() { + var value = value + value = value!!.replace("AMOUNT_SQUARE=", "Amount Square: ") + value = value.replace("AMOUNT=", "Amount: ") + value = value.replace("DURATION=", "Duration: ") + return value + } + + override fun getFormattedDecimal(value: Double): String? { + return StringUtil.getFormatedValueUS(value, 2) + } + + val bolusKey: String + get() = "Bolus_" + bolusType!!.name + + override fun toString(): String { + return "BolusDTO [type=" + bolusType!!.name + ", " + value + "]" + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BolusWizardDTO.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BolusWizardDTO.java deleted file mode 100644 index 24b63015c4..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BolusWizardDTO.java +++ /dev/null @@ -1,50 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.data.dto; - -import java.util.Locale; - -import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil; - -/** - * Created by andy on 18.05.15. - */ -public class BolusWizardDTO extends PumpTimeStampedRecord { - - // bloodGlucose and bgTarets are in mg/dL - public Integer bloodGlucose = 0; // mg/dL - public Integer carbs = 0; - public String chUnit = "g"; - - public Float carbRatio = 0.0f; - public Float insulinSensitivity = 0.0f; - public Integer bgTargetLow = 0; - public Integer bgTargetHigh = 0; - public Float bolusTotal = 0.0f; - public Float correctionEstimate = 0.0f; - public Float foodEstimate = 0.0f; - public Float unabsorbedInsulin = 0.0f; - - - // public LocalDateTime localDateTime; - // public long atechDateTime; - - public String getValue() { - return String.format(Locale.ENGLISH, "BG=%d;CH=%d;CH_UNIT=%s;CH_INS_RATIO=%5.3f;BG_INS_RATIO=%5.3f;" - + "BG_TARGET_LOW=%d;BG_TARGET_HIGH=%d;BOLUS_TOTAL=%5.3f;" - + "BOLUS_CORRECTION=%5.3f;BOLUS_FOOD=%5.3f;UNABSORBED_INSULIN=%5.3f", // - bloodGlucose, carbs, chUnit, carbRatio, insulinSensitivity, bgTargetLow, // - bgTargetHigh, bolusTotal, correctionEstimate, foodEstimate, unabsorbedInsulin); - } - - public String getDisplayableValue() { - return String.format(Locale.ENGLISH, "Bg=%d, CH=%d %s, Ch/Ins Ratio=%5.3f, Bg/Ins Ratio=%5.3f;" - + "Bg Target(L/H)=%d/%d, Bolus: Total=%5.3f, " - + "Correction=%5.3f, Food=%5.3f, IOB=%5.3f", // - bloodGlucose, carbs, chUnit, carbRatio, insulinSensitivity, bgTargetLow, // - bgTargetHigh, bolusTotal, correctionEstimate, foodEstimate, unabsorbedInsulin); - } - - - public String toString() { - return "BolusWizardDTO [dateTime=" + DateTimeUtil.toString(atechDateTime) + ", " + getValue() + "]"; - } -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BolusWizardDTO.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BolusWizardDTO.kt new file mode 100644 index 0000000000..cf73a0506d --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BolusWizardDTO.kt @@ -0,0 +1,44 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.data.dto + +import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil +import java.util.* + +/** + * Created by andy on 18.05.15. + */ +class BolusWizardDTO : PumpTimeStampedRecord() { + + // bloodGlucose and bgTarets are in mg/dL + var bloodGlucose = 0 // mg/dL + var carbs = 0 + var chUnit = "g" + var carbRatio = 0.0f + var insulinSensitivity = 0.0f + var bgTargetLow = 0 + var bgTargetHigh = 0 + var bolusTotal = 0.0f + var correctionEstimate = 0.0f + var foodEstimate = 0.0f + var unabsorbedInsulin = 0.0f// + + + val value: String + get() = String.format(Locale.ENGLISH, "BG=%d;CH=%d;CH_UNIT=%s;CH_INS_RATIO=%5.3f;BG_INS_RATIO=%5.3f;" + + "BG_TARGET_LOW=%d;BG_TARGET_HIGH=%d;BOLUS_TOTAL=%5.3f;" + + "BOLUS_CORRECTION=%5.3f;BOLUS_FOOD=%5.3f;UNABSORBED_INSULIN=%5.3f", // + bloodGlucose, carbs, chUnit, carbRatio, insulinSensitivity, bgTargetLow, // + bgTargetHigh, bolusTotal, correctionEstimate, foodEstimate, unabsorbedInsulin) + + // + // + val displayableValue: String + get() = String.format(Locale.ENGLISH, "Bg=%d, CH=%d %s, Ch/Ins Ratio=%5.3f, Bg/Ins Ratio=%5.3f;" + + "Bg Target(L/H)=%d/%d, Bolus: Total=%5.3f, " + + "Correction=%5.3f, Food=%5.3f, IOB=%5.3f", // + bloodGlucose, carbs, chUnit, carbRatio, insulinSensitivity, bgTargetLow, // + bgTargetHigh, bolusTotal, correctionEstimate, foodEstimate, unabsorbedInsulin) + + override fun toString(): String { + return "BolusWizardDTO [dateTime=" + DateTimeUtil.toString(atechDateTime) + ", " + value + "]" + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/ClockDTO.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/ClockDTO.java deleted file mode 100644 index 1623e03ff5..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/ClockDTO.java +++ /dev/null @@ -1,16 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.data.dto; - -import org.joda.time.LocalDateTime; - -/** - * Created by andy on 2/27/19. - */ - -public class ClockDTO { - - public LocalDateTime localDeviceTime; - - public LocalDateTime pumpTime; - - public int timeDifference; // s (pump -> local) -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/ClockDTO.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/ClockDTO.kt new file mode 100644 index 0000000000..32f52281a9 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/ClockDTO.kt @@ -0,0 +1,12 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.data.dto + +import org.joda.time.LocalDateTime + +/** + * Created by andy on 2/27/19. + */ +class ClockDTO { + var localDeviceTime: LocalDateTime? = null + var pumpTime: LocalDateTime? = null + var timeDifference = 0 +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/DailyTotalsDTO.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/DailyTotalsDTO.java deleted file mode 100644 index f32464b105..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/DailyTotalsDTO.java +++ /dev/null @@ -1,255 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.data.dto; - -import androidx.annotation.NonNull; - -import com.google.gson.annotations.Expose; - -import org.apache.commons.lang3.builder.ToStringBuilder; - -import java.util.Locale; - -import info.nightscout.androidaps.db.TDD; -import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil; -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.PumpHistoryEntry; - -/** - * Created by andy on 11/3/18. - */ - -/** - * NOTE: Decoding is only done for insulin part, everything else is pretty must left undecoded. - */ - -public class DailyTotalsDTO { - - // bg avg, bg low hi, number Bgs, - // Sen Avg, Sen Lo/Hi, Sens Cal/Data = 0/0, - // Insulin=19.8[8,9], Basal[10,11], Bolus[13,14], Carbs, - // Bolus=1.7, Fodd, Corr, Manual=1.7, - // Num bOlus=1, food/corr, Food+corr, manual bolus=1 - private Double bgAvg; - private Double bgLow; - private Double bgHigh; - private Integer bgCount; - - private Double sensorAvg; - private Double sensorMin; - private Double sensorMax; - private Integer sensorCalcCount; - private Integer sensorDataCount; - - @Expose - private Double insulinTotal = 0.0d; - @Expose - private Double insulinBasal = 0.0d; - @Expose - private Double insulinBolus = 0.0d; - private Double insulinCarbs; - - private Double bolusTotal; - private Double bolusFood; - private Double bolusFoodAndCorr; - private Double bolusCorrection; - private Double bolusManual; - - private Integer bolusCount; - private Integer bolusCountFoodOrCorr; - // Integer bolusCountCorr; - Integer bolusCountFoodAndCorr; - Integer bolusCountManual; - private Integer bolusCountFood; - private Integer bolusCountCorr; - - PumpHistoryEntry entry; - - - public DailyTotalsDTO(PumpHistoryEntry entry) { - this.entry = entry; - - switch (entry.getEntryType()) { - case EndResultTotals: - decodeEndResultsTotals(entry); - break; - - case DailyTotals515: - decodeDailyTotals515(entry.getBody()); - break; - - case DailyTotals522: - decodeDailyTotals522(entry.getBody()); - break; - - case DailyTotals523: - decodeDailyTotals523(entry.getBody()); - break; - - default: - break; - } - - setDisplayable(); - } - - - private void setDisplayable() { - - if (this.insulinBasal == null) { - this.entry.setDisplayableValue("Total Insulin: " + StringUtil.getFormatedValueUS(this.insulinTotal, 2)); - } else { - this.entry.setDisplayableValue("Basal Insulin: " + StringUtil.getFormatedValueUS(this.insulinBasal, 2) - + ", Total Insulin: " + StringUtil.getFormatedValueUS(this.insulinTotal, 2)); - } - - } - - - private void decodeEndResultsTotals(PumpHistoryEntry entry) { - double totals = ByteUtil.toInt((int) entry.getHead()[0], (int) entry.getHead()[1], (int) entry.getHead()[2], - (int) entry.getHead()[3], ByteUtil.BitConversion.BIG_ENDIAN) * 0.025d; - - this.insulinTotal = totals; - - entry.addDecodedData("Totals", totals); - } - - - private void testDecode(byte[] data) { - - // Daily - - byte[] body = data; // entry.getBody(); - //System.out.println("Totals 522"); - - for (int i = 0; i < body.length - 2; i++) { - - int j = ByteUtil.toInt(body[i], body[i + 1]); - int k = ByteUtil.toInt(body[i], body[i + 1], body[i + 2]); - - int j1 = ByteUtil.toInt(body[i + 1], body[i]); - int k1 = ByteUtil.toInt(body[i + 2], body[i + 1], body[i]); - - System.out.println(String.format(Locale.ENGLISH, - "index: %d, number=%d, del/40=%.3f, del/10=%.3f, singular=%d, sing_hex=%s", i, j, j / 40.0d, j / 10.0d, - body[i], ByteUtil.shortHexString(body[i]))); - - System.out.println(String.format(Locale.ENGLISH, " number[k,j1,k1]=%d / %d /%d, del/40=%.3f, del/40=%.3f, del/40=%.3f", - k, j1, k1, k / 40.0d, j1 / 40.0d, k1 / 40.0d)); - - } - } - - - private void decodeDailyTotals515(byte[] data) { - // LOG.debug("Can't decode DailyTotals515: Body={}", ByteUtil.getHex(data)); - - this.insulinTotal = ByteUtil.toInt(data[8], data[9]) / 40.0d; - this.insulinBasal = ByteUtil.toInt(data[10], data[11]) / 40.0d; - this.insulinBolus = ByteUtil.toInt(data[13], data[14]) / 40.0d; - - // Delivery Stats: BG AVG: Bg Low/Hi=none,Number BGs=0 - // Delivery Stats: INSULIN: Basal 22.30, Bolus=4.20, Catbs = 0g (26.5) - // Delivery Stats: BOLUS: Food=0.00, Corr=0.00, Manual=4.20 - // Delivery Stats: NUM BOLUS: Food/Corr=0,Food+Corr=0, Manual=3 - - //LOG.debug("515: {}", toString()); - } - - - private void decodeDailyTotals522(byte[] data) { - - this.insulinTotal = ByteUtil.toInt(data[8], data[9]) / 40.0d; - this.insulinBasal = ByteUtil.toInt(data[10], data[11]) / 40.0d; - this.insulinBolus = ByteUtil.toInt(data[13], data[14]) / 40.0d; - - this.bolusTotal = ByteUtil.toInt(data[17], data[18], data[19]) / 40.0d; - this.bolusFood = ByteUtil.toInt(data[21], data[22]) / 40.0d; - this.bolusCorrection = ByteUtil.toInt(data[23], data[24], data[25]) / 40.0d; - this.bolusManual = ByteUtil.toInt(data[26], data[27], data[28]) / 40.0d; - - bolusCount = ByteUtil.asUINT8(data[30]); - bolusCountFoodOrCorr = ByteUtil.asUINT8(data[31]); - bolusCountFoodAndCorr = ByteUtil.asUINT8(data[32]); - bolusCountManual = ByteUtil.asUINT8(data[33]); - - // bg avg, bg low hi, number Bgs, - // Sen Avg, Sen Lo/Hi, Sens Cal/Data = 0/0, - // Insulin=19.8[8,9], Basal[10,11], Bolus[13,14], Carbs, - // Bolus=1.7[18,19], Fodd, Corr, Manual=1.7[27,28], - // Num bOlus=1, food/corr, Food+corr, manual bolus=1 - - //LOG.debug("522: {}", toString()); - } - - - private void decodeDailyTotals523(byte[] data) { - - this.insulinTotal = ByteUtil.toInt(data[8], data[9]) / 40.0d; - this.insulinBasal = ByteUtil.toInt(data[10], data[11]) / 40.0d; - this.insulinBolus = ByteUtil.toInt(data[13], data[14]) / 40.0d; - this.insulinCarbs = ByteUtil.toInt(data[16], data[17]) * 1.0d; - - this.bolusFood = ByteUtil.toInt(data[18], data[19]) / 40.0d; - this.bolusCorrection = ByteUtil.toInt(data[20], data[21]) / 40.0d; - this.bolusFoodAndCorr = ByteUtil.toInt(data[22], data[23]) / 40.0d; - this.bolusManual = ByteUtil.toInt(data[24], data[25]) / 40.0d; - - this.bolusCountFood = ByteUtil.asUINT8(data[26]); - this.bolusCountCorr = ByteUtil.asUINT8(data[27]); - this.bolusCountFoodAndCorr = ByteUtil.asUINT8(data[28]); - this.bolusCountManual = ByteUtil.asUINT8(data[29]); // + - - // Delivery Stats: Carbs=11, Total Insulin=3.850, Basal=2.000 - // Delivery Stats: Basal 52,Bolus 1.850, Bolus=48%o - // Delivery Stats: Food only=0.9, Food only#=1, Corr only = 0.0 - // Delivery Stats: #Corr_only=0,Food+Corr=0.000, #Food+Corr=0 - // Delivery Stats: Manual = 0.95, #Manual=5 - - //LOG.debug("523: {}", toString()); - } - - @Override @NonNull - public String toString() { - return new ToStringBuilder(this) - .append("bgAvg", bgAvg) - .append("bgLow", bgLow) - .append("bgHigh", bgHigh) - .append("bgCount", bgCount) - .append("sensorAvg", sensorAvg) - .append("sensorMin", sensorMin) - .append("sensorMax", sensorMax) - .append("sensorCalcCount", sensorCalcCount) - .append("sensorDataCount", sensorDataCount) - .append("insulinTotal", insulinTotal) - .append("insulinBasal", insulinBasal) - .append("insulinBolus", insulinBolus) - .append("insulinCarbs", insulinCarbs) - .append("bolusTotal", bolusTotal) - .append("bolusFood", bolusFood) - .append("bolusFoodAndCorr", bolusFoodAndCorr) - .append("bolusCorrection", bolusCorrection) - .append("bolusManual", bolusManual) - .append("bolusCount", bolusCount) - .append("bolusCountFoodOrCorr", bolusCountFoodOrCorr) - .append("bolusCountFoodAndCorr", bolusCountFoodAndCorr) - .append("bolusCountManual", bolusCountManual) - .append("bolusCountFood", bolusCountFood) - .append("bolusCountCorr", bolusCountCorr) - .append("entry", entry) - .toString(); - } - - public void setTDD(TDD tdd) { - tdd.date = DateTimeUtil.toMillisFromATD(this.entry.getAtechDateTime()); - tdd.basal = insulinBasal; - tdd.bolus = insulinBolus; - tdd.total = insulinTotal; - } - - - public boolean doesEqual(TDD tdd) { - return tdd.total == this.insulinTotal && tdd.bolus == this.insulinBolus && tdd.basal == this.insulinBasal; - } - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/DailyTotalsDTO.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/DailyTotalsDTO.kt new file mode 100644 index 0000000000..37284cffe1 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/DailyTotalsDTO.kt @@ -0,0 +1,202 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.data.dto + +import com.google.gson.annotations.Expose +import info.nightscout.androidaps.db.TDD +import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil +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.PumpHistoryEntry +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntryType +import org.apache.commons.lang3.builder.ToStringBuilder +import java.util.* + +/** + * Created by andy on 11/3/18. + */ +/** + * NOTE: Decoding is only done for insulin part, everything else is pretty must left undecoded. + */ +class DailyTotalsDTO(var entry: PumpHistoryEntry) { + + // bg avg, bg low hi, number Bgs, + // Sen Avg, Sen Lo/Hi, Sens Cal/Data = 0/0, + // Insulin=19.8[8,9], Basal[10,11], Bolus[13,14], Carbs, + // Bolus=1.7, Fodd, Corr, Manual=1.7, + // Num bOlus=1, food/corr, Food+corr, manual bolus=1 + private val bgAvg: Double? = null + private val bgLow: Double? = null + private val bgHigh: Double? = null + private val bgCount: Int? = null + private val sensorAvg: Double? = null + private val sensorMin: Double? = null + private val sensorMax: Double? = null + private val sensorCalcCount: Int? = null + private val sensorDataCount: Int? = null + + @Expose + private var insulinTotal = 0.0 + + @Expose + private var insulinBasal: Double? = 0.0 + + @Expose + private var insulinBolus = 0.0 + private var insulinCarbs: Double? = null + private var bolusTotal: Double? = null + private var bolusFood: Double? = null + private var bolusFoodAndCorr: Double? = null + private var bolusCorrection: Double? = null + private var bolusManual: Double? = null + private var bolusCount: Int? = null + private var bolusCountFoodOrCorr: Int? = null + + // Integer bolusCountCorr; + var bolusCountFoodAndCorr: Int? = null + var bolusCountManual: Int? = null + private var bolusCountFood: Int? = null + private var bolusCountCorr: Int? = null + private fun setDisplayable() { + if (insulinBasal == null) { + entry.displayableValue = "Total Insulin: " + StringUtil.getFormatedValueUS(insulinTotal, 2) + } else { + entry.displayableValue = ("Basal Insulin: " + StringUtil.getFormatedValueUS(insulinBasal, 2) + + ", Total Insulin: " + StringUtil.getFormatedValueUS(insulinTotal, 2)) + } + } + + private fun decodeEndResultsTotals(entry: PumpHistoryEntry) { + val totals = ByteUtil.toInt(entry.head!![0].toInt(), entry.head!![1].toInt(), entry.head!![2].toInt(), + entry.head!![3].toInt(), ByteUtil.BitConversion.BIG_ENDIAN) * 0.025 + insulinTotal = totals + entry.addDecodedData("Totals", totals) + } + + private fun testDecode(data: ByteArray) { + + // Daily + //System.out.println("Totals 522"); + for (i in 0 until data.size - 2) { + val j = ByteUtil.toInt(data[i], data[i + 1]) + val k: Int = ByteUtil.toInt(data[i], data[i + 1], data[i + 2]) + val j1 = ByteUtil.toInt(data[i + 1], data[i]) + val k1: Int = ByteUtil.toInt(data[i + 2], data[i + 1], data[i]) + println(String.format(Locale.ENGLISH, + "index: %d, number=%d, del/40=%.3f, del/10=%.3f, singular=%d, sing_hex=%s", i, j, j / 40.0, j / 10.0, + data[i], ByteUtil.shortHexString(data[i]))) + println(String.format(Locale.ENGLISH, " number[k,j1,k1]=%d / %d /%d, del/40=%.3f, del/40=%.3f, del/40=%.3f", + k, j1, k1, k / 40.0, j1 / 40.0, k1 / 40.0)) + } + } + + private fun decodeDailyTotals515(data: ByteArray?) { + // LOG.debug("Can't decode DailyTotals515: Body={}", ByteUtil.getHex(data)); + insulinTotal = ByteUtil.toInt(data!![8], data[9]) / 40.0 + insulinBasal = ByteUtil.toInt(data[10], data[11]) / 40.0 + insulinBolus = ByteUtil.toInt(data[13], data[14]) / 40.0 + + // Delivery Stats: BG AVG: Bg Low/Hi=none,Number BGs=0 + // Delivery Stats: INSULIN: Basal 22.30, Bolus=4.20, Catbs = 0g (26.5) + // Delivery Stats: BOLUS: Food=0.00, Corr=0.00, Manual=4.20 + // Delivery Stats: NUM BOLUS: Food/Corr=0,Food+Corr=0, Manual=3 + + //LOG.debug("515: {}", toString()); + } + + private fun decodeDailyTotals522(data: ByteArray?) { + insulinTotal = ByteUtil.toInt(data!![8], data[9]) / 40.0 + insulinBasal = ByteUtil.toInt(data[10], data[11]) / 40.0 + insulinBolus = ByteUtil.toInt(data[13], data[14]) / 40.0 + bolusTotal = ByteUtil.toInt(data[17], data[18], data[19]) / 40.0 + bolusFood = ByteUtil.toInt(data[21], data[22]) / 40.0 + bolusCorrection = ByteUtil.toInt(data[23], data[24], data[25]) / 40.0 + bolusManual = ByteUtil.toInt(data[26], data[27], data[28]) / 40.0 + bolusCount = ByteUtil.asUINT8(data[30]) + bolusCountFoodOrCorr = ByteUtil.asUINT8(data[31]) + bolusCountFoodAndCorr = ByteUtil.asUINT8(data[32]) + bolusCountManual = ByteUtil.asUINT8(data[33]) + + // bg avg, bg low hi, number Bgs, + // Sen Avg, Sen Lo/Hi, Sens Cal/Data = 0/0, + // Insulin=19.8[8,9], Basal[10,11], Bolus[13,14], Carbs, + // Bolus=1.7[18,19], Fodd, Corr, Manual=1.7[27,28], + // Num bOlus=1, food/corr, Food+corr, manual bolus=1 + + //LOG.debug("522: {}", toString()); + } + + private fun decodeDailyTotals523(data: ByteArray?) { + insulinTotal = ByteUtil.toInt(data!![8], data[9]) / 40.0 + insulinBasal = ByteUtil.toInt(data[10], data[11]) / 40.0 + insulinBolus = ByteUtil.toInt(data[13], data[14]) / 40.0 + insulinCarbs = ByteUtil.toInt(data[16], data[17]) * 1.0 + bolusFood = ByteUtil.toInt(data[18], data[19]) / 40.0 + bolusCorrection = ByteUtil.toInt(data[20], data[21]) / 40.0 + bolusFoodAndCorr = ByteUtil.toInt(data[22], data[23]) / 40.0 + bolusManual = ByteUtil.toInt(data[24], data[25]) / 40.0 + bolusCountFood = ByteUtil.asUINT8(data[26]) + bolusCountCorr = ByteUtil.asUINT8(data[27]) + bolusCountFoodAndCorr = ByteUtil.asUINT8(data[28]) + bolusCountManual = ByteUtil.asUINT8(data[29]) // + + + // Delivery Stats: Carbs=11, Total Insulin=3.850, Basal=2.000 + // Delivery Stats: Basal 52,Bolus 1.850, Bolus=48%o + // Delivery Stats: Food only=0.9, Food only#=1, Corr only = 0.0 + // Delivery Stats: #Corr_only=0,Food+Corr=0.000, #Food+Corr=0 + // Delivery Stats: Manual = 0.95, #Manual=5 + + //LOG.debug("523: {}", toString()); + } + + override fun toString(): String { + return ToStringBuilder(this) + .append("bgAvg", bgAvg) + .append("bgLow", bgLow) + .append("bgHigh", bgHigh) + .append("bgCount", bgCount) + .append("sensorAvg", sensorAvg) + .append("sensorMin", sensorMin) + .append("sensorMax", sensorMax) + .append("sensorCalcCount", sensorCalcCount) + .append("sensorDataCount", sensorDataCount) + .append("insulinTotal", insulinTotal) + .append("insulinBasal", insulinBasal) + .append("insulinBolus", insulinBolus) + .append("insulinCarbs", insulinCarbs) + .append("bolusTotal", bolusTotal) + .append("bolusFood", bolusFood) + .append("bolusFoodAndCorr", bolusFoodAndCorr) + .append("bolusCorrection", bolusCorrection) + .append("bolusManual", bolusManual) + .append("bolusCount", bolusCount) + .append("bolusCountFoodOrCorr", bolusCountFoodOrCorr) + .append("bolusCountFoodAndCorr", bolusCountFoodAndCorr) + .append("bolusCountManual", bolusCountManual) + .append("bolusCountFood", bolusCountFood) + .append("bolusCountCorr", bolusCountCorr) + .append("entry", entry) + .toString() + } + + fun setTDD(tdd: TDD) { + tdd.date = DateTimeUtil.toMillisFromATD(entry.atechDateTime!!) + tdd.basal = insulinBasal!! + tdd.bolus = insulinBolus + tdd.total = insulinTotal + } + + fun doesEqual(tdd: TDD): Boolean { + return tdd.total == insulinTotal && tdd.bolus == insulinBolus && tdd.basal == insulinBasal + } + + init { + when (entry.entryType) { + PumpHistoryEntryType.EndResultTotals -> decodeEndResultsTotals(entry) + PumpHistoryEntryType.DailyTotals515 -> decodeDailyTotals515(entry.body) + PumpHistoryEntryType.DailyTotals522 -> decodeDailyTotals522(entry.body) + PumpHistoryEntryType.DailyTotals523 -> decodeDailyTotals523(entry.body) + else -> { + } + } + setDisplayable() + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/PumpSettingDTO.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/PumpSettingDTO.java deleted file mode 100644 index 1868064d8b..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/PumpSettingDTO.java +++ /dev/null @@ -1,29 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.data.dto; - -import info.nightscout.androidaps.plugins.pump.medtronic.defs.PumpConfigurationGroup; - -/** - * Created by andy on 6/6/18. - */ - -public class PumpSettingDTO { - - public String key; - public String value; - - PumpConfigurationGroup configurationGroup; - - - public PumpSettingDTO(String key, String value, PumpConfigurationGroup configurationGroup) { - this.key = key; - this.value = value; - this.configurationGroup = configurationGroup; - } - - - @Override - public String toString() { - return "PumpSettingDTO [key=" + key + ",value=" + value + ",group=" + configurationGroup.name() + "]"; - } - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/PumpSettingDTO.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/PumpSettingDTO.kt new file mode 100644 index 0000000000..824151320e --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/PumpSettingDTO.kt @@ -0,0 +1,14 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.data.dto + +import info.nightscout.androidaps.plugins.pump.medtronic.defs.PumpConfigurationGroup + +/** + * Created by andy on 6/6/18. + */ +class PumpSettingDTO(var key: String, var value: String, var configurationGroup: PumpConfigurationGroup) { + + override fun toString(): String { + return "PumpSettingDTO [key=" + key + ",value=" + value + ",group=" + configurationGroup.name + "]" + } + +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/PumpTimeStampedRecord.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/PumpTimeStampedRecord.java deleted file mode 100644 index 84ad0914b3..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/PumpTimeStampedRecord.java +++ /dev/null @@ -1,28 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.data.dto; - -import info.nightscout.androidaps.plugins.pump.common.utils.StringUtil; - -/** - * Created by andy on 6/2/18. - */ -public class PumpTimeStampedRecord { - - protected int decimalPrecission = 2; - public long atechDateTime; - - - public long getAtechDateTime() { - return this.atechDateTime; - } - - - public void setAtechDateTime(long atechDateTime) { - this.atechDateTime = atechDateTime; - } - - - public String getFormattedDecimal(double value) { - return StringUtil.getFormatedValueUS(value, this.decimalPrecission); - } - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/PumpTimeStampedRecord.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/PumpTimeStampedRecord.kt new file mode 100644 index 0000000000..8d0bd646b7 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/PumpTimeStampedRecord.kt @@ -0,0 +1,16 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.data.dto + +import info.nightscout.androidaps.plugins.pump.common.utils.StringUtil + +/** + * Created by andy on 6/2/18. + */ +open class PumpTimeStampedRecord { + + var decimalPrecission = 2 + var atechDateTime: Long = 0 + + open fun getFormattedDecimal(value: Double): String? { + return StringUtil.getFormatedValueUS(value, decimalPrecission) + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/RLHistoryItemMedtronic.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/RLHistoryItemMedtronic.java deleted file mode 100644 index b171f5a061..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/RLHistoryItemMedtronic.java +++ /dev/null @@ -1,28 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.data.dto; - -import org.joda.time.LocalDateTime; - -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.data.RLHistoryItem; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkTargetDevice; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicCommandType; -import info.nightscout.androidaps.utils.resources.ResourceHelper; - -public class RLHistoryItemMedtronic extends RLHistoryItem { - - private final MedtronicCommandType medtronicCommandType; - - public RLHistoryItemMedtronic(MedtronicCommandType medtronicCommandType) { - super(new LocalDateTime(), RLHistoryItemSource.MedtronicCommand, RileyLinkTargetDevice.MedtronicPump); - this.medtronicCommandType = medtronicCommandType; - } - - @Override - public String getDescription(ResourceHelper resourceHelper) { - if (RLHistoryItemSource.MedtronicCommand.equals(source)) { - return medtronicCommandType.name(); - } - - return super.getDescription(resourceHelper); - } - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/RLHistoryItemMedtronic.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/RLHistoryItemMedtronic.kt new file mode 100644 index 0000000000..4a99585508 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/RLHistoryItemMedtronic.kt @@ -0,0 +1,18 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.data.dto + +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.data.RLHistoryItem +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkTargetDevice +import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicCommandType +import info.nightscout.androidaps.utils.resources.ResourceHelper +import org.joda.time.LocalDateTime + +class RLHistoryItemMedtronic(private val medtronicCommandType: MedtronicCommandType) : + RLHistoryItem(LocalDateTime(), RLHistoryItemSource.MedtronicCommand, RileyLinkTargetDevice.MedtronicPump) { + + override fun getDescription(resourceHelper: ResourceHelper): String { + return if (RLHistoryItemSource.MedtronicCommand == source) { + medtronicCommandType.name + } else super.getDescription(resourceHelper) + } + +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/TempBasalPair.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/TempBasalPair.java deleted file mode 100644 index 418770d4b6..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/TempBasalPair.java +++ /dev/null @@ -1,145 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.data.dto; - -import androidx.annotation.NonNull; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -import info.nightscout.androidaps.logging.AAPSLogger; -import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil; -import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil; - -/** - * Created by geoff on 5/29/15. - *

- * Just need a class to keep the pair together, for parcel transport. - */ -public class TempBasalPair extends info.nightscout.androidaps.plugins.pump.common.defs.TempBasalPair { - - /** - * This constructor is for use with PumpHistoryDecoder - * - * @param rateByte - * @param startTimeByte - * @param isPercent - */ - public TempBasalPair(byte rateByte, int startTimeByte, boolean isPercent) { - super(); - int rateInt = ByteUtil.asUINT8(rateByte); - - if (isPercent) - this.setInsulinRate(rateByte); - else - this.setInsulinRate(rateInt * 0.025); - this.setDurationMinutes(startTimeByte * 30); - this.setPercent(isPercent); - } - - - /** - * This constructor is for use with PumpHistoryDecoder - * - * @param rateByte0 - * @param startTimeByte - * @param isPercent - */ - public TempBasalPair(byte rateByte0, byte rateByte1, int startTimeByte, boolean isPercent) { - if (isPercent) { - this.setInsulinRate(rateByte0); - } else { - this.setInsulinRate(ByteUtil.toInt(rateByte1, rateByte0) * 0.025); - } - this.setDurationMinutes(startTimeByte * 30); - this.setPercent(isPercent); - } - - public TempBasalPair(AAPSLogger aapsLogger, byte[] response) { - super(); - - aapsLogger.debug(LTag.PUMPBTCOMM, "Received TempBasal response: " + ByteUtil.getHex(response)); - - setPercent(response[0] == 1); - - if (isPercent()) { - setInsulinRate(response[1]); - } else { - int strokes = MedtronicUtil.makeUnsignedShort(response[2], response[3]); - - setInsulinRate(strokes / 40.0d); - } - - if (response.length < 6) { - setDurationMinutes(ByteUtil.asUINT8(response[4])); - } else { - setDurationMinutes(MedtronicUtil.makeUnsignedShort(response[4], response[5])); - } - - aapsLogger.warn(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, "TempBasalPair (with %d byte response): %s", response.length, toString())); - - } - - - public TempBasalPair(double insulinRate, boolean isPercent, int durationMinutes) { - super(insulinRate, isPercent, durationMinutes); - } - - - public byte[] getAsRawData() { - - List list = new ArrayList<>(); - - list.add((byte) 5); - - byte[] insulinRate = MedtronicUtil.getBasalStrokes(this.getInsulinRate(), true); - byte timeMin = (byte) MedtronicUtil.getIntervalFromMinutes(getDurationMinutes()); - - // list.add((byte) 0); // ? - - // list.add((byte) 0); // is_absolute - - if (insulinRate.length == 1) - list.add((byte) 0x00); - else - list.add(insulinRate[0]); - - list.add(insulinRate[1]); - // list.add((byte) 0); // percent amount - - list.add(timeMin); // 3 (time) - OK - - if (insulinRate.length == 1) - list.add((byte) 0x00); - else - list.add(insulinRate[0]); - - list.add(insulinRate[1]); - - return MedtronicUtil.createByteArray(list); - } - - public boolean isCancelTBR() { - return (MedtronicUtil.isSame(getInsulinRate(), 0.0d) && getDurationMinutes() == 0); - } - - - public String getDescription() { - if (isCancelTBR()) { - return "Cancel TBR"; - } - - if (isPercent()) { - return String.format(Locale.ENGLISH, "Rate: %.0f%%, Duration: %d min", getInsulinRate(), getDurationMinutes()); - } else { - return String.format(Locale.ENGLISH, "Rate: %.3f U, Duration: %d min", getInsulinRate(), getDurationMinutes()); - } - } - - - @NonNull @Override - public String toString() { - return "TempBasalPair [" + "Rate=" + getInsulinRate() + ", DurationMinutes=" + getDurationMinutes() + ", IsPercent=" - + isPercent() + "]"; - } -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/TempBasalPair.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/TempBasalPair.kt new file mode 100644 index 0000000000..1cd5f8dab7 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/TempBasalPair.kt @@ -0,0 +1,110 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.data.dto + +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.pump.common.defs.TempBasalPair +import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil +import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil +import java.util.* + +/** + * Created by geoff on 5/29/15. + * + * Just need a class to keep the pair together, for parcel transport. + */ +class TempBasalPair : TempBasalPair { + + /** + * This constructor is for use with PumpHistoryDecoder + * + * @param rateByte + * @param startTimeByte + * @param isPercent + */ + constructor(rateByte: Byte, startTimeByte: Int, isPercent: Boolean) : super() { + val rateInt = ByteUtil.asUINT8(rateByte) + if (isPercent) insulinRate = rateByte.toDouble() else insulinRate = rateInt * 0.025 + durationMinutes = startTimeByte * 30 + this.isPercent = isPercent + } + + /** + * This constructor is for use with PumpHistoryDecoder + * + * @param rateByte0 + * @param startTimeByte + * @param isPercent + */ + constructor(rateByte0: Byte, rateByte1: Byte, startTimeByte: Int, isPercent: Boolean) { + if (isPercent) { + insulinRate = rateByte0.toDouble() + } else { + insulinRate = ByteUtil.toInt(rateByte1.toInt(), rateByte0.toInt()) * 0.025 + } + durationMinutes = startTimeByte * 30 + this.isPercent = isPercent + } + + constructor(aapsLogger: AAPSLogger, response: ByteArray) : super() { + aapsLogger.debug(LTag.PUMPBTCOMM, "Received TempBasal response: " + ByteUtil.getHex(response)) + isPercent = response[0] == 1.toByte() + insulinRate = if (isPercent) { + response[1].toDouble() + } else { + val strokes = MedtronicUtil.makeUnsignedShort(response[2].toInt(), response[3].toInt()) + strokes / 40.0 + } + durationMinutes = if (response.size < 6) { + ByteUtil.asUINT8(response[4]) + } else { + MedtronicUtil.makeUnsignedShort(response[4].toInt(), response[5].toInt()) + } + aapsLogger.warn(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, "TempBasalPair (with %d byte response): %s", response.size, toString())) + } + + constructor(insulinRate: Double, isPercent: Boolean, durationMinutes: Int) : super(insulinRate, isPercent, durationMinutes) {} + + // list.add((byte) 0); // ? + + // list.add((byte) 0); // is_absolute + // list.add((byte) 0); // percent amount + // 3 (time) - OK + val asRawData: ByteArray + get() { + val list: MutableList = ArrayList() + list.add(5.toByte()) + val insulinRate = MedtronicUtil.getBasalStrokes(insulinRate, true) + val timeMin = MedtronicUtil.getIntervalFromMinutes(durationMinutes).toByte() + + // list.add((byte) 0); // ? + + // list.add((byte) 0); // is_absolute + if (insulinRate.size == 1) list.add(0x00.toByte()) else list.add(insulinRate[0]) + list.add(insulinRate[1]) + // list.add((byte) 0); // percent amount + list.add(timeMin) // 3 (time) - OK + if (insulinRate.size == 1) list.add(0x00.toByte()) else list.add(insulinRate[0]) + list.add(insulinRate[1]) + return MedtronicUtil.createByteArray(list) + } + + val isCancelTBR: Boolean + get() = MedtronicUtil.isSame(insulinRate, 0.0) && durationMinutes == 0 + + val description: String + get() { + if (isCancelTBR) { + return "Cancel TBR" + } + return if (isPercent) { + String.format(Locale.ENGLISH, "Rate: %.0f%%, Duration: %d min", insulinRate, durationMinutes) + } else { + String.format(Locale.ENGLISH, "Rate: %.3f U, Duration: %d min", insulinRate, durationMinutes) + } + } + + override fun toString(): String { + return ("TempBasalPair [" + "Rate=" + insulinRate + ", DurationMinutes=" + durationMinutes + ", IsPercent=" + + isPercent + "]") + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/TempBasalProcessDTO.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/TempBasalProcessDTO.java deleted file mode 100644 index f35a5b43c0..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/TempBasalProcessDTO.java +++ /dev/null @@ -1,31 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.data.dto; - -import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntry; - -public class TempBasalProcessDTO { - - public PumpHistoryEntry itemOne; - public PumpHistoryEntry itemTwo; - - public Operation processOperation = Operation.None; - - public int getDuration() { - if (itemTwo == null) { - TempBasalPair tbr = (TempBasalPair) itemOne.getDecodedDataEntry("Object"); - return tbr.getDurationMinutes(); - } else { - int difference = DateTimeUtil.getATechDateDiferenceAsMinutes(itemOne.getAtechDateTime(), itemTwo.getAtechDateTime()); - return difference; - } - } - - - public enum Operation { - None, - Add, - Edit - } - - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/TempBasalProcessDTO.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/TempBasalProcessDTO.kt new file mode 100644 index 0000000000..a7705f8c2f --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/TempBasalProcessDTO.kt @@ -0,0 +1,21 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.data.dto + +import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntry + +class TempBasalProcessDTO { + @JvmField var itemOne: PumpHistoryEntry? = null + @JvmField var itemTwo: PumpHistoryEntry? = null + @JvmField var processOperation = Operation.None + val duration: Int + get() = if (itemTwo == null) { + val tbr = itemOne!!.getDecodedDataEntry("Object") as TempBasalPair? + tbr!!.durationMinutes + } else { + DateTimeUtil.getATechDateDiferenceAsMinutes(itemOne!!.atechDateTime, itemTwo!!.atechDateTime) + } + + enum class Operation { + None, Add, Edit + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/BasalProfileStatus.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/BasalProfileStatus.java deleted file mode 100644 index 0710e6ca4c..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/BasalProfileStatus.java +++ /dev/null @@ -1,14 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.defs; - -/** - * Created by andy on 1/20/19. - */ - -public enum BasalProfileStatus { - - NotInitialized, // - ProfileOK, // - ProfileChanged, // - ; - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/BasalProfileStatus.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/BasalProfileStatus.kt new file mode 100644 index 0000000000..5bce7a4d71 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/BasalProfileStatus.kt @@ -0,0 +1,12 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.defs + +/** + * Created by andy on 1/20/19. + */ +enum class BasalProfileStatus { + + NotInitialized, // + ProfileOK, // + ProfileChanged + // +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/BatteryType.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/BatteryType.java deleted file mode 100644 index 503074e640..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/BatteryType.java +++ /dev/null @@ -1,34 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.defs; - -import androidx.annotation.StringRes; - -import java.util.HashMap; -import java.util.Map; - -import info.nightscout.androidaps.plugins.pump.medtronic.R; - - -/** - * Created by andy on 6/4/18. - */ - -public enum BatteryType { - - None(R.string.key_medtronic_pump_battery_no, 0, 0), - Alkaline(R.string.key_medtronic_pump_battery_alkaline, 1.20d, 1.47d), // - Lithium(R.string.key_medtronic_pump_battery_lithium, 1.22d, 1.64d), // - NiZn(R.string.key_medtronic_pump_battery_nizn, 1.40d, 1.70d), // - NiMH(R.string.key_medtronic_pump_battery_nimh, 1.10d, 1.40d) // - ; - - public final @StringRes int description; - public final double lowVoltage; - public final double highVoltage; - - - BatteryType(int resId, double lowVoltage, double highVoltage) { - this.description = resId; - this.lowVoltage = lowVoltage; - this.highVoltage = highVoltage; - } -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/BatteryType.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/BatteryType.kt new file mode 100644 index 0000000000..a1c0aad63b --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/BatteryType.kt @@ -0,0 +1,18 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.defs + +import androidx.annotation.StringRes +import info.nightscout.androidaps.plugins.pump.medtronic.R + +/** + * Created by andy on 6/4/18. + */ +enum class BatteryType(@field:StringRes val description: Int, val lowVoltage: Double, val highVoltage: Double) { + + None(R.string.key_medtronic_pump_battery_no, 0.0, 0.0), + Alkaline(R.string.key_medtronic_pump_battery_alkaline, 1.20, 1.47), // + Lithium(R.string.key_medtronic_pump_battery_lithium, 1.22, 1.64), // + NiZn(R.string.key_medtronic_pump_battery_nizn, 1.40, 1.70), // + NiMH(R.string.key_medtronic_pump_battery_nimh, 1.10, 1.40 // + ); + +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/CommandValueDefinitionMDTType.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/CommandValueDefinitionMDTType.java deleted file mode 100644 index f061b860cf..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/CommandValueDefinitionMDTType.java +++ /dev/null @@ -1,33 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.defs; - -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.CommandValueDefinitionType; - -/** - * Created by andy on 4/5/19. - */ - -public enum CommandValueDefinitionMDTType implements CommandValueDefinitionType { - GetModel, // - TuneUp, // - GetProfile, // - GetTBR, // - ; - - @Override - public String getName() { - return this.name(); - } - - - @Override - public String getDescription() { - return null; - } - - - @Override - public String commandAction() { - return null; - } - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicCommandType.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicCommandType.java deleted file mode 100755 index dfa4e83867..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicCommandType.java +++ /dev/null @@ -1,393 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.defs; - -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; - -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; - -/** - * Taken from GNU Gluco Control diabetes management software (ggc.sourceforge.net) - *

- * Description: Medtronic Commands (Pump and CGMS) for all 512 and later models (just 5xx) - *

- * Link to original/unmodified file: - * https://sourceforge.net/p/ggc/code/HEAD/tree/trunk/ggc-plugins/ggc-plugins-base/src/ - * main/java/ggc/plugin/device/impl/minimed/enums/MinimedCommandType.java - *

- * A lot of stuff has been removed because it is not needed anymore (historical stuff from CareLink - * and Carelink USB communication. - *

- * Author: Andy {andy@atech-software.com} - */ -public enum MedtronicCommandType implements Serializable // , MinimedCommandTypeInterface -{ - InvalidCommand(0, "Invalid Command", null, null), // - - // Pump Responses (9) - CommandACK(0x06, "ACK - Acknowledge", MedtronicDeviceType.All, MinimedCommandParameterType.NoParameters), // - CommandNAK(0x15, "NAK - Not Acknowledged", MedtronicDeviceType.All, MinimedCommandParameterType.NoParameters), // - - // All (8) - PushAck(91, "Push ACK", MedtronicDeviceType.All, MinimedCommandParameterType.FixedParameters, getByteArray(2)), // - - PushEsc(91, "Push Esc", MedtronicDeviceType.All, MinimedCommandParameterType.FixedParameters, getByteArray(1)), // - - PushButton(0x5b, "Push Button", MedtronicDeviceType.All, MinimedCommandParameterType.NoParameters), // 91 - - RFPowerOn(93, "RF Power On", MedtronicDeviceType.All, MinimedCommandParameterType.FixedParameters, getByteArray( - 1, 10)), // - - RFPowerOff(93, "RF Power Off", MedtronicDeviceType.All, MinimedCommandParameterType.FixedParameters, getByteArray( - 0, 0)), // - - // SetSuspend(77, "Set Suspend", MinimedTargetType.InitCommand, MedtronicDeviceType.All, - // MinimedCommandParameterType.FixedParameters, getByteArray(1)), // - - // CancelSuspend(77, "Cancel Suspend", MinimedTargetType.InitCommand, MedtronicDeviceType.All, - // MinimedCommandParameterType.FixedParameters, getByteArray(0)), // - - PumpState(131, "Pump State", MedtronicDeviceType.All, MinimedCommandParameterType.NoParameters), // - - ReadPumpErrorStatus(117, "Pump Error Status", MedtronicDeviceType.All, MinimedCommandParameterType.NoParameters), // - - // 511 (InitCommand = 2, Config 7, Data = 1(+3) -// DetectBolus(75, "Detect Bolus", MedtronicDeviceType.Medtronic_511, MinimedCommandParameterType.FixedParameters, getByteArray( -// 0, 0, 0)), // - - // RemoteControlIds(118, "Remote Control Ids", MinimedTargetType.PumpConfiguration_NA, MedtronicDeviceType.All, - // MinimedCommandParameterType.NoParameters), // - - // FirmwareVersion(116, "Firmware Version", MinimedTargetType.InitCommand, MedtronicDeviceType.All, - // MinimedCommandParameterType.NoParameters), // - - // PumpId(113, "Pump Id", MinimedTargetType.PumpConfiguration, MedtronicDeviceType.All, - // MinimedCommandParameterType.NoParameters), // init - - SetRealTimeClock(0x40, "Set Pump Time", MedtronicDeviceType.All, MinimedCommandParameterType.NoParameters, // - 0), // - - GetRealTimeClock(112, "Get Pump Time", MedtronicDeviceType.All, MinimedCommandParameterType.NoParameters, // - 7, R.string.medtronic_cmd_desc_get_time), // 0x70 - - GetBatteryStatus(0x72, "Get Battery Status", MedtronicDeviceType.All, MinimedCommandParameterType.NoParameters), // - // GetBattery((byte) 0x72), // - - GetRemainingInsulin(0x73, "Read Remaining Insulin", MedtronicDeviceType.All, MinimedCommandParameterType.NoParameters, 2), // 115 - - SetBolus(0x42, "Set Bolus", MedtronicDeviceType.All, MinimedCommandParameterType.NoParameters, // - 0, R.string.medtronic_cmd_desc_set_bolus), // 66 - - // 512 - ReadTemporaryBasal(0x98, "Read Temporary Basal", MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters, // - 5, R.string.medtronic_cmd_desc_get_tbr), // 152 - - SetTemporaryBasal(76, "Set Temporay Basal", MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters, // - 0, R.string.medtronic_cmd_desc_set_tbr), - - // 512 Config - PumpModel(141, "Pump Model", MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters, // - 5, R.string.medtronic_cmd_desc_get_model), // 0x8D - - // BGTargets_512(140, "BG Targets", MinimedTargetType.PumpConfiguration, MedtronicDeviceType.Medtronic_512_712, - // MinimedCommandParameterType.NoParameters), // - - // BGUnits(137, "BG Units", MinimedTargetType.PumpConfiguration, MedtronicDeviceType.Medtronic_512andHigher, - // MinimedCommandParameterType.NoParameters), // - - // Language(134, "Language", MinimedTargetType.PumpConfiguration, MedtronicDeviceType.Medtronic_512andHigher, - // MinimedCommandParameterType.NoParameters), // - - Settings_512(145, "Configuration", MedtronicDeviceType.Medtronic_512_712, MinimedCommandParameterType.NoParameters, // - 64, 1, 18, R.string.medtronic_cmd_desc_get_settings), // - - // BGAlarmClocks(142, "BG Alarm Clocks", MinimedTargetType.PumpConfiguration, - // MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters), // - - // BGAlarmEnable(151, "BG Alarm Enable", MinimedTargetType.PumpConfiguration, - // MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters), // - - // BGReminderEnable(144, "BG Reminder Enable", MinimedTargetType.PumpConfiguration, - // MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters), // - - // ReadInsulinSensitivities(0x8b, "Read Insulin Sensitivities", MinimedTargetType.PumpConfiguration, - // MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters), // 139 - - // 512 Data - GetHistoryData(128, "Get History", MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.SubCommands, // - 1024, 16, 1024, R.string.medtronic_cmd_desc_get_history), // 0x80 - - GetBasalProfileSTD(146, "Get Profile Standard", MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters, // - 64, 3, 192, R.string.medtronic_cmd_desc_get_basal_profile), // 146 - - GetBasalProfileA(147, "Get Profile A", MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters, // - 64, 3, 192, R.string.medtronic_cmd_desc_get_basal_profile), - - GetBasalProfileB(148, "Get Profile B", MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters, // - 64, 3, 192, R.string.medtronic_cmd_desc_get_basal_profile), // 148 - - SetBasalProfileSTD(0x6f, "Set Profile Standard", MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters, // - 64, 3, 192, R.string.medtronic_cmd_desc_set_basal_profile), // 111 - - SetBasalProfileA(0x30, "Set Profile A", MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters, // - 64, 3, 192, R.string.medtronic_cmd_desc_set_basal_profile), // 48 - - SetBasalProfileB(0x31, "Set Profile B", MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters, // - 64, 3, 192, R.string.medtronic_cmd_desc_set_basal_profile), // 49 - - // 515 - PumpStatus(206, "Pump Status", MedtronicDeviceType.Medtronic_515andHigher, MinimedCommandParameterType.NoParameters), // PumpConfiguration - - Settings(192, "Configuration", MedtronicDeviceType.Medtronic_515andHigher, MinimedCommandParameterType.NoParameters, // - 64, 1, 21, R.string.medtronic_cmd_desc_get_settings), // - - // 522 - SensorSettings_522(153, "Sensor Configuration", MedtronicDeviceType.Medtronic_522andHigher, MinimedCommandParameterType.NoParameters), // - - GlucoseHistory(154, "Glucose History", MedtronicDeviceType.Medtronic_522andHigher, MinimedCommandParameterType.SubCommands, 1024, 32, 0, null), // - - // 523 - SensorSettings(207, "Sensor Configuration", MedtronicDeviceType.Medtronic_523andHigher, MinimedCommandParameterType.NoParameters), // - - // 553 - // 554 - - // var MESSAGES = { - // READ_TIME : 0x70, - // READ_BATTERY_STATUS: 0x72, - // READ_HISTORY : 0x80, - // READ_CARB_RATIOS : 0x8A, - // READ_INSULIN_SENSITIVITIES: 0x8B, - // READ_MODEL : 0x8D, - // READ_PROFILE_STD : 0x92, - // READ_PROFILE_A : 0x93, - // READ_PROFILE_B : 0x94, - // READ_CBG_HISTORY: 0x9A, - // READ_ISIG_HISTORY: 0x9B, - // READ_CURRENT_PAGE : 0x9D, - // READ_BG_TARGETS : 0x9F, - // READ_SETTINGS : 0xC0, 192 - // READ_CURRENT_CBG_PAGE : 0xCD - // }; - - // Fake Commands - - CancelTBR(), - ; - - static Map mapByCode; - - static { - MedtronicCommandType.RFPowerOn.maxAllowedTime = 17000; - MedtronicCommandType.RFPowerOn.allowedRetries = 0; - MedtronicCommandType.RFPowerOn.recordLength = 0; - MedtronicCommandType.RFPowerOn.minimalBufferSizeToStartReading = 1; - - mapByCode = new HashMap<>(); - - for (MedtronicCommandType medtronicCommandType : values()) { - mapByCode.put(medtronicCommandType.getCommandCode(), medtronicCommandType); - } - } - - public byte commandCode = 0; - public String commandDescription = ""; - public byte[] commandParameters = null; - public int commandParametersCount = 0; - public int maxRecords = 1; - private Integer resourceId; - public int command_type = 0; - public int allowedRetries = 2; - public int maxAllowedTime = 2000; - public MinimedCommandParameterType parameterType; - public int minimalBufferSizeToStartReading = 14; - public int expectedLength = 0; - //MinimedTargetType targetType; - MedtronicDeviceType devices; - private int recordLength = 64; - - - MedtronicCommandType() { - // this is for "fake" commands needed by AAPS MedtronicUITask - } - - - MedtronicCommandType(int code, String description, MedtronicDeviceType devices, - MinimedCommandParameterType parameterType, byte[] cmd_params) { - this(code, description, devices, parameterType, 0, 1, 0, 0, 11, 0); - - this.commandParameters = cmd_params; - this.commandParametersCount = cmd_params.length; - } - - - MedtronicCommandType(int code, String description, MedtronicDeviceType devices, // - MinimedCommandParameterType parameterType) { - - this(code, description, devices, parameterType, 64, 1, 0, null); - } - - // NEW - MedtronicCommandType(int code, String description, MedtronicDeviceType devices, // - MinimedCommandParameterType parameterType, int expectedLength) { - this(code, description, devices, parameterType, 64, 1, expectedLength, null); - } - - - // NEW - MedtronicCommandType(int code, String description, MedtronicDeviceType devices, // - MinimedCommandParameterType parameterType, int expectedLength, int resourceId) { - this(code, description, devices, parameterType, 64, 1, expectedLength, resourceId); - } - - - // NEW - MedtronicCommandType(int code, String description, - MedtronicDeviceType devices, // - MinimedCommandParameterType parameterType, int recordLength, int max_recs, int expectedLength, - Integer resourceId) { - this.commandCode = (byte) code; - this.commandDescription = description; - this.devices = devices; - this.recordLength = recordLength; - this.maxRecords = max_recs; - this.resourceId = resourceId; - - this.commandParametersCount = 0; - this.allowedRetries = 2; - this.parameterType = parameterType; - this.expectedLength = expectedLength; - - if (this.parameterType == MinimedCommandParameterType.SubCommands) { - this.minimalBufferSizeToStartReading = 200; - } - } - - - @Deprecated - MedtronicCommandType(int code, String description, MedtronicDeviceType devices, // - MinimedCommandParameterType parameterType, int recordLength, int max_recs, int addy, // - int addy_len, int cmd_type, int expectedLength) { - this.commandCode = (byte) code; - this.commandDescription = description; - //this.targetType = targetType; - this.devices = devices; - this.recordLength = recordLength; - this.maxRecords = max_recs; - - this.command_type = cmd_type; - this.commandParametersCount = 0; - this.allowedRetries = 2; - this.parameterType = parameterType; - this.expectedLength = expectedLength; - - if (this.parameterType == MinimedCommandParameterType.SubCommands) { - this.minimalBufferSizeToStartReading = 200; - } - - } - - - private static HashMap getDeviceTypesArray(MedtronicDeviceType... types) { - HashMap hashMap = new HashMap(); - - for (MedtronicDeviceType type : types) { - hashMap.put(type, null); - } - - return hashMap; - } - - - private static byte[] getByteArray(int... data) { - byte[] array = new byte[data.length]; - - for (int i = 0; i < data.length; i++) { - array[i] = (byte) data[i]; - } - - return array; - } - - - private static int[] getIntArray(int... data) { - return data; - } - - - public static MedtronicCommandType getByCode(byte code) { - if (mapByCode.containsKey(code)) { - return mapByCode.get(code); - } else { - return MedtronicCommandType.InvalidCommand; - } - } - - - public static MessageBody constructMessageBody(MedtronicCommandType messageType, byte[] bodyData) { - switch (messageType) { - case CommandACK: - return new PumpAckMessageBody(bodyData); - default: - return new UnknownMessageBody(bodyData); - } - } - - - public static MedtronicCommandType getSettings(MedtronicDeviceType medtronicPumpModel) { - if (MedtronicDeviceType.isSameDevice(medtronicPumpModel, MedtronicDeviceType.Medtronic_512_712)) - return MedtronicCommandType.Settings_512; - else - return MedtronicCommandType.Settings; - } - - - /** - * Get Full Command Description - * - * @return command description - */ - public String getFullCommandDescription() { - return "Command [name=" + this.name() + ", id=" + this.commandCode + ",description=" + this.commandDescription - + "] "; - } - - - public byte getCommandCode() { - return commandCode; - } - - - public int getCommandParametersCount() { - if (this.commandParameters == null) { - return 0; - } else { - return this.commandParameters.length; - } - } - - - public String toString() { - return name(); - } - - - public String getCommandDescription() { - return this.commandDescription; - } - - - public Integer getResourceId() { - return resourceId; - } - - public enum MinimedCommandParameterType { - NoParameters, // - FixedParameters, // - SubCommands // - } - -} 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 new file mode 100755 index 0000000000..47d4f4f1ba --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicCommandType.kt @@ -0,0 +1,285 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.defs + +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.* + +/** + * Taken from GNU Gluco Control diabetes management software (ggc.sourceforge.net) + * + * + * Description: Medtronic Commands (Pump and CGMS) for all 512 and later models (just 5xx) + * + * + * Link to original/unmodified file: + * https://sourceforge.net/p/ggc/code/HEAD/tree/trunk/ggc-plugins/ggc-plugins-base/src/ + * main/java/ggc/plugin/device/impl/minimed/enums/MinimedCommandType.java + * + * + * A lot of stuff has been removed because it is not needed anymore (historical stuff from CareLink + * and Carelink USB communication. + * + * + * Author: Andy {andy@atech-software.com} + */ +enum class MedtronicCommandType +{ + + InvalidCommand(0, "Invalid Command", null, null), // + + // Pump Responses (9) + CommandACK(0x06, "ACK - Acknowledge", MedtronicDeviceType.All, MinimedCommandParameterType.NoParameters), // + CommandNAK(0x15, "NAK - Not Acknowledged", MedtronicDeviceType.All, MinimedCommandParameterType.NoParameters), // + + // All (8) + PushAck(91, "Push ACK", MedtronicDeviceType.All, MinimedCommandParameterType.FixedParameters, byteArrayOf(2)), // + PushEsc(91, "Push Esc", MedtronicDeviceType.All, MinimedCommandParameterType.FixedParameters, byteArrayOf(1)), // + PushButton(0x5b, "Push Button", MedtronicDeviceType.All, MinimedCommandParameterType.NoParameters), // 91 + RFPowerOn(93, "RF Power On", MedtronicDeviceType.All, MinimedCommandParameterType.FixedParameters, byteArrayOf(1, 10)), // + RFPowerOff(93, "RF Power Off", MedtronicDeviceType.All, MinimedCommandParameterType.FixedParameters, byteArrayOf(0, 0)), // + + // SetSuspend(77, "Set Suspend", MinimedTargetType.InitCommand, MedtronicDeviceType.All, MinimedCommandParameterType.FixedParameters, getByteArray(1)), // + // CancelSuspend(77, "Cancel Suspend", MinimedTargetType.InitCommand, MedtronicDeviceType.All,MinimedCommandParameterType.FixedParameters, getByteArray(0)), // + PumpState(131, "Pump State", MedtronicDeviceType.All, MinimedCommandParameterType.NoParameters), // + ReadPumpErrorStatus(117, "Pump Error Status", MedtronicDeviceType.All, MinimedCommandParameterType.NoParameters), // + + // 511 (InitCommand = 2, Config 7, Data = 1(+3) + // DetectBolus(75, "Detect Bolus", MedtronicDeviceType.Medtronic_511, MinimedCommandParameterType.FixedParameters, getByteArray( + // 0, 0, 0)), // + // RemoteControlIds(118, "Remote Control Ids", MinimedTargetType.PumpConfiguration_NA, MedtronicDeviceType.All,MinimedCommandParameterType.NoParameters), // + // FirmwareVersion(116, "Firmware Version", MinimedTargetType.InitCommand, MedtronicDeviceType.All,MinimedCommandParameterType.NoParameters), // + // PumpId(113, "Pump Id", MinimedTargetType.PumpConfiguration, MedtronicDeviceType.All,MinimedCommandParameterType.NoParameters), // init + SetRealTimeClock(0x40, "Set Pump Time", MedtronicDeviceType.All, MinimedCommandParameterType.NoParameters, // + 0, R.string.medtronic_cmd_desc_set_time), // + GetRealTimeClock(112, "Get Pump Time", MedtronicDeviceType.All, MinimedCommandParameterType.NoParameters, // + 7, R.string.medtronic_cmd_desc_get_time), // 0x70 + GetBatteryStatus(0x72, "Get Battery Status", MedtronicDeviceType.All, MinimedCommandParameterType.NoParameters, + 0, R.string.medtronic_cmd_desc_get_battery_status), // + GetRemainingInsulin(0x73, "Read Remaining Insulin", MedtronicDeviceType.All, MinimedCommandParameterType.NoParameters, 2), // 115 + SetBolus(0x42, "Set Bolus", MedtronicDeviceType.All, MinimedCommandParameterType.NoParameters, // + 0, R.string.medtronic_cmd_desc_set_bolus), // 66 + + // 512 + ReadTemporaryBasal(0x98, "Read Temporary Basal", MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters, // + 5, R.string.medtronic_cmd_desc_get_tbr), // 152 + SetTemporaryBasal(76, "Set Temporay Basal", MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters, // + 0, R.string.medtronic_cmd_desc_set_tbr), // 512 Config + PumpModel(141, "Pump Model", MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters, // + 5, R.string.medtronic_cmd_desc_get_model), // 0x8D + + // BGTargets_512(140, "BG Targets", MinimedTargetType.PumpConfiguration, MedtronicDeviceType.Medtronic_512_712, + // MinimedCommandParameterType.NoParameters), // + // BGUnits(137, "BG Units", MinimedTargetType.PumpConfiguration, MedtronicDeviceType.Medtronic_512andHigher, + // MinimedCommandParameterType.NoParameters), // + // Language(134, "Language", MinimedTargetType.PumpConfiguration, MedtronicDeviceType.Medtronic_512andHigher, + // MinimedCommandParameterType.NoParameters), // + Settings_512(145, "Configuration", MedtronicDeviceType.Medtronic_512_712, MinimedCommandParameterType.NoParameters, // + 64, 1, 18, R.string.medtronic_cmd_desc_get_settings), // + + // 512 Data + GetHistoryData(128, "Get History", MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.SubCommands, // + 1024, 16, 1024, R.string.medtronic_cmd_desc_get_history), // 0x80 + GetBasalProfileSTD(146, "Get Profile Standard", MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters, // + 64, 3, 192, R.string.medtronic_cmd_desc_get_basal_profile), // 146 + GetBasalProfileA(147, "Get Profile A", MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters, // + 64, 3, 192, R.string.medtronic_cmd_desc_get_basal_profile), + GetBasalProfileB(148, "Get Profile B", MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters, // + 64, 3, 192, R.string.medtronic_cmd_desc_get_basal_profile), // 148 + SetBasalProfileSTD(0x6f, "Set Profile Standard", MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters, // + 64, 3, 192, R.string.medtronic_cmd_desc_set_basal_profile), // 111 + SetBasalProfileA(0x30, "Set Profile A", MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters, // + 64, 3, 192, R.string.medtronic_cmd_desc_set_basal_profile), // 48 + SetBasalProfileB(0x31, "Set Profile B", MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters, // + 64, 3, 192, R.string.medtronic_cmd_desc_set_basal_profile), // 49 + + // 515 + PumpStatus(206, "Pump Status", MedtronicDeviceType.Medtronic_515andHigher, MinimedCommandParameterType.NoParameters), // PumpConfiguration + Settings(192, "Configuration", MedtronicDeviceType.Medtronic_515andHigher, MinimedCommandParameterType.NoParameters, // + 64, 1, 21, R.string.medtronic_cmd_desc_get_settings), // + + // 522 + SensorSettings_522(153, "Sensor Configuration", MedtronicDeviceType.Medtronic_522andHigher, MinimedCommandParameterType.NoParameters), // + GlucoseHistory(154, "Glucose History", MedtronicDeviceType.Medtronic_522andHigher, MinimedCommandParameterType.SubCommands, 1024, 32, 0, null), // + + // 523 + SensorSettings(207, "Sensor Configuration", MedtronicDeviceType.Medtronic_523andHigher, MinimedCommandParameterType.NoParameters), // + + // 553 + // 554 + // var MESSAGES = { + // READ_TIME : 0x70, + // READ_BATTERY_STATUS: 0x72, + // READ_HISTORY : 0x80, + // READ_CARB_RATIOS : 0x8A, + // READ_INSULIN_SENSITIVITIES: 0x8B, + // READ_MODEL : 0x8D, + // READ_PROFILE_STD : 0x92, + // READ_PROFILE_A : 0x93, + // READ_PROFILE_B : 0x94, + // READ_CBG_HISTORY: 0x9A, + // READ_ISIG_HISTORY: 0x9B, + // READ_CURRENT_PAGE : 0x9D, + // READ_BG_TARGETS : 0x9F, + // READ_SETTINGS : 0xC0, 192 + // READ_CURRENT_CBG_PAGE : 0xCD + // }; + // Fake Commands + CancelTBR; + + + + 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() + // } + // return array + // } + + // 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] + } else { + InvalidCommand + } + } + + fun constructMessageBody(messageType: MedtronicCommandType?, bodyData: ByteArray?): MessageBody { + return when (messageType) { + CommandACK -> PumpAckMessageBody(bodyData) + else -> UnknownMessageBody(bodyData!!) + } + } + + @JvmStatic + fun getSettings(medtronicPumpModel: MedtronicDeviceType?): MedtronicCommandType { + return if (isSameDevice(medtronicPumpModel!!, MedtronicDeviceType.Medtronic_512_712)) Settings_512 else Settings + } + + init { + RFPowerOn.maxAllowedTime = 17000 + RFPowerOn.allowedRetries = 0 + RFPowerOn.recordLength = 0 + RFPowerOn.minimalBufferSizeToStartReading = 1 + for (medtronicCommandType in values()) { + mapByCode[medtronicCommandType.commandCode] = medtronicCommandType + } + } + } + + var commandCode: Byte = 0 + var commandDescription = "" + var commandParameters: ByteArray? = null + var commandParametersCount = 0 + var maxRecords = 1 + var resourceId: Int? = null + private set + var command_type = 0 + var allowedRetries = 2 + var maxAllowedTime = 2000 + var parameterType: MinimedCommandParameterType? = null + var minimalBufferSizeToStartReading = 14 + var expectedLength = 0 + var devices: MedtronicDeviceType? = null + private var recordLength = 64 + + constructor() { + // this is for "fake" commands needed by AAPS MedtronicUITask + } + + constructor(code: Int, description: String, devices: MedtronicDeviceType?, + parameterType: MinimedCommandParameterType?, cmd_params: ByteArray) : this(code, description, devices, parameterType, 0, 1, 0, 0, 11, 0) { + commandParameters = cmd_params + commandParametersCount = cmd_params.size + } + + // NEW + constructor(code: Int, description: String, devices: MedtronicDeviceType?, // + parameterType: MinimedCommandParameterType?, expectedLength: Int) : this(code, description, devices, parameterType, 64, 1, expectedLength, null) { + } + + // NEW + constructor(code: Int, description: String, devices: MedtronicDeviceType?, // + parameterType: MinimedCommandParameterType?, expectedLength: Int, resourceId: Int) : this(code, description, devices, parameterType, 64, 1, expectedLength, resourceId) { + } + + // NEW + 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 + this.recordLength = recordLength + maxRecords = max_recs + this.resourceId = resourceId + 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 { + return name + } + + enum class MinimedCommandParameterType { + NoParameters, // + FixedParameters, // + SubCommands // + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicCustomActionType.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicCustomActionType.java deleted file mode 100644 index af0be33cfa..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicCustomActionType.java +++ /dev/null @@ -1,20 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.defs; - -import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType; - -/** - * Created by andy on 11/3/18. - */ - -public enum MedtronicCustomActionType implements CustomActionType { - - WakeUpAndTune(), // - ClearBolusBlock(), // - ResetRileyLinkConfiguration(), // - ; - - @Override - public String getKey() { - return this.name(); - } -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicCustomActionType.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicCustomActionType.kt new file mode 100644 index 0000000000..80713a7fa5 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicCustomActionType.kt @@ -0,0 +1,19 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.defs + +import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType + +/** + * Created by andy on 11/3/18. + */ +enum class MedtronicCustomActionType : CustomActionType { + + WakeUpAndTune, // + ClearBolusBlock, // + ResetRileyLinkConfiguration; + + // + + override fun getKey(): String { + return name + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicDeviceType.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicDeviceType.java deleted file mode 100644 index 6623a6f9d8..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicDeviceType.java +++ /dev/null @@ -1,140 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.defs; - -import java.util.HashMap; -import java.util.Map; - -/** - * Taken from GNU Gluco Control diabetes management software (ggc.sourceforge.net) - *

- * Author: Andy {andy@atech-software.com} - */ - -public enum MedtronicDeviceType { - Unknown_Device, // - - // Pump - Medtronic_511("511"), // - - Medtronic_512("512"), // - Medtronic_712("712"), // - Medtronic_512_712(Medtronic_512, Medtronic_712), // - - Medtronic_515("515"), // - Medtronic_715("715"), // - Medtronic_515_715(Medtronic_515, Medtronic_715), // - - Medtronic_522("522"), // - Medtronic_722("722"), // - Medtronic_522_722(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), // - - - // - All; - - static Map mapByDescription; - - static { - - mapByDescription = new HashMap<>(); - - for (MedtronicDeviceType minimedDeviceType : values()) { - - if (!minimedDeviceType.isFamily) { - mapByDescription.put(minimedDeviceType.pumpModel, minimedDeviceType); - } - } - - } - - private String pumpModel; - - private final boolean isFamily; - private MedtronicDeviceType[] familyMembers = null; - - - MedtronicDeviceType(String pumpModel) { - this.isFamily = false; - this.pumpModel = pumpModel; - } - - - MedtronicDeviceType(MedtronicDeviceType... familyMembers) { - this.familyMembers = familyMembers; - this.isFamily = true; - } - - - public static boolean isSameDevice(MedtronicDeviceType deviceWeCheck, MedtronicDeviceType deviceSources) { - if (deviceSources.isFamily) { - for (MedtronicDeviceType mdt : deviceSources.familyMembers) { - if (mdt == deviceWeCheck) - return true; - } - } else { - return (deviceWeCheck == deviceSources); - } - - return false; - } - - - public static MedtronicDeviceType getByDescription(String desc) { - if (mapByDescription.containsKey(desc)) { - return mapByDescription.get(desc); - } else { - return MedtronicDeviceType.Unknown_Device; - } - } - - -// public static boolean isLargerFormat(MedtronicDeviceType model) { -// return isSameDevice(model, Medtronic_523andHigher); -// } - - - public boolean isFamily() { - return isFamily; - } - - - public MedtronicDeviceType[] getFamilyMembers() { - return familyMembers; - } - - -// public boolean isLargerFormat() { -// return isSameDevice(this, Medtronic_523andHigher); -// } - - public boolean isMedtronic_523orHigher() { - return isSameDevice(this, Medtronic_523andHigher); - } - - - public int getBolusStrokes() { - return (isMedtronic_523orHigher()) ? 40 : 10; - } - - - public String getPumpModel() { - return pumpModel; - } -} 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 new file mode 100644 index 0000000000..6f4cf7704c --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicDeviceType.kt @@ -0,0 +1,100 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.defs + +import java.util.* + +/** + * Taken from GNU Gluco Control diabetes management software (ggc.sourceforge.net) + * + * + * Author: Andy {andy@atech-software.com} + */ +enum class MedtronicDeviceType { + + Unknown_Device, // + + // Pump + Medtronic_511("511"), // + Medtronic_512("512"), // + Medtronic_712("712"), // + Medtronic_512_712(Medtronic_512, Medtronic_712), // + Medtronic_515("515"), // + Medtronic_715("715"), // + Medtronic_515_715(Medtronic_515, Medtronic_715), // + Medtronic_522("522"), // + Medtronic_722("722"), // + Medtronic_522_722(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), // + + // + All; + + companion object { + var mapByDescription: MutableMap? = null + + @JvmStatic + fun isSameDevice(deviceWeCheck: MedtronicDeviceType, deviceSources: MedtronicDeviceType): Boolean { + if (deviceSources.isFamily) { + for (mdt in deviceSources.familyMembers!!) { + if (mdt == deviceWeCheck) return true + } + } else { + return deviceWeCheck == deviceSources + } + return false + } + + fun getByDescription(desc: String): MedtronicDeviceType { + return if (mapByDescription==null) { + Unknown_Device + } else if (mapByDescription!!.containsKey(desc)) { + mapByDescription!![desc]!! + } else { + Unknown_Device + } + } + + init { + mapByDescription = HashMap() + for (minimedDeviceType in values()) { + if (!minimedDeviceType.isFamily) { + mapByDescription!![minimedDeviceType.pumpModel!!] = minimedDeviceType + } + } + } + } + + var pumpModel: String? = null + private set + + // public static boolean isLargerFormat(MedtronicDeviceType model) { + // return isSameDevice(model, Medtronic_523andHigher); + // } + val isFamily: Boolean + var familyMembers: Array? = null + private set + + constructor(pumpModel: String?) { + isFamily = false + this.pumpModel = pumpModel + } + + constructor(vararg familyMembers: MedtronicDeviceType) { + this.familyMembers = familyMembers as Array? + isFamily = true + } + + val isMedtronic_523orHigher: Boolean + get() = isSameDevice(this, Medtronic_523andHigher) + + val bolusStrokes: Int + get() = if (isMedtronic_523orHigher) 40 else 10 + +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicNotificationType.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicNotificationType.java deleted file mode 100644 index b05fce81fc..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicNotificationType.java +++ /dev/null @@ -1,65 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.defs; - -import info.nightscout.androidaps.plugins.general.overview.notifications.Notification; -import info.nightscout.androidaps.plugins.pump.medtronic.R; - -/** - * Created by andy on 10/15/18. - */ - -public enum MedtronicNotificationType { - - PumpUnreachable(Notification.RILEYLINK_CONNECTION, R.string.medtronic_pump_status_pump_unreachable, Notification.NORMAL), // - PumpTypeNotSame(R.string.medtronic_error_pump_type_set_differs_from_detected, Notification.NORMAL), // - PumpBasalProfilesNotEnabled(R.string.medtronic_error_pump_basal_profiles_not_enabled, Notification.URGENT), // - PumpIncorrectBasalProfileSelected(R.string.medtronic_error_pump_incorrect_basal_profile_selected, Notification.URGENT), // - PumpWrongTBRTypeSet(R.string.medtronic_error_pump_wrong_tbr_type_set, Notification.URGENT), // - PumpWrongMaxBolusSet(R.string.medtronic_error_pump_wrong_max_bolus_set, Notification.NORMAL), // - PumpWrongMaxBasalSet(R.string.medtronic_error_pump_wrong_max_basal_set, Notification.NORMAL), // - PumpWrongTimeUrgent(R.string.medtronic_notification_check_time_date, Notification.URGENT), - PumpWrongTimeNormal(R.string.medtronic_notification_check_time_date, Notification.NORMAL), - TimeChangeOver24h(Notification.OVER_24H_TIME_CHANGE_REQUESTED, R.string.medtronic_error_pump_24h_time_change_requested, Notification.URGENT), - // - ; - - private int notificationType; - private final int resourceId; - private final int notificationUrgency; - - - MedtronicNotificationType(int resourceId, int notificationUrgency) { - this(Notification.MEDTRONIC_PUMP_ALARM, resourceId, notificationUrgency); - } - - - MedtronicNotificationType(int notificationType, int resourceId, int notificationUrgency) { - this.notificationType = notificationType; - this.resourceId = resourceId; - this.notificationUrgency = notificationUrgency; - } - - - public int getNotificationType() { - return notificationType; - } - - - public void setNotificationType(int notificationType) { - this.notificationType = notificationType; - } - - - public int getResourceId() { - - return resourceId; - } - - - public int getNotificationUrgency() { - - return notificationUrgency; - } - - // Notification.MEDTRONIC_PUMP_ALARM R.string.medtronic_pump_status_pump_unreachable, Notification.NORMAL - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicNotificationType.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicNotificationType.kt new file mode 100644 index 0000000000..aad989679d --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicNotificationType.kt @@ -0,0 +1,23 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.defs + +import info.nightscout.androidaps.plugins.general.overview.notifications.Notification +import info.nightscout.androidaps.plugins.pump.medtronic.R + +/** + * Created by andy on 10/15/18. + */ +enum class MedtronicNotificationType(var notificationType: Int, + val resourceId: Int, + val notificationUrgency: Int) { + + PumpUnreachable(Notification.RILEYLINK_CONNECTION, R.string.medtronic_pump_status_pump_unreachable, Notification.NORMAL), // + PumpTypeNotSame(R.string.medtronic_error_pump_type_set_differs_from_detected, Notification.NORMAL), // + PumpBasalProfilesNotEnabled(R.string.medtronic_error_pump_basal_profiles_not_enabled, Notification.URGENT), // + PumpIncorrectBasalProfileSelected(R.string.medtronic_error_pump_incorrect_basal_profile_selected, Notification.URGENT), // + PumpWrongTBRTypeSet(R.string.medtronic_error_pump_wrong_tbr_type_set, Notification.URGENT), // + PumpWrongMaxBolusSet(R.string.medtronic_error_pump_wrong_max_bolus_set, Notification.NORMAL), // + PumpWrongMaxBasalSet(R.string.medtronic_error_pump_wrong_max_basal_set, Notification.NORMAL), // + PumpWrongTimeUrgent(R.string.medtronic_notification_check_time_date, Notification.URGENT), PumpWrongTimeNormal(R.string.medtronic_notification_check_time_date, Notification.NORMAL), TimeChangeOver24h(Notification.OVER_24H_TIME_CHANGE_REQUESTED, R.string.medtronic_error_pump_24h_time_change_requested, Notification.URGENT); + + constructor(resourceId: Int, notificationUrgency: Int) : this(Notification.MEDTRONIC_PUMP_ALARM, resourceId, notificationUrgency) {} +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicStatusRefreshType.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicStatusRefreshType.java deleted file mode 100644 index f84f6d3678..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicStatusRefreshType.java +++ /dev/null @@ -1,37 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.defs; - -/** - * Created by andy on 6/28/18. - */ - -public enum MedtronicStatusRefreshType { - - PumpHistory(5, null), // - Configuration(0, null), // - RemainingInsulin(-1, MedtronicCommandType.GetRemainingInsulin), // - BatteryStatus(55, MedtronicCommandType.GetBatteryStatus), // - PumpTime(60, MedtronicCommandType.GetRealTimeClock) // - ; - - private final int refreshTime; - private final MedtronicCommandType commandType; - - - MedtronicStatusRefreshType(int refreshTime, MedtronicCommandType commandType) { - this.refreshTime = refreshTime; - this.commandType = commandType; - } - - - public int getRefreshTime() { - return refreshTime; - } - - - public MedtronicCommandType getCommandType(MedtronicDeviceType medtronicDeviceType) { - if (this == Configuration) { - return MedtronicCommandType.getSettings(medtronicDeviceType); - } else - return commandType; - } -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicStatusRefreshType.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicStatusRefreshType.kt new file mode 100644 index 0000000000..5a416b80a8 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicStatusRefreshType.kt @@ -0,0 +1,23 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.defs + +/** + * Created by andy on 6/28/18. + */ +enum class MedtronicStatusRefreshType(val refreshTime: Int, + private val commandType: MedtronicCommandType?) { + + PumpHistory(5, null), // + Configuration(0, null), // + RemainingInsulin(-1, MedtronicCommandType.GetRemainingInsulin), // + BatteryStatus(55, MedtronicCommandType.GetBatteryStatus), // + PumpTime(60, MedtronicCommandType.GetRealTimeClock // + ); + + fun getCommandType(medtronicDeviceType: MedtronicDeviceType?): MedtronicCommandType? { + return if (this == Configuration) { + MedtronicCommandType.getSettings(medtronicDeviceType) + } else + commandType + } + +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicUIResponseType.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicUIResponseType.java deleted file mode 100644 index 8ab1fc0871..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicUIResponseType.java +++ /dev/null @@ -1,13 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.defs; - -/** - * Created by andy on 10/18/18. - */ - -public enum MedtronicUIResponseType { - - Data, - Error, - Invalid - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicUIResponseType.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicUIResponseType.kt new file mode 100644 index 0000000000..6067085071 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/MedtronicUIResponseType.kt @@ -0,0 +1,9 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.defs + +/** + * Created by andy on 10/18/18. + */ +enum class MedtronicUIResponseType { + + Data, Error, Invalid +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/PumpBolusType.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/PumpBolusType.java deleted file mode 100644 index 820bff8a5b..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/PumpBolusType.java +++ /dev/null @@ -1,129 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.defs; - -import java.util.HashMap; - -/** - * Application: GGC - GNU Gluco Control - * Plug-in: Pump Tool (support for Pump devices) - *

- * See AUTHORS for copyright information. - *

- * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later - * version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - *

- * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free - * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - *

- * Filename: PumpBolusType Description: Pump Bolus Types - *

- * Author: Andy {andy@atech-software.com} - */ - -public enum PumpBolusType // implements CodeEnumWithTranslation -{ - None(0, "NONE"), // - Normal(1, "BOLUS_STANDARD"), // - Audio(2, "BOLUS_AUDIO"), // - Extended(3, "BOLUS_SQUARE", "AMOUNT_SQUARE=%s;DURATION=%s"), // - Multiwave(4, "BOLUS_MULTIWAVE", "AMOUNT=%s;AMOUNT_SQUARE=%s;DURATION=%s"); - - static String[] descriptions; - // static HashMap translationMapping = new HashMap(); - static HashMap codeMapping = new HashMap(); - private static boolean translated; - - static { - for (PumpBolusType pbt : values()) { - codeMapping.put(pbt.code, pbt); - } - } - - // public static void translateKeywords(I18nControlAbstract ic) - // { - // if (translated) - // return; - // - // for (PumpBolusType pbt : values()) - // { - // pbt.setTranslation(ic.getMessage(pbt.i18nKey)); - // translationMapping.put(pbt.getTranslation(), pbt); - // } - // - // String[] bolusDescriptions = { ic.getMessage("SELECT_BOLUS_TYPE"), // - // ic.getMessage("BOLUS_STANDARD"), // - // ic.getMessage("BOLUS_AUDIO"), // - // ic.getMessage("BOLUS_SQUARE"), // - // ic.getMessage("BOLUS_MULTIWAVE"), }; - // - // descriptions = bolusDescriptions; - // - // translated = true; - // } - - int code; - String i18nKey; - String translation; - String valueTemplate; - - - PumpBolusType(int code, String i18nKey) { - this.code = code; - this.i18nKey = i18nKey; - } - - - PumpBolusType(int code, String i18nKey, String valueTemplate) { - this.code = code; - this.i18nKey = i18nKey; - this.valueTemplate = valueTemplate; - } - - - public static PumpBolusType getByCode(int code) { - if (codeMapping.containsKey(code)) { - return codeMapping.get(code); - } else { - return PumpBolusType.None; - } - } - - - /** - * Get Descriptions (array) - * - * @return array of strings with description - */ - public static String[] getDescriptions() { - return descriptions; - } - - - public String getTranslation() { - return translation; - } - - - public void setTranslation(String translation) { - this.translation = translation; - } - - - public int getCode() { - return code; - } - - - public String getI18nKey() { - return i18nKey; - } - - - public String getName() { - return this.name(); - } -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/PumpBolusType.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/PumpBolusType.kt new file mode 100644 index 0000000000..02e3bdbd2b --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/PumpBolusType.kt @@ -0,0 +1,54 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.defs + +import java.util.* + +/** + * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes + * management and modified/extended for AAPS. + * + * + * Author: Andy {andy.rozman@gmail.com} + */ +enum class PumpBolusType { + + None(0, "NONE"), // + Normal(1, "BOLUS_STANDARD"), // + Audio(2, "BOLUS_AUDIO"), // + Extended(3, "BOLUS_SQUARE", "AMOUNT_SQUARE=%s;DURATION=%s"), // + Multiwave(4, "BOLUS_MULTIWAVE", "AMOUNT=%s;AMOUNT_SQUARE=%s;DURATION=%s"); + + companion object { + var codeMapping = HashMap() + + fun getByCode(code: Int): PumpBolusType? { + return if (codeMapping.containsKey(code)) { + codeMapping[code] + } else { + None + } + } + + init { + for (pbt in values()) { + codeMapping[pbt.code] = pbt + } + } + } + + var code: Int + var i18nKey: String + var valueTemplate: String? = null + + constructor(code: Int, i18nKey: String) { + this.code = code + this.i18nKey = i18nKey + } + + constructor(code: Int, i18nKey: String, valueTemplate: String?) { + this.code = code + this.i18nKey = i18nKey + this.valueTemplate = valueTemplate + } + + //override val name: String +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/PumpConfigurationGroup.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/PumpConfigurationGroup.java deleted file mode 100644 index 1c69641c98..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/PumpConfigurationGroup.java +++ /dev/null @@ -1,58 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.defs; - -/** - * Created by andy on 27.02.15. - */ -public enum PumpConfigurationGroup { - General(1, "GROUP_GENERAL"), // - Device(2, "GROUP_DEVICE"), // - - Insulin(3, "GROUP_INSULIN"), // - - Basal(4, "GROUP_BASAL"), // - Bolus(5, "GROUP_BOLUS"), // - Sound(6, "GROUP_SOUND"), // - - Other(20, "GROUP_OTHER"), // - - UnknownGroup(21, "GROUP_UNKNOWN"), // - - ; // - - static boolean translated; - int code; - String i18nKey; - String translation; - - - PumpConfigurationGroup(int code, String i18nKey) { - this.code = code; - this.i18nKey = i18nKey; - } - - - public String getTranslation() { - return translation; - } - - - public void setTranslation(String translation) { - this.translation = translation; - } - - - public int getCode() { - return code; - } - - - public String getI18nKey() { - return i18nKey; - } - - - public String getName() { - return this.name(); - } - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/PumpConfigurationGroup.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/PumpConfigurationGroup.kt new file mode 100644 index 0000000000..6a1c13a628 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/PumpConfigurationGroup.kt @@ -0,0 +1,20 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.defs + +/** + * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes + * management and modified/extended for AAPS. + * + * Author: Andy {andy.rozman@gmail.com} + */ +enum class PumpConfigurationGroup(var code: Int) { + + General(1), // + Device(2), // + Insulin(3), // + Basal(4), // + Bolus(5), // + Sound(6), // + Other(20), // + UnknownGroup(21); + +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/driver/MedtronicPumpStatus.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/driver/MedtronicPumpStatus.java deleted file mode 100644 index 905a005e29..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/driver/MedtronicPumpStatus.java +++ /dev/null @@ -1,180 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.driver; - -import androidx.annotation.NonNull; - -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.Map; - -import javax.inject.Inject; -import javax.inject.Singleton; - -import info.nightscout.androidaps.plugins.bus.RxBusWrapper; -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.events.EventRileyLinkDeviceStatusChange; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkUtil; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.data.RLHistoryItem; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkTargetDevice; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.BasalProfileStatus; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.BatteryType; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicDeviceType; -import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicConst; -import info.nightscout.androidaps.utils.resources.ResourceHelper; -import info.nightscout.androidaps.utils.sharedPreferences.SP; - - -/** - * Created by andy on 4/28/18. - */ - -@Singleton -public class MedtronicPumpStatus extends info.nightscout.androidaps.plugins.pump.common.data.PumpStatus { - - private final ResourceHelper resourceHelper; - private final SP sp; - private final RileyLinkUtil rileyLinkUtil; - private final RxBusWrapper rxBus; - - public String errorDescription = null; - public String serialNumber; - public String pumpFrequency = null; - public Double maxBolus; - public Double maxBasal; - - // statuses - private PumpDeviceState pumpDeviceState = PumpDeviceState.NeverContacted; - public MedtronicDeviceType medtronicDeviceType = null; - public Date tempBasalStart; - public Double tempBasalAmount = 0.0d; - - // fixme - public Integer tempBasalLength = 0; - - private Map medtronicPumpMap = null; - private Map medtronicDeviceTypeMap = null; - public BasalProfileStatus basalProfileStatus = BasalProfileStatus.NotInitialized; - public BatteryType batteryType = BatteryType.None; - - - @Inject - public MedtronicPumpStatus(ResourceHelper resourceHelper, - SP sp, - RxBusWrapper rxBus, - RileyLinkUtil rileyLinkUtil - ) { - super(PumpType.MEDTRONIC_522_722); - this.resourceHelper = resourceHelper; - this.sp = sp; - this.rxBus = rxBus; - this.rileyLinkUtil = rileyLinkUtil; - initSettings(); - } - - - public void initSettings() { - - this.activeProfileName = "STD"; - this.reservoirRemainingUnits = 75d; - this.batteryRemaining = 75; - - if (this.medtronicPumpMap == null) - createMedtronicPumpMap(); - - if (this.medtronicDeviceTypeMap == null) - createMedtronicDeviceTypeMap(); - - this.lastConnection = sp.getLong(MedtronicConst.Statistics.LastGoodPumpCommunicationTime, 0L); - this.lastDataTime = this.lastConnection; - } - - - private void createMedtronicDeviceTypeMap() { - medtronicDeviceTypeMap = new HashMap<>(); - medtronicDeviceTypeMap.put("512", MedtronicDeviceType.Medtronic_512); - medtronicDeviceTypeMap.put("712", MedtronicDeviceType.Medtronic_712); - medtronicDeviceTypeMap.put("515", MedtronicDeviceType.Medtronic_515); - medtronicDeviceTypeMap.put("715", MedtronicDeviceType.Medtronic_715); - - medtronicDeviceTypeMap.put("522", MedtronicDeviceType.Medtronic_522); - medtronicDeviceTypeMap.put("722", MedtronicDeviceType.Medtronic_722); - medtronicDeviceTypeMap.put("523", MedtronicDeviceType.Medtronic_523_Revel); - medtronicDeviceTypeMap.put("723", MedtronicDeviceType.Medtronic_723_Revel); - medtronicDeviceTypeMap.put("554", MedtronicDeviceType.Medtronic_554_Veo); - medtronicDeviceTypeMap.put("754", MedtronicDeviceType.Medtronic_754_Veo); - } - - - private void createMedtronicPumpMap() { - - medtronicPumpMap = new HashMap<>(); - medtronicPumpMap.put("512", PumpType.MEDTRONIC_512_712); - medtronicPumpMap.put("712", PumpType.MEDTRONIC_512_712); - medtronicPumpMap.put("515", PumpType.MEDTRONIC_515_715); - medtronicPumpMap.put("715", PumpType.MEDTRONIC_515_715); - - medtronicPumpMap.put("522", PumpType.MEDTRONIC_522_722); - medtronicPumpMap.put("722", PumpType.MEDTRONIC_522_722); - medtronicPumpMap.put("523", PumpType.MEDTRONIC_523_723_REVEL); - medtronicPumpMap.put("723", PumpType.MEDTRONIC_523_723_REVEL); - medtronicPumpMap.put("554", PumpType.MEDTRONIC_554_754_VEO); - medtronicPumpMap.put("754", PumpType.MEDTRONIC_554_754_VEO); - - } - - public Map getMedtronicPumpMap() { - return medtronicPumpMap; - } - - public Map getMedtronicDeviceTypeMap() { - return medtronicDeviceTypeMap; - } - - public double getBasalProfileForHour() { - if (basalsByHour != null) { - GregorianCalendar c = new GregorianCalendar(); - int hour = c.get(Calendar.HOUR_OF_DAY); - - return basalsByHour[hour]; - } - - return 0; - } - - // Battery type - private Map mapByDescription; - - public BatteryType getBatteryTypeByDescription(String batteryTypeStr) { - if (mapByDescription == null) { - mapByDescription = new HashMap<>(); - for (BatteryType value : BatteryType.values()) { - mapByDescription.put(resourceHelper.gs(value.description), value); - } - } - if (mapByDescription.containsKey(batteryTypeStr)) { - return mapByDescription.get(batteryTypeStr); - } - return BatteryType.None; - } - - @NonNull - public String getErrorInfo() { - return (errorDescription == null) ? "-" : errorDescription; - } - - - public PumpDeviceState getPumpDeviceState() { - return pumpDeviceState; - } - - - public void setPumpDeviceState(PumpDeviceState pumpDeviceState) { - this.pumpDeviceState = pumpDeviceState; - - rileyLinkUtil.getRileyLinkHistory().add(new RLHistoryItem(pumpDeviceState, RileyLinkTargetDevice.MedtronicPump)); - - rxBus.send(new EventRileyLinkDeviceStatusChange(pumpDeviceState)); - } -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/driver/MedtronicPumpStatus.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/driver/MedtronicPumpStatus.kt new file mode 100644 index 0000000000..e0b65dcf54 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/driver/MedtronicPumpStatus.kt @@ -0,0 +1,139 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.driver + +import info.nightscout.androidaps.plugins.bus.RxBusWrapper +import info.nightscout.androidaps.plugins.pump.common.data.PumpStatus +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.events.EventRileyLinkDeviceStatusChange +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkUtil +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.data.RLHistoryItem +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkTargetDevice +import info.nightscout.androidaps.plugins.pump.medtronic.defs.BasalProfileStatus +import info.nightscout.androidaps.plugins.pump.medtronic.defs.BatteryType +import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicDeviceType +import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicConst +import info.nightscout.androidaps.utils.resources.ResourceHelper +import info.nightscout.androidaps.utils.sharedPreferences.SP +import java.util.* +import javax.inject.Inject +import javax.inject.Singleton + +/** + * Created by andy on 4/28/18. + */ +@Singleton +class MedtronicPumpStatus @Inject constructor(private val resourceHelper: ResourceHelper, + private val sp: SP, + private val rxBus: RxBusWrapper, + private val rileyLinkUtil: RileyLinkUtil +) : PumpStatus(PumpType.MEDTRONIC_522_722) { + + var errorDescription: String? = null + var serialNumber: String? = null + var pumpFrequency: String? = null + var maxBolus: Double? = null + var maxBasal: Double? = null + + // statuses + var pumpDeviceState = PumpDeviceState.NeverContacted + set(pumpDeviceState) { + field = pumpDeviceState + rileyLinkUtil.rileyLinkHistory.add(RLHistoryItem(pumpDeviceState, RileyLinkTargetDevice.MedtronicPump)) + rxBus.send(EventRileyLinkDeviceStatusChange(pumpDeviceState)) + } + var medtronicDeviceType: MedtronicDeviceType? = null + + // fixme + var medtronicPumpMap: MutableMap = HashMap() + var medtronicDeviceTypeMap: MutableMap = HashMap() + var basalProfileStatus = BasalProfileStatus.NotInitialized + var batteryType = BatteryType.None + + override fun initSettings() { + activeProfileName = "STD" + reservoirRemainingUnits = 75.0 + batteryRemaining = 75 + if (medtronicPumpMap.isEmpty()) createMedtronicPumpMap() + if (medtronicDeviceTypeMap.isEmpty()) createMedtronicDeviceTypeMap() + lastConnection = sp.getLong(MedtronicConst.Statistics.LastGoodPumpCommunicationTime, 0L) + lastDataTime = lastConnection + } + + private fun createMedtronicDeviceTypeMap() { + medtronicDeviceTypeMap["512"] = MedtronicDeviceType.Medtronic_512 + medtronicDeviceTypeMap["712"] = MedtronicDeviceType.Medtronic_712 + medtronicDeviceTypeMap["515"] = MedtronicDeviceType.Medtronic_515 + medtronicDeviceTypeMap["715"] = MedtronicDeviceType.Medtronic_715 + medtronicDeviceTypeMap["522"] = MedtronicDeviceType.Medtronic_522 + medtronicDeviceTypeMap["722"] = MedtronicDeviceType.Medtronic_722 + medtronicDeviceTypeMap["523"] = MedtronicDeviceType.Medtronic_523_Revel + medtronicDeviceTypeMap["723"] = MedtronicDeviceType.Medtronic_723_Revel + medtronicDeviceTypeMap["554"] = MedtronicDeviceType.Medtronic_554_Veo + medtronicDeviceTypeMap["754"] = MedtronicDeviceType.Medtronic_754_Veo + } + + private fun createMedtronicPumpMap() { + medtronicPumpMap = HashMap() + medtronicPumpMap["512"] = PumpType.MEDTRONIC_512_712 + medtronicPumpMap["712"] = PumpType.MEDTRONIC_512_712 + medtronicPumpMap["515"] = PumpType.MEDTRONIC_515_715 + medtronicPumpMap["715"] = PumpType.MEDTRONIC_515_715 + medtronicPumpMap["522"] = PumpType.MEDTRONIC_522_722 + medtronicPumpMap["722"] = PumpType.MEDTRONIC_522_722 + medtronicPumpMap["523"] = PumpType.MEDTRONIC_523_723_REVEL + medtronicPumpMap["723"] = PumpType.MEDTRONIC_523_723_REVEL + medtronicPumpMap["554"] = PumpType.MEDTRONIC_554_754_VEO + medtronicPumpMap["754"] = PumpType.MEDTRONIC_554_754_VEO + } + + + val basalProfileForHour: Double + get() { + if (basalsByHour != null) { + val c = GregorianCalendar() + val hour = c[Calendar.HOUR_OF_DAY] + return basalsByHour!![hour] + } + return 0.0 + } + + // Battery type + private var mapByDescription: MutableMap = HashMap() + + fun getBatteryTypeByDescription(batteryTypeStr: String?): BatteryType? { + if (mapByDescription.size == 0) { + for (value in BatteryType.values()) { + mapByDescription[resourceHelper.gs(value.description)] = value + } + } + return if (mapByDescription.containsKey(batteryTypeStr)) { + mapByDescription[batteryTypeStr] + } else BatteryType.None + } + + override val errorInfo: String + get() = if (errorDescription == null) "-" else errorDescription!! + + + val tbrRemainingTime: Int? + get() { + if (tempBasalStart == null) return null + if (tempBasalEnd == null) { + val startTime = tempBasalStart!!.time + tempBasalEnd = startTime + tempBasalLength!! * 60 * 1000 + } + if (System.currentTimeMillis() > tempBasalEnd!!) { + tempBasalStart = null + tempBasalEnd = null + tempBasalLength = null + tempBasalAmount = null + return null + } + val timeMinutes = (tempBasalEnd!! - System.currentTimeMillis()) / (1000 * 60) + return timeMinutes.toInt() + } + + init { + initSettings() + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/service/RileyLinkMedtronicService.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/service/RileyLinkMedtronicService.java deleted file mode 100644 index 2c5274ba0b..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/service/RileyLinkMedtronicService.java +++ /dev/null @@ -1,388 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.service; - -import android.content.Intent; -import android.content.res.Configuration; -import android.os.Binder; -import android.os.IBinder; - -import javax.inject.Inject; -import javax.inject.Singleton; - -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.RileyLinkConst; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.RFSpy; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.defs.RileyLinkEncodingType; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.defs.RileyLinkTargetFrequency; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkTargetDevice; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkService; -import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil; -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.defs.BatteryType; -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; - -/** - * RileyLinkMedtronicService is intended to stay running when the gui-app is closed. - */ -@Singleton -public class RileyLinkMedtronicService extends RileyLinkService { - - @Inject MedtronicPumpPlugin medtronicPumpPlugin; - @Inject MedtronicUtil medtronicUtil; - @Inject MedtronicUIPostprocessor medtronicUIPostprocessor; - @Inject MedtronicPumpStatus medtronicPumpStatus; - @Inject RFSpy rfSpy; - @Inject MedtronicCommunicationManager medtronicCommunicationManager; - - private MedtronicUIComm medtronicUIComm; - private final IBinder mBinder = new LocalBinder(); - - private boolean serialChanged = false; - private String[] frequencies; - private String rileyLinkAddress = null; - private boolean rileyLinkAddressChanged = false; - private RileyLinkEncodingType encodingType; - private boolean encodingChanged = false; - private boolean inPreInit = true; - - - // This empty constructor must be kept, otherwise dagger injection might break! - @Inject - public RileyLinkMedtronicService() { - } - - - @Override public void onCreate() { - super.onCreate(); - aapsLogger.debug(LTag.PUMPCOMM, "RileyLinkMedtronicService newly created"); - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - aapsLogger.warn(LTag.PUMPCOMM, "onConfigurationChanged"); - super.onConfigurationChanged(newConfig); - } - - - @Override - public IBinder onBind(Intent intent) { - return mBinder; - } - - - @Override - public RileyLinkEncodingType getEncoding() { - return RileyLinkEncodingType.FourByteSixByteLocal; - } - - - /** - * If you have customized RileyLinkServiceData you need to override this - */ - public void initRileyLinkServiceData() { - - frequencies = new String[2]; - frequencies[0] = resourceHelper.gs(R.string.key_medtronic_pump_frequency_us_ca); - frequencies[1] = resourceHelper.gs(R.string.key_medtronic_pump_frequency_worldwide); - - rileyLinkServiceData.targetDevice = RileyLinkTargetDevice.MedtronicPump; - - setPumpIDString(sp.getString(MedtronicConst.Prefs.PumpSerial, "000000")); - - // get most recently used RileyLink address and name - rileyLinkServiceData.rileyLinkAddress = sp.getString(RileyLinkConst.Prefs.RileyLinkAddress, ""); - rileyLinkServiceData.rileyLinkName = sp.getString(RileyLinkConst.Prefs.RileyLinkName, ""); - - rfspy.startReader(); - - medtronicUIComm = new MedtronicUIComm(injector, aapsLogger, medtronicUtil, medtronicUIPostprocessor, medtronicCommunicationManager); - - aapsLogger.debug(LTag.PUMPCOMM, "RileyLinkMedtronicService newly constructed"); - } - - public MedtronicCommunicationManager getDeviceCommunicationManager() { - return this.medtronicCommunicationManager; - } - - - @Override - public void setPumpDeviceState(PumpDeviceState pumpDeviceState) { - this.medtronicPumpStatus.setPumpDeviceState(pumpDeviceState); - } - - - public MedtronicUIComm getMedtronicUIComm() { - return medtronicUIComm; - } - - public void setPumpIDString(String pumpID) { - if (pumpID.length() != 6) { - aapsLogger.error("setPumpIDString: invalid pump id string: " + pumpID); - return; - } - - byte[] pumpIDBytes = ByteUtil.fromHexString(pumpID); - - if (pumpIDBytes == null) { - aapsLogger.error("Invalid pump ID? - PumpID is null."); - - rileyLinkServiceData.setPumpID("000000", new byte[]{0, 0, 0}); - - } else if (pumpIDBytes.length != 3) { - aapsLogger.error("Invalid pump ID? " + ByteUtil.shortHexString(pumpIDBytes)); - - rileyLinkServiceData.setPumpID("000000", new byte[]{0, 0, 0}); - - } else if (pumpID.equals("000000")) { - aapsLogger.error("Using pump ID " + pumpID); - - rileyLinkServiceData.setPumpID(pumpID, new byte[]{0, 0, 0}); - - } else { - aapsLogger.info(LTag.PUMPBTCOMM, "Using pump ID " + pumpID); - - String oldId = rileyLinkServiceData.pumpID; - - rileyLinkServiceData.setPumpID(pumpID, pumpIDBytes); - - if (oldId != null && !oldId.equals(pumpID)) { - medtronicUtil.setMedtronicPumpModel(null); // if we change pumpId, model probably changed too - } - - return; - } - - medtronicPumpStatus.setPumpDeviceState(PumpDeviceState.InvalidConfiguration); - - // LOG.info("setPumpIDString: saved pumpID " + idString); - } - - public class LocalBinder extends Binder { - - public RileyLinkMedtronicService getServiceInstance() { - return RileyLinkMedtronicService.this; - } - } - - - /* private functions */ - - // PumpInterface - REMOVE - - public boolean isInitialized() { - return rileyLinkServiceData.rileyLinkServiceState.isReady(); - } - - - public boolean verifyConfiguration(boolean forceRileyLinkAddressRenewal) { - try { - String regexSN = "[0-9]{6}"; - String regexMac = "([\\da-fA-F]{1,2}(?::|$)){6}"; - - medtronicPumpStatus.errorDescription = "-"; - - String serialNr = sp.getStringOrNull(MedtronicConst.Prefs.PumpSerial, null); - - if (serialNr == null) { - medtronicPumpStatus.errorDescription = resourceHelper.gs(R.string.medtronic_error_serial_not_set); - return false; - } else { - if (!serialNr.matches(regexSN)) { - medtronicPumpStatus.errorDescription = resourceHelper.gs(R.string.medtronic_error_serial_invalid); - return false; - } else { - if (!serialNr.equals(medtronicPumpStatus.serialNumber)) { - medtronicPumpStatus.serialNumber = serialNr; - serialChanged = true; - } - } - } - - String pumpTypePref = sp.getStringOrNull(MedtronicConst.Prefs.PumpType, null); - - if (pumpTypePref == null) { - medtronicPumpStatus.errorDescription = resourceHelper.gs(R.string.medtronic_error_pump_type_not_set); - return false; - } else { - String pumpTypePart = pumpTypePref.substring(0, 3); - - if (!pumpTypePart.matches("[0-9]{3}")) { - medtronicPumpStatus.errorDescription = resourceHelper.gs(R.string.medtronic_error_pump_type_invalid); - return false; - } else { - PumpType pumpType = medtronicPumpStatus.getMedtronicPumpMap().get(pumpTypePart); - medtronicPumpStatus.medtronicDeviceType = medtronicPumpStatus.getMedtronicDeviceTypeMap().get(pumpTypePart); - medtronicPumpPlugin.setPumpType(pumpType); - - if (pumpTypePart.startsWith("7")) - medtronicPumpStatus.reservoirFullUnits = 300; - else - medtronicPumpStatus.reservoirFullUnits = 176; - } - } - - String pumpFrequency = sp.getStringOrNull(MedtronicConst.Prefs.PumpFrequency, null); - - if (pumpFrequency == null) { - medtronicPumpStatus.errorDescription = resourceHelper.gs(R.string.medtronic_error_pump_frequency_not_set); - return false; - } else { - if (!pumpFrequency.equals(frequencies[0]) && !pumpFrequency.equals(frequencies[1])) { - medtronicPumpStatus.errorDescription = resourceHelper.gs(R.string.medtronic_error_pump_frequency_invalid); - return false; - } else { - medtronicPumpStatus.pumpFrequency = pumpFrequency; - boolean isFrequencyUS = pumpFrequency.equals(frequencies[0]); - - RileyLinkTargetFrequency newTargetFrequency = isFrequencyUS ? // - RileyLinkTargetFrequency.Medtronic_US - : RileyLinkTargetFrequency.Medtronic_WorldWide; - - if (rileyLinkServiceData.rileyLinkTargetFrequency != newTargetFrequency) { - rileyLinkServiceData.rileyLinkTargetFrequency = newTargetFrequency; - } - - } - } - - String rileyLinkAddress = sp.getStringOrNull(RileyLinkConst.Prefs.RileyLinkAddress, null); - - if (rileyLinkAddress == null) { - aapsLogger.debug(LTag.PUMP, "RileyLink address invalid: null"); - medtronicPumpStatus.errorDescription = resourceHelper.gs(R.string.medtronic_error_rileylink_address_invalid); - return false; - } else { - if (!rileyLinkAddress.matches(regexMac)) { - medtronicPumpStatus.errorDescription = resourceHelper.gs(R.string.medtronic_error_rileylink_address_invalid); - aapsLogger.debug(LTag.PUMP, "RileyLink address invalid: %s", rileyLinkAddress); - } else { - if (!rileyLinkAddress.equals(this.rileyLinkAddress)) { - this.rileyLinkAddress = rileyLinkAddress; - rileyLinkAddressChanged = true; - } - } - } - - double maxBolusLcl = checkParameterValue(MedtronicConst.Prefs.MaxBolus, "25.0", 25.0d); - - if (medtronicPumpStatus.maxBolus == null || !medtronicPumpStatus.maxBolus.equals(maxBolusLcl)) { - medtronicPumpStatus.maxBolus = maxBolusLcl; - - //LOG.debug("Max Bolus from AAPS settings is " + maxBolus); - } - - double maxBasalLcl = checkParameterValue(MedtronicConst.Prefs.MaxBasal, "35.0", 35.0d); - - if (medtronicPumpStatus.maxBasal == null || !medtronicPumpStatus.maxBasal.equals(maxBasalLcl)) { - medtronicPumpStatus.maxBasal = maxBasalLcl; - - //LOG.debug("Max Basal from AAPS settings is " + maxBasal); - } - - - String encodingTypeStr = sp.getStringOrNull(MedtronicConst.Prefs.Encoding, null); - - if (encodingTypeStr == null) { - return false; - } - - RileyLinkEncodingType newEncodingType = RileyLinkEncodingType.getByDescription(encodingTypeStr, resourceHelper); - - if (encodingType == null) { - encodingType = newEncodingType; - } else if (encodingType != newEncodingType) { - encodingType = newEncodingType; - encodingChanged = true; - } - - String batteryTypeStr = sp.getStringOrNull(MedtronicConst.Prefs.BatteryType, null); - - if (batteryTypeStr == null) - return false; - - BatteryType batteryType = medtronicPumpStatus.getBatteryTypeByDescription(batteryTypeStr); - - if (medtronicPumpStatus.batteryType != batteryType) { - medtronicPumpStatus.batteryType = batteryType; - } - - //String bolusDebugEnabled = sp.getStringOrNull(MedtronicConst.Prefs.BolusDebugEnabled, null); - //boolean bolusDebug = bolusDebugEnabled != null && bolusDebugEnabled.equals(resourceHelper.gs(R.string.common_on)); - //MedtronicHistoryData.doubleBolusDebug = bolusDebug; - - rileyLinkServiceData.showBatteryLevel = sp.getBoolean(RileyLinkConst.Prefs.ShowBatteryLevel, false); - - reconfigureService(forceRileyLinkAddressRenewal); - - return true; - - } catch (Exception ex) { - medtronicPumpStatus.errorDescription = ex.getMessage(); - aapsLogger.error(LTag.PUMP, "Error on Verification: " + ex.getMessage(), ex); - return false; - } - } - - private boolean reconfigureService(boolean forceRileyLinkAddressRenewal) { - - if (!inPreInit) { - - if (serialChanged) { - setPumpIDString(medtronicPumpStatus.serialNumber); // short operation - serialChanged = false; - } - - if (rileyLinkAddressChanged || forceRileyLinkAddressRenewal) { - rileyLinkUtil.sendBroadcastMessage(RileyLinkConst.Intents.RileyLinkNewAddressSet, this); - rileyLinkAddressChanged = false; - } - - if (encodingChanged) { - changeRileyLinkEncoding(encodingType); - encodingChanged = false; - } - } - - - // if (targetFrequencyChanged && !inPreInit && MedtronicUtil.getMedtronicService() != null) { - // RileyLinkUtil.setRileyLinkTargetFrequency(targetFrequency); - // // RileyLinkUtil.getRileyLinkCommunicationManager().refreshRileyLinkTargetFrequency(); - // targetFrequencyChanged = false; - // } - - return (!rileyLinkAddressChanged && !serialChanged && !encodingChanged); // && !targetFrequencyChanged); - } - - private double checkParameterValue(int key, String defaultValue, double defaultValueDouble) { - double val; - - String value = sp.getString(key, defaultValue); - - try { - val = Double.parseDouble(value); - } catch (Exception ex) { - aapsLogger.error("Error parsing setting: %s, value found %s", key, value); - val = defaultValueDouble; - } - - if (val > defaultValueDouble) { - sp.putString(key, defaultValue); - val = defaultValueDouble; - } - - return val; - } - - public boolean setNotInPreInit() { - this.inPreInit = false; - - return reconfigureService(false); - } -} 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 new file mode 100644 index 0000000000..89a31552d2 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/service/RileyLinkMedtronicService.kt @@ -0,0 +1,289 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.service + +import android.content.Intent +import android.content.res.Configuration +import android.os.Binder +import android.os.IBinder +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.pump.common.defs.PumpDeviceState +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkConst +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.RFSpy +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.defs.RileyLinkEncodingType +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.defs.RileyLinkTargetFrequency +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkTargetDevice +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkService +import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil +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 +import javax.inject.Singleton + +/** + * RileyLinkMedtronicService is intended to stay running when the gui-app is closed. + */ +@Singleton +class RileyLinkMedtronicService // This empty constructor must be kept, otherwise dagger injection might break! +@Inject constructor() : RileyLinkService() { + + @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 + + var medtronicUIComm: MedtronicUIComm? = null + private set + private val mBinder: IBinder = LocalBinder() + private var serialChanged = false + private var frequencies: Array? = null + private var rileyLinkAddress: String? = null + private var rileyLinkAddressChanged = false + private var encodingType: RileyLinkEncodingType? = null + private var encodingChanged = false + private var inPreInit = true + override fun onCreate() { + super.onCreate() + aapsLogger.debug(LTag.PUMPCOMM, "RileyLinkMedtronicService newly created") + } + + override fun onConfigurationChanged(newConfig: Configuration) { + aapsLogger.warn(LTag.PUMPCOMM, "onConfigurationChanged") + super.onConfigurationChanged(newConfig) + } + + override fun onBind(intent: Intent): IBinder { + return mBinder + } + + override fun getEncoding(): RileyLinkEncodingType { + return RileyLinkEncodingType.FourByteSixByteLocal + } + + /** + * If you have customized RileyLinkServiceData you need to override this + */ + override fun initRileyLinkServiceData() { + frequencies = arrayOfNulls(2) + frequencies!![0] = resourceHelper.gs(R.string.key_medtronic_pump_frequency_us_ca) + frequencies!![1] = resourceHelper.gs(R.string.key_medtronic_pump_frequency_worldwide) + rileyLinkServiceData.targetDevice = RileyLinkTargetDevice.MedtronicPump + setPumpIDString(sp.getString(MedtronicConst.Prefs.PumpSerial, "000000")) + + // get most recently used RileyLink address and name + 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") + } + + override fun getDeviceCommunicationManager(): MedtronicCommunicationManager { + return medtronicCommunicationManager + } + + override fun setPumpDeviceState(pumpDeviceState: PumpDeviceState) { + medtronicPumpStatus.pumpDeviceState = pumpDeviceState + } + + fun setPumpIDString(pumpID: String) { + if (pumpID.length != 6) { + aapsLogger.error("setPumpIDString: invalid pump id string: $pumpID") + return + } + val pumpIDBytes = ByteUtil.fromHexString(pumpID) + if (pumpIDBytes == null) { + aapsLogger.error("Invalid pump ID? - PumpID is null.") + rileyLinkServiceData.setPumpID("000000", byteArrayOf(0, 0, 0)) + } else if (pumpIDBytes.size != 3) { + aapsLogger.error("Invalid pump ID? " + ByteUtil.shortHexString(pumpIDBytes)) + rileyLinkServiceData.setPumpID("000000", byteArrayOf(0, 0, 0)) + } else if (pumpID == "000000") { + aapsLogger.error("Using pump ID $pumpID") + rileyLinkServiceData.setPumpID(pumpID, byteArrayOf(0, 0, 0)) + } else { + aapsLogger.info(LTag.PUMPBTCOMM, "Using pump ID $pumpID") + val oldId = rileyLinkServiceData.pumpID + rileyLinkServiceData.setPumpID(pumpID, pumpIDBytes) + if (oldId != null && oldId != pumpID) { + medtronicUtil.medtronicPumpModel = null // if we change pumpId, model probably changed too + } + return + } + medtronicPumpStatus.pumpDeviceState = PumpDeviceState.InvalidConfiguration + + // LOG.info("setPumpIDString: saved pumpID " + idString); + } + + inner class LocalBinder : Binder() { + val serviceInstance: RileyLinkMedtronicService + get() = this@RileyLinkMedtronicService + } + + /* private functions */ // PumpInterface - REMOVE + val isInitialized: Boolean + get() = rileyLinkServiceData.rileyLinkServiceState.isReady + + override fun verifyConfiguration(forceRileyLinkAddressRenewal: Boolean): Boolean { + return try { + val regexSN = "[0-9]{6}" + val regexMac = "([\\da-fA-F]{1,2}(?::|$)){6}" + medtronicPumpStatus.errorDescription = "-" + val serialNr = sp.getStringOrNull(MedtronicConst.Prefs.PumpSerial, null) + if (serialNr == null) { + medtronicPumpStatus.errorDescription = resourceHelper.gs(R.string.medtronic_error_serial_not_set) + return false + } else { + if (!serialNr.matches(regexSN.toRegex())) { + medtronicPumpStatus.errorDescription = resourceHelper.gs(R.string.medtronic_error_serial_invalid) + return false + } else { + if (serialNr != medtronicPumpStatus.serialNumber) { + medtronicPumpStatus.serialNumber = serialNr + serialChanged = true + } + } + } + val pumpTypePref = sp.getStringOrNull(MedtronicConst.Prefs.PumpType, null) + if (pumpTypePref == null) { + medtronicPumpStatus.errorDescription = resourceHelper.gs(R.string.medtronic_error_pump_type_not_set) + return false + } else { + val pumpTypePart = pumpTypePref.substring(0, 3) + if (!pumpTypePart.matches("[0-9]{3}".toRegex())) { + medtronicPumpStatus.errorDescription = resourceHelper.gs(R.string.medtronic_error_pump_type_invalid) + return false + } else { + val pumpType = medtronicPumpStatus.medtronicPumpMap[pumpTypePart] + medtronicPumpStatus.medtronicDeviceType = medtronicPumpStatus.medtronicDeviceTypeMap[pumpTypePart] + medtronicPumpPlugin.pumpType = pumpType + if (pumpTypePart.startsWith("7")) medtronicPumpStatus.reservoirFullUnits = 300 else medtronicPumpStatus.reservoirFullUnits = 176 + } + } + val pumpFrequency = sp.getStringOrNull(MedtronicConst.Prefs.PumpFrequency, null) + if (pumpFrequency == null) { + medtronicPumpStatus.errorDescription = resourceHelper.gs(R.string.medtronic_error_pump_frequency_not_set) + return false + } else { + if (pumpFrequency != frequencies!![0] && pumpFrequency != frequencies!![1]) { + medtronicPumpStatus.errorDescription = resourceHelper.gs(R.string.medtronic_error_pump_frequency_invalid) + return false + } else { + medtronicPumpStatus.pumpFrequency = pumpFrequency + val isFrequencyUS = pumpFrequency == frequencies!![0] + val newTargetFrequency = if (isFrequencyUS) // + RileyLinkTargetFrequency.Medtronic_US else RileyLinkTargetFrequency.Medtronic_WorldWide + if (rileyLinkServiceData.rileyLinkTargetFrequency != newTargetFrequency) { + rileyLinkServiceData.rileyLinkTargetFrequency = newTargetFrequency + } + } + } + val rileyLinkAddress = sp.getStringOrNull(RileyLinkConst.Prefs.RileyLinkAddress, null) + if (rileyLinkAddress == null) { + aapsLogger.debug(LTag.PUMP, "RileyLink address invalid: null") + medtronicPumpStatus.errorDescription = resourceHelper.gs(R.string.medtronic_error_rileylink_address_invalid) + return false + } else { + if (!rileyLinkAddress.matches(regexMac.toRegex())) { + medtronicPumpStatus.errorDescription = resourceHelper.gs(R.string.medtronic_error_rileylink_address_invalid) + aapsLogger.debug(LTag.PUMP, "RileyLink address invalid: %s", rileyLinkAddress) + } else { + if (rileyLinkAddress != this.rileyLinkAddress) { + this.rileyLinkAddress = rileyLinkAddress + rileyLinkAddressChanged = true + } + } + } + val maxBolusLcl = checkParameterValue(MedtronicConst.Prefs.MaxBolus, "25.0", 25.0) + if (medtronicPumpStatus.maxBolus == null || medtronicPumpStatus.maxBolus != maxBolusLcl) { + medtronicPumpStatus.maxBolus = maxBolusLcl + + //LOG.debug("Max Bolus from AAPS settings is " + maxBolus); + } + val maxBasalLcl = checkParameterValue(MedtronicConst.Prefs.MaxBasal, "35.0", 35.0) + if (medtronicPumpStatus.maxBasal == null || medtronicPumpStatus.maxBasal != maxBasalLcl) { + medtronicPumpStatus.maxBasal = maxBasalLcl + + //LOG.debug("Max Basal from AAPS settings is " + maxBasal); + } + val encodingTypeStr = sp.getStringOrNull(MedtronicConst.Prefs.Encoding, null) + ?: return false + val newEncodingType = RileyLinkEncodingType.getByDescription(encodingTypeStr, resourceHelper) + if (encodingType == null) { + encodingType = newEncodingType + } else if (encodingType != newEncodingType) { + encodingType = newEncodingType + encodingChanged = true + } + val batteryTypeStr = sp.getStringOrNull(MedtronicConst.Prefs.BatteryType, null) + ?: return false + val batteryType = medtronicPumpStatus.getBatteryTypeByDescription(batteryTypeStr) + if (medtronicPumpStatus.batteryType !== batteryType) { + medtronicPumpStatus.batteryType = batteryType!! + } + + //String bolusDebugEnabled = sp.getStringOrNull(MedtronicConst.Prefs.BolusDebugEnabled, null); + //boolean bolusDebug = bolusDebugEnabled != null && bolusDebugEnabled.equals(resourceHelper.gs(R.string.common_on)); + //MedtronicHistoryData.doubleBolusDebug = bolusDebug; + rileyLinkServiceData.showBatteryLevel = sp.getBoolean(RileyLinkConst.Prefs.ShowBatteryLevel, false) + reconfigureService(forceRileyLinkAddressRenewal) + true + } catch (ex: Exception) { + medtronicPumpStatus.errorDescription = ex.message + aapsLogger.error(LTag.PUMP, "Error on Verification: " + ex.message, ex) + false + } + } + + private fun reconfigureService(forceRileyLinkAddressRenewal: Boolean): Boolean { + if (!inPreInit) { + if (serialChanged) { + setPumpIDString(medtronicPumpStatus.serialNumber!!) // short operation + serialChanged = false + } + if (rileyLinkAddressChanged || forceRileyLinkAddressRenewal) { + rileyLinkUtil.sendBroadcastMessage(RileyLinkConst.Intents.RileyLinkNewAddressSet, this) + rileyLinkAddressChanged = false + } + if (encodingChanged) { + changeRileyLinkEncoding(encodingType) + encodingChanged = false + } + } + + // if (targetFrequencyChanged && !inPreInit && MedtronicUtil.getMedtronicService() != null) { + // RileyLinkUtil.setRileyLinkTargetFrequency(targetFrequency); + // // RileyLinkUtil.getRileyLinkCommunicationManager().refreshRileyLinkTargetFrequency(); + // targetFrequencyChanged = false; + // } + return !rileyLinkAddressChanged && !serialChanged && !encodingChanged // && !targetFrequencyChanged); + } + + private fun checkParameterValue(key: Int, defaultValue: String, defaultValueDouble: Double): Double { + var `val`: Double + val value = sp.getString(key, defaultValue) + `val` = try { + value.toDouble() + } catch (ex: Exception) { + aapsLogger.error("Error parsing setting: %s, value found %s", key, value) + defaultValueDouble + } + if (`val` > defaultValueDouble) { + sp.putString(key, defaultValue) + `val` = defaultValueDouble + } + return `val` + } + + fun setNotInPreInit(): Boolean { + inPreInit = false + return reconfigureService(false) + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/util/MedtronicConst.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/util/MedtronicConst.java deleted file mode 100644 index b09f0f80a1..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/util/MedtronicConst.java +++ /dev/null @@ -1,40 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.util; - -import info.nightscout.androidaps.plugins.pump.medtronic.R; - -/** - * Created by andy on 5/12/18. - */ - -public class MedtronicConst { - - static final String Prefix = "AAPS.Medtronic."; - - public static class Prefs { - public static final int PumpSerial = R.string.key_medtronic_serial; - public static final int PumpType = R.string.key_medtronic_pump_type; - public static final int PumpFrequency = R.string.key_medtronic_frequency; - public static final int MaxBolus = R.string.key_medtronic_max_bolus; - public static final int MaxBasal = R.string.key_medtronic_max_basal; - public static final int BolusDelay = R.string.key_medtronic_bolus_delay; - public static final int Encoding = R.string.key_medtronic_encoding; - public static final int BatteryType = R.string.key_medtronic_battery_type; - public static final int BolusDebugEnabled = R.string.key_medtronic_bolus_debug; - } - - public static class Statistics { - - public static final String StatsPrefix = "medtronic_"; - public static final String FirstPumpStart = Prefix + "first_pump_use"; - public static final String LastGoodPumpCommunicationTime = Prefix + "lastGoodPumpCommunicationTime"; - public static final String LastGoodPumpFrequency = Prefix + "LastGoodPumpFrequency"; - public static final String TBRsSet = StatsPrefix + "tbrs_set"; - public static final String StandardBoluses = StatsPrefix + "std_boluses_delivered"; - public static final String SMBBoluses = StatsPrefix + "smb_boluses_delivered"; - public static final String LastPumpHistoryEntry = StatsPrefix + "pump_history_entry"; - public static final String LastPrime = StatsPrefix + "last_sent_prime"; - public static final String LastRewind = StatsPrefix + "last_sent_rewind"; - public static final String InternalTemporaryDatabase = StatsPrefix + "temporary_entries"; - } - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/util/MedtronicConst.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/util/MedtronicConst.kt new file mode 100644 index 0000000000..80d284f80a --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/util/MedtronicConst.kt @@ -0,0 +1,37 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.util + +import info.nightscout.androidaps.plugins.pump.medtronic.R + +/** + * Created by andy on 5/12/18. + */ +object MedtronicConst { + + const val Prefix = "AAPS.Medtronic." + + object Prefs { + @JvmField val PumpSerial = R.string.key_medtronic_serial + @JvmField val PumpType = R.string.key_medtronic_pump_type + @JvmField val PumpFrequency = R.string.key_medtronic_frequency + @JvmField val MaxBolus = R.string.key_medtronic_max_bolus + @JvmField val MaxBasal = R.string.key_medtronic_max_basal + @JvmField val BolusDelay = R.string.key_medtronic_bolus_delay + @JvmField val Encoding = R.string.key_medtronic_encoding + @JvmField val BatteryType = R.string.key_medtronic_battery_type + val BolusDebugEnabled = R.string.key_medtronic_bolus_debug + } + + object Statistics { + const val StatsPrefix = "medtronic_" + const val FirstPumpStart = Prefix + "first_pump_use" + const val LastGoodPumpCommunicationTime = Prefix + "lastGoodPumpCommunicationTime" + const val LastGoodPumpFrequency = Prefix + "LastGoodPumpFrequency" + const val TBRsSet = StatsPrefix + "tbrs_set" + const val StandardBoluses = StatsPrefix + "std_boluses_delivered" + const val SMBBoluses = StatsPrefix + "smb_boluses_delivered" + const val LastPumpHistoryEntry = StatsPrefix + "pump_history_entry" + const val LastPrime = StatsPrefix + "last_sent_prime" + const val LastRewind = StatsPrefix + "last_sent_rewind" + const val InternalTemporaryDatabase = StatsPrefix + "temporary_entries" + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/util/MedtronicUtil.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/util/MedtronicUtil.java deleted file mode 100644 index 680896751c..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/util/MedtronicUtil.java +++ /dev/null @@ -1,456 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.util; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; - -import org.joda.time.LocalTime; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -import javax.inject.Inject; -import javax.inject.Singleton; - -import info.nightscout.androidaps.logging.AAPSLogger; -import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.plugins.bus.RxBusWrapper; -import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification; -import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification; -import info.nightscout.androidaps.plugins.general.overview.notifications.Notification; -import info.nightscout.androidaps.plugins.pump.common.events.EventRileyLinkDeviceStatusChange; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkUtil; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkServiceData; -import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.ClockDTO; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.PumpSettingDTO; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.RLHistoryItemMedtronic; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicCommandType; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicDeviceType; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicNotificationType; -import info.nightscout.androidaps.plugins.pump.medtronic.driver.MedtronicPumpStatus; -import info.nightscout.androidaps.utils.resources.ResourceHelper; - -/** - * Created by andy on 5/9/18. - */ - -@Singleton -public class MedtronicUtil { - - private final int ENVELOPE_SIZE = 4; // 0xA7 S1 S2 S3 CMD PARAM_COUNT [PARAMS] - private static final boolean lowLevelDebug = true; - //private MedtronicDeviceType medtronicPumpModel; - private MedtronicCommandType currentCommand; - private Map settings; - private final int BIG_FRAME_LENGTH = 65; - private final int doneBit = 1 << 7; - private ClockDTO pumpTime; - public Gson gsonInstance = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); - - private final AAPSLogger aapsLogger; - private final RxBusWrapper rxBus; - private final RileyLinkUtil rileyLinkUtil; - private final MedtronicPumpStatus medtronicPumpStatus; - - @Inject - public MedtronicUtil( - AAPSLogger aapsLogger, - RxBusWrapper rxBus, - RileyLinkUtil rileyLinkUtil, - MedtronicPumpStatus medtronicPumpStatus - ) { - this.aapsLogger = aapsLogger; - this.rxBus = rxBus; - this.rileyLinkUtil = rileyLinkUtil; - this.medtronicPumpStatus = medtronicPumpStatus; - } - - public LocalTime getTimeFrom30MinInterval(int interval) { - if (interval % 2 == 0) { - return new LocalTime(interval / 2, 0); - } else { - return new LocalTime((interval - 1) / 2, 30); - } - } - - - public static int getIntervalFromMinutes(int minutes) { - return minutes / 30; - } - - - public static int makeUnsignedShort(int b2, int b1) { - int k = (b2 & 0xff) << 8 | b1 & 0xff; - return k; - } - - public static byte[] getByteArrayFromUnsignedShort(int shortValue, boolean returnFixedSize) { - byte highByte = (byte) (shortValue >> 8 & 0xFF); - byte lowByte = (byte) (shortValue & 0xFF); - - if (highByte > 0) { - return createByteArray(highByte, lowByte); - } else { - return returnFixedSize ? createByteArray(highByte, lowByte) : createByteArray(lowByte); - } - - } - - - public static byte[] createByteArray(byte... data) { - return data; - } - - - public static byte[] createByteArray(List data) { - - byte[] array = new byte[data.size()]; - - for (int i = 0; i < data.size(); i++) { - array[i] = data.get(i); - } - - return array; - } - - - public double decodeBasalInsulin(int i, int j) { - return decodeBasalInsulin(makeUnsignedShort(i, j)); - } - - - public double decodeBasalInsulin(int i) { - return (double) i / 40.0d; - } - - - public byte[] getBasalStrokes(double amount) { - return getBasalStrokes(amount, false); - } - - - public static byte[] getBasalStrokes(double amount, boolean returnFixedSize) { - return getStrokes(amount, 40, returnFixedSize); - } - - - public int getBasalStrokesInt(double amount) { - return getStrokesInt(amount, 40); - } - - - public byte[] getBolusStrokes(double amount) { - - int strokesPerUnit = medtronicPumpStatus.medtronicDeviceType.getBolusStrokes(); - - int length; - int scrollRate; - - if (strokesPerUnit >= 40) { - length = 2; - - // 40-stroke pumps scroll faster for higher unit values - - if (amount > 10) - scrollRate = 4; - else if (amount > 1) - scrollRate = 2; - else - scrollRate = 1; - - } else { - length = 1; - scrollRate = 1; - } - - int strokes = (int) (amount * ((strokesPerUnit * 1.0d) / (scrollRate * 1.0d))) * scrollRate; - - byte[] body = ByteUtil.fromHexString(String.format("%02x%0" + (2 * length) + "x", length, strokes)); - - return body; - } - - - public byte[] createCommandBody(byte[] input) { - - return ByteUtil.concat((byte) input.length, input); - } - - - public static byte[] getStrokes(double amount, int strokesPerUnit, boolean returnFixedSize) { - - int strokes = getStrokesInt(amount, strokesPerUnit); - - return getByteArrayFromUnsignedShort(strokes, returnFixedSize); - - } - - - public static int getStrokesInt(double amount, int strokesPerUnit) { - - int length = 1; - int scrollRate = 1; - - if (strokesPerUnit >= 40) { - length = 2; - - // 40-stroke pumps scroll faster for higher unit values - if (amount > 10) - scrollRate = 4; - else if (amount > 1) - scrollRate = 2; - } - - int strokes = (int) (amount * (strokesPerUnit / (scrollRate * 1.0d))); - - strokes *= scrollRate; - - return strokes; - - } - - - public void sendNotification(MedtronicNotificationType notificationType, ResourceHelper resourceHelper, RxBusWrapper rxBus) { - Notification notification = new Notification( // - notificationType.getNotificationType(), // - resourceHelper.gs(notificationType.getResourceId()), // - notificationType.getNotificationUrgency()); - rxBus.send(new EventNewNotification(notification)); - } - - - public void sendNotification(MedtronicNotificationType notificationType, ResourceHelper resourceHelper, RxBusWrapper rxBus, Object... parameters) { - Notification notification = new Notification( // - notificationType.getNotificationType(), // - resourceHelper.gs(notificationType.getResourceId(), parameters), // - notificationType.getNotificationUrgency()); - rxBus.send(new EventNewNotification(notification)); - } - - - public void dismissNotification(MedtronicNotificationType notificationType, RxBusWrapper rxBus) { - rxBus.send(new EventDismissNotification(notificationType.getNotificationType())); - } - - -// public byte[] buildCommandPayload(MessageType commandType, byte[] parameters) { -// return buildCommandPayload(commandType.getValue(), parameters); -// } - - - public byte[] buildCommandPayload(RileyLinkServiceData rileyLinkServiceData, MedtronicCommandType commandType, byte[] parameters) { - return buildCommandPayload(rileyLinkServiceData, commandType.commandCode, parameters); - } - - - public byte[] buildCommandPayload(RileyLinkServiceData rileyLinkServiceData, byte commandType, byte[] parameters) { - // A7 31 65 51 C0 00 52 - - byte commandLength = (byte) (parameters == null ? 2 : 2 + parameters.length); - - ByteBuffer sendPayloadBuffer = ByteBuffer.allocate(ENVELOPE_SIZE + commandLength); // + CRC_SIZE - sendPayloadBuffer.order(ByteOrder.BIG_ENDIAN); - - byte[] serialNumberBCD = rileyLinkServiceData.pumpIDBytes; - - sendPayloadBuffer.put((byte) 0xA7); - sendPayloadBuffer.put(serialNumberBCD[0]); - sendPayloadBuffer.put(serialNumberBCD[1]); - sendPayloadBuffer.put(serialNumberBCD[2]); - - sendPayloadBuffer.put(commandType); - - if (parameters == null) { - sendPayloadBuffer.put((byte) 0x00); - } else { - sendPayloadBuffer.put((byte) parameters.length); // size - - for (byte val : parameters) { - sendPayloadBuffer.put(val); - } - } - - byte[] payload = sendPayloadBuffer.array(); - - aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "buildCommandPayload [%s]", ByteUtil.shortHexString(payload))); - - // int crc = computeCRC8WithPolynomial(payload, 0, payload.length - 1); - - // LOG.info("crc: " + crc); - - // sendPayloadBuffer.put((byte) crc); - - return sendPayloadBuffer.array(); - } - - - // Note: at the moment supported only for 24 items, if you will use it for more than - // that you will need to add - public List> getBasalProfileFrames(byte[] data) { - - boolean done = false; - int start = 0; - int frame = 1; - - List> frames = new ArrayList<>(); - boolean lastFrame = false; - - do { - int frameLength = BIG_FRAME_LENGTH - 1; - - if (start + frameLength > data.length) { - frameLength = data.length - start; - } - - // System.out.println("Framelength: " + frameLength); - - byte[] substring = ByteUtil.substring(data, start, frameLength); - - // System.out.println("Subarray: " + ByteUtil.getCompactString(substring)); - // System.out.println("Subarray Lenths: " + substring.length); - - List frameData = ByteUtil.getListFromByteArray(substring); - - if (isEmptyFrame(frameData)) { - byte b = (byte) frame; - // b |= 0x80; - b |= 0b1000_0000; - // b |= doneBit; - - frameData.add(0, b); - - checkAndAppenLastFrame(frameData); - - lastFrame = true; - - done = true; - } else { - frameData.add(0, (byte) frame); - } - - // System.out.println("Subarray: " + ByteUtil.getCompactString(substring)); - - frames.add(frameData); - - frame++; - start += (BIG_FRAME_LENGTH - 1); - - if (start == data.length) { - done = true; - } - - } while (!done); - - if (!lastFrame) { - List frameData = new ArrayList<>(); - - byte b = (byte) frame; - b |= 0b1000_0000; - // b |= doneBit; - - frameData.add(b); - - checkAndAppenLastFrame(frameData); - } - - return frames; - - } - - - private void checkAndAppenLastFrame(List frameData) { - - if (frameData.size() == BIG_FRAME_LENGTH) - return; - - int missing = BIG_FRAME_LENGTH - frameData.size(); - - for (int i = 0; i < missing; i++) { - frameData.add((byte) 0x00); - } - } - - - private boolean isEmptyFrame(List frameData) { - - for (Byte frameDateEntry : frameData) { - if (frameDateEntry != 0x00) { - return false; - } - } - - return true; - } - - - public static boolean isLowLevelDebug() { - return lowLevelDebug; - } - - public boolean isModelSet() { - return medtronicPumpStatus.medtronicDeviceType != null; - } - - public MedtronicDeviceType getMedtronicPumpModel() { - return medtronicPumpStatus.medtronicDeviceType; - } - - public void setMedtronicPumpModel(MedtronicDeviceType medtronicPumpModel) { - this.medtronicPumpStatus.medtronicDeviceType = medtronicPumpModel; - } - - public MedtronicCommandType getCurrentCommand() { - return this.currentCommand; - } - - public void setCurrentCommand(MedtronicCommandType currentCommand) { - this.currentCommand = currentCommand; - - if (currentCommand != null) - rileyLinkUtil.getRileyLinkHistory().add(new RLHistoryItemMedtronic(currentCommand)); - - } - - public int pageNumber; - public Integer frameNumber; - - - public void setCurrentCommand(MedtronicCommandType currentCommand, int pageNumber_, Integer frameNumber_) { - pageNumber = pageNumber_; - frameNumber = frameNumber_; - - if (this.currentCommand != currentCommand) { - setCurrentCommand(currentCommand); - } - - rxBus.send(new EventRileyLinkDeviceStatusChange(medtronicPumpStatus.getPumpDeviceState())); - } - - - public static boolean isSame(Double d1, Double d2) { - double diff = d1 - d2; - - return (Math.abs(diff) <= 0.000001); - } - - - public Map getSettings() { - return settings; - } - - public void setSettings(Map settings) { - this.settings = settings; - } - - public void setPumpTime(ClockDTO pumpTime) { - this.pumpTime = pumpTime; - } - - public ClockDTO getPumpTime() { - return this.pumpTime; - } -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/util/MedtronicUtil.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/util/MedtronicUtil.kt new file mode 100644 index 0000000000..ac690be476 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/util/MedtronicUtil.kt @@ -0,0 +1,314 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.util + +import com.google.gson.GsonBuilder +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.bus.RxBusWrapper +import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification +import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification +import info.nightscout.androidaps.plugins.general.overview.notifications.Notification +import info.nightscout.androidaps.plugins.pump.common.events.EventRileyLinkDeviceStatusChange +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkUtil +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkServiceData +import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.ClockDTO +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.PumpSettingDTO +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.RLHistoryItemMedtronic +import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicCommandType +import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicDeviceType +import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicNotificationType +import info.nightscout.androidaps.plugins.pump.medtronic.driver.MedtronicPumpStatus +import info.nightscout.androidaps.utils.resources.ResourceHelper +import org.joda.time.LocalTime +import java.nio.ByteBuffer +import java.nio.ByteOrder +import java.util.* +import javax.inject.Inject +import javax.inject.Singleton +import kotlin.experimental.or + +/** + * Created by andy on 5/9/18. + */ +@Singleton +class MedtronicUtil @Inject constructor( + private val aapsLogger: AAPSLogger, + private val rxBus: RxBusWrapper, + private val rileyLinkUtil: RileyLinkUtil, + private val medtronicPumpStatus: MedtronicPumpStatus +) { + + private val ENVELOPE_SIZE = 4 // 0xA7 S1 S2 S3 CMD PARAM_COUNT [PARAMS] + + //private MedtronicDeviceType medtronicPumpModel; + private var currentCommand: MedtronicCommandType? = null + var settings: Map? = null + private val BIG_FRAME_LENGTH = 65 + private val doneBit = 1 shl 7 + var pumpTime: ClockDTO? = null + var gsonInstance = GsonBuilder().excludeFieldsWithoutExposeAnnotation().create() + + + fun getTimeFrom30MinInterval(interval: Int): LocalTime { + return if (interval % 2 == 0) { + LocalTime(interval / 2, 0) + } else { + LocalTime((interval - 1) / 2, 30) + } + } + + fun decodeBasalInsulin(i: Int, j: Int): Double { + return decodeBasalInsulin(makeUnsignedShort(i, j)) + } + + fun decodeBasalInsulin(i: Int): Double { + return i.toDouble() / 40.0 + } + + fun getBasalStrokes(amount: Double): ByteArray { + return getBasalStrokes(amount, false) + } + + fun getBasalStrokesInt(amount: Double): Int { + return getStrokesInt(amount, 40) + } + + fun getBolusStrokes(amount: Double): ByteArray { + val strokesPerUnit = medtronicPumpStatus.medtronicDeviceType!!.bolusStrokes + val length: Int + val scrollRate: Int + if (strokesPerUnit >= 40) { + length = 2 + + // 40-stroke pumps scroll faster for higher unit values + scrollRate = if (amount > 10) 4 else if (amount > 1) 2 else 1 + } else { + length = 1 + scrollRate = 1 + } + val strokes = (amount * (strokesPerUnit * 1.0 / (scrollRate * 1.0))).toInt() * scrollRate + return ByteUtil.fromHexString(String.format("%02x%0" + 2 * length + "x", length, strokes)) + } + + fun createCommandBody(input: ByteArray): ByteArray { + return ByteUtil.concat(input.size.toByte(), input) + } + + fun sendNotification(notificationType: MedtronicNotificationType, resourceHelper: ResourceHelper, rxBus: RxBusWrapper) { + val notification = Notification( // + notificationType.notificationType, // + resourceHelper.gs(notificationType.resourceId), // + notificationType.notificationUrgency) + rxBus.send(EventNewNotification(notification)) + } + + fun sendNotification(notificationType: MedtronicNotificationType, resourceHelper: ResourceHelper, rxBus: RxBusWrapper, vararg parameters: Any?) { + val notification = Notification( // + notificationType.notificationType, // + resourceHelper.gs(notificationType.resourceId, *parameters), // + notificationType.notificationUrgency) + rxBus.send(EventNewNotification(notification)) + } + + fun dismissNotification(notificationType: MedtronicNotificationType, rxBus: RxBusWrapper) { + rxBus.send(EventDismissNotification(notificationType.notificationType)) + } + + fun buildCommandPayload(rileyLinkServiceData: RileyLinkServiceData, commandType: MedtronicCommandType, parameters: ByteArray?): ByteArray { + return buildCommandPayload(rileyLinkServiceData, commandType.commandCode, parameters) + } + + fun buildCommandPayload(rileyLinkServiceData: RileyLinkServiceData, commandType: Byte, parameters: ByteArray?): ByteArray { + // A7 31 65 51 C0 00 52 + val commandLength = (if (parameters == null) 2 else 2 + parameters.size).toByte() + val sendPayloadBuffer = ByteBuffer.allocate(ENVELOPE_SIZE + commandLength) // + CRC_SIZE + sendPayloadBuffer.order(ByteOrder.BIG_ENDIAN) + val serialNumberBCD = rileyLinkServiceData.pumpIDBytes + sendPayloadBuffer.put(0xA7.toByte()) + sendPayloadBuffer.put(serialNumberBCD[0]) + sendPayloadBuffer.put(serialNumberBCD[1]) + sendPayloadBuffer.put(serialNumberBCD[2]) + sendPayloadBuffer.put(commandType) + if (parameters == null) { + sendPayloadBuffer.put(0x00.toByte()) + } else { + sendPayloadBuffer.put(parameters.size.toByte()) // size + for (`val` in parameters) { + sendPayloadBuffer.put(`val`) + } + } + val payload = sendPayloadBuffer.array() + aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "buildCommandPayload [%s]", ByteUtil.shortHexString(payload))) + + // int crc = computeCRC8WithPolynomial(payload, 0, payload.length - 1); + + // LOG.info("crc: " + crc); + + // sendPayloadBuffer.put((byte) crc); + return sendPayloadBuffer.array() + } + + // Note: at the moment supported only for 24 items, if you will use it for more than + // that you will need to add + fun getBasalProfileFrames(data: ByteArray): List> { + var done = false + var start = 0 + var frame = 1 + val frames: MutableList> = ArrayList() + var lastFrame = false + do { + var frameLength = BIG_FRAME_LENGTH - 1 + if (start + frameLength > data.size) { + frameLength = data.size - start + } + + // System.out.println("Framelength: " + frameLength); + val substring = ByteUtil.substring(data, start, frameLength) + + // System.out.println("Subarray: " + ByteUtil.getCompactString(substring)); + // System.out.println("Subarray Lenths: " + substring.length); + val frameData = ByteUtil.getListFromByteArray(substring) + if (isEmptyFrame(frameData)) { + var b = frame.toByte() + // b |= 0x80; + b = b or 128.toByte() + // b |= doneBit; + frameData.add(0, b) + checkAndAppenLastFrame(frameData) + lastFrame = true + done = true + } else { + frameData.add(0, frame.toByte()) + } + + // System.out.println("Subarray: " + ByteUtil.getCompactString(substring)); + frames.add(frameData) + frame++ + start += BIG_FRAME_LENGTH - 1 + if (start == data.size) { + done = true + } + } while (!done) + if (!lastFrame) { + val frameData: MutableList = ArrayList() + var b = frame.toByte() + b = b or 128.toByte() + // b |= doneBit; + frameData.add(b) + checkAndAppenLastFrame(frameData) + } + return frames + } + + private fun checkAndAppenLastFrame(frameData: MutableList) { + if (frameData.size == BIG_FRAME_LENGTH) return + val missing = BIG_FRAME_LENGTH - frameData.size + for (i in 0 until missing) { + frameData.add(0x00.toByte()) + } + } + + private fun isEmptyFrame(frameData: List): Boolean { + for (frameDateEntry in frameData) { + if (frameDateEntry.toInt() != 0x00) { + return false + } + } + return true + } + + val isModelSet: Boolean + get() = medtronicPumpStatus.medtronicDeviceType != null + + var medtronicPumpModel: MedtronicDeviceType? + get() = medtronicPumpStatus.medtronicDeviceType + set(medtronicPumpModel) { + medtronicPumpStatus.medtronicDeviceType = medtronicPumpModel + } + + fun getCurrentCommand(): MedtronicCommandType? { + return currentCommand + } + + fun setCurrentCommand(currentCommandIn: MedtronicCommandType?) { + this.currentCommand = currentCommandIn + if (currentCommand != null) rileyLinkUtil.rileyLinkHistory.add(RLHistoryItemMedtronic(currentCommandIn!!)) + } + + var pageNumber = 0 + var frameNumber: Int? = null + + fun setCurrentCommand(currentCommand: MedtronicCommandType, pageNumber_: Int, frameNumber_: Int?) { + pageNumber = pageNumber_ + frameNumber = frameNumber_ + if (this.currentCommand !== currentCommand) { + setCurrentCommand(currentCommand) + } + rxBus.send(EventRileyLinkDeviceStatusChange(medtronicPumpStatus.pumpDeviceState)) + } + + companion object { + const val isLowLevelDebug = true + fun getIntervalFromMinutes(minutes: Int): Int { + return minutes / 30 + } + + fun makeUnsignedShort(b2: Int, b1: Int): Int { + return b2 and 0xff shl 8 or b1 and 0xff + } + + @JvmStatic + fun getByteArrayFromUnsignedShort(shortValue: Int, returnFixedSize: Boolean): ByteArray { + val highByte = (shortValue shr 8 and 0xFF).toByte() + val lowByte = (shortValue and 0xFF).toByte() + return if (highByte > 0) { + createByteArray(highByte, lowByte) + } else { + if (returnFixedSize) createByteArray(highByte, lowByte) else createByteArray(lowByte) + } + } + + fun createByteArray(vararg data: Byte): ByteArray { + return data + } + + @JvmStatic + fun createByteArray(data: List): ByteArray { + val array = ByteArray(data.size) + for (i in data.indices) { + array[i] = data[i] + } + return array + } + + fun getBasalStrokes(amount: Double, returnFixedSize: Boolean): ByteArray { + return getStrokes(amount, 40, returnFixedSize) + } + + fun getStrokes(amount: Double, strokesPerUnit: Int, returnFixedSize: Boolean): ByteArray { + val strokes = getStrokesInt(amount, strokesPerUnit) + return getByteArrayFromUnsignedShort(strokes, returnFixedSize) + } + + fun getStrokesInt(amount: Double, strokesPerUnit: Int): Int { + var length = 1 + var scrollRate = 1 + if (strokesPerUnit >= 40) { + length = 2 + + // 40-stroke pumps scroll faster for higher unit values + if (amount > 10) scrollRate = 4 else if (amount > 1) scrollRate = 2 + } + var strokes = (amount * (strokesPerUnit / (scrollRate * 1.0))).toInt() + strokes *= scrollRate + return strokes + } + + @JvmStatic + fun isSame(d1: Double, d2: Double): Boolean { + val diff = d1 - d2 + return Math.abs(diff) <= 0.000001 + } + } + +} \ No newline at end of file diff --git a/medtronic/src/main/res/values/strings.xml b/medtronic/src/main/res/values/strings.xml index 32715ce7b4..801413be38 100644 --- a/medtronic/src/main/res/values/strings.xml +++ b/medtronic/src/main/res/values/strings.xml @@ -95,6 +95,9 @@ Get History - Page %1$d (%2$d/16) Get History - Page %1$d Get Pump Time + Set Pump Time + Get Battery Status + Get Settings Get Pump Model Get Basal Profile @@ -115,8 +118,7 @@ set_neutral_temps Set neutral temp basals If enabled, it will cancel a temporary basal before the end of each hour. This method can help stop some pumps beeping/vibrating on the hour. - - + %1$.1f U/h (%2$d min remaining) ^\\d{6} \ No newline at end of file diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/ByteUtil.java b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/ByteUtil.java index da5e99596c..ac4f6d24af 100644 --- a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/ByteUtil.java +++ b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/ByteUtil.java @@ -186,22 +186,6 @@ public class ByteUtil { } - // public static byte[] fromByteList(List byteArray) { - // byte[] rval = new byte[byteArray.size()]; - // for (int i = 0; i < byteArray.size(); i++) { - // rval[i] = byteArray.get(i); - // } - // return rval; - // } - - // public static List toByteList(byte[] data) { - // ArrayList rval = new ArrayList<>(data.length); - // for (int i = 0; i < data.length; i++) { - // rval.add(i, new Byte(data[i])); - // } - // return rval; - // } - public static List getListFromByteArray(byte[] array) { List listOut = new ArrayList(); @@ -340,6 +324,9 @@ public class ByteUtil { return toInt(b1, b2, b3, null, BitConversion.BIG_ENDIAN); } + public static int toInt(Byte b1, Byte b2, Byte b3) { + return toInt(b1, b2, b3, null, BitConversion.BIG_ENDIAN); + } public static int toInt(int b1, int b2, BitConversion flag) { return toInt(b1, b2, null, null, flag); From 7ebb199de3a9c65df6de6fc997e55597cec32d15 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Apr 2021 08:44:20 +0000 Subject: [PATCH 007/145] Bump byteBuddyVersion from 1.10.22 to 1.11.0 Bumps `byteBuddyVersion` from 1.10.22 to 1.11.0. Updates `byte-buddy` from 1.10.22 to 1.11.0 - [Release notes](https://github.com/raphw/byte-buddy/releases) - [Changelog](https://github.com/raphw/byte-buddy/blob/master/release-notes.md) - [Commits](https://github.com/raphw/byte-buddy/compare/byte-buddy-1.10.22...byte-buddy-1.11.0) Updates `byte-buddy-android` from 1.10.22 to 1.11.0 - [Release notes](https://github.com/raphw/byte-buddy/releases) - [Changelog](https://github.com/raphw/byte-buddy/blob/master/release-notes.md) - [Commits](https://github.com/raphw/byte-buddy/compare/byte-buddy-1.10.22...byte-buddy-1.11.0) Updates `byte-buddy-agent` from 1.10.22 to 1.11.0 - [Release notes](https://github.com/raphw/byte-buddy/releases) - [Changelog](https://github.com/raphw/byte-buddy/blob/master/release-notes.md) - [Commits](https://github.com/raphw/byte-buddy/compare/byte-buddy-1.10.22...byte-buddy-1.11.0) Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 7b872f31b7..32c694aeeb 100644 --- a/build.gradle +++ b/build.gradle @@ -30,7 +30,7 @@ buildscript { dexmakerVersion = "1.2" retrofit2Version = '2.9.0' okhttp3Version = '4.9.0' - byteBuddyVersion = '1.10.22' + byteBuddyVersion = '1.11.0' androidx_junit = '1.1.2' androidx_rules = '1.4.0-alpha04' From 6b7efdcb95abee1240098a6a6487e233700cd654 Mon Sep 17 00:00:00 2001 From: Andy Rozman Date: Tue, 20 Apr 2021 16:45:29 +0100 Subject: [PATCH 008/145] - more kotlinize, MedtronicHistoryActivity not yet working --- app/build.gradle | 2 +- .../pump/common/PumpPluginAbstract.java | 529 ------ .../plugins/pump/common/PumpPluginAbstract.kt | 431 +++++ .../plugins/pump/common/data/PumpDbEntry.java | 21 - .../plugins/pump/common/data/PumpDbEntry.kt | 9 + .../pump/medtronic/MedtronicPumpPlugin.java | 1627 ----------------- .../pump/medtronic/MedtronicPumpPlugin.kt | 1179 ++++++++++++ .../comm/MedtronicCommunicationManager.java | 38 + .../pump/medtronic/data/dto/BasalProfile.kt | 25 +- .../dialog/MedtronicHistoryActivity.java | 250 --- .../dialog/MedtronicHistoryActivity.kt | 200 ++ .../RileyLinkStatusDeviceMedtronic.java | 166 -- .../dialog/RileyLinkStatusDeviceMedtronic.kt | 137 ++ .../service/RileyLinkMedtronicService.kt | 11 +- .../pump/common/defs/PumpHistoryEntryGroup.kt | 4 +- .../res/layout/rileylink_status_device.xml | 2 +- 16 files changed, 2016 insertions(+), 2615 deletions(-) delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpDbEntry.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpDbEntry.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/MedtronicHistoryActivity.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/MedtronicHistoryActivity.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/RileyLinkStatusDeviceMedtronic.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/RileyLinkStatusDeviceMedtronic.kt diff --git a/app/build.gradle b/app/build.gradle index e4d4c5be8b..ce044fe703 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -111,7 +111,7 @@ android { defaultConfig { multiDexEnabled true versionCode 1500 - version "2.8.2.1-dev-e3" + version "2.8.2.1-meallink-mdt" buildConfigField "String", "VERSION", '"' + version + '"' buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"' buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"' diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java deleted file mode 100644 index ca9100a086..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java +++ /dev/null @@ -1,529 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.common; - -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; - -import androidx.annotation.NonNull; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.HashMap; -import java.util.Map; - -import dagger.android.HasAndroidInjector; -import info.nightscout.androidaps.core.R; -import info.nightscout.androidaps.data.DetailedBolusInfo; -import info.nightscout.androidaps.data.Profile; -import info.nightscout.androidaps.data.PumpEnactResult; -import info.nightscout.androidaps.db.TemporaryBasal; -import info.nightscout.androidaps.events.EventAppExit; -import info.nightscout.androidaps.events.EventCustomActionsChanged; -import info.nightscout.androidaps.extensions.PumpStateExtensionKt; -import info.nightscout.androidaps.interfaces.ActivePlugin; -import info.nightscout.androidaps.interfaces.CommandQueueProvider; -import info.nightscout.androidaps.interfaces.Constraints; -import info.nightscout.androidaps.interfaces.PluginDescription; -import info.nightscout.androidaps.interfaces.PumpDescription; -import info.nightscout.androidaps.interfaces.Pump; -import info.nightscout.androidaps.interfaces.PumpPluginBase; -import info.nightscout.androidaps.interfaces.PumpSync; -import info.nightscout.androidaps.logging.AAPSLogger; -import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.plugins.bus.RxBusWrapper; -import info.nightscout.androidaps.plugins.common.ManufacturerType; -import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress; -import info.nightscout.androidaps.plugins.pump.common.data.PumpDbEntry; -import info.nightscout.androidaps.plugins.pump.common.data.PumpStatus; -import info.nightscout.androidaps.plugins.pump.common.defs.PumpDriverState; -import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; -import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicConst; -import info.nightscout.androidaps.utils.DateUtil; -import info.nightscout.androidaps.utils.DecimalFormatter; -import info.nightscout.androidaps.utils.FabricPrivacy; -import info.nightscout.androidaps.utils.resources.ResourceHelper; -import info.nightscout.androidaps.utils.rx.AapsSchedulers; -import info.nightscout.androidaps.utils.sharedPreferences.SP; -import io.reactivex.disposables.CompositeDisposable; - -import static info.nightscout.androidaps.extensions.PumpStateExtensionKt.convertedToAbsolute; -import static info.nightscout.androidaps.extensions.PumpStateExtensionKt.getPlannedRemainingMinutes; - -/** - * Created by andy on 23.04.18. - */ - -// When using this class, make sure that your first step is to create mConnection (see MedtronicPumpPlugin) - -public abstract class PumpPluginAbstract extends PumpPluginBase implements Pump, Constraints { - private final CompositeDisposable disposable = new CompositeDisposable(); - - protected HasAndroidInjector injector; - protected AAPSLogger aapsLogger; - protected RxBusWrapper rxBus; - protected ActivePlugin activePlugin; - protected Context context; - protected FabricPrivacy fabricPrivacy; - protected ResourceHelper resourceHelper; - protected CommandQueueProvider commandQueue; - protected SP sp; - protected DateUtil dateUtil; - protected PumpDescription pumpDescription = new PumpDescription(); - protected ServiceConnection serviceConnection; - protected boolean serviceRunning = false; - protected PumpDriverState pumpState = PumpDriverState.NotInitialized; - protected boolean displayConnectionMessages = false; - protected PumpType pumpType; - protected AapsSchedulers aapsSchedulers; - protected PumpSync pumpSync; - protected Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); - - protected PumpPluginAbstract( - PluginDescription pluginDescription, - PumpType pumpType, - HasAndroidInjector injector, - ResourceHelper resourceHelper, - AAPSLogger aapsLogger, - CommandQueueProvider commandQueue, - RxBusWrapper rxBus, - ActivePlugin activePlugin, - SP sp, - Context context, - FabricPrivacy fabricPrivacy, - DateUtil dateUtil, - AapsSchedulers aapsSchedulers, - PumpSync pumpSync - ) { - - super(pluginDescription, injector, aapsLogger, resourceHelper, commandQueue); - this.aapsLogger = aapsLogger; - this.rxBus = rxBus; - this.activePlugin = activePlugin; - this.context = context; - this.fabricPrivacy = fabricPrivacy; - this.resourceHelper = resourceHelper; - this.sp = sp; - this.commandQueue = commandQueue; - - pumpDescription.setPumpDescription(pumpType); - this.pumpType = pumpType; - this.dateUtil = dateUtil; - this.aapsSchedulers = aapsSchedulers; - this.pumpSync = pumpSync; - } - - - public abstract void initPumpStatusData(); - - - @Override - protected void onStart() { - super.onStart(); - - initPumpStatusData(); - - Intent intent = new Intent(context, getServiceClass()); - context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); - - serviceRunning = true; - - disposable.add(rxBus - .toObservable(EventAppExit.class) - .observeOn(aapsSchedulers.getIo()) - .subscribe(event -> context.unbindService(serviceConnection), fabricPrivacy::logException) - ); - onStartCustomActions(); - } - - - @Override - protected void onStop() { - aapsLogger.debug(LTag.PUMP, this.deviceID() + " onStop()"); - - context.unbindService(serviceConnection); - - serviceRunning = false; - - disposable.clear(); - super.onStop(); - } - - - /** - * If we need to run any custom actions in onStart (triggering events, etc) - */ - public abstract void onStartCustomActions(); - - /** - * Service class (same one you did serviceConnection for) - * - * @return Class - */ - public abstract Class getServiceClass(); - - public abstract PumpStatus getPumpStatusData(); - - - public boolean isInitialized() { - return pumpState.isInitialized(); - } - - - public boolean isSuspended() { - return pumpState == PumpDriverState.Suspended; - } - - - public boolean isBusy() { - return pumpState == PumpDriverState.Busy; - } - - - public boolean isConnected() { - if (displayConnectionMessages) - aapsLogger.debug(LTag.PUMP, "isConnected [PumpPluginAbstract]."); - return pumpState.isConnected(); - } - - - public boolean isConnecting() { - if (displayConnectionMessages) - aapsLogger.debug(LTag.PUMP, "isConnecting [PumpPluginAbstract]."); - return pumpState == PumpDriverState.Connecting; - } - - - public void connect(@NonNull String reason) { - if (displayConnectionMessages) - aapsLogger.debug(LTag.PUMP, "connect (reason={}) [PumpPluginAbstract] - default (empty) implementation." + reason); - } - - - public void disconnect(@NonNull String reason) { - if (displayConnectionMessages) - aapsLogger.debug(LTag.PUMP, "disconnect (reason={}) [PumpPluginAbstract] - default (empty) implementation." + reason); - } - - - public void stopConnecting() { - if (displayConnectionMessages) - aapsLogger.debug(LTag.PUMP, "stopConnecting [PumpPluginAbstract] - default (empty) implementation."); - } - - - @Override - public boolean isHandshakeInProgress() { - if (displayConnectionMessages) - aapsLogger.debug(LTag.PUMP, "isHandshakeInProgress [PumpPluginAbstract] - default (empty) implementation."); - return false; - } - - - @Override - public void finishHandshaking() { - if (displayConnectionMessages) - aapsLogger.debug(LTag.PUMP, "finishHandshaking [PumpPluginAbstract] - default (empty) implementation."); - } - - // Upload to pump new basal profile - @NonNull public PumpEnactResult setNewBasalProfile(@NonNull Profile profile) { - aapsLogger.debug(LTag.PUMP, "setNewBasalProfile [PumpPluginAbstract] - Not implemented."); - return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); - } - - - public boolean isThisProfileSet(@NonNull Profile profile) { - aapsLogger.debug(LTag.PUMP, "isThisProfileSet [PumpPluginAbstract] - Not implemented."); - return true; - } - - - public long lastDataTime() { - aapsLogger.debug(LTag.PUMP, "lastDataTime [PumpPluginAbstract]."); - return getPumpStatusData().getLastConnection(); - } - - - public double getBaseBasalRate() { - aapsLogger.debug(LTag.PUMP, "getBaseBasalRate [PumpPluginAbstract] - Not implemented."); - return 0.0d; - } // base basal rate, not temp basal - - - public void stopBolusDelivering() { - aapsLogger.debug(LTag.PUMP, "stopBolusDelivering [PumpPluginAbstract] - Not implemented."); - } - - - @NonNull @Override - public PumpEnactResult setTempBasalAbsolute(double absoluteRate, int durationInMinutes, @NonNull Profile profile, boolean enforceNew, @NonNull PumpSync.TemporaryBasalType tbrType) { - aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute [PumpPluginAbstract] - Not implemented."); - return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); - } - - - @NonNull @Override - public PumpEnactResult setTempBasalPercent(int percent, int durationInMinutes, @NonNull Profile profile, boolean enforceNew, @NonNull PumpSync.TemporaryBasalType tbrType) { - aapsLogger.debug(LTag.PUMP, "setTempBasalPercent [PumpPluginAbstract] - Not implemented."); - return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); - } - - - @NonNull public PumpEnactResult setExtendedBolus(double insulin, int durationInMinutes) { - aapsLogger.debug(LTag.PUMP, "setExtendedBolus [PumpPluginAbstract] - Not implemented."); - return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); - } - - - // some pumps might set a very short temp close to 100% as cancelling a temp can be noisy - // when the cancel request is requested by the user (forced), the pump should always do a real cancel - - @NonNull public PumpEnactResult cancelTempBasal(boolean enforceNew) { - aapsLogger.debug(LTag.PUMP, "cancelTempBasal [PumpPluginAbstract] - Not implemented."); - return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); - } - - - @NonNull public PumpEnactResult cancelExtendedBolus() { - aapsLogger.debug(LTag.PUMP, "cancelExtendedBolus [PumpPluginAbstract] - Not implemented."); - return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); - } - - - // Status to be passed to NS - - // public JSONObject getJSONStatus(Profile profile, String profileName) { - // return pumpDriver.getJSONStatus(profile, profileName); - // } - - public String deviceID() { - aapsLogger.debug(LTag.PUMP, "deviceID [PumpPluginAbstract] - Not implemented."); - return "FakeDevice"; - } - - - // Pump capabilities - - - public PumpDescription getPumpDescription() { - return pumpDescription; - } - - - // Short info for SMS, Wear etc - - public boolean isFakingTempsByExtendedBoluses() { - aapsLogger.debug(LTag.PUMP, "isFakingTempsByExtendedBoluses [PumpPluginAbstract] - Not implemented."); - return false; - } - - - @NonNull @Override - public PumpEnactResult loadTDDs() { - aapsLogger.debug(LTag.PUMP, "loadTDDs [PumpPluginAbstract] - Not implemented."); - return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); - } - - - @NonNull @Override - public JSONObject getJSONStatus(@NonNull Profile profile, @NonNull String profileName, @NonNull String version) { - - if ((getPumpStatusData().getLastConnection() + 60 * 60 * 1000L) < System.currentTimeMillis()) { - return new JSONObject(); - } - - long now = System.currentTimeMillis(); - JSONObject pump = new JSONObject(); - JSONObject battery = new JSONObject(); - JSONObject status = new JSONObject(); - JSONObject extended = new JSONObject(); - try { - battery.put("percent", getPumpStatusData().getBatteryRemaining()); - status.put("status", getPumpStatusData().getPumpStatusType() != null ? getPumpStatusData().getPumpStatusType().getStatus() : "normal"); - extended.put("Version", version); - try { - extended.put("ActiveProfile", profileName); - } catch (Exception ignored) { - } - - PumpSync.PumpState.TemporaryBasal tb = pumpSync.expectedPumpState().getTemporaryBasal(); - if (tb != null) { - extended.put("TempBasalAbsoluteRate", convertedToAbsolute(tb, now, profile)); - extended.put("TempBasalStart", dateUtil.dateAndTimeString(tb.getTimestamp())); - extended.put("TempBasalRemaining", getPlannedRemainingMinutes(tb)); - } - - PumpSync.PumpState.ExtendedBolus eb = pumpSync.expectedPumpState().getExtendedBolus(); - if (eb != null) { - extended.put("ExtendedBolusAbsoluteRate", eb.getRate()); - extended.put("ExtendedBolusStart", dateUtil.dateAndTimeString(eb.getTimestamp())); - extended.put("ExtendedBolusRemaining", getPlannedRemainingMinutes(eb)); - } - - status.put("timestamp", dateUtil.toISOString(dateUtil.now())); - - pump.put("battery", battery); - pump.put("status", status); - pump.put("extended", extended); - pump.put("reservoir", getPumpStatusData().getReservoirRemainingUnits()); - pump.put("clock", dateUtil.toISOString(dateUtil.now())); - } catch (JSONException e) { - aapsLogger.error("Unhandled exception", e); - } - return pump; - } - - - // FIXME i18n, null checks: iob, TDD - @NonNull @Override - public String shortStatus(boolean veryShort) { - String ret = ""; - if (getPumpStatusData().getLastConnection() != 0) { - long agoMsec = System.currentTimeMillis() - getPumpStatusData().getLastConnection(); - int agoMin = (int) (agoMsec / 60d / 1000d); - ret += "LastConn: " + agoMin + " min ago\n"; - } - if (getPumpStatusData().getLastBolusTime() != null && getPumpStatusData().getLastBolusTime().getTime() != 0) { - ret += "LastBolus: " + DecimalFormatter.INSTANCE.to2Decimal(getPumpStatusData().getLastBolusAmount()) + "U @" + // - android.text.format.DateFormat.format("HH:mm", getPumpStatusData().getLastBolusTime()) + "\n"; - } - PumpSync.PumpState.TemporaryBasal activeTemp = pumpSync.expectedPumpState().getTemporaryBasal(); - if (activeTemp != null) { - ret += "Temp: " + PumpStateExtensionKt.toStringFull(activeTemp, dateUtil) + "\n"; - } - PumpSync.PumpState.ExtendedBolus activeExtendedBolus = pumpSync.expectedPumpState().getExtendedBolus(); - if (activeExtendedBolus != null) { - ret += "Extended: " + PumpStateExtensionKt.toStringFull(activeExtendedBolus, dateUtil) + "\n"; - } - // if (!veryShort) { - // ret += "TDD: " + DecimalFormatter.to0Decimal(pumpStatus.dailyTotalUnits) + " / " - // + pumpStatus.maxDailyTotalUnits + " U\n"; - // } - ret += "IOB: " + getPumpStatusData().getIob() + "U\n"; - ret += "Reserv: " + DecimalFormatter.INSTANCE.to0Decimal(getPumpStatusData().getReservoirRemainingUnits()) + "U\n"; - ret += "Batt: " + getPumpStatusData().getBatteryRemaining() + "\n"; - return ret; - } - - - @NonNull @Override - public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) { - - try { - if (detailedBolusInfo.insulin == 0 && detailedBolusInfo.carbs == 0) { - // neither carbs nor bolus requested - aapsLogger.error("deliverTreatment: Invalid input"); - return new PumpEnactResult(getInjector()).success(false).enacted(false).bolusDelivered(0d).carbsDelivered(0d) - .comment(R.string.invalidinput); - } else if (detailedBolusInfo.insulin > 0) { - // bolus needed, ask pump to deliver it - return deliverBolus(detailedBolusInfo); - } else { - //if (MedtronicHistoryData.doubleBolusDebug) - // aapsLogger.debug("DoubleBolusDebug: deliverTreatment::(carb only entry)"); - - // TODO fix - // no bolus required, carb only treatment - activePlugin.getActiveTreatments().addToHistoryTreatment(detailedBolusInfo, true); - - EventOverviewBolusProgress bolusingEvent = EventOverviewBolusProgress.INSTANCE; - bolusingEvent.setT(new EventOverviewBolusProgress.Treatment(0, 0, detailedBolusInfo.getBolusType() == DetailedBolusInfo.BolusType.SMB)); - bolusingEvent.setPercent(100); - rxBus.send(bolusingEvent); - - aapsLogger.debug(LTag.PUMP, "deliverTreatment: Carb only treatment."); - - return new PumpEnactResult(getInjector()).success(true).enacted(true).bolusDelivered(0d) - .carbsDelivered(detailedBolusInfo.carbs).comment(R.string.common_resultok); - } - } finally { - triggerUIChange(); - } - - } - - - protected void refreshCustomActionsList() { - rxBus.send(new EventCustomActionsChanged()); - } - - - @NonNull public ManufacturerType manufacturer() { - return pumpType.getManufacturer(); - } - - @NonNull - public PumpType model() { - return pumpType; - } - - - public PumpType getPumpType() { - return pumpType; - } - - - public void setPumpType(PumpType pumpType) { - this.pumpType = pumpType; - this.pumpDescription.setPumpDescription(pumpType); - } - - - public boolean canHandleDST() { - return false; - } - - - protected abstract PumpEnactResult deliverBolus(DetailedBolusInfo detailedBolusInfo); - - protected abstract void triggerUIChange(); - - private PumpEnactResult getOperationNotSupportedWithCustomText(int resourceId) { - return new PumpEnactResult(getInjector()).success(false).enacted(false).comment(resourceId); - } - - // PumpSync - - Map driverHistory = new HashMap<>(); - - public abstract long generateTempId(long timeMillis); - - protected boolean addBolusWithTempId(DetailedBolusInfo detailedBolusInfo, boolean writeToInternalHistory) { - long temporaryId = generateTempId(detailedBolusInfo.timestamp); - boolean response = pumpSync.addBolusWithTempId(detailedBolusInfo.timestamp, detailedBolusInfo.insulin, - temporaryId, detailedBolusInfo.getBolusType(), - getPumpType(), serialNumber()); - - if (response && writeToInternalHistory) { - driverHistory.put(temporaryId, new PumpDbEntry(temporaryId, model(), serialNumber(), detailedBolusInfo)); - sp.putString(MedtronicConst.Statistics.InternalTemporaryDatabase, gson.toJson(driverHistory)); - } - - return response; - } - - protected void addTemporaryBasalRateWithTempId(TemporaryBasal temporaryBasal, boolean b) { -// long temporaryId = generateTempId(temporaryBasal.timestamp); -// boolean response = pumpSync.addBolusWithTempId(temporaryBasal.timestamp, detailedBolusInfo.insulin, -// generateTempId(detailedBolusInfo.timestamp), detailedBolusInfo.getBolusType(), -// getPumpType(), serialNumber()); -// -// if (response && writeToInternalHistory) { -// driverHistory.put(temporaryId, new PumpDbEntry(temporaryId, model(), serialNumber(), detailedBolusInfo)); -// sp.putString(MedtronicConst.Statistics.InternalTemporaryDatabase, gson.toJson(driverHistory)); -// } -// -// return response; - } - - - public void removeTemporaryId(long temporaryId) { - driverHistory.remove(temporaryId); - } - - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.kt new file mode 100644 index 0000000000..26660c4936 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.kt @@ -0,0 +1,431 @@ +package info.nightscout.androidaps.plugins.pump.common + +import android.content.Context +import android.content.Intent +import android.content.ServiceConnection +import android.text.format.DateFormat +import com.google.gson.GsonBuilder +import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.core.R +import info.nightscout.androidaps.data.DetailedBolusInfo +import info.nightscout.androidaps.data.Profile +import info.nightscout.androidaps.data.PumpEnactResult +import info.nightscout.androidaps.db.TemporaryBasal +import info.nightscout.androidaps.events.EventAppExit +import info.nightscout.androidaps.events.EventCustomActionsChanged +import info.nightscout.androidaps.extensions.convertedToAbsolute +import info.nightscout.androidaps.extensions.plannedRemainingMinutes +import info.nightscout.androidaps.extensions.toStringFull +import info.nightscout.androidaps.interfaces.* +import info.nightscout.androidaps.interfaces.PumpSync.TemporaryBasalType +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.bus.RxBusWrapper +import info.nightscout.androidaps.plugins.common.ManufacturerType +import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress +import info.nightscout.androidaps.plugins.pump.common.data.PumpDbEntry +import info.nightscout.androidaps.plugins.pump.common.data.PumpStatus +import info.nightscout.androidaps.plugins.pump.common.defs.PumpDriverState +import info.nightscout.androidaps.plugins.pump.common.defs.PumpType +import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicConst +import info.nightscout.androidaps.utils.DateUtil +import info.nightscout.androidaps.utils.DecimalFormatter.to0Decimal +import info.nightscout.androidaps.utils.DecimalFormatter.to2Decimal +import info.nightscout.androidaps.utils.FabricPrivacy +import info.nightscout.androidaps.utils.resources.ResourceHelper +import info.nightscout.androidaps.utils.rx.AapsSchedulers +import info.nightscout.androidaps.utils.sharedPreferences.SP +import io.reactivex.disposables.CompositeDisposable +import org.json.JSONException +import org.json.JSONObject +import java.util.* + +/** + * Created by andy on 23.04.18. + */ +// When using this class, make sure that your first step is to create mConnection (see MedtronicPumpPlugin) +abstract class PumpPluginAbstract protected constructor( + pluginDescription: PluginDescription?, + pumpType: PumpType, + injector: HasAndroidInjector?, + resourceHelper: ResourceHelper, + aapsLogger: AAPSLogger, + commandQueue: CommandQueueProvider, + var rxBus: RxBusWrapper, + var activePlugin: ActivePlugin, + var sp: SP, + var context: Context, + var fabricPrivacy: FabricPrivacy, + dateUtil: DateUtil, + aapsSchedulers: AapsSchedulers, + pumpSync: PumpSync +) : PumpPluginBase(pluginDescription!!, injector!!, aapsLogger, resourceHelper, commandQueue), Pump, Constraints { + + private val disposable = CompositeDisposable() + //protected override var injector: HasAndroidInjector? = null + protected var dateUtil: DateUtil + + // Pump capabilities + final override var pumpDescription = PumpDescription() + //protected set + + @JvmField protected var serviceConnection: ServiceConnection? = null + @JvmField protected var serviceRunning = false + @JvmField protected var pumpState = PumpDriverState.NotInitialized + @JvmField protected var displayConnectionMessages = false + + var pumpType: PumpType? = null + get() = field + set(value) { + field = value + pumpDescription.setPumpDescription(value!!) + } + + + protected var aapsSchedulers: AapsSchedulers + protected var pumpSync: PumpSync + protected var gson = GsonBuilder().excludeFieldsWithoutExposeAnnotation().create() + + abstract fun initPumpStatusData() + + override fun onStart() { + super.onStart() + initPumpStatusData() + val intent = Intent(context, serviceClass) + context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE) + serviceRunning = true + disposable.add(rxBus + .toObservable(EventAppExit::class.java) + .observeOn(aapsSchedulers.io) + .subscribe({ event: EventAppExit? -> context.unbindService(serviceConnection) }) { throwable: Throwable? -> fabricPrivacy.logException(throwable!!) } + ) + onStartCustomActions() + } + + override fun onStop() { + aapsLogger.debug(LTag.PUMP, deviceID() + " onStop()") + context.unbindService(serviceConnection) + serviceRunning = false + disposable.clear() + super.onStop() + } + + /** + * If we need to run any custom actions in onStart (triggering events, etc) + */ + abstract fun onStartCustomActions() + + /** + * Service class (same one you did serviceConnection for) + * + * @return Class + */ + abstract val serviceClass: Class<*>? + abstract val pumpStatusData: PumpStatus + + override fun isInitialized(): Boolean { + return pumpState.isInitialized() + } + + override fun isSuspended(): Boolean { + return pumpState === PumpDriverState.Suspended + } + + override fun isBusy(): Boolean { + return pumpState === PumpDriverState.Busy + } + + override fun isConnected(): Boolean { + if (displayConnectionMessages) aapsLogger.debug(LTag.PUMP, "isConnected [PumpPluginAbstract].") + return pumpState.isConnected() + } + + override fun isConnecting(): Boolean { + if (displayConnectionMessages) aapsLogger.debug(LTag.PUMP, "isConnecting [PumpPluginAbstract].") + return pumpState === PumpDriverState.Connecting + } + + override fun connect(reason: String) { + if (displayConnectionMessages) aapsLogger.debug(LTag.PUMP, "connect (reason={}) [PumpPluginAbstract] - default (empty) implementation.$reason") + } + + override fun disconnect(reason: String) { + if (displayConnectionMessages) aapsLogger.debug(LTag.PUMP, "disconnect (reason={}) [PumpPluginAbstract] - default (empty) implementation.$reason") + } + + override fun stopConnecting() { + if (displayConnectionMessages) aapsLogger.debug(LTag.PUMP, "stopConnecting [PumpPluginAbstract] - default (empty) implementation.") + } + + override fun isHandshakeInProgress(): Boolean { + if (displayConnectionMessages) aapsLogger.debug(LTag.PUMP, "isHandshakeInProgress [PumpPluginAbstract] - default (empty) implementation.") + return false + } + + override fun finishHandshaking() { + if (displayConnectionMessages) aapsLogger.debug(LTag.PUMP, "finishHandshaking [PumpPluginAbstract] - default (empty) implementation.") + } + + // Upload to pump new basal profile + override fun setNewBasalProfile(profile: Profile): PumpEnactResult { + aapsLogger.debug(LTag.PUMP, "setNewBasalProfile [PumpPluginAbstract] - Not implemented.") + return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver) + } + + override fun isThisProfileSet(profile: Profile): Boolean { + aapsLogger.debug(LTag.PUMP, "isThisProfileSet [PumpPluginAbstract] - Not implemented.") + return true + } + + override fun lastDataTime(): Long { + aapsLogger.debug(LTag.PUMP, "lastDataTime [PumpPluginAbstract].") + return pumpStatusData.lastConnection + } + + // base basal rate, not temp basal + override val baseBasalRate: Double + get() { + aapsLogger.debug(LTag.PUMP, "getBaseBasalRate [PumpPluginAbstract] - Not implemented.") + return 0.0 + } + + override fun stopBolusDelivering() { + aapsLogger.debug(LTag.PUMP, "stopBolusDelivering [PumpPluginAbstract] - Not implemented.") + } + + override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: TemporaryBasalType): PumpEnactResult { + aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute [PumpPluginAbstract] - Not implemented.") + return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver) + } + + override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: TemporaryBasalType): PumpEnactResult { + aapsLogger.debug(LTag.PUMP, "setTempBasalPercent [PumpPluginAbstract] - Not implemented.") + return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver) + } + + override fun setExtendedBolus(insulin: Double, durationInMinutes: Int): PumpEnactResult { + aapsLogger.debug(LTag.PUMP, "setExtendedBolus [PumpPluginAbstract] - Not implemented.") + return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver) + } + + // some pumps might set a very short temp close to 100% as cancelling a temp can be noisy + // when the cancel request is requested by the user (forced), the pump should always do a real cancel + override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult { + aapsLogger.debug(LTag.PUMP, "cancelTempBasal [PumpPluginAbstract] - Not implemented.") + return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver) + } + + override fun cancelExtendedBolus(): PumpEnactResult { + aapsLogger.debug(LTag.PUMP, "cancelExtendedBolus [PumpPluginAbstract] - Not implemented.") + return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver) + } + + // Status to be passed to NS + // public JSONObject getJSONStatus(Profile profile, String profileName) { + // return pumpDriver.getJSONStatus(profile, profileName); + // } + open fun deviceID(): String { + aapsLogger.debug(LTag.PUMP, "deviceID [PumpPluginAbstract] - Not implemented.") + return "FakeDevice" + } + + // Short info for SMS, Wear etc + override val isFakingTempsByExtendedBoluses: Boolean + get() { + aapsLogger.debug(LTag.PUMP, "isFakingTempsByExtendedBoluses [PumpPluginAbstract] - Not implemented.") + return false + } + + override fun loadTDDs(): PumpEnactResult { + aapsLogger.debug(LTag.PUMP, "loadTDDs [PumpPluginAbstract] - Not implemented.") + return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver) + } + + override fun getJSONStatus(profile: Profile, profileName: String, version: String): JSONObject { + if (pumpStatusData.lastConnection + 60 * 60 * 1000L < System.currentTimeMillis()) { + return JSONObject() + } + val now = System.currentTimeMillis() + val pump = JSONObject() + val battery = JSONObject() + val status = JSONObject() + val extended = JSONObject() + try { + battery.put("percent", pumpStatusData.batteryRemaining) + status.put("status", if (pumpStatusData.pumpStatusType != null) pumpStatusData.pumpStatusType.status else "normal") + extended.put("Version", version) + try { + extended.put("ActiveProfile", profileName) + } catch (ignored: Exception) { + } + val tb = pumpSync.expectedPumpState().temporaryBasal + if (tb != null) { + extended.put("TempBasalAbsoluteRate", tb.convertedToAbsolute(now, profile)) + extended.put("TempBasalStart", dateUtil.dateAndTimeString(tb.timestamp)) + extended.put("TempBasalRemaining", tb.plannedRemainingMinutes) + } + val eb = pumpSync.expectedPumpState().extendedBolus + if (eb != null) { + extended.put("ExtendedBolusAbsoluteRate", eb.rate) + extended.put("ExtendedBolusStart", dateUtil.dateAndTimeString(eb.timestamp)) + extended.put("ExtendedBolusRemaining", eb.plannedRemainingMinutes) + } + status.put("timestamp", dateUtil.toISOString(dateUtil.now())) + pump.put("battery", battery) + pump.put("status", status) + pump.put("extended", extended) + pump.put("reservoir", pumpStatusData.reservoirRemainingUnits) + pump.put("clock", dateUtil.toISOString(dateUtil.now())) + } catch (e: JSONException) { + aapsLogger.error("Unhandled exception", e) + } + return pump + } + + // FIXME i18n, null checks: iob, TDD + override fun shortStatus(veryShort: Boolean): String { + var ret = "" + + if (pumpStatusData.lastConnection==0L) { + ret += "LastConn: never\n" + } else { + val agoMsec = System.currentTimeMillis() - pumpStatusData.lastConnection + val agoMin = (agoMsec / 60.0 / 1000.0).toInt() + ret += "LastConn: $agoMin min ago\n" + } + + if (pumpStatusData.lastBolusTime != null && pumpStatusData.lastBolusTime!!.time != 0L) { + ret += """ + LastBolus: ${to2Decimal(pumpStatusData.lastBolusAmount!!)}U @${DateFormat.format("HH:mm", pumpStatusData.lastBolusTime)} + + """.trimIndent() + } + val activeTemp = pumpSync.expectedPumpState().temporaryBasal + if (activeTemp != null) { + ret += """ + Temp: ${activeTemp.toStringFull(dateUtil)} + + """.trimIndent() + } + val activeExtendedBolus = pumpSync.expectedPumpState().extendedBolus + if (activeExtendedBolus != null) { + ret += """ + Extended: ${activeExtendedBolus.toStringFull(dateUtil)} + + """.trimIndent() + } + // if (!veryShort) { + // ret += "TDD: " + DecimalFormatter.to0Decimal(pumpStatus.dailyTotalUnits) + " / " + // + pumpStatus.maxDailyTotalUnits + " U\n"; + // } + ret += """ + IOB: ${pumpStatusData.iob}U + + """.trimIndent() + ret += """ + Reserv: ${to0Decimal(pumpStatusData.reservoirRemainingUnits)}U + + """.trimIndent() + ret += """ + Batt: ${pumpStatusData.batteryRemaining} + + """.trimIndent() + return ret + } + + override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult { + return try { + if (detailedBolusInfo.insulin == 0.0 && detailedBolusInfo.carbs == 0.0) { + // neither carbs nor bolus requested + aapsLogger.error("deliverTreatment: Invalid input") + PumpEnactResult(injector).success(false).enacted(false).bolusDelivered(0.0).carbsDelivered(0.0) + .comment(R.string.invalidinput) + } else if (detailedBolusInfo.insulin > 0) { + // bolus needed, ask pump to deliver it + deliverBolus(detailedBolusInfo) + } else { + + // TODO fix + // no bolus required, carb only treatment + activePlugin.activeTreatments.addToHistoryTreatment(detailedBolusInfo, true) + val bolusingEvent = EventOverviewBolusProgress + bolusingEvent.t = EventOverviewBolusProgress.Treatment(0.0, 0, detailedBolusInfo.bolusType === DetailedBolusInfo.BolusType.SMB) + bolusingEvent.percent = 100 + rxBus.send(bolusingEvent) + aapsLogger.debug(LTag.PUMP, "deliverTreatment: Carb only treatment.") + PumpEnactResult(injector).success(true).enacted(true).bolusDelivered(0.0) + .carbsDelivered(detailedBolusInfo.carbs).comment(R.string.common_resultok) + } + } finally { + triggerUIChange() + } + } + + protected fun refreshCustomActionsList() { + rxBus.send(EventCustomActionsChanged()) + } + + override fun manufacturer(): ManufacturerType { + return pumpType!!.manufacturer!! + } + + override fun model(): PumpType { + return pumpType!! + } + + + override fun canHandleDST(): Boolean { + return false + } + + protected abstract fun deliverBolus(detailedBolusInfo: DetailedBolusInfo?): PumpEnactResult + + protected abstract fun triggerUIChange() + + private fun getOperationNotSupportedWithCustomText(resourceId: Int): PumpEnactResult { + return PumpEnactResult(injector).success(false).enacted(false).comment(resourceId) + } + + // PumpSync + var driverHistory: MutableMap = HashMap() + + abstract fun generateTempId(timeMillis: Long): Long + + protected fun addBolusWithTempId(detailedBolusInfo: DetailedBolusInfo, writeToInternalHistory: Boolean): Boolean { + val temporaryId = generateTempId(detailedBolusInfo.timestamp) + val response = pumpSync.addBolusWithTempId(detailedBolusInfo.timestamp, detailedBolusInfo.insulin, + temporaryId, detailedBolusInfo.bolusType, + pumpType!!, serialNumber()) + if (response && writeToInternalHistory) { + driverHistory[temporaryId] = PumpDbEntry(temporaryId, model(), serialNumber(), detailedBolusInfo) + sp.putString(MedtronicConst.Statistics.InternalTemporaryDatabase, gson.toJson(driverHistory)) + } + return response + } + + protected fun addTemporaryBasalRateWithTempId(temporaryBasal: TemporaryBasal?, b: Boolean) { +// long temporaryId = generateTempId(temporaryBasal.timestamp); +// boolean response = pumpSync.addBolusWithTempId(temporaryBasal.timestamp, detailedBolusInfo.insulin, +// generateTempId(detailedBolusInfo.timestamp), detailedBolusInfo.getBolusType(), +// getPumpType(), serialNumber()); +// +// if (response && writeToInternalHistory) { +// driverHistory.put(temporaryId, new PumpDbEntry(temporaryId, model(), serialNumber(), detailedBolusInfo)); +// sp.putString(MedtronicConst.Statistics.InternalTemporaryDatabase, gson.toJson(driverHistory)); +// } +// +// return response; + } + + fun removeTemporaryId(temporaryId: Long) { + driverHistory.remove(temporaryId) + } + + init { + pumpDescription.setPumpDescription(pumpType) + this.pumpType = pumpType + this.dateUtil = dateUtil + this.aapsSchedulers = aapsSchedulers + this.pumpSync = pumpSync + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpDbEntry.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpDbEntry.java deleted file mode 100644 index f67a9741f8..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpDbEntry.java +++ /dev/null @@ -1,21 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.common.data; - -import info.nightscout.androidaps.data.DetailedBolusInfo; -import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; - -public class PumpDbEntry { - - long temporaryId; - PumpType pumpType; - String serialNumber; - DetailedBolusInfo detailedBolusInfo; - - public PumpDbEntry(long temporaryId, PumpType pumpType, String serialNumber, DetailedBolusInfo detailedBolusInfo) { - this.temporaryId = temporaryId; - this.pumpType = pumpType; - this.serialNumber = serialNumber; - this.detailedBolusInfo = detailedBolusInfo; - } - - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpDbEntry.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpDbEntry.kt new file mode 100644 index 0000000000..6dfe38133a --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpDbEntry.kt @@ -0,0 +1,9 @@ +package info.nightscout.androidaps.plugins.pump.common.data + +import info.nightscout.androidaps.data.DetailedBolusInfo +import info.nightscout.androidaps.plugins.pump.common.defs.PumpType + +data class PumpDbEntry(var temporaryId: Long, + var pumpType: PumpType, + var serialNumber: String, + var detailedBolusInfo: DetailedBolusInfo) \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java deleted file mode 100644 index c86e7c95a3..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java +++ /dev/null @@ -1,1627 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic; - -import android.content.ComponentName; -import android.content.Context; -import android.content.ServiceConnection; -import android.os.IBinder; -import android.os.SystemClock; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.preference.Preference; - -import org.joda.time.LocalDateTime; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; - -import javax.inject.Inject; -import javax.inject.Singleton; - -import dagger.android.HasAndroidInjector; -import info.nightscout.androidaps.activities.ErrorHelperActivity; -import info.nightscout.androidaps.data.DetailedBolusInfo; -import info.nightscout.androidaps.data.Profile; -import info.nightscout.androidaps.data.PumpEnactResult; -import info.nightscout.androidaps.db.Source; -import info.nightscout.androidaps.db.TemporaryBasal; -import info.nightscout.androidaps.events.EventRefreshOverview; -import info.nightscout.androidaps.interfaces.ActivePlugin; -import info.nightscout.androidaps.interfaces.CommandQueueProvider; -import info.nightscout.androidaps.interfaces.PluginDescription; -import info.nightscout.androidaps.interfaces.PluginType; -import info.nightscout.androidaps.interfaces.Pump; -import info.nightscout.androidaps.interfaces.PumpDescription; -import info.nightscout.androidaps.interfaces.PumpSync; -import info.nightscout.androidaps.logging.AAPSLogger; -import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.plugins.bus.RxBusWrapper; -import info.nightscout.androidaps.plugins.common.ManufacturerType; -import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction; -import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType; -import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification; -import info.nightscout.androidaps.plugins.general.overview.notifications.Notification; -import info.nightscout.androidaps.plugins.pump.common.PumpPluginAbstract; -import info.nightscout.androidaps.plugins.pump.common.data.PumpStatus; -import info.nightscout.androidaps.plugins.pump.common.defs.PumpDriverState; -import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; -import info.nightscout.androidaps.plugins.pump.common.events.EventRefreshButtonState; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkConst; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkPumpDevice; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkPumpInfo; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkServiceState; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkServiceData; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.tasks.ResetRileyLinkConfigurationTask; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.tasks.ServiceTaskExecutor; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.tasks.WakeAndTuneTask; -import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntry; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryResult; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.ui.MedtronicUITask; -import info.nightscout.androidaps.plugins.pump.medtronic.data.MedtronicHistoryData; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BasalProfile; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BasalProfileEntry; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.ClockDTO; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.TempBasalPair; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.BasalProfileStatus; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicCommandType; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicCustomActionType; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicNotificationType; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicStatusRefreshType; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicUIResponseType; -import info.nightscout.androidaps.plugins.pump.medtronic.driver.MedtronicPumpStatus; -import info.nightscout.androidaps.plugins.pump.medtronic.events.EventMedtronicPumpConfigurationChanged; -import info.nightscout.androidaps.plugins.pump.medtronic.events.EventMedtronicPumpValuesChanged; -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 info.nightscout.androidaps.utils.DateUtil; -import info.nightscout.androidaps.utils.FabricPrivacy; -import info.nightscout.androidaps.utils.TimeChangeType; -import info.nightscout.androidaps.utils.resources.ResourceHelper; -import info.nightscout.androidaps.utils.rx.AapsSchedulers; -import info.nightscout.androidaps.utils.sharedPreferences.SP; - - -/** - * Created by andy on 23.04.18. - * - * @author Andy Rozman (andy.rozman@gmail.com) - */ -@Singleton -public class MedtronicPumpPlugin extends PumpPluginAbstract implements Pump, RileyLinkPumpDevice { - - private final MedtronicUtil medtronicUtil; - private final MedtronicPumpStatus medtronicPumpStatus; - private final MedtronicHistoryData medtronicHistoryData; - private final RileyLinkServiceData rileyLinkServiceData; - private final ServiceTaskExecutor serviceTaskExecutor; - - private RileyLinkMedtronicService rileyLinkMedtronicService; - - // variables for handling statuses and history - private boolean firstRun = true; - private boolean isRefresh = false; - private final Map statusRefreshMap = new HashMap<>(); - private boolean isInitialized = false; - private PumpHistoryEntry lastPumpHistoryEntry; - - public static boolean isBusy = false; - private final List busyTimestamps = new ArrayList<>(); - private boolean hasTimeDateOrTimeZoneChanged = false; - private boolean usePumpSync = false; - - @Inject - public MedtronicPumpPlugin( - HasAndroidInjector injector, - AAPSLogger aapsLogger, - RxBusWrapper rxBus, - Context context, - ResourceHelper resourceHelper, - ActivePlugin activePlugin, - SP sp, - CommandQueueProvider commandQueue, - FabricPrivacy fabricPrivacy, - MedtronicUtil medtronicUtil, - MedtronicPumpStatus medtronicPumpStatus, - MedtronicHistoryData medtronicHistoryData, - RileyLinkServiceData rileyLinkServiceData, - ServiceTaskExecutor serviceTaskExecutor, - DateUtil dateUtil, - AapsSchedulers aapsSchedulers, - PumpSync pumpSync - ) { - - super(new PluginDescription() // - .mainType(PluginType.PUMP) // - .fragmentClass(MedtronicFragment.class.getName()) // - .pluginIcon(R.drawable.ic_veo_128) - .pluginName(R.string.medtronic_name) // - .shortName(R.string.medtronic_name_short) // - .preferencesId(R.xml.pref_medtronic) - .description(R.string.description_pump_medtronic), // - PumpType.MEDTRONIC_522_722, // we default to most basic model, correct model from config is loaded later - injector, resourceHelper, aapsLogger, commandQueue, rxBus, activePlugin, sp, context, fabricPrivacy, dateUtil, aapsSchedulers, pumpSync - ); - - this.medtronicUtil = medtronicUtil; - this.medtronicPumpStatus = medtronicPumpStatus; - this.medtronicHistoryData = medtronicHistoryData; - this.rileyLinkServiceData = rileyLinkServiceData; - this.serviceTaskExecutor = serviceTaskExecutor; - - displayConnectionMessages = false; - } - - - @Override - protected void onStart() { - aapsLogger.debug(LTag.PUMP, this.deviceID() + " started."); - - serviceConnection = new ServiceConnection() { - - public void onServiceDisconnected(ComponentName name) { - aapsLogger.debug(LTag.PUMP, "RileyLinkMedtronicService is disconnected"); - rileyLinkMedtronicService = null; - } - - public void onServiceConnected(ComponentName name, IBinder service) { - aapsLogger.debug(LTag.PUMP, "RileyLinkMedtronicService is connected"); - RileyLinkMedtronicService.LocalBinder mLocalBinder = (RileyLinkMedtronicService.LocalBinder) service; - rileyLinkMedtronicService = mLocalBinder.getServiceInstance(); - rileyLinkMedtronicService.verifyConfiguration(); - - new Thread(() -> { - - for (int i = 0; i < 20; i++) { - SystemClock.sleep(5000); - - aapsLogger.debug(LTag.PUMP, "Starting Medtronic-RileyLink service"); - if (rileyLinkMedtronicService.setNotInPreInit()) { - break; - } - } - }).start(); - } - }; - - super.onStart(); - } - - @Override - public void updatePreferenceSummary(@NonNull Preference pref) { - super.updatePreferenceSummary(pref); - - if (pref.getKey().equals(getResourceHelper().gs(R.string.key_rileylink_mac_address))) { - String value = sp.getStringOrNull(R.string.key_rileylink_mac_address, null); - pref.setSummary(value == null ? getResourceHelper().gs(R.string.not_set_short) : value); - } - } - - private String getLogPrefix() { - return "MedtronicPumpPlugin::"; - } - -// public PumpDescription getPumpDescription() { -// return super.pumpDescription; -// } - - - @Override - public void initPumpStatusData() { - - medtronicPumpStatus.setLastConnection(sp.getLong(RileyLinkConst.Prefs.LastGoodDeviceCommunicationTime, 0L)); - medtronicPumpStatus.setLastDataTime(medtronicPumpStatus.getLastConnection()); - medtronicPumpStatus.setPreviousConnection( medtronicPumpStatus.getLastConnection()); - - //if (rileyLinkMedtronicService != null) rileyLinkMedtronicService.verifyConfiguration(); - - aapsLogger.debug(LTag.PUMP, "initPumpStatusData: " + this.medtronicPumpStatus); - - // this is only thing that can change, by being configured - pumpDescription.setMaxTempAbsolute((medtronicPumpStatus.getMaxBasal() != null) ? medtronicPumpStatus.getMaxBasal() : 35.0d); - - // set first Medtronic Pump Start - if (!sp.contains(MedtronicConst.Statistics.FirstPumpStart)) { - sp.putLong(MedtronicConst.Statistics.FirstPumpStart, System.currentTimeMillis()); - } - - migrateSettings(); - - } - - @Override - public void triggerPumpConfigurationChangedEvent() { - rxBus.send(new EventMedtronicPumpConfigurationChanged()); - } - - private void migrateSettings() { - - if ("US (916 MHz)".equals(sp.getString(MedtronicConst.Prefs.PumpFrequency, "US (916 MHz)"))) { - sp.putString(MedtronicConst.Prefs.PumpFrequency, getResourceHelper().gs(R.string.key_medtronic_pump_frequency_us_ca)); - } - - String encoding = sp.getString(MedtronicConst.Prefs.Encoding, "RileyLink 4b6b Encoding"); - - if ("RileyLink 4b6b Encoding".equals(encoding)) { - sp.putString(MedtronicConst.Prefs.Encoding, getResourceHelper().gs(R.string.key_medtronic_pump_encoding_4b6b_rileylink)); - } - - if ("Local 4b6b Encoding".equals(encoding)) { - sp.putString(MedtronicConst.Prefs.Encoding, getResourceHelper().gs(R.string.key_medtronic_pump_encoding_4b6b_local)); - } - } - - - public void onStartCustomActions() { - - // check status every minute (if any status needs refresh we send readStatus command) - new Thread(() -> { - - do { - SystemClock.sleep(60000); - - if (this.isInitialized) { - - Map statusRefresh = workWithStatusRefresh( - StatusRefreshAction.GetData, null, null); - - if (doWeHaveAnyStatusNeededRefereshing(statusRefresh)) { - if (!getCommandQueue().statusInQueue()) { - getCommandQueue().readStatus("Scheduled Status Refresh", null); - } - } - - clearBusyQueue(); - } - - } while (serviceRunning); - - }).start(); - } - - - public Class getServiceClass() { - return RileyLinkMedtronicService.class; - } - - @Override public PumpStatus getPumpStatusData() { - return medtronicPumpStatus; - } - - @Override - public String deviceID() { - return "Medtronic"; - } - - - @Override - public boolean isFakingTempsByExtendedBoluses() { - return false; - } - - - @Override - public boolean canHandleDST() { - return false; - } - - - // Pump Plugin - - private boolean isServiceSet() { - return rileyLinkMedtronicService != null; - } - - @Nullable - public RileyLinkMedtronicService getRileyLinkService() { - return rileyLinkMedtronicService; - } - - @Override - public RileyLinkPumpInfo getPumpInfo() { - String frequency = resourceHelper.gs(medtronicPumpStatus.getPumpFrequency().equals("medtronic_pump_frequency_us_ca") ? R.string.medtronic_pump_frequency_us_ca : R.string.medtronic_pump_frequency_worldwide); - String model = medtronicPumpStatus.getMedtronicDeviceType() == null ? "???" : "Medtronic " + medtronicPumpStatus.getMedtronicDeviceType().getPumpModel(); - String serialNumber = medtronicPumpStatus.getSerialNumber(); - return new RileyLinkPumpInfo(frequency, model, serialNumber); - } - - @Override public long getLastConnectionTimeMillis() { - return medtronicPumpStatus.getLastConnection(); - } - - @Override public void setLastCommunicationToNow() { - medtronicPumpStatus.setLastCommunicationToNow(); - } - - @Override - public boolean isInitialized() { - if (displayConnectionMessages) - aapsLogger.debug(LTag.PUMP, "MedtronicPumpPlugin::isInitialized"); - return isServiceSet() && isInitialized; - } - - - @Override - public void setBusy(boolean busy) { - isBusy = busy; - } - - @Override - public boolean isBusy() { - if (displayConnectionMessages) - aapsLogger.debug(LTag.PUMP, "MedtronicPumpPlugin::isBusy"); - - if (isServiceSet()) { - - if (isBusy) - return true; - - if (busyTimestamps.size() > 0) { - - clearBusyQueue(); - - return busyTimestamps.size() > 0; - } - } - - return false; - } - - - private synchronized void clearBusyQueue() { - - if (busyTimestamps.size() == 0) { - return; - } - - Set deleteFromQueue = new HashSet<>(); - - for (Long busyTimestamp : busyTimestamps) { - - if (System.currentTimeMillis() > busyTimestamp) { - deleteFromQueue.add(busyTimestamp); - } - } - - if (deleteFromQueue.size() == busyTimestamps.size()) { - busyTimestamps.clear(); - setEnableCustomAction(MedtronicCustomActionType.ClearBolusBlock, false); - } - - if (deleteFromQueue.size() > 0) { - busyTimestamps.removeAll(deleteFromQueue); - } - - } - - - @Override - public boolean isConnected() { - if (displayConnectionMessages) - aapsLogger.debug(LTag.PUMP, "MedtronicPumpPlugin::isConnected"); - return isServiceSet() && rileyLinkMedtronicService.isInitialized(); - } - - - @Override - public boolean isConnecting() { - if (displayConnectionMessages) - aapsLogger.debug(LTag.PUMP, "MedtronicPumpPlugin::isConnecting"); - return !isServiceSet() || !rileyLinkMedtronicService.isInitialized(); - } - - - @Override - public void getPumpStatus(String reason) { - boolean needRefresh = true; - - if (firstRun) { - needRefresh = initializePump(!isRefresh); - } else { - refreshAnyStatusThatNeedsToBeRefreshed(); - } - - if (needRefresh) - rxBus.send(new EventMedtronicPumpValuesChanged()); - } - - - void resetStatusState() { - firstRun = true; - isRefresh = true; - } - - - private boolean isPumpNotReachable() { - - RileyLinkServiceState rileyLinkServiceState = rileyLinkServiceData.rileyLinkServiceState; - - if (rileyLinkServiceState == null) { - aapsLogger.debug(LTag.PUMP, "RileyLink unreachable. RileyLinkServiceState is null."); - return false; - } - - if (rileyLinkServiceState != RileyLinkServiceState.PumpConnectorReady // - && rileyLinkServiceState != RileyLinkServiceState.RileyLinkReady // - && rileyLinkServiceState != RileyLinkServiceState.TuneUpDevice) { - aapsLogger.debug(LTag.PUMP, "RileyLink unreachable."); - return false; - } - - return (!rileyLinkMedtronicService.getDeviceCommunicationManager().isDeviceReachable()); - } - - - private void refreshAnyStatusThatNeedsToBeRefreshed() { - - Map statusRefresh = workWithStatusRefresh(StatusRefreshAction.GetData, null, - null); - - if (!doWeHaveAnyStatusNeededRefereshing(statusRefresh)) { - return; - } - - boolean resetTime = false; - - if (isPumpNotReachable()) { - aapsLogger.error("Pump unreachable."); - medtronicUtil.sendNotification(MedtronicNotificationType.PumpUnreachable, getResourceHelper(), rxBus); - - return; - } - - medtronicUtil.dismissNotification(MedtronicNotificationType.PumpUnreachable, rxBus); - - - if (hasTimeDateOrTimeZoneChanged) { - - checkTimeAndOptionallySetTime(); - - // read time if changed, set new time - hasTimeDateOrTimeZoneChanged = false; - } - - - // execute - Set refreshTypesNeededToReschedule = new HashSet<>(); - - for (Map.Entry refreshType : statusRefresh.entrySet()) { - - if (refreshType.getValue() > 0 && System.currentTimeMillis() > refreshType.getValue()) { - - switch (refreshType.getKey()) { - case PumpHistory: { - readPumpHistory(); - } - break; - - case PumpTime: { - checkTimeAndOptionallySetTime(); - refreshTypesNeededToReschedule.add(refreshType.getKey()); - resetTime = true; - } - break; - - case BatteryStatus: - case RemainingInsulin: { - rileyLinkMedtronicService.getMedtronicUIComm().executeCommand(refreshType.getKey().getCommandType(medtronicUtil.getMedtronicPumpModel())); - refreshTypesNeededToReschedule.add(refreshType.getKey()); - resetTime = true; - } - break; - - case Configuration: { - rileyLinkMedtronicService.getMedtronicUIComm().executeCommand(refreshType.getKey().getCommandType(medtronicUtil.getMedtronicPumpModel())); - resetTime = true; - } - break; - } - } - - // reschedule - for (MedtronicStatusRefreshType refreshType2 : refreshTypesNeededToReschedule) { - scheduleNextRefresh(refreshType2); - } - - } - - if (resetTime) - medtronicPumpStatus.setLastCommunicationToNow(); - - } - - - private boolean doWeHaveAnyStatusNeededRefereshing(Map statusRefresh) { - - for (Map.Entry refreshType : statusRefresh.entrySet()) { - - if (refreshType.getValue() > 0 && System.currentTimeMillis() > refreshType.getValue()) { - return true; - } - } - - return hasTimeDateOrTimeZoneChanged; - } - - - private void setRefreshButtonEnabled(boolean enabled) { - rxBus.send(new EventRefreshButtonState(enabled)); - } - - - private boolean initializePump(boolean realInit) { - - if (rileyLinkMedtronicService == null) - return false; - - aapsLogger.info(LTag.PUMP, getLogPrefix() + "initializePump - start"); - - rileyLinkMedtronicService.getDeviceCommunicationManager().setDoWakeUpBeforeCommand(false); - - setRefreshButtonEnabled(false); - - if (isRefresh) { - if (isPumpNotReachable()) { - aapsLogger.error(getLogPrefix() + "initializePump::Pump unreachable."); - medtronicUtil.sendNotification(MedtronicNotificationType.PumpUnreachable, getResourceHelper(), rxBus); - - setRefreshButtonEnabled(true); - - return true; - } - - medtronicUtil.dismissNotification(MedtronicNotificationType.PumpUnreachable, rxBus); - } - - // model (once) - if (medtronicUtil.getMedtronicPumpModel() == null) { - rileyLinkMedtronicService.getMedtronicUIComm().executeCommand(MedtronicCommandType.PumpModel); - } else { - if (medtronicPumpStatus.getMedtronicDeviceType() != medtronicUtil.getMedtronicPumpModel()) { - aapsLogger.warn(LTag.PUMP, getLogPrefix() + "Configured pump is not the same as one detected."); - medtronicUtil.sendNotification(MedtronicNotificationType.PumpTypeNotSame, getResourceHelper(), rxBus); - } - } - - this.pumpState = PumpDriverState.Connected; - - // time (1h) - checkTimeAndOptionallySetTime(); - - readPumpHistory(); - - // remaining insulin (>50 = 4h; 50-20 = 1h; 15m) - rileyLinkMedtronicService.getMedtronicUIComm().executeCommand(MedtronicCommandType.GetRemainingInsulin); - scheduleNextRefresh(MedtronicStatusRefreshType.RemainingInsulin, 10); - - // remaining power (1h) - rileyLinkMedtronicService.getMedtronicUIComm().executeCommand(MedtronicCommandType.GetBatteryStatus); - scheduleNextRefresh(MedtronicStatusRefreshType.BatteryStatus, 20); - - // configuration (once and then if history shows config changes) - rileyLinkMedtronicService.getMedtronicUIComm().executeCommand(MedtronicCommandType.getSettings(medtronicUtil.getMedtronicPumpModel())); - - // read profile (once, later its controlled by isThisProfileSet method) - getBasalProfiles(); - - int errorCount = rileyLinkMedtronicService.getMedtronicUIComm().getInvalidResponsesCount(); - - if (errorCount >= 5) { - aapsLogger.error("Number of error counts was 5 or more. Starting tunning."); - setRefreshButtonEnabled(true); - serviceTaskExecutor.startTask(new WakeAndTuneTask(getInjector())); - return true; - } - - medtronicPumpStatus.setLastCommunicationToNow(); - setRefreshButtonEnabled(true); - - if (!isRefresh) { - pumpState = PumpDriverState.Initialized; - } - - isInitialized = true; - // this.pumpState = PumpDriverState.Initialized; - - this.firstRun = false; - - return true; - } - - private void getBasalProfiles() { - - MedtronicUITask medtronicUITask = rileyLinkMedtronicService.getMedtronicUIComm().executeCommand(MedtronicCommandType.GetBasalProfileSTD); - - if (medtronicUITask.getResponseType() == MedtronicUIResponseType.Error) { - rileyLinkMedtronicService.getMedtronicUIComm().executeCommand(MedtronicCommandType.GetBasalProfileSTD); - } - } - - - @Override - public boolean isThisProfileSet(@NonNull Profile profile) { - aapsLogger.debug(LTag.PUMP, "isThisProfileSet: basalInitalized=" + medtronicPumpStatus.getBasalProfileStatus()); - - if (!isInitialized) - return true; - - if (medtronicPumpStatus.getBasalProfileStatus() == BasalProfileStatus.NotInitialized) { - // this shouldn't happen, but if there was problem we try again - getBasalProfiles(); - return isProfileSame(profile); - } else if (medtronicPumpStatus.getBasalProfileStatus() == BasalProfileStatus.ProfileChanged) { - return false; - } - - return (medtronicPumpStatus.getBasalProfileStatus() != BasalProfileStatus.ProfileOK) || isProfileSame(profile); - } - - - private boolean isProfileSame(Profile profile) { - - boolean invalid = false; - Double[] basalsByHour = medtronicPumpStatus.getBasalsByHour(); - - aapsLogger.debug(LTag.PUMP, "Current Basals (h): " - + (basalsByHour == null ? "null" : BasalProfile.getProfilesByHourToString(basalsByHour))); - - // int index = 0; - - if (basalsByHour == null) - return true; // we don't want to set profile again, unless we are sure - - StringBuilder stringBuilder = new StringBuilder("Requested Basals (h): "); - - for (Profile.ProfileValue basalValue : profile.getBasalValues()) { - - double basalValueValue = pumpDescription.getPumpType().determineCorrectBasalSize(basalValue.value); - - int hour = basalValue.timeAsSeconds / (60 * 60); - - if (!MedtronicUtil.isSame(basalsByHour[hour], basalValueValue)) { - invalid = true; - } - - stringBuilder.append(String.format(Locale.ENGLISH, "%.3f", basalValueValue)); - stringBuilder.append(" "); - } - - aapsLogger.debug(LTag.PUMP, stringBuilder.toString()); - - if (!invalid) { - aapsLogger.debug(LTag.PUMP, "Basal profile is same as AAPS one."); - } else { - aapsLogger.debug(LTag.PUMP, "Basal profile on Pump is different than the AAPS one."); - } - - return (!invalid); - } - - - @Override - public long lastDataTime() { - - if (medtronicPumpStatus.getLastConnection() != 0) { - return medtronicPumpStatus.getLastConnection(); - } - - return System.currentTimeMillis(); - } - - - @Override - public double getBaseBasalRate() { - return medtronicPumpStatus.getBasalProfileForHour(); - } - - - @Override - public double getReservoirLevel() { - return medtronicPumpStatus.getReservoirRemainingUnits(); - } - - - @Override - public int getBatteryLevel() { - return medtronicPumpStatus.getBatteryRemaining(); - } - - protected void triggerUIChange() { - rxBus.send(new EventMedtronicPumpValuesChanged()); - } - - @Override public long generateTempId(long timeMillis) { - return 0; - } - -// @Override public String getSerial() { -// return null; -// } - - private BolusDeliveryType bolusDeliveryType = BolusDeliveryType.Idle; - - private enum BolusDeliveryType { - Idle, // - DeliveryPrepared, // - Delivering, // - CancelDelivery - } - - - private void checkTimeAndOptionallySetTime() { - - aapsLogger.info(LTag.PUMP, "MedtronicPumpPlugin::checkTimeAndOptionallySetTime - Start"); - - setRefreshButtonEnabled(false); - - if (isPumpNotReachable()) { - aapsLogger.debug(LTag.PUMP, "MedtronicPumpPlugin::checkTimeAndOptionallySetTime - Pump Unreachable."); - setRefreshButtonEnabled(true); - return; - } - - medtronicUtil.dismissNotification(MedtronicNotificationType.PumpUnreachable, rxBus); - - rileyLinkMedtronicService.getMedtronicUIComm().executeCommand(MedtronicCommandType.GetRealTimeClock); - - ClockDTO clock = medtronicUtil.getPumpTime(); - - if (clock == null) { // retry - rileyLinkMedtronicService.getMedtronicUIComm().executeCommand(MedtronicCommandType.GetRealTimeClock); - - clock = medtronicUtil.getPumpTime(); - } - - if (clock == null) - return; - - int timeDiff = Math.abs(clock.getTimeDifference()); - - if (timeDiff > 20) { - - if ((clock.getLocalDeviceTime().getYear() <= 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.getMedtronicUIComm().executeCommand(MedtronicCommandType.SetRealTimeClock); - - if (clock.getTimeDifference() == 0) { - Notification notification = new Notification(Notification.INSIGHT_DATE_TIME_UPDATED, getResourceHelper().gs(R.string.pump_time_updated), Notification.INFO, 60); - rxBus.send(new EventNewNotification(notification)); - } - } else { - if ((clock.getLocalDeviceTime().getYear() > 2015)) { - aapsLogger.error(String.format(Locale.ENGLISH, "MedtronicPumpPlugin::checkTimeAndOptionallySetTime - Time difference over 24h requested [diff=%d s]. Doing nothing.", timeDiff)); - medtronicUtil.sendNotification(MedtronicNotificationType.TimeChangeOver24h, getResourceHelper(), rxBus); - } - } - - } else { - aapsLogger.info(LTag.PUMP, String.format(Locale.ENGLISH, "MedtronicPumpPlugin::checkTimeAndOptionallySetTime - Time difference is %d s. Do nothing.", timeDiff)); - } - - scheduleNextRefresh(MedtronicStatusRefreshType.PumpTime, 0); - } - - - @NonNull - protected PumpEnactResult deliverBolus(final DetailedBolusInfo detailedBolusInfo) { - - aapsLogger.info(LTag.PUMP, "MedtronicPumpPlugin::deliverBolus - " + BolusDeliveryType.DeliveryPrepared); - - setRefreshButtonEnabled(false); - - if (detailedBolusInfo.insulin > medtronicPumpStatus.getReservoirRemainingUnits()) { - return new PumpEnactResult(getInjector()) // - .success(false) // - .enacted(false) // - .comment(getResourceHelper().gs(R.string.medtronic_cmd_bolus_could_not_be_delivered_no_insulin, - medtronicPumpStatus.getReservoirRemainingUnits(), - detailedBolusInfo.insulin)); - } - - bolusDeliveryType = BolusDeliveryType.DeliveryPrepared; - - if (isPumpNotReachable()) { - aapsLogger.debug(LTag.PUMP, "MedtronicPumpPlugin::deliverBolus - Pump Unreachable."); - return setNotReachable(true, false); - } - - medtronicUtil.dismissNotification(MedtronicNotificationType.PumpUnreachable, rxBus); - - if (bolusDeliveryType == BolusDeliveryType.CancelDelivery) { - // LOG.debug("MedtronicPumpPlugin::deliverBolus - Delivery Canceled."); - return setNotReachable(true, true); - } - - // LOG.debug("MedtronicPumpPlugin::deliverBolus - Starting wait period."); - - int sleepTime = sp.getInt(MedtronicConst.Prefs.BolusDelay, 10) * 1000; - - SystemClock.sleep(sleepTime); - - if (bolusDeliveryType == BolusDeliveryType.CancelDelivery) { - // LOG.debug("MedtronicPumpPlugin::deliverBolus - Delivery Canceled, before wait period."); - return setNotReachable(true, true); - } - - // LOG.debug("MedtronicPumpPlugin::deliverBolus - End wait period. Start delivery"); - - try { - - bolusDeliveryType = BolusDeliveryType.Delivering; - - // LOG.debug("MedtronicPumpPlugin::deliverBolus - Start delivery"); - - MedtronicUITask responseTask = rileyLinkMedtronicService.getMedtronicUIComm().executeCommand(MedtronicCommandType.SetBolus, - Arrays.asList(detailedBolusInfo.insulin)); - - Boolean response = (Boolean) responseTask.getResult(); - - setRefreshButtonEnabled(true); - - // LOG.debug("MedtronicPumpPlugin::deliverBolus - Response: {}", response); - - if (response) { - - if (bolusDeliveryType == BolusDeliveryType.CancelDelivery) { - // LOG.debug("MedtronicPumpPlugin::deliverBolus - Delivery Canceled after Bolus started."); - - new Thread(() -> { - // Looper.prepare(); - // LOG.debug("MedtronicPumpPlugin::deliverBolus - Show dialog - before"); - SystemClock.sleep(2000); - // LOG.debug("MedtronicPumpPlugin::deliverBolus - Show dialog. Context: " - // + MainApp.instance().getApplicationContext()); - - ErrorHelperActivity.Companion.runAlarm(context, getResourceHelper().gs(R.string.medtronic_cmd_cancel_bolus_not_supported), getResourceHelper().gs(R.string.medtronic_warning), R.raw.boluserror); - }).start(); - } - - long now = System.currentTimeMillis(); - - detailedBolusInfo.timestamp = now; - detailedBolusInfo.deliverAtTheLatest = now; // not sure about that one - - // TODO fix - if (usePumpSync) { - addBolusWithTempId(detailedBolusInfo, true); - } else { - activePlugin.getActiveTreatments().addToHistoryTreatment(detailedBolusInfo, true); - } - - // we subtract insulin, exact amount will be visible with next remainingInsulin update. - medtronicPumpStatus.setReservoirRemainingUnits(medtronicPumpStatus.getReservoirRemainingUnits() - detailedBolusInfo.insulin); - - incrementStatistics(detailedBolusInfo.getBolusType() == DetailedBolusInfo.BolusType.SMB ? MedtronicConst.Statistics.SMBBoluses - : MedtronicConst.Statistics.StandardBoluses); - - - // calculate time for bolus and set driver to busy for that time - int bolusTime = (int) (detailedBolusInfo.insulin * 42.0d); - long time = now + (bolusTime * 1000); - - this.busyTimestamps.add(time); - setEnableCustomAction(MedtronicCustomActionType.ClearBolusBlock, true); - - return new PumpEnactResult(getInjector()).success(true) // - .enacted(true) // - .bolusDelivered(detailedBolusInfo.insulin) // - .carbsDelivered(detailedBolusInfo.carbs); - - } else { - return new PumpEnactResult(getInjector()) // - .success(bolusDeliveryType == BolusDeliveryType.CancelDelivery) // - .enacted(false) // - .comment(R.string.medtronic_cmd_bolus_could_not_be_delivered); - } - - } finally { - finishAction("Bolus"); - this.bolusDeliveryType = BolusDeliveryType.Idle; - } - } - - - private PumpEnactResult setNotReachable(boolean isBolus, boolean success) { - setRefreshButtonEnabled(true); - - if (isBolus) { - bolusDeliveryType = BolusDeliveryType.Idle; - } - - if (success) { - return new PumpEnactResult(getInjector()) // - .success(true) // - .enacted(false); - } else { - return new PumpEnactResult(getInjector()) // - .success(false) // - .enacted(false) // - .comment(R.string.medtronic_pump_status_pump_unreachable); - } - } - - - public void stopBolusDelivering() { - - this.bolusDeliveryType = BolusDeliveryType.CancelDelivery; - - // if (isLoggingEnabled()) - // LOG.warn("MedtronicPumpPlugin::deliverBolus - Stop Bolus Delivery."); - } - - - private void incrementStatistics(String statsKey) { - long currentCount = sp.getLong(statsKey, 0L); - currentCount++; - sp.putLong(statsKey, currentCount); - } - - - // if enforceNew===true current temp basal is canceled and new TBR set (duration is prolonged), - // if false and the same rate is requested enacted=false and success=true is returned and TBR is not changed - @NonNull @Override - public PumpEnactResult setTempBasalAbsolute(double absoluteRate, int durationInMinutes, Profile profile, boolean enforceNew, @NonNull PumpSync.TemporaryBasalType tbrType) { - - setRefreshButtonEnabled(false); - - if (isPumpNotReachable()) { - - setRefreshButtonEnabled(true); - - return new PumpEnactResult(getInjector()) // - .success(false) // - .enacted(false) // - .comment(R.string.medtronic_pump_status_pump_unreachable); - } - - medtronicUtil.dismissNotification(MedtronicNotificationType.PumpUnreachable, rxBus); - - aapsLogger.info(LTag.PUMP, getLogPrefix() + "setTempBasalAbsolute: rate: " + absoluteRate + ", duration=" + durationInMinutes); - - // read current TBR - TempBasalPair tbrCurrent = readTBR(); - - if (tbrCurrent == null) { - aapsLogger.warn(LTag.PUMP, getLogPrefix() + "setTempBasalAbsolute - Could not read current TBR, canceling operation."); - finishAction("TBR"); - return new PumpEnactResult(getInjector()).success(false).enacted(false) - .comment(R.string.medtronic_cmd_cant_read_tbr); - } else { - aapsLogger.info(LTag.PUMP, getLogPrefix() + "setTempBasalAbsolute: Current Basal: duration: " + tbrCurrent.getDurationMinutes() + " min, rate=" + tbrCurrent.getInsulinRate()); - } - - if (!enforceNew) { - - if (MedtronicUtil.isSame(tbrCurrent.getInsulinRate(), absoluteRate)) { - - boolean sameRate = true; - if (MedtronicUtil.isSame(0.0d, absoluteRate) && durationInMinutes > 0) { - // if rate is 0.0 and duration>0 then the rate is not the same - sameRate = false; - } - - if (sameRate) { - aapsLogger.info(LTag.PUMP, getLogPrefix() + "setTempBasalAbsolute - No enforceNew and same rate. Exiting."); - finishAction("TBR"); - return new PumpEnactResult(getInjector()).success(true).enacted(false); - } - } - // if not the same rate, we cancel and start new - } - - // if TBR is running we will cancel it. - if (tbrCurrent.getInsulinRate() != 0.0f && tbrCurrent.getDurationMinutes() > 0) { - aapsLogger.info(LTag.PUMP, getLogPrefix() + "setTempBasalAbsolute - TBR running - so canceling it."); - - // CANCEL - - MedtronicUITask responseTask2 = rileyLinkMedtronicService.getMedtronicUIComm().executeCommand(MedtronicCommandType.CancelTBR); - - Boolean response = (Boolean) responseTask2.getResult(); - - if (response) { - aapsLogger.info(LTag.PUMP, getLogPrefix() + "setTempBasalAbsolute - Current TBR cancelled."); - } else { - aapsLogger.error(getLogPrefix() + "setTempBasalAbsolute - Cancel TBR failed."); - - finishAction("TBR"); - - return new PumpEnactResult(getInjector()).success(false).enacted(false) - .comment(R.string.medtronic_cmd_cant_cancel_tbr_stop_op); - } - } - - // now start new TBR - MedtronicUITask responseTask = rileyLinkMedtronicService.getMedtronicUIComm().executeCommand(MedtronicCommandType.SetTemporaryBasal, - Arrays.asList(absoluteRate, durationInMinutes)); - - Boolean response = (Boolean) responseTask.getResult(); - - aapsLogger.info(LTag.PUMP, getLogPrefix() + "setTempBasalAbsolute - setTBR. Response: " + response); - - if (response) { - // FIXME put this into UIPostProcessor - medtronicPumpStatus.setTempBasalStart(new Date()); - medtronicPumpStatus.setTempBasalAmount(absoluteRate); - medtronicPumpStatus.setTempBasalLength(durationInMinutes); - - TemporaryBasal tempStart = new TemporaryBasal(getInjector()) // - .date(System.currentTimeMillis()) // - .duration(durationInMinutes) // - .absolute(absoluteRate) // - .source(Source.USER); - - // TODO fix - if (usePumpSync) { - addTemporaryBasalRateWithTempId(tempStart, true); - } else { - activePlugin.getActiveTreatments().addToHistoryTempBasal(tempStart); - } - - - incrementStatistics(MedtronicConst.Statistics.TBRsSet); - - finishAction("TBR"); - - return new PumpEnactResult(getInjector()).success(true).enacted(true) // - .absolute(absoluteRate).duration(durationInMinutes); - - } else { - finishAction("TBR"); - - return new PumpEnactResult(getInjector()).success(false).enacted(false) // - .comment(R.string.medtronic_cmd_tbr_could_not_be_delivered); - } - - } - - - @NonNull @Override - public PumpEnactResult setTempBasalPercent(int percent, int durationInMinutes, @NonNull Profile profile, boolean enforceNew, @NonNull PumpSync.TemporaryBasalType tbrType) { - if (percent == 0) { - return setTempBasalAbsolute(0.0d, durationInMinutes, profile, enforceNew, tbrType); - } else { - double absoluteValue = profile.getBasal() * (percent / 100.0d); - absoluteValue = pumpDescription.getPumpType().determineCorrectBasalSize(absoluteValue); - aapsLogger.warn(LTag.PUMP, "setTempBasalPercent [MedtronicPumpPlugin] - You are trying to use setTempBasalPercent with percent other then 0% (" + percent + "). This will start setTempBasalAbsolute, with calculated value (" + absoluteValue + "). Result might not be 100% correct."); - return setTempBasalAbsolute(absoluteValue, durationInMinutes, profile, enforceNew, tbrType); - } - } - - - private void finishAction(String overviewKey) { - - if (overviewKey != null) - rxBus.send(new EventRefreshOverview(overviewKey, false)); - - triggerUIChange(); - - setRefreshButtonEnabled(true); - } - - - private void readPumpHistory() { - -// if (isLoggingEnabled()) -// LOG.error(getLogPrefix() + "readPumpHistory WIP."); - - readPumpHistoryLogic(); - - scheduleNextRefresh(MedtronicStatusRefreshType.PumpHistory); - - if (medtronicHistoryData.hasRelevantConfigurationChanged()) { - scheduleNextRefresh(MedtronicStatusRefreshType.Configuration, -1); - } - - if (medtronicHistoryData.hasPumpTimeChanged()) { - scheduleNextRefresh(MedtronicStatusRefreshType.PumpTime, -1); - } - - if (this.medtronicPumpStatus.getBasalProfileStatus() != BasalProfileStatus.NotInitialized - && medtronicHistoryData.hasBasalProfileChanged()) { - medtronicHistoryData.processLastBasalProfileChange(pumpDescription.getPumpType(), medtronicPumpStatus); - } - - PumpDriverState previousState = this.pumpState; - - if (medtronicHistoryData.isPumpSuspended()) { - this.pumpState = PumpDriverState.Suspended; - aapsLogger.debug(LTag.PUMP, getLogPrefix() + "isPumpSuspended: true"); - } else { - if (previousState == PumpDriverState.Suspended) { - this.pumpState = PumpDriverState.Ready; - } - aapsLogger.debug(LTag.PUMP, getLogPrefix() + "isPumpSuspended: false"); - } - - medtronicHistoryData.processNewHistoryData(); - - this.medtronicHistoryData.finalizeNewHistoryRecords(); - // this.medtronicHistoryData.setLastHistoryRecordTime(this.lastPumpHistoryEntry.atechDateTime); - - } - - - private void readPumpHistoryLogic() { - - boolean debugHistory = false; - - LocalDateTime targetDate = null; - - if (lastPumpHistoryEntry == null) { - - if (debugHistory) - aapsLogger.debug(LTag.PUMP, getLogPrefix() + "readPumpHistoryLogic(): lastPumpHistoryEntry: null"); - - Long lastPumpHistoryEntryTime = getLastPumpEntryTime(); - - LocalDateTime timeMinus36h = new LocalDateTime(); - timeMinus36h = timeMinus36h.minusHours(36); - medtronicHistoryData.setIsInInit(true); - - if (lastPumpHistoryEntryTime == 0L) { - if (debugHistory) - aapsLogger.debug(LTag.PUMP, getLogPrefix() + "readPumpHistoryLogic(): lastPumpHistoryEntryTime: 0L - targetDate: " - + targetDate); - targetDate = timeMinus36h; - } else { - // LocalDateTime lastHistoryRecordTime = DateTimeUtil.toLocalDateTime(lastPumpHistoryEntryTime); - - if (debugHistory) - aapsLogger.debug(LTag.PUMP, getLogPrefix() + "readPumpHistoryLogic(): lastPumpHistoryEntryTime: " + lastPumpHistoryEntryTime + " - targetDate: " + targetDate); - - medtronicHistoryData.setLastHistoryRecordTime(lastPumpHistoryEntryTime); - - LocalDateTime lastHistoryRecordTime = DateTimeUtil.toLocalDateTime(lastPumpHistoryEntryTime); - - lastHistoryRecordTime = lastHistoryRecordTime.minusHours(12); // we get last 12 hours of history to - // determine pump state - // (we don't process that data), we process only - - if (timeMinus36h.isAfter(lastHistoryRecordTime)) { - targetDate = timeMinus36h; - } - - targetDate = (timeMinus36h.isAfter(lastHistoryRecordTime) ? timeMinus36h : lastHistoryRecordTime); - - if (debugHistory) - aapsLogger.debug(LTag.PUMP, getLogPrefix() + "readPumpHistoryLogic(): targetDate: " + targetDate); - } - } else { - if (debugHistory) - aapsLogger.debug(LTag.PUMP, getLogPrefix() + "readPumpHistoryLogic(): lastPumpHistoryEntry: not null - " + medtronicUtil.getGsonInstance().toJson(lastPumpHistoryEntry)); - medtronicHistoryData.setIsInInit(false); - // medtronicHistoryData.setLastHistoryRecordTime(lastPumpHistoryEntry.atechDateTime); - - // targetDate = lastPumpHistoryEntry.atechDateTime; - } - - //aapsLogger.debug(LTag.PUMP, "HST: Target Date: " + targetDate); - - MedtronicUITask responseTask2 = rileyLinkMedtronicService.getMedtronicUIComm().executeCommand(MedtronicCommandType.GetHistoryData, - Arrays.asList(lastPumpHistoryEntry, targetDate)); - - if (debugHistory) - aapsLogger.debug(LTag.PUMP, "HST: After task"); - - PumpHistoryResult historyResult = (PumpHistoryResult) responseTask2.getResult(); - - if (debugHistory) - aapsLogger.debug(LTag.PUMP, "HST: History Result: " + historyResult.toString()); - - PumpHistoryEntry latestEntry = historyResult.getLatestEntry(); - - if (debugHistory) - aapsLogger.debug(LTag.PUMP, getLogPrefix() + "Last entry: " + latestEntry); - - if (latestEntry == null) // no new history to read - return; - - this.lastPumpHistoryEntry = latestEntry; - sp.putLong(MedtronicConst.Statistics.LastPumpHistoryEntry, latestEntry.getAtechDateTime()); - - if (debugHistory) - aapsLogger.debug(LTag.PUMP, "HST: History: valid=" + historyResult.getValidEntries().size() + ", unprocessed=" + historyResult.getUnprocessedEntries().size()); - - this.medtronicHistoryData.addNewHistory(historyResult); - this.medtronicHistoryData.filterNewEntries(); - - // determine if first run, if yes detrmine how much of update do we need - // first run: - // get last hiostory entry, if not there download 1.5 days of data - // - there: check if last entry is older than 1.5 days - // - yes: download 1.5 days - // - no: download with last entry - // - not there: download 1.5 days - // - // upload all new entries to NightScout (TBR, Bolus) - // determine pump status - // - // save last entry - // - // not first run: - // update to last entry - // - save - // - determine pump status - } - - - private Long getLastPumpEntryTime() { - Long lastPumpEntryTime = sp.getLong(MedtronicConst.Statistics.LastPumpHistoryEntry, 0L); - - try { - LocalDateTime localDateTime = DateTimeUtil.toLocalDateTime(lastPumpEntryTime); - - if (localDateTime.getYear() != (new GregorianCalendar().get(Calendar.YEAR))) { - aapsLogger.warn(LTag.PUMP, "Saved LastPumpHistoryEntry was invalid. Year was not the same."); - return 0L; - } - - return lastPumpEntryTime; - - } catch (Exception ex) { - aapsLogger.warn(LTag.PUMP, "Saved LastPumpHistoryEntry was invalid."); - return 0L; - } - - } - - - private void scheduleNextRefresh(MedtronicStatusRefreshType refreshType) { - scheduleNextRefresh(refreshType, 0); - } - - - private void scheduleNextRefresh(MedtronicStatusRefreshType refreshType, int additionalTimeInMinutes) { - switch (refreshType) { - - case RemainingInsulin: { - double remaining = medtronicPumpStatus.getReservoirRemainingUnits(); - int min; - if (remaining > 50) - min = 4 * 60; - else if (remaining > 20) - min = 60; - else - min = 15; - - workWithStatusRefresh(StatusRefreshAction.Add, refreshType, getTimeInFutureFromMinutes(min)); - } - break; - - case PumpTime: - case Configuration: - case BatteryStatus: - case PumpHistory: { - workWithStatusRefresh(StatusRefreshAction.Add, refreshType, - getTimeInFutureFromMinutes(refreshType.getRefreshTime() + additionalTimeInMinutes)); - } - break; - } - } - - private enum StatusRefreshAction { - Add, // - GetData - } - - - private synchronized Map workWithStatusRefresh(StatusRefreshAction action, // - MedtronicStatusRefreshType statusRefreshType, // - Long time) { - - switch (action) { - - case Add: { - statusRefreshMap.put(statusRefreshType, time); - return null; - } - - case GetData: { - return new HashMap<>(statusRefreshMap); - } - - default: - return null; - - } - - } - - - private long getTimeInFutureFromMinutes(int minutes) { - return System.currentTimeMillis() + getTimeInMs(minutes); - } - - - private long getTimeInMs(int minutes) { - return minutes * 60 * 1000L; - } - - - private TempBasalPair readTBR() { - MedtronicUITask responseTask = rileyLinkMedtronicService.getMedtronicUIComm().executeCommand(MedtronicCommandType.ReadTemporaryBasal); - - if (responseTask.hasData()) { - TempBasalPair tbr = (TempBasalPair) responseTask.getResult(); - - // we sometimes get rate returned even if TBR is no longer running - if (tbr.getDurationMinutes() == 0) { - tbr.setInsulinRate(0.0d); - } - - return tbr; - } else { - return null; - } - } - - - @NonNull @Override - public PumpEnactResult cancelTempBasal(boolean enforceNew) { - - aapsLogger.info(LTag.PUMP, getLogPrefix() + "cancelTempBasal - started"); - - if (isPumpNotReachable()) { - - setRefreshButtonEnabled(true); - - return new PumpEnactResult(getInjector()) // - .success(false) // - .enacted(false) // - .comment(R.string.medtronic_pump_status_pump_unreachable); - } - - medtronicUtil.dismissNotification(MedtronicNotificationType.PumpUnreachable, rxBus); - setRefreshButtonEnabled(false); - - TempBasalPair tbrCurrent = readTBR(); - - if (tbrCurrent != null) { - if (tbrCurrent.getInsulinRate() == 0.0f && tbrCurrent.getDurationMinutes() == 0) { - aapsLogger.info(LTag.PUMP, getLogPrefix() + "cancelTempBasal - TBR already canceled."); - finishAction("TBR"); - return new PumpEnactResult(getInjector()).success(true).enacted(false); - } - } else { - aapsLogger.warn(LTag.PUMP, getLogPrefix() + "cancelTempBasal - Could not read currect TBR, canceling operation."); - finishAction("TBR"); - return new PumpEnactResult(getInjector()).success(false).enacted(false) - .comment(R.string.medtronic_cmd_cant_read_tbr); - } - - MedtronicUITask responseTask2 = rileyLinkMedtronicService.getMedtronicUIComm().executeCommand(MedtronicCommandType.CancelTBR); - - Boolean response = (Boolean) responseTask2.getResult(); - - finishAction("TBR"); - - if (response) { - aapsLogger.info(LTag.PUMP, getLogPrefix() + "cancelTempBasal - Cancel TBR successful."); - - TemporaryBasal tempBasal = new TemporaryBasal(getInjector()) // - .date(System.currentTimeMillis()) // - .duration(0) // - .source(Source.USER); - - // TODO fix - activePlugin.getActiveTreatments().addToHistoryTempBasal(tempBasal); - - return new PumpEnactResult(getInjector()).success(true).enacted(true) // - .isTempCancel(true); - } else { - aapsLogger.info(LTag.PUMP, getLogPrefix() + "cancelTempBasal - Cancel TBR failed."); - - return new PumpEnactResult(getInjector()).success(response).enacted(response) // - .comment(R.string.medtronic_cmd_cant_cancel_tbr); - } - } - - @NonNull @Override - public ManufacturerType manufacturer() { - return pumpDescription.getPumpType().getManufacturer(); - } - - @NonNull @Override - public PumpType model() { - return pumpDescription.getPumpType(); - } - - @NonNull @Override - public String serialNumber() { - return medtronicPumpStatus.getSerialNumber(); - } - - @NonNull @Override - public PumpEnactResult setNewBasalProfile(@NonNull Profile profile) { - aapsLogger.info(LTag.PUMP, getLogPrefix() + "setNewBasalProfile"); - - // this shouldn't be needed, but let's do check if profile setting we are setting is same as current one - if (isProfileSame(profile)) { - return new PumpEnactResult(getInjector()) // - .success(true) // - .enacted(false) // - .comment(R.string.medtronic_cmd_basal_profile_not_set_is_same); - } - - setRefreshButtonEnabled(false); - - if (isPumpNotReachable()) { - - setRefreshButtonEnabled(true); - - return new PumpEnactResult(getInjector()) // - .success(false) // - .enacted(false) // - .comment(R.string.medtronic_pump_status_pump_unreachable); - } - - medtronicUtil.dismissNotification(MedtronicNotificationType.PumpUnreachable, rxBus); - - BasalProfile basalProfile = convertProfileToMedtronicProfile(profile); - - aapsLogger.debug("Basal Profile: " + basalProfile); - - String profileInvalid = isProfileValid(basalProfile); - - if (profileInvalid != null) { - return new PumpEnactResult(getInjector()) // - .success(false) // - .enacted(false) // - .comment(getResourceHelper().gs(R.string.medtronic_cmd_set_profile_pattern_overflow, profileInvalid)); - } - - MedtronicUITask responseTask = rileyLinkMedtronicService.getMedtronicUIComm().executeCommand(MedtronicCommandType.SetBasalProfileSTD, - Arrays.asList(basalProfile)); - - Boolean response = (Boolean) responseTask.getResult(); - - aapsLogger.info(LTag.PUMP, getLogPrefix() + "Basal Profile was set: " + response); - - if (response) { - return new PumpEnactResult(getInjector()).success(true).enacted(true); - } else { - return new PumpEnactResult(getInjector()).success(response).enacted(response) // - .comment(R.string.medtronic_cmd_basal_profile_could_not_be_set); - } - } - - - private String isProfileValid(BasalProfile basalProfile) { - - StringBuilder stringBuilder = new StringBuilder(); - - if (medtronicPumpStatus.getMaxBasal() == null) - return null; - - for (BasalProfileEntry profileEntry : basalProfile.getEntries()) { - - if (profileEntry.getRate() > medtronicPumpStatus.getMaxBasal()) { - stringBuilder.append(profileEntry.getStartTime().toString("HH:mm")); - stringBuilder.append("="); - stringBuilder.append(profileEntry.getRate()); - } - } - - return stringBuilder.length() == 0 ? null : stringBuilder.toString(); - } - - - @NonNull - private BasalProfile convertProfileToMedtronicProfile(Profile profile) { - - BasalProfile basalProfile = new BasalProfile(aapsLogger); - - for (int i = 0; i < 24; i++) { - double rate = profile.getBasalTimeFromMidnight(i * 60 * 60); - - double v = pumpDescription.getPumpType().determineCorrectBasalSize(rate); - - BasalProfileEntry basalEntry = new BasalProfileEntry(v, i, 0); - basalProfile.addEntry(basalEntry); - - } - - basalProfile.generateRawDataFromEntries(); - - return basalProfile; - } - - // OPERATIONS not supported by Pump or Plugin - - private List customActions = null; - - private final CustomAction customActionWakeUpAndTune = new CustomAction(R.string.medtronic_custom_action_wake_and_tune, - MedtronicCustomActionType.WakeUpAndTune); - - private final CustomAction customActionClearBolusBlock = new CustomAction( - R.string.medtronic_custom_action_clear_bolus_block, MedtronicCustomActionType.ClearBolusBlock, false); - - private final CustomAction customActionResetRLConfig = new CustomAction( - R.string.medtronic_custom_action_reset_rileylink, MedtronicCustomActionType.ResetRileyLinkConfiguration, true); - - - @Override - public List getCustomActions() { - - if (customActions == null) { - this.customActions = Arrays.asList(customActionWakeUpAndTune, // - customActionClearBolusBlock, // - customActionResetRLConfig); - } - - return this.customActions; - } - - - @Override - public void executeCustomAction(@NonNull CustomActionType customActionType) { - - MedtronicCustomActionType mcat = (MedtronicCustomActionType) customActionType; - - switch (mcat) { - - case WakeUpAndTune: { - if (rileyLinkMedtronicService.verifyConfiguration()) { - serviceTaskExecutor.startTask(new WakeAndTuneTask(getInjector())); - } else { - ErrorHelperActivity.Companion.runAlarm(context, getResourceHelper().gs(R.string.medtronic_error_operation_not_possible_no_configuration), getResourceHelper().gs(R.string.medtronic_warning), R.raw.boluserror); - } - } - break; - - case ClearBolusBlock: { - this.busyTimestamps.clear(); - this.customActionClearBolusBlock.setEnabled(false); - refreshCustomActionsList(); - } - break; - - case ResetRileyLinkConfiguration: { - serviceTaskExecutor.startTask(new ResetRileyLinkConfigurationTask(getInjector())); - } - break; - - default: - break; - } - - } - - @Override - public void timezoneOrDSTChanged(@NonNull TimeChangeType changeType) { - - aapsLogger.warn(LTag.PUMP, getLogPrefix() + "Time or TimeZone changed. "); - - this.hasTimeDateOrTimeZoneChanged = true; - } - - @Override - public boolean setNeutralTempAtFullHour() { - return sp.getBoolean(R.string.key_set_neutral_temps, true); - } - - - @SuppressWarnings("SameParameterValue") private void setEnableCustomAction(MedtronicCustomActionType customAction, boolean isEnabled) { - - if (customAction == MedtronicCustomActionType.ClearBolusBlock) { - this.customActionClearBolusBlock.setEnabled(isEnabled); - } else if (customAction == MedtronicCustomActionType.ResetRileyLinkConfiguration) { - this.customActionResetRLConfig.setEnabled(isEnabled); - } - - refreshCustomActionsList(); - } -} 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 new file mode 100644 index 0000000000..803f281b45 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.kt @@ -0,0 +1,1179 @@ +package info.nightscout.androidaps.plugins.pump.medtronic + +import android.content.ComponentName +import android.content.Context +import android.content.ServiceConnection +import android.os.IBinder +import android.os.SystemClock +import androidx.preference.Preference +import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.activities.ErrorHelperActivity.Companion.runAlarm +import info.nightscout.androidaps.data.DetailedBolusInfo +import info.nightscout.androidaps.data.Profile +import info.nightscout.androidaps.data.PumpEnactResult +import info.nightscout.androidaps.db.Source +import info.nightscout.androidaps.db.TemporaryBasal +import info.nightscout.androidaps.events.EventRefreshOverview +import info.nightscout.androidaps.interfaces.* +import info.nightscout.androidaps.interfaces.PumpSync.TemporaryBasalType +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.bus.RxBusWrapper +import info.nightscout.androidaps.plugins.common.ManufacturerType +import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction +import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType +import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification +import info.nightscout.androidaps.plugins.general.overview.notifications.Notification +import info.nightscout.androidaps.plugins.pump.common.PumpPluginAbstract +import info.nightscout.androidaps.plugins.pump.common.data.PumpStatus +import info.nightscout.androidaps.plugins.pump.common.defs.PumpDriverState +import info.nightscout.androidaps.plugins.pump.common.defs.PumpType +import info.nightscout.androidaps.plugins.pump.common.events.EventRefreshButtonState +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkConst +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkPumpDevice +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkPumpInfo +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkServiceState +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkServiceData +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.tasks.ResetRileyLinkConfigurationTask +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.tasks.ServiceTaskExecutor +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.tasks.WakeAndTuneTask +import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntry +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryResult +import info.nightscout.androidaps.plugins.pump.medtronic.data.MedtronicHistoryData +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BasalProfile +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BasalProfile.Companion.getProfilesByHourToString +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BasalProfileEntry +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.TempBasalPair +import info.nightscout.androidaps.plugins.pump.medtronic.defs.* +import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicCommandType.Companion.getSettings +import info.nightscout.androidaps.plugins.pump.medtronic.driver.MedtronicPumpStatus +import info.nightscout.androidaps.plugins.pump.medtronic.events.EventMedtronicPumpConfigurationChanged +import info.nightscout.androidaps.plugins.pump.medtronic.events.EventMedtronicPumpValuesChanged +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 info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil.Companion.isSame +import info.nightscout.androidaps.utils.DateUtil +import info.nightscout.androidaps.utils.FabricPrivacy +import info.nightscout.androidaps.utils.TimeChangeType +import info.nightscout.androidaps.utils.resources.ResourceHelper +import info.nightscout.androidaps.utils.rx.AapsSchedulers +import info.nightscout.androidaps.utils.sharedPreferences.SP +import org.joda.time.LocalDateTime +import java.util.* +import javax.inject.Inject +import javax.inject.Singleton + +/** + * Created by andy on 23.04.18. + * + * @author Andy Rozman (andy.rozman@gmail.com) + */ +@Singleton +class MedtronicPumpPlugin @Inject constructor( + injector: HasAndroidInjector, + aapsLogger: AAPSLogger, + rxBus: RxBusWrapper, + context: Context, + resourceHelper: ResourceHelper, + activePlugin: ActivePlugin, + sp: SP, + commandQueue: CommandQueueProvider, + fabricPrivacy: FabricPrivacy, + private val medtronicUtil: MedtronicUtil, + private val medtronicPumpStatus: MedtronicPumpStatus, + private val medtronicHistoryData: MedtronicHistoryData, + private val rileyLinkServiceData: RileyLinkServiceData, + private val serviceTaskExecutor: ServiceTaskExecutor, + dateUtil: DateUtil, + aapsSchedulers: AapsSchedulers, + pumpSync: PumpSync +) : PumpPluginAbstract(PluginDescription() // + .mainType(PluginType.PUMP) // + .fragmentClass(MedtronicFragment::class.java.name) // + .pluginIcon(R.drawable.ic_veo_128) + .pluginName(R.string.medtronic_name) // + .shortName(R.string.medtronic_name_short) // + .preferencesId(R.xml.pref_medtronic) + .description(R.string.description_pump_medtronic), // + PumpType.MEDTRONIC_522_722, // we default to most basic model, correct model from config is loaded later + injector, resourceHelper, aapsLogger, commandQueue, rxBus, activePlugin, sp, context, fabricPrivacy, dateUtil, aapsSchedulers!!, pumpSync!! +), Pump, RileyLinkPumpDevice { + + private var rileyLinkMedtronicService: RileyLinkMedtronicService? = null + + // variables for handling statuses and history + private var firstRun = true + private var isRefresh = false + private val statusRefreshMap: MutableMap = HashMap() + private var isInitialized = false + private var lastPumpHistoryEntry: PumpHistoryEntry? = null + private val busyTimestamps: MutableList = ArrayList() + private var hasTimeDateOrTimeZoneChanged = false + private val usePumpSync = false + + override fun onStart() { + aapsLogger.debug(LTag.PUMP, deviceID() + " started.") + serviceConnection = object : ServiceConnection { + override fun onServiceDisconnected(name: ComponentName) { + aapsLogger.debug(LTag.PUMP, "RileyLinkMedtronicService is disconnected") + rileyLinkMedtronicService = null + } + + override fun onServiceConnected(name: ComponentName, service: IBinder) { + aapsLogger.debug(LTag.PUMP, "RileyLinkMedtronicService is connected") + val mLocalBinder = service as RileyLinkMedtronicService.LocalBinder + rileyLinkMedtronicService = mLocalBinder.serviceInstance + rileyLinkMedtronicService!!.verifyConfiguration() + Thread(Runnable { + for (i in 0..19) { + SystemClock.sleep(5000) + aapsLogger.debug(LTag.PUMP, "Starting Medtronic-RileyLink service") + if (rileyLinkMedtronicService!!.setNotInPreInit()) { + break + } + } + }).start() + } + } + super.onStart() + } + + override fun updatePreferenceSummary(pref: Preference) { + super.updatePreferenceSummary(pref) + if (pref.key == resourceHelper.gs(R.string.key_rileylink_mac_address)) { + val value = sp.getStringOrNull(R.string.key_rileylink_mac_address, null) + pref.summary = value ?: resourceHelper.gs(R.string.not_set_short) + } + } + + private val logPrefix: String + private get() = "MedtronicPumpPlugin::" + + override fun initPumpStatusData() { + medtronicPumpStatus.lastConnection = sp.getLong(RileyLinkConst.Prefs.LastGoodDeviceCommunicationTime, 0L) + medtronicPumpStatus.lastDataTime = medtronicPumpStatus.lastConnection + medtronicPumpStatus.previousConnection = medtronicPumpStatus.lastConnection + + //if (rileyLinkMedtronicService != null) rileyLinkMedtronicService.verifyConfiguration(); + aapsLogger.debug(LTag.PUMP, "initPumpStatusData: " + medtronicPumpStatus) + + // this is only thing that can change, by being configured + pumpDescription.maxTempAbsolute = if (medtronicPumpStatus.maxBasal != null) medtronicPumpStatus.maxBasal!! else 35.0 + + // set first Medtronic Pump Start + if (!sp.contains(MedtronicConst.Statistics.FirstPumpStart)) { + sp.putLong(MedtronicConst.Statistics.FirstPumpStart, System.currentTimeMillis()) + } + migrateSettings() + } + + override fun triggerPumpConfigurationChangedEvent() { + rxBus.send(EventMedtronicPumpConfigurationChanged()) + } + + private fun migrateSettings() { + if ("US (916 MHz)" == sp.getString(MedtronicConst.Prefs.PumpFrequency, "US (916 MHz)")) { + sp.putString(MedtronicConst.Prefs.PumpFrequency, resourceHelper.gs(R.string.key_medtronic_pump_frequency_us_ca)) + } + val encoding = sp.getString(MedtronicConst.Prefs.Encoding, "RileyLink 4b6b Encoding") + if ("RileyLink 4b6b Encoding" == encoding) { + sp.putString(MedtronicConst.Prefs.Encoding, resourceHelper.gs(R.string.key_medtronic_pump_encoding_4b6b_rileylink)) + } + if ("Local 4b6b Encoding" == encoding) { + sp.putString(MedtronicConst.Prefs.Encoding, resourceHelper.gs(R.string.key_medtronic_pump_encoding_4b6b_local)) + } + } + + override fun onStartCustomActions() { + + // check status every minute (if any status needs refresh we send readStatus command) + Thread(Runnable { + do { + SystemClock.sleep(60000) + if (this.isInitialized) { + val statusRefresh = workWithStatusRefresh( + StatusRefreshAction.GetData, null, null) + if (doWeHaveAnyStatusNeededRefereshing(statusRefresh)) { + if (!commandQueue.statusInQueue()) { + commandQueue.readStatus("Scheduled Status Refresh", null) + } + } + clearBusyQueue() + } + } while (serviceRunning) + }).start() + } + + override val serviceClass: Class<*> + get() = RileyLinkMedtronicService::class.java + + override val pumpStatusData: PumpStatus + get() = medtronicPumpStatus + + override fun deviceID(): String { + return "Medtronic" + } + + override val isFakingTempsByExtendedBoluses: Boolean + get() = false + + override fun canHandleDST(): Boolean { + return false + } + + // Pump Plugin + private val isServiceSet: Boolean + private get() = rileyLinkMedtronicService != null + + override fun getRileyLinkService(): RileyLinkMedtronicService? { + return rileyLinkMedtronicService + } + + override fun getPumpInfo(): RileyLinkPumpInfo { + val frequency = resourceHelper.gs(if (medtronicPumpStatus.pumpFrequency == "medtronic_pump_frequency_us_ca") R.string.medtronic_pump_frequency_us_ca else R.string.medtronic_pump_frequency_worldwide) + val model = if (medtronicPumpStatus.medtronicDeviceType == null) "???" else "Medtronic " + medtronicPumpStatus.medtronicDeviceType!!.pumpModel + val serialNumber = medtronicPumpStatus.serialNumber + return RileyLinkPumpInfo(frequency, model, serialNumber) + } + + override fun getLastConnectionTimeMillis(): Long { + return medtronicPumpStatus.lastConnection + } + + override fun setLastCommunicationToNow() { + medtronicPumpStatus.setLastCommunicationToNow() + } + + override fun isInitialized(): Boolean { + if (displayConnectionMessages) aapsLogger.debug(LTag.PUMP, "MedtronicPumpPlugin::isInitialized") + return isServiceSet && isInitialized + } + + override fun setBusy(busy: Boolean) { + isBusy = busy + } + + override fun isBusy(): Boolean { + if (displayConnectionMessages) aapsLogger.debug(LTag.PUMP, "MedtronicPumpPlugin::isBusy") + if (isServiceSet) { + if (isBusy) return true + if (busyTimestamps.size > 0) { + clearBusyQueue() + return busyTimestamps.size > 0 + } + } + return false + } + + @Synchronized + private fun clearBusyQueue() { + if (busyTimestamps.size == 0) { + return + } + val deleteFromQueue: MutableSet = HashSet() + for (busyTimestamp in busyTimestamps) { + if (System.currentTimeMillis() > busyTimestamp) { + deleteFromQueue.add(busyTimestamp) + } + } + if (deleteFromQueue.size == busyTimestamps.size) { + busyTimestamps.clear() + setEnableCustomAction(MedtronicCustomActionType.ClearBolusBlock, false) + } + if (deleteFromQueue.size > 0) { + busyTimestamps.removeAll(deleteFromQueue) + } + } + + override fun isConnected(): Boolean { + if (displayConnectionMessages) aapsLogger.debug(LTag.PUMP, "MedtronicPumpPlugin::isConnected") + return isServiceSet && rileyLinkMedtronicService!!.isInitialized + } + + override fun isConnecting(): Boolean { + if (displayConnectionMessages) aapsLogger.debug(LTag.PUMP, "MedtronicPumpPlugin::isConnecting") + return !isServiceSet || !rileyLinkMedtronicService!!.isInitialized + } + + override fun getPumpStatus(reason: String) { + var needRefresh = true + if (firstRun) { + needRefresh = initializePump(!isRefresh) + } else { + refreshAnyStatusThatNeedsToBeRefreshed() + } + if (needRefresh) rxBus.send(EventMedtronicPumpValuesChanged()) + } + + fun resetStatusState() { + firstRun = true + isRefresh = true + }// + + private val isPumpNotReachable: Boolean + private get() { + val rileyLinkServiceState = rileyLinkServiceData.rileyLinkServiceState + if (rileyLinkServiceState == null) { + aapsLogger.debug(LTag.PUMP, "RileyLink unreachable. RileyLinkServiceState is null.") + return false + } + if (rileyLinkServiceState != RileyLinkServiceState.PumpConnectorReady // + && rileyLinkServiceState != RileyLinkServiceState.RileyLinkReady // + && rileyLinkServiceState != RileyLinkServiceState.TuneUpDevice) { + aapsLogger.debug(LTag.PUMP, "RileyLink unreachable.") + return false + } + return !rileyLinkMedtronicService!!.deviceCommunicationManager.isDeviceReachable + } + + private fun refreshAnyStatusThatNeedsToBeRefreshed() { + val statusRefresh = workWithStatusRefresh(StatusRefreshAction.GetData, null, + null) + if (!doWeHaveAnyStatusNeededRefereshing(statusRefresh)) { + return + } + var resetTime = false + if (isPumpNotReachable) { + aapsLogger.error("Pump unreachable.") + medtronicUtil.sendNotification(MedtronicNotificationType.PumpUnreachable, resourceHelper, rxBus) + return + } + medtronicUtil.dismissNotification(MedtronicNotificationType.PumpUnreachable, rxBus) + if (hasTimeDateOrTimeZoneChanged) { + checkTimeAndOptionallySetTime() + + // read time if changed, set new time + hasTimeDateOrTimeZoneChanged = false + } + + // execute + val refreshTypesNeededToReschedule: MutableSet = HashSet() + for ((key, value) in statusRefresh!!) { + if (value!! > 0 && System.currentTimeMillis() > value) { + when (key) { + MedtronicStatusRefreshType.PumpHistory -> { + readPumpHistory() + } + + MedtronicStatusRefreshType.PumpTime -> { + checkTimeAndOptionallySetTime() + refreshTypesNeededToReschedule.add(key) + resetTime = true + } + + MedtronicStatusRefreshType.BatteryStatus, MedtronicStatusRefreshType.RemainingInsulin -> { + rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(key.getCommandType(medtronicUtil.medtronicPumpModel)!!) + refreshTypesNeededToReschedule.add(key) + resetTime = true + } + + MedtronicStatusRefreshType.Configuration -> { + rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(key.getCommandType(medtronicUtil.medtronicPumpModel)!!) + resetTime = true + } + } + } + + // reschedule + for (refreshType2 in refreshTypesNeededToReschedule) { + scheduleNextRefresh(refreshType2) + } + } + + if (resetTime) medtronicPumpStatus.setLastCommunicationToNow() + } + + private fun doWeHaveAnyStatusNeededRefereshing(statusRefresh: Map?): Boolean { + for ((_, value) in statusRefresh!!) { + if (value!! > 0 && System.currentTimeMillis() > value) { + return true + } + } + return hasTimeDateOrTimeZoneChanged + } + + private fun setRefreshButtonEnabled(enabled: Boolean) { + rxBus.send(EventRefreshButtonState(enabled)) + } + + private fun initializePump(realInit: Boolean): Boolean { + if (rileyLinkMedtronicService == null) return false + aapsLogger.info(LTag.PUMP, logPrefix + "initializePump - start") + rileyLinkMedtronicService!!.deviceCommunicationManager.setDoWakeUpBeforeCommand(false) + setRefreshButtonEnabled(false) + if (isRefresh) { + if (isPumpNotReachable) { + aapsLogger.error(logPrefix + "initializePump::Pump unreachable.") + medtronicUtil.sendNotification(MedtronicNotificationType.PumpUnreachable, resourceHelper, rxBus) + setRefreshButtonEnabled(true) + return true + } + medtronicUtil.dismissNotification(MedtronicNotificationType.PumpUnreachable, rxBus) + } + + // model (once) + if (medtronicUtil.medtronicPumpModel == null) { + 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.") + medtronicUtil.sendNotification(MedtronicNotificationType.PumpTypeNotSame, resourceHelper, rxBus) + } + } + pumpState = PumpDriverState.Connected + + // time (1h) + checkTimeAndOptionallySetTime() + readPumpHistory() + + // remaining insulin (>50 = 4h; 50-20 = 1h; 15m) + rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(MedtronicCommandType.GetRemainingInsulin) + scheduleNextRefresh(MedtronicStatusRefreshType.RemainingInsulin, 10) + + // remaining power (1h) + rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(MedtronicCommandType.GetBatteryStatus) + scheduleNextRefresh(MedtronicStatusRefreshType.BatteryStatus, 20) + + // configuration (once and then if history shows config changes) + rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(getSettings(medtronicUtil.medtronicPumpModel)) + + // read profile (once, later its controlled by isThisProfileSet method) + basalProfiles + val errorCount = rileyLinkMedtronicService!!.medtronicUIComm!!.invalidResponsesCount + if (errorCount >= 5) { + aapsLogger.error("Number of error counts was 5 or more. Starting tunning.") + setRefreshButtonEnabled(true) + serviceTaskExecutor.startTask(WakeAndTuneTask(injector)) + return true + } + medtronicPumpStatus.setLastCommunicationToNow() + setRefreshButtonEnabled(true) + if (!isRefresh) { + pumpState = PumpDriverState.Initialized + } + isInitialized = true + // this.pumpState = PumpDriverState.Initialized; + firstRun = false + return true + } + + private val basalProfiles: Unit + private get() { + val medtronicUITask = rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(MedtronicCommandType.GetBasalProfileSTD) + if (medtronicUITask.responseType === MedtronicUIResponseType.Error) { + rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(MedtronicCommandType.GetBasalProfileSTD) + } + } + + override fun isThisProfileSet(profile: Profile): Boolean { + aapsLogger.debug(LTag.PUMP, "isThisProfileSet: basalInitalized=" + medtronicPumpStatus.basalProfileStatus) + if (!isInitialized) return true + if (medtronicPumpStatus.basalProfileStatus === BasalProfileStatus.NotInitialized) { + // this shouldn't happen, but if there was problem we try again + basalProfiles + return isProfileSame(profile) + } else if (medtronicPumpStatus.basalProfileStatus === BasalProfileStatus.ProfileChanged) { + return false + } + return medtronicPumpStatus.basalProfileStatus !== BasalProfileStatus.ProfileOK || isProfileSame(profile) + } + + private fun isProfileSame(profile: Profile): Boolean { + var invalid = false + val basalsByHour: Array? = medtronicPumpStatus.basalsByHour + aapsLogger.debug(LTag.PUMP, "Current Basals (h): " + + (basalsByHour?.let { getProfilesByHourToString(it) } ?: "null")) + + // int index = 0; + if (basalsByHour == null) return true // we don't want to set profile again, unless we are sure + val stringBuilder = StringBuilder("Requested Basals (h): ") + for (basalValue in profile.basalValues) { + val basalValueValue = pumpDescription.pumpType.determineCorrectBasalSize(basalValue.value) + val hour = basalValue.timeAsSeconds / (60 * 60) + if (!isSame(basalsByHour[hour]!!, basalValueValue)) { + invalid = true + } + stringBuilder.append(String.format(Locale.ENGLISH, "%.3f", basalValueValue)) + stringBuilder.append(" ") + } + aapsLogger.debug(LTag.PUMP, stringBuilder.toString()) + if (!invalid) { + aapsLogger.debug(LTag.PUMP, "Basal profile is same as AAPS one.") + } else { + aapsLogger.debug(LTag.PUMP, "Basal profile on Pump is different than the AAPS one.") + } + return !invalid + } + + override fun lastDataTime(): Long { + return if (medtronicPumpStatus.lastConnection > 0) { + medtronicPumpStatus.lastConnection + } else System.currentTimeMillis() + } + + override val baseBasalRate: Double + get() = medtronicPumpStatus.basalProfileForHour + + override val reservoirLevel: Double + get() = medtronicPumpStatus.reservoirRemainingUnits + + override val batteryLevel: Int + get() = medtronicPumpStatus.batteryRemaining + + override fun triggerUIChange() { + rxBus.send(EventMedtronicPumpValuesChanged()) + } + + override fun generateTempId(timeMillis: Long): Long { + return 0 + } + + // @Override public String getSerial() { + // return null; + // } + private var bolusDeliveryType = BolusDeliveryType.Idle + + private enum class BolusDeliveryType { + Idle, // + DeliveryPrepared, // + Delivering, // + CancelDelivery + } + + private fun checkTimeAndOptionallySetTime() { + aapsLogger.info(LTag.PUMP, "MedtronicPumpPlugin::checkTimeAndOptionallySetTime - Start") + setRefreshButtonEnabled(false) + if (isPumpNotReachable) { + aapsLogger.debug(LTag.PUMP, "MedtronicPumpPlugin::checkTimeAndOptionallySetTime - Pump Unreachable.") + setRefreshButtonEnabled(true) + return + } + medtronicUtil.dismissNotification(MedtronicNotificationType.PumpUnreachable, rxBus) + rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(MedtronicCommandType.GetRealTimeClock) + var clock = medtronicUtil.pumpTime + if (clock == null) { // retry + rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(MedtronicCommandType.GetRealTimeClock) + clock = medtronicUtil.pumpTime + } + if (clock == null) return + val timeDiff = Math.abs(clock.timeDifference) + 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) + 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)) + } + } else { + if (clock.localDeviceTime!!.year > 2015) { + aapsLogger.error(String.format(Locale.ENGLISH, "MedtronicPumpPlugin::checkTimeAndOptionallySetTime - Time difference over 24h requested [diff=%d s]. Doing nothing.", timeDiff)) + medtronicUtil.sendNotification(MedtronicNotificationType.TimeChangeOver24h, resourceHelper, rxBus) + } + } + } else { + aapsLogger.info(LTag.PUMP, String.format(Locale.ENGLISH, "MedtronicPumpPlugin::checkTimeAndOptionallySetTime - Time difference is %d s. Do nothing.", timeDiff)) + } + scheduleNextRefresh(MedtronicStatusRefreshType.PumpTime, 0) + } + + override fun deliverBolus(detailedBolusInfo: DetailedBolusInfo?): PumpEnactResult { + aapsLogger.info(LTag.PUMP, "MedtronicPumpPlugin::deliverBolus - " + BolusDeliveryType.DeliveryPrepared) + setRefreshButtonEnabled(false) + if (detailedBolusInfo!!.insulin > medtronicPumpStatus.reservoirRemainingUnits) { + return PumpEnactResult(injector) // + .success(false) // + .enacted(false) // + .comment(resourceHelper.gs(R.string.medtronic_cmd_bolus_could_not_be_delivered_no_insulin, + medtronicPumpStatus.reservoirRemainingUnits, + detailedBolusInfo.insulin)) + } + bolusDeliveryType = BolusDeliveryType.DeliveryPrepared + if (isPumpNotReachable) { + aapsLogger.debug(LTag.PUMP, "MedtronicPumpPlugin::deliverBolus - Pump Unreachable.") + return setNotReachable(true, false) + } + medtronicUtil.dismissNotification(MedtronicNotificationType.PumpUnreachable, rxBus) + if (bolusDeliveryType == BolusDeliveryType.CancelDelivery) { + // LOG.debug("MedtronicPumpPlugin::deliverBolus - Delivery Canceled."); + return setNotReachable(true, true) + } + + // LOG.debug("MedtronicPumpPlugin::deliverBolus - Starting wait period."); + val sleepTime = sp.getInt(MedtronicConst.Prefs.BolusDelay, 10) * 1000 + SystemClock.sleep(sleepTime.toLong()) + return if (bolusDeliveryType == BolusDeliveryType.CancelDelivery) { + // LOG.debug("MedtronicPumpPlugin::deliverBolus - Delivery Canceled, before wait period."); + setNotReachable(true, true) + } else try { + bolusDeliveryType = BolusDeliveryType.Delivering + + // LOG.debug("MedtronicPumpPlugin::deliverBolus - Start delivery"); + val responseTask = rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(MedtronicCommandType.SetBolus, + Arrays.asList(detailedBolusInfo.insulin)) + val response = responseTask.result as Boolean? + setRefreshButtonEnabled(true) + + // LOG.debug("MedtronicPumpPlugin::deliverBolus - Response: {}", response); + if (response!!) { + 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() + } + val now = System.currentTimeMillis() + detailedBolusInfo.timestamp = now + detailedBolusInfo.deliverAtTheLatest = now // not sure about that one + + // TODO fix + if (usePumpSync) { + addBolusWithTempId(detailedBolusInfo, true) + } else { + activePlugin.activeTreatments.addToHistoryTreatment(detailedBolusInfo, true) + } + + // we subtract insulin, exact amount will be visible with next remainingInsulin update. + medtronicPumpStatus.reservoirRemainingUnits = medtronicPumpStatus.reservoirRemainingUnits - detailedBolusInfo.insulin + incrementStatistics(if (detailedBolusInfo.bolusType === DetailedBolusInfo.BolusType.SMB) MedtronicConst.Statistics.SMBBoluses else MedtronicConst.Statistics.StandardBoluses) + + // calculate time for bolus and set driver to busy for that time + val bolusTime = (detailedBolusInfo.insulin * 42.0).toInt() + val time = now + bolusTime * 1000 + busyTimestamps.add(time) + setEnableCustomAction(MedtronicCustomActionType.ClearBolusBlock, true) + PumpEnactResult(injector).success(true) // + .enacted(true) // + .bolusDelivered(detailedBolusInfo.insulin) // + .carbsDelivered(detailedBolusInfo.carbs) + } else { + PumpEnactResult(injector) // + .success(bolusDeliveryType == BolusDeliveryType.CancelDelivery) // + .enacted(false) // + .comment(R.string.medtronic_cmd_bolus_could_not_be_delivered) + } + } finally { + finishAction("Bolus") + bolusDeliveryType = BolusDeliveryType.Idle + } + + // LOG.debug("MedtronicPumpPlugin::deliverBolus - End wait period. Start delivery"); + } + + private fun setNotReachable(isBolus: Boolean, success: Boolean): PumpEnactResult { + setRefreshButtonEnabled(true) + if (isBolus) { + bolusDeliveryType = BolusDeliveryType.Idle + } + return if (success) { + PumpEnactResult(injector) // + .success(true) // + .enacted(false) + } else { + PumpEnactResult(injector) // + .success(false) // + .enacted(false) // + .comment(R.string.medtronic_pump_status_pump_unreachable) + } + } + + override fun stopBolusDelivering() { + bolusDeliveryType = BolusDeliveryType.CancelDelivery + + // if (isLoggingEnabled()) + // LOG.warn("MedtronicPumpPlugin::deliverBolus - Stop Bolus Delivery."); + } + + private fun incrementStatistics(statsKey: String) { + var currentCount = sp.getLong(statsKey, 0L) + currentCount++ + sp.putLong(statsKey, currentCount) + } + + // if enforceNew===true current temp basal is canceled and new TBR set (duration is prolonged), + // if false and the same rate is requested enacted=false and success=true is returned and TBR is not changed + override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: TemporaryBasalType): PumpEnactResult { + setRefreshButtonEnabled(false) + if (isPumpNotReachable) { + setRefreshButtonEnabled(true) + return PumpEnactResult(injector) // + .success(false) // + .enacted(false) // + .comment(R.string.medtronic_pump_status_pump_unreachable) + } + medtronicUtil.dismissNotification(MedtronicNotificationType.PumpUnreachable, rxBus) + aapsLogger.info(LTag.PUMP, logPrefix + "setTempBasalAbsolute: rate: " + absoluteRate + ", duration=" + durationInMinutes) + + // read current TBR + val tbrCurrent = readTBR() + if (tbrCurrent == null) { + aapsLogger.warn(LTag.PUMP, logPrefix + "setTempBasalAbsolute - Could not read current TBR, canceling operation.") + finishAction("TBR") + return PumpEnactResult(injector).success(false).enacted(false) + .comment(R.string.medtronic_cmd_cant_read_tbr) + } else { + aapsLogger.info(LTag.PUMP, logPrefix + "setTempBasalAbsolute: Current Basal: duration: " + tbrCurrent.durationMinutes + " min, rate=" + tbrCurrent.insulinRate) + } + if (!enforceNew) { + if (isSame(tbrCurrent.insulinRate, absoluteRate)) { + var sameRate = true + if (isSame(0.0, absoluteRate) && durationInMinutes > 0) { + // if rate is 0.0 and duration>0 then the rate is not the same + sameRate = false + } + if (sameRate) { + aapsLogger.info(LTag.PUMP, logPrefix + "setTempBasalAbsolute - No enforceNew and same rate. Exiting.") + finishAction("TBR") + return PumpEnactResult(injector).success(true).enacted(false) + } + } + // if not the same rate, we cancel and start new + } + + // if TBR is running we will cancel it. + if (tbrCurrent.insulinRate > 0.0 && tbrCurrent.durationMinutes > 0) { + aapsLogger.info(LTag.PUMP, logPrefix + "setTempBasalAbsolute - TBR running - so canceling it.") + + // CANCEL + val responseTask2 = rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(MedtronicCommandType.CancelTBR) + val response = responseTask2.result as Boolean? + if (response!!) { + aapsLogger.info(LTag.PUMP, logPrefix + "setTempBasalAbsolute - Current TBR cancelled.") + } else { + aapsLogger.error(logPrefix + "setTempBasalAbsolute - Cancel TBR failed.") + finishAction("TBR") + return PumpEnactResult(injector).success(false).enacted(false) + .comment(R.string.medtronic_cmd_cant_cancel_tbr_stop_op) + } + } + + // now start new TBR + val responseTask = rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(MedtronicCommandType.SetTemporaryBasal, + Arrays.asList(absoluteRate, durationInMinutes)) + val response = responseTask.result as Boolean? + aapsLogger.info(LTag.PUMP, logPrefix + "setTempBasalAbsolute - setTBR. Response: " + response) + return if (response!!) { + // FIXME put this into UIPostProcessor + medtronicPumpStatus.tempBasalStart = Date() + medtronicPumpStatus.tempBasalAmount = absoluteRate + medtronicPumpStatus.tempBasalLength = durationInMinutes + val tempStart = TemporaryBasal(injector) // + .date(System.currentTimeMillis()) // + .duration(durationInMinutes) // + .absolute(absoluteRate) // + .source(Source.USER) + + // TODO fix + if (usePumpSync) { + addTemporaryBasalRateWithTempId(tempStart, true) + } else { + activePlugin.activeTreatments.addToHistoryTempBasal(tempStart) + } + incrementStatistics(MedtronicConst.Statistics.TBRsSet) + finishAction("TBR") + PumpEnactResult(injector).success(true).enacted(true) // + .absolute(absoluteRate).duration(durationInMinutes) + } else { + finishAction("TBR") + PumpEnactResult(injector).success(false).enacted(false) // + .comment(R.string.medtronic_cmd_tbr_could_not_be_delivered) + } + } + + override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: TemporaryBasalType): PumpEnactResult { + return if (percent == 0) { + setTempBasalAbsolute(0.0, durationInMinutes, profile, enforceNew, tbrType) + } else { + var absoluteValue = profile.basal * (percent / 100.0) + absoluteValue = pumpDescription.pumpType.determineCorrectBasalSize(absoluteValue) + aapsLogger.warn(LTag.PUMP, "setTempBasalPercent [MedtronicPumpPlugin] - You are trying to use setTempBasalPercent with percent other then 0% ($percent). This will start setTempBasalAbsolute, with calculated value ($absoluteValue). Result might not be 100% correct.") + setTempBasalAbsolute(absoluteValue, durationInMinutes, profile, enforceNew, tbrType) + } + } + + private fun finishAction(overviewKey: String?) { + if (overviewKey != null) rxBus.send(EventRefreshOverview(overviewKey, false)) + triggerUIChange() + setRefreshButtonEnabled(true) + } + + private fun readPumpHistory() { + +// if (isLoggingEnabled()) +// LOG.error(getLogPrefix() + "readPumpHistory WIP."); + readPumpHistoryLogic() + scheduleNextRefresh(MedtronicStatusRefreshType.PumpHistory) + if (medtronicHistoryData.hasRelevantConfigurationChanged()) { + scheduleNextRefresh(MedtronicStatusRefreshType.Configuration, -1) + } + if (medtronicHistoryData.hasPumpTimeChanged()) { + scheduleNextRefresh(MedtronicStatusRefreshType.PumpTime, -1) + } + if (medtronicPumpStatus.basalProfileStatus !== BasalProfileStatus.NotInitialized + && medtronicHistoryData.hasBasalProfileChanged()) { + medtronicHistoryData.processLastBasalProfileChange(pumpDescription.pumpType, medtronicPumpStatus) + } + val previousState = pumpState + if (medtronicHistoryData.isPumpSuspended) { + pumpState = PumpDriverState.Suspended + aapsLogger.debug(LTag.PUMP, logPrefix + "isPumpSuspended: true") + } else { + if (previousState === PumpDriverState.Suspended) { + pumpState = PumpDriverState.Ready + } + aapsLogger.debug(LTag.PUMP, logPrefix + "isPumpSuspended: false") + } + medtronicHistoryData.processNewHistoryData() + medtronicHistoryData.finalizeNewHistoryRecords() + // this.medtronicHistoryData.setLastHistoryRecordTime(this.lastPumpHistoryEntry.atechDateTime); + } + + private fun readPumpHistoryLogic() { + + val debugHistory = false + var targetDate: LocalDateTime? = null + if (lastPumpHistoryEntry == null) { + if (debugHistory) aapsLogger.debug(LTag.PUMP, logPrefix + "readPumpHistoryLogic(): lastPumpHistoryEntry: null") + val lastPumpHistoryEntryTime = lastPumpEntryTime + var timeMinus36h = LocalDateTime() + timeMinus36h = timeMinus36h.minusHours(36) + medtronicHistoryData.setIsInInit(true) + if (lastPumpHistoryEntryTime == 0L) { + if (debugHistory) aapsLogger.debug(LTag.PUMP, logPrefix + "readPumpHistoryLogic(): lastPumpHistoryEntryTime: 0L - targetDate: " + + targetDate) + targetDate = timeMinus36h + } else { + // LocalDateTime lastHistoryRecordTime = DateTimeUtil.toLocalDateTime(lastPumpHistoryEntryTime); + if (debugHistory) aapsLogger.debug(LTag.PUMP, logPrefix + "readPumpHistoryLogic(): lastPumpHistoryEntryTime: " + lastPumpHistoryEntryTime + " - targetDate: " + targetDate) + medtronicHistoryData.setLastHistoryRecordTime(lastPumpHistoryEntryTime) + var lastHistoryRecordTime = DateTimeUtil.toLocalDateTime(lastPumpHistoryEntryTime) + lastHistoryRecordTime = lastHistoryRecordTime.minusHours(12) // we get last 12 hours of history to + // determine pump state + // (we don't process that data), we process only + if (timeMinus36h.isAfter(lastHistoryRecordTime)) { + targetDate = timeMinus36h + } + targetDate = if (timeMinus36h.isAfter(lastHistoryRecordTime)) timeMinus36h else lastHistoryRecordTime + if (debugHistory) aapsLogger.debug(LTag.PUMP, logPrefix + "readPumpHistoryLogic(): targetDate: " + targetDate) + } + } else { + if (debugHistory) aapsLogger.debug(LTag.PUMP, logPrefix + "readPumpHistoryLogic(): lastPumpHistoryEntry: not null - " + medtronicUtil.gsonInstance.toJson(lastPumpHistoryEntry)) + medtronicHistoryData.setIsInInit(false) + // medtronicHistoryData.setLastHistoryRecordTime(lastPumpHistoryEntry.atechDateTime); + + // targetDate = lastPumpHistoryEntry.atechDateTime; + } + + //aapsLogger.debug(LTag.PUMP, "HST: Target Date: " + targetDate); + val responseTask2 = rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(MedtronicCommandType.GetHistoryData, + Arrays.asList(lastPumpHistoryEntry, targetDate) as List?) + 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()) + val latestEntry = historyResult!!.latestEntry + if (debugHistory) aapsLogger.debug(LTag.PUMP, logPrefix + "Last entry: " + latestEntry) + if (latestEntry == null) // no new history to read + return + lastPumpHistoryEntry = latestEntry + sp.putLong(MedtronicConst.Statistics.LastPumpHistoryEntry, latestEntry.atechDateTime!!) + if (debugHistory) aapsLogger.debug(LTag.PUMP, "HST: History: valid=" + historyResult.validEntries.size + ", unprocessed=" + historyResult.unprocessedEntries.size) + medtronicHistoryData.addNewHistory(historyResult) + medtronicHistoryData.filterNewEntries() + + // determine if first run, if yes detrmine how much of update do we need + // first run: + // get last hiostory entry, if not there download 1.5 days of data + // - there: check if last entry is older than 1.5 days + // - yes: download 1.5 days + // - no: download with last entry + // - not there: download 1.5 days + // + // upload all new entries to NightScout (TBR, Bolus) + // determine pump status + // + // save last entry + // + // not first run: + // update to last entry + // - save + // - determine pump status + } + + private val lastPumpEntryTime: Long + private get() { + val lastPumpEntryTime = sp.getLong(MedtronicConst.Statistics.LastPumpHistoryEntry, 0L) + return try { + val localDateTime = DateTimeUtil.toLocalDateTime(lastPumpEntryTime) + if (localDateTime.year != GregorianCalendar()[Calendar.YEAR]) { + aapsLogger.warn(LTag.PUMP, "Saved LastPumpHistoryEntry was invalid. Year was not the same.") + return 0L + } + lastPumpEntryTime + } catch (ex: Exception) { + aapsLogger.warn(LTag.PUMP, "Saved LastPumpHistoryEntry was invalid.") + 0L + } + } + + private fun scheduleNextRefresh(refreshType: MedtronicStatusRefreshType?, additionalTimeInMinutes: Int = 0) { + when (refreshType) { + MedtronicStatusRefreshType.RemainingInsulin -> { + val remaining = medtronicPumpStatus.reservoirRemainingUnits + val min: Int + min = if (remaining > 50) 4 * 60 else if (remaining > 20) 60 else 15 + workWithStatusRefresh(StatusRefreshAction.Add, refreshType, getTimeInFutureFromMinutes(min)) + } + + MedtronicStatusRefreshType.PumpTime, MedtronicStatusRefreshType.Configuration, MedtronicStatusRefreshType.BatteryStatus, MedtronicStatusRefreshType.PumpHistory -> { + workWithStatusRefresh(StatusRefreshAction.Add, refreshType, + getTimeInFutureFromMinutes(refreshType.refreshTime + additionalTimeInMinutes)) + } + } + } + + private enum class StatusRefreshAction { + Add, // + GetData + } + + @Synchronized + private fun workWithStatusRefresh(action: StatusRefreshAction, // + statusRefreshType: MedtronicStatusRefreshType?, // + time: Long?): Map? { + return when (action) { + StatusRefreshAction.Add -> { + statusRefreshMap[statusRefreshType] = time + null + } + + StatusRefreshAction.GetData -> { + HashMap(statusRefreshMap) + } + + else -> null + } + } + + private fun getTimeInFutureFromMinutes(minutes: Int): Long { + return System.currentTimeMillis() + getTimeInMs(minutes) + } + + private fun getTimeInMs(minutes: Int): Long { + return minutes * 60 * 1000L + } + + private fun readTBR(): TempBasalPair? { + val responseTask = rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(MedtronicCommandType.ReadTemporaryBasal) + return if (responseTask.hasData()) { + val tbr = responseTask.result as TempBasalPair? + + // we sometimes get rate returned even if TBR is no longer running + if (tbr!!.durationMinutes == 0) { + tbr.insulinRate = 0.0 + } + tbr + } else { + null + } + } + + override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult { + aapsLogger.info(LTag.PUMP, logPrefix + "cancelTempBasal - started") + if (isPumpNotReachable) { + setRefreshButtonEnabled(true) + return PumpEnactResult(injector) // + .success(false) // + .enacted(false) // + .comment(R.string.medtronic_pump_status_pump_unreachable) + } + medtronicUtil.dismissNotification(MedtronicNotificationType.PumpUnreachable, rxBus) + setRefreshButtonEnabled(false) + val tbrCurrent = readTBR() + if (tbrCurrent != null) { + if (tbrCurrent.insulinRate > 0.0f && tbrCurrent.durationMinutes == 0) { + aapsLogger.info(LTag.PUMP, logPrefix + "cancelTempBasal - TBR already canceled.") + finishAction("TBR") + return PumpEnactResult(injector).success(true).enacted(false) + } + } else { + aapsLogger.warn(LTag.PUMP, logPrefix + "cancelTempBasal - Could not read currect TBR, canceling operation.") + finishAction("TBR") + return PumpEnactResult(injector).success(false).enacted(false) + .comment(R.string.medtronic_cmd_cant_read_tbr) + } + val responseTask2 = rileyLinkMedtronicService!!.medtronicUIComm!!.executeCommand(MedtronicCommandType.CancelTBR) + val response = responseTask2.result as Boolean? + finishAction("TBR") + return if (response!!) { + aapsLogger.info(LTag.PUMP, logPrefix + "cancelTempBasal - Cancel TBR successful.") + val tempBasal = TemporaryBasal(injector) // + .date(System.currentTimeMillis()) // + .duration(0) // + .source(Source.USER) + + // TODO fix + activePlugin.activeTreatments.addToHistoryTempBasal(tempBasal) + PumpEnactResult(injector).success(true).enacted(true) // + .isTempCancel(true) + } else { + aapsLogger.info(LTag.PUMP, logPrefix + "cancelTempBasal - Cancel TBR failed.") + PumpEnactResult(injector).success(response).enacted(response) // + .comment(R.string.medtronic_cmd_cant_cancel_tbr) + } + } + + override fun manufacturer(): ManufacturerType { + return pumpDescription.pumpType.manufacturer!! + } + + override fun model(): PumpType { + return pumpDescription.pumpType + } + + override fun serialNumber(): String { + return medtronicPumpStatus.serialNumber!! + } + + override fun setNewBasalProfile(profile: Profile): PumpEnactResult { + aapsLogger.info(LTag.PUMP, logPrefix + "setNewBasalProfile") + + // this shouldn't be needed, but let's do check if profile setting we are setting is same as current one + if (isProfileSame(profile)) { + return PumpEnactResult(injector) // + .success(true) // + .enacted(false) // + .comment(R.string.medtronic_cmd_basal_profile_not_set_is_same) + } + setRefreshButtonEnabled(false) + if (isPumpNotReachable) { + setRefreshButtonEnabled(true) + return PumpEnactResult(injector) // + .success(false) // + .enacted(false) // + .comment(R.string.medtronic_pump_status_pump_unreachable) + } + medtronicUtil.dismissNotification(MedtronicNotificationType.PumpUnreachable, rxBus) + val basalProfile = convertProfileToMedtronicProfile(profile) + aapsLogger.debug("Basal Profile: $basalProfile") + val profileInvalid = isProfileValid(basalProfile) + if (profileInvalid != null) { + return PumpEnactResult(injector) // + .success(false) // + .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 response = responseTask.result as Boolean? + aapsLogger.info(LTag.PUMP, logPrefix + "Basal Profile was set: " + response) + return if (response!!) { + PumpEnactResult(injector).success(true).enacted(true) + } else { + PumpEnactResult(injector).success(response).enacted(response) // + .comment(R.string.medtronic_cmd_basal_profile_could_not_be_set) + } + } + + private fun isProfileValid(basalProfile: BasalProfile): String? { + val stringBuilder = StringBuilder() + if (medtronicPumpStatus.maxBasal == null) return null + for (profileEntry in basalProfile.entries) { + if (profileEntry.rate > medtronicPumpStatus.maxBasal!!) { + stringBuilder.append(profileEntry.startTime!!.toString("HH:mm")) + stringBuilder.append("=") + stringBuilder.append(profileEntry.rate) + } + } + return if (stringBuilder.length == 0) null else stringBuilder.toString() + } + + private fun convertProfileToMedtronicProfile(profile: Profile): BasalProfile { + val basalProfile = BasalProfile(aapsLogger) + for (i in 0..23) { + val rate = profile.getBasalTimeFromMidnight(i * 60 * 60) + val v = pumpDescription.pumpType.determineCorrectBasalSize(rate) + val basalEntry = BasalProfileEntry(v, i, 0) + basalProfile.addEntry(basalEntry) + } + basalProfile.generateRawDataFromEntries() + return basalProfile + } + + // OPERATIONS not supported by Pump or Plugin + private var customActions: List? = null + private val customActionWakeUpAndTune = CustomAction(R.string.medtronic_custom_action_wake_and_tune, + MedtronicCustomActionType.WakeUpAndTune) + private val customActionClearBolusBlock = CustomAction( + R.string.medtronic_custom_action_clear_bolus_block, MedtronicCustomActionType.ClearBolusBlock, false) + private val customActionResetRLConfig = CustomAction( + R.string.medtronic_custom_action_reset_rileylink, MedtronicCustomActionType.ResetRileyLinkConfiguration, true) + + override fun getCustomActions(): List? { + if (customActions == null) { + customActions = Arrays.asList(customActionWakeUpAndTune, // + customActionClearBolusBlock, // + customActionResetRLConfig) + } + return customActions + } + + override fun executeCustomAction(customActionType: CustomActionType) { + val mcat = customActionType as MedtronicCustomActionType + when (mcat) { + MedtronicCustomActionType.WakeUpAndTune -> { + if (rileyLinkMedtronicService!!.verifyConfiguration()) { + serviceTaskExecutor.startTask(WakeAndTuneTask(injector)) + } else { + runAlarm(context, resourceHelper.gs(R.string.medtronic_error_operation_not_possible_no_configuration), resourceHelper.gs(R.string.medtronic_warning), R.raw.boluserror) + } + } + + MedtronicCustomActionType.ClearBolusBlock -> { + busyTimestamps.clear() + customActionClearBolusBlock.isEnabled = false + refreshCustomActionsList() + } + + MedtronicCustomActionType.ResetRileyLinkConfiguration -> { + serviceTaskExecutor.startTask(ResetRileyLinkConfigurationTask(injector)) + } + + else -> { + } + } + } + + override fun timezoneOrDSTChanged(changeType: TimeChangeType) { + aapsLogger.warn(LTag.PUMP, logPrefix + "Time or TimeZone changed. ") + hasTimeDateOrTimeZoneChanged = true + } + + override fun setNeutralTempAtFullHour(): Boolean { + return sp.getBoolean(R.string.key_set_neutral_temps, true) + } + + private fun setEnableCustomAction(customAction: MedtronicCustomActionType, isEnabled: Boolean) { + if (customAction === MedtronicCustomActionType.ClearBolusBlock) { + customActionClearBolusBlock.isEnabled = isEnabled + } else if (customAction === MedtronicCustomActionType.ResetRileyLinkConfiguration) { + customActionResetRLConfig.isEnabled = isEnabled + } + refreshCustomActionsList() + } + + companion object { + var isBusy = false + } + + init { + displayConnectionMessages = false + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicCommunicationManager.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicCommunicationManager.java index 7773f28ba7..4e855dafa3 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicCommunicationManager.java +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicCommunicationManager.java @@ -599,6 +599,44 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager } + private T sendAndGetResponseWithCheck(MedtronicCommandType commandType, byte[] bodyData, Class clazz) { + + aapsLogger.debug(LTag.PUMPCOMM, "getDataFromPump: " + commandType); + + for (int retries = 0; retries < MAX_COMMAND_TRIES; retries++) { + + try { + PumpMessage response = sendAndGetResponse(commandType, bodyData, DEFAULT_TIMEOUT + (DEFAULT_TIMEOUT * retries)); + + String check = checkResponseContent(response, commandType.getCommandDescription(), commandType.getExpectedLength()); + + if (check == null) { + + T dataResponse = (T)medtronicConverter.convertResponse(medtronicPumpPlugin.getPumpDescription().getPumpType(), commandType, response.getRawContent()); + + if (dataResponse != null) { + this.errorMessage = null; + aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Converted response for %s is %s.", commandType.name(), dataResponse)); + + return dataResponse; + } else { + this.errorMessage = "Error decoding response."; + } + } else { + this.errorMessage = check; + // return null; + } + + } catch (RileyLinkCommunicationException e) { + aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Error getting response from RileyLink (error=%s, retry=%d)", e.getMessage(), retries + 1)); + } + + } + + return null; + } + + private String checkResponseContent(PumpMessage response, String method, int expectedLength) { if (!response.isValid()) { 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 489e2b2c36..92720b72f2 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 @@ -32,7 +32,8 @@ class BasalProfile { private val aapsLogger: AAPSLogger - @Expose var rawData : ByteArray? = null // store as byte array to make transport (via parcel) easier + @Expose + lateinit var rawData : ByteArray // store as byte array to make transport (via parcel) easier private set private var listEntries: MutableList? = null @@ -48,14 +49,11 @@ class BasalProfile { } fun init() { - rawData = ByteArray(MAX_RAW_DATA_SIZE) - rawData!![0] = 0 - rawData!![1] = 0 - rawData!![2] = 0x3f + rawData = byteArrayOf(0,0,0x3f) } private fun setRawData(data: ByteArray): Boolean { - var dataInternal: ByteArray? = data + var dataInternal: ByteArray = data if (dataInternal == null) { aapsLogger.error(LTag.PUMPCOMM, "setRawData: buffer is null!") return false @@ -81,17 +79,16 @@ class BasalProfile { return false } rawData = ByteArray(MAX_RAW_DATA_SIZE) - val item = 0 var i = 0 while (i < data.size - 2) { if (data[i] == 0.toByte() && data[i + 1] == 0.toByte() && data[i + 2] == 0.toByte()) { - rawData!![i] = 0 - rawData!![i + 1] = 0 - rawData!![i + 2] = 0 + rawData[i] = 0 + rawData[i + 1] = 0 + rawData[i + 2] = 0 } - rawData!![i] = data[i + 1] - rawData!![i + 1] = data[i + 2] - rawData!![i + 2] = data[i] + rawData[i] = data[i + 1] + rawData[i + 1] = data[i + 2] + rawData[i + 2] = data[i] i += 3 } return true @@ -306,7 +303,7 @@ class BasalProfile { } @JvmStatic - fun getProfilesByHourToString(data: Array): String { + fun getProfilesByHourToString(data: Array): String { val stringBuilder = StringBuilder() for (value in data) { stringBuilder.append(String.format("%.3f", value)) diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/MedtronicHistoryActivity.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/MedtronicHistoryActivity.java deleted file mode 100644 index fc986f4f83..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/MedtronicHistoryActivity.java +++ /dev/null @@ -1,250 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.dialog; - -import android.os.Bundle; -import android.os.SystemClock; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.Spinner; -import android.widget.TextView; - -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - -import java.util.ArrayList; -import java.util.List; - -import javax.inject.Inject; - -import info.nightscout.androidaps.activities.NoSplashAppCompatActivity; -import info.nightscout.androidaps.plugins.pump.common.defs.PumpHistoryEntryGroup; -import info.nightscout.androidaps.plugins.pump.medtronic.R; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntry; -import info.nightscout.androidaps.plugins.pump.medtronic.data.MedtronicHistoryData; -import info.nightscout.androidaps.utils.resources.ResourceHelper; - - -public class MedtronicHistoryActivity extends NoSplashAppCompatActivity { - - @Inject MedtronicHistoryData medtronicHistoryData; - @Inject ResourceHelper resourceHelper; - - Spinner historyTypeSpinner; - TextView statusView; - RecyclerView recyclerView; - LinearLayoutManager llm; - - static TypeList showingType = null; - static PumpHistoryEntryGroup selectedGroup = PumpHistoryEntryGroup.All; - List filteredHistoryList = new ArrayList<>(); - - RecyclerViewAdapter recyclerViewAdapter; - boolean manualChange = false; - - List typeListFull; - - - private void filterHistory(PumpHistoryEntryGroup group) { - - this.filteredHistoryList.clear(); - - List list = new ArrayList<>(); - list.addAll(medtronicHistoryData.getAllHistory()); - - //LOG.debug("Items on full list: {}", list.size()); - - if (group == PumpHistoryEntryGroup.All) { - this.filteredHistoryList.addAll(list); - } else { - for (PumpHistoryEntry pumpHistoryEntry : list) { - if (pumpHistoryEntry.getEntryType().getGroup() == group) { - this.filteredHistoryList.add(pumpHistoryEntry); - } - } - } - - if (this.recyclerViewAdapter != null) { - this.recyclerViewAdapter.setHistoryList(this.filteredHistoryList); - this.recyclerViewAdapter.notifyDataSetChanged(); - } - - //LOG.debug("Items on filtered list: {}", filteredHistoryList.size()); - } - - - @Override - protected void onResume() { - super.onResume(); - filterHistory(selectedGroup); - setHistoryTypeSpinner(); - } - - - private void setHistoryTypeSpinner() { - this.manualChange = true; - - for (int i = 0; i < typeListFull.size(); i++) { - if (typeListFull.get(i).entryGroup == selectedGroup) { - historyTypeSpinner.setSelection(i); - break; - } - } - - SystemClock.sleep(200); - this.manualChange = false; - } - - - @Override - protected void onPause() { - super.onPause(); - } - - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.medtronic_history_activity); - - historyTypeSpinner = findViewById(R.id.medtronic_historytype); - statusView = findViewById(R.id.medtronic_historystatus); - recyclerView = findViewById(R.id.medtronic_history_recyclerview); - - recyclerView.setHasFixedSize(true); - llm = new LinearLayoutManager(this); - recyclerView.setLayoutManager(llm); - - recyclerViewAdapter = new RecyclerViewAdapter(filteredHistoryList); - recyclerView.setAdapter(recyclerViewAdapter); - - statusView.setVisibility(View.GONE); - - typeListFull = getTypeList(PumpHistoryEntryGroup.getTranslatedList(resourceHelper)); - - ArrayAdapter spinnerAdapter = new ArrayAdapter<>(this, R.layout.spinner_centered, typeListFull); - historyTypeSpinner.setAdapter(spinnerAdapter); - - historyTypeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { - - @Override - public void onItemSelected(AdapterView parent, View view, int position, long id) { - if (manualChange) - return; - TypeList selected = (TypeList) historyTypeSpinner.getSelectedItem(); - showingType = selected; - selectedGroup = selected.entryGroup; - filterHistory(selectedGroup); - } - - - @Override - public void onNothingSelected(AdapterView parent) { - if (manualChange) - return; - filterHistory(PumpHistoryEntryGroup.All); - } - }); - - } - - - private List getTypeList(List list) { - - ArrayList typeList = new ArrayList<>(); - - for (PumpHistoryEntryGroup pumpHistoryEntryGroup : list) { - typeList.add(new TypeList(pumpHistoryEntryGroup)); - } - - return typeList; - } - - public static class TypeList { - - PumpHistoryEntryGroup entryGroup; - String name; - - - TypeList(PumpHistoryEntryGroup entryGroup) { - this.entryGroup = entryGroup; - this.name = entryGroup.getTranslated(); - } - - - @Override - public String toString() { - return name; - } - } - - public static class RecyclerViewAdapter extends RecyclerView.Adapter { - - List historyList; - - - RecyclerViewAdapter(List historyList) { - this.historyList = historyList; - } - - - public void setHistoryList(List historyList) { - // this.historyList.clear(); - // this.historyList.addAll(historyList); - - this.historyList = historyList; - - // this.notifyDataSetChanged(); - } - - - @Override - public HistoryViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { - View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.medtronic_history_item, // - viewGroup, false); - return new HistoryViewHolder(v); - } - - - @Override - public void onBindViewHolder(HistoryViewHolder holder, int position) { - PumpHistoryEntry record = historyList.get(position); - - if (record != null) { - holder.timeView.setText(record.getDateTimeString()); - holder.typeView.setText(record.getEntryType().getDescription()); - holder.valueView.setText(record.getDisplayableValue()); - } - } - - - @Override - public int getItemCount() { - return historyList.size(); - } - - - @Override - public void onAttachedToRecyclerView(RecyclerView recyclerView) { - super.onAttachedToRecyclerView(recyclerView); - } - - static class HistoryViewHolder extends RecyclerView.ViewHolder { - - TextView timeView; - TextView typeView; - TextView valueView; - - - HistoryViewHolder(View itemView) { - super(itemView); - // cv = (CardView)itemView.findViewById(R.id.rileylink_history_item); - timeView = itemView.findViewById(R.id.medtronic_history_time); - typeView = itemView.findViewById(R.id.medtronic_history_source); - valueView = itemView.findViewById(R.id.medtronic_history_description); - } - } - } - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/MedtronicHistoryActivity.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/MedtronicHistoryActivity.kt new file mode 100644 index 0000000000..e5a047ab97 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/MedtronicHistoryActivity.kt @@ -0,0 +1,200 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.dialog + +import android.os.Bundle +import android.os.SystemClock +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.AdapterView +import android.widget.ArrayAdapter +import android.widget.Spinner +import android.widget.TextView +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import dagger.android.DaggerActivity +import dagger.android.DispatchingAndroidInjector +import info.nightscout.androidaps.plugins.pump.common.defs.PumpHistoryEntryGroup +import info.nightscout.androidaps.plugins.pump.common.defs.PumpHistoryEntryGroup.Companion.getTranslatedList +import info.nightscout.androidaps.plugins.pump.medtronic.R +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntry +import info.nightscout.androidaps.plugins.pump.medtronic.data.MedtronicHistoryData +import info.nightscout.androidaps.plugins.pump.medtronic.databinding.MedtronicHistoryActivityBinding +import info.nightscout.androidaps.utils.resources.ResourceHelper +import java.util.* +import javax.inject.Inject + +class MedtronicHistoryActivity : DaggerActivity() { + + @Inject lateinit var medtronicHistoryData: MedtronicHistoryData + @Inject lateinit var resourceHelper: ResourceHelper + + lateinit var historyTypeSpinner: Spinner + lateinit var statusView: TextView + lateinit var recyclerView: RecyclerView + lateinit var llm: LinearLayoutManager + lateinit var recyclerViewAdapter: RecyclerViewAdapter + + var filteredHistoryList: MutableList = ArrayList() + var manualChange = false + var typeListFull: List? = null + + private var _binding: MedtronicHistoryActivityBinding? = null + + //@Inject + //var fragmentInjector: DispatchingAndroidInjector? = null + + // This property is only valid between onCreateView and + // onDestroyView. + private val binding get() = _binding!! + + private fun filterHistory(group: PumpHistoryEntryGroup) { + filteredHistoryList.clear() + val list: MutableList = ArrayList() + list.addAll(medtronicHistoryData.allHistory) + + //LOG.debug("Items on full list: {}", list.size()); + if (group === PumpHistoryEntryGroup.All) { + filteredHistoryList.addAll(list) + } else { + for (pumpHistoryEntry in list) { + if (pumpHistoryEntry.entryType!!.group === group) { + filteredHistoryList.add(pumpHistoryEntry) + } + } + } + + recyclerViewAdapter.setHistoryListInternal(filteredHistoryList) + recyclerViewAdapter.notifyDataSetChanged() + + //LOG.debug("Items on filtered list: {}", filteredHistoryList.size()); + } + + override fun onResume() { + super.onResume() + filterHistory(selectedGroup) + setHistoryTypeSpinner() + } + + private fun setHistoryTypeSpinner() { + manualChange = true + for (i in typeListFull!!.indices) { + if (typeListFull!![i].entryGroup === selectedGroup) { + historyTypeSpinner.setSelection(i) + break + } + } + SystemClock.sleep(200) + manualChange = false + } + + override fun onPause() { + super.onPause() + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + //setContentView(R.layout.medtronic_history_activity) + + _binding = MedtronicHistoryActivityBinding.inflate(getLayoutInflater()) //(inflater, container, false) + + historyTypeSpinner = binding.medtronicHistorytype //findViewById(R.id.medtronic_historytype) + statusView = binding.medtronicHistorystatus //findViewById(R.id.medtronic_historystatus) + recyclerView = binding.medtronicHistoryRecyclerview //findViewById(R.id.medtronic_history_recyclerview) + recyclerView.setHasFixedSize(true) + llm = LinearLayoutManager(this) + recyclerView.setLayoutManager(llm) + recyclerViewAdapter = RecyclerViewAdapter(filteredHistoryList) + recyclerView.setAdapter(recyclerViewAdapter) + statusView.setVisibility(View.GONE) + typeListFull = getTypeList(getTranslatedList(resourceHelper!!)) + val spinnerAdapter = ArrayAdapter(this, R.layout.spinner_centered, typeListFull) + historyTypeSpinner.setAdapter(spinnerAdapter) + historyTypeSpinner.setOnItemSelectedListener(object : AdapterView.OnItemSelectedListener { + override fun onItemSelected(parent: AdapterView<*>?, view: View, position: Int, id: Long) { + if (manualChange) return + val selected = historyTypeSpinner.getSelectedItem() as TypeList + showingType = selected + selectedGroup = selected.entryGroup + filterHistory(selectedGroup) + } + + override fun onNothingSelected(parent: AdapterView<*>?) { + if (manualChange) return + filterHistory(PumpHistoryEntryGroup.All) + } + }) + } + + private fun getTypeList(list: List?): List { + val typeList = ArrayList() + for (pumpHistoryEntryGroup in list!!) { + typeList.add(TypeList(pumpHistoryEntryGroup)) + } + return typeList + } + + class TypeList internal constructor(var entryGroup: PumpHistoryEntryGroup) { + var name: String + override fun toString(): String { + return name + } + + init { + name = entryGroup.translated!! + } + } + + class RecyclerViewAdapter internal constructor(var historyList: List) : RecyclerView.Adapter() { + + + fun setHistoryListInternal(historyList: List) { + // this.historyList.clear(); + // this.historyList.addAll(historyList); + this.historyList = historyList + + // this.notifyDataSetChanged(); + } + + override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): HistoryViewHolder { + val v = LayoutInflater.from(viewGroup.context).inflate(R.layout.medtronic_history_item, // + viewGroup, false) + return HistoryViewHolder(v) + } + + override fun onBindViewHolder(holder: HistoryViewHolder, position: Int) { + val record = historyList[position] + if (record != null) { + holder.timeView.text = record.dateTimeString + holder.typeView.text = record.entryType!!.description + holder.valueView.text = record.displayableValue + } + } + + override fun getItemCount(): Int { + return historyList.size + } + + override fun onAttachedToRecyclerView(recyclerView: RecyclerView) { + super.onAttachedToRecyclerView(recyclerView) + } + + class HistoryViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + var timeView: TextView + var typeView: TextView + var valueView: TextView + + init { + // cv = (CardView)itemView.findViewById(R.id.rileylink_history_item); + timeView = itemView.findViewById(R.id.medtronic_history_time) + typeView = itemView.findViewById(R.id.medtronic_history_source) + valueView = itemView.findViewById(R.id.medtronic_history_description) + } + } + + } + + companion object { + var showingType: TypeList? = null + var selectedGroup = PumpHistoryEntryGroup.All + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/RileyLinkStatusDeviceMedtronic.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/RileyLinkStatusDeviceMedtronic.java deleted file mode 100644 index e4b6c0e13a..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/RileyLinkStatusDeviceMedtronic.java +++ /dev/null @@ -1,166 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.dialog; - -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.BaseAdapter; -import android.widget.ListView; -import android.widget.TextView; - -import java.util.ArrayList; -import java.util.List; - -import javax.inject.Inject; - -import dagger.android.support.DaggerFragment; -import info.nightscout.androidaps.plugins.pump.common.dialog.RefreshableInterface; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.data.RLHistoryItem; -import info.nightscout.androidaps.plugins.pump.common.utils.StringUtil; -import info.nightscout.androidaps.plugins.pump.medtronic.R; -import info.nightscout.androidaps.utils.DateUtil; -import info.nightscout.androidaps.utils.resources.ResourceHelper; - -/** - * Created by andy on 5/19/18. - *

- * This is for 3rd tab, called Medtronic (in RileyLink stats), that should work similarly as the one in Loop. - *

- * Showing currently selected RL, speed of RL, ability to issue simple commands (getModel, tuneUp, gerProfile) - */ - -// TODO needs to be implemented -public class RileyLinkStatusDeviceMedtronic extends DaggerFragment implements RefreshableInterface { - - @Inject ResourceHelper resourceHelper; - @Inject DateUtil dateUtil; - - // @BindView(R.id.rileylink_history_list) - ListView listView; - - RileyLinkCommandListAdapter adapter; - - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View rootView = inflater.inflate(R.layout.rileylink_status_device, container, false); - - adapter = new RileyLinkCommandListAdapter(); - - return rootView; - } - - - @Override - public void onStart() { - super.onStart(); - - this.listView = getActivity().findViewById(R.id.rileylink_history_list); - - listView.setAdapter(adapter); - - refreshData(); - } - - - @Override - public void refreshData() { - // adapter.addItemsAndClean(RileyLinkUtil.getRileyLinkHistory()); - } - - static class ViewHolder { - - TextView itemTime; - TextView itemSource; - TextView itemDescription; - } - - private class RileyLinkCommandListAdapter extends BaseAdapter { - - private final List historyItemList; - private final LayoutInflater mInflator; - - - public RileyLinkCommandListAdapter() { - super(); - historyItemList = new ArrayList<>(); - mInflator = RileyLinkStatusDeviceMedtronic.this.getLayoutInflater(); - } - - - public void addItem(RLHistoryItem item) { - if (!historyItemList.contains(item)) { - historyItemList.add(item); - notifyDataSetChanged(); - } - } - - - public RLHistoryItem getHistoryItem(int position) { - return historyItemList.get(position); - } - - - public void addItemsAndClean(List items) { - this.historyItemList.clear(); - - for (RLHistoryItem item : items) { - - if (!historyItemList.contains(item)) { - historyItemList.add(item); - } - } - - notifyDataSetChanged(); - } - - - public void clear() { - historyItemList.clear(); - notifyDataSetChanged(); - } - - - @Override - public int getCount() { - return historyItemList.size(); - } - - - @Override - public Object getItem(int i) { - return historyItemList.get(i); - } - - - @Override - public long getItemId(int i) { - return i; - } - - - @Override - public View getView(int i, View view, ViewGroup viewGroup) { - RileyLinkStatusDeviceMedtronic.ViewHolder viewHolder; - // General ListView optimization code. - if (view == null) { - view = mInflator.inflate(R.layout.rileylink_status_device_item, null); - viewHolder = new RileyLinkStatusDeviceMedtronic.ViewHolder(); - viewHolder.itemTime = view.findViewById(R.id.rileylink_history_time); - viewHolder.itemSource = view.findViewById(R.id.rileylink_history_source); - viewHolder.itemDescription = view.findViewById(R.id.rileylink_history_description); - view.setTag(viewHolder); - } else { - viewHolder = (RileyLinkStatusDeviceMedtronic.ViewHolder) view.getTag(); - } - - RLHistoryItem item = historyItemList.get(i); - viewHolder.itemTime.setText(StringUtil.toDateTimeString(dateUtil, item.getDateTime())); - viewHolder.itemSource.setText("Riley Link"); // for now - viewHolder.itemDescription.setText(item.getDescription(resourceHelper)); - - return view; - } - } - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/RileyLinkStatusDeviceMedtronic.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/RileyLinkStatusDeviceMedtronic.kt new file mode 100644 index 0000000000..b753ac5795 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/RileyLinkStatusDeviceMedtronic.kt @@ -0,0 +1,137 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.dialog + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.BaseAdapter +import android.widget.ListView +import android.widget.TextView +import dagger.android.support.DaggerFragment +import info.nightscout.androidaps.plugins.pump.common.dialog.RefreshableInterface +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.data.RLHistoryItem +import info.nightscout.androidaps.plugins.pump.common.utils.StringUtil +import info.nightscout.androidaps.plugins.pump.medtronic.R +import info.nightscout.androidaps.utils.DateUtil +import info.nightscout.androidaps.utils.resources.ResourceHelper +import io.reactivex.disposables.CompositeDisposable +import java.util.* +import javax.inject.Inject + +/** + * Created by andy on 5/19/18. + * NOTE: This class is not used yet, so it has no Bindings + * + * This is for 3rd tab, called Medtronic (in RileyLink stats), that should work similarly as the one in Loop. + * + * + * Showing currently selected RL, speed of RL, ability to issue simple commands (getModel, tuneUp, gerProfile) + */ +// TODO needs to be implemented +class RileyLinkStatusDeviceMedtronic : DaggerFragment(), RefreshableInterface { + + @Inject lateinit var resourceHelper: ResourceHelper + @Inject lateinit var dateUtil: DateUtil + + var listView: ListView? = null + var adapter: RileyLinkCommandListAdapter? = null + + private var disposable: CompositeDisposable = CompositeDisposable() + //private var _binding: RileyLinkStatusDeviceBinding? = null + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + + // _binding = LoopFragmentBinding.inflate(inflater, container, false) + // return binding.root + + + val rootView = inflater.inflate(R.layout.rileylink_status_device, container, false) + adapter = RileyLinkCommandListAdapter() + return rootView + } + + override fun onStart() { + super.onStart() + //listView = activity!!.findViewById(R.id.rileylink_history_list) + //listView.setAdapter(adapter) + refreshData() + } + + override fun refreshData() { + // adapter.addItemsAndClean(RileyLinkUtil.getRileyLinkHistory()); + } + + internal class ViewHolder { + var itemTime: TextView? = null + var itemSource: TextView? = null + var itemDescription: TextView? = null + } + + inner class RileyLinkCommandListAdapter : BaseAdapter() { + private val historyItemList: MutableList + private val mInflator: LayoutInflater + fun addItem(item: RLHistoryItem) { + if (!historyItemList.contains(item)) { + historyItemList.add(item) + notifyDataSetChanged() + } + } + + fun getHistoryItem(position: Int): RLHistoryItem { + return historyItemList[position] + } + + fun addItemsAndClean(items: List) { + historyItemList.clear() + for (item in items) { + if (!historyItemList.contains(item)) { + historyItemList.add(item) + } + } + notifyDataSetChanged() + } + + fun clear() { + historyItemList.clear() + notifyDataSetChanged() + } + + override fun getCount(): Int { + return historyItemList.size + } + + override fun getItem(i: Int): Any { + return historyItemList[i] + } + + override fun getItemId(i: Int): Long { + return i.toLong() + } + + override fun getView(i: Int, view: View, viewGroup: ViewGroup): View { + var view = view + val viewHolder: ViewHolder + // General ListView optimization code. + if (view == null) { + view = mInflator.inflate(R.layout.rileylink_status_device_item, null) + viewHolder = ViewHolder() + viewHolder.itemTime = view.findViewById(R.id.rileylink_history_time) + viewHolder.itemSource = view.findViewById(R.id.rileylink_history_source) + viewHolder.itemDescription = view.findViewById(R.id.rileylink_history_description) + view.tag = viewHolder + } else { + viewHolder = view.tag as ViewHolder + } + val item = historyItemList[i] + viewHolder.itemTime!!.text = StringUtil.toDateTimeString(dateUtil, item.dateTime) + viewHolder.itemSource!!.text = "Riley Link" // for now + viewHolder.itemDescription!!.text = item.getDescription(resourceHelper) + return view + } + + init { + historyItemList = ArrayList() + mInflator = this@RileyLinkStatusDeviceMedtronic.layoutInflater + } + } +} \ No newline at end of file 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 89a31552d2..205742a336 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 @@ -49,6 +49,7 @@ class RileyLinkMedtronicService // This empty constructor must be kept, otherwi private var encodingType: RileyLinkEncodingType? = null private var encodingChanged = false private var inPreInit = true + override fun onCreate() { super.onCreate() aapsLogger.debug(LTag.PUMPCOMM, "RileyLinkMedtronicService newly created") @@ -267,19 +268,19 @@ class RileyLinkMedtronicService // This empty constructor must be kept, otherwi } private fun checkParameterValue(key: Int, defaultValue: String, defaultValueDouble: Double): Double { - var `val`: Double + var valueDouble: Double val value = sp.getString(key, defaultValue) - `val` = try { + valueDouble = try { value.toDouble() } catch (ex: Exception) { aapsLogger.error("Error parsing setting: %s, value found %s", key, value) defaultValueDouble } - if (`val` > defaultValueDouble) { + if (valueDouble > defaultValueDouble) { sp.putString(key, defaultValue) - `val` = defaultValueDouble + valueDouble = defaultValueDouble } - return `val` + return valueDouble } fun setNotInPreInit(): Boolean { diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpHistoryEntryGroup.kt b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpHistoryEntryGroup.kt index 8b856d7036..8c7cbafada 100644 --- a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpHistoryEntryGroup.kt +++ b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpHistoryEntryGroup.kt @@ -33,6 +33,7 @@ enum class PumpHistoryEntryGroup(val resourceId: Int) { companion object { private var translatedList: MutableList? = null + private fun doTranslation(resourceHelper: ResourceHelper) { translatedList = ArrayList() for (pumpHistoryEntryGroup in values()) { @@ -41,7 +42,8 @@ enum class PumpHistoryEntryGroup(val resourceId: Int) { } } - @JvmStatic fun getTranslatedList(resourceHelper: ResourceHelper): List? { + @JvmStatic + fun getTranslatedList(resourceHelper: ResourceHelper): List? { if (translatedList == null) doTranslation(resourceHelper) return translatedList } diff --git a/rileylink/src/main/res/layout/rileylink_status_device.xml b/rileylink/src/main/res/layout/rileylink_status_device.xml index edf3cbdd7e..f56c4b0d6d 100644 --- a/rileylink/src/main/res/layout/rileylink_status_device.xml +++ b/rileylink/src/main/res/layout/rileylink_status_device.xml @@ -2,7 +2,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".plugins.pump.common.hw.rileylink.dialog.RileyLinkStatusDevice"> + tools:context=".plugins.pump.medtronic.dialog.RileyLinkStatusDevice"> Date: Tue, 20 Apr 2021 23:23:03 +0100 Subject: [PATCH 009/145] - kotlin changes almost done, 1 file left --- .../plugins/treatments/TreatmentsPlugin.java | 57 +- medtronic/build.gradle | 3 + .../plugins/pump/common/PumpPluginAbstract.kt | 11 +- .../pump/medtronic/MedtronicFragment.kt | 1 - .../pump/medtronic/MedtronicPumpPlugin.kt | 14 +- .../comm/MedtronicCommunicationManager.java | 956 ------------------ .../comm/MedtronicCommunicationManager.kt | 664 ++++++++++++ .../comm/history/MedtronicHistoryDecoder.kt | 4 +- .../cgms/MedtronicCGMSHistoryDecoder.kt | 5 +- .../pump/MedtronicPumpHistoryDecoder.kt | 13 +- .../comm/history/pump/PumpHistoryEntry.kt | 8 +- .../comm/history/pump/PumpHistoryResult.kt | 4 +- .../pump/medtronic/comm/ui/MedtronicUITask.kt | 25 +- .../pump/medtronic/data/dto/BasalProfile.kt | 59 +- .../dialog/MedtronicHistoryActivity.kt | 21 +- .../dialog/RileyLinkStatusDeviceMedtronic.kt | 4 +- .../service/RileyLinkMedtronicService.kt | 1 + .../pump/medtronic/util/MedtronicUtil.kt | 4 +- 18 files changed, 793 insertions(+), 1061 deletions(-) delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicCommunicationManager.java create mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicCommunicationManager.kt diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java index 94673a29b6..c795ea4050 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java @@ -1,10 +1,13 @@ package info.nightscout.androidaps.plugins.treatments; import android.content.Context; +import android.os.Bundle; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.google.firebase.analytics.FirebaseAnalytics; + import java.util.List; import java.util.stream.Collectors; @@ -14,9 +17,11 @@ import javax.inject.Singleton; import dagger.android.HasAndroidInjector; import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.R; +import info.nightscout.androidaps.activities.ErrorHelperActivity; import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.ProfileIntervals; import info.nightscout.androidaps.database.AppRepository; +import info.nightscout.androidaps.database.embedments.InterfaceIDs; import info.nightscout.androidaps.db.ExtendedBolus; import info.nightscout.androidaps.db.ProfileSwitch; import info.nightscout.androidaps.db.Source; @@ -32,12 +37,16 @@ import info.nightscout.androidaps.interfaces.ProfileFunction; import info.nightscout.androidaps.interfaces.ProfileStore; import info.nightscout.androidaps.interfaces.TreatmentServiceInterface; import info.nightscout.androidaps.interfaces.TreatmentsInterface; +import info.nightscout.androidaps.interfaces.UpdateReturn; import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.general.nsclient.NSUpload; import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification; import info.nightscout.androidaps.plugins.general.overview.notifications.Notification; +import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; +import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicPumpPlugin; +import info.nightscout.androidaps.plugins.pump.medtronic.data.MedtronicHistoryData; import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.FabricPrivacy; import info.nightscout.androidaps.utils.resources.ResourceHelper; @@ -67,6 +76,10 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface private final ProfileIntervals profiles = new ProfileIntervals<>(); + private final boolean useNewPumpSync = false; + + + @Inject public TreatmentsPlugin( HasAndroidInjector injector, @@ -245,38 +258,48 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface @Deprecated @Override public boolean addToHistoryTempBasal(TemporaryBasal tempBasal) { - throw new IllegalStateException("Migrate to new DB"); -/* + if (useNewPumpSync) { + throw new IllegalStateException("Migrate to new DB"); + } else { + getAapsLogger().error("!!! addToHistoryTempBasal: Need to migrate to new DB"); + } + //log.debug("Adding new TemporaryBasal record" + tempBasal.toString()); boolean newRecordCreated = databaseHelper.createOrUpdate(tempBasal); if (newRecordCreated) { - if (tempBasal.durationInMinutes == 0) - nsUpload.uploadTempBasalEnd(tempBasal.date, false, tempBasal.pumpId); - else if (tempBasal.isAbsolute) - nsUpload.uploadTempBasalStartAbsolute(tempBasal, null); - else - nsUpload.uploadTempBasalStartPercent(tempBasal, profileFunction.getProfile(tempBasal.date)); +// if (tempBasal.durationInMinutes == 0) +// nsUpload.uploadTempBasalEnd(tempBasal.date, false, tempBasal.pumpId); +// else if (tempBasal.isAbsolute) +// nsUpload.uploadTempBasalStartAbsolute(tempBasal, null); +// else +// nsUpload.uploadTempBasalStartPercent(tempBasal, profileFunction.getProfile(tempBasal.date)); } return newRecordCreated; - */ } @Deprecated public TreatmentUpdateReturn createOrUpdateMedtronic(Treatment treatment, boolean fromNightScout) { - throw new IllegalStateException("Migrate to new DB"); -/* + if (useNewPumpSync) { + throw new IllegalStateException("Migrate to new DB"); + } else { + getAapsLogger().error("!!! createOrUpdateMedtronic: Need to migrate to new DB"); + } + UpdateReturn resultRecord = getService().createOrUpdateMedtronic(treatment, fromNightScout); return new TreatmentUpdateReturn(resultRecord.getSuccess(), resultRecord.getNewRecord()); - */ } // return true if new record is created @Deprecated @Override public boolean addToHistoryTreatment(DetailedBolusInfo detailedBolusInfo, boolean allowUpdate) { - throw new IllegalStateException("Migrate to new DB"); -/* + if (useNewPumpSync) { + throw new IllegalStateException("Migrate to new DB"); + } else { + getAapsLogger().error("!!! addToHistoryTreatment: Need to migrate to new DB"); + } + boolean medtronicPump = activePlugin.getActivePump() instanceof MedtronicPumpPlugin; getAapsLogger().debug(MedtronicHistoryData.doubleBolusDebug, LTag.DATATREATMENTS, "DoubleBolusDebug: addToHistoryTreatment::isMedtronicPump={} " + medtronicPump); @@ -320,8 +343,8 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface getService().createOrUpdateMedtronic(carbsTreatment, false); //log.debug("Adding new Treatment record" + carbsTreatment); } - if (newRecordCreated && detailedBolusInfo.getBolusType() != DetailedBolusInfo.BolusType.PRIMING) - nsUpload.uploadTreatmentRecord(detailedBolusInfo); +// if (newRecordCreated && detailedBolusInfo.getBolusType() != DetailedBolusInfo.BolusType.PRIMING) +// nsUpload.uploadTreatmentRecord(detailedBolusInfo); if (!allowUpdate && !creatOrUpdateResult.getSuccess()) { getAapsLogger().error("Treatment could not be added to DB", new Exception()); @@ -337,7 +360,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface } return newRecordCreated; - */ + } @Override diff --git a/medtronic/build.gradle b/medtronic/build.gradle index a3cb9f789e..0488efd078 100644 --- a/medtronic/build.gradle +++ b/medtronic/build.gradle @@ -12,6 +12,9 @@ android { versionCode 1 versionName "1.0" } + dataBinding { + enabled = true + } } dependencies { diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.kt index 26660c4936..6b7e738929 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.kt @@ -74,11 +74,11 @@ abstract class PumpPluginAbstract protected constructor( @JvmField protected var pumpState = PumpDriverState.NotInitialized @JvmField protected var displayConnectionMessages = false - var pumpType: PumpType? = null + var pumpType: PumpType = PumpType.GENERIC_AAPS get() = field set(value) { field = value - pumpDescription.setPumpDescription(value!!) + pumpDescription.setPumpDescription(value) } @@ -366,11 +366,11 @@ abstract class PumpPluginAbstract protected constructor( } override fun manufacturer(): ManufacturerType { - return pumpType!!.manufacturer!! + return pumpType.manufacturer!! } override fun model(): PumpType { - return pumpType!! + return pumpType } @@ -395,7 +395,7 @@ abstract class PumpPluginAbstract protected constructor( val temporaryId = generateTempId(detailedBolusInfo.timestamp) val response = pumpSync.addBolusWithTempId(detailedBolusInfo.timestamp, detailedBolusInfo.insulin, temporaryId, detailedBolusInfo.bolusType, - pumpType!!, serialNumber()) + pumpType, serialNumber()) if (response && writeToInternalHistory) { driverHistory[temporaryId] = PumpDbEntry(temporaryId, model(), serialNumber(), detailedBolusInfo) sp.putString(MedtronicConst.Statistics.InternalTemporaryDatabase, gson.toJson(driverHistory)) @@ -403,6 +403,7 @@ abstract class PumpPluginAbstract protected constructor( return response } + // TODO protected fun addTemporaryBasalRateWithTempId(temporaryBasal: TemporaryBasal?, b: Boolean) { // long temporaryId = generateTempId(temporaryBasal.timestamp); // boolean response = pumpSync.addBolusWithTempId(temporaryBasal.timestamp, detailedBolusInfo.insulin, diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicFragment.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicFragment.kt index 49b2415264..c9d4009bf7 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicFragment.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicFragment.kt @@ -210,7 +210,6 @@ class MedtronicFragment : DaggerFragment() { } ?: "-" when (medtronicPumpStatus.pumpDeviceState) { - null, PumpDeviceState.Sleeping -> binding.pumpStatusIcon.text = "{fa-bed} " // + pumpStatus.pumpDeviceState.name()); PumpDeviceState.NeverContacted, PumpDeviceState.WakingUp, 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 803f281b45..64bb650744 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 @@ -98,7 +98,7 @@ class MedtronicPumpPlugin @Inject constructor( .preferencesId(R.xml.pref_medtronic) .description(R.string.description_pump_medtronic), // PumpType.MEDTRONIC_522_722, // we default to most basic model, correct model from config is loaded later - injector, resourceHelper, aapsLogger, commandQueue, rxBus, activePlugin, sp, context, fabricPrivacy, dateUtil, aapsSchedulers!!, pumpSync!! + injector, resourceHelper, aapsLogger, commandQueue, rxBus, activePlugin, sp, context, fabricPrivacy, dateUtil, aapsSchedulers, pumpSync ), Pump, RileyLinkPumpDevice { private var rileyLinkMedtronicService: RileyLinkMedtronicService? = null @@ -149,7 +149,7 @@ class MedtronicPumpPlugin @Inject constructor( } private val logPrefix: String - private get() = "MedtronicPumpPlugin::" + get() = "MedtronicPumpPlugin::" override fun initPumpStatusData() { medtronicPumpStatus.lastConnection = sp.getLong(RileyLinkConst.Prefs.LastGoodDeviceCommunicationTime, 0L) @@ -225,7 +225,7 @@ class MedtronicPumpPlugin @Inject constructor( // Pump Plugin private val isServiceSet: Boolean - private get() = rileyLinkMedtronicService != null + get() = rileyLinkMedtronicService != null override fun getRileyLinkService(): RileyLinkMedtronicService? { return rileyLinkMedtronicService @@ -313,7 +313,7 @@ class MedtronicPumpPlugin @Inject constructor( }// private val isPumpNotReachable: Boolean - private get() { + get() { val rileyLinkServiceState = rileyLinkServiceData.rileyLinkServiceState if (rileyLinkServiceState == null) { aapsLogger.debug(LTag.PUMP, "RileyLink unreachable. RileyLinkServiceState is null.") @@ -908,7 +908,7 @@ class MedtronicPumpPlugin @Inject constructor( } private val lastPumpEntryTime: Long - private get() { + get() { val lastPumpEntryTime = sp.getLong(MedtronicConst.Statistics.LastPumpHistoryEntry, 0L) return try { val localDateTime = DateTimeUtil.toLocalDateTime(lastPumpEntryTime) @@ -1085,7 +1085,7 @@ class MedtronicPumpPlugin @Inject constructor( private fun isProfileValid(basalProfile: BasalProfile): String? { val stringBuilder = StringBuilder() if (medtronicPumpStatus.maxBasal == null) return null - for (profileEntry in basalProfile.entries) { + for (profileEntry in basalProfile.getEntries()) { if (profileEntry.rate > medtronicPumpStatus.maxBasal!!) { stringBuilder.append(profileEntry.startTime!!.toString("HH:mm")) stringBuilder.append("=") @@ -1099,7 +1099,7 @@ class MedtronicPumpPlugin @Inject constructor( val basalProfile = BasalProfile(aapsLogger) for (i in 0..23) { val rate = profile.getBasalTimeFromMidnight(i * 60 * 60) - val v = pumpDescription.pumpType.determineCorrectBasalSize(rate) + val v = pumpType.determineCorrectBasalSize(rate) val basalEntry = BasalProfileEntry(v, i, 0) basalProfile.addEntry(basalEntry) } diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicCommunicationManager.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicCommunicationManager.java deleted file mode 100644 index 4e855dafa3..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicCommunicationManager.java +++ /dev/null @@ -1,956 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm; - -import android.os.SystemClock; - -import org.joda.time.LocalDateTime; - -import java.util.Calendar; -import java.util.GregorianCalendar; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -import javax.inject.Inject; -import javax.inject.Singleton; - -import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.plugins.pump.common.defs.PumpDeviceState; -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; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.data.RFSpyResponse; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.data.RadioPacket; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.data.RadioResponse; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.defs.RLMessageType; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.tasks.WakeAndTuneTask; -import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil; -import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil; -import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicPumpPlugin; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.RawHistoryPage; -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.PumpHistoryResult; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.message.CarelinkLongMessageBody; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.message.CarelinkShortMessageBody; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.message.GetHistoryPageCarelinkMessageBody; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.message.MessageBody; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.message.PacketType; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.message.PumpAckMessageBody; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.message.PumpMessage; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BasalProfile; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BatteryStatusDTO; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.ClockDTO; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.PumpSettingDTO; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.TempBasalPair; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicCommandType; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicDeviceType; -import info.nightscout.androidaps.plugins.pump.medtronic.driver.MedtronicPumpStatus; -import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil; - -/** - * Original file created by geoff on 5/30/16. - *

- * Split into 2 implementations, so that we can split it by target device. - Andy - * This was mostly rewritten from Original version, and lots of commands and - * functionality added. - */ -@Singleton -public class MedtronicCommunicationManager extends RileyLinkCommunicationManager { - - @Inject MedtronicPumpStatus medtronicPumpStatus; - @Inject MedtronicPumpPlugin medtronicPumpPlugin; - @Inject MedtronicConverter medtronicConverter; - @Inject MedtronicUtil medtronicUtil; - @Inject MedtronicPumpHistoryDecoder medtronicPumpHistoryDecoder; - - private final int MAX_COMMAND_TRIES = 3; - private final int DEFAULT_TIMEOUT = 2000; - private final long RILEYLINK_TIMEOUT = 15 * 60 * 1000; // 15 min - - private String errorMessage; - private final boolean debugSetCommands = false; - - private boolean doWakeUpBeforeCommand = true; - - // This empty constructor must be kept, otherwise dagger injection might break! - @Inject - public MedtronicCommunicationManager() { - } - - @Inject - public void onInit() { - // we can't do this in the constructor, as sp only gets injected after the constructor has returned - medtronicPumpStatus.setPreviousConnection(sp.getLong( - RileyLinkConst.Prefs.LastGoodDeviceCommunicationTime, 0L)); - } - - @Override - public PumpMessage createResponseMessage(byte[] payload) { - return new PumpMessage(aapsLogger, payload); - } - - @Override - public void setPumpDeviceState(PumpDeviceState pumpDeviceState) { - this.medtronicPumpStatus.setPumpDeviceState(pumpDeviceState); - } - - public void setDoWakeUpBeforeCommand(boolean doWakeUp) { - this.doWakeUpBeforeCommand = doWakeUp; - } - - - @Override - public boolean isDeviceReachable() { - return isDeviceReachable(false); - } - - - /** - * We do actual wakeUp and compare PumpModel with currently selected one. If returned model is - * not Unknown, pump is reachable. - * - * @return - */ - public boolean isDeviceReachable(boolean canPreventTuneUp) { - - PumpDeviceState state = medtronicPumpStatus.getPumpDeviceState(); - - if (state != PumpDeviceState.PumpUnreachable) - medtronicPumpStatus.setPumpDeviceState(PumpDeviceState.WakingUp); - - for (int retry = 0; retry < 5; retry++) { - - aapsLogger.debug(LTag.PUMPCOMM, "isDeviceReachable. Waking pump... " + (retry != 0 ? " (retry " + retry + ")" : "")); - - boolean connected = connectToDevice(); - - if (connected) - return true; - - SystemClock.sleep(1000); - - } - - if (state != PumpDeviceState.PumpUnreachable) - medtronicPumpStatus.setPumpDeviceState(PumpDeviceState.PumpUnreachable); - - if (!canPreventTuneUp) { - - long diff = System.currentTimeMillis() - medtronicPumpStatus.getLastConnection(); - - if (diff > RILEYLINK_TIMEOUT) { - serviceTaskExecutor.startTask(new WakeAndTuneTask(injector)); - } - } - - return false; - } - - - private boolean connectToDevice() { - - PumpDeviceState state = medtronicPumpStatus.getPumpDeviceState(); - - // check connection - - byte[] pumpMsgContent = createPumpMessageContent(RLMessageType.ReadSimpleData); // simple - RFSpyResponse rfSpyResponse = rfspy.transmitThenReceive(new RadioPacket(injector, pumpMsgContent), (byte) 0, (byte) 200, - (byte) 0, (byte) 0, 25000, (byte) 0); - aapsLogger.info(LTag.PUMPCOMM, "wakeup: raw response is " + ByteUtil.shortHexString(rfSpyResponse.getRaw())); - - if (rfSpyResponse.wasTimeout()) { - aapsLogger.error(LTag.PUMPCOMM, "isDeviceReachable. Failed to find pump (timeout)."); - } else if (rfSpyResponse.looksLikeRadioPacket()) { - RadioResponse radioResponse = new RadioResponse(injector); - - try { - - radioResponse.init(rfSpyResponse.getRaw()); - - if (radioResponse.isValid()) { - - PumpMessage pumpResponse = createResponseMessage(radioResponse.getPayload()); - - if (!pumpResponse.isValid()) { - aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Response is invalid ! [interrupted=%b, timeout=%b]", rfSpyResponse.wasInterrupted(), - rfSpyResponse.wasTimeout())); - } else { - - // radioResponse.rssi; - Object dataResponse = medtronicConverter.convertResponse(medtronicPumpPlugin.getPumpDescription().getPumpType(), MedtronicCommandType.PumpModel, - pumpResponse.getRawContent()); - - MedtronicDeviceType pumpModel = (MedtronicDeviceType) dataResponse; - boolean valid = (pumpModel != MedtronicDeviceType.Unknown_Device); - - if (medtronicUtil.getMedtronicPumpModel() == null && valid) { - medtronicUtil.setMedtronicPumpModel(pumpModel); - } - - aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "isDeviceReachable. PumpModel is %s - Valid: %b (rssi=%d)", pumpModel.name(), valid, - radioResponse.rssi)); - - if (valid) { - if (state == PumpDeviceState.PumpUnreachable) - medtronicPumpStatus.setPumpDeviceState(PumpDeviceState.WakingUp); - else - medtronicPumpStatus.setPumpDeviceState(PumpDeviceState.Sleeping); - - rememberLastGoodDeviceCommunicationTime(); - - return true; - - } else { - if (state != PumpDeviceState.PumpUnreachable) - medtronicPumpStatus.setPumpDeviceState(PumpDeviceState.PumpUnreachable); - } - - } - - } else { - aapsLogger.warn(LTag.PUMPCOMM, "isDeviceReachable. Failed to parse radio response: " - + ByteUtil.shortHexString(rfSpyResponse.getRaw())); - } - - } catch (RileyLinkCommunicationException e) { - aapsLogger.warn(LTag.PUMPCOMM, "isDeviceReachable. Failed to decode radio response: " - + ByteUtil.shortHexString(rfSpyResponse.getRaw())); - } - - } else { - aapsLogger.warn(LTag.PUMPCOMM, "isDeviceReachable. Unknown response: " + ByteUtil.shortHexString(rfSpyResponse.getRaw())); - } - - return false; - } - - - @Override - public boolean tryToConnectToDevice() { - return isDeviceReachable(true); - } - - - private PumpMessage runCommandWithArgs(PumpMessage msg) throws RileyLinkCommunicationException { - - if (debugSetCommands) - aapsLogger.debug(LTag.PUMPCOMM, "Run command with Args: "); - - PumpMessage rval; - PumpMessage shortMessage = makePumpMessage(msg.getCommandType(), new CarelinkShortMessageBody(new byte[]{0})); - // look for ack from short message - PumpMessage shortResponse = sendAndListen(shortMessage); - if (shortResponse.getCommandType() == MedtronicCommandType.CommandACK) { - if (debugSetCommands) - aapsLogger.debug(LTag.PUMPCOMM, "Run command with Args: Got ACK response"); - - rval = sendAndListen(msg); - if (debugSetCommands) - aapsLogger.debug(LTag.PUMPCOMM, "2nd Response: " + rval); - - return rval; - } else { - aapsLogger.error(LTag.PUMPCOMM, "runCommandWithArgs: Pump did not ack Attention packet"); - return new PumpMessage(aapsLogger, "No ACK after Attention packet."); - } - } - - - private PumpMessage runCommandWithFrames(MedtronicCommandType commandType, List> frames) - throws RileyLinkCommunicationException { - - aapsLogger.debug(LTag.PUMPCOMM, "Run command with Frames: " + commandType.name()); - - PumpMessage rval = null; - PumpMessage shortMessage = makePumpMessage(commandType, new CarelinkShortMessageBody(new byte[]{0})); - // look for ack from short message - PumpMessage shortResponse = sendAndListen(shortMessage); - - if (shortResponse.getCommandType() != MedtronicCommandType.CommandACK) { - aapsLogger.error(LTag.PUMPCOMM, "runCommandWithFrames: Pump did not ack Attention packet"); - - return new PumpMessage(aapsLogger, "No ACK after start message."); - } else { - aapsLogger.debug(LTag.PUMPCOMM, "Run command with Frames: Got ACK response for Attention packet"); - } - - int frameNr = 1; - - for (List frame : frames) { - - byte[] frameData = medtronicUtil.createByteArray(frame); - - // aapsLogger.debug(LTag.PUMPCOMM,"Frame {} data:\n{}", frameNr, ByteUtil.getCompactString(frameData)); - - PumpMessage msg = makePumpMessage(commandType, new CarelinkLongMessageBody(frameData)); - - rval = sendAndListen(msg); - - // aapsLogger.debug(LTag.PUMPCOMM,"PumpResponse: " + rval); - - if (rval.getCommandType() != MedtronicCommandType.CommandACK) { - aapsLogger.error(LTag.PUMPCOMM, "runCommandWithFrames: Pump did not ACK frame #" + frameNr); - - aapsLogger.error(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Run command with Frames FAILED (command=%s, response=%s)", commandType.name(), - rval.toString())); - - return new PumpMessage(aapsLogger, "No ACK after frame #" + frameNr); - } else { - aapsLogger.debug(LTag.PUMPCOMM, "Run command with Frames: Got ACK response for frame #" + frameNr); - } - - frameNr++; - } - - return rval; - - } - - - public PumpHistoryResult getPumpHistory(PumpHistoryEntry lastEntry, LocalDateTime targetDate) { - - PumpHistoryResult pumpTotalResult = new PumpHistoryResult(aapsLogger, lastEntry, targetDate == null ? null - : DateTimeUtil.toATechDate(targetDate)); - - if (doWakeUpBeforeCommand) - wakeUp(receiverDeviceAwakeForMinutes, false); - - aapsLogger.debug(LTag.PUMPCOMM, "Current command: " + medtronicUtil.getCurrentCommand()); - - medtronicPumpStatus.setPumpDeviceState(PumpDeviceState.Active); - boolean doneWithError = false; - - for (int pageNumber = 0; pageNumber < 5; pageNumber++) { - - RawHistoryPage rawHistoryPage = new RawHistoryPage(aapsLogger); - // wakeUp(receiverDeviceAwakeForMinutes, false); - PumpMessage getHistoryMsg = makePumpMessage(MedtronicCommandType.GetHistoryData, - new GetHistoryPageCarelinkMessageBody(pageNumber)); - - aapsLogger.info(LTag.PUMPCOMM, "getPumpHistory: Page " + pageNumber); - // aapsLogger.info(LTag.PUMPCOMM,"getPumpHistoryPage("+pageNumber+"): "+ByteUtil.shortHexString(getHistoryMsg.getTxData())); - // Ask the pump to transfer history (we get first frame?) - - PumpMessage firstResponse = null; - boolean failed = false; - - medtronicUtil.setCurrentCommand(MedtronicCommandType.GetHistoryData, pageNumber, null); - - for (int retries = 0; retries < MAX_COMMAND_TRIES; retries++) { - - try { - firstResponse = runCommandWithArgs(getHistoryMsg); - failed = false; - break; - } catch (RileyLinkCommunicationException e) { - aapsLogger.error(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "First call for PumpHistory failed (retry=%d)", retries)); - failed = true; - } - } - - if (failed) { - medtronicPumpStatus.setPumpDeviceState(PumpDeviceState.Sleeping); - return pumpTotalResult; - } - - // aapsLogger.info(LTag.PUMPCOMM,"getPumpHistoryPage("+pageNumber+"): " + ByteUtil.shortHexString(firstResponse.getContents())); - - PumpMessage ackMsg = makePumpMessage(MedtronicCommandType.CommandACK, new PumpAckMessageBody()); - GetHistoryPageCarelinkMessageBody currentResponse = new GetHistoryPageCarelinkMessageBody(firstResponse.getMessageBody().getTxData()); - int expectedFrameNum = 1; - boolean done = false; - // while (expectedFrameNum == currentResponse.getFrameNumber()) { - - int failures = 0; - while (!done) { - // examine current response for problems. - byte[] frameData = currentResponse.getFrameData(); - if ((frameData != null) && (frameData.length > 0) - && currentResponse.getFrameNumber() == expectedFrameNum) { - // success! got a frame. - if (frameData.length != 64) { - aapsLogger.warn(LTag.PUMPCOMM, "Expected frame of length 64, got frame of length " + frameData.length); - // but append it anyway? - } - // handle successful frame data - rawHistoryPage.appendData(currentResponse.getFrameData()); - // RileyLinkMedtronicService.getInstance().announceProgress(((100 / 16) * - // currentResponse.getFrameNumber() + 1)); - medtronicUtil.setCurrentCommand(MedtronicCommandType.GetHistoryData, pageNumber, - currentResponse.getFrameNumber()); - - aapsLogger.info(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "getPumpHistory: Got frame %d of Page %d", currentResponse.getFrameNumber(), pageNumber)); - // Do we need to ask for the next frame? - if (expectedFrameNum < 16) { // This number may not be correct for pumps other than 522/722 - expectedFrameNum++; - } else { - done = true; // successful completion - } - } else { - if (frameData == null) { - aapsLogger.error(LTag.PUMPCOMM, "null frame data, retrying"); - } else if (currentResponse.getFrameNumber() != expectedFrameNum) { - aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Expected frame number %d, received %d (retrying)", expectedFrameNum, - currentResponse.getFrameNumber())); - } else if (frameData.length == 0) { - aapsLogger.warn(LTag.PUMPCOMM, "Frame has zero length, retrying"); - } - failures++; - if (failures == 6) { - aapsLogger.error(LTag.PUMPCOMM, - String.format(Locale.ENGLISH, "getPumpHistory: 6 failures in attempting to download frame %d of page %d, giving up.", - expectedFrameNum, pageNumber)); - done = true; // failure completion. - doneWithError = true; - } - } - - if (!done) { - // ask for next frame - PumpMessage nextMsg = null; - - for (int retries = 0; retries < MAX_COMMAND_TRIES; retries++) { - - try { - nextMsg = sendAndListen(ackMsg); - break; - } catch (RileyLinkCommunicationException e) { - aapsLogger.error(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Problem acknowledging frame response. (retry=%d)", retries)); - } - } - - if (nextMsg != null) - currentResponse = new GetHistoryPageCarelinkMessageBody(nextMsg.getMessageBody().getTxData()); - else { - aapsLogger.error(LTag.PUMPCOMM, "We couldn't acknowledge frame from pump, aborting operation."); - } - } - } - - if (rawHistoryPage.getLength() != 1024) { - aapsLogger.warn(LTag.PUMPCOMM, "getPumpHistory: short page. Expected length of 1024, found length of " - + rawHistoryPage.getLength()); - doneWithError = true; - } - - if (!rawHistoryPage.isChecksumOK()) { - aapsLogger.error(LTag.PUMPCOMM, "getPumpHistory: checksum is wrong"); - doneWithError = true; - } - - if (doneWithError) { - medtronicPumpStatus.setPumpDeviceState(PumpDeviceState.Sleeping); - return pumpTotalResult; - } - - rawHistoryPage.dumpToDebug(); - - List medtronicHistoryEntries = medtronicPumpHistoryDecoder.processPageAndCreateRecords(rawHistoryPage); - - aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "getPumpHistory: Found %d history entries.", medtronicHistoryEntries.size())); - - pumpTotalResult.addHistoryEntries(medtronicHistoryEntries, pageNumber); - - aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "getPumpHistory: Search status: Search finished: %b", pumpTotalResult.isSearchFinished())); - - if (pumpTotalResult.isSearchFinished()) { - medtronicPumpStatus.setPumpDeviceState(PumpDeviceState.Sleeping); - - return pumpTotalResult; - } - } - - medtronicPumpStatus.setPumpDeviceState(PumpDeviceState.Sleeping); - - return pumpTotalResult; - - } - - - public String getErrorResponse() { - return this.errorMessage; - } - - - @Override - public byte[] createPumpMessageContent(RLMessageType type) { - switch (type) { - case PowerOn: - return medtronicUtil.buildCommandPayload(rileyLinkServiceData, MedtronicCommandType.RFPowerOn, // - new byte[]{2, 1, (byte) receiverDeviceAwakeForMinutes}); // maybe this is better FIXME - - case ReadSimpleData: - return medtronicUtil.buildCommandPayload(rileyLinkServiceData, MedtronicCommandType.PumpModel, null); - } - return new byte[0]; - } - - - private PumpMessage makePumpMessage(MedtronicCommandType messageType, byte[] body) { - return makePumpMessage(messageType, body == null ? new CarelinkShortMessageBody() - : new CarelinkShortMessageBody(body)); - } - - - private PumpMessage makePumpMessage(MedtronicCommandType messageType) { - return makePumpMessage(messageType, (byte[]) null); - } - - - private PumpMessage makePumpMessage(MedtronicCommandType messageType, MessageBody messageBody) { - PumpMessage msg = new PumpMessage(aapsLogger); - msg.init(PacketType.Carelink, rileyLinkServiceData.pumpIDBytes, messageType, messageBody); - return msg; - } - - - private PumpMessage sendAndGetResponse(MedtronicCommandType commandType) throws RileyLinkCommunicationException { - - return sendAndGetResponse(commandType, null, DEFAULT_TIMEOUT); - } - - - /** - * Main wrapper method for sending data - (for getting responses) - * - * @param commandType - * @param bodyData - * @param timeoutMs - * @return - */ - private PumpMessage sendAndGetResponse(MedtronicCommandType commandType, byte[] bodyData, int timeoutMs) - throws RileyLinkCommunicationException { - // wakeUp - if (doWakeUpBeforeCommand) - wakeUp(receiverDeviceAwakeForMinutes, false); - - medtronicPumpStatus.setPumpDeviceState(PumpDeviceState.Active); - - // create message - PumpMessage msg; - - if (bodyData == null) - msg = makePumpMessage(commandType); - else - msg = makePumpMessage(commandType, bodyData); - - // send and wait for response - PumpMessage response = sendAndListen(msg, timeoutMs); - - medtronicPumpStatus.setPumpDeviceState(PumpDeviceState.Sleeping); - - return response; - } - - - private PumpMessage sendAndListen(PumpMessage msg) throws RileyLinkCommunicationException { - return sendAndListen(msg, 4000); // 2000 - } - - - // All pump communications go through this function. - @Override - protected PumpMessage sendAndListen(PumpMessage msg, int timeout_ms) throws RileyLinkCommunicationException { - return super.sendAndListen(msg, timeout_ms); - } - - - private Object sendAndGetResponseWithCheck(MedtronicCommandType commandType) { - - return sendAndGetResponseWithCheck(commandType, null); - } - - - private Object sendAndGetResponseWithCheck(MedtronicCommandType commandType, byte[] bodyData) { - - aapsLogger.debug(LTag.PUMPCOMM, "getDataFromPump: " + commandType); - - for (int retries = 0; retries < MAX_COMMAND_TRIES; retries++) { - - try { - PumpMessage response = sendAndGetResponse(commandType, bodyData, DEFAULT_TIMEOUT + (DEFAULT_TIMEOUT * retries)); - - String check = checkResponseContent(response, commandType.getCommandDescription(), commandType.getExpectedLength()); - - if (check == null) { - - Object dataResponse = medtronicConverter.convertResponse(medtronicPumpPlugin.getPumpDescription().getPumpType(), commandType, response.getRawContent()); - - if (dataResponse != null) { - this.errorMessage = null; - aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Converted response for %s is %s.", commandType.name(), dataResponse)); - - return dataResponse; - } else { - this.errorMessage = "Error decoding response."; - } - } else { - this.errorMessage = check; - // return null; - } - - } catch (RileyLinkCommunicationException e) { - aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Error getting response from RileyLink (error=%s, retry=%d)", e.getMessage(), retries + 1)); - } - - } - - return null; - } - - - private T sendAndGetResponseWithCheck(MedtronicCommandType commandType, byte[] bodyData, Class clazz) { - - aapsLogger.debug(LTag.PUMPCOMM, "getDataFromPump: " + commandType); - - for (int retries = 0; retries < MAX_COMMAND_TRIES; retries++) { - - try { - PumpMessage response = sendAndGetResponse(commandType, bodyData, DEFAULT_TIMEOUT + (DEFAULT_TIMEOUT * retries)); - - String check = checkResponseContent(response, commandType.getCommandDescription(), commandType.getExpectedLength()); - - if (check == null) { - - T dataResponse = (T)medtronicConverter.convertResponse(medtronicPumpPlugin.getPumpDescription().getPumpType(), commandType, response.getRawContent()); - - if (dataResponse != null) { - this.errorMessage = null; - aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Converted response for %s is %s.", commandType.name(), dataResponse)); - - return dataResponse; - } else { - this.errorMessage = "Error decoding response."; - } - } else { - this.errorMessage = check; - // return null; - } - - } catch (RileyLinkCommunicationException e) { - aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Error getting response from RileyLink (error=%s, retry=%d)", e.getMessage(), retries + 1)); - } - - } - - return null; - } - - - private String checkResponseContent(PumpMessage response, String method, int expectedLength) { - - if (!response.isValid()) { - String responseData = String.format("%s: Invalid response.", method); - aapsLogger.warn(LTag.PUMPCOMM, responseData); - return responseData; - } - - byte[] contents = response.getRawContent(); - - if (contents != null) { - if (contents.length >= expectedLength) { - aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "%s: Content: %s", method, ByteUtil.shortHexString(contents))); - return null; - - } else { - String responseData = String.format( - "%s: Cannot return data. Data is too short [expected=%s, received=%s].", method, "" - + expectedLength, "" + contents.length); - - aapsLogger.warn(LTag.PUMPCOMM, responseData); - return responseData; - } - } else { - String responseData = String.format("%s: Cannot return data. Null response.", method); - aapsLogger.warn(LTag.PUMPCOMM, responseData); - return responseData; - } - } - - - // PUMP SPECIFIC COMMANDS - - public Double getRemainingInsulin() { - - Object responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.GetRemainingInsulin); - - return responseObject == null ? null : (Double) responseObject; - } - - - public MedtronicDeviceType getPumpModel() { - - Object responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.PumpModel); - - return responseObject == null ? null : (MedtronicDeviceType) responseObject; - } - - - public BasalProfile getBasalProfile() { - - // wakeUp - if (doWakeUpBeforeCommand) - wakeUp(receiverDeviceAwakeForMinutes, false); - - MedtronicCommandType commandType = MedtronicCommandType.GetBasalProfileSTD; - - aapsLogger.debug(LTag.PUMPCOMM, "getDataFromPump: " + commandType); - - medtronicUtil.setCurrentCommand(commandType); - - medtronicPumpStatus.setPumpDeviceState(PumpDeviceState.Active); - - for (int retries = 0; retries <= MAX_COMMAND_TRIES; retries++) { - - try { - // create message - PumpMessage msg; - - msg = makePumpMessage(commandType); - - // send and wait for response - - PumpMessage response = sendAndListen(msg, DEFAULT_TIMEOUT + (DEFAULT_TIMEOUT * retries)); - -// aapsLogger.debug(LTag.PUMPCOMM,"1st Response: " + HexDump.toHexStringDisplayable(response.getRawContent())); -// aapsLogger.debug(LTag.PUMPCOMM,"1st Response: " + HexDump.toHexStringDisplayable(response.getMessageBody().getTxData())); - - String check = checkResponseContent(response, commandType.getCommandDescription(), 1); - - byte[] data = null; - - if (check == null) { - - data = response.getRawContentOfFrame(); - - PumpMessage ackMsg = makePumpMessage(MedtronicCommandType.CommandACK, new PumpAckMessageBody()); - - while (checkIfWeHaveMoreData(commandType, response, data)) { - - response = sendAndListen(ackMsg, DEFAULT_TIMEOUT + (DEFAULT_TIMEOUT * retries)); - -// aapsLogger.debug(LTag.PUMPCOMM,"{} Response: {}", runs, HexDump.toHexStringDisplayable(response2.getRawContent())); -// aapsLogger.debug(LTag.PUMPCOMM,"{} Response: {}", runs, -// HexDump.toHexStringDisplayable(response2.getMessageBody().getTxData())); - - String check2 = checkResponseContent(response, commandType.getCommandDescription(), 1); - - if (check2 == null) { - - data = ByteUtil.concat(data, response.getRawContentOfFrame()); - - } else { - this.errorMessage = check2; - aapsLogger.error(LTag.PUMPCOMM, "Error with response got GetProfile: " + check2); - } - } - - } else { - errorMessage = check; - } - - BasalProfile basalProfile = (BasalProfile) medtronicConverter.convertResponse(medtronicPumpPlugin.getPumpDescription().getPumpType(), commandType, data); - - if (basalProfile != null) { - aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Converted response for %s is %s.", commandType.name(), basalProfile)); - - medtronicUtil.setCurrentCommand(null); - medtronicPumpStatus.setPumpDeviceState(PumpDeviceState.Sleeping); - - return basalProfile; - } - - } catch (RileyLinkCommunicationException e) { - aapsLogger.error(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Error getting response from RileyLink (error=%s, retry=%d)", e.getMessage(), retries + 1)); - } - } - - aapsLogger.warn(LTag.PUMPCOMM, "Error reading profile in max retries."); - medtronicUtil.setCurrentCommand(null); - medtronicPumpStatus.setPumpDeviceState(PumpDeviceState.Sleeping); - - return null; - - } - - - private boolean checkIfWeHaveMoreData(MedtronicCommandType commandType, PumpMessage response, byte[] data) { - - if (commandType == MedtronicCommandType.GetBasalProfileSTD || // - commandType == MedtronicCommandType.GetBasalProfileA || // - commandType == MedtronicCommandType.GetBasalProfileB) { - byte[] responseRaw = response.getRawContentOfFrame(); - - int last = responseRaw.length - 1; - - aapsLogger.debug(LTag.PUMPCOMM, "Length: " + data.length); - - if (data.length >= BasalProfile.MAX_RAW_DATA_SIZE) { - return false; - } - - if (responseRaw.length < 2) { - return false; - } - - return !(responseRaw[last] == 0x00 && responseRaw[last - 1] == 0x00 && responseRaw[last - 2] == 0x00); - } - - return false; - } - - - public ClockDTO getPumpTime() { - - ClockDTO clockDTO = new ClockDTO(); - clockDTO.setLocalDeviceTime(new LocalDateTime()); - - Object responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.GetRealTimeClock); - - if (responseObject != null) { - clockDTO.setPumpTime((LocalDateTime) responseObject); - return clockDTO; - } - - return null; - } - - - public TempBasalPair getTemporaryBasal() { - - Object responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.ReadTemporaryBasal); - - return responseObject == null ? null : (TempBasalPair) responseObject; - } - - - public Map getPumpSettings() { - - Object responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.getSettings(medtronicUtil - .getMedtronicPumpModel())); - - return responseObject == null ? null : (Map) responseObject; - } - - - public Boolean setBolus(double units) { - - aapsLogger.info(LTag.PUMPCOMM, "setBolus: " + units); - - return setCommand(MedtronicCommandType.SetBolus, medtronicUtil.getBolusStrokes(units)); - - } - - - public boolean setTBR(TempBasalPair tbr) { - - aapsLogger.info(LTag.PUMPCOMM, "setTBR: " + tbr.getDescription()); - - return setCommand(MedtronicCommandType.SetTemporaryBasal, tbr.getAsRawData()); - } - - - public Boolean setPumpTime() { - - GregorianCalendar gc = new GregorianCalendar(); - gc.add(Calendar.SECOND, 5); - - aapsLogger.info(LTag.PUMPCOMM, "setPumpTime: " + DateTimeUtil.toString(gc)); - - int i = 1; - byte[] data = new byte[8]; - data[0] = 7; - data[i] = (byte) gc.get(Calendar.HOUR_OF_DAY); - data[i + 1] = (byte) gc.get(Calendar.MINUTE); - data[i + 2] = (byte) gc.get(Calendar.SECOND); - - byte[] yearByte = MedtronicUtil.getByteArrayFromUnsignedShort(gc.get(Calendar.YEAR), true); - - data[i + 3] = yearByte[0]; - data[i + 4] = yearByte[1]; - - data[i + 5] = (byte) (gc.get(Calendar.MONTH) + 1); - data[i + 6] = (byte) gc.get(Calendar.DAY_OF_MONTH); - - //aapsLogger.info(LTag.PUMPCOMM,"setPumpTime: Body: " + ByteUtil.getHex(data)); - - return setCommand(MedtronicCommandType.SetRealTimeClock, data); - - } - - - private boolean setCommand(MedtronicCommandType commandType, byte[] body) { - - for (int retries = 0; retries <= MAX_COMMAND_TRIES; retries++) { - - try { - if (this.doWakeUpBeforeCommand) - wakeUp(false); - - if (debugSetCommands) - aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "%s: Body - %s", commandType.getCommandDescription(), - ByteUtil.getHex(body))); - - PumpMessage msg = makePumpMessage(commandType, new CarelinkLongMessageBody(body)); - - PumpMessage pumpMessage = runCommandWithArgs(msg); - - if (debugSetCommands) - aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "%s: %s", commandType.getCommandDescription(), pumpMessage.getResponseContent())); - - if (pumpMessage.getCommandType() == MedtronicCommandType.CommandACK) { - return true; - } else { - aapsLogger.warn(LTag.PUMPCOMM, "We received non-ACK response from pump: " + pumpMessage.getResponseContent()); - } - - } catch (RileyLinkCommunicationException e) { - aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Error getting response from RileyLink (error=%s, retry=%d)", e.getMessage(), retries + 1)); - } - } - - return false; - } - - - public boolean cancelTBR() { - return setTBR(new TempBasalPair(0.0d, false, 0)); - } - - - public BatteryStatusDTO getRemainingBattery() { - - Object responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.GetBatteryStatus); - - return responseObject == null ? null : (BatteryStatusDTO) responseObject; - } - - - public Boolean setBasalProfile(BasalProfile basalProfile) { - - List> basalProfileFrames = medtronicUtil.getBasalProfileFrames(basalProfile.getRawData()); - - for (int retries = 0; retries <= MAX_COMMAND_TRIES; retries++) { - - PumpMessage responseMessage = null; - try { - responseMessage = runCommandWithFrames(MedtronicCommandType.SetBasalProfileSTD, - basalProfileFrames); - - if (responseMessage.getCommandType() == MedtronicCommandType.CommandACK) - return true; - - } catch (RileyLinkCommunicationException e) { - aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Error getting response from RileyLink (error=%s, retry=%d)", e.getMessage(), retries + 1)); - } - - if (responseMessage != null) - aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Set Basal Profile: Invalid response: commandType=%s,rawData=%s", responseMessage.getCommandType(), ByteUtil.shortHexString(responseMessage.getRawContent()))); - else - aapsLogger.warn(LTag.PUMPCOMM, "Set Basal Profile: Null response."); - } - - return false; - - } -} 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 new file mode 100644 index 0000000000..e913ff52f7 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicCommunicationManager.kt @@ -0,0 +1,664 @@ +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.hw.rileylink.RileyLinkCommunicationManager +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkConst +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.RileyLinkCommunicationException +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.data.RadioPacket +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.data.RadioResponse +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.defs.RLMessageType +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.tasks.WakeAndTuneTask +import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil +import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil +import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicPumpPlugin +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.RawHistoryPage +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.PumpHistoryResult +import info.nightscout.androidaps.plugins.pump.medtronic.comm.message.* +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BasalProfile +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BatteryStatusDTO +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.ClockDTO +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.PumpSettingDTO +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.TempBasalPair +import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicCommandType +import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicCommandType.Companion.getSettings +import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicDeviceType +import info.nightscout.androidaps.plugins.pump.medtronic.driver.MedtronicPumpStatus +import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil +import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil.Companion.createByteArray +import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil.Companion.getByteArrayFromUnsignedShort +import org.joda.time.LocalDateTime +import java.util.* +import javax.inject.Inject +import javax.inject.Singleton +import kotlin.jvm.Throws + +/** + * Original file created by geoff on 5/30/16. + * + * + * Split into 2 implementations, so that we can split it by target device. - Andy + * This was mostly rewritten from Original version, and lots of commands and + * functionality added. + */ +@Singleton +class MedtronicCommunicationManager // This empty constructor must be kept, otherwise dagger injection might break! +@Inject constructor() : RileyLinkCommunicationManager() { + + @Inject lateinit var medtronicPumpStatus: MedtronicPumpStatus + @Inject lateinit var medtronicPumpPlugin: MedtronicPumpPlugin + @Inject lateinit var medtronicConverter: MedtronicConverter + @Inject lateinit var medtronicUtil: MedtronicUtil + @Inject lateinit var medtronicPumpHistoryDecoder: MedtronicPumpHistoryDecoder + + private val MAX_COMMAND_TRIES = 3 + private val DEFAULT_TIMEOUT = 2000 + private val RILEYLINK_TIMEOUT: Long = 15 * 60 * 1000 // 15 min + + var errorResponse: String? = null + private set + private val debugSetCommands = false + private var doWakeUpBeforeCommand = true + + @Inject + open 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) + } + + override fun createResponseMessage(payload: ByteArray): PumpMessage { + return PumpMessage(aapsLogger, payload) + } + + override fun setPumpDeviceState(pumpDeviceState: PumpDeviceState) { + medtronicPumpStatus.pumpDeviceState = pumpDeviceState + } + + fun setDoWakeUpBeforeCommand(doWakeUp: Boolean) { + doWakeUpBeforeCommand = doWakeUp + } + + override fun isDeviceReachable(): Boolean { + return isDeviceReachable(false) + } + + /** + * We do actual wakeUp and compare PumpModel with currently selected one. If returned model is + * not Unknown, pump is reachable. + * + * @return + */ + fun isDeviceReachable(canPreventTuneUp: Boolean): Boolean { + val state = medtronicPumpStatus.pumpDeviceState + if (state !== PumpDeviceState.PumpUnreachable) medtronicPumpStatus.pumpDeviceState = PumpDeviceState.WakingUp + for (retry in 0..4) { + aapsLogger.debug(LTag.PUMPCOMM, "isDeviceReachable. Waking pump... " + if (retry != 0) " (retry $retry)" else "") + val connected = connectToDevice() + if (connected) return true + SystemClock.sleep(1000) + } + if (state !== PumpDeviceState.PumpUnreachable) medtronicPumpStatus.pumpDeviceState = PumpDeviceState.PumpUnreachable + if (!canPreventTuneUp) { + val diff = System.currentTimeMillis() - medtronicPumpStatus.lastConnection + if (diff > RILEYLINK_TIMEOUT) { + serviceTaskExecutor.startTask(WakeAndTuneTask(injector)) + } + } + return false + } + + private fun connectToDevice(): Boolean { + val state = medtronicPumpStatus.pumpDeviceState + + // check connection + val pumpMsgContent = createPumpMessageContent(RLMessageType.ReadSimpleData) // simple + val rfSpyResponse = rfspy.transmitThenReceive(RadioPacket(injector, pumpMsgContent), 0.toByte(), 200.toByte(), + 0.toByte(), 0.toByte(), 25000, 0.toByte()) + aapsLogger.info(LTag.PUMPCOMM, "wakeup: raw response is " + ByteUtil.shortHexString(rfSpyResponse.raw)) + if (rfSpyResponse.wasTimeout()) { + aapsLogger.error(LTag.PUMPCOMM, "isDeviceReachable. Failed to find pump (timeout).") + } else if (rfSpyResponse.looksLikeRadioPacket()) { + val radioResponse = RadioResponse(injector) + try { + radioResponse.init(rfSpyResponse.raw) + if (radioResponse.isValid) { + val pumpResponse = createResponseMessage(radioResponse.payload) + if (!pumpResponse.isValid) { + aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Response is invalid ! [interrupted=%b, timeout=%b]", rfSpyResponse.wasInterrupted(), + rfSpyResponse.wasTimeout())) + } else { + + // radioResponse.rssi; + val dataResponse = medtronicConverter!!.convertResponse(medtronicPumpStatus.pumpType, MedtronicCommandType.PumpModel, + pumpResponse.rawContent) + val pumpModel = dataResponse as MedtronicDeviceType? + val valid = pumpModel !== MedtronicDeviceType.Unknown_Device + if (medtronicUtil.medtronicPumpModel == null && valid) { + medtronicUtil.medtronicPumpModel = pumpModel + } + aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "isDeviceReachable. PumpModel is %s - Valid: %b (rssi=%d)", pumpModel!!.name, valid, + radioResponse.rssi)) + if (valid) { + if (state === PumpDeviceState.PumpUnreachable) + medtronicPumpStatus.pumpDeviceState = PumpDeviceState.WakingUp + else + medtronicPumpStatus.pumpDeviceState = PumpDeviceState.Sleeping + rememberLastGoodDeviceCommunicationTime() + return true + } else { + if (state !== PumpDeviceState.PumpUnreachable) medtronicPumpStatus.pumpDeviceState = PumpDeviceState.PumpUnreachable + } + } + } else { + aapsLogger.warn(LTag.PUMPCOMM, "isDeviceReachable. Failed to parse radio response: " + + ByteUtil.shortHexString(rfSpyResponse.raw)) + } + } catch (e: RileyLinkCommunicationException) { + aapsLogger.warn(LTag.PUMPCOMM, "isDeviceReachable. Failed to decode radio response: " + + ByteUtil.shortHexString(rfSpyResponse.raw)) + } + } else { + aapsLogger.warn(LTag.PUMPCOMM, "isDeviceReachable. Unknown response: " + ByteUtil.shortHexString(rfSpyResponse.raw)) + } + return false + } + + override fun tryToConnectToDevice(): Boolean { + return isDeviceReachable(true) + } + + @Throws(RileyLinkCommunicationException::class) + private fun runCommandWithArgs(msg: PumpMessage): PumpMessage { + if (debugSetCommands) aapsLogger.debug(LTag.PUMPCOMM, "Run command with Args: ") + val rval: PumpMessage + val shortMessage = makePumpMessage(msg.commandType, CarelinkShortMessageBody(byteArrayOf(0))) + // look for ack from short message + val shortResponse = sendAndListen(shortMessage) + return if (shortResponse.commandType === MedtronicCommandType.CommandACK) { + if (debugSetCommands) aapsLogger.debug(LTag.PUMPCOMM, "Run command with Args: Got ACK response") + rval = sendAndListen(msg) + if (debugSetCommands) aapsLogger.debug(LTag.PUMPCOMM, "2nd Response: $rval") + rval + } else { + aapsLogger.error(LTag.PUMPCOMM, "runCommandWithArgs: Pump did not ack Attention packet") + PumpMessage(aapsLogger, "No ACK after Attention packet.") + } + } + + @Throws(RileyLinkCommunicationException::class) + private fun runCommandWithFrames(commandType: MedtronicCommandType, frames: List>): PumpMessage? { + aapsLogger.debug(LTag.PUMPCOMM, "Run command with Frames: " + commandType.name) + var rval: PumpMessage? = null + val shortMessage = makePumpMessage(commandType, CarelinkShortMessageBody(byteArrayOf(0))) + // look for ack from short message + val shortResponse = sendAndListen(shortMessage) + if (shortResponse.commandType !== MedtronicCommandType.CommandACK) { + aapsLogger.error(LTag.PUMPCOMM, "runCommandWithFrames: Pump did not ack Attention packet") + return PumpMessage(aapsLogger, "No ACK after start message.") + } else { + aapsLogger.debug(LTag.PUMPCOMM, "Run command with Frames: Got ACK response for Attention packet") + } + var frameNr = 1 + for (frame in frames) { + val frameData = createByteArray(frame) + + // aapsLogger.debug(LTag.PUMPCOMM,"Frame {} data:\n{}", frameNr, ByteUtil.getCompactString(frameData)); + val msg = makePumpMessage(commandType, CarelinkLongMessageBody(frameData)) + rval = sendAndListen(msg) + + // aapsLogger.debug(LTag.PUMPCOMM,"PumpResponse: " + rval); + if (rval.commandType !== MedtronicCommandType.CommandACK) { + aapsLogger.error(LTag.PUMPCOMM, "runCommandWithFrames: Pump did not ACK frame #$frameNr") + aapsLogger.error(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Run command with Frames FAILED (command=%s, response=%s)", commandType.name, + rval.toString())) + return PumpMessage(aapsLogger, "No ACK after frame #$frameNr") + } else { + aapsLogger.debug(LTag.PUMPCOMM, "Run command with Frames: Got ACK response for frame #$frameNr") + } + frameNr++ + } + return rval + } + + fun getPumpHistory(lastEntry: PumpHistoryEntry?, targetDate: LocalDateTime?): PumpHistoryResult { + val pumpTotalResult = PumpHistoryResult(aapsLogger, lastEntry, if (targetDate == null) null else DateTimeUtil.toATechDate(targetDate)) + if (doWakeUpBeforeCommand) wakeUp(receiverDeviceAwakeForMinutes, false) + aapsLogger.debug(LTag.PUMPCOMM, "Current command: " + medtronicUtil.getCurrentCommand()) + medtronicPumpStatus.pumpDeviceState = PumpDeviceState.Active + var doneWithError = false + for (pageNumber in 0..4) { + val rawHistoryPage = RawHistoryPage(aapsLogger) + // wakeUp(receiverDeviceAwakeForMinutes, false); + val getHistoryMsg = makePumpMessage(MedtronicCommandType.GetHistoryData, + GetHistoryPageCarelinkMessageBody(pageNumber)) + aapsLogger.info(LTag.PUMPCOMM, "getPumpHistory: Page $pageNumber") + // aapsLogger.info(LTag.PUMPCOMM,"getPumpHistoryPage("+pageNumber+"): "+ByteUtil.shortHexString(getHistoryMsg.getTxData())); + // Ask the pump to transfer history (we get first frame?) + var firstResponse: PumpMessage? = null + var failed = false + medtronicUtil.setCurrentCommand(MedtronicCommandType.GetHistoryData, pageNumber, null) + for (retries in 0 until MAX_COMMAND_TRIES) { + try { + firstResponse = runCommandWithArgs(getHistoryMsg) + failed = false + break + } catch (e: RileyLinkCommunicationException) { + aapsLogger.error(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "First call for PumpHistory failed (retry=%d)", retries)) + failed = true + } + } + if (failed) { + medtronicPumpStatus.pumpDeviceState = PumpDeviceState.Sleeping + return pumpTotalResult + } + + // aapsLogger.info(LTag.PUMPCOMM,"getPumpHistoryPage("+pageNumber+"): " + ByteUtil.shortHexString(firstResponse.getContents())); + val ackMsg = makePumpMessage(MedtronicCommandType.CommandACK, PumpAckMessageBody()) + var currentResponse = GetHistoryPageCarelinkMessageBody(firstResponse!!.messageBody!!.txData) + var expectedFrameNum = 1 + var done = false + // while (expectedFrameNum == currentResponse.getFrameNumber()) { + var failures = 0 + while (!done) { + // examine current response for problems. + val frameData = currentResponse.frameData + if (frameData != null && frameData.size > 0 + && currentResponse.frameNumber == expectedFrameNum) { + // success! got a frame. + if (frameData.size != 64) { + aapsLogger.warn(LTag.PUMPCOMM, "Expected frame of length 64, got frame of length " + frameData.size) + // but append it anyway? + } + // handle successful frame data + rawHistoryPage.appendData(currentResponse.frameData) + // RileyLinkMedtronicService.getInstance().announceProgress(((100 / 16) * + // currentResponse.getFrameNumber() + 1)); + medtronicUtil.setCurrentCommand(MedtronicCommandType.GetHistoryData, pageNumber, + currentResponse.frameNumber) + aapsLogger.info(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "getPumpHistory: Got frame %d of Page %d", currentResponse.frameNumber, pageNumber)) + // Do we need to ask for the next frame? + if (expectedFrameNum < 16) { // This number may not be correct for pumps other than 522/722 + expectedFrameNum++ + } else { + done = true // successful completion + } + } else { + if (frameData == null) { + aapsLogger.error(LTag.PUMPCOMM, "null frame data, retrying") + } else if (currentResponse.frameNumber != expectedFrameNum) { + aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Expected frame number %d, received %d (retrying)", expectedFrameNum, + currentResponse.frameNumber)) + } else if (frameData.size == 0) { + aapsLogger.warn(LTag.PUMPCOMM, "Frame has zero length, retrying") + } + failures++ + if (failures == 6) { + aapsLogger.error(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "getPumpHistory: 6 failures in attempting to download frame %d of page %d, giving up.", + expectedFrameNum, pageNumber)) + done = true // failure completion. + doneWithError = true + } + } + if (!done) { + // ask for next frame + var nextMsg: PumpMessage? = null + for (retries in 0 until MAX_COMMAND_TRIES) { + try { + nextMsg = sendAndListen(ackMsg) + break + } catch (e: RileyLinkCommunicationException) { + aapsLogger.error(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Problem acknowledging frame response. (retry=%d)", retries)) + } + } + if (nextMsg != null) currentResponse = GetHistoryPageCarelinkMessageBody(nextMsg.messageBody!!.txData) else { + aapsLogger.error(LTag.PUMPCOMM, "We couldn't acknowledge frame from pump, aborting operation.") + } + } + } + if (rawHistoryPage.length != 1024) { + aapsLogger.warn(LTag.PUMPCOMM, "getPumpHistory: short page. Expected length of 1024, found length of " + + rawHistoryPage.length) + doneWithError = true + } + if (!rawHistoryPage.isChecksumOK) { + aapsLogger.error(LTag.PUMPCOMM, "getPumpHistory: checksum is wrong") + doneWithError = true + } + if (doneWithError) { + medtronicPumpStatus.pumpDeviceState = PumpDeviceState.Sleeping + return pumpTotalResult + } + rawHistoryPage.dumpToDebug() + val medtronicHistoryEntries = medtronicPumpHistoryDecoder.processPageAndCreateRecords(rawHistoryPage) + aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "getPumpHistory: Found %d history entries.", medtronicHistoryEntries.size)) + pumpTotalResult.addHistoryEntries(medtronicHistoryEntries, pageNumber) + aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "getPumpHistory: Search status: Search finished: %b", pumpTotalResult.isSearchFinished)) + if (pumpTotalResult.isSearchFinished) { + medtronicPumpStatus.pumpDeviceState = PumpDeviceState.Sleeping + return pumpTotalResult + } + } + medtronicPumpStatus.pumpDeviceState = PumpDeviceState.Sleeping + return pumpTotalResult + } + + override fun createPumpMessageContent(type: RLMessageType): ByteArray { + 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) + } + return ByteArray(0) + } + + private fun makePumpMessage(messageType: MedtronicCommandType, body: ByteArray? = null as ByteArray?): PumpMessage { + return makePumpMessage(messageType, body?.let { CarelinkShortMessageBody(it) } + ?: CarelinkShortMessageBody()) + } + + private fun makePumpMessage(messageType: MedtronicCommandType?, messageBody: MessageBody): PumpMessage { + val msg = PumpMessage(aapsLogger) + msg.init(PacketType.Carelink, rileyLinkServiceData.pumpIDBytes, messageType, messageBody) + return msg + } + + /** + * Main wrapper method for sending data - (for getting responses) + * + * @param commandType + * @param bodyData + * @param timeoutMs + * @return + */ + @Throws(RileyLinkCommunicationException::class) + private fun sendAndGetResponse(commandType: MedtronicCommandType, bodyData: ByteArray? = null, timeoutMs: Int = DEFAULT_TIMEOUT): PumpMessage { + // wakeUp + if (doWakeUpBeforeCommand) wakeUp(receiverDeviceAwakeForMinutes, false) + medtronicPumpStatus.pumpDeviceState = PumpDeviceState.Active + + // create message + val msg: PumpMessage + msg = bodyData?.let { makePumpMessage(commandType, it) } ?: makePumpMessage(commandType) + + // send and wait for response + val response = sendAndListen(msg, timeoutMs) + medtronicPumpStatus.pumpDeviceState = PumpDeviceState.Sleeping + return response + } + + @Throws(RileyLinkCommunicationException::class) + private fun sendAndListen(msg: PumpMessage): PumpMessage { + return sendAndListen(msg, 4000) // 2000 + } + + // All pump communications go through this function. + @Throws(RileyLinkCommunicationException::class) + protected /*override*/ fun sendAndListen(msg: PumpMessage, timeout_ms: Int): PumpMessage { + return super.sendAndListen(msg, timeout_ms)!! + } + + private fun sendAndGetResponseWithCheck(commandType: MedtronicCommandType, bodyData: ByteArray? = null): Any? { + 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) + if (dataResponse != null) { + errorResponse = null + aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Converted response for %s is %s.", commandType.name, dataResponse)) + return dataResponse + } else { + errorResponse = "Error decoding response." + } + } else { + errorResponse = check + // return null; + } + } catch (e: RileyLinkCommunicationException) { + aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Error getting response from RileyLink (error=%s, retry=%d)", e.message, retries + 1)) + } + } + return null + } + + // private fun sendAndGetResponseWithCheck(commandType: MedtronicCommandType, bodyData: ByteArray, clazz: Class): 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(medtronicPumpPlugin!!.pumpDescription.pumpType, commandType, response.rawContent) as T? + // if (dataResponse != null) { + // errorResponse = null + // aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Converted response for %s is %s.", commandType.name, dataResponse)) + // return dataResponse + // } else { + // errorResponse = "Error decoding response." + // } + // } else { + // errorResponse = check + // // return null; + // } + // } catch (e: RileyLinkCommunicationException) { + // aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Error getting response from RileyLink (error=%s, retry=%d)", e.message, retries + 1)) + // } + // } + // return null + // } + + private fun checkResponseContent(response: PumpMessage, method: String, expectedLength: Int): String? { + if (!response.isValid) { + val responseData = String.format("%s: Invalid response.", method) + aapsLogger.warn(LTag.PUMPCOMM, responseData) + return responseData + } + val contents = response.rawContent + return if (contents != null) { + if (contents.size >= expectedLength) { + aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "%s: Content: %s", method, ByteUtil.shortHexString(contents))) + null + } else { + val responseData = String.format( + "%s: Cannot return data. Data is too short [expected=%s, received=%s].", method, "" + + expectedLength, "" + contents.size) + aapsLogger.warn(LTag.PUMPCOMM, responseData) + responseData + } + } else { + val responseData = String.format("%s: Cannot return data. Null response.", method) + aapsLogger.warn(LTag.PUMPCOMM, responseData) + responseData + } + } + + // PUMP SPECIFIC COMMANDS + fun getRemainingInsulin(): Double? { + val responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.GetRemainingInsulin) + return if (responseObject == null) null else responseObject as Double? + } + + fun getPumpModel(): MedtronicDeviceType? { + val responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.PumpModel) + return if (responseObject == null) null else responseObject as MedtronicDeviceType? + } + + + + fun getBasalProfile(): BasalProfile? { + + // wakeUp + if (doWakeUpBeforeCommand) wakeUp(receiverDeviceAwakeForMinutes, false) + val commandType = MedtronicCommandType.GetBasalProfileSTD + aapsLogger.debug(LTag.PUMPCOMM, "getDataFromPump: $commandType") + medtronicUtil.setCurrentCommand(commandType) + medtronicPumpStatus.pumpDeviceState = PumpDeviceState.Active + for (retries in 0..MAX_COMMAND_TRIES) { + try { + // create message + var msg: PumpMessage + msg = makePumpMessage(commandType) + + // send and wait for response + var response = sendAndListen(msg, DEFAULT_TIMEOUT + DEFAULT_TIMEOUT * retries) + +// aapsLogger.debug(LTag.PUMPCOMM,"1st Response: " + HexDump.toHexStringDisplayable(response.getRawContent())); +// aapsLogger.debug(LTag.PUMPCOMM,"1st Response: " + HexDump.toHexStringDisplayable(response.getMessageBody().getTxData())); + val check = checkResponseContent(response, commandType.commandDescription, 1) + var data: ByteArray? = null + if (check == null) { + data = response.rawContentOfFrame + val ackMsg = makePumpMessage(MedtronicCommandType.CommandACK, PumpAckMessageBody()) + while (checkIfWeHaveMoreData(commandType, response, data)) { + response = sendAndListen(ackMsg, DEFAULT_TIMEOUT + DEFAULT_TIMEOUT * retries) + +// aapsLogger.debug(LTag.PUMPCOMM,"{} Response: {}", runs, HexDump.toHexStringDisplayable(response2.getRawContent())); +// aapsLogger.debug(LTag.PUMPCOMM,"{} Response: {}", runs, +// HexDump.toHexStringDisplayable(response2.getMessageBody().getTxData())); + val check2 = checkResponseContent(response, commandType.commandDescription, 1) + if (check2 == null) { + data = ByteUtil.concat(data, response.rawContentOfFrame) + } else { + errorResponse = check2 + aapsLogger.error(LTag.PUMPCOMM, "Error with response got GetProfile: $check2") + } + } + } else { + errorResponse = check + } + val basalProfile = medtronicConverter.convertResponse(medtronicPumpPlugin.pumpType, commandType, data) as BasalProfile? + if (basalProfile != null) { + aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Converted response for %s is %s.", commandType.name, basalProfile)) + medtronicUtil.setCurrentCommand(null) + medtronicPumpStatus.pumpDeviceState = PumpDeviceState.Sleeping + return basalProfile + } + } catch (e: RileyLinkCommunicationException) { + aapsLogger.error(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Error getting response from RileyLink (error=%s, retry=%d)", e.message, retries + 1)) + } + } + aapsLogger.warn(LTag.PUMPCOMM, "Error reading profile in max retries.") + medtronicUtil.setCurrentCommand(null) + medtronicPumpStatus.pumpDeviceState = PumpDeviceState.Sleeping + return null + } + + private fun checkIfWeHaveMoreData(commandType: MedtronicCommandType, response: PumpMessage, data: ByteArray?): Boolean { + if (commandType === MedtronicCommandType.GetBasalProfileSTD || // + commandType === MedtronicCommandType.GetBasalProfileA || // + commandType === MedtronicCommandType.GetBasalProfileB) { + val responseRaw = response.rawContentOfFrame + val last = responseRaw.size - 1 + aapsLogger.debug(LTag.PUMPCOMM, "Length: " + data!!.size) + if (data.size >= BasalProfile.MAX_RAW_DATA_SIZE) { + return false + } + return if (responseRaw.size < 2) { + false + } else !(responseRaw[last] == 0x00.toByte() && responseRaw[last - 1] == 0x00.toByte() && responseRaw[last - 2] == 0x00.toByte()) + } + return false + } + + fun getPumpTime(): ClockDTO? { + val clockDTO = ClockDTO() + clockDTO.localDeviceTime = LocalDateTime() + val responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.GetRealTimeClock) + if (responseObject != null) { + clockDTO.pumpTime = responseObject as LocalDateTime? + return clockDTO + } + return null + } + + fun getTemporaryBasal(): TempBasalPair? { + val responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.ReadTemporaryBasal) + return if (responseObject == null) null else responseObject as TempBasalPair? + } + + fun getPumpSettings(): Map? { + val responseObject = sendAndGetResponseWithCheck(getSettings(medtronicUtil.medtronicPumpModel)) + return if (responseObject == null) null else responseObject as Map? + } + + fun setBolus(units: Double): Boolean { + aapsLogger.info(LTag.PUMPCOMM, "setBolus: $units") + return setCommand(MedtronicCommandType.SetBolus, medtronicUtil.getBolusStrokes(units)) + } + + fun setTemporaryBasal(tbr: TempBasalPair): Boolean { + aapsLogger.info(LTag.PUMPCOMM, "setTBR: " + tbr.description) + return setCommand(MedtronicCommandType.SetTemporaryBasal, tbr.asRawData) + } + + fun setPumpTime(): Boolean { + 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() + + //aapsLogger.info(LTag.PUMPCOMM,"setPumpTime: Body: " + ByteUtil.getHex(data)); + return setCommand(MedtronicCommandType.SetRealTimeClock, data) + } + + private fun setCommand(commandType: MedtronicCommandType, body: ByteArray): Boolean { + for (retries in 0..MAX_COMMAND_TRIES) { + try { + if (doWakeUpBeforeCommand) wakeUp(false) + if (debugSetCommands) aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "%s: Body - %s", commandType.commandDescription, + ByteUtil.getHex(body))) + val msg = makePumpMessage(commandType, CarelinkLongMessageBody(body)) + val pumpMessage = runCommandWithArgs(msg) + if (debugSetCommands) aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "%s: %s", commandType.commandDescription, pumpMessage.responseContent)) + if (pumpMessage.commandType === MedtronicCommandType.CommandACK) { + return true + } else { + aapsLogger.warn(LTag.PUMPCOMM, "We received non-ACK response from pump: " + pumpMessage.responseContent) + } + } catch (e: RileyLinkCommunicationException) { + aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Error getting response from RileyLink (error=%s, retry=%d)", e.message, retries + 1)) + } + } + return false + } + + fun cancelTBR(): Boolean { + return setTemporaryBasal(TempBasalPair(0.0, false, 0)) + } + + fun getRemainingBattery(): BatteryStatusDTO? { + val responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.GetBatteryStatus) + return if (responseObject == null) null else responseObject as BatteryStatusDTO? + } + + fun setBasalProfile(basalProfile: BasalProfile): Boolean { + val basalProfileFrames = medtronicUtil.getBasalProfileFrames(basalProfile.rawData) + for (retries in 0..MAX_COMMAND_TRIES) { + var responseMessage: PumpMessage? = null + try { + responseMessage = runCommandWithFrames(MedtronicCommandType.SetBasalProfileSTD, + basalProfileFrames) + if (responseMessage!!.commandType === MedtronicCommandType.CommandACK) return true + } catch (e: RileyLinkCommunicationException) { + aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Error getting response from RileyLink (error=%s, retry=%d)", e.message, retries + 1)) + } + if (responseMessage != null) aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Set Basal Profile: Invalid response: commandType=%s,rawData=%s", responseMessage.commandType, ByteUtil.shortHexString(responseMessage.rawContent))) else aapsLogger.warn(LTag.PUMPCOMM, "Set Basal Profile: Null response.") + } + return false + } +} \ No newline at end of file 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 57bc0eab11..0a4db88ede 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 @@ -51,7 +51,7 @@ abstract class MedtronicHistoryDecoder : MedtronicHi } } - fun processPageAndCreateRecords(rawHistoryPage: RawHistoryPage): List? { + fun processPageAndCreateRecords(rawHistoryPage: RawHistoryPage): List { return processPageAndCreateRecords(rawHistoryPage, false) } @@ -120,7 +120,7 @@ abstract class MedtronicHistoryDecoder : MedtronicHi private fun processPageAndCreateRecords(rawHistoryPage: RawHistoryPage, partial: Boolean): List { val dataClear = checkPage(rawHistoryPage, partial) val records: List = createRecords(dataClear) - for (record in records!!) { + for (record in records) { decodeRecord(record) } runPostDecodeTasks() 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 77f1ee32c1..83a20262cc 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 @@ -25,14 +25,14 @@ class MedtronicCGMSHistoryDecoder : MedtronicHistoryDecoder() override fun decodeRecord(record: CGMSHistoryEntry): RecordDecodeStatus? { return try { - decodeRecord(record, false) + decodeRecordInternal(record) } catch (ex: Exception) { LOG.error(" Error decoding: type={}, ex={}", record.entryType!!.name, ex.message, ex) RecordDecodeStatus.Error } } - fun decodeRecord(entry: CGMSHistoryEntry, ignore: Boolean): RecordDecodeStatus { + fun decodeRecordInternal(entry: CGMSHistoryEntry): RecordDecodeStatus { if (entry.dateTimeLength > 0) { parseDate(entry) } @@ -62,6 +62,7 @@ class MedtronicCGMSHistoryDecoder : MedtronicHistoryDecoder() } override fun postProcess() {} + override fun createRecords(dataClearInput: List): List { val dataClear = reverseList(dataClearInput, Byte::class.java) prepareStatistics() 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 0a2da5b5be..e9131694d2 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 @@ -79,7 +79,7 @@ class MedtronicPumpHistoryDecoder @Inject constructor( listRawData.add(opCode.toByte()) if (entryType === PumpHistoryEntryType.UnabsorbedInsulin || entryType === PumpHistoryEntryType.UnabsorbedInsulin512) { - val elements: Int = dataClear[counter]!!.toInt() + val elements: Int = dataClear[counter].toInt() listRawData.add(elements.toByte()) counter++ val els = getUnsignedInt(elements) @@ -106,12 +106,12 @@ class MedtronicPumpHistoryDecoder @Inject constructor( if (incompletePacket) break } if (entryType === PumpHistoryEntryType.None) { - aapsLogger!!.error(LTag.PUMPBTCOMM, "Error in code. We should have not come into this branch.") + aapsLogger.error(LTag.PUMPBTCOMM, "Error in code. We should have not come into this branch.") } else { if (pe.entryType === PumpHistoryEntryType.UnknownBasePacket) { pe.opCode = opCode.toByte() } - if (entryType.getHeadLength(medtronicUtil!!.medtronicPumpModel!!) == 0) special = true + if (entryType.getHeadLength(medtronicUtil.medtronicPumpModel!!) == 0) special = true pe.setData(listRawData as List, special) val decoded = decodeRecord(pe) if (decoded === RecordDecodeStatus.OK || decoded === RecordDecodeStatus.Ignored) { @@ -132,7 +132,7 @@ class MedtronicPumpHistoryDecoder @Inject constructor( override fun decodeRecord(record: PumpHistoryEntry): RecordDecodeStatus? { return try { - decodeRecord(record, false) + decodeRecordInternal(record) } catch (ex: Exception) { aapsLogger.error(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, " Error decoding: type=%s, ex=%s", record.entryType!!.name, ex.message, ex)) //ex.printStackTrace() @@ -140,7 +140,7 @@ class MedtronicPumpHistoryDecoder @Inject constructor( } } - private fun decodeRecord(entry: PumpHistoryEntry, x: Boolean): RecordDecodeStatus { + private fun decodeRecordInternal(entry: PumpHistoryEntry): RecordDecodeStatus { if (entry.dateTimeLength > 0) { decodeDateTime(entry) } @@ -169,6 +169,7 @@ class MedtronicPumpHistoryDecoder @Inject constructor( PumpHistoryEntryType.TempBasalDuration -> // decodeTempBasal(entry); RecordDecodeStatus.OK + PumpHistoryEntryType.TempBasalRate -> // decodeTempBasal(entry); RecordDecodeStatus.OK @@ -254,7 +255,7 @@ class MedtronicPumpHistoryDecoder @Inject constructor( val body = entry.body!! val dto = BolusWizardDTO() var bolusStrokes = 10.0f - if (MedtronicDeviceType.isSameDevice(medtronicUtil!!.medtronicPumpModel!!, MedtronicDeviceType.Medtronic_523andHigher)) { + if (MedtronicDeviceType.isSameDevice(medtronicUtil.medtronicPumpModel!!, MedtronicDeviceType.Medtronic_523andHigher)) { // https://github.com/ps2/minimed_rf/blob/master/lib/minimed_rf/log_entries/bolus_wizard.rb#L102 bolusStrokes = 40.0f dto.carbs = ((body[1] and 0x0c.toByte()).toInt() shl 6) + body[0] diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.kt index 7cb40c46e6..a5a7cbfaa8 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.kt @@ -69,10 +69,10 @@ class PumpHistoryEntry : MedtronicHistoryEntry() { override val dateLength: Int get() = entryType!!.dateLength - override fun equals(o: Any?): Boolean { - if (this === o) return true - if (o !is PumpHistoryEntry) return false - val that = o + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is PumpHistoryEntry) return false + val that = other return entryType == that.entryType && // atechDateTime === that.atechDateTime // && // // Objects.equals(this.decodedData, that.decodedData); diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryResult.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryResult.kt index b772119de8..09d694f061 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryResult.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryResult.kt @@ -81,8 +81,8 @@ class PumpHistoryResult(private val aapsLogger: AAPSLogger, searchEntry: PumpHis } override fun toString(): String { - return "PumpHistoryResult [unprocessed=" + (if (unprocessedEntries != null) "" + unprocessedEntries!!.size else "0") + // - ", valid=" + (if (validEntries != null) "" + validEntries!!.size else "0") + // + return "PumpHistoryResult [unprocessed=" + unprocessedEntries.size + // + ", valid=" + validEntries.size + // ", searchEntry=" + searchEntry + // ", searchDate=" + searchDate + // ", searchType=" + searchType + // diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUITask.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUITask.kt index 815ca14549..addcd5d2c3 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUITask.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUITask.kt @@ -53,19 +53,19 @@ class MedtronicUITask { aapsLogger.debug(LTag.PUMP, "MedtronicUITask: @@@ In execute. $commandType") when (commandType) { MedtronicCommandType.PumpModel -> { - result = communicationManager.pumpModel + result = communicationManager.getPumpModel() } MedtronicCommandType.GetBasalProfileSTD -> { - result = communicationManager.basalProfile + result = communicationManager.getBasalProfile() } MedtronicCommandType.GetRemainingInsulin -> { - result = communicationManager.remainingInsulin + result = communicationManager.getRemainingInsulin() } MedtronicCommandType.GetRealTimeClock -> { - result = communicationManager.pumpTime + result = communicationManager.getPumpTime() medtronicUtil.pumpTime = null } @@ -74,22 +74,22 @@ class MedtronicUITask { } MedtronicCommandType.GetBatteryStatus -> { - result = communicationManager.remainingBattery + result = communicationManager.getRemainingBattery() } MedtronicCommandType.SetTemporaryBasal -> { - val tbr = tBRSettings + val tbr = getTbrSettings() if (tbr != null) { - result = communicationManager.setTBR(tbr) + result = communicationManager.setTemporaryBasal(tbr) } } MedtronicCommandType.ReadTemporaryBasal -> { - result = communicationManager.temporaryBasal + result = communicationManager.getTemporaryBasal() } MedtronicCommandType.Settings, MedtronicCommandType.Settings_512 -> { - result = communicationManager.pumpSettings + result = communicationManager.getPumpSettings() } MedtronicCommandType.SetBolus -> { @@ -127,12 +127,11 @@ class MedtronicUITask { } } - // - // - private val tBRSettings: TempBasalPair - private get() = TempBasalPair(getDoubleFromParameters(0), // + private fun getTbrSettings(): TempBasalPair? { + return TempBasalPair(getDoubleFromParameters(0), // false, // getIntegerFromParameters(1)) + } private fun getFloatFromParameters(index: Int): Float { return parameters!![index] as Float 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 92720b72f2..b1af19654a 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 @@ -96,7 +96,7 @@ class BasalProfile { fun dumpBasalProfile() { aapsLogger.debug(LTag.PUMPCOMM, "Basal Profile entries:") - val entries = entries + val entries = getEntries() for (i in entries.indices) { val entry = entries[i] val startString = entry.startTime!!.toString("HH:mm") @@ -109,7 +109,7 @@ class BasalProfile { val basalProfileAsString: String get() { val sb = StringBuffer("Basal Profile entries:\n") - val entries = entries + val entries = getEntries() for (i in entries.indices) { val entry = entries[i] val startString = entry.startTime!!.toString("HH:mm") @@ -124,7 +124,7 @@ class BasalProfile { fun basalProfileToString(): String { val sb = StringBuffer("Basal Profile [") - val entries = entries + val entries = getEntries() for (i in entries.indices) { val entry = entries[i] val startString = entry.startTime!!.toString("HH:mm") @@ -138,7 +138,7 @@ class BasalProfile { // and changes to the profiles themselves. fun getEntryForTime(`when`: Instant): BasalProfileEntry { var rval = BasalProfileEntry() - val entries = entries + val entries = getEntries() if (entries.size == 0) { aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "getEntryForTime(%s): table is empty", `when`.toDateTime().toLocalTime().toString("HH:mm"))) @@ -181,31 +181,30 @@ class BasalProfile { }// readUnsignedByte(mRawData[i]); // an empty list - val entries: List - get() { - val entries: MutableList = ArrayList() - if (rawData == null || rawData!![2] == 0x3f.toByte()) { - aapsLogger.warn(LTag.PUMPCOMM, "Raw Data is empty.") - return entries // an empty list - } - var r: Int - var st: Int - var i = 0 - while (i < rawData!!.size - 2) { - if (rawData!![i] == 0.toByte() && rawData!![i + 1] == 0.toByte() && rawData!![i + 2] == 0.toByte()) break - if (rawData!![i] == 0.toByte() && rawData!![i + 1] == 0.toByte() && rawData!![i + 2] == 0x3f.toByte()) break - r = MedtronicUtil.makeUnsignedShort(rawData!![i + 1].toInt(), rawData!![i].toInt()) // readUnsignedByte(mRawData[i]); - st = readUnsignedByte(rawData!![i + 2]) - try { - entries.add(BasalProfileEntry(aapsLogger, r, st)) - } catch (ex: Exception) { - aapsLogger.error(LTag.PUMPCOMM, "Error decoding basal profile from bytes: " + ByteUtil.shortHexString(rawData)) - throw ex - } - i += 3 - } - return entries + fun getEntries(): List { + val entries: MutableList = ArrayList() + if (rawData[2] == 0x3f.toByte()) { + aapsLogger.warn(LTag.PUMPCOMM, "Raw Data is empty.") + return entries // an empty list } + var r: Int + var st: Int + var i = 0 + while (i < rawData.size - 2) { + if (rawData[i] == 0.toByte() && rawData[i + 1] == 0.toByte() && rawData[i + 2] == 0.toByte()) break + if (rawData[i] == 0.toByte() && rawData[i + 1] == 0.toByte() && rawData[i + 2] == 0x3f.toByte()) break + r = MedtronicUtil.makeUnsignedShort(rawData[i + 1].toInt(), rawData[i].toInt()) // readUnsignedByte(mRawData[i]); + st = readUnsignedByte(rawData[i + 2]) + try { + entries.add(BasalProfileEntry(aapsLogger, r, st)) + } catch (ex: Exception) { + aapsLogger.error(LTag.PUMPCOMM, "Error decoding basal profile from bytes: " + ByteUtil.shortHexString(rawData)) + throw ex + } + i += 3 + } + return entries + } /** * This is used to prepare new profile @@ -233,7 +232,7 @@ class BasalProfile { fun getProfilesByHour(pumpType: PumpType): Array { var entriesCopy: List? = null try { - entriesCopy = entries + entriesCopy = getEntries() } catch (ex: Exception) { aapsLogger.error(LTag.PUMPCOMM, "=============================================================================") aapsLogger.error(LTag.PUMPCOMM, " Error generating entries. Ex.: $ex", ex) @@ -280,7 +279,7 @@ class BasalProfile { fun verify(pumpType: PumpType): Boolean { try { - entries + getEntries() } catch (ex: Exception) { return false } diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/MedtronicHistoryActivity.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/MedtronicHistoryActivity.kt index e5a047ab97..c1e08c7f18 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/MedtronicHistoryActivity.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/MedtronicHistoryActivity.kt @@ -38,14 +38,14 @@ class MedtronicHistoryActivity : DaggerActivity() { var manualChange = false var typeListFull: List? = null - private var _binding: MedtronicHistoryActivityBinding? = null + //private var _binding: MedtronicHistoryActivityBinding? = null //@Inject //var fragmentInjector: DispatchingAndroidInjector? = null // This property is only valid between onCreateView and // onDestroyView. - private val binding get() = _binding!! + //private val binding get() = _binding!! private fun filterHistory(group: PumpHistoryEntryGroup) { filteredHistoryList.clear() @@ -93,20 +93,17 @@ class MedtronicHistoryActivity : DaggerActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - //setContentView(R.layout.medtronic_history_activity) - - _binding = MedtronicHistoryActivityBinding.inflate(getLayoutInflater()) //(inflater, container, false) - - historyTypeSpinner = binding.medtronicHistorytype //findViewById(R.id.medtronic_historytype) - statusView = binding.medtronicHistorystatus //findViewById(R.id.medtronic_historystatus) - recyclerView = binding.medtronicHistoryRecyclerview //findViewById(R.id.medtronic_history_recyclerview) + setContentView(R.layout.medtronic_history_activity) + historyTypeSpinner = findViewById(R.id.medtronic_historytype) + statusView = findViewById(R.id.medtronic_historystatus) + recyclerView = findViewById(R.id.medtronic_history_recyclerview) recyclerView.setHasFixedSize(true) llm = LinearLayoutManager(this) recyclerView.setLayoutManager(llm) recyclerViewAdapter = RecyclerViewAdapter(filteredHistoryList) recyclerView.setAdapter(recyclerViewAdapter) statusView.setVisibility(View.GONE) - typeListFull = getTypeList(getTranslatedList(resourceHelper!!)) + typeListFull = getTypeList(PumpHistoryEntryGroup.getTranslatedList(resourceHelper)) val spinnerAdapter = ArrayAdapter(this, R.layout.spinner_centered, typeListFull) historyTypeSpinner.setAdapter(spinnerAdapter) historyTypeSpinner.setOnItemSelectedListener(object : AdapterView.OnItemSelectedListener { @@ -163,11 +160,11 @@ class MedtronicHistoryActivity : DaggerActivity() { override fun onBindViewHolder(holder: HistoryViewHolder, position: Int) { val record = historyList[position] - if (record != null) { + //if (record != null) { holder.timeView.text = record.dateTimeString holder.typeView.text = record.entryType!!.description holder.valueView.text = record.displayableValue - } + //} } override fun getItemCount(): Int { diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/RileyLinkStatusDeviceMedtronic.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/RileyLinkStatusDeviceMedtronic.kt index b753ac5795..3fe1eb4d8e 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/RileyLinkStatusDeviceMedtronic.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/RileyLinkStatusDeviceMedtronic.kt @@ -108,8 +108,8 @@ class RileyLinkStatusDeviceMedtronic : DaggerFragment(), RefreshableInterface { return i.toLong() } - override fun getView(i: Int, view: View, viewGroup: ViewGroup): View { - var view = view + override fun getView(i: Int, viewIn: View, viewGroup: ViewGroup): View { + var view = viewIn val viewHolder: ViewHolder // General ListView optimization code. if (view == null) { 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 205742a336..d8fb29c42a 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 @@ -164,6 +164,7 @@ class RileyLinkMedtronicService // This empty constructor must be kept, otherwi } else { val pumpType = medtronicPumpStatus.medtronicPumpMap[pumpTypePart] medtronicPumpStatus.medtronicDeviceType = medtronicPumpStatus.medtronicDeviceTypeMap[pumpTypePart] + medtronicPumpStatus.pumpType = pumpType!! medtronicPumpPlugin.pumpType = pumpType if (pumpTypePart.startsWith("7")) medtronicPumpStatus.reservoirFullUnits = 300 else medtronicPumpStatus.reservoirFullUnits = 176 } diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/util/MedtronicUtil.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/util/MedtronicUtil.kt index ac690be476..72574a99b0 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/util/MedtronicUtil.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/util/MedtronicUtil.kt @@ -291,10 +291,10 @@ class MedtronicUtil @Inject constructor( } fun getStrokesInt(amount: Double, strokesPerUnit: Int): Int { - var length = 1 + //var length = 1 var scrollRate = 1 if (strokesPerUnit >= 40) { - length = 2 + // length = 2 // 40-stroke pumps scroll faster for higher unit values if (amount > 10) scrollRate = 4 else if (amount > 1) scrollRate = 2 From e7578b4c8f37d610bb1554203cc3da9501bbb6e7 Mon Sep 17 00:00:00 2001 From: Philoul Date: Fri, 23 Apr 2021 00:31:40 +0200 Subject: [PATCH 010/145] Loop Dialog, hide loop buttons if pump disconnected or loop suspended --- .../main/java/info/nightscout/androidaps/dialogs/LoopDialog.kt | 1 + app/src/main/res/layout/dialog_loop.xml | 1 + 2 files changed, 2 insertions(+) diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/LoopDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/LoopDialog.kt index 9b10142c8c..e412998cd4 100644 --- a/app/src/main/java/info/nightscout/androidaps/dialogs/LoopDialog.kt +++ b/app/src/main/java/info/nightscout/androidaps/dialogs/LoopDialog.kt @@ -195,6 +195,7 @@ class LoopDialog : DaggerDialogFragment() { binding.overviewDisconnectButtons.visibility = View.GONE binding.overviewReconnect.visibility = View.VISIBLE } + binding.overviewLoop.visibility = (!loopPlugin.isSuspended && !loopPlugin.isDisconnected).toVisibility() } val profile = profileFunction.getProfile() val profileStore = activePlugin.activeProfileInterface.profile diff --git a/app/src/main/res/layout/dialog_loop.xml b/app/src/main/res/layout/dialog_loop.xml index b0658e56e1..594d1855e3 100644 --- a/app/src/main/res/layout/dialog_loop.xml +++ b/app/src/main/res/layout/dialog_loop.xml @@ -51,6 +51,7 @@ From 28c0f1b8940ecdb877b8c0d28eecd37d3af7daec Mon Sep 17 00:00:00 2001 From: Andy Rozman Date: Sat, 24 Apr 2021 19:11:01 +0100 Subject: [PATCH 011/145] - 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") } From 727862c7434ac65a1821003324c3027be910fe84 Mon Sep 17 00:00:00 2001 From: Andy Rozman Date: Sun, 25 Apr 2021 18:15:53 +0100 Subject: [PATCH 012/145] - DailyTotals changes - GraphData merge --- .../general/overview/graphData/GraphData.kt | 7 -- .../plugins/pump/common/PumpPluginAbstract.kt | 25 ++-- .../pump/medtronic/MedtronicPumpPlugin.kt | 7 +- .../comm/MedtronicCommunicationManager.kt | 2 +- .../comm/ui/MedtronicUIPostprocessor.kt | 12 -- .../medtronic/data/MedtronicHistoryData.kt | 111 ++++++++---------- .../pump/medtronic/data/dto/DailyTotalsDTO.kt | 28 ++--- 7 files changed, 80 insertions(+), 112 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.kt index 9f87d3d0b0..aa7016d10a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.kt @@ -582,17 +582,10 @@ class GraphData( val ratioScale = if (useForScale) Scale(100.0) else Scale() var time = fromTime while (time <= toTime) { -<<<<<<<<< Temporary merge branch 1 iobCobCalculator.ads.getAutosensDataAtTime(time)?.let { autosensData -> - ratioArray.add(ScaledDataPoint(time, autosensData.autosensResult.ratio - 1, ratioScale)) - maxRatioValueFound = max(maxRatioValueFound, autosensData.autosensResult.ratio - 1) - minRatioValueFound = min(minRatioValueFound, autosensData.autosensResult.ratio - 1) -========= - iobCobCalculatorPlugin.getAutosensData(time)?.let { autosensData -> ratioArray.add(ScaledDataPoint(time, 100.0 * (autosensData.autosensResult.ratio - 1 ), ratioScale)) maxRatioValueFound = max(maxRatioValueFound, 100.0 * (autosensData.autosensResult.ratio - 1)) minRatioValueFound = min(minRatioValueFound, 100.0 * (autosensData.autosensResult.ratio - 1)) ->>>>>>>>> Temporary merge branch 2 } time += 5 * 60 * 1000L } diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.kt index 6b7e738929..4ac44e2627 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.kt @@ -404,18 +404,19 @@ abstract class PumpPluginAbstract protected constructor( } // TODO - protected fun addTemporaryBasalRateWithTempId(temporaryBasal: TemporaryBasal?, b: Boolean) { -// long temporaryId = generateTempId(temporaryBasal.timestamp); -// boolean response = pumpSync.addBolusWithTempId(temporaryBasal.timestamp, detailedBolusInfo.insulin, -// generateTempId(detailedBolusInfo.timestamp), detailedBolusInfo.getBolusType(), -// getPumpType(), serialNumber()); -// -// if (response && writeToInternalHistory) { -// driverHistory.put(temporaryId, new PumpDbEntry(temporaryId, model(), serialNumber(), detailedBolusInfo)); -// sp.putString(MedtronicConst.Statistics.InternalTemporaryDatabase, gson.toJson(driverHistory)); -// } -// -// return response; + protected fun addTemporaryBasalRateWithTempId(temporaryBasal: TemporaryBasal, b: Boolean) { + val temporaryId = generateTempId(temporaryBasal.date) + val response = pumpSync.addBolusWithTempId(temporaryBasal.timestamp, detailedBolusInfo.insulin, + generateTempId(detailedBolusInfo.timestamp), detailedBolusInfo.getBolusType(), + getPumpType(), serialNumber()); + + if (response && writeToInternalHistory) { + driverHistory.put(temporaryId, new PumpDbEntry(temporaryId, model(), serialNumber(), detailedBolusInfo)); + sp.putString(MedtronicConst.Statistics.InternalTemporaryDatabase, gson.toJson(driverHistory)); + } + + return response; + } fun removeTemporaryId(temporaryId: Long) { 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 a32a8937e2..6df557318f 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 @@ -756,7 +756,6 @@ class MedtronicPumpPlugin @Inject constructor( val response = responseTask.result as Boolean? aapsLogger.info(LTag.PUMP, logPrefix + "setTempBasalAbsolute - setTBR. Response: " + response) return if (response!!) { - // FIXME put this into UIPostProcessor medtronicPumpStatus.tempBasalStart = Date() medtronicPumpStatus.tempBasalAmount = absoluteRate medtronicPumpStatus.tempBasalLength = durationInMinutes @@ -1015,7 +1014,11 @@ class MedtronicPumpPlugin @Inject constructor( .source(Source.USER) // TODO fix - activePlugin.activeTreatments.addToHistoryTempBasal(tempBasal) + if (usePumpSync) { + addTemporaryBasalRateWithTempId(tempBasal, true) + } else { + activePlugin.activeTreatments.addToHistoryTempBasal(tempBasal) + } PumpEnactResult(injector).success(true).enacted(true) // .isTempCancel(true) } else { 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 531e6f3422..ee509ffd7d 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 @@ -348,7 +348,7 @@ class MedtronicCommunicationManager // This empty constructor must be kept, oth override fun createPumpMessageContent(type: RLMessageType): ByteArray { return when (type) { - RLMessageType.PowerOn -> medtronicUtil.buildCommandPayload(rileyLinkServiceData, MedtronicCommandType.RFPowerOn, byteArrayOf(2, 1, receiverDeviceAwakeForMinutes.toByte())) // maybe this is better FIXME + RLMessageType.PowerOn -> medtronicUtil.buildCommandPayload(rileyLinkServiceData, MedtronicCommandType.RFPowerOn, byteArrayOf(2, 1, receiverDeviceAwakeForMinutes.toByte())) RLMessageType.ReadSimpleData -> medtronicUtil.buildCommandPayload(rileyLinkServiceData, MedtronicCommandType.PumpModel, null) else -> ByteArray(0) } diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUIPostprocessor.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUIPostprocessor.kt index 21945e1707..9c340798be 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUIPostprocessor.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUIPostprocessor.kt @@ -133,18 +133,6 @@ class MedtronicUIPostprocessor @Inject constructor( medtronicUtil.pumpTime = clockDTO aapsLogger.debug(LTag.PUMP, "Pump Time: " + clockDTO.localDeviceTime + ", DeviceTime=" + clockDTO.pumpTime + // ", diff: " + dur.standardSeconds + " s") - -// if (dur.getStandardMinutes() >= 10) { -// if (isLogEnabled()) -// LOG.warn("Pump clock needs update, pump time: " + clockDTO.pumpTime.toString("HH:mm:ss") + " (difference: " -// + dur.getStandardSeconds() + " s)"); -// sendNotification(MedtronicNotificationType.PumpWrongTimeUrgent); -// } else if (dur.getStandardMinutes() >= 4) { -// if (isLogEnabled()) -// LOG.warn("Pump clock needs update, pump time: " + clockDTO.pumpTime.toString("HH:mm:ss") + " (difference: " -// + dur.getStandardSeconds() + " s)"); -// sendNotification(MedtronicNotificationType.PumpWrongTimeNormal); -// } } private fun postProcessSettings(uiTask: MedtronicUITask) { 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 index dd81eafd00..6ffbb556ae 100644 --- 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 @@ -40,7 +40,6 @@ import javax.inject.Singleton // 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( @@ -278,7 +277,6 @@ class MedtronicHistoryData @Inject constructor( */ 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))) @@ -416,24 +414,37 @@ class MedtronicHistoryData @Inject constructor( ${logPrefix}TDDs found: %d. %s """.trimIndent(), tdds.size, gson.toJson(tdds))) - val tddsDb = databaseHelper.getTDDsForLastXDays(3) + //val tddsDb = databaseHelper.getTDDsForLastXDays(3) for (tdd in tdds) { - val tddDbEntry = findTDD(tdd.atechDateTime!!, tddsDb) - val totalsDTO = tdd.decodedData!!["Object"] as DailyTotalsDTO? + //val tddDbEntry = findTDD(tdd.atechDateTime!!, tddsDb) + val totalsDTO = tdd.decodedData!!["Object"] as DailyTotalsDTO + + pumpSync.createOrUpdateTotalDailyDose( + DateTimeUtil.toMillisFromATD(tdd.atechDateTime!!), + totalsDTO.insulinBolus, + totalsDTO.insulinBasal!!, + totalsDTO.insulinTotal, + tdd.pumpId, + medtronicPumpStatus.pumpType, + medtronicPumpStatus.serialNumber!! + ) + + // timestamp: Long, bolusAmount: Double, basalAmount: Double, totalAmount: Double, + // pumpId: Long?, pumpType: PumpType, pumpSerial: String //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) - } - } + // 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) + // } + // } } } @@ -534,6 +545,7 @@ class MedtronicHistoryData @Inject constructor( val tempBasal = findTempBasalWithPumpId(tempBasalProcessDTO.itemOne!!.pumpId!!, entriesFromHistory) if (tempBasal != null) { tempBasal.durationInMinutes = tempBasalProcessDTO.duration + // TODO pumpSync - createOrUpdate(tempBasal) databaseHelper.createOrUpdate(tempBasal) aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "Edit " + ProcessHistoryRecord.TBR.description + " - (entryFromDb=%s) ", tempBasal)) } else { @@ -568,6 +580,7 @@ class MedtronicHistoryData @Inject constructor( return tbr } } + // TODO pumpSync - findTempBasalByPumpId return databaseHelper.findTempBasalByPumpId(pumpId) } @@ -591,7 +604,6 @@ class MedtronicHistoryData @Inject constructor( } 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)) @@ -636,10 +648,10 @@ class MedtronicHistoryData @Inject constructor( var outList: MutableList = mutableListOf() if (processHistoryRecord == ProcessHistoryRecord.Bolus) { - // TODO pumpSync + // TODO pumpSync - activeTreatments.getTreatmentsFromHistoryAfterTimestamp outList.addAll(activePlugin.activeTreatments.getTreatmentsFromHistoryAfterTimestamp(startTimestamp)) } else { - // TODO pumpSync + // TODO pumpSync - databaseHelper.getTemporaryBasalsDataFromTime(startTimestamp, true) outList.addAll(databaseHelper.getTemporaryBasalsDataFromTime(startTimestamp, true)) } @@ -689,7 +701,7 @@ class MedtronicHistoryData @Inject constructor( detailedBolusInfo.insulin = bolusDTO.deliveredAmount!! addCarbsFromEstimate(detailedBolusInfo, bolus) if (doubleBolusDebug) aapsLogger.debug(LTag.PUMP, "DoubleBolusDebug: addBolus(tretament==null): DetailedBolusInfo=$detailedBolusInfo") - // TODO pumpSync + // TODO pumpSync - activeTreatments.addToHistoryTreatment 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, @@ -706,7 +718,7 @@ class MedtronicHistoryData @Inject constructor( extendedBolus.durationInMinutes = bolusDTO.duration!! bolus.linkedObject = extendedBolus if (doubleBolusDebug) aapsLogger.debug(LTag.PUMP, "DoubleBolusDebug: addBolus(tretament==null): ExtendedBolus=$extendedBolus") - // TODO pumpSync + // TODO pumpSync - activeTreatments.addToHistoryExtendedBolus 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)) @@ -717,7 +729,7 @@ class MedtronicHistoryData @Inject constructor( treatment.source = Source.PUMP treatment.pumpId = bolus.pumpId!! treatment.insulin = bolusDTO!!.deliveredAmount!! - // TODO pumpSync + // TODO pumpSync - activeTreatments.createOrUpdateMedtronic(treatment) 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, @@ -730,6 +742,7 @@ class MedtronicHistoryData @Inject constructor( 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)) + // TODO pumpSync - Carbs detailedBolusInfo.carbs = bolusWizard!!.carbs.toDouble() } } @@ -749,6 +762,7 @@ class MedtronicHistoryData @Inject constructor( temporaryBasalDb.absoluteRate = tbr.insulinRate temporaryBasalDb.isAbsolute = !tbr.isPercent treatment.linkedObject = temporaryBasalDb + // TODO pumpSync - databaseHelper.createOrUpdate(tbr) databaseHelper.createOrUpdate(temporaryBasalDb) aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "$operation - [date=%d,pumpId=%d, rate=%s %s, duration=%d]", // temporaryBasalDb.getDate(), // @@ -760,6 +774,7 @@ class MedtronicHistoryData @Inject constructor( private fun processSuspends(tempBasalProcessList: List) { for (tempBasalProcess in tempBasalProcessList) { + // TODO pumpSync - databaseHelper.findTempBasalByPumpId var tempBasal = databaseHelper.findTempBasalByPumpId(tempBasalProcess.itemOne!!.pumpId!!) if (tempBasal == null) { // add @@ -772,6 +787,7 @@ class MedtronicHistoryData @Inject constructor( tempBasal.isAbsolute = true tempBasalProcess.itemOne!!.linkedObject = tempBasal tempBasalProcess.itemTwo!!.linkedObject = tempBasal + // TODO pumpSync -databaseHelper.createOrUpdate(tbr-suspebd( databaseHelper.createOrUpdate(tempBasal) } } @@ -928,52 +944,19 @@ class MedtronicHistoryData @Inject constructor( 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 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 diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/DailyTotalsDTO.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/DailyTotalsDTO.kt index 37284cffe1..f6f5c99300 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/DailyTotalsDTO.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/DailyTotalsDTO.kt @@ -1,7 +1,7 @@ package info.nightscout.androidaps.plugins.pump.medtronic.data.dto import com.google.gson.annotations.Expose -import info.nightscout.androidaps.db.TDD +//import info.nightscout.androidaps.db.TDD import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil import info.nightscout.androidaps.plugins.pump.common.utils.StringUtil @@ -34,13 +34,13 @@ class DailyTotalsDTO(var entry: PumpHistoryEntry) { private val sensorDataCount: Int? = null @Expose - private var insulinTotal = 0.0 + var insulinTotal = 0.0 @Expose - private var insulinBasal: Double? = 0.0 + var insulinBasal: Double? = 0.0 @Expose - private var insulinBolus = 0.0 + var insulinBolus = 0.0 private var insulinCarbs: Double? = null private var bolusTotal: Double? = null private var bolusFood: Double? = null @@ -177,16 +177,16 @@ class DailyTotalsDTO(var entry: PumpHistoryEntry) { .toString() } - fun setTDD(tdd: TDD) { - tdd.date = DateTimeUtil.toMillisFromATD(entry.atechDateTime!!) - tdd.basal = insulinBasal!! - tdd.bolus = insulinBolus - tdd.total = insulinTotal - } - - fun doesEqual(tdd: TDD): Boolean { - return tdd.total == insulinTotal && tdd.bolus == insulinBolus && tdd.basal == insulinBasal - } + // fun setTDD(tdd: TDD) { + // tdd.date = DateTimeUtil.toMillisFromATD(entry.atechDateTime!!) + // tdd.basal = insulinBasal!! + // tdd.bolus = insulinBolus + // tdd.total = insulinTotal + // } + // + // fun doesEqual(tdd: TDD): Boolean { + // return tdd.total == insulinTotal && tdd.bolus == insulinBolus && tdd.basal == insulinBasal + // } init { when (entry.entryType) { From 358c738076f7797d8f301f11e3c17f2dcd038d9d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 28 Apr 2021 07:11:47 +0000 Subject: [PATCH 013/145] Bump dagger_version from 2.34.1 to 2.35.1 Bumps `dagger_version` from 2.34.1 to 2.35.1. Updates `dagger-compiler` from 2.34.1 to 2.35.1 - [Release notes](https://github.com/google/dagger/releases) - [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md) - [Commits](https://github.com/google/dagger/compare/dagger-2.34.1...dagger-2.35.1) Updates `dagger-android-processor` from 2.34.1 to 2.35.1 - [Release notes](https://github.com/google/dagger/releases) - [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md) - [Commits](https://github.com/google/dagger/compare/dagger-2.34.1...dagger-2.35.1) Updates `dagger-android` from 2.34.1 to 2.35.1 - [Release notes](https://github.com/google/dagger/releases) - [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md) - [Commits](https://github.com/google/dagger/compare/dagger-2.34.1...dagger-2.35.1) Updates `dagger-android-support` from 2.34.1 to 2.35.1 - [Release notes](https://github.com/google/dagger/releases) - [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md) - [Commits](https://github.com/google/dagger/compare/dagger-2.34.1...dagger-2.35.1) Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 7b872f31b7..84dad116b7 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ buildscript { rxkotlin_version = '2.4.0' room_version = '2.2.6' lifecycle_version = '2.3.1' - dagger_version = '2.34.1' + dagger_version = '2.35.1' coroutinesVersion = '1.4.1' activityVersion = '1.2.0' fragmentktx_version = '1.3.0' From 18e19ae4c901a342f6d40fb57dd565ec612d6ec5 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Thu, 29 Apr 2021 14:47:08 +0200 Subject: [PATCH 014/145] Fix: Insight capabilities; fix reference to basal/bolus. --- .../nightscout/androidaps/plugins/pump/common/defs/PumpType.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpType.kt b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpType.kt index d372c84c6b..147ce98801 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpType.kt +++ b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpType.kt @@ -89,7 +89,7 @@ enum class PumpType { baseBasalMinValue = 0.02, baseBasalMaxValue = null, baseBasalStep = 0.01, - baseBasalSpecialSteps = DoseStepSize.InsightBolus, + baseBasalSpecialSteps = DoseStepSize.InsightBasal, pumpCapability = PumpCapability.InsightCapabilities), ACCU_CHEK_SOLO(description = "Accu-Chek Solo", manufacturer = ManufacturerType.Roche, From 970aebc6db8655937963d89b24d813dc45cea465 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Thu, 29 Apr 2021 14:48:22 +0200 Subject: [PATCH 015/145] Refactor: rename PumpDescription.setPumpDescription to pd.fillFor(). --- .../androidaps/plugins/pump/virtual/VirtualPumpPlugin.kt | 2 +- .../nightscout/androidaps/plugins/pump/combo/ComboPlugin.java | 2 +- .../info/nightscout/androidaps/interfaces/PumpDescription.kt | 4 ++-- .../androidaps/plugins/configBuilder/RunningConfiguration.kt | 2 +- .../nightscout/androidaps/interfaces/PumpDescriptionTest.kt | 2 +- .../nightscout/androidaps/plugins/aps/loop/APSResultTest.kt | 4 ++-- .../nightscout/androidaps/danaRKorean/DanaRKoreanPlugin.kt | 2 +- .../info/nightscout/androidaps/danaRv2/DanaRv2Plugin.java | 2 +- .../java/info/nightscout/androidaps/danar/DanaRPlugin.java | 2 +- .../androidaps/plugins/pump/insight/LocalInsightPlugin.java | 2 +- .../androidaps/plugins/pump/common/PumpPluginAbstract.java | 4 ++-- 11 files changed, 14 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPlugin.kt index b595da0409..afc7f59b97 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPlugin.kt @@ -400,7 +400,7 @@ open class VirtualPumpPlugin @Inject constructor( aapsLogger.debug(LTag.PUMP, "Pump in configuration: $pumpType, PumpType object: $pumpTypeNew") if (this.pumpType == pumpTypeNew) return aapsLogger.debug(LTag.PUMP, "New pump configuration found ($pumpTypeNew), changing from previous (${this.pumpType})") - pumpDescription.setPumpDescription(pumpTypeNew) + pumpDescription.fillFor(pumpTypeNew) this.pumpType = pumpTypeNew } diff --git a/combo/src/main/java/info/nightscout/androidaps/plugins/pump/combo/ComboPlugin.java b/combo/src/main/java/info/nightscout/androidaps/plugins/pump/combo/ComboPlugin.java index 1f17b035cc..b98ac52f15 100644 --- a/combo/src/main/java/info/nightscout/androidaps/plugins/pump/combo/ComboPlugin.java +++ b/combo/src/main/java/info/nightscout/androidaps/plugins/pump/combo/ComboPlugin.java @@ -160,7 +160,7 @@ public class ComboPlugin extends PumpPluginBase implements Pump, Constraints { this.pumpSync = pumpSync; this.dateUtil = dateUtil; - pumpDescription.setPumpDescription(PumpType.ACCU_CHEK_COMBO); + pumpDescription.fillFor(PumpType.ACCU_CHEK_COMBO); } @Override protected void onStart() { diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/PumpDescription.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/PumpDescription.kt index 0aec8d7484..136e899a2c 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/PumpDescription.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/PumpDescription.kt @@ -7,7 +7,7 @@ import info.nightscout.androidaps.plugins.pump.common.defs.PumpType class PumpDescription() { constructor(pumpType: PumpType) : this() { - setPumpDescription(pumpType) + fillFor(pumpType) } var pumpType = PumpType.GENERIC_AAPS @@ -69,7 +69,7 @@ class PumpDescription() { hasCustomUnreachableAlertCheck = false } - fun setPumpDescription(pumpType: PumpType) { + fun fillFor(pumpType: PumpType) { resetSettings() this.pumpType = pumpType val pumpCapability = pumpType.pumpCapability ?: return diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/configBuilder/RunningConfiguration.kt b/core/src/main/java/info/nightscout/androidaps/plugins/configBuilder/RunningConfiguration.kt index cf3b151d4d..7b5cb9c382 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/configBuilder/RunningConfiguration.kt +++ b/core/src/main/java/info/nightscout/androidaps/plugins/configBuilder/RunningConfiguration.kt @@ -82,7 +82,7 @@ class RunningConfiguration @Inject constructor( if (configuration.has("pump")) { val pumpType = JsonHelper.safeGetString(configuration, "pump", PumpType.GENERIC_AAPS.description) sp.putString(R.string.key_virtualpump_type, pumpType) - activePlugin.activePump.pumpDescription.setPumpDescription(PumpType.getByDescription(pumpType)) + activePlugin.activePump.pumpDescription.fillFor(PumpType.getByDescription(pumpType)) aapsLogger.debug(LTag.CORE, "Changing pump type to $pumpType") } diff --git a/core/src/test/java/info/nightscout/androidaps/interfaces/PumpDescriptionTest.kt b/core/src/test/java/info/nightscout/androidaps/interfaces/PumpDescriptionTest.kt index 392c7f9791..397619d21a 100644 --- a/core/src/test/java/info/nightscout/androidaps/interfaces/PumpDescriptionTest.kt +++ b/core/src/test/java/info/nightscout/androidaps/interfaces/PumpDescriptionTest.kt @@ -10,7 +10,7 @@ class PumpDescriptionTest { @Test fun setPumpDescription() { val pumpDescription = PumpDescription() - pumpDescription.setPumpDescription(PumpType.ACCU_CHEK_COMBO) + pumpDescription.fillFor(PumpType.ACCU_CHEK_COMBO) Assert.assertEquals(pumpDescription.bolusStep, PumpType.ACCU_CHEK_COMBO.bolusSize, 0.1) Assert.assertEquals(pumpDescription.basalMinimumRate, PumpType.ACCU_CHEK_COMBO.baseBasalStep, 0.1) Assert.assertEquals(pumpDescription.basalStep, PumpType.ACCU_CHEK_COMBO.baseBasalStep, 0.1) diff --git a/core/src/test/java/info/nightscout/androidaps/plugins/aps/loop/APSResultTest.kt b/core/src/test/java/info/nightscout/androidaps/plugins/aps/loop/APSResultTest.kt index 40a6cd3c20..aa3b7944b3 100644 --- a/core/src/test/java/info/nightscout/androidaps/plugins/aps/loop/APSResultTest.kt +++ b/core/src/test/java/info/nightscout/androidaps/plugins/aps/loop/APSResultTest.kt @@ -51,7 +51,7 @@ class APSResultTest : TestBaseWithProfile() { // BASAL RATE IN TEST PROFILE IS 1U/h // **** PERCENT pump **** - testPumpPlugin.pumpDescription.setPumpDescription(PumpType.CELLNOVO) // % based + testPumpPlugin.pumpDescription.fillFor(PumpType.CELLNOVO) // % based apsResult.usePercent(true) // closed loop mode return original request @@ -109,7 +109,7 @@ class APSResultTest : TestBaseWithProfile() { Assert.assertEquals(true, apsResult.isChangeRequested) // **** ABSOLUTE pump **** - testPumpPlugin.pumpDescription.setPumpDescription(PumpType.MEDTRONIC_515_715) // U/h based + testPumpPlugin.pumpDescription.fillFor(PumpType.MEDTRONIC_515_715) // U/h based apsResult.usePercent(false) // open loop diff --git a/danar/src/main/java/info/nightscout/androidaps/danaRKorean/DanaRKoreanPlugin.kt b/danar/src/main/java/info/nightscout/androidaps/danaRKorean/DanaRKoreanPlugin.kt index 0f9669df39..16616efe46 100644 --- a/danar/src/main/java/info/nightscout/androidaps/danaRKorean/DanaRKoreanPlugin.kt +++ b/danar/src/main/java/info/nightscout/androidaps/danaRKorean/DanaRKoreanPlugin.kt @@ -60,7 +60,7 @@ class DanaRKoreanPlugin @Inject constructor( init { pluginDescription.description(R.string.description_pump_dana_r_korean) useExtendedBoluses = sp.getBoolean(R.string.key_danar_useextended, false) - pumpDescription.setPumpDescription(PumpType.DANA_R_KOREAN) + pumpDescription.fillFor(PumpType.DANA_R_KOREAN) } override fun onStart() { diff --git a/danar/src/main/java/info/nightscout/androidaps/danaRv2/DanaRv2Plugin.java b/danar/src/main/java/info/nightscout/androidaps/danaRv2/DanaRv2Plugin.java index 34309dd182..86685217ee 100644 --- a/danar/src/main/java/info/nightscout/androidaps/danaRv2/DanaRv2Plugin.java +++ b/danar/src/main/java/info/nightscout/androidaps/danaRv2/DanaRv2Plugin.java @@ -85,7 +85,7 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin { getPluginDescription().description(R.string.description_pump_dana_r_v2); useExtendedBoluses = false; - pumpDescription.setPumpDescription(PumpType.DANA_RV2); + pumpDescription.fillFor(PumpType.DANA_RV2); } @Override diff --git a/danar/src/main/java/info/nightscout/androidaps/danar/DanaRPlugin.java b/danar/src/main/java/info/nightscout/androidaps/danar/DanaRPlugin.java index 6aaa1f2bf2..17f831893a 100644 --- a/danar/src/main/java/info/nightscout/androidaps/danar/DanaRPlugin.java +++ b/danar/src/main/java/info/nightscout/androidaps/danar/DanaRPlugin.java @@ -74,7 +74,7 @@ public class DanaRPlugin extends AbstractDanaRPlugin { this.fabricPrivacy = fabricPrivacy; useExtendedBoluses = sp.getBoolean(R.string.key_danar_useextended, false); - pumpDescription.setPumpDescription(PumpType.DANA_R); + pumpDescription.fillFor(PumpType.DANA_R); } @Override diff --git a/insight/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java b/insight/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java index 2ba8ced252..c211d2380e 100644 --- a/insight/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java +++ b/insight/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java @@ -242,7 +242,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements Pump, Constrai this.pumpSync = pumpSync; pumpDescription = new PumpDescription(); - pumpDescription.setPumpDescription(PumpType.ACCU_CHEK_INSIGHT_BLUETOOTH); + pumpDescription.fillFor(PumpType.ACCU_CHEK_INSIGHT_BLUETOOTH); } public TBROverNotificationBlock getTBROverNotificationBlock() { diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java index 47077d5135..d785153d49 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java @@ -99,7 +99,7 @@ public abstract class PumpPluginAbstract extends PumpPluginBase implements Pump, this.sp = sp; this.commandQueue = commandQueue; - pumpDescription.setPumpDescription(pumpType); + pumpDescription.fillFor(pumpType); this.pumpType = pumpType; this.dateUtil = dateUtil; this.aapsSchedulers = aapsSchedulers; @@ -457,7 +457,7 @@ public abstract class PumpPluginAbstract extends PumpPluginBase implements Pump, public void setPumpType(PumpType pumpType) { this.pumpType = pumpType; - this.pumpDescription.setPumpDescription(pumpType); + this.pumpDescription.fillFor(pumpType); } From c52526cf6fb66823dc8c667071697157d3f14eac Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Thu, 29 Apr 2021 14:49:55 +0200 Subject: [PATCH 016/145] Fix: Insight; change references to correct Pumpdescription. --- .../plugins/pump/insight/LocalInsightPlugin.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/insight/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java b/insight/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java index c211d2380e..1bd72c2245 100644 --- a/insight/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java +++ b/insight/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java @@ -606,7 +606,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements Pump, Constrai insightBolusID.pumpSerial = connectionService.getPumpSystemIdentification().getSerialNumber(); databaseHelper.createOrUpdate(insightBolusID); detailedBolusInfo.setBolusTimestamp(insightBolusID.timestamp); - detailedBolusInfo.setPumpType(PumpType.ACCU_CHEK_INSIGHT); + detailedBolusInfo.setPumpType(PumpType.ACCU_CHEK_INSIGHT_BLUETOOTH); detailedBolusInfo.setPumpSerial(serialNumber()); detailedBolusInfo.setBolusPumpId(insightBolusID.id); if (detailedBolusInfo.carbs > 0 && detailedBolusInfo.carbTime != 0) { @@ -1388,7 +1388,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements Pump, Constrai if (event.getBolusType() == BolusType.STANDARD || event.getBolusType() == BolusType.MULTIWAVE) { DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo(); detailedBolusInfo.timestamp = bolusID.timestamp; - detailedBolusInfo.setPumpType(PumpType.ACCU_CHEK_INSIGHT); + detailedBolusInfo.setPumpType(PumpType.ACCU_CHEK_INSIGHT_BLUETOOTH); detailedBolusInfo.setPumpSerial(serialNumber()); detailedBolusInfo.setBolusPumpId(bolusID.id); detailedBolusInfo.insulin = event.getImmediateAmount(); @@ -1423,7 +1423,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements Pump, Constrai if (event.getBolusType() == BolusType.STANDARD || event.getBolusType() == BolusType.MULTIWAVE) { DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo(); detailedBolusInfo.setBolusTimestamp(bolusID.timestamp); - detailedBolusInfo.setPumpType(PumpType.ACCU_CHEK_INSIGHT); + detailedBolusInfo.setPumpType(PumpType.ACCU_CHEK_INSIGHT_BLUETOOTH); detailedBolusInfo.setPumpSerial(serialNumber()); detailedBolusInfo.setBolusPumpId(bolusID.id); detailedBolusInfo.insulin = event.getImmediateAmount(); @@ -1551,7 +1551,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements Pump, Constrai } private void logNote(long date, String note) { - pumpSync.insertTherapyEventIfNewWithTimestamp(date, DetailedBolusInfo.EventType.NOTE, note, null, PumpType.ACCU_CHEK_INSIGHT, serialNumber()); + pumpSync.insertTherapyEventIfNewWithTimestamp(date, DetailedBolusInfo.EventType.NOTE, note, null, PumpType.ACCU_CHEK_INSIGHT_BLUETOOTH, serialNumber()); } private long parseRelativeDate(int year, int month, int day, int hour, int minute, int second, int relativeHour, int relativeMinute, int relativeSecond) { @@ -1568,7 +1568,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements Pump, Constrai } private void uploadCareportalEvent(long date, DetailedBolusInfo.EventType event) { - pumpSync.insertTherapyEventIfNewWithTimestamp(date, event, null, null, PumpType.ACCU_CHEK_INSIGHT, serialNumber()); + pumpSync.insertTherapyEventIfNewWithTimestamp(date, event, null, null, PumpType.ACCU_CHEK_INSIGHT_BLUETOOTH, serialNumber()); } @NonNull @Override From 884eb497bde15cfb79f336d2920f193976a06b1e Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Thu, 29 Apr 2021 14:50:41 +0200 Subject: [PATCH 017/145] Refactor: Rename ACCU_CHEK_INSIGHT -> ACCU_CHEK_VIRTUAL. --- .../info/nightscout/androidaps/activities/TDDStatsActivity.kt | 2 +- .../androidaps/plugins/pump/common/defs/PumpType.kt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/info/nightscout/androidaps/activities/TDDStatsActivity.kt b/core/src/main/java/info/nightscout/androidaps/activities/TDDStatsActivity.kt index 353f808935..34fdbfba62 100644 --- a/core/src/main/java/info/nightscout/androidaps/activities/TDDStatsActivity.kt +++ b/core/src/main/java/info/nightscout/androidaps/activities/TDDStatsActivity.kt @@ -422,7 +422,7 @@ class TDDStatsActivity : NoSplashAppCompatActivity() { private fun isOldData(historyList: List): Boolean { val type = activePlugin.activePump.pumpDescription.pumpType - val startsYesterday = type == PumpType.DANA_R || type == PumpType.DANA_RS || type == PumpType.DANA_RV2 || type == PumpType.DANA_R_KOREAN || type == PumpType.ACCU_CHEK_INSIGHT + val startsYesterday = type == PumpType.DANA_R || type == PumpType.DANA_RS || type == PumpType.DANA_RV2 || type == PumpType.DANA_R_KOREAN || type == PumpType.ACCU_CHEK_INSIGHT_VIRTUAL val df: DateFormat = SimpleDateFormat("dd.MM.", Locale.getDefault()) return historyList.size < 3 || df.format(Date(historyList[0].date)) != df.format(Date(System.currentTimeMillis() - if (startsYesterday) 1000 * 60 * 60 * 24 else 0)) } diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpType.kt b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpType.kt index 147ce98801..4f73ef0d6a 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpType.kt +++ b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpType.kt @@ -64,7 +64,7 @@ enum class PumpType { baseBasalStep = 0.1, baseBasalSpecialSteps = null, pumpCapability = PumpCapability.VirtualPumpCapabilities), - ACCU_CHEK_INSIGHT(description = "Accu-Chek Insight", + ACCU_CHEK_INSIGHT_VIRTUAL(description = "Accu-Chek Insight", manufacturer = ManufacturerType.Roche, model = "Insight", bolusSize = 0.05, @@ -418,7 +418,7 @@ enum class PumpType { CELLNOVO -> InterfaceIDs.PumpType.CELLNOVO ACCU_CHEK_COMBO -> InterfaceIDs.PumpType.ACCU_CHEK_COMBO ACCU_CHEK_SPIRIT -> InterfaceIDs.PumpType.ACCU_CHEK_SPIRIT - ACCU_CHEK_INSIGHT -> InterfaceIDs.PumpType.ACCU_CHEK_INSIGHT + ACCU_CHEK_INSIGHT_VIRTUAL -> InterfaceIDs.PumpType.ACCU_CHEK_INSIGHT ACCU_CHEK_INSIGHT_BLUETOOTH -> InterfaceIDs.PumpType.ACCU_CHEK_INSIGHT_BLUETOOTH ACCU_CHEK_SOLO -> InterfaceIDs.PumpType.ACCU_CHEK_SOLO ANIMAS_VIBE -> InterfaceIDs.PumpType.ANIMAS_VIBE From c62d92e984fba73a544e13cf063af1bf51143b30 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Thu, 29 Apr 2021 14:58:58 +0200 Subject: [PATCH 018/145] Refactor: Remove (now) superflous BLUETOOTH from ACCU_CHEK_INSIGHT_BLUETHOOTH. This aligns with the naming of other pumps and BLUETOOTH doesn't provide much information. --- .../plugins/pump/common/defs/PumpType.kt | 8 ++++---- .../plugins/pump/insight/LocalInsightPlugin.java | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpType.kt b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpType.kt index 4f73ef0d6a..387386f927 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpType.kt +++ b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpType.kt @@ -77,7 +77,7 @@ enum class PumpType { baseBasalStep = 0.01, baseBasalSpecialSteps = null, pumpCapability = PumpCapability.InsightCapabilities), - ACCU_CHEK_INSIGHT_BLUETOOTH(description = "Accu-Chek Insight", + ACCU_CHEK_INSIGHT(description = "Accu-Chek Insight", manufacturer = ManufacturerType.Roche, model = "Insight", bolusSize = 0.01, @@ -418,9 +418,9 @@ enum class PumpType { CELLNOVO -> InterfaceIDs.PumpType.CELLNOVO ACCU_CHEK_COMBO -> InterfaceIDs.PumpType.ACCU_CHEK_COMBO ACCU_CHEK_SPIRIT -> InterfaceIDs.PumpType.ACCU_CHEK_SPIRIT - ACCU_CHEK_INSIGHT_VIRTUAL -> InterfaceIDs.PumpType.ACCU_CHEK_INSIGHT - ACCU_CHEK_INSIGHT_BLUETOOTH -> InterfaceIDs.PumpType.ACCU_CHEK_INSIGHT_BLUETOOTH - ACCU_CHEK_SOLO -> InterfaceIDs.PumpType.ACCU_CHEK_SOLO + ACCU_CHEK_INSIGHT_VIRTUAL -> InterfaceIDs.PumpType.ACCU_CHEK_INSIGHT + ACCU_CHEK_INSIGHT -> InterfaceIDs.PumpType.ACCU_CHEK_INSIGHT_BLUETOOTH + ACCU_CHEK_SOLO -> InterfaceIDs.PumpType.ACCU_CHEK_SOLO ANIMAS_VIBE -> InterfaceIDs.PumpType.ANIMAS_VIBE ANIMAS_PING -> InterfaceIDs.PumpType.ANIMAS_PING DANA_R -> InterfaceIDs.PumpType.DANA_R diff --git a/insight/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java b/insight/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java index 1bd72c2245..f9a333e39a 100644 --- a/insight/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java +++ b/insight/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java @@ -242,7 +242,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements Pump, Constrai this.pumpSync = pumpSync; pumpDescription = new PumpDescription(); - pumpDescription.fillFor(PumpType.ACCU_CHEK_INSIGHT_BLUETOOTH); + pumpDescription.fillFor(PumpType.ACCU_CHEK_INSIGHT); } public TBROverNotificationBlock getTBROverNotificationBlock() { @@ -606,7 +606,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements Pump, Constrai insightBolusID.pumpSerial = connectionService.getPumpSystemIdentification().getSerialNumber(); databaseHelper.createOrUpdate(insightBolusID); detailedBolusInfo.setBolusTimestamp(insightBolusID.timestamp); - detailedBolusInfo.setPumpType(PumpType.ACCU_CHEK_INSIGHT_BLUETOOTH); + detailedBolusInfo.setPumpType(PumpType.ACCU_CHEK_INSIGHT); detailedBolusInfo.setPumpSerial(serialNumber()); detailedBolusInfo.setBolusPumpId(insightBolusID.id); if (detailedBolusInfo.carbs > 0 && detailedBolusInfo.carbTime != 0) { @@ -1027,7 +1027,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements Pump, Constrai @NonNull @Override public PumpType model() { - return PumpType.ACCU_CHEK_INSIGHT_BLUETOOTH; + return PumpType.ACCU_CHEK_INSIGHT; } @NonNull @Override @@ -1388,7 +1388,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements Pump, Constrai if (event.getBolusType() == BolusType.STANDARD || event.getBolusType() == BolusType.MULTIWAVE) { DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo(); detailedBolusInfo.timestamp = bolusID.timestamp; - detailedBolusInfo.setPumpType(PumpType.ACCU_CHEK_INSIGHT_BLUETOOTH); + detailedBolusInfo.setPumpType(PumpType.ACCU_CHEK_INSIGHT); detailedBolusInfo.setPumpSerial(serialNumber()); detailedBolusInfo.setBolusPumpId(bolusID.id); detailedBolusInfo.insulin = event.getImmediateAmount(); @@ -1423,7 +1423,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements Pump, Constrai if (event.getBolusType() == BolusType.STANDARD || event.getBolusType() == BolusType.MULTIWAVE) { DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo(); detailedBolusInfo.setBolusTimestamp(bolusID.timestamp); - detailedBolusInfo.setPumpType(PumpType.ACCU_CHEK_INSIGHT_BLUETOOTH); + detailedBolusInfo.setPumpType(PumpType.ACCU_CHEK_INSIGHT); detailedBolusInfo.setPumpSerial(serialNumber()); detailedBolusInfo.setBolusPumpId(bolusID.id); detailedBolusInfo.insulin = event.getImmediateAmount(); @@ -1551,7 +1551,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements Pump, Constrai } private void logNote(long date, String note) { - pumpSync.insertTherapyEventIfNewWithTimestamp(date, DetailedBolusInfo.EventType.NOTE, note, null, PumpType.ACCU_CHEK_INSIGHT_BLUETOOTH, serialNumber()); + pumpSync.insertTherapyEventIfNewWithTimestamp(date, DetailedBolusInfo.EventType.NOTE, note, null, PumpType.ACCU_CHEK_INSIGHT, serialNumber()); } private long parseRelativeDate(int year, int month, int day, int hour, int minute, int second, int relativeHour, int relativeMinute, int relativeSecond) { @@ -1568,7 +1568,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements Pump, Constrai } private void uploadCareportalEvent(long date, DetailedBolusInfo.EventType event) { - pumpSync.insertTherapyEventIfNewWithTimestamp(date, event, null, null, PumpType.ACCU_CHEK_INSIGHT_BLUETOOTH, serialNumber()); + pumpSync.insertTherapyEventIfNewWithTimestamp(date, event, null, null, PumpType.ACCU_CHEK_INSIGHT, serialNumber()); } @NonNull @Override From 6504498cd246ba78622ec6e62f467d59938ce82b Mon Sep 17 00:00:00 2001 From: Andy Rozman Date: Fri, 30 Apr 2021 15:28:24 +0100 Subject: [PATCH 019/145] - added bolus handling (complete) - added PumpSyncStorage class for handling temporary data --- .../dependencyInjection/AppModule.kt | 11 + .../plugins/pump/common/sync/PumpDbEntry.kt | 32 +++ .../common/sync/PumpSyncEntriesCreator.java | 13 + .../pump/common/sync/PumpSyncStorage.kt | 154 ++++++++++ .../plugins/pump/common/PumpPluginAbstract.kt | 58 +--- .../plugins/pump/common/data/PumpDbEntry.kt | 9 - .../plugins/pump/common/data/PumpStatus.kt | 2 +- .../pump/medtronic/MedtronicPumpPlugin.kt | 74 ++--- .../comm/MedtronicCommunicationManager.kt | 11 +- .../comm/history/pump/PumpHistoryEntryType.kt | 2 +- .../comm/history/pump/PumpHistoryResult.kt | 2 + .../medtronic/data/MedtronicHistoryData.kt | 268 +++++++++++++++--- .../pump/medtronic/data/dto/BasalProfile.kt | 7 +- .../medtronic/defs/MedtronicCommandType.kt | 3 +- .../medtronic/driver/MedtronicPumpStatus.kt | 17 +- medtronic/src/main/res/values/strings.xml | 1 + 16 files changed, 515 insertions(+), 149 deletions(-) create mode 100644 core/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpDbEntry.kt create mode 100644 core/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpSyncEntriesCreator.java create mode 100644 core/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpSyncStorage.kt delete mode 100644 medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpDbEntry.kt diff --git a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppModule.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppModule.kt index 740426792c..46af1a1228 100644 --- a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppModule.kt +++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppModule.kt @@ -21,6 +21,7 @@ import info.nightscout.androidaps.plugins.general.nsclient.UploadQueue import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.plugins.pump.PumpSyncImplementation +import info.nightscout.androidaps.plugins.pump.common.sync.PumpSyncStorage import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.queue.CommandQueue import info.nightscout.androidaps.utils.androidNotification.NotificationHolderImpl @@ -72,6 +73,16 @@ open class AppModule { rxBus: RxBusWrapper ): UploadQueueAdminInterface = UploadQueue(aapsLogger, databaseHelper, context, sp, rxBus) + @Provides + @Singleton + fun providesPumpSyncStorage( + pumpSync: PumpSync, + sp: SP, + aapsLogger: AAPSLogger + ): PumpSyncStorage { + return PumpSyncStorage(pumpSync, sp, aapsLogger) + } + @Module interface AppBindings { @Binds fun bindContext(mainApp: MainApp): Context diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpDbEntry.kt b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpDbEntry.kt new file mode 100644 index 0000000000..08a782c918 --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpDbEntry.kt @@ -0,0 +1,32 @@ +package info.nightscout.androidaps.plugins.pump.common.sync + +import info.nightscout.androidaps.data.DetailedBolusInfo +import info.nightscout.androidaps.plugins.pump.common.defs.PumpType + + +data class PumpDbEntry constructor(var temporaryId: Long, + var date: Long, + var pumpType: PumpType, + var serialNumber: String, + var bolusData: PumpDbEntryBolus? = null, + var tbrData: PumpDbEntryTBR? = null ) { + + constructor(temporaryId: Long, + date: Long, + pumpType: PumpType, + serialNumber: String, + detailedBolusInfo: DetailedBolusInfo) : this(temporaryId, date, pumpType, serialNumber) { + this.bolusData = PumpDbEntryBolus( + detailedBolusInfo.insulin, + detailedBolusInfo.carbs, + detailedBolusInfo.bolusType) + } +} + + +data class PumpDbEntryBolus(var insulin: Double, + var carbs: Double, + var bolusType: DetailedBolusInfo.BolusType) + + +data class PumpDbEntryTBR(var temporaryId: Long) \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpSyncEntriesCreator.java b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpSyncEntriesCreator.java new file mode 100644 index 0000000000..1ba73df0bb --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpSyncEntriesCreator.java @@ -0,0 +1,13 @@ +package info.nightscout.androidaps.plugins.pump.common.sync; + +import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; + +public interface PumpSyncEntriesCreator { + + long generateTempId(Object dataObject); + + PumpType model(); + + String serialNumber(); + +} diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpSyncStorage.kt b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpSyncStorage.kt new file mode 100644 index 0000000000..3bb07b770c --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpSyncStorage.kt @@ -0,0 +1,154 @@ +package info.nightscout.androidaps.plugins.pump.common.sync + +import com.google.gson.Gson +import com.google.gson.GsonBuilder +import com.google.gson.reflect.TypeToken +import info.nightscout.androidaps.data.DetailedBolusInfo +import info.nightscout.androidaps.db.TemporaryBasal +import info.nightscout.androidaps.interfaces.PumpSync +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.utils.sharedPreferences.SP +import java.lang.reflect.Type +import javax.inject.Inject +import javax.inject.Singleton + +/** + * This class is intended for Pump Drivers that use temporaryId and need way to pair records + */ +@Singleton +class PumpSyncStorage @Inject constructor( + val pumpSync: PumpSync, + val sp: SP, + val aapsLogger: AAPSLogger +) { + + val pumpSyncStorageKey: String = "pump_sync_storage" + var pumpSyncStorage: MutableMap> = mutableMapOf() + var TBR: String = "TBR" + var BOLUS: String = "BOLUS" + var storageInitialized: Boolean = false + var gson: Gson = GsonBuilder().create() + + + init { + initStorage() + } + + + fun initStorage() { + if (storageInitialized) + return + + var loaded = false + + if (sp.contains(pumpSyncStorageKey)) { + val jsonData: String = sp.getString("pump_sync_storage", ""); + + if (!jsonData.isBlank()) { + + val pumpSyncStorageType: Type = object : TypeToken>>() {}.getType() + + val baseMap: MutableMap> = gson.fromJson(jsonData, pumpSyncStorageType) //as MutableMap> + + pumpSyncStorage = baseMap + + aapsLogger.debug(String.format("Loading Pump Sync Storage: boluses=%d, tbrs=%d.", pumpSyncStorage[BOLUS]!!.size, pumpSyncStorage[TBR]!!.size)) + loaded = true + } + } + + if (!loaded) { + pumpSyncStorage[BOLUS] = mutableListOf() + pumpSyncStorage[TBR] = mutableListOf() + } + } + + + fun saveStorage() { + if (!isStorageEmpty()) { + sp.putString(pumpSyncStorageKey, gson.toJson(pumpSyncStorage)) + aapsLogger.debug(String.format("Saving Pump Sync Storage: boluses=%d, tbrs=%d.", pumpSyncStorage[BOLUS]!!.size, pumpSyncStorage[TBR]!!.size)) + } + } + + + fun isStorageEmpty() : Boolean { + return pumpSyncStorage[BOLUS]!!.isEmpty() && pumpSyncStorage[TBR]!!.isEmpty() + } + + + fun getBoluses() : MutableList { + return pumpSyncStorage[BOLUS]!!; + } + + fun getTBRs() : MutableList { + return pumpSyncStorage[TBR]!!; + } + + + //abstract fun generateTempId(timeMillis: Long): Long + + fun addBolusWithTempId(detailedBolusInfo: DetailedBolusInfo, writeToInternalHistory: Boolean, creator: PumpSyncEntriesCreator): Boolean { + val temporaryId = creator.generateTempId(detailedBolusInfo.timestamp) + val response = pumpSync.addBolusWithTempId( + detailedBolusInfo.timestamp, + detailedBolusInfo.insulin, + temporaryId, + detailedBolusInfo.bolusType, + creator.model(), + creator.serialNumber()) + if (response && writeToInternalHistory) { + var innerList: MutableList = pumpSyncStorage[BOLUS]!! + + innerList.add(PumpDbEntry(temporaryId, detailedBolusInfo.timestamp, creator.model(), creator.serialNumber(), detailedBolusInfo)) + pumpSyncStorage[BOLUS] = innerList + saveStorage() + } + return response + } + + // TODO + fun addTemporaryBasalRateWithTempId(temporaryBasal: TemporaryBasal, writeToInternalHistory: Boolean, creator: PumpSyncEntriesCreator) : Boolean { + // val temporaryId = generateTempId(temporaryBasal.date) + // val response = pumpSync.addBolusWithTempId(temporaryBasal.timestamp, detailedBolusInfo.insulin, + // generateTempId(detailedBolusInfo.timestamp), detailedBolusInfo.getBolusType(), + // getPumpType(), serialNumber()); + // + // if (response && writeToInternalHistory) { + // driverHistory.put(temporaryId, new PumpDbEntry(temporaryId, model(), serialNumber(), detailedBolusInfo)); + // sp.putString(MedtronicConst.Statistics.InternalTemporaryDatabase, gson.toJson(driverHistory)); + // } + // + // return response; + return false + } + + fun removeBolusWithTemporaryId(temporaryId: Long) { + val bolusList = removeTemporaryId(temporaryId, pumpSyncStorage[BOLUS]!!) + pumpSyncStorage[BOLUS] = bolusList + saveStorage() + } + + fun removeTemporaryBasalWithTemporaryId(temporaryId: Long) { + val tbrList = removeTemporaryId(temporaryId, pumpSyncStorage[TBR]!!) + pumpSyncStorage[TBR] = tbrList + saveStorage() + } + + private fun removeTemporaryId(temporaryId: Long, list: MutableList): MutableList { + var dbEntry: PumpDbEntry? = null + + for (pumpDbEntry in list) { + if (pumpDbEntry.temporaryId == temporaryId) { + dbEntry = pumpDbEntry + } + } + + if (dbEntry!=null) { + list.remove(dbEntry) + } + + return list + } + +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.kt index 4ac44e2627..d88a3d362d 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.kt @@ -23,7 +23,6 @@ import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.common.ManufacturerType import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress -import info.nightscout.androidaps.plugins.pump.common.data.PumpDbEntry import info.nightscout.androidaps.plugins.pump.common.data.PumpStatus import info.nightscout.androidaps.plugins.pump.common.defs.PumpDriverState import info.nightscout.androidaps.plugins.pump.common.defs.PumpType @@ -56,14 +55,14 @@ abstract class PumpPluginAbstract protected constructor( var sp: SP, var context: Context, var fabricPrivacy: FabricPrivacy, - dateUtil: DateUtil, - aapsSchedulers: AapsSchedulers, - pumpSync: PumpSync + var dateUtil: DateUtil, + var aapsSchedulers: AapsSchedulers, + var pumpSync: PumpSync ) : PumpPluginBase(pluginDescription!!, injector!!, aapsLogger, resourceHelper, commandQueue), Pump, Constraints { private val disposable = CompositeDisposable() //protected override var injector: HasAndroidInjector? = null - protected var dateUtil: DateUtil + //protected var dateUtil: DateUtil // Pump capabilities final override var pumpDescription = PumpDescription() @@ -82,8 +81,8 @@ abstract class PumpPluginAbstract protected constructor( } - protected var aapsSchedulers: AapsSchedulers - protected var pumpSync: PumpSync + //protected var aapsSchedulers: AapsSchedulers + //protected var pumpSync: PumpSync protected var gson = GsonBuilder().excludeFieldsWithoutExposeAnnotation().create() abstract fun initPumpStatusData() @@ -344,12 +343,12 @@ abstract class PumpPluginAbstract protected constructor( // bolus needed, ask pump to deliver it deliverBolus(detailedBolusInfo) } else { - - // TODO fix // no bolus required, carb only treatment - activePlugin.activeTreatments.addToHistoryTreatment(detailedBolusInfo, true) + // TODO carb only bolus - DONE + pumpSync.syncCarbsWithTimestamp(System.currentTimeMillis(), detailedBolusInfo.carbs, null, model(), serialNumber()); + // activePlugin.activeTreatments.addToHistoryTreatment(detailedBolusInfo, true) val bolusingEvent = EventOverviewBolusProgress - bolusingEvent.t = EventOverviewBolusProgress.Treatment(0.0, 0, detailedBolusInfo.bolusType === DetailedBolusInfo.BolusType.SMB) + bolusingEvent.t = EventOverviewBolusProgress.Treatment(0.0, detailedBolusInfo.carbs.toInt(), detailedBolusInfo.bolusType === DetailedBolusInfo.BolusType.SMB) bolusingEvent.percent = 100 rxBus.send(bolusingEvent) aapsLogger.debug(LTag.PUMP, "deliverTreatment: Carb only treatment.") @@ -386,48 +385,13 @@ abstract class PumpPluginAbstract protected constructor( return PumpEnactResult(injector).success(false).enacted(false).comment(resourceId) } - // PumpSync - var driverHistory: MutableMap = HashMap() - abstract fun generateTempId(timeMillis: Long): Long - - protected fun addBolusWithTempId(detailedBolusInfo: DetailedBolusInfo, writeToInternalHistory: Boolean): Boolean { - val temporaryId = generateTempId(detailedBolusInfo.timestamp) - val response = pumpSync.addBolusWithTempId(detailedBolusInfo.timestamp, detailedBolusInfo.insulin, - temporaryId, detailedBolusInfo.bolusType, - pumpType, serialNumber()) - if (response && writeToInternalHistory) { - driverHistory[temporaryId] = PumpDbEntry(temporaryId, model(), serialNumber(), detailedBolusInfo) - sp.putString(MedtronicConst.Statistics.InternalTemporaryDatabase, gson.toJson(driverHistory)) - } - return response - } - - // TODO - protected fun addTemporaryBasalRateWithTempId(temporaryBasal: TemporaryBasal, b: Boolean) { - val temporaryId = generateTempId(temporaryBasal.date) - val response = pumpSync.addBolusWithTempId(temporaryBasal.timestamp, detailedBolusInfo.insulin, - generateTempId(detailedBolusInfo.timestamp), detailedBolusInfo.getBolusType(), - getPumpType(), serialNumber()); - - if (response && writeToInternalHistory) { - driverHistory.put(temporaryId, new PumpDbEntry(temporaryId, model(), serialNumber(), detailedBolusInfo)); - sp.putString(MedtronicConst.Statistics.InternalTemporaryDatabase, gson.toJson(driverHistory)); - } - - return response; - - } - - fun removeTemporaryId(temporaryId: Long) { - driverHistory.remove(temporaryId) - } init { pumpDescription.setPumpDescription(pumpType) this.pumpType = pumpType this.dateUtil = dateUtil this.aapsSchedulers = aapsSchedulers - this.pumpSync = pumpSync + //this.pumpSync = pumpSync } } \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpDbEntry.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpDbEntry.kt deleted file mode 100644 index 6dfe38133a..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpDbEntry.kt +++ /dev/null @@ -1,9 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.common.data - -import info.nightscout.androidaps.data.DetailedBolusInfo -import info.nightscout.androidaps.plugins.pump.common.defs.PumpType - -data class PumpDbEntry(var temporaryId: Long, - var pumpType: PumpType, - var serialNumber: String, - var detailedBolusInfo: DetailedBolusInfo) \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpStatus.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpStatus.kt index 061465c354..42bc97f6ee 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpStatus.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/data/PumpStatus.kt @@ -34,7 +34,7 @@ abstract class PumpStatus(var pumpType: PumpType) { var maxDailyTotalUnits: String? = null var units : String? = null // Constants.MGDL or Constants.MMOL var pumpStatusType = PumpStatusType.Running - var basalsByHour: Array? = null + var basalsByHour: DoubleArray? = null var tempBasalStart: Date? = null var tempBasalAmount: Double? = 0.0 var tempBasalLength: Int? = 0 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 6df557318f..f66c7b531f 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 @@ -37,7 +37,9 @@ import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.Riley import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.tasks.ResetRileyLinkConfigurationTask import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.tasks.ServiceTaskExecutor import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.tasks.WakeAndTuneTask +import info.nightscout.androidaps.plugins.pump.common.sync.PumpSyncEntriesCreator import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil +import info.nightscout.androidaps.plugins.pump.common.sync.PumpSyncStorage import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntry import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryResult import info.nightscout.androidaps.plugins.pump.medtronic.data.MedtronicHistoryData @@ -88,7 +90,8 @@ class MedtronicPumpPlugin @Inject constructor( private val serviceTaskExecutor: ServiceTaskExecutor, dateUtil: DateUtil, aapsSchedulers: AapsSchedulers, - pumpSync: PumpSync + pumpSync: PumpSync, + val pumpSyncStorage: PumpSyncStorage ) : PumpPluginAbstract(PluginDescription() // .mainType(PluginType.PUMP) // .fragmentClass(MedtronicFragment::class.java.name) // @@ -99,7 +102,7 @@ class MedtronicPumpPlugin @Inject constructor( .description(R.string.description_pump_medtronic), // PumpType.MEDTRONIC_522_722, // we default to most basic model, correct model from config is loaded later injector, resourceHelper, aapsLogger, commandQueue, rxBus, activePlugin, sp, context, fabricPrivacy, dateUtil, aapsSchedulers, pumpSync -), Pump, RileyLinkPumpDevice { +), Pump, RileyLinkPumpDevice, PumpSyncEntriesCreator { private var rileyLinkMedtronicService: RileyLinkMedtronicService? = null @@ -167,6 +170,8 @@ class MedtronicPumpPlugin @Inject constructor( sp.putLong(MedtronicConst.Statistics.FirstPumpStart, System.currentTimeMillis()) } migrateSettings() + + pumpSyncStorage.initStorage(); } override fun triggerPumpConfigurationChangedEvent() { @@ -482,7 +487,7 @@ class MedtronicPumpPlugin @Inject constructor( private fun isProfileSame(profile: Profile): Boolean { var invalid = false - val basalsByHour: Array? = medtronicPumpStatus.basalsByHour + val basalsByHour: DoubleArray? = medtronicPumpStatus.basalsByHour aapsLogger.debug(LTag.PUMP, "Current Basals (h): " + (basalsByHour?.let { getProfilesByHourToString(it) } ?: "null")) @@ -526,13 +531,12 @@ class MedtronicPumpPlugin @Inject constructor( rxBus.send(EventMedtronicPumpValuesChanged()) } - override fun generateTempId(timeMillis: Long): Long { - return 0 + override fun generateTempId(objectA: Any): Long { + val timestamp: Long = objectA as Long + return DateTimeUtil.toATechDate(timestamp) } - // @Override public String getSerial() { - // return null; - // } + private var bolusDeliveryType = BolusDeliveryType.Idle private enum class BolusDeliveryType { @@ -629,12 +633,15 @@ class MedtronicPumpPlugin @Inject constructor( detailedBolusInfo.timestamp = now detailedBolusInfo.deliverAtTheLatest = now // not sure about that one - // TODO fix - if (usePumpSync) { - addBolusWithTempId(detailedBolusInfo, true) - } else { - activePlugin.activeTreatments.addToHistoryTreatment(detailedBolusInfo, true) - } + pumpSyncStorage.addBolusWithTempId(detailedBolusInfo, true, this) + + + // // TODO fix + // if (usePumpSync) { + // pumpSyncStorage.addBolusWithTempId(detailedBolusInfo, true, this) + // } else { + // activePlugin.activeTreatments.addToHistoryTreatment(detailedBolusInfo, true) + // } // we subtract insulin, exact amount will be visible with next remainingInsulin update. medtronicPumpStatus.reservoirRemainingUnits = medtronicPumpStatus.reservoirRemainingUnits - detailedBolusInfo.insulin @@ -767,7 +774,7 @@ class MedtronicPumpPlugin @Inject constructor( // TODO fix if (usePumpSync) { - addTemporaryBasalRateWithTempId(tempStart, true) + pumpSyncStorage.addTemporaryBasalRateWithTempId(tempStart, true, this) } else { activePlugin.activeTreatments.addToHistoryTempBasal(tempStart) } @@ -834,7 +841,7 @@ class MedtronicPumpPlugin @Inject constructor( val debugHistory = false var targetDate: LocalDateTime? = null - if (lastPumpHistoryEntry == null) { + if (lastPumpHistoryEntry == null) { // first read if (debugHistory) aapsLogger.debug(LTag.PUMP, logPrefix + "readPumpHistoryLogic(): lastPumpHistoryEntry: null") val lastPumpHistoryEntryTime = lastPumpEntryTime var timeMinus36h = LocalDateTime() @@ -858,12 +865,9 @@ class MedtronicPumpPlugin @Inject constructor( targetDate = if (timeMinus36h.isAfter(lastHistoryRecordTime)) timeMinus36h else lastHistoryRecordTime if (debugHistory) aapsLogger.debug(LTag.PUMP, logPrefix + "readPumpHistoryLogic(): targetDate: " + targetDate) } - } else { + } else { // all other reads if (debugHistory) aapsLogger.debug(LTag.PUMP, logPrefix + "readPumpHistoryLogic(): lastPumpHistoryEntry: not null - " + medtronicUtil.gsonInstance.toJson(lastPumpHistoryEntry)) medtronicHistoryData.setIsInInit(false) - // medtronicHistoryData.setLastHistoryRecordTime(lastPumpHistoryEntry.atechDateTime); - - // targetDate = lastPumpHistoryEntry.atechDateTime; } //aapsLogger.debug(LTag.PUMP, "HST: Target Date: " + targetDate); @@ -883,22 +887,22 @@ class MedtronicPumpPlugin @Inject constructor( medtronicHistoryData.filterNewEntries() // determine if first run, if yes detrmine how much of update do we need - // first run: - // get last hiostory entry, if not there download 1.5 days of data - // - there: check if last entry is older than 1.5 days - // - yes: download 1.5 days - // - no: download with last entry - // - not there: download 1.5 days + // - first run: + // - get last history entry + // - if not there download 1.5 days of data + // - there: check if last entry is older than 1.5 days + // - yes: download 1.5 days + // - no: download with last entry TODO 5min + // - not there: download 1.5 days // - // upload all new entries to NightScout (TBR, Bolus) - // determine pump status + // upload all new entries to NightScout (TBR, Bolus) + // determine pump status + // save last entry // - // save last entry - // - // not first run: - // update to last entry - // - save - // - determine pump status + // - not first run: + // - update to last entry TODO 5min + // - save + // - determine pump status } private val lastPumpEntryTime: Long @@ -1015,7 +1019,7 @@ class MedtronicPumpPlugin @Inject constructor( // TODO fix if (usePumpSync) { - addTemporaryBasalRateWithTempId(tempBasal, true) + pumpSyncStorage.addTemporaryBasalRateWithTempId(tempBasal, true, this) } else { activePlugin.activeTreatments.addToHistoryTempBasal(tempBasal) } 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 ee509ffd7d..acdbcc2e10 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 @@ -551,10 +551,13 @@ class MedtronicCommunicationManager // This empty constructor must be kept, oth errorResponse = check } - var basalProfile: BasalProfile? = null - checkResponseRawContent(data, commandType) { - basalProfile = medtronicConverter.decodeBasalProfile(medtronicPumpPlugin.pumpDescription.pumpType, data) - } + + aapsLogger.debug(LTag.PUMPCOMM,"End Response: {}", ByteUtil.getHex(data)) + + var basalProfile: BasalProfile? = medtronicConverter.decodeBasalProfile(medtronicPumpPlugin.pumpDescription.pumpType, data) + // 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)) diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntryType.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntryType.kt index 796ec828db..3151131838 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntryType.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntryType.kt @@ -47,7 +47,7 @@ enum class PumpHistoryEntryType // implements CodeEnum BolusWizardEnabled(0x2d, "Bolus Wizard Enabled", PumpHistoryEntryGroup.Configuration), // V3 ? /* TODO */ EventUnknown_MM512_0x2e(0x2e, "Unknown Event 0x2e", PumpHistoryEntryGroup.Unknown, 2, 5, 100), // BolusWizard512(0x2f, "Bolus Wizard (512)", PumpHistoryEntryGroup.Bolus, 2, 5, 12), // - UnabsorbedInsulin512(0x30, "Unabsorbed Insulin (512)", PumpHistoryEntryGroup.Statistic, 5, 0, 0), // FIXME + UnabsorbedInsulin512(0x30, "Unabsorbed Insulin (512)", PumpHistoryEntryGroup.Statistic, 5, 0, 0), ChangeBGReminderOffset(0x31, "Change BG Reminder Offset", PumpHistoryEntryGroup.Configuration), // ChangeAlarmClockTime(0x32, "Change Alarm Clock Time", PumpHistoryEntryGroup.Configuration), // TempBasalRate(0x33, "TBR Rate", PumpHistoryEntryGroup.Basal, 2, 5, 1), // diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryResult.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryResult.kt index 09d694f061..5fd484628d 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryResult.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryResult.kt @@ -51,8 +51,10 @@ class PumpHistoryResult(private val aapsLogger: AAPSLogger, searchEntry: PumpHis } //aapsLogger.debug(LTag.PUMPCOMM,"PE. Entry {} added.", unprocessedEntry); + validEntries.add(unprocessedEntry) } + // TODO 5minutes back } SearchType.Date -> { 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 index 6ffbb556ae..3264694d06 100644 --- 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 @@ -11,6 +11,8 @@ 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.sync.PumpDbEntry +import info.nightscout.androidaps.plugins.pump.common.sync.PumpSyncStorage 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 @@ -27,7 +29,6 @@ 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 @@ -51,7 +52,8 @@ class MedtronicHistoryData @Inject constructor( val medtronicPumpHistoryDecoder: MedtronicPumpHistoryDecoder, val medtronicPumpStatus: MedtronicPumpStatus, val databaseHelper: DatabaseHelperInterface, - val pumpSync: PumpSync + val pumpSync: PumpSync, + val pumpSyncStorage: PumpSyncStorage ) { val allHistory: MutableList = mutableListOf() @@ -304,7 +306,7 @@ class MedtronicHistoryData @Inject constructor( // 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)) { + if (tdds.isNotEmpty()) { try { processTDDs(tdds) } catch (ex: Exception) { @@ -317,7 +319,7 @@ class MedtronicHistoryData @Inject constructor( // 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) { + if (treatments.isNotEmpty()) { try { processBolusEntries(treatments) } catch (ex: Exception) { @@ -329,9 +331,9 @@ class MedtronicHistoryData @Inject constructor( // 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) { + if (tbrs.isNotEmpty()) { try { - processTBREntries(tbrs) + processTBREntries(tbrs) // TODO not implemented yet } catch (ex: Exception) { aapsLogger.error(LTag.PUMP, "ProcessHistoryData: Error processing TBR entries: " + ex.message, ex) throw ex @@ -348,9 +350,9 @@ class MedtronicHistoryData @Inject constructor( } aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "ProcessHistoryData: 'Delivery Suspend' Processed [count=%d, items=%s]", suspends.size, gson.toJson(suspends))) - if (isCollectionNotEmpty(suspends)) { + if (suspends.isNotEmpty()) { try { - processSuspends(suspends) + processSuspends(suspends) // TODO not tested yet } catch (ex: Exception) { aapsLogger.error(LTag.PUMP, "ProcessHistoryData: Error processing Suspends entries: " + ex.message, ex) throw ex @@ -410,13 +412,11 @@ class MedtronicHistoryData @Inject constructor( 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) + + aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, logPrefix + "TDDs found: %d.\n%s", + tdds.size, gson.toJson(tdds))) + for (tdd in tdds) { - //val tddDbEntry = findTDD(tdd.atechDateTime!!, tddsDb) val totalsDTO = tdd.decodedData!!["Object"] as DailyTotalsDTO pumpSync.createOrUpdateTotalDailyDose( @@ -428,33 +428,148 @@ class MedtronicHistoryData @Inject constructor( medtronicPumpStatus.pumpType, medtronicPumpStatus.serialNumber!! ) - - // timestamp: Long, bolusAmount: Double, basalAmount: Double, totalAmount: Double, - // pumpId: Long?, pumpType: PumpType, pumpSerial: String - - //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 fun processTDDs_Old(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 boluses = pumpSyncStorage.getBoluses() + + for (bolus in entryList) { + + val bolusDTO = bolus.decodedData!!["Object"]!! as BolusDTO + var type: DetailedBolusInfo.BolusType = DetailedBolusInfo.BolusType.NORMAL + var multiwave = false + + if (bolusDTO.bolusType==PumpBolusType.Extended) { + addExtendedBolus(bolus, bolusDTO, multiwave) + continue; + } else if (bolusDTO.bolusType==PumpBolusType.Multiwave) { + multiwave = true + aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "Multiwave bolus from pump, extended bolus and normal bolus will be added.")) + addExtendedBolus(bolus, bolusDTO, multiwave); + } + + val deliveredAmount: Double = if (multiwave) bolusDTO.immediateAmount!! else bolusDTO.deliveredAmount!! + + var temporaryId: Long? = null + + if (!multiwave) { + val entryWithTempId = findDbEntry(bolus, boluses) + + if (entryWithTempId != null) { + temporaryId = entryWithTempId.temporaryId + pumpSyncStorage.removeBolusWithTemporaryId(temporaryId) + boluses.remove(entryWithTempId) + type = entryWithTempId.bolusData!!.bolusType + } + } + + if (temporaryId!=null) { + val result = pumpSync.syncBolusWithTempId( + tryToGetByLocalTime(bolus.atechDateTime!!), + deliveredAmount, + temporaryId, + type, + bolus.pumpId, + medtronicPumpStatus.pumpType, + medtronicPumpStatus.serialNumber!!) + + aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "syncBolusWithTempId [date=%d, temporaryId=%d, pumpId=%d, insulin=%.2f, pumpSerial=%s] - Result: %b", + bolus.atechDateTime!!, temporaryId, bolus.pumpId, deliveredAmount, + medtronicPumpStatus.serialNumber!!, result)) + } else { + val result = pumpSync.syncBolusWithPumpId( + tryToGetByLocalTime(bolus.atechDateTime!!), + deliveredAmount, + type, + bolus.pumpId!!, + medtronicPumpStatus.pumpType, + medtronicPumpStatus.serialNumber!!) + + aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "syncBolusWithPumpId [date=%d, pumpId=%d, insulin=%.2f, pumpSerial=%s] - Result: %b", + bolus.atechDateTime!!, bolus.pumpId, deliveredAmount, + medtronicPumpStatus.serialNumber!!, result)) + } + + addCarbs(bolus) + } + } + + + private fun addExtendedBolus(bolus: PumpHistoryEntry, bolusDTO: BolusDTO, isMultiwave: Boolean) { + + val durationMs : Long = bolusDTO.duration!! * 60L * 1000L + + val result = pumpSync.syncExtendedBolusWithPumpId( + tryToGetByLocalTime(bolus.atechDateTime!!), + bolusDTO.deliveredAmount!!, + durationMs, + false, + bolus.pumpId!!, + medtronicPumpStatus.pumpType, + medtronicPumpStatus.serialNumber!!) + + aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "syncExtendedBolusWithPumpId [date=%d, amount=%.2f, duration=%d, pumpId=%d, pumpSerial=%s, multiwave=%b] - Result: %b", + bolus.atechDateTime!!, bolusDTO.deliveredAmount!!, bolusDTO.duration, bolus.pumpId, + medtronicPumpStatus.serialNumber!!, isMultiwave, result)) + } + + + private fun addCarbs(bolus: PumpHistoryEntry) { + if (bolus.containsDecodedData("Estimate")) { + val bolusWizard = bolus.decodedData!!["Estimate"] as BolusWizardDTO + + val result = pumpSync.syncCarbsWithTimestamp( + tryToGetByLocalTime(bolus.atechDateTime!!), + bolusWizard.carbs.toDouble(), + bolus.pumpId!!, + medtronicPumpStatus.pumpType, + medtronicPumpStatus.serialNumber!!) + + aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "syncCarbsWithTimestamp [date=%d, pumpId=%d, carbs=%.2f, pumpSerial=%s] - Result: %b", + bolus.atechDateTime!!, bolusWizard.carbs.toDouble(), bolus.pumpId, + medtronicPumpStatus.serialNumber!!, result)) + } + } + + + private fun processBolusEntries_Old(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), @@ -475,7 +590,7 @@ class MedtronicHistoryData @Inject constructor( } } else { for (treatment in entryList) { - val treatmentDb = findDbEntry(treatment, entriesFromHistory) + val treatmentDb = findDbEntry_Old(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?) @@ -558,7 +673,7 @@ class MedtronicHistoryData @Inject constructor( tbr2!!.durationMinutes = tempBasalProcessDTO.duration val tempBasal = findTempBasalWithPumpId(tempBasalProcessDTO.itemOne!!.pumpId!!, entriesFromHistory) if (tempBasal == null) { - val treatmentDb = findDbEntry(treatment, entriesFromHistory) + val treatmentDb = findDbEntry_Old(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 { @@ -593,7 +708,7 @@ class MedtronicHistoryData @Inject constructor( * @param entriesFromHistory entries from history * @return DbObject from AAPS (if found) */ - private fun findDbEntry(treatment: PumpHistoryEntry?, entriesFromHistory: List): DbObjectBase? { + private fun findDbEntry_Old(treatment: PumpHistoryEntry?, entriesFromHistory: List): DbObjectBase? { val proposedTime = DateTimeUtil.toMillisFromATD(treatment!!.atechDateTime!!) //proposedTime += (this.pumpTime.timeDifference * 1000); @@ -644,11 +759,69 @@ class MedtronicHistoryData @Inject constructor( return null } + /** + * Looks at all boluses that have temporaryId and find one that is correct for us (if such entry exists) + */ + private fun findDbEntry(treatment: PumpHistoryEntry?, temporaryEntries: MutableList): PumpDbEntry? { + + if (temporaryEntries.isEmpty()) { + return null + } + + var proposedTime = DateTimeUtil.toMillisFromATD(treatment!!.atechDateTime!!) + proposedTime += (this.pumpTime!!.timeDifference * 1000) + + val proposedTimeDiff : LongArray = longArrayOf(proposedTime-(2*60*1000), proposedTime+(2L*60L*1000L)) + val tempEntriesList: MutableList = mutableListOf() + + for (temporaryEntry in temporaryEntries) { + if (temporaryEntry.date > proposedTimeDiff[0] && temporaryEntry.date < proposedTimeDiff[1]) { + tempEntriesList.add(temporaryEntry) + } + } + + if (tempEntriesList.isEmpty()) { + return null + } else if (tempEntriesList.size==1) { + return tempEntriesList[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 = mutableListOf() + for (treatment1 in tempEntriesList) { + if (treatment1.date > proposedTime - diff && treatment1.date < 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, outList[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 - activeTreatments.getTreatmentsFromHistoryAfterTimestamp outList.addAll(activePlugin.activeTreatments.getTreatmentsFromHistoryAfterTimestamp(startTimestamp)) } else { // TODO pumpSync - databaseHelper.getTemporaryBasalsDataFromTime(startTimestamp, true) @@ -701,7 +874,6 @@ class MedtronicHistoryData @Inject constructor( detailedBolusInfo.insulin = bolusDTO.deliveredAmount!! addCarbsFromEstimate(detailedBolusInfo, bolus) if (doubleBolusDebug) aapsLogger.debug(LTag.PUMP, "DoubleBolusDebug: addBolus(tretament==null): DetailedBolusInfo=$detailedBolusInfo") - // TODO pumpSync - activeTreatments.addToHistoryTreatment 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, @@ -718,7 +890,6 @@ class MedtronicHistoryData @Inject constructor( extendedBolus.durationInMinutes = bolusDTO.duration!! bolus.linkedObject = extendedBolus if (doubleBolusDebug) aapsLogger.debug(LTag.PUMP, "DoubleBolusDebug: addBolus(tretament==null): ExtendedBolus=$extendedBolus") - // TODO pumpSync - activeTreatments.addToHistoryExtendedBolus 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)) @@ -729,7 +900,6 @@ class MedtronicHistoryData @Inject constructor( treatment.source = Source.PUMP treatment.pumpId = bolus.pumpId!! treatment.insulin = bolusDTO!!.deliveredAmount!! - // TODO pumpSync - activeTreatments.createOrUpdateMedtronic(treatment) 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, @@ -742,7 +912,6 @@ class MedtronicHistoryData @Inject constructor( 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)) - // TODO pumpSync - Carbs detailedBolusInfo.carbs = bolusWizard!!.carbs.toDouble() } } @@ -772,7 +941,28 @@ class MedtronicHistoryData @Inject constructor( temporaryBasalDb.durationInMinutes)) } + private fun processSuspends(tempBasalProcessList: List) { + for (tempBasalProcess in tempBasalProcessList) { + + val result = pumpSync.syncTemporaryBasalWithPumpId( + tryToGetByLocalTime(tempBasalProcess.itemOne!!.atechDateTime!!), + 0.0, + tempBasalProcess.duration * 60 * 1000L, + true, + PumpSync.TemporaryBasalType.PUMP_SUSPEND, + tempBasalProcess.itemOne!!.pumpId!!, + medtronicPumpStatus.pumpType, + medtronicPumpStatus.serialNumber!!) + + aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "processSuspends::syncTemporaryBasalWithPumpId [date=%d, rate=%.2f, duration=%d, pumpId=%d, pumpSerial=%s] - Result: %b", + tempBasalProcess.itemOne!!.atechDateTime!!, 0.0, tempBasalProcess.duration, tempBasalProcess.itemOne!!.pumpId!!, + medtronicPumpStatus.serialNumber!!, result)) + } + } + + + private fun processSuspends_Old(tempBasalProcessList: List) { for (tempBasalProcess in tempBasalProcessList) { // TODO pumpSync - databaseHelper.findTempBasalByPumpId var tempBasal = databaseHelper.findTempBasalByPumpId(tempBasalProcess.itemOne!!.pumpId!!) 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 0d4d896fab..2dc14b7c06 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 @@ -229,7 +229,7 @@ class BasalProfile { // return this.mRawData; } - fun getProfilesByHour(pumpType: PumpType): Array { + fun getProfilesByHour(pumpType: PumpType): DoubleArray { var entriesCopy: List? = null try { entriesCopy = getEntries() @@ -241,7 +241,7 @@ class BasalProfile { //FabricUtil.createEvent("MedtronicBasalProfileGetByHourError", null); } - val basalByHour = arrayOf() + val basalByHour = DoubleArray(24) if (entriesCopy == null || entriesCopy.size == 0) { for (i in 0..23) { @@ -249,6 +249,7 @@ class BasalProfile { } return basalByHour } + 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 @@ -301,7 +302,7 @@ class BasalProfile { } @JvmStatic - fun getProfilesByHourToString(data: Array): String { + fun getProfilesByHourToString(data: DoubleArray): String { val stringBuilder = StringBuilder() for (value in data) { stringBuilder.append(String.format("%.3f", value)) 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 f419c7f56c..60dd954b20 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 @@ -58,7 +58,8 @@ enum class MedtronicCommandType 7, R.string.medtronic_cmd_desc_get_time), // 0x70 GetBatteryStatus(0x72, "Get Battery Status", MedtronicDeviceType.All, MinimedCommandParameterType.NoParameters, 0, R.string.medtronic_cmd_desc_get_battery_status), // - GetRemainingInsulin(0x73, "Read Remaining Insulin", MedtronicDeviceType.All, MinimedCommandParameterType.NoParameters, 2), // 115 + GetRemainingInsulin(0x73, "Read Remaining Insulin", MedtronicDeviceType.All, MinimedCommandParameterType.NoParameters, + 2, R.string.medtronic_cmd_desc_get_remaining_insulin), // 115 SetBolus(0x42, "Set Bolus", MedtronicDeviceType.All, MinimedCommandParameterType.NoParameters, // 0, R.string.medtronic_cmd_desc_set_bolus), // 66 diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/driver/MedtronicPumpStatus.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/driver/MedtronicPumpStatus.kt index e0b65dcf54..c54bbcf90d 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/driver/MedtronicPumpStatus.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/driver/MedtronicPumpStatus.kt @@ -41,11 +41,10 @@ class MedtronicPumpStatus @Inject constructor(private val resourceHelper: Resour rileyLinkUtil.rileyLinkHistory.add(RLHistoryItem(pumpDeviceState, RileyLinkTargetDevice.MedtronicPump)) rxBus.send(EventRileyLinkDeviceStatusChange(pumpDeviceState)) } - var medtronicDeviceType: MedtronicDeviceType? = null - // fixme - var medtronicPumpMap: MutableMap = HashMap() - var medtronicDeviceTypeMap: MutableMap = HashMap() + var medtronicDeviceType: MedtronicDeviceType? = null + var medtronicPumpMap: MutableMap = mutableMapOf() + var medtronicDeviceTypeMap: MutableMap = mutableMapOf() var basalProfileStatus = BasalProfileStatus.NotInitialized var batteryType = BatteryType.None @@ -98,16 +97,16 @@ class MedtronicPumpStatus @Inject constructor(private val resourceHelper: Resour } // Battery type - private var mapByDescription: MutableMap = HashMap() + private var batteryTypeByDescMap: MutableMap = HashMap() fun getBatteryTypeByDescription(batteryTypeStr: String?): BatteryType? { - if (mapByDescription.size == 0) { + if (batteryTypeByDescMap.size == 0) { for (value in BatteryType.values()) { - mapByDescription[resourceHelper.gs(value.description)] = value + batteryTypeByDescMap[resourceHelper.gs(value.description)] = value } } - return if (mapByDescription.containsKey(batteryTypeStr)) { - mapByDescription[batteryTypeStr] + return if (batteryTypeByDescMap.containsKey(batteryTypeStr)) { + batteryTypeByDescMap[batteryTypeStr] } else BatteryType.None } diff --git a/medtronic/src/main/res/values/strings.xml b/medtronic/src/main/res/values/strings.xml index 801413be38..f2831199cb 100644 --- a/medtronic/src/main/res/values/strings.xml +++ b/medtronic/src/main/res/values/strings.xml @@ -105,6 +105,7 @@ Get Temporary Basal Set Temporary Basal Set Bolus + Get Remaining Insulin Pump unreachable Warning From a3f0bf41cdfdadc0c9d22f6d61bb6b52146efe5b Mon Sep 17 00:00:00 2001 From: Andy Rozman Date: Fri, 30 Apr 2021 20:05:03 +0100 Subject: [PATCH 020/145] - removed unused (old) methods from MedtronicHistoryData - PumpSyncStorage added method addCarbs, that is now used in PUmpPluginAbstract and in MetronicPumpPlugin and MedtronicHistoryData - extended PumpDbEntry with other data classes: for Bolus, TBR (incomplete) and Carbs --- .../plugins/pump/common/sync/PumpDbEntry.kt | 11 + .../pump/common/sync/PumpSyncStorage.kt | 34 +- .../plugins/pump/common/PumpPluginAbstract.kt | 19 +- .../pump/medtronic/MedtronicPumpPlugin.kt | 5 +- .../medtronic/data/MedtronicHistoryData.kt | 310 ++++-------------- 5 files changed, 117 insertions(+), 262 deletions(-) diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpDbEntry.kt b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpDbEntry.kt index 08a782c918..e7ebc46ba4 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpDbEntry.kt +++ b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpDbEntry.kt @@ -28,5 +28,16 @@ data class PumpDbEntryBolus(var insulin: Double, var carbs: Double, var bolusType: DetailedBolusInfo.BolusType) +data class PumpDbEntryCarbs(var date: Long, + var carbs: Double, + var pumpType: PumpType, + var serialNumber: String, + var pumpId: Long? = null) { + constructor(detailedBolusInfo: DetailedBolusInfo, + creator: PumpSyncEntriesCreator) : this(detailedBolusInfo.timestamp, + detailedBolusInfo.carbs, + creator.model(), + creator.serialNumber()) +} data class PumpDbEntryTBR(var temporaryId: Long) \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpSyncStorage.kt b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpSyncStorage.kt index 3bb07b770c..31e1a733f3 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpSyncStorage.kt +++ b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpSyncStorage.kt @@ -7,8 +7,10 @@ import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.db.TemporaryBasal import info.nightscout.androidaps.interfaces.PumpSync import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.utils.sharedPreferences.SP import java.lang.reflect.Type +import java.util.* import javax.inject.Inject import javax.inject.Singleton @@ -86,25 +88,45 @@ class PumpSyncStorage @Inject constructor( } - //abstract fun generateTempId(timeMillis: Long): Long - fun addBolusWithTempId(detailedBolusInfo: DetailedBolusInfo, writeToInternalHistory: Boolean, creator: PumpSyncEntriesCreator): Boolean { val temporaryId = creator.generateTempId(detailedBolusInfo.timestamp) - val response = pumpSync.addBolusWithTempId( + val result = pumpSync.addBolusWithTempId( detailedBolusInfo.timestamp, detailedBolusInfo.insulin, temporaryId, detailedBolusInfo.bolusType, creator.model(), creator.serialNumber()) - if (response && writeToInternalHistory) { + + aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "addBolusWithTempId [date=%d, temporaryId=%d, insulin=%.2f, type=%s, pumpSerial=%s] - Result: %b", + detailedBolusInfo.timestamp, temporaryId, detailedBolusInfo.insulin, detailedBolusInfo.bolusType, + creator.serialNumber(), result)) + + if (detailedBolusInfo.carbs>0.0) { + addCarbs(PumpDbEntryCarbs(detailedBolusInfo, creator)) + } + + if (result && writeToInternalHistory) { var innerList: MutableList = pumpSyncStorage[BOLUS]!! innerList.add(PumpDbEntry(temporaryId, detailedBolusInfo.timestamp, creator.model(), creator.serialNumber(), detailedBolusInfo)) pumpSyncStorage[BOLUS] = innerList saveStorage() } - return response + return result + } + + + fun addCarbs(carbsDto: PumpDbEntryCarbs) { + val result = pumpSync.syncCarbsWithTimestamp( + carbsDto.date, + carbsDto.carbs, + null, + carbsDto.pumpType, + carbsDto.serialNumber) + + aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "syncCarbsWithTimestamp [date=%d, carbs=%.2f, pumpSerial=%s] - Result: %b", + carbsDto.date, carbsDto.carbs, carbsDto.serialNumber, result)) } // TODO @@ -123,6 +145,8 @@ class PumpSyncStorage @Inject constructor( return false } + + fun removeBolusWithTemporaryId(temporaryId: Long) { val bolusList = removeTemporaryId(temporaryId, pumpSyncStorage[BOLUS]!!) pumpSyncStorage[BOLUS] = bolusList diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.kt index d88a3d362d..5a16531766 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.kt @@ -26,6 +26,9 @@ import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewB import info.nightscout.androidaps.plugins.pump.common.data.PumpStatus import info.nightscout.androidaps.plugins.pump.common.defs.PumpDriverState import info.nightscout.androidaps.plugins.pump.common.defs.PumpType +import info.nightscout.androidaps.plugins.pump.common.sync.PumpDbEntryCarbs +import info.nightscout.androidaps.plugins.pump.common.sync.PumpSyncEntriesCreator +import info.nightscout.androidaps.plugins.pump.common.sync.PumpSyncStorage import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicConst import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DecimalFormatter.to0Decimal @@ -57,12 +60,11 @@ abstract class PumpPluginAbstract protected constructor( var fabricPrivacy: FabricPrivacy, var dateUtil: DateUtil, var aapsSchedulers: AapsSchedulers, - var pumpSync: PumpSync -) : PumpPluginBase(pluginDescription!!, injector!!, aapsLogger, resourceHelper, commandQueue), Pump, Constraints { + var pumpSync: PumpSync, + var pumpSyncStorage: PumpSyncStorage +) : PumpPluginBase(pluginDescription!!, injector!!, aapsLogger, resourceHelper, commandQueue), Pump, Constraints, PumpSyncEntriesCreator { private val disposable = CompositeDisposable() - //protected override var injector: HasAndroidInjector? = null - //protected var dateUtil: DateUtil // Pump capabilities final override var pumpDescription = PumpDescription() @@ -81,8 +83,6 @@ abstract class PumpPluginAbstract protected constructor( } - //protected var aapsSchedulers: AapsSchedulers - //protected var pumpSync: PumpSync protected var gson = GsonBuilder().excludeFieldsWithoutExposeAnnotation().create() abstract fun initPumpStatusData() @@ -343,10 +343,11 @@ abstract class PumpPluginAbstract protected constructor( // bolus needed, ask pump to deliver it deliverBolus(detailedBolusInfo) } else { + detailedBolusInfo.timestamp = System.currentTimeMillis() + // no bolus required, carb only treatment - // TODO carb only bolus - DONE - pumpSync.syncCarbsWithTimestamp(System.currentTimeMillis(), detailedBolusInfo.carbs, null, model(), serialNumber()); - // activePlugin.activeTreatments.addToHistoryTreatment(detailedBolusInfo, true) + pumpSyncStorage.addCarbs(PumpDbEntryCarbs(detailedBolusInfo, this)) + val bolusingEvent = EventOverviewBolusProgress bolusingEvent.t = EventOverviewBolusProgress.Treatment(0.0, detailedBolusInfo.carbs.toInt(), detailedBolusInfo.bolusType === DetailedBolusInfo.BolusType.SMB) bolusingEvent.percent = 100 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 f66c7b531f..4a91046067 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 @@ -91,7 +91,7 @@ class MedtronicPumpPlugin @Inject constructor( dateUtil: DateUtil, aapsSchedulers: AapsSchedulers, pumpSync: PumpSync, - val pumpSyncStorage: PumpSyncStorage + pumpSyncStorage: PumpSyncStorage ) : PumpPluginAbstract(PluginDescription() // .mainType(PluginType.PUMP) // .fragmentClass(MedtronicFragment::class.java.name) // @@ -101,7 +101,7 @@ class MedtronicPumpPlugin @Inject constructor( .preferencesId(R.xml.pref_medtronic) .description(R.string.description_pump_medtronic), // PumpType.MEDTRONIC_522_722, // we default to most basic model, correct model from config is loaded later - injector, resourceHelper, aapsLogger, commandQueue, rxBus, activePlugin, sp, context, fabricPrivacy, dateUtil, aapsSchedulers, pumpSync + injector, resourceHelper, aapsLogger, commandQueue, rxBus, activePlugin, sp, context, fabricPrivacy, dateUtil, aapsSchedulers, pumpSync, pumpSyncStorage ), Pump, RileyLinkPumpDevice, PumpSyncEntriesCreator { private var rileyLinkMedtronicService: RileyLinkMedtronicService? = null @@ -635,7 +635,6 @@ class MedtronicPumpPlugin @Inject constructor( pumpSyncStorage.addBolusWithTempId(detailedBolusInfo, true, this) - // // TODO fix // if (usePumpSync) { // pumpSyncStorage.addBolusWithTempId(detailedBolusInfo, true, this) 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 index 3264694d06..093947ec78 100644 --- 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 @@ -12,6 +12,7 @@ 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.sync.PumpDbEntry +import info.nightscout.androidaps.plugins.pump.common.sync.PumpDbEntryCarbs import info.nightscout.androidaps.plugins.pump.common.sync.PumpSyncStorage import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil import info.nightscout.androidaps.plugins.pump.common.utils.StringUtil @@ -215,9 +216,9 @@ class MedtronicHistoryData @Inject constructor( private fun isCollectionNotEmpty(col: List<*>?): Boolean { return col != null && !col.isEmpty() - }//////// + } + - // val isPumpSuspended: Boolean get() { val items = getDataForPumpSuspends() @@ -304,7 +305,7 @@ class MedtronicHistoryData @Inject constructor( } // TDD - val tdds: MutableList = getFilteredItems(setOf(PumpHistoryEntryType.EndResultTotals, tDDType)) + val tdds: MutableList = getFilteredItems(setOf(PumpHistoryEntryType.EndResultTotals, getTDDType())) aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "ProcessHistoryData: TDD [count=%d, items=%s]", tdds.size, gson.toJson(tdds))) if (tdds.isNotEmpty()) { try { @@ -432,33 +433,6 @@ class MedtronicHistoryData @Inject constructor( } - // private fun processTDDs_Old(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"), @@ -533,7 +507,6 @@ class MedtronicHistoryData @Inject constructor( private fun addExtendedBolus(bolus: PumpHistoryEntry, bolusDTO: BolusDTO, isMultiwave: Boolean) { - val durationMs : Long = bolusDTO.duration!! * 60L * 1000L val result = pumpSync.syncExtendedBolusWithPumpId( @@ -555,61 +528,17 @@ class MedtronicHistoryData @Inject constructor( if (bolus.containsDecodedData("Estimate")) { val bolusWizard = bolus.decodedData!!["Estimate"] as BolusWizardDTO - val result = pumpSync.syncCarbsWithTimestamp( + pumpSyncStorage.addCarbs(PumpDbEntryCarbs( tryToGetByLocalTime(bolus.atechDateTime!!), bolusWizard.carbs.toDouble(), - bolus.pumpId!!, medtronicPumpStatus.pumpType, - medtronicPumpStatus.serialNumber!!) - - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "syncCarbsWithTimestamp [date=%d, pumpId=%d, carbs=%.2f, pumpSerial=%s] - Result: %b", - bolus.atechDateTime!!, bolusWizard.carbs.toDouble(), bolus.pumpId, - medtronicPumpStatus.serialNumber!!, result)) + medtronicPumpStatus.serialNumber!!, + bolus.pumpId!! + )) } } - private fun processBolusEntries_Old(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_Old(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? @@ -831,82 +760,6 @@ class MedtronicHistoryData @Inject constructor( 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") - 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") - 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!! - 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")) { @@ -962,53 +815,41 @@ class MedtronicHistoryData @Inject constructor( } - private fun processSuspends_Old(tempBasalProcessList: List) { - for (tempBasalProcess in tempBasalProcessList) { - // TODO pumpSync - databaseHelper.findTempBasalByPumpId - 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 - // TODO pumpSync -databaseHelper.createOrUpdate(tbr-suspebd( - databaseHelper.createOrUpdate(tempBasal) - } - } - } - // suspend/resume // no_delivery/prime & rewind/prime private fun getSuspendRecords(): MutableList { - val outList: MutableList = ArrayList() + val outList: MutableList = mutableListOf() + + // suspend/resume + outList.addAll(getSuspendResumeRecordsList()) + // no_delivery/prime & rewind/prime + outList.addAll(getNoDeliveryRewindPrimeRecordsList()) + return outList + } - // 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 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) @@ -1017,39 +858,29 @@ class MedtronicHistoryData @Inject constructor( } 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 - } + // remove last and have paired items + filteredItems.removeAt(0) + filtered2Items.addAll(filteredItems) } } - return outList - }////////// + 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)) @@ -1134,15 +965,6 @@ class MedtronicHistoryData @Inject constructor( 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) } @@ -1169,20 +991,22 @@ class MedtronicHistoryData @Inject constructor( } } - private val tDDType: PumpHistoryEntryType - get() = if (medtronicUtil.medtronicPumpModel == null) { + private fun getTDDType(): PumpHistoryEntryType { + return 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_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 -> { + MedtronicDeviceType.Medtronic_754_Veo -> PumpHistoryEntryType.DailyTotals523 + + else -> { PumpHistoryEntryType.EndResultTotals } } + } fun hasBasalProfileChanged(): Boolean { val filteredItems: List = getFilteredItems(PumpHistoryEntryType.ChangeBasalProfile_NewProfile) @@ -1217,10 +1041,6 @@ class MedtronicHistoryData @Inject constructor( PumpHistoryEntryType.ChangeTime)) } - // fun setLastHistoryRecordTime(lastHistoryRecordTime: Long?) { - // // this.previousLastHistoryRecordTime = this.lastHistoryRecordTime; - // } - fun setIsInInit(init: Boolean) { isInit = init } From dc2d64ceb7c7a086e5e82c3c96301ae2a0d141c6 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 1 May 2021 00:22:45 +0200 Subject: [PATCH 021/145] Fix: turn APSResult.bolusRequested into a function. Previously this var was set while parsing determine-basal output, setting it to true if determine-basal provided a value which was assigned to var smb. However, the variable smb is changed when constraints are applied, making the val bolusRequested invalid afterwards. Hence, dynamically evaluate the smb var by turning bolusRequested into a function. --- .../nightscout/androidaps/plugins/aps/loop/LoopPlugin.kt | 4 ++-- .../plugins/aps/openAPSAMA/DetermineBasalResultAMA.kt | 1 - .../plugins/aps/openAPSSMB/DetermineBasalResultSMB.kt | 1 - .../nightscout/androidaps/plugins/aps/loop/APSResult.kt | 8 ++++---- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.kt index 6c7e8a3ac5..4795283ec1 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.kt @@ -403,7 +403,7 @@ open class LoopPlugin @Inject constructor( val waiting = PumpEnactResult(injector) waiting.queued = true if (resultAfterConstraints.tempBasalRequested) lastRun.tbrSetByPump = waiting - if (resultAfterConstraints.bolusRequested) lastRun.smbSetByPump = waiting + if (resultAfterConstraints.bolusRequested()) lastRun.smbSetByPump = waiting rxBus.send(EventLoopUpdateGui()) fabricPrivacy.logCustom("APSRequest") applyTBRRequest(resultAfterConstraints, profile, object : Callback() { @@ -600,7 +600,7 @@ open class LoopPlugin @Inject constructor( } private fun applySMBRequest(request: APSResult, callback: Callback?) { - if (!request.bolusRequested) { + if (!request.bolusRequested()) { return } val pump = activePlugin.activePump diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/DetermineBasalResultAMA.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/DetermineBasalResultAMA.kt index 6f66dd235f..5411bd2fa3 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/DetermineBasalResultAMA.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/DetermineBasalResultAMA.kt @@ -40,7 +40,6 @@ class DetermineBasalResultAMA private constructor(injector: HasAndroidInjector) tempBasalRequested = false } } - bolusRequested = false } override fun newAndClone(injector: HasAndroidInjector): DetermineBasalResultAMA { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/DetermineBasalResultSMB.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/DetermineBasalResultSMB.kt index 996621b8db..aa5dff4b38 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/DetermineBasalResultSMB.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/DetermineBasalResultSMB.kt @@ -35,7 +35,6 @@ class DetermineBasalResultSMB private constructor(injector: HasAndroidInjector) duration = -1 } if (result.has("units")) { - bolusRequested = true smb = result.getDouble("units") } else { smb = 0.0 diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/aps/loop/APSResult.kt b/core/src/main/java/info/nightscout/androidaps/plugins/aps/loop/APSResult.kt index 989ecdcdd0..eb110e9391 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/aps/loop/APSResult.kt +++ b/core/src/main/java/info/nightscout/androidaps/plugins/aps/loop/APSResult.kt @@ -48,7 +48,6 @@ open class APSResult @Inject constructor(val injector: HasAndroidInjector) { var usePercent = false var duration = 0 var tempBasalRequested = false - var bolusRequested = false var iob: IobTotal? = null var json: JSONObject? = JSONObject() var hasPredictions = false @@ -161,7 +160,6 @@ open class APSResult @Inject constructor(val injector: HasAndroidInjector) { newResult.rate = rate newResult.duration = duration newResult.tempBasalRequested = tempBasalRequested - newResult.bolusRequested = bolusRequested newResult.iob = iob newResult.json = JSONObject(json.toString()) newResult.hasPredictions = hasPredictions @@ -309,11 +307,11 @@ open class APSResult @Inject constructor(val injector: HasAndroidInjector) { // closed loop mode: handle change at driver level if (closedLoopEnabled.value()) { aapsLogger.debug(LTag.APS, "DEFAULT: Closed mode") - return tempBasalRequested || bolusRequested + return tempBasalRequested || bolusRequested() } // open loop mode: try to limit request - if (!tempBasalRequested && !bolusRequested) { + if (!tempBasalRequested && !bolusRequested()) { aapsLogger.debug(LTag.APS, "FALSE: No request") return false } @@ -399,4 +397,6 @@ open class APSResult @Inject constructor(val injector: HasAndroidInjector) { } } } + + fun bolusRequested(): Boolean = smb > 0.0 } \ No newline at end of file From 5bd41d9abdbc6486bc628c73c12f1c9ea46f3251 Mon Sep 17 00:00:00 2001 From: Andy Rozman Date: Sat, 1 May 2021 11:24:50 +0100 Subject: [PATCH 022/145] - some cleanup - prelim work on TBR --- .../plugins/pump/common/sync/PumpDbEntry.kt | 23 +++++++++++- .../pump/common/sync/PumpSyncStorage.kt | 27 ++++++++------ .../pump/medtronic/MedtronicPumpPlugin.kt | 36 +++++++++---------- .../medtronic/data/MedtronicHistoryData.kt | 4 +++ 4 files changed, 58 insertions(+), 32 deletions(-) diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpDbEntry.kt b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpDbEntry.kt index e7ebc46ba4..9301d0c891 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpDbEntry.kt +++ b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpDbEntry.kt @@ -1,6 +1,8 @@ package info.nightscout.androidaps.plugins.pump.common.sync import info.nightscout.androidaps.data.DetailedBolusInfo +import info.nightscout.androidaps.data.Profile +import info.nightscout.androidaps.interfaces.PumpSync import info.nightscout.androidaps.plugins.pump.common.defs.PumpType @@ -21,6 +23,22 @@ data class PumpDbEntry constructor(var temporaryId: Long, detailedBolusInfo.carbs, detailedBolusInfo.bolusType) } + + constructor(temporaryId: Long, + date: Long, + pumpType: PumpType, + serialNumber: String, + rate: Double, + isAbsolute: Boolean, + durationInMinutes: Int, + tbrType: PumpSync.TemporaryBasalType) : this(temporaryId, date, pumpType, serialNumber) { + this.tbrData = PumpDbEntryTBR( + rate, + isAbsolute, + durationInMinutes, + tbrType) + } + } @@ -40,4 +58,7 @@ data class PumpDbEntryCarbs(var date: Long, creator.serialNumber()) } -data class PumpDbEntryTBR(var temporaryId: Long) \ No newline at end of file +data class PumpDbEntryTBR(var rate: Double, + var isAbsolute: Boolean, + var durationInMinutes: Int, + var tbrType: PumpSync.TemporaryBasalType) \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpSyncStorage.kt b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpSyncStorage.kt index 31e1a733f3..ef13ad9f0d 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpSyncStorage.kt +++ b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpSyncStorage.kt @@ -130,19 +130,24 @@ class PumpSyncStorage @Inject constructor( } // TODO - fun addTemporaryBasalRateWithTempId(temporaryBasal: TemporaryBasal, writeToInternalHistory: Boolean, creator: PumpSyncEntriesCreator) : Boolean { - // val temporaryId = generateTempId(temporaryBasal.date) - // val response = pumpSync.addBolusWithTempId(temporaryBasal.timestamp, detailedBolusInfo.insulin, + fun addTemporaryBasalRateWithTempId(temporaryBasal: PumpDbEntryTBR, writeToInternalHistory: Boolean, creator: PumpSyncEntriesCreator) : Boolean { + val timenow : Long = System.currentTimeMillis() + + val temporaryId = creator.generateTempId(timenow) + val response = false + // pumpSync.addBolusWithTempId(temporaryBasal.timestamp, detailedBolusInfo.insulin, // generateTempId(detailedBolusInfo.timestamp), detailedBolusInfo.getBolusType(), // getPumpType(), serialNumber()); - // - // if (response && writeToInternalHistory) { - // driverHistory.put(temporaryId, new PumpDbEntry(temporaryId, model(), serialNumber(), detailedBolusInfo)); - // sp.putString(MedtronicConst.Statistics.InternalTemporaryDatabase, gson.toJson(driverHistory)); - // } - // - // return response; - return false + + if (response && writeToInternalHistory) { + var innerList: MutableList = pumpSyncStorage[TBR]!! + + innerList.add(PumpDbEntry(temporaryId, timenow, creator.model(), creator.serialNumber(), null, temporaryBasal)) + pumpSyncStorage[BOLUS] = innerList + saveStorage() + } + + return response; } 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 4a91046067..53d72dc076 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 @@ -37,6 +37,8 @@ import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.Riley import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.tasks.ResetRileyLinkConfigurationTask import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.tasks.ServiceTaskExecutor import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.tasks.WakeAndTuneTask +import info.nightscout.androidaps.plugins.pump.common.sync.PumpDbEntry +import info.nightscout.androidaps.plugins.pump.common.sync.PumpDbEntryTBR import info.nightscout.androidaps.plugins.pump.common.sync.PumpSyncEntriesCreator import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil import info.nightscout.androidaps.plugins.pump.common.sync.PumpSyncStorage @@ -354,7 +356,7 @@ class MedtronicPumpPlugin @Inject constructor( } // execute - val refreshTypesNeededToReschedule: MutableSet = HashSet() + val refreshTypesNeededToReschedule: MutableSet = mutableSetOf() for ((key, value) in statusRefresh!!) { if (value!! > 0 && System.currentTimeMillis() > value) { when (key) { @@ -635,13 +637,6 @@ class MedtronicPumpPlugin @Inject constructor( pumpSyncStorage.addBolusWithTempId(detailedBolusInfo, true, this) - // // TODO fix - // if (usePumpSync) { - // pumpSyncStorage.addBolusWithTempId(detailedBolusInfo, true, this) - // } else { - // activePlugin.activeTreatments.addToHistoryTreatment(detailedBolusInfo, true) - // } - // we subtract insulin, exact amount will be visible with next remainingInsulin update. medtronicPumpStatus.reservoirRemainingUnits = medtronicPumpStatus.reservoirRemainingUnits - detailedBolusInfo.insulin incrementStatistics(if (detailedBolusInfo.bolusType === DetailedBolusInfo.BolusType.SMB) MedtronicConst.Statistics.SMBBoluses else MedtronicConst.Statistics.StandardBoluses) @@ -771,12 +766,12 @@ class MedtronicPumpPlugin @Inject constructor( .absolute(absoluteRate) // .source(Source.USER) - // TODO fix - if (usePumpSync) { - pumpSyncStorage.addTemporaryBasalRateWithTempId(tempStart, true, this) - } else { - activePlugin.activeTreatments.addToHistoryTempBasal(tempStart) - } + activePlugin.activeTreatments.addToHistoryTempBasal(tempStart) + + // val tempData = PumpDbEntryTBR(absoluteRate, true, durationInMinutes, tbrType) + // + // pumpSyncStorage.addTemporaryBasalRateWithTempId(tempData, true, this) + incrementStatistics(MedtronicConst.Statistics.TBRsSet) finishAction("TBR") PumpEnactResult(injector).success(true).enacted(true) // @@ -1016,12 +1011,13 @@ class MedtronicPumpPlugin @Inject constructor( .duration(0) // .source(Source.USER) - // TODO fix - if (usePumpSync) { - pumpSyncStorage.addTemporaryBasalRateWithTempId(tempBasal, true, this) - } else { - activePlugin.activeTreatments.addToHistoryTempBasal(tempBasal) - } + activePlugin.activeTreatments.addToHistoryTempBasal(tempBasal) + + // TODO need to find solution for this !? + // val tempData = PumpDbEntryTBR(absoluteRate, true, durationInMinutes, tbrType) + // + // pumpSyncStorage.addTemporaryBasalRateWithTempId(tempData, true, this) + PumpEnactResult(injector).success(true).enacted(true) // .isTempCancel(true) } else { 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 index 093947ec78..1e82d2b35e 100644 --- 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 @@ -42,6 +42,10 @@ import javax.inject.Singleton // 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) +// +// TODO New Database changes, we need to read 35 minutes from history on each read and then compare if items have the same +// amounts, if not send them back to database changes. ALSO we need to remove and invalidate TBRs that are cancels from +// PumpSyncStorage @Suppress("DEPRECATION") @Singleton class MedtronicHistoryData @Inject constructor( From 49f345d42514c35d86c1852710181c85229d9579 Mon Sep 17 00:00:00 2001 From: Andy Rozman Date: Sun, 2 May 2021 13:45:56 +0100 Subject: [PATCH 023/145] - startted adding 35 minut - before reading functionality - some refactoring --- .../pump/medtronic/MedtronicPumpPlugin.kt | 12 ++-- .../comm/history/MedtronicHistoryDecoder.kt | 21 +++--- .../comm/history/pump/PumpHistoryEntry.kt | 15 ++++- .../comm/ui/MedtronicUIPostprocessor.kt | 1 + .../pump/medtronic/comm/ui/MedtronicUITask.kt | 9 +-- .../medtronic/data/MedtronicHistoryData.kt | 65 +++++++++++++------ .../dialog/RileyLinkStatusDeviceMedtronic.kt | 9 +-- 7 files changed, 81 insertions(+), 51 deletions(-) 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 8a1c1ff14e..511f6ef70e 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 @@ -466,7 +466,7 @@ class MedtronicPumpPlugin @Inject constructor( } private val basalProfiles: Unit - private get() { + get() { val medtronicUITask = rileyLinkMedtronicService!!.medtronicUIComm.executeCommand(MedtronicCommandType.GetBasalProfileSTD) if (medtronicUITask.responseType === MedtronicUIResponseType.Error) { rileyLinkMedtronicService!!.medtronicUIComm.executeCommand(MedtronicCommandType.GetBasalProfileSTD) @@ -816,7 +816,7 @@ class MedtronicPumpPlugin @Inject constructor( medtronicHistoryData.processLastBasalProfileChange(pumpDescription.pumpType, medtronicPumpStatus) } val previousState = pumpState - if (medtronicHistoryData.isPumpSuspended) { + if (medtronicHistoryData.isPumpSuspended()) { pumpState = PumpDriverState.Suspended aapsLogger.debug(LTag.PUMP, logPrefix + "isPumpSuspended: true") } else { @@ -852,20 +852,19 @@ class MedtronicPumpPlugin @Inject constructor( lastHistoryRecordTime = lastHistoryRecordTime.minusHours(12) // we get last 12 hours of history to // determine pump state // (we don't process that data), we process only - if (timeMinus36h.isAfter(lastHistoryRecordTime)) { - targetDate = timeMinus36h - } targetDate = if (timeMinus36h.isAfter(lastHistoryRecordTime)) timeMinus36h else lastHistoryRecordTime if (debugHistory) aapsLogger.debug(LTag.PUMP, logPrefix + "readPumpHistoryLogic(): targetDate: " + targetDate) } } else { // all other reads if (debugHistory) aapsLogger.debug(LTag.PUMP, logPrefix + "readPumpHistoryLogic(): lastPumpHistoryEntry: not null - " + medtronicUtil.gsonInstance.toJson(lastPumpHistoryEntry)) medtronicHistoryData.setIsInInit(false) + // we need to read 35 minutes in the past so that we can repair any TBR or Bolus values if neeeded + targetDate = LocalDateTime(DateTimeUtil.getMillisFromATDWithAddedMinutes(lastPumpHistoryEntry!!.atechDateTime!!, -35)) } //aapsLogger.debug(LTag.PUMP, "HST: Target Date: " + targetDate); val responseTask2 = rileyLinkMedtronicService!!.medtronicUIComm.executeCommand(MedtronicCommandType.GetHistoryData, - arrayListOf(lastPumpHistoryEntry, targetDate) as ArrayList?) + arrayListOf(/*lastPumpHistoryEntry*/ null, 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()) @@ -949,7 +948,6 @@ class MedtronicPumpPlugin @Inject constructor( HashMap(statusRefreshMap) } - else -> null } } 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 91d64f3efc..65b03e70cb 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,7 +35,7 @@ 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): MutableList { + private fun checkPage(page: RawHistoryPage): MutableList { //val byteList: MutableList = mutableListOf() if (medtronicUtil.medtronicPumpModel == null) { @@ -51,8 +51,14 @@ abstract class MedtronicHistoryDecoder : MedtronicHi } } - fun processPageAndCreateRecords(rawHistoryPage: RawHistoryPage): List { - return processPageAndCreateRecords(rawHistoryPage, false) + fun processPageAndCreateRecords(rawHistoryPage: RawHistoryPage): MutableList { + val dataClear = checkPage(rawHistoryPage) + val records: MutableList = createRecords(dataClear) + for (record in records) { + decodeRecord(record) + } + runPostDecodeTasks() + return records } protected fun prepareStatistics() { @@ -117,13 +123,4 @@ abstract class MedtronicHistoryDecoder : MedtronicHi return StringUtil.getFormatedValueUS(value, decimals) } - private fun processPageAndCreateRecords(rawHistoryPage: RawHistoryPage, partial: Boolean): MutableList { - val dataClear = checkPage(rawHistoryPage, partial) - val records: MutableList = createRecords(dataClear) - for (record in records) { - decodeRecord(record) - } - runPostDecodeTasks() - return records - } } \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.kt index a5a7cbfaa8..b8f37cf379 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.kt @@ -72,9 +72,10 @@ class PumpHistoryEntry : MedtronicHistoryEntry() { override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is PumpHistoryEntry) return false - val that = other - return entryType == that.entryType && // - atechDateTime === that.atechDateTime // && // + val that = other as PumpHistoryEntry + return this.pumpId === that.pumpId + // return entryType == that.entryType && // + // atechDateTime === that.atechDateTime // && // // Objects.equals(this.decodedData, that.decodedData); } @@ -111,4 +112,12 @@ class PumpHistoryEntry : MedtronicHistoryEntry() { set(pumpId) { super.pumpId = pumpId } + + fun hasBolusOrTBRDataChanged(entry: PumpHistoryEntry) : Boolean { + if (entryType!=null && (entryType!! == PumpHistoryEntryType.Bolus || entryType!! == PumpHistoryEntryType.TempBasalCombined)) { + return false // TODO needs to be implemented + } + + return false + } } \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUIPostprocessor.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUIPostprocessor.kt index 9c340798be..f4398bee62 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUIPostprocessor.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUIPostprocessor.kt @@ -55,6 +55,7 @@ class MedtronicUIPostprocessor @Inject constructor( //aapsLogger.debug("D: basal profile on read: " + basalProfile); try { + // TODO need to refactor val profilesByHour = basalProfile!!.getProfilesByHour(medtronicPumpPlugin.pumpDescription.pumpType) if (profilesByHour != null) { medtronicPumpStatus.basalsByHour = profilesByHour diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUITask.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUITask.kt index addcd5d2c3..be334adf76 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUITask.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUITask.kt @@ -101,7 +101,8 @@ class MedtronicUITask { result = communicationManager.cancelTBR() } - MedtronicCommandType.SetBasalProfileSTD, MedtronicCommandType.SetBasalProfileA -> { + MedtronicCommandType.SetBasalProfileSTD, + MedtronicCommandType.SetBasalProfileA -> { val profile = parameters!![0] as BasalProfile result = communicationManager.setBasalProfile(profile) } @@ -128,7 +129,7 @@ class MedtronicUITask { } private fun getTbrSettings(): TempBasalPair? { - return TempBasalPair(getDoubleFromParameters(0), // + return TempBasalPair(getDoubleFromParameters(0)!!, // false, // getIntegerFromParameters(1)) } @@ -137,8 +138,8 @@ class MedtronicUITask { return parameters!![index] as Float } - fun getDoubleFromParameters(index: Int): Double { - return parameters!![index] as Double + fun getDoubleFromParameters(index: Int): Double? { + return parameters!![index] as Double? } private fun getIntegerFromParameters(index: Int): Int { 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 index 1e82d2b35e..e731eb1ce9 100644 --- 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 @@ -43,9 +43,10 @@ import javax.inject.Singleton // 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) // -// TODO New Database changes, we need to read 35 minutes from history on each read and then compare if items have the same -// amounts, if not send them back to database changes. ALSO we need to remove and invalidate TBRs that are cancels from -// PumpSyncStorage +// TODO New Database changes: +// + we need to read 35 minutes from history on each read +// - compare all read items if they have the same amounts, if not send them back to database changes. +// - we need to remove and invalidate TBRs that are cancels from PumpSyncStorage @Suppress("DEPRECATION") @Singleton class MedtronicHistoryData @Inject constructor( @@ -82,12 +83,35 @@ class MedtronicHistoryData @Inject constructor( for (validEntry in validEntries) { if (!allHistory.contains(validEntry)) { newEntries.add(validEntry) + } else { + val entryByPumpId = getEntryByPumpId(validEntry.pumpId!!) + + // TODO not implemented + if (entryByPumpId!=null && entryByPumpId.hasBolusOrTBRDataChanged(validEntry)) { + newEntries.add(validEntry) + allHistory.remove(entryByPumpId) + } } } newHistory = newEntries showLogs("List of history (before filtering): [" + newHistory.size + "]", gson.toJson(newHistory)) } + private fun getEntryByPumpId(pumpId: Long): PumpHistoryEntry? { + val findFirst = this.allHistory.stream() + .filter { f -> f.pumpId!! == pumpId } + .findFirst() + + return if (findFirst.isPresent()) findFirst.get() else null + // + // for (pumpHistoryEntry in allHistory) { + // if (pumpHistoryEntry.pumpId == pumpId) { + // return pumpHistoryEntry + // } + // } + // return null + } + private fun showLogs(header: String?, data: String) { if (header != null) { aapsLogger.debug(LTag.PUMP, header) @@ -223,22 +247,21 @@ class MedtronicHistoryData @Inject constructor( } - 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 - } + fun isPumpSuspended(): Boolean { + 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() @@ -246,7 +269,7 @@ class MedtronicHistoryData @Inject constructor( newAndAll.addAll(allHistory) } if (isCollectionNotEmpty(newHistory)) { - for (pumpHistoryEntry in newHistory!!) { + for (pumpHistoryEntry in newHistory) { if (!newAndAll.contains(pumpHistoryEntry)) { newAndAll.add(pumpHistoryEntry) } @@ -563,7 +586,7 @@ class MedtronicHistoryData @Inject constructor( var processDTO: TempBasalProcessDTO? = null val processList: MutableList = ArrayList() for (treatment in entryList) { - val tbr2 = treatment!!.getDecodedDataEntry("Object") as TempBasalPair? + val tbr2 = treatment.getDecodedDataEntry("Object") as TempBasalPair? if (tbr2!!.isCancelTBR) { if (processDTO != null) { processDTO.itemTwo = treatment diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/RileyLinkStatusDeviceMedtronic.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/RileyLinkStatusDeviceMedtronic.kt index 3fe1eb4d8e..fade5fbed0 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/RileyLinkStatusDeviceMedtronic.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/RileyLinkStatusDeviceMedtronic.kt @@ -112,16 +112,17 @@ class RileyLinkStatusDeviceMedtronic : DaggerFragment(), RefreshableInterface { var view = viewIn val viewHolder: ViewHolder // General ListView optimization code. - if (view == null) { +// if (view == null) { view = mInflator.inflate(R.layout.rileylink_status_device_item, null) viewHolder = ViewHolder() viewHolder.itemTime = view.findViewById(R.id.rileylink_history_time) viewHolder.itemSource = view.findViewById(R.id.rileylink_history_source) viewHolder.itemDescription = view.findViewById(R.id.rileylink_history_description) view.tag = viewHolder - } else { - viewHolder = view.tag as ViewHolder - } + // } + // else { + // viewHolder = view.tag as ViewHolder + // } val item = historyItemList[i] viewHolder.itemTime!!.text = StringUtil.toDateTimeString(dateUtil, item.dateTime) viewHolder.itemSource!!.text = "Riley Link" // for now From a9e6cfaa666a5a14be9d526ca88bdae672cf712c Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Sun, 2 May 2021 16:08:24 +0200 Subject: [PATCH 024/145] sync TBR with temp id --- .../androidaps/interfaces/PumpSync.kt | 61 +++++++++++- .../plugins/pump/PumpSyncImplementation.kt | 97 ++++++++++++++----- .../database/daos/TemporaryBasalDao.kt | 3 + ...kt => InsertBolusWithTempIdTransaction.kt} | 4 +- ...sertTemporaryBasalWithTempIdTransaction.kt | 28 ++++++ ...n.kt => SyncBolusWithTempIdTransaction.kt} | 4 +- ...SyncTemporaryBasalWithTempIdTransaction.kt | 35 +++++++ 7 files changed, 199 insertions(+), 33 deletions(-) rename database/src/main/java/info/nightscout/androidaps/database/transactions/{InsertPumpBolusWithTempIdTransaction.kt => InsertBolusWithTempIdTransaction.kt} (87%) create mode 100644 database/src/main/java/info/nightscout/androidaps/database/transactions/InsertTemporaryBasalWithTempIdTransaction.kt rename database/src/main/java/info/nightscout/androidaps/database/transactions/{SyncPumpBolusWithTempIdTransaction.kt => SyncBolusWithTempIdTransaction.kt} (90%) create mode 100644 database/src/main/java/info/nightscout/androidaps/database/transactions/SyncTemporaryBasalWithTempIdTransaction.kt diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/PumpSync.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/PumpSync.kt index 0ac0080f34..b8d21730d3 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/PumpSync.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/PumpSync.kt @@ -77,7 +77,7 @@ interface PumpSync { * USAGE: * Generate unique temporaryId * Call before bolus when no pumpId is known (provide timestamp, amount, temporaryId, type, pumpType, pumpSerial) - * After reading record from history or completed bolus call syncBolusWithTempId with the same temporaryId provided + * After reading record from history or completed bolus call [syncBolusWithTempId] with the same temporaryId provided * If syncBolusWithTempId is not called afterwards record remains valid and is calculated towards iob * * @param timestamp timestamp of event from pump history @@ -276,6 +276,61 @@ interface PumpSync { **/ fun syncStopTemporaryBasalWithPumpId(timestamp: Long, endPumpId: Long, pumpType: PumpType, pumpSerial: String): Boolean + /** + * Create temporary basal with temporary id + * + * Search for combination of temporaryId, PumpType, pumpSerial + * + * If db record doesn't exist, new record is created. + * If exists false is returned and data is ignored + * + * USAGE: + * Generate unique temporaryId + * Call on setting temporary basal when no pumpId is known (provide timestamp, temporaryId, type, pumpType, pumpSerial) + * After reading record from history or completed bolus call [syncTemporaryBasalWithTempId] with the same temporaryId provided + * If syncTemporaryBasalWithTempId is not called afterwards record remains valid and is calculated towards iob + * + * @param timestamp timestamp of event from pump history + * @param rate TBR rate in U/h or % (value of 100% is equal to no TBR) + * @param duration duration in milliseconds + * @param isAbsolute is TBR in U/h or % ? + * @param tempId pump id from history + * @param type type of TBR, from request sent to the driver + * @param pumpType pump type like PumpType.ACCU_CHEK_COMBO + * @param pumpSerial pump serial number + * @return true if new record is created + * + * see [info.nightscout.androidaps.database.transactions.InsertTemporaryBasalWithTempIdTransaction] + **/ + + fun addTemporaryBasalWithTempId(timestamp: Long, rate: Double, duration: Long, isAbsolute: Boolean, tempId: Long, type: TemporaryBasalType, pumpType: PumpType, pumpSerial: String): Boolean + + /** + * Synchronization of temporary basal with temporary id + * + * Search for combination of temporaryId, PumpType, pumpSerial + * + * If db record doesn't exist data is ignored and false returned. + * If exists, data is updated, type and pumpId only if provided + * isValid field is preserved + * + * USAGE: + * After reading record from history or completed bolus call syncTemporaryBasalWithTempId and + * provide updated timestamp, rate, duration, pumpId (if known), type (if change needed) with the same temporaryId, pumpType, pumpSerial + * + * @param timestamp timestamp of event from pump history + * @param rate TBR rate in U/h or % (value of 100% is equal to no TBR) + * @param duration duration in milliseconds + * @param isAbsolute is TBR in U/h or % ? + * @param temporaryId temporary id generated when pump id in not know yet + * @param type type of TBR, from request sent to the driver + * @param pumpId pump id from history + * @param pumpType pump type like PumpType.ACCU_CHEK_COMBO + * @param pumpSerial pump serial number + * @return true if record is successfully updated + **/ + fun syncTemporaryBasalWithTempId(timestamp: Long, rate: Double, duration: Long, isAbsolute: Boolean, temporaryId: Long, type: TemporaryBasalType?, pumpId: Long?, pumpType: PumpType, pumpSerial: String): Boolean + /** * Invalidate of temporary basals that failed to start * EROS specific, replace by setting duration to zero ???? @@ -284,9 +339,7 @@ interface PumpSync { * If db record doesn't exist data is ignored and false returned * * - * @param pumpId pump id of ending event from history - * @param pumpType pump type like PumpType.ACCU_CHEK_COMBO - * @param pumpSerial pump serial number + * @param id id of temporary basal * @return true if running record is found and invalidated **/ fun invalidateTemporaryBasal(id: Long): Boolean diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/PumpSyncImplementation.kt b/core/src/main/java/info/nightscout/androidaps/plugins/pump/PumpSyncImplementation.kt index ac9fa5ded0..0c995a3a44 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/pump/PumpSyncImplementation.kt +++ b/core/src/main/java/info/nightscout/androidaps/plugins/pump/PumpSyncImplementation.kt @@ -124,11 +124,11 @@ class PumpSyncImplementation @Inject constructor( pumpSerial = pumpSerial ) ) - repository.runTransactionForResult(InsertPumpBolusWithTempIdTransaction(bolus)) - .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving bolus", it) } + repository.runTransactionForResult(InsertBolusWithTempIdTransaction(bolus)) + .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving Bolus", it) } .blockingGet() .also { result -> - result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted bolus $it") } + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted Bolus $it") } return result.inserted.size > 0 } } @@ -146,11 +146,11 @@ class PumpSyncImplementation @Inject constructor( pumpSerial = pumpSerial ) ) - repository.runTransactionForResult(SyncPumpBolusWithTempIdTransaction(bolus, type?.toDBbBolusType())) - .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving bolus", it) } + repository.runTransactionForResult(SyncBolusWithTempIdTransaction(bolus, type?.toDBbBolusType())) + .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving Bolus", it) } .blockingGet() .also { result -> - result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated bolus $it") } + result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated Bolus $it") } return result.updated.size > 0 } } @@ -168,11 +168,11 @@ class PumpSyncImplementation @Inject constructor( ) ) repository.runTransactionForResult(SyncPumpBolusTransaction(bolus, type?.toDBbBolusType())) - .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving bolus", it) } + .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving Bolus", it) } .blockingGet() .also { result -> - result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted bolus $it") } - result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated bolus $it") } + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted Bolus $it") } + result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated Bolus $it") } return result.inserted.size > 0 } } @@ -189,10 +189,10 @@ class PumpSyncImplementation @Inject constructor( pumpSerial = pumpSerial) ) repository.runTransactionForResult(InsertIfNewByTimestampCarbsTransaction(carbs)) - .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving carbs", it) } + .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving Carbs", it) } .blockingGet() .also { result -> - result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted carbs $it") } + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted Carbs $it") } return result.inserted.size > 0 } } @@ -215,11 +215,11 @@ class PumpSyncImplementation @Inject constructor( ) repository.runTransactionForResult(InsertIfNewByTimestampTherapyEventTransaction(therapyEvent)) .doOnError { - aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", it) + aapsLogger.error(LTag.DATABASE, "Error while saving TherapyEvent", it) } .blockingGet() .also { result -> - result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted therapy event $it") } + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted TherapyEvent $it") } return result.inserted.size > 0 } } @@ -249,11 +249,11 @@ class PumpSyncImplementation @Inject constructor( ) ) repository.runTransactionForResult(SyncPumpTemporaryBasalTransaction(temporaryBasal, type?.toDbType())) - .doOnError { aapsLogger.error(LTag.DATABASE, "Error while temporary basal", it) } + .doOnError { aapsLogger.error(LTag.DATABASE, "Error while TemporaryBasal", it) } .blockingGet() .also { result -> - result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted temporary basal $it") } - result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated temporary basal $it") } + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted TemporaryBasal $it") } + result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated TemporaryBasal $it") } return result.inserted.size > 0 } } @@ -261,23 +261,70 @@ class PumpSyncImplementation @Inject constructor( override fun syncStopTemporaryBasalWithPumpId(timestamp: Long, endPumpId: Long, pumpType: PumpType, pumpSerial: String): Boolean { if (!confirmActivePump(timestamp, pumpType, pumpSerial)) return false repository.runTransactionForResult(SyncPumpCancelTemporaryBasalIfAnyTransaction(timestamp, endPumpId, pumpType.toDbPumpType(), pumpSerial)) - .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving temporary basal", it) } + .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving TemporaryBasal", it) } .blockingGet() .also { result -> result.updated.forEach { - aapsLogger.debug(LTag.DATABASE, "Updated temporary basal $it") + aapsLogger.debug(LTag.DATABASE, "Updated TemporaryBasal $it") } return result.updated.size > 0 } } + override fun addTemporaryBasalWithTempId(timestamp: Long, rate: Double, duration: Long, isAbsolute: Boolean, tempId: Long, type: PumpSync.TemporaryBasalType, pumpType: PumpType, pumpSerial: String): Boolean { + if (!confirmActivePump(timestamp, pumpType, pumpSerial)) return false + val temporaryBasal = TemporaryBasal( + timestamp = timestamp, + rate = rate, + duration = duration, + type = type.toDbType(), + isAbsolute = isAbsolute, + interfaceIDs_backing = InterfaceIDs( + temporaryId = tempId, + pumpType = pumpType.toDbPumpType(), + pumpSerial = pumpSerial + ) + ) + repository.runTransactionForResult(InsertTemporaryBasalWithTempIdTransaction(temporaryBasal)) + .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving TemporaryBasal", it) } + .blockingGet() + .also { result -> + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted TemporaryBasal $it") } + return result.inserted.size > 0 + } + } + + override fun syncTemporaryBasalWithTempId(timestamp: Long, rate: Double, duration: Long, isAbsolute: Boolean, temporaryId: Long, type: PumpSync.TemporaryBasalType?, pumpId: Long?, pumpType: PumpType, pumpSerial: String): Boolean { + if (!confirmActivePump(timestamp, pumpType, pumpSerial)) return false + val bolus = TemporaryBasal( + timestamp = timestamp, + rate = rate, + duration = duration, + type = TemporaryBasal.Type.NORMAL, // not used for update + isAbsolute = isAbsolute, + interfaceIDs_backing = InterfaceIDs( + temporaryId = temporaryId, + pumpId = pumpId, + pumpType = pumpType.toDbPumpType(), + pumpSerial = pumpSerial + ) + ) + repository.runTransactionForResult(SyncTemporaryBasalWithTempIdTransaction(bolus, type?.toDbType())) + .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving TemporaryBasal", it) } + .blockingGet() + .also { result -> + result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated TemporaryBasal $it") } + return result.updated.size > 0 + } + } + override fun invalidateTemporaryBasal(id: Long): Boolean { repository.runTransactionForResult(InvalidateTemporaryBasalTransaction(id)) - .doOnError { aapsLogger.error(LTag.DATABASE, "Error while invalidating temporary basal", it) } + .doOnError { aapsLogger.error(LTag.DATABASE, "Error while invalidating TemporaryBasal", it) } .blockingGet() .also { result -> result.invalidated.forEach { - aapsLogger.debug(LTag.DATABASE, "Invalidated temporary basal $it") + aapsLogger.debug(LTag.DATABASE, "Invalidated TemporaryBasal $it") } return result.invalidated.size > 0 } @@ -297,11 +344,11 @@ class PumpSyncImplementation @Inject constructor( ) ) repository.runTransactionForResult(SyncPumpExtendedBolusTransaction(extendedBolus)) - .doOnError { aapsLogger.error(LTag.DATABASE, "Error while extended bolus", it) } + .doOnError { aapsLogger.error(LTag.DATABASE, "Error while ExtendedBolus", it) } .blockingGet() .also { result -> - result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted extended bolus $it") } - result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated extended bolus $it") } + result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted ExtendedBolus $it") } + result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated ExtendedBolus $it") } return result.inserted.size > 0 } } @@ -309,11 +356,11 @@ class PumpSyncImplementation @Inject constructor( override fun syncStopExtendedBolusWithPumpId(timestamp: Long, endPumpId: Long, pumpType: PumpType, pumpSerial: String): Boolean { if (!confirmActivePump(timestamp, pumpType, pumpSerial)) return false repository.runTransactionForResult(SyncPumpCancelExtendedBolusIfAnyTransaction(timestamp, endPumpId, pumpType.toDbPumpType(), pumpSerial)) - .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving extended bolus", it) } + .doOnError { aapsLogger.error(LTag.DATABASE, "Error while saving ExtendedBolus", it) } .blockingGet() .also { result -> result.updated.forEach { - aapsLogger.debug(LTag.DATABASE, "Updated extended bolus $it") + aapsLogger.debug(LTag.DATABASE, "Updated ExtendedBolus $it") } return result.updated.size > 0 } diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/TemporaryBasalDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/TemporaryBasalDao.kt index 49f0c8342c..d03cc6d91d 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/daos/TemporaryBasalDao.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/TemporaryBasalDao.kt @@ -30,6 +30,9 @@ internal interface TemporaryBasalDao : TraceableDao { @Query("SELECT * FROM $TABLE_TEMPORARY_BASALS WHERE nightscoutId = :nsId AND referenceId IS NULL") fun findByNSId(nsId: String): TemporaryBasal? + @Query("SELECT * FROM $TABLE_TEMPORARY_BASALS WHERE temporaryId = :temporaryId AND pumpType = :pumpType AND pumpSerial = :pumpSerial AND referenceId IS NULL") + fun findByPumpTempIds(temporaryId: Long, pumpType: InterfaceIDs.PumpType, pumpSerial: String): TemporaryBasal? + @Query("SELECT * FROM $TABLE_TEMPORARY_BASALS WHERE timestamp <= :timestamp AND (timestamp + duration) > :timestamp AND pumpType = :pumpType AND pumpSerial = :pumpSerial AND referenceId IS NULL AND isValid = 1 ORDER BY timestamp DESC LIMIT 1") fun getTemporaryBasalActiveAt(timestamp: Long, pumpType: InterfaceIDs.PumpType, pumpSerial: String): Maybe diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertPumpBolusWithTempIdTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertBolusWithTempIdTransaction.kt similarity index 87% rename from database/src/main/java/info/nightscout/androidaps/database/transactions/InsertPumpBolusWithTempIdTransaction.kt rename to database/src/main/java/info/nightscout/androidaps/database/transactions/InsertBolusWithTempIdTransaction.kt index 97f8286eff..2b7ad086ac 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertPumpBolusWithTempIdTransaction.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertBolusWithTempIdTransaction.kt @@ -5,9 +5,9 @@ import info.nightscout.androidaps.database.entities.Bolus /** * Creates or updates the Bolus from pump synchronization */ -class InsertPumpBolusWithTempIdTransaction( +class InsertBolusWithTempIdTransaction( private val bolus: Bolus -) : Transaction() { +) : Transaction() { override fun run(): TransactionResult { bolus.interfaceIDs.temporaryId ?: bolus.interfaceIDs.pumpType ?: bolus.interfaceIDs.pumpSerial ?: diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertTemporaryBasalWithTempIdTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertTemporaryBasalWithTempIdTransaction.kt new file mode 100644 index 0000000000..27f931bcd9 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertTemporaryBasalWithTempIdTransaction.kt @@ -0,0 +1,28 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.TemporaryBasal + +/** + * Creates or updates the TemporaryBasal from pump synchronization + */ +class InsertTemporaryBasalWithTempIdTransaction(private val temporaryBasal: TemporaryBasal +) : Transaction() { + + override fun run(): TransactionResult { + temporaryBasal.interfaceIDs.temporaryId ?: temporaryBasal.interfaceIDs.pumpType + ?: temporaryBasal.interfaceIDs.pumpSerial + ?: throw IllegalStateException("Some pump ID is null") + val result = TransactionResult() + val current = database.temporaryBasalDao.findByPumpTempIds(temporaryBasal.interfaceIDs.temporaryId!!, temporaryBasal.interfaceIDs.pumpType!!, temporaryBasal.interfaceIDs.pumpSerial!!) + if (current == null) { + database.temporaryBasalDao.insert(temporaryBasal) + result.inserted.add(temporaryBasal) + } + return result + } + + class TransactionResult { + + val inserted = mutableListOf() + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncPumpBolusWithTempIdTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncBolusWithTempIdTransaction.kt similarity index 90% rename from database/src/main/java/info/nightscout/androidaps/database/transactions/SyncPumpBolusWithTempIdTransaction.kt rename to database/src/main/java/info/nightscout/androidaps/database/transactions/SyncBolusWithTempIdTransaction.kt index 8fe8eb4fc3..99449f5ce7 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncPumpBolusWithTempIdTransaction.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncBolusWithTempIdTransaction.kt @@ -5,10 +5,10 @@ import info.nightscout.androidaps.database.entities.Bolus /** * Creates or updates the Bolus from pump synchronization */ -class SyncPumpBolusWithTempIdTransaction( +class SyncBolusWithTempIdTransaction( private val bolus: Bolus, private val newType: Bolus.Type? -) : Transaction() { +) : Transaction() { override fun run(): TransactionResult { bolus.interfaceIDs.temporaryId ?: bolus.interfaceIDs.pumpType ?: bolus.interfaceIDs.pumpSerial ?: diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncTemporaryBasalWithTempIdTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncTemporaryBasalWithTempIdTransaction.kt new file mode 100644 index 0000000000..81f061a0ff --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncTemporaryBasalWithTempIdTransaction.kt @@ -0,0 +1,35 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.TemporaryBasal + +/** + * Creates or updates the TemporaryBasal from pump synchronization + */ +class SyncTemporaryBasalWithTempIdTransaction( + private val bolus: TemporaryBasal, + private val newType: TemporaryBasal.Type? +) : Transaction() { + + override fun run(): TransactionResult { + bolus.interfaceIDs.temporaryId ?: bolus.interfaceIDs.pumpType + ?: bolus.interfaceIDs.pumpSerial ?: throw IllegalStateException("Some pump ID is null") + val result = TransactionResult() + val current = database.temporaryBasalDao.findByPumpTempIds(bolus.interfaceIDs.temporaryId!!, bolus.interfaceIDs.pumpType!!, bolus.interfaceIDs.pumpSerial!!) + if (current != null) { + current.timestamp = bolus.timestamp + current.rate = bolus.rate + current.duration = bolus.duration + current.isAbsolute = bolus.isAbsolute + current.type = newType ?: current.type + current.interfaceIDs.pumpId = bolus.interfaceIDs.pumpId + database.temporaryBasalDao.updateExistingEntry(current) + result.updated.add(current) + } + return result + } + + class TransactionResult { + + val updated = mutableListOf() + } +} \ No newline at end of file From 5747f972014937eeb3d0fff8ecbeffac7440f551 Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Mon, 3 May 2021 09:33:14 +0200 Subject: [PATCH 025/145] DanaHistoryDatabase --- .../androidaps/db/DatabaseHelper.java | 466 ------------------ .../androidaps/db/DatabaseHelperProvider.java | 28 +- .../dependencyInjection/AppComponent.kt | 2 + .../dependencyInjection/AppModule.kt | 5 +- .../maintenance/MaintenanceFragment.kt | 6 +- .../general/nsclient/NSClientFragment.kt | 17 - .../plugins/general/nsclient/UploadQueue.java | 56 +-- .../general/openhumans/OpenHumansUploader.kt | 90 ++-- .../general/overview/graphData/GraphData.kt | 6 +- .../plugins/treatments/TreatmentService.java | 15 - .../main/res/layout/ns_client_fragment.xml | 29 -- .../androidaps/db/DanaRHistoryRecord.java | 77 --- .../androidaps/di/CoreDataClassesModule.kt | 6 - .../interfaces/DatabaseHelperInterface.kt | 3 - .../androidaps/interfaces/IobCobCalculator.kt | 2 +- .../androidaps/interfaces/ProfileStore.kt | 4 +- .../interfaces/UploadQueueAdminInterface.kt | 6 - .../interfaces/UploadQueueInterface.java | 4 - .../plugins/general/nsclient/NSUpload.java | 52 -- dana/build.gradle | 6 + .../dana/activities/DanaHistoryActivity.kt | 190 ++++--- .../dana/database/DanaHistoryDatabase.kt | 33 ++ .../dana/database/DanaHistoryRecord.kt | 19 + .../dana/database/DanaHistoryRecordDao.kt | 17 + .../androidaps/dana/di/DanaHistoryModule.kt | 21 + .../androidaps/dana/di/DanaModule.kt | 5 + .../res/layout/danar_history_activity.xml | 112 +++-- .../main/res/layout/danar_history_item.xml | 152 +++--- .../androidaps/danar/comm/MessageBase.java | 3 +- .../androidaps/danar/comm/MsgHistoryAll.kt | 77 +-- .../danars/comm/DanaRS_Packet_History_.kt | 90 ++-- .../comm/DanaRSPacketHistoryAlarmTest.kt | 16 +- .../pump/insight/LocalInsightPlugin.java | 10 +- 33 files changed, 506 insertions(+), 1119 deletions(-) delete mode 100644 core/src/main/java/info/nightscout/androidaps/db/DanaRHistoryRecord.java delete mode 100644 core/src/main/java/info/nightscout/androidaps/interfaces/UploadQueueAdminInterface.kt create mode 100644 dana/src/main/java/info/nightscout/androidaps/dana/database/DanaHistoryDatabase.kt create mode 100644 dana/src/main/java/info/nightscout/androidaps/dana/database/DanaHistoryRecord.kt create mode 100644 dana/src/main/java/info/nightscout/androidaps/dana/database/DanaHistoryRecordDao.kt create mode 100644 dana/src/main/java/info/nightscout/androidaps/dana/di/DanaHistoryModule.kt diff --git a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java index 1520dd0bbd..c241d65732 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java +++ b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java @@ -4,8 +4,6 @@ import android.content.Context; import android.database.DatabaseUtils; import android.database.sqlite.SQLiteDatabase; -import androidx.annotation.Nullable; - import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper; import com.j256.ormlite.dao.CloseableIterator; import com.j256.ormlite.dao.Dao; @@ -20,9 +18,6 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; import javax.inject.Inject; @@ -76,10 +71,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { public void onCreate(SQLiteDatabase database, ConnectionSource connectionSource) { try { aapsLogger.info(LTag.DATABASE, "onCreate"); - TableUtils.createTableIfNotExists(connectionSource, DanaRHistoryRecord.class); TableUtils.createTableIfNotExists(connectionSource, DbRequest.class); - TableUtils.createTableIfNotExists(connectionSource, TemporaryBasal.class); - TableUtils.createTableIfNotExists(connectionSource, ExtendedBolus.class); TableUtils.createTableIfNotExists(connectionSource, InsightHistoryOffset.class); TableUtils.createTableIfNotExists(connectionSource, InsightBolusID.class); TableUtils.createTableIfNotExists(connectionSource, InsightPumpID.class); @@ -103,10 +95,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { if (oldVersion < 7) { aapsLogger.info(LTag.DATABASE, "onUpgrade"); - TableUtils.dropTable(connectionSource, DanaRHistoryRecord.class, true); TableUtils.dropTable(connectionSource, DbRequest.class, true); - TableUtils.dropTable(connectionSource, TemporaryBasal.class, true); - TableUtils.dropTable(connectionSource, ExtendedBolus.class, true); onCreate(database, connectionSource); } else if (oldVersion < 10) { TableUtils.createTableIfNotExists(connectionSource, InsightHistoryOffset.class); @@ -149,15 +138,9 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { public void resetDatabases() { try { - TableUtils.dropTable(connectionSource, DanaRHistoryRecord.class, true); TableUtils.dropTable(connectionSource, DbRequest.class, true); - TableUtils.dropTable(connectionSource, TemporaryBasal.class, true); - TableUtils.dropTable(connectionSource, ExtendedBolus.class, true); TableUtils.dropTable(connectionSource, OmnipodHistoryRecord.class, true); - TableUtils.createTableIfNotExists(connectionSource, DanaRHistoryRecord.class); TableUtils.createTableIfNotExists(connectionSource, DbRequest.class); - TableUtils.createTableIfNotExists(connectionSource, TemporaryBasal.class); - TableUtils.createTableIfNotExists(connectionSource, ExtendedBolus.class); TableUtils.createTableIfNotExists(connectionSource, OmnipodHistoryRecord.class); updateEarliestDataChange(0); } catch (SQLException e) { @@ -177,22 +160,10 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { // ------------------ getDao ------------------------------------------- - private Dao getDaoDanaRHistory() throws SQLException { - return getDao(DanaRHistoryRecord.class); - } - private Dao getDaoDbRequest() throws SQLException { return getDao(DbRequest.class); } - private Dao getDaoTemporaryBasal() throws SQLException { - return getDao(TemporaryBasal.class); - } - - private Dao getDaoExtendedBolus() throws SQLException { - return getDao(ExtendedBolus.class); - } - private Dao getDaoInsightPumpID() throws SQLException { return getDao(InsightPumpID.class); } @@ -293,433 +264,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { } } - // ----------------- DanaRHistory handling -------------------- - - public void createOrUpdate(DanaRHistoryRecord record) { - try { - getDaoDanaRHistory().createOrUpdate(record); - } catch (SQLException e) { - aapsLogger.error("Unhandled exception", e); - } - } - - public List getDanaRHistoryRecordsByType(byte type) { - List historyList; - try { - QueryBuilder queryBuilder = getDaoDanaRHistory().queryBuilder(); - queryBuilder.orderBy("recordDate", false); - Where where = queryBuilder.where(); - where.eq("recordCode", type); - queryBuilder.limit(200L); - PreparedQuery preparedQuery = queryBuilder.prepare(); - historyList = getDaoDanaRHistory().query(preparedQuery); - } catch (SQLException e) { - aapsLogger.error("Unhandled exception", e); - historyList = new ArrayList<>(); - } - return historyList; - } - - // ------------ TemporaryBasal handling --------------- - - //return true if new record was created - public boolean createOrUpdate(TemporaryBasal tempBasal) { - try { - TemporaryBasal old; - tempBasal.date = roundDateToSec(tempBasal.date); - - if (tempBasal.source == Source.PUMP) { - // check for changed from pump change in NS - QueryBuilder queryBuilder = getDaoTemporaryBasal().queryBuilder(); - Where where = queryBuilder.where(); - where.eq("pumpId", tempBasal.pumpId); - PreparedQuery preparedQuery = queryBuilder.prepare(); - List trList = getDaoTemporaryBasal().query(preparedQuery); - if (trList.size() > 0) { - // do nothing, pump history record cannot be changed - aapsLogger.debug(LTag.DATABASE, "TEMPBASAL: Already exists from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString()); - return false; - } - - // search by date (in case its standard record that has become pump record) - QueryBuilder queryBuilder2 = getDaoTemporaryBasal().queryBuilder(); - Where where2 = queryBuilder2.where(); - where2.eq("date", tempBasal.date); - PreparedQuery preparedQuery2 = queryBuilder2.prepare(); - List trList2 = getDaoTemporaryBasal().query(preparedQuery2); - - if (trList2.size() > 0) { - old = trList2.get(0); - - old.copyFromPump(tempBasal); - old.source = Source.PUMP; - - aapsLogger.debug(LTag.DATABASE, "TEMPBASAL: Updated record with Pump Data : " + Source.getString(tempBasal.source) + " " + tempBasal.toString()); - - getDaoTemporaryBasal().update(old); - openHumansUploader.enqueueTemporaryBasal(old); - - updateEarliestDataChange(tempBasal.date); -// scheduleTemporaryBasalChange(); - - return false; - } - - getDaoTemporaryBasal().create(tempBasal); - openHumansUploader.enqueueTemporaryBasal(tempBasal); - aapsLogger.debug(LTag.DATABASE, "TEMPBASAL: New record from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString()); - updateEarliestDataChange(tempBasal.date); -// scheduleTemporaryBasalChange(); - return true; - } - if (tempBasal.source == Source.NIGHTSCOUT) { - old = getDaoTemporaryBasal().queryForId(tempBasal.date); - if (old != null) { - if (!old.isAbsolute && tempBasal.isAbsolute) { // converted to absolute by "ns_sync_use_absolute" - // so far ignore, do not convert back because it may not be accurate - return false; - } - if (!old.isEqual(tempBasal)) { - long oldDate = old.date; - getDaoTemporaryBasal().delete(old); // need to delete/create because date may change too - old.copyFrom(tempBasal); - getDaoTemporaryBasal().create(old); - openHumansUploader.enqueueTemporaryBasal(old); - aapsLogger.debug(LTag.DATABASE, "TEMPBASAL: Updating record by date from: " + Source.getString(tempBasal.source) + " " + old.toString()); - updateEarliestDataChange(oldDate); - updateEarliestDataChange(old.date); -// scheduleTemporaryBasalChange(); - return true; - } - return false; - } - // find by NS _id - if (tempBasal._id != null) { - QueryBuilder queryBuilder = getDaoTemporaryBasal().queryBuilder(); - Where where = queryBuilder.where(); - where.eq("_id", tempBasal._id); - PreparedQuery preparedQuery = queryBuilder.prepare(); - List trList = getDaoTemporaryBasal().query(preparedQuery); - if (trList.size() > 0) { - old = trList.get(0); - if (!old.isEqual(tempBasal)) { - long oldDate = old.date; - getDaoTemporaryBasal().delete(old); // need to delete/create because date may change too - old.copyFrom(tempBasal); - getDaoTemporaryBasal().create(old); - openHumansUploader.enqueueTemporaryBasal(old); - aapsLogger.debug(LTag.DATABASE, "TEMPBASAL: Updating record by _id from: " + Source.getString(tempBasal.source) + " " + old.toString()); - updateEarliestDataChange(oldDate); - updateEarliestDataChange(old.date); -// scheduleTemporaryBasalChange(); - return true; - } - } - } - getDaoTemporaryBasal().create(tempBasal); - openHumansUploader.enqueueTemporaryBasal(tempBasal); - aapsLogger.debug(LTag.DATABASE, "TEMPBASAL: New record from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString()); - updateEarliestDataChange(tempBasal.date); -// scheduleTemporaryBasalChange(); - return true; - } - if (tempBasal.source == Source.USER) { - getDaoTemporaryBasal().create(tempBasal); - openHumansUploader.enqueueTemporaryBasal(tempBasal); - aapsLogger.debug(LTag.DATABASE, "TEMPBASAL: New record from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString()); - updateEarliestDataChange(tempBasal.date); -// scheduleTemporaryBasalChange(); - return true; - } - } catch (SQLException e) { - aapsLogger.error("Unhandled exception", e); - } - return false; - } - - public void delete(TemporaryBasal tempBasal) { - try { - getDaoTemporaryBasal().delete(tempBasal); - openHumansUploader.enqueueTemporaryBasal(tempBasal, true); - updateEarliestDataChange(tempBasal.date); - } catch (SQLException e) { - aapsLogger.error("Unhandled exception", e); - } -// scheduleTemporaryBasalChange(); - } - - public List getTemporaryBasalsDataFromTime(long mills, boolean ascending) { - try { - List tempbasals; - QueryBuilder queryBuilder = getDaoTemporaryBasal().queryBuilder(); - queryBuilder.orderBy("date", ascending); - Where where = queryBuilder.where(); - where.ge("date", mills); - PreparedQuery preparedQuery = queryBuilder.prepare(); - tempbasals = getDaoTemporaryBasal().query(preparedQuery); - return tempbasals; - } catch (SQLException e) { - aapsLogger.error("Unhandled exception", e); - } - return new ArrayList(); - } - - /* - { - "_id": "59232e1ddd032d04218dab00", - "eventType": "Temp Basal", - "duration": 60, - "percent": -50, - "created_at": "2017-05-22T18:29:57Z", - "enteredBy": "AndroidAPS", - "notes": "Basal Temp Start 50% 60.0 min", - "NSCLIENT_ID": 1495477797863, - "mills": 1495477797000, - "mgdl": 194.5, - "endmills": 1495481397000 - } - */ - - public TemporaryBasal findTempBasalByPumpId(Long pumpId) { - try { - QueryBuilder queryBuilder = null; - queryBuilder = getDaoTemporaryBasal().queryBuilder(); - queryBuilder.orderBy("date", false); - Where where = queryBuilder.where(); - where.eq("pumpId", pumpId); - PreparedQuery preparedQuery = queryBuilder.prepare(); - List list = getDaoTemporaryBasal().query(preparedQuery); - - if (list.size() > 0) - return list.get(0); - else - return null; - - } catch (SQLException e) { - aapsLogger.error("Unhandled exception", e); - } - return null; - } - - - // ------------ ExtendedBolus handling --------------- - - public ExtendedBolus getExtendedBolusByPumpId(long pumpId) { - try { - return getDaoExtendedBolus().queryBuilder() - .where().eq("pumpId", pumpId) - .queryForFirst(); - } catch (SQLException e) { - aapsLogger.error("Unhandled exception", e); - } - return null; - } - - public void delete(ExtendedBolus extendedBolus) { - try { - getDaoExtendedBolus().delete(extendedBolus); - openHumansUploader.enqueueExtendedBolus(extendedBolus, true); - updateEarliestDataChange(extendedBolus.date); - } catch (SQLException e) { - aapsLogger.error("Unhandled exception", e); - } -// scheduleExtendedBolusChange(); - } - - /* -{ - "_id": "5924898d577eb0880e355337", - "eventType": "Combo Bolus", - "duration": 120, - "splitNow": 0, - "splitExt": 100, - "enteredinsulin": 1, - "relative": 1, - "created_at": "2017-05-23T19:12:14Z", - "enteredBy": "AndroidAPS", - "NSCLIENT_ID": 1495566734628, - "mills": 1495566734000, - "mgdl": 106 -} - */ - - // ---------------- ProfileSwitch handling --------------- - -/* - public boolean createOrUpdate(ProfileSwitch profileSwitch) { - try { - ProfileSwitch old; - profileSwitch.date = roundDateToSec(profileSwitch.date); - - if (profileSwitch.source == Source.NIGHTSCOUT) { - old = getDaoProfileSwitch().queryForId(profileSwitch.date); - if (old != null) { - if (!old.isEqual(profileSwitch)) { - profileSwitch.source = old.source; - profileSwitch.profileName = old.profileName; // preserver profileName to prevent multiple CPP extension - getDaoProfileSwitch().delete(old); // need to delete/create because date may change too - getDaoProfileSwitch().create(profileSwitch); - aapsLogger.debug(LTag.DATABASE, "PROFILESWITCH: Updating record by date from: " + Source.getString(profileSwitch.source) + " " + old.toString()); - openHumansUploader.enqueueProfileSwitch(profileSwitch); - scheduleProfileSwitchChange(); - return true; - } - return false; - } - // find by NS _id - if (profileSwitch._id != null) { - QueryBuilder queryBuilder = getDaoProfileSwitch().queryBuilder(); - Where where = queryBuilder.where(); - where.eq("_id", profileSwitch._id); - PreparedQuery preparedQuery = queryBuilder.prepare(); - List trList = getDaoProfileSwitch().query(preparedQuery); - if (trList.size() > 0) { - old = trList.get(0); - if (!old.isEqual(profileSwitch)) { - getDaoProfileSwitch().delete(old); // need to delete/create because date may change too - old.copyFrom(profileSwitch); - getDaoProfileSwitch().create(old); - aapsLogger.debug(LTag.DATABASE, "PROFILESWITCH: Updating record by _id from: " + Source.getString(profileSwitch.source) + " " + old.toString()); - openHumansUploader.enqueueProfileSwitch(old); - scheduleProfileSwitchChange(); - return true; - } - } - } - // look for already added percentage from NS - profileSwitch.profileName = PercentageSplitter.INSTANCE.pureName(profileSwitch.profileName); - getDaoProfileSwitch().create(profileSwitch); - aapsLogger.debug(LTag.DATABASE, "PROFILESWITCH: New record from: " + Source.getString(profileSwitch.source) + " " + profileSwitch.toString()); - openHumansUploader.enqueueProfileSwitch(profileSwitch); - scheduleProfileSwitchChange(); - return true; - } - if (profileSwitch.source == Source.USER) { - getDaoProfileSwitch().create(profileSwitch); - aapsLogger.debug(LTag.DATABASE, "PROFILESWITCH: New record from: " + Source.getString(profileSwitch.source) + " " + profileSwitch.toString()); - openHumansUploader.enqueueProfileSwitch(profileSwitch); - scheduleProfileSwitchChange(); - return true; - } - } catch (SQLException e) { - aapsLogger.error("Unhandled exception", e); - } - return false; - } - - public void delete(ProfileSwitch profileSwitch) { - try { - getDaoProfileSwitch().delete(profileSwitch); - openHumansUploader.enqueueProfileSwitch(profileSwitch, true); - scheduleProfileSwitchChange(); - } catch (SQLException e) { - aapsLogger.error("Unhandled exception", e); - } - } - - private void scheduleProfileSwitchChange() { - class PostRunnable implements Runnable { - public void run() { - aapsLogger.debug(LTag.DATABASE, "Firing EventProfileNeedsUpdate"); - rxBus.send(new EventReloadProfileSwitchData()); - rxBus.send(new EventProfileNeedsUpdate()); - scheduledProfileSwitchEventPost = null; - } - } - // prepare task for execution in 1 sec - // cancel waiting task to prevent sending multiple posts - if (scheduledProfileSwitchEventPost != null) - scheduledProfileSwitchEventPost.cancel(false); - Runnable task = new PostRunnable(); - final int sec = 1; - scheduledProfileSwitchEventPost = profileSwitchEventWorker.schedule(task, sec, TimeUnit.SECONDS); - - } -*/ - /* -{ - "_id":"592fa43ed97496a80da913d2", - "created_at":"2017-06-01T05:20:06Z", - "eventType":"Profile Switch", - "profile":"2016 +30%", - "units":"mmol", - "enteredBy":"sony", - "NSCLIENT_ID":1496294454309, -} - */ -/* - - public void createProfileSwitchFromJsonIfNotExists(JSONObject trJson) { - try { - ProfileSwitch profileSwitch = new ProfileSwitch(StaticInjector.Companion.getInstance()); - profileSwitch.date = trJson.getLong("mills"); - if (trJson.has("duration")) - profileSwitch.durationInMinutes = trJson.getInt("duration"); - profileSwitch._id = trJson.getString("_id"); - profileSwitch.profileName = trJson.getString("profile"); - profileSwitch.isCPP = trJson.has("CircadianPercentageProfile"); - profileSwitch.source = Source.NIGHTSCOUT; - if (trJson.has("timeshift")) - profileSwitch.timeshift = trJson.getInt("timeshift"); - if (trJson.has("percentage")) - profileSwitch.percentage = trJson.getInt("percentage"); - if (trJson.has("profileJson")) - profileSwitch.profileJson = trJson.getString("profileJson"); - else { - ProfileSource profileSource = activePlugin.getActiveProfileSource(); - ProfileStore store = profileSource.getProfile(); - if (store != null) { - PureProfile profile = store.getSpecificProfile(profileSwitch.profileName); - if (profile != null) { - profileSwitch.profileJson = profile.getJsonObject().toString(); - aapsLogger.debug(LTag.DATABASE, "Profile switch prefilled with JSON from local store"); - // Update data in NS - nsUpload.updateProfileSwitch(profileSwitch, dateUtil); - } else { - aapsLogger.debug(LTag.DATABASE, "JSON for profile switch doesn't exist. Ignoring: " + trJson.toString()); - return; - } - } else { - aapsLogger.debug(LTag.DATABASE, "Store for profile switch doesn't exist. Ignoring: " + trJson.toString()); - return; - } - } - if (trJson.has("profilePlugin")) - profileSwitch.profilePlugin = trJson.getString("profilePlugin"); - createOrUpdate(profileSwitch); - } catch (JSONException e) { - aapsLogger.error("Unhandled exception: " + trJson.toString(), e); - } - } - - public void deleteProfileSwitchById(String _id) { - ProfileSwitch stored = findProfileSwitchById(_id); - if (stored != null) { - aapsLogger.debug(LTag.DATABASE, "PROFILESWITCH: Removing ProfileSwitch record from database: " + stored.toString()); - delete(stored); - scheduleProfileSwitchChange(); - } - } - - public ProfileSwitch findProfileSwitchById(String _id) { - try { - QueryBuilder queryBuilder = getDaoProfileSwitch().queryBuilder(); - Where where = queryBuilder.where(); - where.eq("_id", _id); - PreparedQuery preparedQuery = queryBuilder.prepare(); - List list = getDaoProfileSwitch().query(preparedQuery); - - if (list.size() == 1) { - return list.get(0); - } else { - return null; - } - } catch (SQLException e) { - aapsLogger.error("Unhandled exception", e); - } - return null; - } -*/ // ---------------- Insight history handling --------------- public void createOrUpdate(InsightHistoryOffset offset) { @@ -924,14 +468,4 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { } return 0L; } - - public long getCountOfAllRows() { - try { - return getDaoExtendedBolus().countOf() - + getDaoTemporaryBasal().countOf(); - } catch (SQLException e) { - aapsLogger.error("Unhandled exception", e); - } - return 0L; - } } diff --git a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelperProvider.java b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelperProvider.java index 4c3816c934..68ec8ca62b 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelperProvider.java +++ b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelperProvider.java @@ -5,8 +5,6 @@ import androidx.annotation.Nullable; import com.j256.ormlite.dao.CloseableIterator; -import org.json.JSONObject; - import java.sql.SQLException; import java.util.List; @@ -23,18 +21,10 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface { @Inject DatabaseHelperProvider() { } - @Override public void createOrUpdate(@NonNull DanaRHistoryRecord record) { - MainApp.Companion.getDbHelper().createOrUpdate(record); - } - @Override public void createOrUpdate(@NonNull OmnipodHistoryRecord record) { MainApp.Companion.getDbHelper().createOrUpdate(record); } - @NonNull @Override public List getDanaRHistoryRecordsByType(byte type) { - return MainApp.Companion.getDbHelper().getDanaRHistoryRecordsByType(type); - } - @Override public long size(@NonNull String table) { return MainApp.Companion.getDbHelper().size(table); } @@ -68,16 +58,19 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface { } @Override public boolean createOrUpdate(@NonNull TemporaryBasal tempBasal) { - return MainApp.Companion.getDbHelper().createOrUpdate(tempBasal); +// return MainApp.Companion.getDbHelper().createOrUpdate(tempBasal); + return false; } @Nullable @Override public TemporaryBasal findTempBasalByPumpId(long id) { - return MainApp.Companion.getDbHelper().findTempBasalByPumpId(id); +// return MainApp.Companion.getDbHelper().findTempBasalByPumpId(id); + return null; } @Deprecated @NonNull @Override public List getTemporaryBasalsDataFromTime(long mills, boolean ascending) { - return MainApp.Companion.getDbHelper().getTemporaryBasalsDataFromTime(mills, ascending); +// return MainApp.Companion.getDbHelper().getTemporaryBasalsDataFromTime(mills, ascending); + return null; } @NonNull @Override public List getAllOmnipodHistoryRecordsFromTimestamp(long timestamp, boolean ascending) { @@ -101,11 +94,12 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface { } @Override public void delete(@NonNull ExtendedBolus extendedBolus) { - MainApp.Companion.getDbHelper().delete(extendedBolus); +// MainApp.Companion.getDbHelper().delete(extendedBolus); } @Nullable @Override public ExtendedBolus getExtendedBolusByPumpId(long pumpId) { - return MainApp.Companion.getDbHelper().getExtendedBolusByPumpId(pumpId); +// return MainApp.Companion.getDbHelper().getExtendedBolusByPumpId(pumpId); + return null; } @Nullable @Override public InsightBolusID getInsightBolusID(@NonNull String pumpSerial, int bolusID, long timestamp) { @@ -140,10 +134,6 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface { MainApp.Companion.getDbHelper().clearOpenHumansQueue(); } - @Override public long getCountOfAllRows() { - return MainApp.Companion.getDbHelper().getCountOfAllRows(); - } - @Override public void removeAllOHQueueItemsWithIdSmallerThan(long id) { MainApp.Companion.getDbHelper().removeAllOHQueueItemsWithIdSmallerThan(id); } diff --git a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppComponent.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppComponent.kt index b7881ca7f4..05b5974bb5 100644 --- a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppComponent.kt +++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppComponent.kt @@ -7,6 +7,7 @@ import dagger.android.AndroidInjector import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.automation.di.AutomationModule import info.nightscout.androidaps.combo.di.ComboModule +import info.nightscout.androidaps.dana.di.DanaHistoryModule import info.nightscout.androidaps.di.CoreModule import info.nightscout.androidaps.dana.di.DanaModule import info.nightscout.androidaps.danar.di.DanaRModule @@ -45,6 +46,7 @@ import javax.inject.Singleton UIModule::class, CoreModule::class, DanaModule::class, + DanaHistoryModule::class, DanaRModule::class, DanaRSModule::class, ComboModule::class, diff --git a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppModule.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppModule.kt index 740426792c..ed55beb8e7 100644 --- a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppModule.kt +++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppModule.kt @@ -6,7 +6,6 @@ import dagger.Lazy import dagger.Module import dagger.Provides import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.db.DatabaseHelperProvider import info.nightscout.androidaps.interfaces.* @@ -32,6 +31,7 @@ import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.storage.FileStorage import info.nightscout.androidaps.utils.storage.Storage import javax.inject.Singleton + @Suppress("unused") @Module(includes = [ AppModule.AppBindings::class @@ -70,7 +70,7 @@ open class AppModule { context: Context, sp: SP, rxBus: RxBusWrapper - ): UploadQueueAdminInterface = UploadQueue(aapsLogger, databaseHelper, context, sp, rxBus) + ): UploadQueueInterface = UploadQueue(aapsLogger, databaseHelper, context, sp, rxBus) @Module interface AppBindings { @@ -88,7 +88,6 @@ open class AppModule { @Binds fun bindLoopInterface(loopPlugin: LoopPlugin): LoopInterface @Binds fun bindIobCobCalculatorInterface(iobCobCalculatorPlugin: IobCobCalculatorPlugin): IobCobCalculator @Binds fun bindSmsCommunicatorInterface(smsCommunicatorPlugin: SmsCommunicatorPlugin): SmsCommunicator - @Binds fun bindUploadQueueAdminInterfaceToUploadQueue(uploadQueueAdminInterface: UploadQueueAdminInterface) : UploadQueueInterface @Binds fun bindDataSyncSelector(dataSyncSelectorImplementation: DataSyncSelectorImplementation): DataSyncSelector @Binds fun bindPumpSync(pumpSyncImplementation: PumpSyncImplementation): PumpSync diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/MaintenanceFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/MaintenanceFragment.kt index 4337808106..8ff8dac818 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/MaintenanceFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/MaintenanceFragment.kt @@ -7,13 +7,13 @@ import android.view.View import android.view.ViewGroup import dagger.android.support.DaggerFragment import info.nightscout.androidaps.R +import info.nightscout.androidaps.dana.database.DanaHistoryDatabase import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.entities.UserEntry.Action import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.databinding.MaintenanceFragmentBinding import info.nightscout.androidaps.events.EventNewBG import info.nightscout.androidaps.interfaces.DataSyncSelector -import info.nightscout.androidaps.interfaces.DatabaseHelperInterface import info.nightscout.androidaps.interfaces.ImportExportPrefs import info.nightscout.androidaps.interfaces.PumpSync import info.nightscout.androidaps.logging.AAPSLogger @@ -38,7 +38,7 @@ class MaintenanceFragment : DaggerFragment() { @Inject lateinit var importExportPrefs: ImportExportPrefs @Inject lateinit var aapsSchedulers: AapsSchedulers @Inject lateinit var repository: AppRepository - @Inject lateinit var databaseHelper: DatabaseHelperInterface + @Inject lateinit var danaHistoryDatabase: DanaHistoryDatabase @Inject lateinit var uel: UserEntryLogger @Inject lateinit var dataSyncSelector: DataSyncSelector @Inject lateinit var pumpSync: PumpSync @@ -68,8 +68,8 @@ class MaintenanceFragment : DaggerFragment() { OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.maintenance), resourceHelper.gs(R.string.reset_db_confirm), Runnable { compositeDisposable.add( fromAction { - databaseHelper.resetDatabases() repository.clearDatabases() + danaHistoryDatabase.clearAllTables() dataSyncSelector.resetToNextFullSync() pumpSync.connectNewPump() } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientFragment.kt index d2e77a4f95..80b508766d 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientFragment.kt @@ -12,14 +12,11 @@ import info.nightscout.androidaps.database.entities.UserEntry.Action import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.databinding.NsClientFragmentBinding import info.nightscout.androidaps.interfaces.DataSyncSelector -import info.nightscout.androidaps.interfaces.UploadQueueAdminInterface import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.bus.RxBusWrapper -import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientUpdateGUI import info.nightscout.androidaps.utils.FabricPrivacy -import info.nightscout.androidaps.utils.HtmlHelper.fromHtml import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers @@ -33,7 +30,6 @@ class NSClientFragment : DaggerFragment() { @Inject lateinit var sp: SP @Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var rxBus: RxBusWrapper - @Inject lateinit var uploadQueue: UploadQueueAdminInterface @Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var aapsSchedulers: AapsSchedulers @Inject lateinit var dataSyncSelector: DataSyncSelector @@ -72,18 +68,6 @@ class NSClientFragment : DaggerFragment() { binding.restart.paintFlags = binding.restart.paintFlags or Paint.UNDERLINE_TEXT_FLAG binding.deliverNow.setOnClickListener { nsClientPlugin.resend("GUI") } binding.deliverNow.paintFlags = binding.deliverNow.paintFlags or Paint.UNDERLINE_TEXT_FLAG - binding.clearQueue.setOnClickListener { - context?.let { context -> - OKDialog.showConfirmation(context, resourceHelper.gs(R.string.nsclientinternal), resourceHelper.gs(R.string.clearqueueconfirm), Runnable { - uel.log(Action.NS_QUEUE_CLEARED, Sources.NSClient) - uploadQueue.clearQueue() - updateGui() - }) - } - } - binding.clearQueue.paintFlags = binding.clearQueue.paintFlags or Paint.UNDERLINE_TEXT_FLAG - binding.showQueue.setOnClickListener { rxBus.send(EventNSClientNewLog("QUEUE", uploadQueue.textList())) } - binding.showQueue.paintFlags = binding.showQueue.paintFlags or Paint.UNDERLINE_TEXT_FLAG binding.fullSync.setOnClickListener { context?.let { context -> OKDialog.showConfirmation(context, resourceHelper.gs(R.string.nsclientinternal), resourceHelper.gs(R.string.full_sync), Runnable { @@ -116,7 +100,6 @@ class NSClientFragment : DaggerFragment() { binding.log.text = nsClientPlugin.textLog if (nsClientPlugin.autoscroll) binding.logScrollview.fullScroll(ScrollView.FOCUS_DOWN) binding.url.text = nsClientPlugin.url() - binding.queue.text = fromHtml(resourceHelper.gs(R.string.queue) + " " + uploadQueue.size() + "") binding.status.text = nsClientPlugin.status } } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/UploadQueue.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/UploadQueue.java index f7669b182d..d217c1bd15 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/UploadQueue.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/UploadQueue.java @@ -4,18 +4,10 @@ import android.content.Context; import android.content.Intent; import android.os.SystemClock; -import com.j256.ormlite.dao.CloseableIterator; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.sql.SQLException; - import info.nightscout.androidaps.R; import info.nightscout.androidaps.db.DatabaseHelper; import info.nightscout.androidaps.db.DbRequest; import info.nightscout.androidaps.interfaces.DatabaseHelperInterface; -import info.nightscout.androidaps.interfaces.UploadQueueAdminInterface; import info.nightscout.androidaps.interfaces.UploadQueueInterface; import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.LTag; @@ -27,7 +19,7 @@ import info.nightscout.androidaps.utils.sharedPreferences.SP; /** * Created by mike on 21.02.2016. */ -public class UploadQueue implements UploadQueueAdminInterface { +public class UploadQueue implements UploadQueueInterface { private final AAPSLogger aapsLogger; private final DatabaseHelperInterface databaseHelper; private final Context context; @@ -75,50 +67,4 @@ public class UploadQueue implements UploadQueueAdminInterface { rxBus.send(new EventNSClientResend("newdata")); } - @Override public void clearQueue() { - startService(); - if (NSClientService.handler != null) { - NSClientService.handler.post(() -> { - aapsLogger.debug(LTag.NSCLIENT, "ClearQueue"); - databaseHelper.deleteAllDbRequests(); - aapsLogger.debug(LTag.NSCLIENT, status()); - }); - } - } - - @Override - public void removeByMongoId(final String action, final String _id) { - if (_id == null || _id.equals("")) - return; - startService(); - if (NSClientService.handler != null) { - NSClientService.handler.post(() -> { - databaseHelper.deleteDbRequestbyMongoId(action, _id); - aapsLogger.debug(LTag.NSCLIENT, "Removing " + _id + " from UploadQueue. " + status()); - }); - } - } - - @Override public String textList() { - String result = ""; - CloseableIterator iterator; - try { - iterator = databaseHelper.getDbRequestIterator(); - try { - while (iterator.hasNext()) { - DbRequest dbr = iterator.next(); - result += "
"; - result += dbr.action.toUpperCase() + " "; - result += dbr.collection + ": "; - result += dbr.data; - } - } finally { - iterator.close(); - } - } catch (SQLException e) { - aapsLogger.error("Unhandled exception", e); - } - return result; - } - } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/openhumans/OpenHumansUploader.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/openhumans/OpenHumansUploader.kt index cf4f0c62fa..a331fcd88d 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/openhumans/OpenHumansUploader.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/openhumans/OpenHumansUploader.kt @@ -178,24 +178,24 @@ class OpenHumansUploader @Inject constructor( } } - @JvmOverloads - fun enqueueTreatment(treatment: Treatment?, deleted: Boolean = false) = treatment?.let { - insertQueueItem("Treatments") { - put("date", treatment.date) - put("isValid", treatment.isValid) - put("source", treatment.source) - put("nsId", treatment._id) - put("boluscalc", treatment.boluscalc) - put("carbs", treatment.carbs) - put("dia", treatment.dia) - put("insulin", treatment.insulin) - put("insulinInterfaceID", treatment.insulinInterfaceID) - put("isSMB", treatment.isSMB) - put("mealBolus", treatment.mealBolus) - put("bolusCalcJson", treatment.getBoluscalc()) - put("isDeletion", deleted) - } - } + // @JvmOverloads + // fun enqueueTreatment(treatment: Treatment?, deleted: Boolean = false) = treatment?.let { + // insertQueueItem("Treatments") { + // put("date", treatment.date) + // put("isValid", treatment.isValid) + // put("source", treatment.source) + // put("nsId", treatment._id) + // put("boluscalc", treatment.boluscalc) + // put("carbs", treatment.carbs) + // put("dia", treatment.dia) + // put("insulin", treatment.insulin) + // put("insulinInterfaceID", treatment.insulinInterfaceID) + // put("isSMB", treatment.isSMB) + // put("mealBolus", treatment.mealBolus) + // put("bolusCalcJson", treatment.getBoluscalc()) + // put("isDeletion", deleted) + // } + // } @JvmOverloads fun enqueueTherapyEvent(therapyEvent: TherapyEvent, deleted: Boolean = false) = insertQueueItem("TherapyEvents") { @@ -210,17 +210,17 @@ class OpenHumansUploader @Inject constructor( put("isDeletion", deleted) } - @JvmOverloads - fun enqueueExtendedBolus(extendedBolus: ExtendedBolus, deleted: Boolean = false) = insertQueueItem("ExtendedBoluses") { - put("date", extendedBolus.date) - put("isValid", extendedBolus.isValid) - put("source", extendedBolus.source) - put("nsId", extendedBolus._id) - put("pumpId", extendedBolus.pumpId) - put("insulin", extendedBolus.insulin) - put("durationInMinutes", extendedBolus.durationInMinutes) - put("isDeletion", deleted) - } + // @JvmOverloads + // fun enqueueExtendedBolus(extendedBolus: ExtendedBolus, deleted: Boolean = false) = insertQueueItem("ExtendedBoluses") { + // put("date", extendedBolus.date) + // put("isValid", extendedBolus.isValid) + // put("source", extendedBolus.source) + // put("nsId", extendedBolus._id) + // put("pumpId", extendedBolus.pumpId) + // put("insulin", extendedBolus.insulin) + // put("durationInMinutes", extendedBolus.durationInMinutes) + // put("isDeletion", deleted) + // } // @JvmOverloads // fun enqueueProfileSwitch(profileSwitch: ProfileSwitch, deleted: Boolean = false) = insertQueueItem("ProfileSwitches") { @@ -244,22 +244,22 @@ class OpenHumansUploader @Inject constructor( // put("double", tdd.total) // } - @JvmOverloads - fun enqueueTemporaryBasal(temporaryBasal: TemporaryBasal?, deleted: Boolean = false) = temporaryBasal?.let { - insertQueueItem("TemporaryBasals") { - put("date", temporaryBasal.date) - put("isValid", temporaryBasal.isValid) - put("source", temporaryBasal.source) - put("nsId", temporaryBasal._id) - put("pumpId", temporaryBasal.pumpId) - put("durationInMinutes", temporaryBasal.durationInMinutes) - put("durationInMinutes", temporaryBasal.durationInMinutes) - put("isAbsolute", temporaryBasal.isAbsolute) - put("percentRate", temporaryBasal.percentRate) - put("absoluteRate", temporaryBasal.absoluteRate) - put("isDeletion", deleted) - } - } + // @JvmOverloads + // fun enqueueTemporaryBasal(temporaryBasal: TemporaryBasal?, deleted: Boolean = false) = temporaryBasal?.let { + // insertQueueItem("TemporaryBasals") { + // put("date", temporaryBasal.date) + // put("isValid", temporaryBasal.isValid) + // put("source", temporaryBasal.source) + // put("nsId", temporaryBasal._id) + // put("pumpId", temporaryBasal.pumpId) + // put("durationInMinutes", temporaryBasal.durationInMinutes) + // put("durationInMinutes", temporaryBasal.durationInMinutes) + // put("isAbsolute", temporaryBasal.isAbsolute) + // put("percentRate", temporaryBasal.percentRate) + // put("absoluteRate", temporaryBasal.absoluteRate) + // put("isDeletion", deleted) + // } + // } @JvmOverloads fun enqueueTempTarget(tempTarget: TemporaryTarget?, deleted: Boolean = false) = tempTarget?.let { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.kt index a4da17f159..4d17a119be 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.kt @@ -400,9 +400,8 @@ class GraphData( time += 5 * 60 * 1000L continue } - var iob = 0.0 var absIob = 0.0 - iob = iobCobCalculator.calculateFromTreatmentsAndTemps(time, profile).iob + val iob: Double = iobCobCalculator.calculateFromTreatmentsAndTemps(time, profile).iob if (absScale) absIob = iobCobCalculator.calculateAbsInsulinFromTreatmentsAndTemps(time).iob if (abs(lastIob - iob) > 0.02) { if (abs(lastIob - iob) > 0.2) iobArray.add(ScaledDataPoint(time, lastIob, iobScale)) @@ -461,8 +460,7 @@ class GraphData( time += 5 * 60 * 1000L continue } - var iob = 0.0 - iob = iobCobCalculator.calculateAbsInsulinFromTreatmentsAndTemps(time).iob + val iob: Double = iobCobCalculator.calculateAbsInsulinFromTreatmentsAndTemps(time).iob if (abs(lastIob - iob) > 0.02) { if (abs(lastIob - iob) > 0.2) iobArray.add(ScaledDataPoint(time, lastIob, iobScale)) iobArray.add(ScaledDataPoint(time, iob, iobScale)) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentService.java b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentService.java index 3619e209f6..a8293002f8 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentService.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentService.java @@ -105,25 +105,10 @@ public class TreatmentService extends OrmLiteBaseService impleme return wrapped.queryForAll(); } - public void delete(Treatment data) throws SQLException { - wrapped.delete(data); - openHumansUploader.enqueueTreatment(data, true); - } - - public void create(Treatment data) throws SQLException { - wrapped.create(data); - openHumansUploader.enqueueTreatment(data); - } - public Treatment queryForId(long id) throws SQLException { return wrapped.queryForId(id); } - public void update(Treatment data) throws SQLException { - wrapped.update(data); - openHumansUploader.enqueueTreatment(data); - } - public QueryBuilder queryBuilder() { return wrapped.queryBuilder(); } diff --git a/app/src/main/res/layout/ns_client_fragment.xml b/app/src/main/res/layout/ns_client_fragment.xml index a4b625d2a7..e10791bb52 100644 --- a/app/src/main/res/layout/ns_client_fragment.xml +++ b/app/src/main/res/layout/ns_client_fragment.xml @@ -75,15 +75,6 @@ android:layout_height="wrap_content" android:textStyle="normal|bold" /> - -
- - - - >> 4]; - hexChars[j * 2 + 1] = hexArray[v & 0x0F]; - } - return new String(hexChars); - } -} - diff --git a/core/src/main/java/info/nightscout/androidaps/di/CoreDataClassesModule.kt b/core/src/main/java/info/nightscout/androidaps/di/CoreDataClassesModule.kt index dcf5e99967..0c37e3e32c 100644 --- a/core/src/main/java/info/nightscout/androidaps/di/CoreDataClassesModule.kt +++ b/core/src/main/java/info/nightscout/androidaps/di/CoreDataClassesModule.kt @@ -4,9 +4,6 @@ import dagger.Module import dagger.android.ContributesAndroidInjector import info.nightscout.androidaps.data.ProfileImplOld import info.nightscout.androidaps.data.PumpEnactResult -import info.nightscout.androidaps.db.ExtendedBolus -import info.nightscout.androidaps.db.TemporaryBasal -import info.nightscout.androidaps.db.Treatment import info.nightscout.androidaps.interfaces.ProfileStore import info.nightscout.androidaps.plugins.aps.loop.APSResult import info.nightscout.androidaps.plugins.general.nsclient.data.NSMbg @@ -24,7 +21,4 @@ abstract class CoreDataClassesModule { @ContributesAndroidInjector abstract fun profileInjector(): ProfileImplOld @ContributesAndroidInjector abstract fun profileStoreInjector(): ProfileStore - @ContributesAndroidInjector abstract fun treatmentInjector(): Treatment - @ContributesAndroidInjector abstract fun temporaryBasalInjector(): TemporaryBasal - @ContributesAndroidInjector abstract fun extendedBolusInjector(): ExtendedBolus } diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/DatabaseHelperInterface.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/DatabaseHelperInterface.kt index e4a5582d49..9a11451fc2 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/DatabaseHelperInterface.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/DatabaseHelperInterface.kt @@ -8,14 +8,12 @@ interface DatabaseHelperInterface { fun resetDatabases() - fun createOrUpdate(record: DanaRHistoryRecord) fun createOrUpdate(record: OmnipodHistoryRecord) fun createOrUpdate(record: InsightBolusID) fun createOrUpdate(record: InsightPumpID) fun createOrUpdate(record: InsightHistoryOffset) fun createOrUpdate(record: OHQueueItem) fun create(record: DbRequest) - fun getDanaRHistoryRecordsByType(type: Byte): List fun size(table: String): Long fun deleteAllDbRequests() fun deleteDbRequest(id: String): Int @@ -41,7 +39,6 @@ interface DatabaseHelperInterface { fun getOHQueueSize(): Long fun clearOpenHumansQueue() - fun getCountOfAllRows(): Long fun removeAllOHQueueItemsWithIdSmallerThan(id: Long) companion object { diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/IobCobCalculator.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/IobCobCalculator.kt index 7f505674eb..0dbe420b24 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/IobCobCalculator.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/IobCobCalculator.kt @@ -20,7 +20,7 @@ interface IobCobCalculator { fun getLastAutosensDataWithWaitForCalculationFinish(reason: String): AutosensData? fun calculateAbsInsulinFromTreatmentsAndTemps(fromTime: Long): IobTotal - fun calculateFromTreatmentsAndTemps(time: Long, profile: Profile): IobTotal + fun calculateFromTreatmentsAndTemps(fromTime: Long, profile: Profile): IobTotal fun getBasalData(profile: Profile, fromTime: Long): BasalData diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/ProfileStore.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/ProfileStore.kt index 13d8c008ff..64dc9099a8 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/ProfileStore.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/ProfileStore.kt @@ -2,7 +2,6 @@ package info.nightscout.androidaps.interfaces import androidx.collection.ArrayMap import dagger.android.HasAndroidInjector -import info.nightscout.androidaps.data.ProfileImplOld import info.nightscout.androidaps.data.PureProfile import info.nightscout.androidaps.extensions.pureProfileFromJson import info.nightscout.androidaps.logging.AAPSLogger @@ -67,8 +66,7 @@ class ProfileStore(val injector: HasAndroidInjector, val data: JSONObject, val d return profile } - fun getSpecificProfileJson(profileName: String): JSONObject? { - var profile: PureProfile? = null + private fun getSpecificProfileJson(profileName: String): JSONObject? { getStore()?.let { store -> if (store.has(profileName)) return JsonHelper.safeGetJSONObject(store, profileName, null) diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/UploadQueueAdminInterface.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/UploadQueueAdminInterface.kt deleted file mode 100644 index e749854c0a..0000000000 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/UploadQueueAdminInterface.kt +++ /dev/null @@ -1,6 +0,0 @@ -package info.nightscout.androidaps.interfaces - -interface UploadQueueAdminInterface : UploadQueueInterface { - - fun clearQueue() -} \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/UploadQueueInterface.java b/core/src/main/java/info/nightscout/androidaps/interfaces/UploadQueueInterface.java index 65e02dcdb8..903bffd4c2 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/UploadQueueInterface.java +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/UploadQueueInterface.java @@ -9,8 +9,4 @@ public interface UploadQueueInterface { long size(); void add(DbRequest dbRequest); - - void removeByMongoId(final String action, final String _id); - - String textList(); } diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSUpload.java b/core/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSUpload.java index c65ca85828..f143ad92b0 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSUpload.java +++ b/core/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSUpload.java @@ -31,62 +31,10 @@ public class NSUpload { this.sp = sp; this.uploadQueue = uploadQueue; } -/* - public void uploadProfileSwitch(ProfileSwitch profileSwitch, long nsClientId, DateUtil dateUtil) { - try { - JSONObject data = getJson(profileSwitch, dateUtil); - DbRequest dbr = new DbRequest("dbAdd", "treatments", data, nsClientId); - aapsLogger.debug("Prepared: " + dbr.log()); - uploadQueue.add(dbr); - } catch (JSONException e) { - aapsLogger.error("Unhandled exception", e); - } - } - - public void updateProfileSwitch(ProfileSwitch profileSwitch, DateUtil dateUtil) { - try { - JSONObject data = getJson(profileSwitch, dateUtil); - if (profileSwitch._id != null) { - uploadQueue.add(new DbRequest("dbUpdate", "treatments", profileSwitch._id, data, profileSwitch.date)); - } - } catch (JSONException e) { - aapsLogger.error("Unhandled exception", e); - } - } - - private static JSONObject getJson(ProfileSwitch profileSwitch, DateUtil dateUtil) throws JSONException { - JSONObject data = new JSONObject(); - data.put("eventType", TherapyEvent.Type.PROFILE_SWITCH.getText()); - data.put("duration", profileSwitch.durationInMinutes); - data.put("profile", profileSwitch.getCustomizedName()); - data.put("profileJson", profileSwitch.profileJson); - data.put("profilePlugin", profileSwitch.profilePlugin); - if (profileSwitch.isCPP) { - data.put("CircadianPercentageProfile", true); - data.put("timeshift", profileSwitch.timeshift); - data.put("percentage", profileSwitch.percentage); - } - data.put("created_at", dateUtil.toISOString(profileSwitch.date)); - data.put("enteredBy", "AndroidAPS"); - - return data; - } -*/ - // TODO replace with setting isValid = false - public void removeCareportalEntryFromNS(String _id) { - uploadQueue.add(new DbRequest("dbRemove", "treatments", _id, System.currentTimeMillis())); - } public void uploadProfileStore(JSONObject profileStore) { if (sp.getBoolean(R.string.key_ns_uploadlocalprofile, false)) { uploadQueue.add(new DbRequest("dbAdd", "profile", profileStore, System.currentTimeMillis())); } } - - public static boolean isIdValid(String _id) { - if (_id == null) - return false; - return _id.length() == 24; - } - } diff --git a/dana/build.gradle b/dana/build.gradle index 8020051b31..e36ef61f0d 100644 --- a/dana/build.gradle +++ b/dana/build.gradle @@ -17,4 +17,10 @@ android { dependencies { implementation project(':core') + + api "androidx.room:room-ktx:$room_version" + api "androidx.room:room-runtime:$room_version" + api "androidx.room:room-rxjava2:$room_version" + kapt "androidx.room:room-compiler:$room_version" + kapt "android.arch.persistence.room:compiler:$room_version" } \ No newline at end of file diff --git a/dana/src/main/java/info/nightscout/androidaps/dana/activities/DanaHistoryActivity.kt b/dana/src/main/java/info/nightscout/androidaps/dana/activities/DanaHistoryActivity.kt index ae01f4d2d4..0c6111e14e 100644 --- a/dana/src/main/java/info/nightscout/androidaps/dana/activities/DanaHistoryActivity.kt +++ b/dana/src/main/java/info/nightscout/androidaps/dana/activities/DanaHistoryActivity.kt @@ -6,21 +6,21 @@ import android.view.View import android.view.ViewGroup import android.widget.AdapterView import android.widget.ArrayAdapter -import android.widget.TextView import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import info.nightscout.androidaps.Constants import info.nightscout.androidaps.activities.NoSplashAppCompatActivity import info.nightscout.androidaps.dana.R import info.nightscout.androidaps.dana.comm.RecordTypes +import info.nightscout.androidaps.dana.database.DanaHistoryRecord +import info.nightscout.androidaps.dana.database.DanaHistoryRecordDao import info.nightscout.androidaps.dana.databinding.DanarHistoryActivityBinding -import info.nightscout.androidaps.interfaces.Profile -import info.nightscout.androidaps.db.DanaRHistoryRecord +import info.nightscout.androidaps.dana.databinding.DanarHistoryItemBinding import info.nightscout.androidaps.events.EventDanaRSyncStatus import info.nightscout.androidaps.events.EventPumpStatusChanged import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.CommandQueueProvider -import info.nightscout.androidaps.interfaces.DatabaseHelperInterface +import info.nightscout.androidaps.interfaces.Profile import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag @@ -30,6 +30,7 @@ import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DecimalFormatter import info.nightscout.androidaps.utils.FabricPrivacy +import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.rx.AapsSchedulers import io.reactivex.disposables.CompositeDisposable import io.reactivex.rxkotlin.plusAssign @@ -44,14 +45,13 @@ class DanaHistoryActivity : NoSplashAppCompatActivity() { @Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var commandQueue: CommandQueueProvider - @Inject lateinit var databaseHelper: DatabaseHelperInterface + @Inject lateinit var danaHistoryRecordDao: DanaHistoryRecordDao @Inject lateinit var dateUtil: DateUtil @Inject lateinit var aapsSchedulers: AapsSchedulers private val disposable = CompositeDisposable() private var showingType = RecordTypes.RECORD_TYPE_ALARM - private var historyList: List = ArrayList() class TypeList internal constructor(var type: Byte, var name: String) { @@ -73,6 +73,7 @@ class DanaHistoryActivity : NoSplashAppCompatActivity() { aapsLogger.debug(LTag.PUMP, "EventDanaRSyncStatus: " + it.message) binding.status.text = it.message }, fabricPrivacy::logException) + swapAdapter(showingType) } override fun onPause() { @@ -87,7 +88,6 @@ class DanaHistoryActivity : NoSplashAppCompatActivity() { binding.recyclerview.setHasFixedSize(true) binding.recyclerview.layoutManager = LinearLayoutManager(this) - binding.recyclerview.adapter = RecyclerViewAdapter(historyList) binding.status.visibility = View.GONE val pump = activePlugin.activePump @@ -115,14 +115,12 @@ class DanaHistoryActivity : NoSplashAppCompatActivity() { binding.reload.setOnClickListener { val selected = binding.spinner.selectedItem as TypeList? ?: return@setOnClickListener - runOnUiThread { - binding.reload.visibility = View.GONE - binding.status.visibility = View.VISIBLE - } + binding.reload.visibility = View.GONE + binding.status.visibility = View.VISIBLE clearCardView() commandQueue.loadHistory(selected.type, object : Callback() { override fun run() { - loadDataFromDB(selected.type) + swapAdapter(selected.type) runOnUiThread { binding.reload.visibility = View.VISIBLE binding.status.visibility = View.GONE @@ -133,7 +131,7 @@ class DanaHistoryActivity : NoSplashAppCompatActivity() { binding.spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { val selected = typeList[position] - loadDataFromDB(selected.type) + swapAdapter(selected.type) showingType = selected.type } @@ -143,95 +141,95 @@ class DanaHistoryActivity : NoSplashAppCompatActivity() { } } - inner class RecyclerViewAdapter internal constructor(private var historyList: List) : RecyclerView.Adapter() { + inner class RecyclerViewAdapter internal constructor(private var historyList: List) : RecyclerView.Adapter() { override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): HistoryViewHolder = HistoryViewHolder(LayoutInflater.from(viewGroup.context).inflate(R.layout.danar_history_item, viewGroup, false)) override fun onBindViewHolder(holder: HistoryViewHolder, position: Int) { val record = historyList[position] - holder.time.text = dateUtil.dateAndTimeString(record.recordDate) - holder.value.text = DecimalFormatter.to2Decimal(record.recordValue) - holder.stringValue.text = record.stringRecordValue - holder.bolusType.text = record.bolusType - holder.duration.text = DecimalFormatter.to0Decimal(record.recordDuration.toDouble()) - holder.alarm.text = record.recordAlarm + holder.binding.time.text = dateUtil.dateAndTimeString(record.timestamp) + holder.binding.value.text = DecimalFormatter.to2Decimal(record.value) + holder.binding.stringValue.text = record.stringValue + holder.binding.bolusType.text = record.bolusType + holder.binding.duration.text = record.duration.toString() + holder.binding.alarm.text = record.alarm when (showingType) { - RecordTypes.RECORD_TYPE_ALARM -> { - holder.time.visibility = View.VISIBLE - holder.value.visibility = View.VISIBLE - holder.stringValue.visibility = View.GONE - holder.bolusType.visibility = View.GONE - holder.duration.visibility = View.GONE - holder.dailyBasal.visibility = View.GONE - holder.dailyBolus.visibility = View.GONE - holder.dailyTotal.visibility = View.GONE - holder.alarm.visibility = View.VISIBLE + RecordTypes.RECORD_TYPE_ALARM -> { + holder.binding.time.visibility = View.VISIBLE + holder.binding.value.visibility = View.VISIBLE + holder.binding.stringValue.visibility = View.GONE + holder.binding.bolusType.visibility = View.GONE + holder.binding.duration.visibility = View.GONE + holder.binding.dailyBasal.visibility = View.GONE + holder.binding.dailyBolus.visibility = View.GONE + holder.binding.dailyTotal.visibility = View.GONE + holder.binding.alarm.visibility = View.VISIBLE } - RecordTypes.RECORD_TYPE_BOLUS -> { - holder.time.visibility = View.VISIBLE - holder.value.visibility = View.VISIBLE - holder.stringValue.visibility = View.GONE - holder.bolusType.visibility = View.VISIBLE - holder.duration.visibility = View.VISIBLE - holder.dailyBasal.visibility = View.GONE - holder.dailyBolus.visibility = View.GONE - holder.dailyTotal.visibility = View.GONE - holder.alarm.visibility = View.GONE + RecordTypes.RECORD_TYPE_BOLUS -> { + holder.binding.time.visibility = View.VISIBLE + holder.binding.value.visibility = View.VISIBLE + holder.binding.stringValue.visibility = View.GONE + holder.binding.bolusType.visibility = View.VISIBLE + holder.binding.duration.visibility = View.VISIBLE + holder.binding.dailyBasal.visibility = View.GONE + holder.binding.dailyBolus.visibility = View.GONE + holder.binding.dailyTotal.visibility = View.GONE + holder.binding.alarm.visibility = View.GONE } - RecordTypes.RECORD_TYPE_DAILY -> { - holder.dailyBasal.text = resourceHelper.gs(R.string.formatinsulinunits, record.recordDailyBasal) - holder.dailyBolus.text = resourceHelper.gs(R.string.formatinsulinunits, record.recordDailyBolus) - holder.dailyTotal.text = resourceHelper.gs(R.string.formatinsulinunits, record.recordDailyBolus + record.recordDailyBasal) - holder.time.text = dateUtil.dateString(record.recordDate) - holder.time.visibility = View.VISIBLE - holder.value.visibility = View.GONE - holder.stringValue.visibility = View.GONE - holder.bolusType.visibility = View.GONE - holder.duration.visibility = View.GONE - holder.dailyBasal.visibility = View.VISIBLE - holder.dailyBolus.visibility = View.VISIBLE - holder.dailyTotal.visibility = View.VISIBLE - holder.alarm.visibility = View.GONE + RecordTypes.RECORD_TYPE_DAILY -> { + holder.binding.dailyBasal.text = resourceHelper.gs(R.string.formatinsulinunits, record.dailyBasal) + holder.binding.dailyBolus.text = resourceHelper.gs(R.string.formatinsulinunits, record.dailyBolus) + holder.binding.dailyTotal.text = resourceHelper.gs(R.string.formatinsulinunits, record.dailyBolus + record.dailyBasal) + holder.binding.time.text = dateUtil.dateString(record.timestamp) + holder.binding.time.visibility = View.VISIBLE + holder.binding.value.visibility = View.GONE + holder.binding.stringValue.visibility = View.GONE + holder.binding.bolusType.visibility = View.GONE + holder.binding.duration.visibility = View.GONE + holder.binding.dailyBasal.visibility = View.VISIBLE + holder.binding.dailyBolus.visibility = View.VISIBLE + holder.binding.dailyTotal.visibility = View.VISIBLE + holder.binding.alarm.visibility = View.GONE } - RecordTypes.RECORD_TYPE_GLUCOSE -> { - holder.value.text = Profile.toUnitsString(record.recordValue, record.recordValue * Constants.MGDL_TO_MMOLL, profileFunction.getUnits()) - holder.time.visibility = View.VISIBLE - holder.value.visibility = View.VISIBLE - holder.stringValue.visibility = View.GONE - holder.bolusType.visibility = View.GONE - holder.duration.visibility = View.GONE - holder.dailyBasal.visibility = View.GONE - holder.dailyBolus.visibility = View.GONE - holder.dailyTotal.visibility = View.GONE - holder.alarm.visibility = View.GONE + RecordTypes.RECORD_TYPE_GLUCOSE -> { + holder.binding.value.text = Profile.toUnitsString(record.value, record.value * Constants.MGDL_TO_MMOLL, profileFunction.getUnits()) + holder.binding.time.visibility = View.VISIBLE + holder.binding.value.visibility = View.VISIBLE + holder.binding.stringValue.visibility = View.GONE + holder.binding.bolusType.visibility = View.GONE + holder.binding.duration.visibility = View.GONE + holder.binding.dailyBasal.visibility = View.GONE + holder.binding.dailyBolus.visibility = View.GONE + holder.binding.dailyTotal.visibility = View.GONE + holder.binding.alarm.visibility = View.GONE } RecordTypes.RECORD_TYPE_CARBO, RecordTypes.RECORD_TYPE_BASALHOUR, RecordTypes.RECORD_TYPE_ERROR, RecordTypes.RECORD_TYPE_PRIME, RecordTypes.RECORD_TYPE_REFILL, RecordTypes.RECORD_TYPE_TB -> { - holder.time.visibility = View.VISIBLE - holder.value.visibility = View.VISIBLE - holder.stringValue.visibility = View.GONE - holder.bolusType.visibility = View.GONE - holder.duration.visibility = View.GONE - holder.dailyBasal.visibility = View.GONE - holder.dailyBolus.visibility = View.GONE - holder.dailyTotal.visibility = View.GONE - holder.alarm.visibility = View.GONE + holder.binding.time.visibility = View.VISIBLE + holder.binding.value.visibility = View.VISIBLE + holder.binding.stringValue.visibility = View.GONE + holder.binding.bolusType.visibility = View.GONE + holder.binding.duration.visibility = View.GONE + holder.binding.dailyBasal.visibility = View.GONE + holder.binding.dailyBolus.visibility = View.GONE + holder.binding.dailyTotal.visibility = View.GONE + holder.binding.alarm.visibility = View.GONE } - RecordTypes.RECORD_TYPE_SUSPEND -> { - holder.time.visibility = View.VISIBLE - holder.value.visibility = View.GONE - holder.stringValue.visibility = View.VISIBLE - holder.bolusType.visibility = View.GONE - holder.duration.visibility = View.GONE - holder.dailyBasal.visibility = View.GONE - holder.dailyBolus.visibility = View.GONE - holder.dailyTotal.visibility = View.GONE - holder.alarm.visibility = View.GONE + RecordTypes.RECORD_TYPE_SUSPEND -> { + holder.binding.time.visibility = View.VISIBLE + holder.binding.value.visibility = View.GONE + holder.binding.stringValue.visibility = View.VISIBLE + holder.binding.bolusType.visibility = View.GONE + holder.binding.duration.visibility = View.GONE + holder.binding.dailyBasal.visibility = View.GONE + holder.binding.dailyBolus.visibility = View.GONE + holder.binding.dailyTotal.visibility = View.GONE + holder.binding.alarm.visibility = View.GONE } } } @@ -242,25 +240,17 @@ class DanaHistoryActivity : NoSplashAppCompatActivity() { inner class HistoryViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - var time: TextView = itemView.findViewById(R.id.danar_history_time) - var value: TextView = itemView.findViewById(R.id.danar_history_value) - var bolusType: TextView = itemView.findViewById(R.id.danar_history_bolustype) - var stringValue: TextView = itemView.findViewById(R.id.danar_history_stringvalue) - var duration: TextView = itemView.findViewById(R.id.danar_history_duration) - var dailyBasal: TextView = itemView.findViewById(R.id.danar_history_dailybasal) - var dailyBolus: TextView = itemView.findViewById(R.id.danar_history_dailybolus) - var dailyTotal: TextView = itemView.findViewById(R.id.danar_history_dailytotal) - var alarm: TextView = itemView.findViewById(R.id.danar_history_alarm) + val binding = DanarHistoryItemBinding.bind(itemView) } } - private fun loadDataFromDB(type: Byte) { - historyList = databaseHelper.getDanaRHistoryRecordsByType(type) - runOnUiThread { binding.recyclerview.swapAdapter(RecyclerViewAdapter(historyList), false) } + private fun swapAdapter(type: Byte) { + disposable += danaHistoryRecordDao + .allFromByType(dateUtil.now() - T.months(1).msecs(), type) + .subscribeOn(aapsSchedulers.io) + .observeOn(aapsSchedulers.main) + .subscribe { historyList -> binding.recyclerview.swapAdapter(RecyclerViewAdapter(historyList), false) } } - private fun clearCardView() { - historyList = ArrayList() - runOnUiThread { binding.recyclerview.swapAdapter(RecyclerViewAdapter(historyList), false) } - } + private fun clearCardView() = binding.recyclerview.swapAdapter(RecyclerViewAdapter(ArrayList()), false) } \ No newline at end of file diff --git a/dana/src/main/java/info/nightscout/androidaps/dana/database/DanaHistoryDatabase.kt b/dana/src/main/java/info/nightscout/androidaps/dana/database/DanaHistoryDatabase.kt new file mode 100644 index 0000000000..f04779c4ec --- /dev/null +++ b/dana/src/main/java/info/nightscout/androidaps/dana/database/DanaHistoryDatabase.kt @@ -0,0 +1,33 @@ +package info.nightscout.androidaps.dana.database + +import android.content.Context +import androidx.room.Database +import androidx.room.Room +import androidx.room.RoomDatabase +import androidx.room.TypeConverters + +const val TABLE_DANA_HISTORY = "danaHistory" + +@Database( + entities = [DanaHistoryRecord::class], + exportSchema = true, + version = DanaHistoryDatabase.VERSION +) +abstract class DanaHistoryDatabase : RoomDatabase() { + + abstract fun historyRecordDao(): DanaHistoryRecordDao + + companion object { + + const val VERSION = 1 + + fun build(context: Context) = + Room.databaseBuilder( + context.applicationContext, + DanaHistoryDatabase::class.java, + "dana_database.db" + ) + .fallbackToDestructiveMigration() + .build() + } +} diff --git a/dana/src/main/java/info/nightscout/androidaps/dana/database/DanaHistoryRecord.kt b/dana/src/main/java/info/nightscout/androidaps/dana/database/DanaHistoryRecord.kt new file mode 100644 index 0000000000..8aaf3e32f4 --- /dev/null +++ b/dana/src/main/java/info/nightscout/androidaps/dana/database/DanaHistoryRecord.kt @@ -0,0 +1,19 @@ +package info.nightscout.androidaps.dana.database + +import androidx.room.Entity +import androidx.room.Index +import androidx.room.PrimaryKey + +@Entity(tableName = TABLE_DANA_HISTORY, + indices = [Index("code", "timestamp")]) +data class DanaHistoryRecord( + @PrimaryKey var timestamp: Long, + var code: Byte = 0x0F, + var value: Double = 0.0, + var bolusType: String = "None", + var stringValue: String = "", + var duration: Long = 0, + var dailyBasal: Double = 0.0, + var dailyBolus: Double = 0.0, + var alarm: String = "" +) diff --git a/dana/src/main/java/info/nightscout/androidaps/dana/database/DanaHistoryRecordDao.kt b/dana/src/main/java/info/nightscout/androidaps/dana/database/DanaHistoryRecordDao.kt new file mode 100644 index 0000000000..276d73fbac --- /dev/null +++ b/dana/src/main/java/info/nightscout/androidaps/dana/database/DanaHistoryRecordDao.kt @@ -0,0 +1,17 @@ +package info.nightscout.androidaps.dana.database + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import io.reactivex.Single + +@Dao +abstract class DanaHistoryRecordDao { + + @Query("SELECT * from $TABLE_DANA_HISTORY WHERE timestamp >= :timestamp AND code = :type") + abstract fun allFromByType(timestamp: Long, type: Byte): Single> + + @Insert(onConflict = OnConflictStrategy.REPLACE) + abstract fun createOrUpdate(danaHistoryRecord: DanaHistoryRecord) +} diff --git a/dana/src/main/java/info/nightscout/androidaps/dana/di/DanaHistoryModule.kt b/dana/src/main/java/info/nightscout/androidaps/dana/di/DanaHistoryModule.kt new file mode 100644 index 0000000000..1d52df3139 --- /dev/null +++ b/dana/src/main/java/info/nightscout/androidaps/dana/di/DanaHistoryModule.kt @@ -0,0 +1,21 @@ +package info.nightscout.androidaps.dana.di + +import android.content.Context +import dagger.Module +import dagger.Provides +import info.nightscout.androidaps.dana.database.DanaHistoryDatabase +import info.nightscout.androidaps.dana.database.DanaHistoryRecordDao +import javax.inject.Singleton + +@Module +class DanaHistoryModule { + + @Provides + @Singleton + internal fun provideDatabase(context: Context): DanaHistoryDatabase = DanaHistoryDatabase.build(context) + + @Provides + @Singleton + internal fun provideHistoryRecordDao(danaHistoryDatabase: DanaHistoryDatabase): DanaHistoryRecordDao = + danaHistoryDatabase.historyRecordDao() +} diff --git a/dana/src/main/java/info/nightscout/androidaps/dana/di/DanaModule.kt b/dana/src/main/java/info/nightscout/androidaps/dana/di/DanaModule.kt index 224838979b..472feef422 100644 --- a/dana/src/main/java/info/nightscout/androidaps/dana/di/DanaModule.kt +++ b/dana/src/main/java/info/nightscout/androidaps/dana/di/DanaModule.kt @@ -1,10 +1,15 @@ package info.nightscout.androidaps.dana.di +import android.content.Context import dagger.Module +import dagger.Provides import dagger.android.ContributesAndroidInjector import info.nightscout.androidaps.dana.DanaFragment import info.nightscout.androidaps.dana.activities.DanaHistoryActivity import info.nightscout.androidaps.dana.activities.DanaUserOptionsActivity +import info.nightscout.androidaps.dana.database.DanaHistoryDatabase +import info.nightscout.androidaps.dana.database.DanaHistoryRecordDao +import javax.inject.Singleton @Module @Suppress("unused") diff --git a/dana/src/main/res/layout/danar_history_activity.xml b/dana/src/main/res/layout/danar_history_activity.xml index 5839c37dc0..f49c841bb9 100644 --- a/dana/src/main/res/layout/danar_history_activity.xml +++ b/dana/src/main/res/layout/danar_history_activity.xml @@ -1,94 +1,110 @@ - - + android:padding="5dp" + app:layout_constraintBottom_toTopOf="@+id/spinner" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + android:textAppearance="?android:attr/textAppearanceLarge" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintTop_toTopOf="parent" /> - + - + android:layout_marginStart="10dp" + android:layout_marginEnd="20dp" + android:text="@string/eventtype" + android:textAppearance="?android:attr/textAppearanceSmall" + app:layout_constraintBottom_toBottomOf="@+id/spinner" + app:layout_constraintEnd_toStartOf="@+id/spinner" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="@+id/spinner" /> - - - - - - - + android:layout_marginEnd="10dp" + app:layout_constraintBottom_toTopOf="@+id/status" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@+id/textView" + app:layout_constraintTop_toBottomOf="@+id/header" /> + android:layout_marginTop="10dp" + android:layout_marginBottom="5dp" + android:gravity="center_horizontal" + app:layout_constraintBottom_toTopOf="@+id/recyclerview" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/textView" /> + android:layout_width="0dp" + android:layout_height="0dp" + app:layout_constraintBottom_toTopOf="@+id/reload" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/status" />