dash ble: detekt
This commit is contained in:
parent
c1426941cf
commit
6d2d5a7e76
7 changed files with 98 additions and 106 deletions
|
@ -148,6 +148,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
it == mapProfileToBasalProgram(profile)
|
it == mapProfileToBasalProgram(profile)
|
||||||
} ?: true
|
} ?: true
|
||||||
|
|
||||||
|
|
||||||
override fun lastDataTime(): Long {
|
override fun lastDataTime(): Long {
|
||||||
return podStateManager.lastConnection
|
return podStateManager.lastConnection
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,9 +46,7 @@ class OmnipodDashBleManagerImpl @Inject constructor(
|
||||||
throw BusyException()
|
throw BusyException()
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
val conn = connection ?: throw NotConnectedException("Not connected")
|
val session = assertSessionEstablished()
|
||||||
|
|
||||||
val session = conn.session ?: throw NotConnectedException("Missing session")
|
|
||||||
|
|
||||||
emitter.onNext(PodEvent.CommandSending(cmd))
|
emitter.onNext(PodEvent.CommandSending(cmd))
|
||||||
when (session.sendCommand(cmd)) {
|
when (session.sendCommand(cmd)) {
|
||||||
|
@ -84,6 +82,12 @@ class OmnipodDashBleManagerImpl @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun assertSessionEstablished(): Session {
|
||||||
|
val conn = assertConnected()
|
||||||
|
return conn.session
|
||||||
|
?: throw NotConnectedException("Missing session")
|
||||||
|
}
|
||||||
|
|
||||||
override fun getStatus(): ConnectionStatus {
|
override fun getStatus(): ConnectionStatus {
|
||||||
// TODO is this used?
|
// TODO is this used?
|
||||||
var s: ConnectionStatus
|
var s: ConnectionStatus
|
||||||
|
@ -135,8 +139,9 @@ class OmnipodDashBleManagerImpl @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun establishSession(msgSeq: Byte) {
|
private fun establishSession(msgSeq: Byte) {
|
||||||
val conn = connection ?: throw FailedToConnectException("connection lost")
|
val conn = assertConnected()
|
||||||
val ltk: ByteArray = podState.ltk ?: throw FailedToConnectException("Missing LTK, activate the pod first")
|
|
||||||
|
val ltk = assertPaired()
|
||||||
|
|
||||||
val uniqueId = podState.uniqueId
|
val uniqueId = podState.uniqueId
|
||||||
val podId = uniqueId?.let { Id.fromLong(uniqueId) }
|
val podId = uniqueId?.let { Id.fromLong(uniqueId) }
|
||||||
|
@ -149,7 +154,7 @@ class OmnipodDashBleManagerImpl @Inject constructor(
|
||||||
if (newSqn != null) {
|
if (newSqn != null) {
|
||||||
aapsLogger.info(LTag.PUMPBTCOMM, "Updating EAP SQN to: $newSqn")
|
aapsLogger.info(LTag.PUMPBTCOMM, "Updating EAP SQN to: $newSqn")
|
||||||
podState.eapAkaSequenceNumber = newSqn.toLong()
|
podState.eapAkaSequenceNumber = newSqn.toLong()
|
||||||
var newSqn = conn.establishSession(ltk, msgSeq, myId, podId, podState.increaseEapAkaSequenceNumber())
|
newSqn = conn.establishSession(ltk, msgSeq, myId, podId, podState.increaseEapAkaSequenceNumber())
|
||||||
if (newSqn != null) {
|
if (newSqn != null) {
|
||||||
throw SessionEstablishmentException("Received resynchronization SQN for the second time")
|
throw SessionEstablishmentException("Received resynchronization SQN for the second time")
|
||||||
}
|
}
|
||||||
|
@ -158,6 +163,16 @@ class OmnipodDashBleManagerImpl @Inject constructor(
|
||||||
podState.commitEapAkaSequenceNumber()
|
podState.commitEapAkaSequenceNumber()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun assertPaired(): ByteArray {
|
||||||
|
return podState.ltk
|
||||||
|
?: throw FailedToConnectException("Missing LTK, activate the pod first")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assertConnected(): Connection {
|
||||||
|
return connection
|
||||||
|
?: throw FailedToConnectException("connection lost")
|
||||||
|
}
|
||||||
|
|
||||||
override fun pairNewPod(): Observable<PodEvent> = Observable.create { emitter ->
|
override fun pairNewPod(): Observable<PodEvent> = Observable.create { emitter ->
|
||||||
if (!busy.compareAndSet(false, true)) {
|
if (!busy.compareAndSet(false, true)) {
|
||||||
throw BusyException()
|
throw BusyException()
|
||||||
|
|
|
@ -15,7 +15,7 @@ data class MessagePacket(
|
||||||
val sequenceNumber: Byte,
|
val sequenceNumber: Byte,
|
||||||
val ack: Boolean = false,
|
val ack: Boolean = false,
|
||||||
val ackNumber: Byte = 0.toByte(),
|
val ackNumber: Byte = 0.toByte(),
|
||||||
val eqos: Short = 0.toShort(), // TODO: understand. Seems to be set to 1 for commands
|
val eqos: Short = 0.toShort(),
|
||||||
val priority: Boolean = false,
|
val priority: Boolean = false,
|
||||||
val lastMessage: Boolean = false,
|
val lastMessage: Boolean = false,
|
||||||
val gateway: Boolean = false,
|
val gateway: Boolean = false,
|
||||||
|
|
|
@ -42,7 +42,7 @@ class PayloadJoiner(private val firstPacket: ByteArray) {
|
||||||
oneExtraPacket = lastPacket.oneExtraPacket
|
oneExtraPacket = lastPacket.oneExtraPacket
|
||||||
}
|
}
|
||||||
|
|
||||||
idx > fullFragments && oneExtraPacket -> {
|
idx == fullFragments+1 && oneExtraPacket -> {
|
||||||
fragments.add(LastOptionalPlusOneBlePacket.parse(packet))
|
fragments.add(LastOptionalPlusOneBlePacket.parse(packet))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,29 +6,11 @@ import java.util.zip.CRC32
|
||||||
internal class PayloadSplitter(private val payload: ByteArray) {
|
internal class PayloadSplitter(private val payload: ByteArray) {
|
||||||
|
|
||||||
fun splitInPackets(): List<BlePacket> {
|
fun splitInPackets(): List<BlePacket> {
|
||||||
|
if (payload.size <= FirstBlePacket.CAPACITY_WITH_THE_OPTIONAL_PLUS_ONE_PACKET) {
|
||||||
|
return splitInOnePacket()
|
||||||
|
}
|
||||||
val ret = ArrayList<BlePacket>()
|
val ret = ArrayList<BlePacket>()
|
||||||
val crc32 = payload.crc32()
|
val crc32 = payload.crc32()
|
||||||
if (payload.size <= FirstBlePacket.CAPACITY_WITH_THE_OPTIONAL_PLUS_ONE_PACKET) {
|
|
||||||
val end = min(FirstBlePacket.CAPACITY_WITHOUT_MIDDLE_PACKETS, payload.size)
|
|
||||||
ret.add(
|
|
||||||
FirstBlePacket(
|
|
||||||
fullFragments = 0,
|
|
||||||
payload = payload.copyOfRange(0, end),
|
|
||||||
size = payload.size.toByte(),
|
|
||||||
crc32 = crc32
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if (payload.size > FirstBlePacket.CAPACITY_WITHOUT_MIDDLE_PACKETS) {
|
|
||||||
ret.add(
|
|
||||||
LastOptionalPlusOneBlePacket(
|
|
||||||
index = 1,
|
|
||||||
payload = payload.copyOfRange(end, payload.size),
|
|
||||||
size = (payload.size - end).toByte()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
val middleFragments = (payload.size - FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS) / MiddleBlePacket.CAPACITY
|
val middleFragments = (payload.size - FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS) / MiddleBlePacket.CAPACITY
|
||||||
val rest =
|
val rest =
|
||||||
(
|
(
|
||||||
|
@ -42,17 +24,10 @@ internal class PayloadSplitter(private val payload: ByteArray) {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
for (i in 1..middleFragments) {
|
for (i in 1..middleFragments) {
|
||||||
val p = if (i == 1) {
|
val p = payload.copyOfRange(
|
||||||
payload.copyOfRange(
|
|
||||||
FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS,
|
|
||||||
FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS + MiddleBlePacket.CAPACITY
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
payload.copyOfRange(
|
|
||||||
FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS + (i - 1) * MiddleBlePacket.CAPACITY,
|
FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS + (i - 1) * MiddleBlePacket.CAPACITY,
|
||||||
FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS + i * MiddleBlePacket.CAPACITY
|
FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS + i * MiddleBlePacket.CAPACITY
|
||||||
)
|
)
|
||||||
}
|
|
||||||
ret.add(
|
ret.add(
|
||||||
MiddleBlePacket(
|
MiddleBlePacket(
|
||||||
index = i.toByte(),
|
index = i.toByte(),
|
||||||
|
@ -88,6 +63,30 @@ internal class PayloadSplitter(private val payload: ByteArray) {
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun splitInOnePacket(): List<BlePacket> {
|
||||||
|
val ret = ArrayList<BlePacket>()
|
||||||
|
val crc32 = payload.crc32()
|
||||||
|
val end = min(FirstBlePacket.CAPACITY_WITHOUT_MIDDLE_PACKETS, payload.size)
|
||||||
|
ret.add(
|
||||||
|
FirstBlePacket(
|
||||||
|
fullFragments = 0,
|
||||||
|
payload = payload.copyOfRange(0, end),
|
||||||
|
size = payload.size.toByte(),
|
||||||
|
crc32 = crc32
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if (payload.size > FirstBlePacket.CAPACITY_WITHOUT_MIDDLE_PACKETS) {
|
||||||
|
ret.add(
|
||||||
|
LastOptionalPlusOneBlePacket(
|
||||||
|
index = 1,
|
||||||
|
payload = payload.copyOfRange(end, payload.size),
|
||||||
|
size = (payload.size - end).toByte()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun ByteArray.crc32(): Long {
|
internal fun ByteArray.crc32(): Long {
|
||||||
|
|
|
@ -29,29 +29,57 @@ internal class LTKExchanger(
|
||||||
|
|
||||||
@Throws(PairingException::class)
|
@Throws(PairingException::class)
|
||||||
fun negotiateLTK(): PairResult {
|
fun negotiateLTK(): PairResult {
|
||||||
val sp1sp2 = sp1sp2(podId.address, sp2())
|
val sp1sp2 = PairMessage(
|
||||||
throwOnSendError(sp1sp2.messagePacket, "SP1SP2")
|
sequenceNumber = seq,
|
||||||
|
source = myId,
|
||||||
|
destination = podAddress,
|
||||||
|
keys = arrayOf(SP1, SP2),
|
||||||
|
payloads = arrayOf(podId.address, sp2())
|
||||||
|
)
|
||||||
|
throwOnSendError(sp1sp2.messagePacket, SP1+SP2)
|
||||||
|
|
||||||
seq++
|
seq++
|
||||||
val sps1 = sps1()
|
val sps1 = PairMessage(
|
||||||
throwOnSendError(sps1.messagePacket, "SP1")
|
sequenceNumber = seq,
|
||||||
|
source = myId,
|
||||||
|
destination = podAddress,
|
||||||
|
keys = arrayOf(SPS1),
|
||||||
|
payloads = arrayOf(keyExchange.pdmPublic + keyExchange.pdmNonce)
|
||||||
|
)
|
||||||
|
throwOnSendError(sps1.messagePacket, SPS1)
|
||||||
|
|
||||||
val podSps1 = msgIO.receiveMessage() ?: throw PairingException("Could not read SPS1")
|
val podSps1 = msgIO.receiveMessage() ?: throw PairingException("Could not read SPS1")
|
||||||
processSps1FromPod(podSps1)
|
processSps1FromPod(podSps1)
|
||||||
// now we have all the data to generate: confPod, confPdm, ltk and noncePrefix
|
// now we have all the data to generate: confPod, confPdm, ltk and noncePrefix
|
||||||
|
|
||||||
seq++
|
seq++
|
||||||
val sps2 = sps2()
|
val sps2 = PairMessage(
|
||||||
throwOnSendError(sps2.messagePacket, "SPS2")
|
sequenceNumber = seq,
|
||||||
|
source = myId,
|
||||||
|
destination = podAddress,
|
||||||
|
keys = arrayOf(SPS2),
|
||||||
|
payloads = arrayOf(keyExchange.pdmConf)
|
||||||
|
)
|
||||||
|
throwOnSendError(sps2.messagePacket, SPS2)
|
||||||
|
|
||||||
val podSps2 = msgIO.receiveMessage() ?: throw PairingException("Could not read SPS2")
|
val podSps2 = msgIO.receiveMessage() ?: throw PairingException("Could not read SPS2")
|
||||||
validatePodSps2(podSps2)
|
validatePodSps2(podSps2)
|
||||||
|
// No exception throwing after this point. It is possible that the pod saved the LTK
|
||||||
|
|
||||||
seq++
|
seq++
|
||||||
// send SP0GP0
|
// send SP0GP0
|
||||||
throwOnSendErrorSending(sp0gp0().messagePacket, "SP0GP0")
|
val sp0gp0 = PairMessage (
|
||||||
|
sequenceNumber = seq,
|
||||||
|
source = myId,
|
||||||
|
destination = podAddress,
|
||||||
|
keys = arrayOf(SP0GP0),
|
||||||
|
payloads = arrayOf(ByteArray(0))
|
||||||
|
)
|
||||||
|
val result = msgIO.sendMessage(sp0gp0.messagePacket)
|
||||||
|
if (result !is MessageSendSuccess) {
|
||||||
|
aapsLogger.warn(LTag.PUMPBTCOMM,"Error sending SP0GP0: $result")
|
||||||
|
}
|
||||||
|
|
||||||
// No exception throwing after this point. It is possible that the pod saved the LTK
|
|
||||||
msgIO.receiveMessage()
|
msgIO.receiveMessage()
|
||||||
?.let { validateP0(it) }
|
?.let { validateP0(it) }
|
||||||
?: aapsLogger.warn(LTag.PUMPBTCOMM, "Could not read P0")
|
?: aapsLogger.warn(LTag.PUMPBTCOMM, "Could not read P0")
|
||||||
|
@ -70,39 +98,6 @@ internal class LTKExchanger(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(PairingException::class)
|
|
||||||
private fun throwOnSendErrorSending(msg: MessagePacket, msgType: String) {
|
|
||||||
val result = msgIO.sendMessage(msg)
|
|
||||||
if (result is MessageSendErrorSending) {
|
|
||||||
throw PairingException("Could not send $msgType: $result")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun sp1sp2(sp1: ByteArray, sp2: ByteArray): PairMessage {
|
|
||||||
val payload = StringLengthPrefixEncoding.formatKeys(
|
|
||||||
arrayOf(SP1, SP2),
|
|
||||||
arrayOf(sp1, sp2)
|
|
||||||
)
|
|
||||||
return PairMessage(
|
|
||||||
sequenceNumber = seq,
|
|
||||||
source = myId,
|
|
||||||
destination = podAddress,
|
|
||||||
payload = payload
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun sps1(): PairMessage {
|
|
||||||
val payload = StringLengthPrefixEncoding.formatKeys(
|
|
||||||
arrayOf("SPS1="),
|
|
||||||
arrayOf(keyExchange.pdmPublic + keyExchange.pdmNonce)
|
|
||||||
)
|
|
||||||
return PairMessage(
|
|
||||||
sequenceNumber = seq,
|
|
||||||
source = myId,
|
|
||||||
destination = podAddress,
|
|
||||||
payload = payload
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun processSps1FromPod(msg: MessagePacket) {
|
private fun processSps1FromPod(msg: MessagePacket) {
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Received SPS1 from pod: ${msg.payload.toHex()}")
|
aapsLogger.debug(LTag.PUMPBTCOMM, "Received SPS1 from pod: ${msg.payload.toHex()}")
|
||||||
|
@ -111,19 +106,6 @@ internal class LTKExchanger(
|
||||||
keyExchange.updatePodPublicData(payload)
|
keyExchange.updatePodPublicData(payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sps2(): PairMessage {
|
|
||||||
val payload = StringLengthPrefixEncoding.formatKeys(
|
|
||||||
arrayOf(SPS2),
|
|
||||||
arrayOf(keyExchange.pdmConf)
|
|
||||||
)
|
|
||||||
return PairMessage(
|
|
||||||
sequenceNumber = seq,
|
|
||||||
source = myId,
|
|
||||||
destination = podAddress,
|
|
||||||
payload = payload
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun validatePodSps2(msg: MessagePacket) {
|
private fun validatePodSps2(msg: MessagePacket) {
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Received SPS2 from pod: ${msg.payload.toHex()}")
|
aapsLogger.debug(LTag.PUMPBTCOMM, "Received SPS2 from pod: ${msg.payload.toHex()}")
|
||||||
|
|
||||||
|
@ -142,16 +124,6 @@ internal class LTKExchanger(
|
||||||
return GET_POD_STATUS_HEX_COMMAND.hexStringToByteArray()
|
return GET_POD_STATUS_HEX_COMMAND.hexStringToByteArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sp0gp0(): PairMessage {
|
|
||||||
val payload = SP0GP0.toByteArray()
|
|
||||||
return PairMessage(
|
|
||||||
sequenceNumber = seq,
|
|
||||||
source = myId,
|
|
||||||
destination = podAddress,
|
|
||||||
payload = payload
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun validateP0(msg: MessagePacket) {
|
private fun validateP0(msg: MessagePacket) {
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Received P0 from pod: ${msg.payload.toHex()}")
|
aapsLogger.debug(LTag.PUMPBTCOMM, "Received P0 from pod: ${msg.payload.toHex()}")
|
||||||
|
|
||||||
|
|
|
@ -3,17 +3,22 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.pair
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.Id
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.Id
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.MessagePacket
|
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.plugins.pump.omnipod.dash.driver.comm.message.MessageType
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.StringLengthPrefixEncoding
|
||||||
|
|
||||||
data class PairMessage(
|
data class PairMessage(
|
||||||
val sequenceNumber: Byte,
|
val sequenceNumber: Byte,
|
||||||
val source: Id,
|
val source: Id,
|
||||||
val destination: Id,
|
val destination: Id,
|
||||||
val payload: ByteArray,
|
private val keys: Array<String>,
|
||||||
|
private val payloads: Array<ByteArray>,
|
||||||
val messagePacket: MessagePacket = MessagePacket(
|
val messagePacket: MessagePacket = MessagePacket(
|
||||||
type = MessageType.PAIRING,
|
type = MessageType.PAIRING,
|
||||||
source = source,
|
source = source,
|
||||||
destination = destination,
|
destination = destination,
|
||||||
payload = payload,
|
payload = StringLengthPrefixEncoding.formatKeys(
|
||||||
|
keys,
|
||||||
|
payloads,
|
||||||
|
),
|
||||||
sequenceNumber = sequenceNumber,
|
sequenceNumber = sequenceNumber,
|
||||||
sas = true // TODO: understand why this is true for PairMessages
|
sas = true // TODO: understand why this is true for PairMessages
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue