- address review comments: renames and removed unused vars
 - implement serialization for BlePackets
 - improve logging, add .toHex() where we have []byte

```
INFO[0009] Received SP1 SP2 payload 5350313d0004024200032c5350323d000bffc32dbd20030e01000016
TRAC[0009] Read field: SP1= :: 02420003 :: 4
TRAC[0009] Read field: ,SP2= :: ffc32dbd20030e01000016 :: 11
INFO[0009] Received SP1 SP2: 02420003 :: ffc32dbd20030e01000016
```
This commit is contained in:
Andrei Vereha 2021-02-25 19:19:06 +01:00
parent 08ff02dd4f
commit af1d505e36
9 changed files with 58 additions and 24 deletions

View file

@ -11,6 +11,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.Chara
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.CharacteristicType.Companion.byValue import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.CharacteristicType.Companion.byValue
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.CouldNotConfirmDescriptorWriteException import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.CouldNotConfirmDescriptorWriteException
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.CouldNotConfirmWriteException import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.CouldNotConfirmWriteException
import info.nightscout.androidaps.utils.extensions.toHex
import java.util.concurrent.BlockingQueue import java.util.concurrent.BlockingQueue
import java.util.concurrent.CountDownLatch import java.util.concurrent.CountDownLatch
import java.util.concurrent.LinkedBlockingQueue import java.util.concurrent.LinkedBlockingQueue
@ -63,10 +64,10 @@ class BleCommCallbacks(private val aapsLogger: AAPSLogger, private val incomingP
private fun confirmWritePayload(expectedPayload: ByteArray, received: CharacteristicWriteConfirmationPayload) { private fun confirmWritePayload(expectedPayload: ByteArray, received: CharacteristicWriteConfirmationPayload) {
if (!expectedPayload.contentEquals(received.payload)) { if (!expectedPayload.contentEquals(received.payload)) {
aapsLogger.warn(LTag.PUMPBTCOMM, "Could not confirm write. Got " + received.payload + ".Excepted: " + expectedPayload) aapsLogger.warn(LTag.PUMPBTCOMM, "Could not confirm write. Got " + received.payload.toHex() + ".Excepted: " + expectedPayload.toHex())
throw CouldNotConfirmWriteException(expectedPayload, received.payload) throw CouldNotConfirmWriteException(expectedPayload, received.payload)
} }
aapsLogger.debug(LTag.PUMPBTCOMM, "Confirmed write with value: " + received.payload) aapsLogger.debug(LTag.PUMPBTCOMM, "Confirmed write with value: " + received.payload.toHex())
} }
override fun onCharacteristicWrite(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) { override fun onCharacteristicWrite(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) {
@ -77,7 +78,7 @@ class BleCommCallbacks(private val aapsLogger: AAPSLogger, private val incomingP
CharacteristicWriteConfirmationError(status) CharacteristicWriteConfirmationError(status)
} }
aapsLogger.debug(LTag.PUMPBTCOMM, "OnCharacteristicWrite with status/char/value " + aapsLogger.debug(LTag.PUMPBTCOMM, "OnCharacteristicWrite with status/char/value " +
status + "/" + byValue(characteristic.uuid.toString()) + "/" + characteristic.value) status + "/" + byValue(characteristic.uuid.toString()) + "/" + characteristic.value.toHex())
try { try {
if (writeQueue.size > 0) { if (writeQueue.size > 0) {
aapsLogger.warn(LTag.PUMPBTCOMM, "Write confirm queue should be empty. found: " + writeQueue.size) aapsLogger.warn(LTag.PUMPBTCOMM, "Write confirm queue should be empty. found: " + writeQueue.size)
@ -98,7 +99,7 @@ class BleCommCallbacks(private val aapsLogger: AAPSLogger, private val incomingP
val characteristicType = byValue(characteristic.uuid.toString()) val characteristicType = byValue(characteristic.uuid.toString())
aapsLogger.debug(LTag.PUMPBTCOMM, "OnCharacteristicChanged with char/value " + aapsLogger.debug(LTag.PUMPBTCOMM, "OnCharacteristicChanged with char/value " +
characteristicType + "/" + characteristicType + "/" +
payload) payload.toHex())
incomingPackets[characteristicType]!!.add(payload) incomingPackets[characteristicType]!!.add(payload)
} }
@ -120,7 +121,7 @@ class BleCommCallbacks(private val aapsLogger: AAPSLogger, private val incomingP
override fun onDescriptorWrite(gatt: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int) { override fun onDescriptorWrite(gatt: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int) {
super.onDescriptorWrite(gatt, descriptor, status) super.onDescriptorWrite(gatt, descriptor, status)
val writeConfirmation = if (status == BluetoothGatt.GATT_SUCCESS) { val writeConfirmation = if (status == BluetoothGatt.GATT_SUCCESS) {
aapsLogger.debug(LTag.PUMPBTCOMM, "OnDescriptor value " + descriptor.value) aapsLogger.debug(LTag.PUMPBTCOMM, "OnDescriptor value " + descriptor.value.toHex())
DescriptorWriteConfirmationUUID(descriptor.uuid.toString()) DescriptorWriteConfirmationUUID(descriptor.uuid.toString())
} else { } else {
DescriptorWriteConfirmationError(status) DescriptorWriteConfirmationError(status)

View file

@ -7,6 +7,7 @@ import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.callbacks.BleCommCallbacks import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.callbacks.BleCommCallbacks
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.* import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.*
import info.nightscout.androidaps.utils.extensions.toHex
import java.util.concurrent.BlockingQueue import java.util.concurrent.BlockingQueue
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException import java.util.concurrent.TimeoutException
@ -48,7 +49,8 @@ class BleIO(private val aapsLogger: AAPSLogger, private val chars: Map<Character
} }
state = IOState.WRITING state = IOState.WRITING
} }
aapsLogger.debug(LTag.PUMPBTCOMM, "BleIO: Sending data on" + characteristic.name + "/" + payload.toString()) aapsLogger.debug(LTag.PUMPBTCOMM, "BleIO: Sending data on " + characteristic.name + "/" + payload.toHex())
aapsLogger.debug(LTag.PUMPBTCOMM, "BleIO: Sending data on " + characteristic.name + "/" + payload.toHex())
val ch = chars[characteristic] val ch = chars[characteristic]
val set = ch!!.setValue(payload) val set = ch!!.setValue(payload)
if (!set) { if (!set) {

View file

@ -7,7 +7,6 @@ class PayloadJoiner() {
private val payload = ByteArrayOutputStream() private val payload = ByteArrayOutputStream()
fun accumulate(packet: BlePacket) { fun accumulate(packet: BlePacket) {
} }
fun bytes(): ByteArray { fun bytes(): ByteArray {

View file

@ -62,7 +62,7 @@ internal class PayloadSplitter(private val payload: ByteArray) {
} }
} }
internal fun ByteArray.crc32(): Long { private fun ByteArray.crc32(): Long {
val crc = CRC32() val crc = CRC32()
crc.update(this) crc.update(this)
return crc.value return crc.value

View file

@ -12,7 +12,7 @@ internal class LTKExchanger(private val aapsLogger: AAPSLogger,private val msgIO
val msg = PairMessage( val msg = PairMessage(
destination = Address(byteArrayOf(1,2,3,4)), destination = Address(byteArrayOf(1,2,3,4)),
source = Address(byteArrayOf(5,6,7,8)), source = Address(byteArrayOf(5,6,7,8)),
payload = "5350313d0004024200032c5350323d000bffc32dbd20030e01000016".hexStringToByteArray(), payload = "545710030100038002420000fffffffe5350313d0004024200032c5350323d000bffc32dbd20030e01000016".hexStringToByteArray(),
sequenceNumber = 1, sequenceNumber = 1,
) )
msgIO.sendMesssage(msg) msgIO.sendMesssage(msg)

View file

@ -10,12 +10,12 @@ abstract class Message(
val ackNumber: Byte = 0.toByte(), val ackNumber: Byte = 0.toByte(),
val eqos: Short = 0.toShort(), // TODO: understand val eqos: Short = 0.toShort(), // TODO: understand
val priority: Boolean = false, val priority: Boolean = false,
val lastMessage: Boolean= false, val lastMessage: Boolean = false,
val gateway: Boolean = false, val gateway: Boolean = false,
val sas: Boolean = false, // TODO: understand val sas: Boolean = false, // TODO: understand
val tfs: Boolean = false, // TODO: understand val tfs: Boolean = false, // TODO: understand
val version: Short = 0.toShort(), val version: Short = 0.toShort(),
) { ) {
fun asByteArray(): ByteArray { fun asByteArray(): ByteArray {
return payload; // TODO implement return payload; // TODO implement

View file

@ -2,19 +2,19 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.BleManager
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.command.BleCommand import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.command.BleCommand
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.command.BleCommandCTS import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.command.BleCommandCTS
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.command.BleCommandHello
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.command.BleCommandRTS import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.command.BleCommandRTS
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.UnexpectedCommandException import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.UnexpectedCommandException
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.PayloadSplitter import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.PayloadSplitter
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) {
fun sendMesssage(msg: Message) { fun sendMesssage(msg: Message) {
bleIO.flushIncomingQueues(); bleIO.flushIncomingQueues()
bleIO.sendAndConfirmPacket(CharacteristicType.CMD, BleCommandRTS().data) bleIO.sendAndConfirmPacket(CharacteristicType.CMD, BleCommandRTS().data)
val expectCTS = bleIO.receivePacket(CharacteristicType.CMD) val expectCTS = bleIO.receivePacket(CharacteristicType.CMD)
if (BleCommand(expectCTS) != BleCommandCTS()) { if (BleCommand(expectCTS) != BleCommandCTS()) {
@ -24,6 +24,7 @@ class MessageIO(private val aapsLogger: AAPSLogger, private val bleIO: BleIO) {
val splitter = PayloadSplitter(payload) val splitter = PayloadSplitter(payload)
val packets = splitter.splitInPackets() val packets = splitter.splitInPackets()
for (packet in packets) { for (packet in packets) {
aapsLogger.debug(LTag.PUMPBTCOMM, "Sending DATA: ", packet.asByteArray().toHex())
bleIO.sendAndConfirmPacket(CharacteristicType.DATA, packet.asByteArray()) bleIO.sendAndConfirmPacket(CharacteristicType.DATA, packet.asByteArray())
} }
// TODO: peek for NACKs // TODO: peek for NACKs
@ -32,10 +33,9 @@ class MessageIO(private val aapsLogger: AAPSLogger, private val bleIO: BleIO) {
throw UnexpectedCommandException(BleCommand(expectSuccess)) throw UnexpectedCommandException(BleCommand(expectSuccess))
} }
// TODO: handle NACKS/FAILS/etc // TODO: handle NACKS/FAILS/etc
bleIO.flushIncomingQueues(); bleIO.flushIncomingQueues()
} }
fun receiveMessage(): Message? { fun receiveMessage(): Message? {
// do the RTS/CTS/data/success dance // do the RTS/CTS/data/success dance
return null return null

View file

@ -1,34 +1,64 @@
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.packet package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.packet
import java.nio.ByteBuffer
sealed class BlePacket { sealed class BlePacket {
abstract fun asByteArray(): ByteArray abstract fun asByteArray(): ByteArray
companion object {
const val MAX_BLE_PACKET_LEN = 30 // we use this as the size allocated for the ByteBuffer
}
} }
data class FirstBlePacket(val totalFragments: Byte, val payload: ByteArray, val size: Byte = 0, val crc32: Long? = null) : BlePacket() { data class FirstBlePacket(val totalFragments: Byte, val payload: ByteArray, val size: Byte? = null, val crc32: Long? = null) : BlePacket() {
override fun asByteArray(): ByteArray { override fun asByteArray(): ByteArray {
TODO("Not yet implemented") val bb = ByteBuffer
.allocate(MAX_BLE_PACKET_LEN)
.put(0) // index
.put(totalFragments) // # of fragments except FirstBlePacket and LastOptionalPlusOneBlePacket
crc32?.let {
bb.putInt(crc32.toInt())
}
size?.let {
bb.put(size)
}
bb.put(payload)
val ret = ByteArray(bb.position())
bb.flip()
bb.get(ret)
return ret
} }
} }
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 asByteArray(): ByteArray {
TODO("Not yet implemented") return byteArrayOf(index) + payload
} }
} }
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 asByteArray(): ByteArray {
TODO("Not yet implemented") val bb = ByteBuffer
.allocate(MAX_BLE_PACKET_LEN)
.put(index)
.put(size)
.putInt(crc32.toInt())
.put(payload)
val ret = ByteArray(bb.position())
bb.flip()
bb.get(ret)
return ret
} }
} }
data class LastOptionalPlusOneBlePacket(val index: Byte, val payload: ByteArray) : BlePacket() { data class LastOptionalPlusOneBlePacket(val index: Byte, val payload: ByteArray) : BlePacket() {
override fun asByteArray(): ByteArray { override fun asByteArray(): ByteArray {
TODO("Not yet implemented") return byteArrayOf(index) + payload
} }
} }

View file

@ -9,6 +9,7 @@ import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.pump.omnipod.common.ui.wizard.activation.viewmodel.action.InitializePodViewModel import info.nightscout.androidaps.plugins.pump.omnipod.common.ui.wizard.activation.viewmodel.action.InitializePodViewModel
import info.nightscout.androidaps.plugins.pump.omnipod.dash.R import info.nightscout.androidaps.plugins.pump.omnipod.dash.R
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.OmnipodDashBleManager import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.OmnipodDashBleManager
import org.apache.commons.lang3.exception.ExceptionUtils
import javax.inject.Inject import javax.inject.Inject
class DashInitializePodViewModel @Inject constructor(private val aapsLogger: AAPSLogger, class DashInitializePodViewModel @Inject constructor(private val aapsLogger: AAPSLogger,
@ -27,7 +28,8 @@ class DashInitializePodViewModel @Inject constructor(private val aapsLogger: AAP
try { try {
bleManager.activateNewPod() bleManager.activateNewPod()
} catch (e: Exception) { } catch (e: Exception) {
aapsLogger.error(LTag.PUMP, "TEST ACTIVATE Exception" + e.toString()) aapsLogger.error(LTag.PUMP, "TEST ACTIVATE Exception" + e.toString() + ExceptionUtils.getStackTrace(e))
} }
} }
@ -39,4 +41,4 @@ class DashInitializePodViewModel @Inject constructor(private val aapsLogger: AAP
@StringRes @StringRes
override fun getTextId() = R.string.omnipod_dash_pod_activation_wizard_initialize_pod_text override fun getTextId() = R.string.omnipod_dash_pod_activation_wizard_initialize_pod_text
} }