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)
|
||||
} ?: true
|
||||
|
||||
|
||||
override fun lastDataTime(): Long {
|
||||
return podStateManager.lastConnection
|
||||
}
|
||||
|
|
|
@ -46,9 +46,7 @@ class OmnipodDashBleManagerImpl @Inject constructor(
|
|||
throw BusyException()
|
||||
}
|
||||
try {
|
||||
val conn = connection ?: throw NotConnectedException("Not connected")
|
||||
|
||||
val session = conn.session ?: throw NotConnectedException("Missing session")
|
||||
val session = assertSessionEstablished()
|
||||
|
||||
emitter.onNext(PodEvent.CommandSending(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 {
|
||||
// TODO is this used?
|
||||
var s: ConnectionStatus
|
||||
|
@ -135,8 +139,9 @@ class OmnipodDashBleManagerImpl @Inject constructor(
|
|||
}
|
||||
|
||||
private fun establishSession(msgSeq: Byte) {
|
||||
val conn = connection ?: throw FailedToConnectException("connection lost")
|
||||
val ltk: ByteArray = podState.ltk ?: throw FailedToConnectException("Missing LTK, activate the pod first")
|
||||
val conn = assertConnected()
|
||||
|
||||
val ltk = assertPaired()
|
||||
|
||||
val uniqueId = podState.uniqueId
|
||||
val podId = uniqueId?.let { Id.fromLong(uniqueId) }
|
||||
|
@ -149,7 +154,7 @@ class OmnipodDashBleManagerImpl @Inject constructor(
|
|||
if (newSqn != null) {
|
||||
aapsLogger.info(LTag.PUMPBTCOMM, "Updating EAP SQN to: $newSqn")
|
||||
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) {
|
||||
throw SessionEstablishmentException("Received resynchronization SQN for the second time")
|
||||
}
|
||||
|
@ -158,6 +163,16 @@ class OmnipodDashBleManagerImpl @Inject constructor(
|
|||
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 ->
|
||||
if (!busy.compareAndSet(false, true)) {
|
||||
throw BusyException()
|
||||
|
|
|
@ -15,7 +15,7 @@ data class MessagePacket(
|
|||
val sequenceNumber: Byte,
|
||||
val ack: Boolean = false,
|
||||
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 lastMessage: Boolean = false,
|
||||
val gateway: Boolean = false,
|
||||
|
|
|
@ -42,7 +42,7 @@ class PayloadJoiner(private val firstPacket: ByteArray) {
|
|||
oneExtraPacket = lastPacket.oneExtraPacket
|
||||
}
|
||||
|
||||
idx > fullFragments && oneExtraPacket -> {
|
||||
idx == fullFragments+1 && oneExtraPacket -> {
|
||||
fragments.add(LastOptionalPlusOneBlePacket.parse(packet))
|
||||
}
|
||||
|
||||
|
|
|
@ -6,29 +6,11 @@ import java.util.zip.CRC32
|
|||
internal class PayloadSplitter(private val payload: ByteArray) {
|
||||
|
||||
fun splitInPackets(): List<BlePacket> {
|
||||
if (payload.size <= FirstBlePacket.CAPACITY_WITH_THE_OPTIONAL_PLUS_ONE_PACKET) {
|
||||
return splitInOnePacket()
|
||||
}
|
||||
val ret = ArrayList<BlePacket>()
|
||||
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 rest =
|
||||
(
|
||||
|
@ -42,17 +24,10 @@ internal class PayloadSplitter(private val payload: ByteArray) {
|
|||
)
|
||||
)
|
||||
for (i in 1..middleFragments) {
|
||||
val p = if (i == 1) {
|
||||
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 * MiddleBlePacket.CAPACITY
|
||||
)
|
||||
}
|
||||
val p = payload.copyOfRange(
|
||||
FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS + (i - 1) * MiddleBlePacket.CAPACITY,
|
||||
FirstBlePacket.CAPACITY_WITH_MIDDLE_PACKETS + i * MiddleBlePacket.CAPACITY
|
||||
)
|
||||
ret.add(
|
||||
MiddleBlePacket(
|
||||
index = i.toByte(),
|
||||
|
@ -88,6 +63,30 @@ internal class PayloadSplitter(private val payload: ByteArray) {
|
|||
}
|
||||
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 {
|
||||
|
|
|
@ -29,29 +29,57 @@ internal class LTKExchanger(
|
|||
|
||||
@Throws(PairingException::class)
|
||||
fun negotiateLTK(): PairResult {
|
||||
val sp1sp2 = sp1sp2(podId.address, sp2())
|
||||
throwOnSendError(sp1sp2.messagePacket, "SP1SP2")
|
||||
val sp1sp2 = PairMessage(
|
||||
sequenceNumber = seq,
|
||||
source = myId,
|
||||
destination = podAddress,
|
||||
keys = arrayOf(SP1, SP2),
|
||||
payloads = arrayOf(podId.address, sp2())
|
||||
)
|
||||
throwOnSendError(sp1sp2.messagePacket, SP1+SP2)
|
||||
|
||||
seq++
|
||||
val sps1 = sps1()
|
||||
throwOnSendError(sps1.messagePacket, "SP1")
|
||||
val sps1 = PairMessage(
|
||||
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")
|
||||
processSps1FromPod(podSps1)
|
||||
// now we have all the data to generate: confPod, confPdm, ltk and noncePrefix
|
||||
|
||||
seq++
|
||||
val sps2 = sps2()
|
||||
throwOnSendError(sps2.messagePacket, "SPS2")
|
||||
val sps2 = PairMessage(
|
||||
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")
|
||||
validatePodSps2(podSps2)
|
||||
// No exception throwing after this point. It is possible that the pod saved the LTK
|
||||
|
||||
seq++
|
||||
// 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()
|
||||
?.let { validateP0(it) }
|
||||
?: 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) {
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Received SPS1 from pod: ${msg.payload.toHex()}")
|
||||
|
@ -111,19 +106,6 @@ internal class LTKExchanger(
|
|||
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) {
|
||||
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()
|
||||
}
|
||||
|
||||
private fun sp0gp0(): PairMessage {
|
||||
val payload = SP0GP0.toByteArray()
|
||||
return PairMessage(
|
||||
sequenceNumber = seq,
|
||||
source = myId,
|
||||
destination = podAddress,
|
||||
payload = payload
|
||||
)
|
||||
}
|
||||
|
||||
private fun validateP0(msg: MessagePacket) {
|
||||
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.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.StringLengthPrefixEncoding
|
||||
|
||||
data class PairMessage(
|
||||
val sequenceNumber: Byte,
|
||||
val source: Id,
|
||||
val destination: Id,
|
||||
val payload: ByteArray,
|
||||
private val keys: Array<String>,
|
||||
private val payloads: Array<ByteArray>,
|
||||
val messagePacket: MessagePacket = MessagePacket(
|
||||
type = MessageType.PAIRING,
|
||||
source = source,
|
||||
destination = destination,
|
||||
payload = payload,
|
||||
payload = StringLengthPrefixEncoding.formatKeys(
|
||||
keys,
|
||||
payloads,
|
||||
),
|
||||
sequenceNumber = sequenceNumber,
|
||||
sas = true // TODO: understand why this is true for PairMessages
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue