bugfix: bolusPulsesRemaining
This commit is contained in:
parent
2b5a1020af
commit
3a2ac68a6f
7 changed files with 124 additions and 34 deletions
|
@ -4,5 +4,5 @@ import info.nightscout.androidaps.extensions.toHex
|
||||||
|
|
||||||
class IncorrectPacketException(
|
class IncorrectPacketException(
|
||||||
val payload: ByteArray,
|
val payload: ByteArray,
|
||||||
val expectedIndex: Byte? = null
|
private val expectedIndex: Byte? = null
|
||||||
) : Exception("Invalid payload: ${payload.toHex()}. Expected index: $expectedIndex")
|
) : Exception("Invalid payload: ${payload.toHex()}. Expected index: $expectedIndex")
|
||||||
|
|
|
@ -29,7 +29,7 @@ class MessageIO(
|
||||||
private val dataBleIO: DataBleIO,
|
private val dataBleIO: DataBleIO,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val receivedOutOfOrder = LinkedHashMap<Byte, ByteArray>()
|
private val receivedOutOfOrder = LinkedHashMap<Byte, ByteArray>()
|
||||||
var maxMessageReadTries = 3
|
var maxMessageReadTries = 3
|
||||||
var messageReadTries = 0
|
var messageReadTries = 0
|
||||||
|
|
||||||
|
|
|
@ -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.Id
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.CouldNotParseMessageException
|
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
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
/***
|
/***
|
||||||
|
@ -80,13 +81,13 @@ data class MessagePacket(
|
||||||
if (payload.copyOfRange(0, 2).decodeToString() != MAGIC_PATTERN) {
|
if (payload.copyOfRange(0, 2).decodeToString() != MAGIC_PATTERN) {
|
||||||
throw CouldNotParseMessageException(payload)
|
throw CouldNotParseMessageException(payload)
|
||||||
}
|
}
|
||||||
val f1 = Flag(payload[2].toInt())
|
val f1 = Flag(payload[2].toInt() and 0xff)
|
||||||
val sas = f1.get(3) != 0
|
val sas = f1.get(3) != 0
|
||||||
val tfs = f1.get(4) != 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 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 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 ack = f2.get(0) != 0
|
||||||
val priority = f2.get(1) != 0
|
val priority = f2.get(1) != 0
|
||||||
val lastMessage = f2.get(2) != 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
|
internal fun Byte.toUnsignedInt() = this.toInt() and 0xff
|
||||||
|
|
||||||
private fun ByteArray.assertSizeAtLeast(size: Int) {
|
private fun ByteArray.assertSizeAtLeast(size: Int) {
|
||||||
|
|
|
@ -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.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.AlertUtil
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.byValue
|
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 java.util.*
|
||||||
import kotlin.experimental.and
|
import kotlin.experimental.and
|
||||||
|
|
||||||
|
@ -13,18 +15,21 @@ class DefaultStatusResponse(
|
||||||
) : ResponseBase(ResponseType.DEFAULT_STATUS_RESPONSE, encoded) {
|
) : ResponseBase(ResponseType.DEFAULT_STATUS_RESPONSE, encoded) {
|
||||||
|
|
||||||
val messageType: Byte = encoded[0]
|
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()
|
private var first4bytes = ByteBuffer.wrap(byteArrayOf(encoded[2], encoded[3], encoded[4], encoded[5])).int
|
||||||
val bolusPulsesRemaining: Short = ((encoded[4] and 0x07 shl 10 or (encoded[5].toInt() and 0xff) and 2047).toShort())
|
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<AlertType> =
|
val activeAlerts: EnumSet<AlertType> =
|
||||||
AlertUtil.decodeAlertSet((encoded[6].toInt() and 0xff shl 1 or (encoded[7] ushr 7)).toByte())
|
AlertUtil.decodeAlertSet((last4bytes ushr 10 ushr 13 and 0xFF).toByte())
|
||||||
val minutesSinceActivation: Short =
|
val minutesSinceActivation: Short = ((last4bytes ushr 10 and 0x1FFF)).toShort()
|
||||||
(encoded[7] and 0x7f shl 6 or (encoded[8].toInt() and 0xff ushr 2 and 0x3f)).toShort()
|
val reservoirPulsesRemaining: Short = (last4bytes and 0X3FF).toShort()
|
||||||
val reservoirPulsesRemaining: Short = (encoded[8] shl 8 or (encoded[9].toInt() and 0xff) and 0x3ff).toShort()
|
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "DefaultStatusResponse(" +
|
return "DefaultStatusResponse(" +
|
||||||
|
|
|
@ -2,6 +2,6 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.util
|
||||||
|
|
||||||
class Constants {
|
class Constants {
|
||||||
companion object {
|
companion object {
|
||||||
val PUMP_SERIAL_FOR_FAKE_TBR = "4241"
|
const val PUMP_SERIAL_FOR_FAKE_TBR = "4241"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response
|
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.DeliveryStatus
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodStatus
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodStatus
|
||||||
import org.apache.commons.codec.DecoderException
|
import org.apache.commons.codec.DecoderException
|
||||||
|
@ -117,7 +118,7 @@ class DefaultStatusResponseTest {
|
||||||
Full reservoir pulses remaining: 392
|
Full reservoir pulses remaining: 392
|
||||||
Time since activation: 4283
|
Time since activation: 4283
|
||||||
*/
|
*/
|
||||||
@Test @Throws(DecoderException::class) fun testValidResponseBolusPulsesRemaining2() {
|
@Test @Throws(DecoderException::class) fun testValidResponseReservoirPulsesRemaining() {
|
||||||
val encoded = Hex.decodeHex("1D990714201F0042ED8801DE")
|
val encoded = Hex.decodeHex("1D990714201F0042ED8801DE")
|
||||||
val response = DefaultStatusResponse(encoded)
|
val response = DefaultStatusResponse(encoded)
|
||||||
Assert.assertArrayEquals(encoded, response.encoded)
|
Assert.assertArrayEquals(encoded, response.encoded)
|
||||||
|
@ -133,4 +134,86 @@ class DefaultStatusResponseTest {
|
||||||
Assert.assertEquals(392.toShort(), response.reservoirPulsesRemaining)
|
Assert.assertEquals(392.toShort(), response.reservoirPulsesRemaining)
|
||||||
Assert.assertEquals(3624.toShort(), response.totalPulsesDelivered)
|
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))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue