From 109f66a48d62bfe39fbeb1d546afda2c4cf3ba57 Mon Sep 17 00:00:00 2001 From: Andrei Vereha Date: Sun, 14 Mar 2021 20:28:16 +0100 Subject: [PATCH] dash ble: start implementing retries Handle NACKs for now. --- .../pump/omnipod/dash/driver/comm/io/BleIO.kt | 8 +++- .../dash/driver/comm/message/MessageIO.kt | 40 ++++++++++++++++--- .../dash/driver/comm/packet/BlePacket.kt | 10 ++--- .../comm/message/PayloadSplitJoinTest.kt | 4 +- .../comm/message/PayloadSplitterTest.kt | 4 +- 5 files changed, 51 insertions(+), 15 deletions(-) diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/io/BleIO.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/io/BleIO.kt index 8831ba3d81..0375d05ad1 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/io/BleIO.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/io/BleIO.kt @@ -43,6 +43,10 @@ class BleIO( return ret } + fun peekCommand(): ByteArray? { + return incomingPackets[CharacteristicType.CMD]?.peek() + } + /*** * * @param characteristic where to write to(CMD or DATA) @@ -82,6 +86,8 @@ class BleIO( * The incoming queues should be empty, so we log when they are not. */ fun flushIncomingQueues() { + synchronized(state) { state = IOState.IDLE } + for (char in CharacteristicType.values()) { do { val found = incomingPackets[char]?.poll()?.also { @@ -123,6 +129,6 @@ class BleIO( companion object { - private const val DEFAULT_IO_TIMEOUT_MS = 60000 + private const val DEFAULT_IO_TIMEOUT_MS = 2000 } } 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 36e9613714..b7ad19b0e1 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 @@ -8,6 +8,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptio import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.BleIO import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.CharacteristicType import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.PayloadJoiner +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.packet.BlePacket import info.nightscout.androidaps.utils.extensions.toHex class MessageIO(private val aapsLogger: AAPSLogger, private val bleIO: BleIO) { @@ -23,6 +24,36 @@ class MessageIO(private val aapsLogger: AAPSLogger, private val bleIO: BleIO) { throw UnexpectedCommandException(actual) } + fun peekForNack(index: Int, packets: List) { + bleIO.peekCommand()?.let { + if (it.isEmpty()) { + throw UnexpectedCommandException(BleCommand(it)) + } + when (BleCommandType.byValue(it[0])) { + BleCommandType.NACK -> { + if (it.size < 2) { + throw UnexpectedCommandException(BleCommand(it)) + } + val missingIdx = it[1] + if (missingIdx > packets.size) { + throw UnexpectedCommandException(BleCommand(it)) + + } + bleIO.sendAndConfirmPacket(CharacteristicType.DATA, packets[missingIdx.toInt()].toByteArray()) + } + + BleCommandType.SUCCESS -> { + if (index != packets.size - 1) { + throw UnexpectedCommandException(BleCommand(it)) + } + } + + else -> + throw UnexpectedCommandException(BleCommand(it)) + } + } + } + fun sendMessage(msg: MessagePacket) { bleIO.flushIncomingQueues() bleIO.sendAndConfirmPacket(CharacteristicType.CMD, BleCommandRTS().data) @@ -32,14 +63,13 @@ class MessageIO(private val aapsLogger: AAPSLogger, private val bleIO: BleIO) { aapsLogger.debug(LTag.PUMPBTCOMM, "Sending message: ${payload.toHex()}") val splitter = PayloadSplitter(payload) val packets = splitter.splitInPackets() - for (packet in packets) { - aapsLogger.debug(LTag.PUMPBTCOMM, "Sending DATA: ${packet.asByteArray().toHex()}") - bleIO.sendAndConfirmPacket(CharacteristicType.DATA, packet.asByteArray()) + for ((index, packet) in packets.withIndex()) { + aapsLogger.debug(LTag.PUMPBTCOMM, "Sending DATA: ${packet.toByteArray().toHex()}") + bleIO.sendAndConfirmPacket(CharacteristicType.DATA, packet.toByteArray()) + peekForNack(index, packets) } - // TODO: peek for NACKs val expectSuccess = bleIO.receivePacket(CharacteristicType.CMD) expectCommandType(BleCommand(expectSuccess), BleCommandSuccess()) - // TODO: handle NACKS/FAILS/etc } // TODO: use higher timeout when receiving the first packet in a message diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/packet/BlePacket.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/packet/BlePacket.kt index 16ff9d61e5..ed56b02335 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/packet/BlePacket.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/packet/BlePacket.kt @@ -4,7 +4,7 @@ import java.nio.ByteBuffer sealed class BlePacket { - abstract fun asByteArray(): ByteArray + abstract fun toByteArray(): ByteArray companion object { @@ -19,7 +19,7 @@ data class FirstBlePacket( val crc32: Long? = null ) : BlePacket() { - override fun asByteArray(): ByteArray { + override fun toByteArray(): ByteArray { val bb = ByteBuffer .allocate(MAX_SIZE) .put(0) // index @@ -55,7 +55,7 @@ data class FirstBlePacket( data class MiddleBlePacket(val index: Byte, val payload: ByteArray) : BlePacket() { - override fun asByteArray(): ByteArray { + override fun toByteArray(): ByteArray { return byteArrayOf(index) + payload } @@ -67,7 +67,7 @@ data class MiddleBlePacket(val index: Byte, val payload: ByteArray) : BlePacket( data class LastBlePacket(val index: Byte, val size: Byte, val payload: ByteArray, val crc32: Long) : BlePacket() { - override fun asByteArray(): ByteArray { + override fun toByteArray(): ByteArray { val bb = ByteBuffer .allocate(MAX_SIZE) .put(index) @@ -90,7 +90,7 @@ data class LastBlePacket(val index: Byte, val size: Byte, val payload: ByteArray data class LastOptionalPlusOneBlePacket(val index: Byte, val payload: ByteArray, val size: Byte) : BlePacket() { - override fun asByteArray(): ByteArray { + override fun toByteArray(): ByteArray { return byteArrayOf(index, size) + payload + ByteArray(MAX_SIZE - payload.size - 2) } diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadSplitJoinTest.kt b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadSplitJoinTest.kt index 6eecdf780f..305d3d71a0 100644 --- a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadSplitJoinTest.kt +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadSplitJoinTest.kt @@ -15,9 +15,9 @@ class PayloadSplitJoinTest { random.nextBytes(payload) val splitter = PayloadSplitter(payload) val packets = splitter.splitInPackets() - val joiner = PayloadJoiner(packets.get(0).asByteArray()) + val joiner = PayloadJoiner(packets.get(0).toByteArray()) for (p in packets.subList(1, packets.size)) { - joiner.accumulate(p.asByteArray()) + joiner.accumulate(p.toByteArray()) } val got = joiner.finalize() assertEquals(got.toHex(), payload.toHex()) diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadSplitterTest.kt b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadSplitterTest.kt index 8d046c0439..170e7d75a1 100644 --- a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadSplitterTest.kt +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadSplitterTest.kt @@ -16,8 +16,8 @@ class PayloadSplitterTest { val packets = splitter.splitInPackets() assertEquals(packets.size, 2) - assertEquals(f1, packets.get(0).asByteArray().toHex()) - val p2 = packets.get(1).asByteArray() + assertEquals(f1, packets.get(0).toByteArray().toHex()) + val p2 = packets.get(1).toByteArray() assertTrue(p2.size >= 10) assertEquals(f2.subSequence(0, 20), p2.copyOfRange(0, 10).toHex()) }