WIP: sp1sp2
This commit is contained in:
parent
4e6ad3f113
commit
318c0c642c
8 changed files with 165 additions and 27 deletions
|
@ -95,7 +95,7 @@ class OmnipodDashBleManagerImpl @Inject constructor(private val context: Context
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private const val CONNECT_TIMEOUT_MS = 5000
|
private const val CONNECT_TIMEOUT_MS = 5000
|
||||||
private const val CONTROLLER_ID = 4242 // TODO read from preferences or somewhere else.
|
public const val CONTROLLER_ID = 4242 // TODO read from preferences or somewhere else.
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,35 +1,65 @@
|
||||||
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.plugins.pump.omnipod.dash.driver.comm.message.Address
|
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.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.MessagePacket
|
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.MessageType
|
|
||||||
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) {
|
||||||
|
|
||||||
fun negociateLTKAndNonce(): LTK? {
|
fun negociateLTKAndNonce(): LTK? {
|
||||||
// send SP1, SP2
|
// send SP1, SP2
|
||||||
|
// TODO: get this from somewhere(preferences?)
|
||||||
|
var seq: Byte = 1
|
||||||
|
val controllerId = Id.fromInt(OmnipodDashBleManagerImpl.CONTROLLER_ID)
|
||||||
|
val nodeId = controllerId.increment()
|
||||||
|
|
||||||
|
var sp1sp2 = sp1sp2(nodeId.address, sp2(), seq, controllerId, nodeId)
|
||||||
|
msgIO.sendMesssage(sp1sp2.messagePacket)
|
||||||
|
/*
|
||||||
|
var sps1 =
|
||||||
|
msgIO.sendMesssage(sps1.messagePacket)
|
||||||
// send SPS1
|
// send SPS1
|
||||||
// read SPS1
|
// read SPS1
|
||||||
|
val podSps1 = msgIO.receiveMessage()
|
||||||
|
|
||||||
// send SPS2
|
// send SPS2
|
||||||
|
var sps2 = PairMessage()
|
||||||
|
msgIO.sendMesssage(sps2.messagePacket)
|
||||||
// read SPS2
|
// read SPS2
|
||||||
|
val podSps2 = msgIO.receiveMessage()
|
||||||
|
|
||||||
// send SP0GP0
|
// send SP0GP0
|
||||||
|
msgIO.sendMesssage(sps2.messagePacket)
|
||||||
// read P0
|
// read P0
|
||||||
|
val p0 = msgIO.receiveMessage()
|
||||||
val msg = MessagePacket(
|
*/
|
||||||
destination = Address(byteArrayOf(1,2,3,4)),
|
|
||||||
source = Address(byteArrayOf(5,6,7,8)),
|
|
||||||
payload = "545710030100038002420000fffffffe5350313d0004024200032c5350323d000bffc32dbd20030e01000016".hexStringToByteArray(),
|
|
||||||
sequenceNumber = 1,
|
|
||||||
type = MessageType.PAIRING,
|
|
||||||
)
|
|
||||||
msgIO.sendMesssage(msg)
|
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
private fun sp2(): ByteArray {
|
||||||
|
// This is GetPodStatus command, with page 0 parameter.
|
||||||
|
// We could replace that in the future with the serialized GetPodStatus()
|
||||||
|
return GET_POD_STATUS_HEX_COMMAND.hexStringToByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sp1sp2(sp1: ByteArray, sp2: ByteArray, seq: Byte, controllerId: Id, nodeId: Id): PairMessage {
|
||||||
|
val payload = "SP1=".toByteArray() + sp1
|
||||||
|
",SP2=".toByteArray() + sp2
|
||||||
|
return PairMessage(
|
||||||
|
sequenceNumber = seq,
|
||||||
|
source = controllerId,
|
||||||
|
destination = nodeId,
|
||||||
|
payload = payload,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private val GET_POD_STATUS_HEX_COMMAND = "ffc32dbd08030e0100008a" // TODO for now we are assuming this command is build out of constant parameters, use a proper command builder for that.
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,21 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.ltk
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.ltk
|
||||||
|
|
||||||
class PairMessage
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.Id
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.MessagePacket
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.MessageType
|
||||||
|
|
||||||
|
data class PairMessage(
|
||||||
|
val sequenceNumber: Byte,
|
||||||
|
val source: Id,
|
||||||
|
val destination: Id,
|
||||||
|
val payload: ByteArray,
|
||||||
|
val messagePacket: MessagePacket = MessagePacket(
|
||||||
|
type=MessageType.PAIRING,
|
||||||
|
source=source,
|
||||||
|
destination = destination,
|
||||||
|
encryptedPayload=false,
|
||||||
|
payload=payload,
|
||||||
|
sequenceNumber=sequenceNumber,
|
||||||
|
sas=true, // TODO: understand why this is true for PairMessages
|
||||||
|
),
|
||||||
|
) {}
|
|
@ -1,7 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message
|
|
||||||
|
|
||||||
data class Address(val address: ByteArray) {
|
|
||||||
init {
|
|
||||||
require(address.size == 4)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.logging.LTag
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.ltk.LTKExchanger
|
||||||
|
import info.nightscout.androidaps.utils.extensions.toHex
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
|
data class Id(val address: ByteArray) {
|
||||||
|
init {
|
||||||
|
require(address.size == 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to obtain podId from controllerId
|
||||||
|
*/
|
||||||
|
fun increment(): Id {
|
||||||
|
val nodeId = address.copyOf()
|
||||||
|
nodeId[3] = (nodeId[3].toInt() and -4).toByte()
|
||||||
|
nodeId[3] = (nodeId[3].toInt() or PERIPHERAL_NODE_INDEX).toByte()
|
||||||
|
return Id(nodeId)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
val asInt = ByteBuffer.wrap(address).getInt()
|
||||||
|
return "${asInt}/${address.toHex()}"
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val PERIPHERAL_NODE_INDEX = 1 // TODO: understand the meaning of this value. It comes from preferences
|
||||||
|
|
||||||
|
fun fromInt(v: Int): Id {
|
||||||
|
return Id(ByteBuffer.allocate(4).putInt(v).array())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message
|
||||||
|
|
||||||
|
interface Message {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
fun messagePacket(): MessagePacket
|
||||||
|
}
|
|
@ -1,9 +1,38 @@
|
||||||
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
|
||||||
|
|
||||||
|
/***
|
||||||
|
* 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: Address,
|
val source: Id,
|
||||||
val destination: Address,
|
val destination: Id,
|
||||||
val payload: ByteArray,
|
val payload: ByteArray,
|
||||||
val sequenceNumber: Byte,
|
val sequenceNumber: Byte,
|
||||||
val ack: Boolean = false,
|
val ack: Boolean = false,
|
||||||
|
@ -17,11 +46,17 @@ data class MessagePacket(
|
||||||
val version: Short = 0.toShort()) {
|
val version: Short = 0.toShort()) {
|
||||||
|
|
||||||
fun asByteArray(): ByteArray {
|
fun asByteArray(): ByteArray {
|
||||||
// TODO: implement proper serialization
|
val v = ByteBuffer.allocate(16+ payload.size)
|
||||||
|
v.put(MAGIC_PATTERN.toByteArray())
|
||||||
|
val f1: Byte=0
|
||||||
|
|
||||||
|
|
||||||
return this.payload
|
return this.payload
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
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")
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message
|
||||||
|
|
||||||
|
/***
|
||||||
|
* String prefix and length encoding and decoding. Example message:
|
||||||
|
*/
|
||||||
|
class StringLengthPrefixEncoding {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun parseKeys(keys: List<String>): List<ByteArray> {
|
||||||
|
TODO("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun formatKeys(keys: List<String>, payload: List<ByteArray>, addLength: Boolean): ByteArray {
|
||||||
|
TODO("not implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue