ble: sending the first SP1/SP2 pairing command
from the fake pod logs ``` INFO[0007] Received SP1 SP2 payload 5350313d0004000010912c5350323d000bffc32dbd08030e0100008a TRAC[0007] Read field: SP1= :: 00001091 :: 4 TRAC[0007] Read field: ,SP2= :: ffc32dbd08030e0100008a :: 11 INFO[0007] Received SP1 SP2: 00001091 :: ffc32dbd08030e0100008a ```
This commit is contained in:
parent
318c0c642c
commit
badf8fe24d
6 changed files with 83 additions and 38 deletions
|
@ -4,7 +4,7 @@ import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.BleIO
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.BleIO
|
||||||
|
|
||||||
data class LTK(val ltk: ByteArray, val noncePrefix: ByteArray) {
|
data class LTK(val ltk: ByteArray, val noncePrefix: ByteArray) {
|
||||||
init{
|
init {
|
||||||
require(ltk.size == 16)
|
require(ltk.size == 16)
|
||||||
require(noncePrefix.size == 16)
|
require(noncePrefix.size == 16)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.ltk
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.ltk
|
||||||
|
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.OmnipodDashBleManagerImpl
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.OmnipodDashBleManagerImpl
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.Id
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.Id
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.MessageIO
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.MessageIO
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.StringLengthPrefixEncoding
|
||||||
import info.nightscout.androidaps.utils.extensions.hexStringToByteArray
|
import info.nightscout.androidaps.utils.extensions.hexStringToByteArray
|
||||||
import info.nightscout.androidaps.utils.extensions.toHex
|
|
||||||
import java.nio.ByteBuffer
|
|
||||||
|
|
||||||
internal class LTKExchanger(private val aapsLogger: AAPSLogger, private val msgIO: MessageIO) {
|
internal class LTKExchanger(private val aapsLogger: AAPSLogger, private val msgIO: MessageIO) {
|
||||||
|
|
||||||
|
@ -48,8 +46,10 @@ internal class LTKExchanger(private val aapsLogger: AAPSLogger, private val msgI
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sp1sp2(sp1: ByteArray, sp2: ByteArray, seq: Byte, controllerId: Id, nodeId: Id): PairMessage {
|
fun sp1sp2(sp1: ByteArray, sp2: ByteArray, seq: Byte, controllerId: Id, nodeId: Id): PairMessage {
|
||||||
val payload = "SP1=".toByteArray() + sp1
|
val payload = StringLengthPrefixEncoding.formatKeys(
|
||||||
",SP2=".toByteArray() + sp2
|
arrayOf("SP1=", ",SP2="),
|
||||||
|
arrayOf(sp1, sp2),
|
||||||
|
)
|
||||||
return PairMessage(
|
return PairMessage(
|
||||||
sequenceNumber = seq,
|
sequenceNumber = seq,
|
||||||
source = controllerId,
|
source = controllerId,
|
||||||
|
|
|
@ -13,7 +13,6 @@ data class PairMessage(
|
||||||
type=MessageType.PAIRING,
|
type=MessageType.PAIRING,
|
||||||
source=source,
|
source=source,
|
||||||
destination = destination,
|
destination = destination,
|
||||||
encryptedPayload=false,
|
|
||||||
payload=payload,
|
payload=payload,
|
||||||
sequenceNumber=sequenceNumber,
|
sequenceNumber=sequenceNumber,
|
||||||
sas=true, // TODO: understand why this is true for PairMessages
|
sas=true, // TODO: understand why this is true for PairMessages
|
||||||
|
|
|
@ -26,7 +26,7 @@ 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) != BleCommandCTS()) {
|
if (BleCommand(expectSuccess) != BleCommandSuccess()) {
|
||||||
throw UnexpectedCommandException(BleCommand(expectSuccess))
|
throw UnexpectedCommandException(BleCommand(expectSuccess))
|
||||||
}
|
}
|
||||||
// TODO: handle NACKS/FAILS/etc
|
// TODO: handle NACKS/FAILS/etc
|
||||||
|
|
|
@ -1,34 +1,10 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message
|
||||||
|
|
||||||
import java.io.DataOutput
|
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* MessagePacket contains header and raw payload for a message
|
* MessagePacket contains header and raw payload for a message
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class Flag:Byte{
|
|
||||||
fun set(idx: Byte, val: Boolean) {
|
|
||||||
val mask = 1 <lsh (7-idx)
|
|
||||||
|
|
||||||
}
|
|
||||||
func (f *flag) set(index byte, val bool) {
|
|
||||||
var mask flag = 1 << (7 - index)
|
|
||||||
if !val {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
*f |= mask
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f flag) get(index byte) byte {
|
|
||||||
var mask flag = 1 << (7 - index)
|
|
||||||
if f&mask == 0 {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class MessagePacket(
|
data class MessagePacket(
|
||||||
val type: MessageType,
|
val type: MessageType,
|
||||||
val source: Id,
|
val source: Id,
|
||||||
|
@ -46,19 +22,70 @@ data class MessagePacket(
|
||||||
val version: Short = 0.toShort()) {
|
val version: Short = 0.toShort()) {
|
||||||
|
|
||||||
fun asByteArray(): ByteArray {
|
fun asByteArray(): ByteArray {
|
||||||
val v = ByteBuffer.allocate(16+ payload.size)
|
val bb = ByteBuffer.allocate(16 + payload.size)
|
||||||
v.put(MAGIC_PATTERN.toByteArray())
|
bb.put(MAGIC_PATTERN.toByteArray())
|
||||||
val f1: Byte=0
|
|
||||||
|
|
||||||
|
val f1 = Flag()
|
||||||
|
f1.set(0, this.version.toInt() and 4 != 0)
|
||||||
|
f1.set(1, this.version.toInt() and 2 != 0)
|
||||||
|
f1.set(2, this.version.toInt() and 1 != 0)
|
||||||
|
f1.set(3, this.sas)
|
||||||
|
f1.set(4, this.tfs)
|
||||||
|
f1.set(5, this.eqos.toInt() and 4 != 0)
|
||||||
|
f1.set(6, this.eqos.toInt() and 2 != 0)
|
||||||
|
f1.set(7, this.eqos.toInt() and 1 != 0)
|
||||||
|
|
||||||
return this.payload
|
val f2 = Flag()
|
||||||
|
f2.set(0, this.ack)
|
||||||
|
f2.set(1, this.priority)
|
||||||
|
f2.set(2, this.lastMessage)
|
||||||
|
f2.set(3, this.gateway)
|
||||||
|
f2.set(4, this.type.value.toInt() and 8 != 0)
|
||||||
|
f2.set(5, this.type.value.toInt() and 4 != 0)
|
||||||
|
f2.set(6, this.type.value.toInt() and 2 != 0)
|
||||||
|
f2.set(7, this.type.value.toInt() and 1 != 0)
|
||||||
|
|
||||||
|
bb.put(f1.value.toByte())
|
||||||
|
bb.put(f2.value.toByte())
|
||||||
|
bb.put(this.sequenceNumber)
|
||||||
|
bb.put(this.ackNumber)
|
||||||
|
|
||||||
|
bb.put((this.payload.size ushr 3).toByte())
|
||||||
|
bb.put((this.payload.size shl 5).toByte())
|
||||||
|
|
||||||
|
bb.put(this.source.address)
|
||||||
|
bb.put(this.destination.address)
|
||||||
|
|
||||||
|
bb.put(this.payload)
|
||||||
|
|
||||||
|
val ret = ByteArray(bb.position())
|
||||||
|
bb.flip()
|
||||||
|
bb.get(ret)
|
||||||
|
|
||||||
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private val MAGIC_PATTERN = "TW" // all messages start with this string
|
private val MAGIC_PATTERN = "TW" // all messages start with this string
|
||||||
|
|
||||||
fun parse(payload: ByteArray): MessagePacket {
|
fun parse(payload: ByteArray): MessagePacket {
|
||||||
TODO("implement message header parsing")
|
TODO("implement message header parsing")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Flag(var value: Int=0) {
|
||||||
|
|
||||||
|
fun set(idx: Byte, set: Boolean) {
|
||||||
|
val mask = 1 shl (7 - idx)
|
||||||
|
if (!set)
|
||||||
|
return
|
||||||
|
value = value or mask
|
||||||
|
}
|
||||||
|
|
||||||
|
fun get(idx: Byte): Boolean {
|
||||||
|
val mask = 1 shl (7 - idx)
|
||||||
|
return value and mask != 0
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,17 +1,36 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* String prefix and length encoding and decoding. Example message:
|
* String prefix and length encoding and decoding. Example message:
|
||||||
*/
|
*/
|
||||||
class StringLengthPrefixEncoding {
|
class StringLengthPrefixEncoding {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun parseKeys(keys: List<String>): List<ByteArray> {
|
fun parseKeys(keys: List<String>): List<ByteArray> {
|
||||||
TODO("not implemented")
|
TODO("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun formatKeys(keys: List<String>, payload: List<ByteArray>, addLength: Boolean): ByteArray {
|
fun formatKeys(keys: Array<String>, payloads: Array<ByteArray>): ByteArray {
|
||||||
TODO("not implemented")
|
val payloadTotalSize = payloads.fold(0) { acc, i -> acc + i.size }
|
||||||
|
val keyTotalSize = keys.fold(0) { acc, i -> acc + i.length }
|
||||||
|
|
||||||
|
val bb = ByteBuffer.allocate(2 * keys.size + keyTotalSize + payloadTotalSize)
|
||||||
|
for (idx in keys.indices) {
|
||||||
|
val k = keys[idx]
|
||||||
|
val payload = payloads[idx]
|
||||||
|
bb.put(k.toByteArray())
|
||||||
|
bb.putShort(payload.size.toShort())
|
||||||
|
bb.put(payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
val ret = ByteArray(bb.position())
|
||||||
|
bb.flip()
|
||||||
|
bb.get(ret)
|
||||||
|
|
||||||
|
return ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue