From 3a2ac68a6f54638a0570d30436317811b30d2334 Mon Sep 17 00:00:00 2001 From: Andrei Vereha Date: Sat, 9 Oct 2021 12:56:43 +0200 Subject: [PATCH] bugfix: bolusPulsesRemaining --- .../comm/message/IncorrectPacketException.kt | 2 +- .../dash/driver/comm/message/MessageIO.kt | 2 +- .../dash/driver/comm/message/MessagePacket.kt | 23 +---- .../pod/response/DefaultStatusResponse.kt | 25 +++--- .../pump/omnipod/dash/util/Constants.kt | 2 +- .../plugins/pump/omnipod/dash/util/Flag.kt | 19 +++++ .../pod/response/DefaultStatusResponseTest.kt | 85 ++++++++++++++++++- 7 files changed, 124 insertions(+), 34 deletions(-) create mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/util/Flag.kt diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/IncorrectPacketException.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/IncorrectPacketException.kt index 049e8fa5d2..a02b9afa8a 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/IncorrectPacketException.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/IncorrectPacketException.kt @@ -4,5 +4,5 @@ import info.nightscout.androidaps.extensions.toHex class IncorrectPacketException( val payload: ByteArray, - val expectedIndex: Byte? = null + private val expectedIndex: Byte? = null ) : Exception("Invalid payload: ${payload.toHex()}. Expected index: $expectedIndex") diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/MessageIO.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/MessageIO.kt index 6e750069bc..5b8d614dde 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/MessageIO.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/MessageIO.kt @@ -29,7 +29,7 @@ class MessageIO( private val dataBleIO: DataBleIO, ) { - val receivedOutOfOrder = LinkedHashMap() + private val receivedOutOfOrder = LinkedHashMap() var maxMessageReadTries = 3 var messageReadTries = 0 diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/MessagePacket.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/MessagePacket.kt index 5506703311..cb6bef176f 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/MessagePacket.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/MessagePacket.kt @@ -2,6 +2,7 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.Id import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.CouldNotParseMessageException +import info.nightscout.androidaps.plugins.pump.omnipod.dash.util.Flag import java.nio.ByteBuffer /*** @@ -80,13 +81,13 @@ data class MessagePacket( if (payload.copyOfRange(0, 2).decodeToString() != MAGIC_PATTERN) { throw CouldNotParseMessageException(payload) } - val f1 = Flag(payload[2].toInt()) + val f1 = Flag(payload[2].toInt() and 0xff) val sas = f1.get(3) != 0 val tfs = f1.get(4) != 0 val version = ((f1.get(0) shl 2) or (f1.get(1) shl 1) or (f1.get(2) shl 0)).toShort() val eqos = (f1.get(7) or (f1.get(6) shl 1) or (f1.get(5) shl 2)).toShort() - val f2 = Flag(payload[3].toInt()) + val f2 = Flag(payload[3].toInt() and 0xff) val ack = f2.get(0) != 0 val priority = f2.get(1) != 0 val lastMessage = f2.get(2) != 0 @@ -125,24 +126,6 @@ data class MessagePacket( } } -private class Flag(var value: Int = 0) { - - fun set(idx: Byte, set: Boolean) { - val mask = 1 shl (7 - idx) - if (!set) - return - value = value or mask - } - - fun get(idx: Byte): Int { - val mask = 1 shl (7 - idx) - if (value and mask == 0) { - return 0 - } - return 1 - } -} - internal fun Byte.toUnsignedInt() = this.toInt() and 0xff private fun ByteArray.assertSizeAtLeast(size: Int) { diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/response/DefaultStatusResponse.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/response/DefaultStatusResponse.kt index 3017a5ed49..e028d7d1e7 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/response/DefaultStatusResponse.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/response/DefaultStatusResponse.kt @@ -5,6 +5,8 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definitio import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodStatus import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.AlertUtil import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.byValue +import info.nightscout.androidaps.plugins.pump.omnipod.dash.util.Flag +import java.nio.ByteBuffer import java.util.* import kotlin.experimental.and @@ -13,18 +15,21 @@ class DefaultStatusResponse( ) : ResponseBase(ResponseType.DEFAULT_STATUS_RESPONSE, encoded) { val messageType: Byte = encoded[0] - val deliveryStatus: DeliveryStatus = byValue((encoded[1].toInt() shr 4 and 0x0f).toByte(), DeliveryStatus.UNKNOWN) - val podStatus: PodStatus = byValue((encoded[1] and 0x0f), PodStatus.UNKNOWN) - val totalPulsesDelivered: Short = - (encoded[2] and 0x0f shl 9 or (encoded[3].toInt() and 0xff shl 1) or (encoded[4].toInt() and 0xff ushr 7)).toShort() - val sequenceNumberOfLastProgrammingCommand: Short = (encoded[4] ushr 3 and 0x0f).toShort() - val bolusPulsesRemaining: Short = ((encoded[4] and 0x07 shl 10 or (encoded[5].toInt() and 0xff) and 2047).toShort()) + private var first4bytes = ByteBuffer.wrap(byteArrayOf(encoded[2], encoded[3], encoded[4], encoded[5])).int + private var last4bytes = ByteBuffer.wrap(byteArrayOf(encoded[6], encoded[7], encoded[8], encoded[9])).int + + val podStatus: PodStatus = byValue((encoded[1] and 0x0f), PodStatus.UNKNOWN) + val deliveryStatus: DeliveryStatus = byValue(( (encoded[1].toInt() and 0xff) shr 4 and 0x0f).toByte(), DeliveryStatus.UNKNOWN) + + val totalPulsesDelivered: Short = (first4bytes ushr 11 ushr 4 and 0x1FFF).toShort() + val sequenceNumberOfLastProgrammingCommand: Short = (first4bytes ushr 11 and 0X0F).toShort() + val bolusPulsesRemaining: Short = (first4bytes and 0X7FF).toShort() + val activeAlerts: EnumSet = - AlertUtil.decodeAlertSet((encoded[6].toInt() and 0xff shl 1 or (encoded[7] ushr 7)).toByte()) - val minutesSinceActivation: Short = - (encoded[7] and 0x7f shl 6 or (encoded[8].toInt() and 0xff ushr 2 and 0x3f)).toShort() - val reservoirPulsesRemaining: Short = (encoded[8] shl 8 or (encoded[9].toInt() and 0xff) and 0x3ff).toShort() + AlertUtil.decodeAlertSet((last4bytes ushr 10 ushr 13 and 0xFF).toByte()) + val minutesSinceActivation: Short = ((last4bytes ushr 10 and 0x1FFF)).toShort() + val reservoirPulsesRemaining: Short = (last4bytes and 0X3FF).toShort() override fun toString(): String { return "DefaultStatusResponse(" + diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/util/Constants.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/util/Constants.kt index acbdffdc6c..18d640012c 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/util/Constants.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/util/Constants.kt @@ -2,6 +2,6 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.util class Constants { companion object { - val PUMP_SERIAL_FOR_FAKE_TBR = "4241" + const val PUMP_SERIAL_FOR_FAKE_TBR = "4241" } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/util/Flag.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/util/Flag.kt new file mode 100644 index 0000000000..b059b10618 --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/util/Flag.kt @@ -0,0 +1,19 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.util + +class Flag(var value: Int = 0) { + + fun set(idx: Byte, set: Boolean) { + val mask = 1 shl (7 - idx) + if (!set) + return + value = value or mask + } + + fun get(idx: Byte): Int { + val mask = 1 shl (7 - idx) + if (value and mask == 0) { + return 0 + } + return 1 + } +} \ No newline at end of file diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/response/DefaultStatusResponseTest.kt b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/response/DefaultStatusResponseTest.kt index 20341a9a67..7d32ae3790 100644 --- a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/response/DefaultStatusResponseTest.kt +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/response/DefaultStatusResponseTest.kt @@ -1,5 +1,6 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.AlertType import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.DeliveryStatus import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodStatus import org.apache.commons.codec.DecoderException @@ -117,7 +118,7 @@ class DefaultStatusResponseTest { Full reservoir pulses remaining: 392 Time since activation: 4283 */ - @Test @Throws(DecoderException::class) fun testValidResponseBolusPulsesRemaining2() { + @Test @Throws(DecoderException::class) fun testValidResponseReservoirPulsesRemaining() { val encoded = Hex.decodeHex("1D990714201F0042ED8801DE") val response = DefaultStatusResponse(encoded) Assert.assertArrayEquals(encoded, response.encoded) @@ -133,4 +134,86 @@ class DefaultStatusResponseTest { Assert.assertEquals(392.toShort(), response.reservoirPulsesRemaining) Assert.assertEquals(3624.toShort(), response.totalPulsesDelivered) } + + /** response (hex) 1d68002601f400002bff0368 + Status response: 29 + Pod status: RUNNING_BELOW_MIN_VOLUME + Basal active: true + Temp Basal active: false + Immediate bolus active: false + Extended bolus active: true + Bolus pulses remaining: 31 + sequence number of last programing command: 4 + Total full pulses delivered: 3624 + Full reservoir pulses remaining: 392 + Time since activation: 4283 + */ + @Test @Throws(DecoderException::class) fun testValidResponseBolusPulsesRemaining3() { + val encoded = Hex.decodeHex("1d68002601f400002bff0368") + val response = DefaultStatusResponse(encoded) + Assert.assertArrayEquals(encoded, response.encoded) + Assert.assertNotSame(encoded, response.encoded) + Assert.assertEquals(500.toShort(), response.bolusPulsesRemaining) + Assert.assertEquals(0, response.activeAlerts.size) + } + /** response (hex) 1d28002e91e400002fff8256 + Status response: 29 + Pod status: RUNNING_BELOW_MIN_VOLUME + Basal active: true + Temp Basal active: false + Immediate bolus active: false + Extended bolus active: true + Bolus pulses remaining: 31 + sequence number of last programing command: 4 + Total full pulses delivered: 3624 + Full reservoir pulses remaining: 392 + Time since activation: 4283 + */ + @Test @Throws(DecoderException::class) fun testValidResponseBolusPulsesRemaining4() { + val encoded = Hex.decodeHex("1d28002e91e400002fff8256") + val response = DefaultStatusResponse(encoded) + Assert.assertArrayEquals(encoded, response.encoded) + Assert.assertNotSame(encoded, response.encoded) + Assert.assertEquals(484.toShort(), response.bolusPulsesRemaining) + Assert.assertEquals(0, response.activeAlerts.size) + } + + /* + 1D980559C820404393FF83AA + Pod status: RUNNING_ABOVE_MIN_VOLUME + Basal active: true + Temp Basal active: false + Immediate bolus active: false + Extended bolus active: true + Bolus pulses remaining: 32 + sequence number of last programing command: 9 + Total full pulses delivered: 2739 + Full reservoir pulses remaining: 1023 + Time since activation: 4324 + Alert 1 is InActive + Alert 2 is InActive + Alert 3 is InActive + Alert 4 is InActive + Alert 5 is InActive + Alert 6 is InActive + Alert 7 is Active + Occlusion alert active false + */ + @Test @Throws(DecoderException::class) fun testValidResponseActiveAlert1() { + val encoded = Hex.decodeHex("1D980559C820404393FF83AA") + val response = DefaultStatusResponse(encoded) + Assert.assertArrayEquals(encoded, response.encoded) + Assert.assertNotSame(encoded, response.encoded) + Assert.assertEquals(ResponseType.DEFAULT_STATUS_RESPONSE, response.responseType) + Assert.assertEquals(ResponseType.DEFAULT_STATUS_RESPONSE.value, response.messageType) + Assert.assertEquals(DeliveryStatus.UNKNOWN, response.deliveryStatus) + Assert.assertEquals(PodStatus.RUNNING_ABOVE_MIN_VOLUME, response.podStatus) + Assert.assertEquals(9.toShort(), response.sequenceNumberOfLastProgrammingCommand) + Assert.assertEquals(32.toShort(), response.bolusPulsesRemaining) + Assert.assertEquals(1, response.activeAlerts.size) + Assert.assertEquals(4324.toShort(), response.minutesSinceActivation) + Assert.assertEquals(1023.toShort(), response.reservoirPulsesRemaining) + Assert.assertEquals(2739.toShort(), response.totalPulsesDelivered) + Assert.assertEquals(true, response.activeAlerts.contains(AlertType.EXPIRATION)) + } }