dash ble: move parsing logic out of PayloadJoiner to BlePacket
This commit is contained in:
parent
8868f29ab2
commit
de6ca939ed
3 changed files with 139 additions and 80 deletions
|
@ -7,52 +7,24 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.packet.B
|
|||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.packet.FirstBlePacket
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.packet.LastBlePacket
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.packet.LastOptionalPlusOneBlePacket
|
||||
import java.lang.Integer.min
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.packet.MiddleBlePacket
|
||||
import java.nio.ByteBuffer
|
||||
import java.util.*
|
||||
|
||||
class PayloadJoiner(private val firstPacket: ByteArray) {
|
||||
|
||||
var oneExtraPacket: Boolean = false
|
||||
var oneExtraPacket: Boolean
|
||||
val fullFragments: Int
|
||||
var crc: Long = 0
|
||||
private var expectedIndex = 0
|
||||
private val fragments: LinkedList<ByteArray> = LinkedList<ByteArray>()
|
||||
private val fragments: MutableList<BlePacket> = LinkedList<BlePacket>()
|
||||
|
||||
init {
|
||||
if (firstPacket.size < FirstBlePacket.HEADER_SIZE_WITH_MIDDLE_PACKETS) {
|
||||
throw IncorrectPacketException(0, firstPacket)
|
||||
}
|
||||
fullFragments = firstPacket[1].toInt()
|
||||
when {
|
||||
// Without middle packets
|
||||
firstPacket.size < FirstBlePacket.HEADER_SIZE_WITHOUT_MIDDLE_PACKETS ->
|
||||
throw IncorrectPacketException(0, firstPacket)
|
||||
|
||||
fullFragments == 0 -> {
|
||||
crc = ByteBuffer.wrap(firstPacket.copyOfRange(2, 6)).int.toUnsignedLong()
|
||||
val rest = firstPacket[6]
|
||||
val end = min(rest + FirstBlePacket.HEADER_SIZE_WITHOUT_MIDDLE_PACKETS, firstPacket.size)
|
||||
oneExtraPacket = rest + FirstBlePacket.HEADER_SIZE_WITHOUT_MIDDLE_PACKETS > end
|
||||
if (end > firstPacket.size) {
|
||||
throw IncorrectPacketException(0, firstPacket)
|
||||
}
|
||||
fragments.add(firstPacket.copyOfRange(FirstBlePacket.HEADER_SIZE_WITHOUT_MIDDLE_PACKETS, end))
|
||||
}
|
||||
|
||||
// With middle packets
|
||||
firstPacket.size < BlePacket.MAX_SIZE ->
|
||||
throw IncorrectPacketException(0, firstPacket)
|
||||
|
||||
else -> {
|
||||
fragments.add(
|
||||
firstPacket.copyOfRange(
|
||||
FirstBlePacket.HEADER_SIZE_WITH_MIDDLE_PACKETS,
|
||||
BlePacket.MAX_SIZE
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
val firstPacket = FirstBlePacket.parse(firstPacket)
|
||||
fragments.add(firstPacket)
|
||||
fullFragments = firstPacket.fullFragments
|
||||
crc = firstPacket.crc32 ?: 0
|
||||
oneExtraPacket = firstPacket.oneExtraPacket
|
||||
}
|
||||
|
||||
fun accumulate(packet: ByteArray) {
|
||||
|
@ -65,47 +37,32 @@ class PayloadJoiner(private val firstPacket: ByteArray) {
|
|||
}
|
||||
expectedIndex++
|
||||
when {
|
||||
idx < fullFragments -> { // this is a middle fragment
|
||||
if (packet.size < BlePacket.MAX_SIZE) {
|
||||
throw IncorrectPacketException(idx.toByte(), packet)
|
||||
}
|
||||
fragments.add(packet.copyOfRange(1, BlePacket.MAX_SIZE))
|
||||
idx < fullFragments -> {
|
||||
fragments.add(MiddleBlePacket.parse(packet))
|
||||
}
|
||||
|
||||
idx == fullFragments -> { // this is the last fragment
|
||||
if (packet.size < LastBlePacket.HEADER_SIZE) {
|
||||
throw IncorrectPacketException(idx.toByte(), packet)
|
||||
}
|
||||
crc = ByteBuffer.wrap(packet.copyOfRange(2, 6)).int.toUnsignedLong()
|
||||
val rest = packet[1].toInt()
|
||||
val end = min(rest + LastBlePacket.HEADER_SIZE, packet.size)
|
||||
oneExtraPacket = rest + LastBlePacket.HEADER_SIZE > end
|
||||
if (packet.size < end) {
|
||||
throw IncorrectPacketException(idx.toByte(), packet)
|
||||
}
|
||||
fragments.add(packet.copyOfRange(LastBlePacket.HEADER_SIZE, end))
|
||||
idx == fullFragments -> {
|
||||
val lastPacket = LastBlePacket.parse(packet)
|
||||
fragments.add(lastPacket)
|
||||
crc = lastPacket.crc32
|
||||
oneExtraPacket = lastPacket.oneExtraPacket
|
||||
}
|
||||
|
||||
idx > fullFragments -> { // this is the extra fragment
|
||||
val size = packet[1].toInt()
|
||||
if (packet.size < LastOptionalPlusOneBlePacket.HEADER_SIZE + size) {
|
||||
throw IncorrectPacketException(idx.toByte(), packet)
|
||||
}
|
||||
idx > fullFragments && oneExtraPacket -> {
|
||||
fragments.add(LastOptionalPlusOneBlePacket.parse(packet))
|
||||
}
|
||||
|
||||
fragments.add(
|
||||
packet.copyOfRange(
|
||||
LastOptionalPlusOneBlePacket.HEADER_SIZE,
|
||||
LastOptionalPlusOneBlePacket.HEADER_SIZE + size
|
||||
)
|
||||
)
|
||||
idx > fullFragments -> {
|
||||
throw IncorrectPacketException(idx.toByte(), packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun finalize(): ByteArray {
|
||||
val totalLen = fragments.fold(0, { acc, elem -> acc + elem.size })
|
||||
val payloads = fragments.map { x -> x.payload }
|
||||
val totalLen = payloads.fold(0, { acc, elem -> acc + elem.size })
|
||||
val bb = ByteBuffer.allocate(totalLen)
|
||||
fragments.map { fragment -> bb.put(fragment) }
|
||||
payloads.map { p -> bb.put(p) }
|
||||
bb.flip()
|
||||
val bytes = bb.array()
|
||||
if (bytes.crc32() != crc) {
|
||||
|
|
|
@ -17,7 +17,7 @@ internal class PayloadSplitter(private val payload: ByteArray) {
|
|||
val end = min(FirstBlePacket.CAPACITY_WITHOUT_MIDDLE_PACKETS, payload.size)
|
||||
ret.add(
|
||||
FirstBlePacket(
|
||||
totalFragments = 0,
|
||||
fullFragments = 0,
|
||||
payload = payload.copyOfRange(0, end),
|
||||
size = payload.size.toByte(),
|
||||
crc32 = crc32
|
||||
|
@ -39,7 +39,7 @@ internal class PayloadSplitter(private val payload: ByteArray) {
|
|||
((payload.size - middleFragments * MiddleBlePacket.CAPACITY) - FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS).toByte()
|
||||
ret.add(
|
||||
FirstBlePacket(
|
||||
totalFragments = (middleFragments + 1).toByte(),
|
||||
fullFragments = middleFragments + 1,
|
||||
payload = payload.copyOfRange(0, FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.packet
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.toUnsignedLong
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.IncorrectPacketException
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
sealed class BlePacket {
|
||||
|
||||
abstract val payload: ByteArray
|
||||
abstract fun toByteArray(): ByteArray
|
||||
|
||||
companion object {
|
||||
|
@ -13,17 +15,18 @@ sealed class BlePacket {
|
|||
}
|
||||
|
||||
data class FirstBlePacket(
|
||||
val totalFragments: Byte,
|
||||
val payload: ByteArray,
|
||||
val fullFragments: Int,
|
||||
override val payload: ByteArray,
|
||||
val size: Byte? = null,
|
||||
val crc32: Long? = null
|
||||
val crc32: Long? = null,
|
||||
val oneExtraPacket: Boolean = false
|
||||
) : BlePacket() {
|
||||
|
||||
override fun toByteArray(): ByteArray {
|
||||
val bb = ByteBuffer
|
||||
.allocate(MAX_SIZE)
|
||||
.put(0) // index
|
||||
.put(totalFragments) // # of fragments except FirstBlePacket and LastOptionalPlusOneBlePacket
|
||||
.put(fullFragments.toByte()) // # of fragments except FirstBlePacket and LastOptionalPlusOneBlePacket
|
||||
crc32?.let {
|
||||
bb.putInt(crc32.toInt())
|
||||
}
|
||||
|
@ -42,18 +45,64 @@ data class FirstBlePacket(
|
|||
|
||||
companion object {
|
||||
|
||||
internal const val HEADER_SIZE_WITHOUT_MIDDLE_PACKETS = 7 // we are using all fields
|
||||
internal const val HEADER_SIZE_WITH_MIDDLE_PACKETS = 2
|
||||
fun parse(payload: ByteArray): FirstBlePacket {
|
||||
if (payload.size < FirstBlePacket.HEADER_SIZE_WITH_MIDDLE_PACKETS) {
|
||||
throw IncorrectPacketException(0, payload)
|
||||
}
|
||||
if (payload[0].toInt() != 0) {
|
||||
// most likely we lost the first packet.
|
||||
// TODO: try to recover with NACKs?
|
||||
throw IncorrectPacketException(0, payload)
|
||||
}
|
||||
val fullFragments = payload[1].toInt()
|
||||
require(fullFragments < MAX_FRAGMENTS) { "Received more than ${MAX_FRAGMENTS} fragments" }
|
||||
when {
|
||||
// Without middle packets
|
||||
payload.size < HEADER_SIZE_WITHOUT_MIDDLE_PACKETS ->
|
||||
throw IncorrectPacketException(0, payload)
|
||||
|
||||
fullFragments == 0 -> {
|
||||
val rest = payload[6]
|
||||
val end = Integer.min(rest + HEADER_SIZE_WITHOUT_MIDDLE_PACKETS, payload.size)
|
||||
if (end > payload.size) {
|
||||
throw IncorrectPacketException(0, payload)
|
||||
}
|
||||
return FirstBlePacket(
|
||||
fullFragments = fullFragments,
|
||||
payload = payload.copyOfRange(HEADER_SIZE_WITHOUT_MIDDLE_PACKETS, end),
|
||||
crc32 = ByteBuffer.wrap(payload.copyOfRange(2, 6)).int.toUnsignedLong(),
|
||||
size = rest,
|
||||
oneExtraPacket = rest + HEADER_SIZE_WITHOUT_MIDDLE_PACKETS > end
|
||||
)
|
||||
}
|
||||
|
||||
// With middle packets
|
||||
payload.size < BlePacket.MAX_SIZE ->
|
||||
throw IncorrectPacketException(0, payload)
|
||||
|
||||
else -> {
|
||||
return FirstBlePacket(
|
||||
fullFragments = fullFragments,
|
||||
payload = payload.copyOfRange(HEADER_SIZE_WITH_MIDDLE_PACKETS, MAX_SIZE)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private const val HEADER_SIZE_WITHOUT_MIDDLE_PACKETS = 7 // we are using all fields
|
||||
private const val HEADER_SIZE_WITH_MIDDLE_PACKETS = 2
|
||||
|
||||
internal const val CAPACITY_WITHOUT_MIDDLE_PACKETS =
|
||||
MAX_SIZE - HEADER_SIZE_WITHOUT_MIDDLE_PACKETS // we are using all fields
|
||||
internal const val CAPACITY_WITH_MIDDLE_PACKETS =
|
||||
MAX_SIZE - HEADER_SIZE_WITH_MIDDLE_PACKETS // we are not using crc32 or size
|
||||
internal const val CAPACITY_WITH_THE_OPTIONAL_PLUS_ONE_PACKET = 18
|
||||
|
||||
private const val MAX_FRAGMENTS = 15 // 15*20=300 bytes
|
||||
}
|
||||
}
|
||||
|
||||
data class MiddleBlePacket(val index: Byte, val payload: ByteArray) : BlePacket() {
|
||||
data class MiddleBlePacket(val index: Byte, override val payload: ByteArray) : BlePacket() {
|
||||
|
||||
override fun toByteArray(): ByteArray {
|
||||
return byteArrayOf(index) + payload
|
||||
|
@ -61,11 +110,27 @@ data class MiddleBlePacket(val index: Byte, val payload: ByteArray) : BlePacket(
|
|||
|
||||
companion object {
|
||||
|
||||
fun parse(payload: ByteArray): MiddleBlePacket {
|
||||
if (payload.size < MAX_SIZE) {
|
||||
throw IncorrectPacketException(0, payload)
|
||||
}
|
||||
return MiddleBlePacket(
|
||||
index = payload[0],
|
||||
payload.copyOfRange(1, MAX_SIZE)
|
||||
)
|
||||
}
|
||||
|
||||
internal const val CAPACITY = 19
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
override val payload: ByteArray,
|
||||
val crc32: Long,
|
||||
val oneExtraPacket: Boolean = false
|
||||
) : BlePacket() {
|
||||
|
||||
override fun toByteArray(): ByteArray {
|
||||
val bb = ByteBuffer
|
||||
|
@ -83,12 +148,33 @@ data class LastBlePacket(val index: Byte, val size: Byte, val payload: ByteArray
|
|||
|
||||
companion object {
|
||||
|
||||
internal const val HEADER_SIZE = 6
|
||||
fun parse(payload: ByteArray): LastBlePacket {
|
||||
if (payload.size < HEADER_SIZE) {
|
||||
throw IncorrectPacketException(0, payload)
|
||||
}
|
||||
val rest = payload[1]
|
||||
val end = Integer.min(rest + HEADER_SIZE, payload.size)
|
||||
if (payload.size < end) {
|
||||
throw IncorrectPacketException(0, payload)
|
||||
}
|
||||
return LastBlePacket(
|
||||
index = payload[0],
|
||||
crc32 = ByteBuffer.wrap(payload.copyOfRange(2, 6)).int.toUnsignedLong(),
|
||||
oneExtraPacket = rest + HEADER_SIZE > end,
|
||||
size = rest,
|
||||
payload = payload.copyOfRange(HEADER_SIZE, end)
|
||||
)
|
||||
}
|
||||
|
||||
private const val HEADER_SIZE = 6
|
||||
internal const val CAPACITY = MAX_SIZE - HEADER_SIZE
|
||||
}
|
||||
}
|
||||
|
||||
data class LastOptionalPlusOneBlePacket(val index: Byte, val payload: ByteArray, val size: Byte) : BlePacket() {
|
||||
data class LastOptionalPlusOneBlePacket(
|
||||
val index: Byte,
|
||||
override val payload: ByteArray,
|
||||
val size: Byte) : BlePacket() {
|
||||
|
||||
override fun toByteArray(): ByteArray {
|
||||
return byteArrayOf(index, size) + payload + ByteArray(MAX_SIZE - payload.size - 2)
|
||||
|
@ -96,6 +182,22 @@ data class LastOptionalPlusOneBlePacket(val index: Byte, val payload: ByteArray,
|
|||
|
||||
companion object {
|
||||
|
||||
internal const val HEADER_SIZE = 2
|
||||
fun parse(payload: ByteArray): LastOptionalPlusOneBlePacket {
|
||||
val size = payload[1].toInt()
|
||||
if (payload.size < HEADER_SIZE + size) {
|
||||
throw IncorrectPacketException(0, payload)
|
||||
}
|
||||
return LastOptionalPlusOneBlePacket(
|
||||
index = payload[0],
|
||||
payload = payload.copyOfRange(
|
||||
HEADER_SIZE,
|
||||
HEADER_SIZE + size
|
||||
),
|
||||
size = size.toByte(),
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
private const val HEADER_SIZE = 2
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue