dash/ble: support both 1 and 2 byte command

It seems that the PDM is sending 1 byte commands and the POD answers
with 2 byte commands.

Add logging for decrypted responses.

I think `eqos` means that we are expecting an ACK for the last message.
Read (and log for now) a pending message if the POD is trying to sending it back while we want
to send a command.
This commit is contained in:
Andrei Vereha 2021-03-08 22:47:56 +01:00
parent db51b762ca
commit c337b52aa0
5 changed files with 41 additions and 19 deletions

View file

@ -14,7 +14,7 @@ class BleCommandFail : BleCommand(BleCommandType.FAIL)
open class BleCommand(val data: ByteArray) { open class BleCommand(val data: ByteArray) {
constructor(type: BleCommandType) : this(byteArrayOf(type.value, 0)) constructor(type: BleCommandType) : this(byteArrayOf(type.value))
constructor(type: BleCommandType, payload: ByteArray) : this( constructor(type: BleCommandType, payload: ByteArray) : this(
byteArrayOf(type.value) + payload byteArrayOf(type.value) + payload
@ -36,4 +36,5 @@ open class BleCommand(val data: ByteArray) {
override fun hashCode(): Int { override fun hashCode(): Int {
return data.contentHashCode() return data.contentHashCode()
} }
} }

View file

@ -7,9 +7,7 @@ enum class BleCommandType(val value: Byte) {
ABORT(0x03.toByte()), ABORT(0x03.toByte()),
SUCCESS(0x04.toByte()), SUCCESS(0x04.toByte()),
FAIL(0x05.toByte()), FAIL(0x05.toByte()),
HELLO( HELLO(0x06.toByte());
0x06.toByte()
);
companion object { companion object {

View file

@ -32,6 +32,7 @@ class EnDecrypt(private val aapsLogger: AAPSLogger, private val nonce: Nonce, pr
) )
val decryptedPayload = ByteArray(payload.size - MAC_SIZE) val decryptedPayload = ByteArray(payload.size - MAC_SIZE)
cipher.processPacket(payload, 0, payload.size, decryptedPayload, 0) cipher.processPacket(payload, 0, payload.size, decryptedPayload, 0)
aapsLogger.debug(LTag.PUMPBTCOMM, "Decrypted payload ${decryptedPayload.toHex()}")
return msg.copy(payload = decryptedPayload) return msg.copy(payload = decryptedPayload)
} }

View file

@ -8,17 +8,34 @@ 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.pod.command.base.CommandType
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) {
fun sendMessage(msg: MessagePacket) { private fun expectCommandType(actual: BleCommand, expected: BleCommand) {
if (actual.data.isEmpty()) {
throw UnexpectedCommandException(actual)
}
// first byte is the command type
if (actual.data[0] == expected.data[0]) {
return
}
throw UnexpectedCommandException(actual)
}
fun sendMessage(msg: MessagePacket):MessagePacket? {
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 (expectCTS.isEmpty()) {
throw UnexpectedCommandException(BleCommand(expectCTS)) throw UnexpectedCommandException(BleCommand(expectCTS))
} }
//if (expectCTS[0] == BleCommandType.RTS.value) {
//the pod is trying to send something, after we sent RTS, let's read it
//}
expectCommandType(BleCommand(expectCTS), BleCommandCTS())
val payload = msg.asByteArray() val payload = msg.asByteArray()
aapsLogger.debug(LTag.PUMPBTCOMM, "Sending message: ${payload.toHex()}") aapsLogger.debug(LTag.PUMPBTCOMM, "Sending message: ${payload.toHex()}")
val splitter = PayloadSplitter(payload) val splitter = PayloadSplitter(payload)
@ -29,17 +46,18 @@ class MessageIO(private val aapsLogger: AAPSLogger, private val bleIO: BleIO) {
} }
// TODO: peek for NACKs // TODO: peek for NACKs
val expectSuccess = bleIO.receivePacket(CharacteristicType.CMD) val expectSuccess = bleIO.receivePacket(CharacteristicType.CMD)
if (BleCommand(expectSuccess) != BleCommandSuccess()) { expectCommandType(BleCommand(expectSuccess), BleCommandSuccess())
throw UnexpectedCommandException(BleCommand(expectSuccess))
}
// TODO: handle NACKS/FAILS/etc // TODO: handle NACKS/FAILS/etc
return null
} }
fun receiveMessage(): MessagePacket { // TODO: use higher timeout when receiving the first packet in a message
val expectRTS = bleIO.receivePacket(CharacteristicType.CMD) fun receiveMessage( firstCmd: ByteArray? = null): MessagePacket {
if (BleCommand(expectRTS) != BleCommandRTS()) { var expectRTS = firstCmd
throw UnexpectedCommandException(BleCommand(expectRTS)) if (expectRTS == null) {
expectRTS = bleIO.receivePacket(CharacteristicType.CMD)
} }
expectCommandType(BleCommand(expectRTS), BleCommandRTS())
bleIO.sendAndConfirmPacket(CharacteristicType.CMD, BleCommandCTS().data) bleIO.sendAndConfirmPacket(CharacteristicType.CMD, BleCommandCTS().data)
try { try {
val joiner = PayloadJoiner(bleIO.receivePacket(CharacteristicType.DATA)) val joiner = PayloadJoiner(bleIO.receivePacket(CharacteristicType.DATA))

View file

@ -31,12 +31,14 @@ class Session(
*/ */
fun sendCommand(cmd: Command): Response { fun sendCommand(cmd: Command): Response {
sessionKeys.msgSequenceNumber++ sessionKeys.msgSequenceNumber++
aapsLogger.debug(LTag.PUMPBTCOMM, "Sending command: ${cmd.encoded.toHex()}") aapsLogger.debug(LTag.PUMPBTCOMM, "Sending command: ${cmd.encoded.toHex()} in packet $cmd")
val msg = getCmdMessage(cmd) val msg = getCmdMessage(cmd)
aapsLogger.debug(LTag.PUMPBTCOMM, "Sending command(wrapped): ${msg.payload.toHex()}") aapsLogger.debug(LTag.PUMPBTCOMM, "Sending command(wrapped): ${msg.payload.toHex()}")
msgIO.sendMessage(msg) val reply = msgIO.sendMessage(msg)
if (reply != null) { // TODO : this means the last ACK was not received, send it again?
aapsLogger.debug(LTag.PUMPBTCOMM, "Received a message with payload instead of CTS: ${reply.payload.toHex()} in packet $reply")
}
val responseMsg = msgIO.receiveMessage() val responseMsg = msgIO.receiveMessage()
val decrypted = enDecrypt.decrypt(responseMsg) val decrypted = enDecrypt.decrypt(responseMsg)
aapsLogger.debug(LTag.PUMPBTCOMM, "Received response: $decrypted") aapsLogger.debug(LTag.PUMPBTCOMM, "Received response: $decrypted")
@ -44,13 +46,15 @@ class Session(
sessionKeys.msgSequenceNumber++ sessionKeys.msgSequenceNumber++
val ack = getAck(responseMsg) val ack = getAck(responseMsg)
aapsLogger.debug(LTag.PUMPBTCOMM, "Sending ACK: ${ack.payload.toHex()}") aapsLogger.debug(LTag.PUMPBTCOMM, "Sending ACK: ${ack.payload.toHex()} in packet $ack")
msgIO.sendMessage(ack) msgIO.sendMessage(ack)
return response return response
} }
private fun parseResponse(decrypted: MessagePacket): Response { private fun parseResponse(decrypted: MessagePacket): Response {
val payload = parseKeys(arrayOf(RESPONSE_PREFIX), decrypted.payload)[0] val payload = parseKeys(arrayOf(RESPONSE_PREFIX), decrypted.payload)[0]
aapsLogger.info(LTag.PUMPBTCOMM, "Received decrypted response: ${payload.toHex()} in packet: $decrypted")
return NakResponse(payload) return NakResponse(payload)
} }
@ -61,9 +65,9 @@ class Session(
source = myId, source = myId,
destination = podId, destination = podId,
payload = ByteArray(0), payload = ByteArray(0),
eqos = 1, eqos = 0,
ack = true, ack = true,
ackNumber = response.sequenceNumber.inc() ackNumber = (response.sequenceNumber.toInt()+1).toByte()
) )
return enDecrypt.encrypt((msg)) return enDecrypt.encrypt((msg))
} }