dash ble: start implementing retries
Handle NACKs for now.
This commit is contained in:
parent
95d7f0737c
commit
109f66a48d
5 changed files with 51 additions and 15 deletions
|
@ -43,6 +43,10 @@ class BleIO(
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun peekCommand(): ByteArray? {
|
||||||
|
return incomingPackets[CharacteristicType.CMD]?.peek()
|
||||||
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
*
|
*
|
||||||
* @param characteristic where to write to(CMD or DATA)
|
* @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.
|
* The incoming queues should be empty, so we log when they are not.
|
||||||
*/
|
*/
|
||||||
fun flushIncomingQueues() {
|
fun flushIncomingQueues() {
|
||||||
|
synchronized(state) { state = IOState.IDLE }
|
||||||
|
|
||||||
for (char in CharacteristicType.values()) {
|
for (char in CharacteristicType.values()) {
|
||||||
do {
|
do {
|
||||||
val found = incomingPackets[char]?.poll()?.also {
|
val found = incomingPackets[char]?.poll()?.also {
|
||||||
|
@ -123,6 +129,6 @@ class BleIO(
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private const val DEFAULT_IO_TIMEOUT_MS = 60000
|
private const val DEFAULT_IO_TIMEOUT_MS = 2000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.BleIO
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.CharacteristicType
|
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.io.PayloadJoiner
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.packet.BlePacket
|
||||||
import info.nightscout.androidaps.utils.extensions.toHex
|
import info.nightscout.androidaps.utils.extensions.toHex
|
||||||
|
|
||||||
class MessageIO(private val aapsLogger: AAPSLogger, private val bleIO: BleIO) {
|
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)
|
throw UnexpectedCommandException(actual)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun peekForNack(index: Int, packets: List<BlePacket>) {
|
||||||
|
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) {
|
fun sendMessage(msg: MessagePacket) {
|
||||||
bleIO.flushIncomingQueues()
|
bleIO.flushIncomingQueues()
|
||||||
bleIO.sendAndConfirmPacket(CharacteristicType.CMD, BleCommandRTS().data)
|
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()}")
|
aapsLogger.debug(LTag.PUMPBTCOMM, "Sending message: ${payload.toHex()}")
|
||||||
val splitter = PayloadSplitter(payload)
|
val splitter = PayloadSplitter(payload)
|
||||||
val packets = splitter.splitInPackets()
|
val packets = splitter.splitInPackets()
|
||||||
for (packet in packets) {
|
for ((index, packet) in packets.withIndex()) {
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Sending DATA: ${packet.asByteArray().toHex()}")
|
aapsLogger.debug(LTag.PUMPBTCOMM, "Sending DATA: ${packet.toByteArray().toHex()}")
|
||||||
bleIO.sendAndConfirmPacket(CharacteristicType.DATA, packet.asByteArray())
|
bleIO.sendAndConfirmPacket(CharacteristicType.DATA, packet.toByteArray())
|
||||||
|
peekForNack(index, packets)
|
||||||
}
|
}
|
||||||
// TODO: peek for NACKs
|
|
||||||
val expectSuccess = bleIO.receivePacket(CharacteristicType.CMD)
|
val expectSuccess = bleIO.receivePacket(CharacteristicType.CMD)
|
||||||
expectCommandType(BleCommand(expectSuccess), BleCommandSuccess())
|
expectCommandType(BleCommand(expectSuccess), BleCommandSuccess())
|
||||||
// TODO: handle NACKS/FAILS/etc
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: use higher timeout when receiving the first packet in a message
|
// TODO: use higher timeout when receiving the first packet in a message
|
||||||
|
|
|
@ -4,7 +4,7 @@ import java.nio.ByteBuffer
|
||||||
|
|
||||||
sealed class BlePacket {
|
sealed class BlePacket {
|
||||||
|
|
||||||
abstract fun asByteArray(): ByteArray
|
abstract fun toByteArray(): ByteArray
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ data class FirstBlePacket(
|
||||||
val crc32: Long? = null
|
val crc32: Long? = null
|
||||||
) : BlePacket() {
|
) : BlePacket() {
|
||||||
|
|
||||||
override fun asByteArray(): ByteArray {
|
override fun toByteArray(): ByteArray {
|
||||||
val bb = ByteBuffer
|
val bb = ByteBuffer
|
||||||
.allocate(MAX_SIZE)
|
.allocate(MAX_SIZE)
|
||||||
.put(0) // index
|
.put(0) // index
|
||||||
|
@ -55,7 +55,7 @@ data class FirstBlePacket(
|
||||||
|
|
||||||
data class MiddleBlePacket(val index: Byte, val payload: ByteArray) : BlePacket() {
|
data class MiddleBlePacket(val index: Byte, val payload: ByteArray) : BlePacket() {
|
||||||
|
|
||||||
override fun asByteArray(): ByteArray {
|
override fun toByteArray(): ByteArray {
|
||||||
return byteArrayOf(index) + payload
|
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() {
|
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
|
val bb = ByteBuffer
|
||||||
.allocate(MAX_SIZE)
|
.allocate(MAX_SIZE)
|
||||||
.put(index)
|
.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() {
|
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)
|
return byteArrayOf(index, size) + payload + ByteArray(MAX_SIZE - payload.size - 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,9 +15,9 @@ class PayloadSplitJoinTest {
|
||||||
random.nextBytes(payload)
|
random.nextBytes(payload)
|
||||||
val splitter = PayloadSplitter(payload)
|
val splitter = PayloadSplitter(payload)
|
||||||
val packets = splitter.splitInPackets()
|
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)) {
|
for (p in packets.subList(1, packets.size)) {
|
||||||
joiner.accumulate(p.asByteArray())
|
joiner.accumulate(p.toByteArray())
|
||||||
}
|
}
|
||||||
val got = joiner.finalize()
|
val got = joiner.finalize()
|
||||||
assertEquals(got.toHex(), payload.toHex())
|
assertEquals(got.toHex(), payload.toHex())
|
||||||
|
|
|
@ -16,8 +16,8 @@ class PayloadSplitterTest {
|
||||||
val packets = splitter.splitInPackets()
|
val packets = splitter.splitInPackets()
|
||||||
|
|
||||||
assertEquals(packets.size, 2)
|
assertEquals(packets.size, 2)
|
||||||
assertEquals(f1, packets.get(0).asByteArray().toHex())
|
assertEquals(f1, packets.get(0).toByteArray().toHex())
|
||||||
val p2 = packets.get(1).asByteArray()
|
val p2 = packets.get(1).toByteArray()
|
||||||
assertTrue(p2.size >= 10)
|
assertTrue(p2.size >= 10)
|
||||||
assertEquals(f2.subSequence(0, 20), p2.copyOfRange(0, 10).toHex())
|
assertEquals(f2.subSequence(0, 20), p2.copyOfRange(0, 10).toHex())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue