This commit is contained in:
Andrei Vereha 2021-03-28 23:15:42 +02:00
parent 96b1b177a6
commit b630c4d21a
16 changed files with 96 additions and 64 deletions

View file

@ -46,11 +46,13 @@ data class Id(val address: ByteArray) {
companion object { companion object {
private const val PERIPHERAL_NODE_INDEX = 1 // TODO: understand the meaning of this value. It comes from preferences private const val PERIPHERAL_NODE_INDEX =
1 // TODO: understand the meaning of this value. It comes from preferences
fun fromInt(v: Int): Id { fun fromInt(v: Int): Id {
return Id(ByteBuffer.allocate(4).putInt(v).array()) return Id(ByteBuffer.allocate(4).putInt(v).array())
} }
fun fromLong(v: Long): Id { fun fromLong(v: Long): Id {
return Id(ByteBuffer.allocate(8).putLong(v).array().copyOfRange(4, 8)) return Id(ByteBuffer.allocate(8).putLong(v).array().copyOfRange(4, 8))
} }

View file

@ -3,12 +3,10 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm
import android.bluetooth.BluetoothAdapter import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothManager import android.bluetooth.BluetoothManager
import android.content.Context import android.content.Context
import android.os.Message
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.pump.omnipod.dash.BuildConfig import info.nightscout.androidaps.plugins.pump.omnipod.dash.BuildConfig
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.* import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.*
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.MessageIO
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.pair.LTKExchanger import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.pair.LTKExchanger
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.scan.PodScanner import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.scan.PodScanner
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session.* import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session.*
@ -18,7 +16,6 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.b
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager
import info.nightscout.androidaps.utils.extensions.toHex import info.nightscout.androidaps.utils.extensions.toHex
import io.reactivex.Observable import io.reactivex.Observable
import java.util.concurrent.TimeoutException
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -29,7 +26,8 @@ class OmnipodDashBleManagerImpl @Inject constructor(
private val aapsLogger: AAPSLogger, private val aapsLogger: AAPSLogger,
private val podState: OmnipodDashPodStateManager private val podState: OmnipodDashPodStateManager
) : OmnipodDashBleManager { ) : OmnipodDashBleManager {
private val busy = AtomicBoolean(false);
private val busy = AtomicBoolean(false)
private val bluetoothManager: BluetoothManager = private val bluetoothManager: BluetoothManager =
context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
private val bluetoothAdapter: BluetoothAdapter = bluetoothManager.adapter private val bluetoothAdapter: BluetoothAdapter = bluetoothManager.adapter

View file

@ -45,7 +45,7 @@ class BleCommCallbacks(
try { try {
connected.await(timeoutMs.toLong(), TimeUnit.MILLISECONDS) connected.await(timeoutMs.toLong(), TimeUnit.MILLISECONDS)
} catch (e: InterruptedException) { } catch (e: InterruptedException) {
aapsLogger.warn(LTag.PUMPBTCOMM,"Interrupted while waiting for Connection") aapsLogger.warn(LTag.PUMPBTCOMM, "Interrupted while waiting for Connection")
} }
} }
@ -53,13 +53,13 @@ class BleCommCallbacks(
try { try {
serviceDiscoveryComplete.await(timeoutMs.toLong(), TimeUnit.MILLISECONDS) serviceDiscoveryComplete.await(timeoutMs.toLong(), TimeUnit.MILLISECONDS)
} catch (e: InterruptedException) { } catch (e: InterruptedException) {
aapsLogger.warn(LTag.PUMPBTCOMM,"Interrupted while waiting for ServiceDiscovery") aapsLogger.warn(LTag.PUMPBTCOMM, "Interrupted while waiting for ServiceDiscovery")
} }
} }
fun confirmWrite(expectedPayload: ByteArray, expectedUUID: String, timeoutMs: Long) : WriteConfirmation{ fun confirmWrite(expectedPayload: ByteArray, expectedUUID: String, timeoutMs: Long): WriteConfirmation {
try { try {
return when(val received = writeQueue.poll(timeoutMs, TimeUnit.MILLISECONDS) ) { return when (val received = writeQueue.poll(timeoutMs, TimeUnit.MILLISECONDS)) {
null -> return WriteConfirmationError("Timeout waiting for writeConfirmation") null -> return WriteConfirmationError("Timeout waiting for writeConfirmation")
is WriteConfirmationSuccess -> is WriteConfirmationSuccess ->
if (expectedPayload.contentEquals(received.payload) && if (expectedPayload.contentEquals(received.payload) &&
@ -75,7 +75,7 @@ class BleCommCallbacks(
is WriteConfirmationError -> is WriteConfirmationError ->
received received
} }
}catch (e: InterruptedException) { } catch (e: InterruptedException) {
return WriteConfirmationError("Interrupted waiting for confirmation") return WriteConfirmationError("Interrupted waiting for confirmation")
} }
} }
@ -112,11 +112,13 @@ class BleCommCallbacks(
val writeConfirmation = when { val writeConfirmation = when {
uuid == null || value == null -> uuid == null || value == null ->
WriteConfirmationError("onWrite received Null: UUID=$uuid, value=${value.toHex()} status=$status") WriteConfirmationError("onWrite received Null: UUID=$uuid, value=${value.toHex()} status=$status")
status == BluetoothGatt.GATT_SUCCESS -> {
status == BluetoothGatt.GATT_SUCCESS -> {
aapsLogger.debug(LTag.PUMPBTCOMM, "OnWrite value " + value.toHex()) aapsLogger.debug(LTag.PUMPBTCOMM, "OnWrite value " + value.toHex())
WriteConfirmationSuccess(uuid.toString(), value) WriteConfirmationSuccess(uuid.toString(), value)
} }
else ->WriteConfirmationError("onDescriptorWrite status is not success: $status")
else -> WriteConfirmationError("onDescriptorWrite status is not success: $status")
} }
try { try {

View file

@ -1,6 +1,5 @@
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.command package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.command
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
import java.nio.ByteBuffer import java.nio.ByteBuffer
@ -16,12 +15,13 @@ object BleCommandFail : BleCommand(BleCommandType.FAIL)
data class BleCommandNack(val idx: Byte) : BleCommand(BleCommandType.NACK, byteArrayOf(idx)) { data class BleCommandNack(val idx: Byte) : BleCommand(BleCommandType.NACK, byteArrayOf(idx)) {
companion object { companion object {
fun parse(payload: ByteArray): BleCommand { fun parse(payload: ByteArray): BleCommand {
if (payload.size < 2) { if (payload.size < 2) {
return BleCommandIncorrect("Incorrect NACK payload", payload) return BleCommandIncorrect("Incorrect NACK payload", payload)
} }
if (payload[0] != BleCommandType.NACK.value) { if (payload[0] != BleCommandType.NACK.value) {
return BleCommandIncorrect("Incorrect NACK header", payload) return BleCommandIncorrect("Incorrect NACK header", payload)
} }
return BleCommandNack(payload[1]) return BleCommandNack(payload[1])
} }
@ -36,7 +36,7 @@ data class BleCommandHello(private val controllerId: Int) : BleCommand(
.putInt(controllerId).array() .putInt(controllerId).array()
) )
data class BleCommandIncorrect(val msg:String, val payload: ByteArray): BleCommand(BleCommandType.INCORRECT) data class BleCommandIncorrect(val msg: String, val payload: ByteArray) : BleCommand(BleCommandType.INCORRECT)
sealed class BleCommand(val data: ByteArray) { sealed class BleCommand(val data: ByteArray) {
@ -64,13 +64,14 @@ sealed class BleCommand(val data: ByteArray) {
} }
companion object { companion object {
fun parse(payload: ByteArray): BleCommand { fun parse(payload: ByteArray): BleCommand {
if (payload.isEmpty()) { if (payload.isEmpty()) {
return BleCommandIncorrect("Incorrect command: empty payload", payload) return BleCommandIncorrect("Incorrect command: empty payload", payload)
} }
try { try {
return when(BleCommandType.byValue(payload[0])) { return when (BleCommandType.byValue(payload[0])) {
BleCommandType.RTS -> BleCommandType.RTS ->
BleCommandRTS BleCommandRTS
BleCommandType.CTS -> BleCommandType.CTS ->

View file

@ -1,3 +1,3 @@
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions
class BusyException(): Exception("Bluetooth busy") class BusyException : Exception("Bluetooth busy")

View file

@ -1,4 +1,3 @@
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions
class CouldNotSendCommandException (val msg: String="Could not send command") : Exception(msg){ class CouldNotSendCommandException(val msg: String = "Could not send command") : Exception(msg)
}

View file

@ -1,6 +1,6 @@
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions
open class FailedToConnectException : Exception { open class FailedToConnectException : Exception {
constructor(message: String?=null) : super("Failed to connect: ${message ?: ""}") constructor(message: String? = null) : super("Failed to connect: ${message ?: ""}")
} }

View file

@ -8,20 +8,17 @@ import android.bluetooth.BluetoothGattDescriptor
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.callbacks.BleCommCallbacks import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.callbacks.BleCommCallbacks
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.callbacks.WriteConfirmation
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.callbacks.WriteConfirmationError import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.callbacks.WriteConfirmationError
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.callbacks.WriteConfirmationSuccess import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.callbacks.WriteConfirmationSuccess
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.* import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.*
import info.nightscout.androidaps.utils.extensions.toHex import info.nightscout.androidaps.utils.extensions.toHex
import java.util.concurrent.BlockingQueue import java.util.concurrent.BlockingQueue
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException
sealed class BleReceiveResult sealed class BleReceiveResult
data class BleReceivePayload(val payload: ByteArray) : BleReceiveResult() data class BleReceivePayload(val payload: ByteArray) : BleReceiveResult()
data class BleReceiveError(val msg: String, val cause: Throwable? = null) : BleReceiveResult() data class BleReceiveError(val msg: String, val cause: Throwable? = null) : BleReceiveResult()
sealed class BleSendResult sealed class BleSendResult
object BleSendSuccess : BleSendResult() object BleSendSuccess : BleSendResult()
@ -71,11 +68,12 @@ abstract class BleIO(
return when (val confirmation = bleCommCallbacks.confirmWrite( return when (val confirmation = bleCommCallbacks.confirmWrite(
payload, type.value, payload, type.value,
DEFAULT_IO_TIMEOUT_MS)){ DEFAULT_IO_TIMEOUT_MS
is WriteConfirmationError -> )) {
is WriteConfirmationError ->
BleSendErrorConfirming(confirmation.msg) BleSendErrorConfirming(confirmation.msg)
is WriteConfirmationSuccess -> is WriteConfirmationSuccess ->
BleSendSuccess BleSendSuccess
} }
} }
@ -111,10 +109,12 @@ abstract class BleIO(
if (!wrote) { if (!wrote) {
throw ConnectException("Could not enable indications on descriptor") throw ConnectException("Could not enable indications on descriptor")
} }
val confirmation = bleCommCallbacks.confirmWrite(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE, val confirmation = bleCommCallbacks.confirmWrite(
descriptor.uuid.toString(), BluetoothGattDescriptor.ENABLE_INDICATION_VALUE,
DEFAULT_IO_TIMEOUT_MS) descriptor.uuid.toString(),
return when(confirmation) { DEFAULT_IO_TIMEOUT_MS
)
return when (confirmation) {
is WriteConfirmationError -> is WriteConfirmationError ->
throw ConnectException(confirmation.msg) throw ConnectException(confirmation.msg)
is WriteConfirmationSuccess -> is WriteConfirmationSuccess ->

View file

@ -29,6 +29,7 @@ class CmdBleIO(
bleCommCallbacks, bleCommCallbacks,
CharacteristicType.CMD CharacteristicType.CMD
) { ) {
init { init {
} }
@ -38,7 +39,6 @@ class CmdBleIO(
fun hello() = sendAndConfirmPacket(BleCommandHello(OmnipodDashBleManagerImpl.CONTROLLER_ID).data) fun hello() = sendAndConfirmPacket(BleCommandHello(OmnipodDashBleManagerImpl.CONTROLLER_ID).data)
fun expectCommandType(expected: BleCommand, timeoutMs: Long = DEFAULT_IO_TIMEOUT_MS): BleConfirmResult { fun expectCommandType(expected: BleCommand, timeoutMs: Long = DEFAULT_IO_TIMEOUT_MS): BleConfirmResult {
return when (val actual = receivePacket(timeoutMs)) { return when (val actual = receivePacket(timeoutMs)) {
is BleReceiveError -> BleConfirmError(actual.toString()) is BleReceiveError -> BleConfirmError(actual.toString())

View file

@ -18,11 +18,11 @@ data class MessageReceiveError(val msg: String, val cause: Throwable? = null) :
sealed class MessageSendResult sealed class MessageSendResult
object MessageSendSuccess : MessageSendResult() object MessageSendSuccess : MessageSendResult()
data class MessageSendErrorSending(val msg: String, val cause: Throwable? = null) : MessageSendResult() { data class MessageSendErrorSending(val msg: String, val cause: Throwable? = null) : MessageSendResult() {
constructor(e: BleSendResult): this("Could not send packet: $e") constructor(e: BleSendResult) : this("Could not send packet: $e")
} }
data class MessageSendErrorConfirming(val msg: String, val cause: Throwable? = null) : MessageSendResult() { data class MessageSendErrorConfirming(val msg: String, val cause: Throwable? = null) : MessageSendResult() {
constructor(e: BleSendResult): this("Could not confirm packet: $e") constructor(e: BleSendResult) : this("Could not confirm packet: $e")
} }
sealed class PacketReceiveResult sealed class PacketReceiveResult

View file

@ -4,6 +4,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.
import java.nio.ByteBuffer import java.nio.ByteBuffer
sealed class BlePacket { sealed class BlePacket {
abstract val payload: ByteArray abstract val payload: ByteArray
abstract fun toByteArray(): ByteArray abstract fun toByteArray(): ByteArray
@ -173,7 +174,8 @@ data class LastBlePacket(
data class LastOptionalPlusOneBlePacket( data class LastOptionalPlusOneBlePacket(
val index: Byte, val index: Byte,
override val payload: ByteArray, override val payload: ByteArray,
val size: Byte) : BlePacket() { val size: Byte
) : BlePacket() {
override fun toByteArray(): ByteArray { override fun toByteArray(): ByteArray {
return byteArrayOf(index, size) + payload + ByteArray(MAX_SIZE - payload.size - 2) return byteArrayOf(index, size) + payload + ByteArray(MAX_SIZE - payload.size - 2)

View file

@ -1,6 +1,5 @@
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.pair package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.pair
import android.app.Notification
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.Id import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.Id
@ -12,7 +11,6 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.Rand
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.X25519KeyGenerator import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.X25519KeyGenerator
import info.nightscout.androidaps.utils.extensions.hexStringToByteArray import info.nightscout.androidaps.utils.extensions.hexStringToByteArray
import info.nightscout.androidaps.utils.extensions.toHex import info.nightscout.androidaps.utils.extensions.toHex
import info.nightscout.androidaps.utils.extensions.waitMillis
internal class LTKExchanger( internal class LTKExchanger(
private val aapsLogger: AAPSLogger, private val aapsLogger: AAPSLogger,
@ -71,7 +69,7 @@ internal class LTKExchanger(
val p0 = msgIO.receiveMessage() val p0 = msgIO.receiveMessage()
if (p0 is MessageReceiveSuccess) { if (p0 is MessageReceiveSuccess) {
validateP0(p0.msg) validateP0(p0.msg)
} else{ } else {
aapsLogger.warn(LTag.PUMPBTCOMM, "Could not read P0: $p0") aapsLogger.warn(LTag.PUMPBTCOMM, "Could not read P0: $p0")
} }
return PairResult( return PairResult(

View file

@ -5,7 +5,6 @@ import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothManager import android.bluetooth.BluetoothManager
import android.bluetooth.BluetoothProfile import android.bluetooth.BluetoothProfile
import android.content.Context import android.content.Context
import com.j256.ormlite.stmt.query.Not
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.pump.omnipod.dash.BuildConfig import info.nightscout.androidaps.plugins.pump.omnipod.dash.BuildConfig
@ -21,7 +20,6 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.DataB
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.IncomingPackets import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.IncomingPackets
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.utils.extensions.toHex import info.nightscout.androidaps.utils.extensions.toHex
import info.nightscout.androidaps.utils.extensions.wait
sealed class ConnectionState sealed class ConnectionState
@ -43,17 +41,21 @@ class Connection(val podDevice: BluetoothDevice, private val aapsLogger: AAPSLog
val autoConnect = false val autoConnect = false
gattConnection = podDevice.connectGatt(context, autoConnect, bleCommCallbacks, BluetoothDevice.TRANSPORT_LE) gattConnection = podDevice.connectGatt(context, autoConnect, bleCommCallbacks, BluetoothDevice.TRANSPORT_LE)
val state = waitForConnection() val state = waitForConnection()
if (state !is Connected){ if (state !is Connected) {
throw FailedToConnectException(podDevice.address) throw FailedToConnectException(podDevice.address)
} }
} }
private val discoverer = ServiceDiscoverer(aapsLogger, gattConnection, bleCommCallbacks) private val discoverer = ServiceDiscoverer(aapsLogger, gattConnection, bleCommCallbacks)
private val discoveredCharacteristics = discoverer.discoverServices() private val discoveredCharacteristics = discoverer.discoverServices()
private val cmdBleIO = CmdBleIO(aapsLogger, discoveredCharacteristics[CharacteristicType.CMD]!!, incomingPackets private val cmdBleIO = CmdBleIO(
.cmdQueue, gattConnection, bleCommCallbacks) aapsLogger, discoveredCharacteristics[CharacteristicType.CMD]!!, incomingPackets
private val dataBleIO = DataBleIO(aapsLogger, discoveredCharacteristics[CharacteristicType.DATA]!!, incomingPackets .cmdQueue, gattConnection, bleCommCallbacks
.dataQueue, gattConnection, bleCommCallbacks) )
private val dataBleIO = DataBleIO(
aapsLogger, discoveredCharacteristics[CharacteristicType.DATA]!!, incomingPackets
.dataQueue, gattConnection, bleCommCallbacks
)
val msgIO = MessageIO(aapsLogger, cmdBleIO, dataBleIO) val msgIO = MessageIO(aapsLogger, cmdBleIO, dataBleIO)
var session: Session? = null var session: Session? = null
@ -71,7 +73,7 @@ class Connection(val podDevice: BluetoothDevice, private val aapsLogger: AAPSLog
throw FailedToConnectException("connect() returned false") throw FailedToConnectException("connect() returned false")
} }
if (waitForConnection() is NotConnected){ if (waitForConnection() is NotConnected) {
throw FailedToConnectException(podDevice.address) throw FailedToConnectException(podDevice.address)
} }
@ -82,12 +84,12 @@ class Connection(val podDevice: BluetoothDevice, private val aapsLogger: AAPSLog
gattConnection.disconnect() gattConnection.disconnect()
} }
fun waitForConnection(): ConnectionState { private fun waitForConnection(): ConnectionState {
try { try {
bleCommCallbacks.waitForConnection(CONNECT_TIMEOUT_MS) bleCommCallbacks.waitForConnection(CONNECT_TIMEOUT_MS)
}catch (e: InterruptedException) { } catch (e: InterruptedException) {
// We are still going to check if connection was successful // We are still going to check if connection was successful
aapsLogger.info(LTag.PUMPBTCOMM,"Interruped while waiting for connection") aapsLogger.info(LTag.PUMPBTCOMM, "Interruped while waiting for connection")
} }
return connectionState() return connectionState()
} }
@ -116,6 +118,7 @@ class Connection(val podDevice: BluetoothDevice, private val aapsLogger: AAPSLog
) )
session = Session(aapsLogger, msgIO, myId, podID, sessionKeys = keys, enDecrypt = enDecrypt) session = Session(aapsLogger, msgIO, myId, podID, sessionKeys = keys, enDecrypt = enDecrypt)
} }
companion object { companion object {
private const val CONNECT_TIMEOUT_MS = 7000 private const val CONNECT_TIMEOUT_MS = 7000

View file

@ -50,7 +50,14 @@ sealed class EapAkaAttribute {
EapAkaAttributeType.AT_RAND -> EapAkaAttributeType.AT_RAND ->
ret.add(EapAkaAttributeRand.parse(tail.copyOfRange(2, EapAkaAttributeRand.SIZE))) ret.add(EapAkaAttributeRand.parse(tail.copyOfRange(2, EapAkaAttributeRand.SIZE)))
EapAkaAttributeType.AT_CLIENT_ERROR_CODE -> EapAkaAttributeType.AT_CLIENT_ERROR_CODE ->
ret.add(EapAkaAttributeClientErrorCode.parse(tail.copyOfRange(2, EapAkaAttributeClientErrorCode.SIZE))) ret.add(
EapAkaAttributeClientErrorCode.parse(
tail.copyOfRange(
2,
EapAkaAttributeClientErrorCode.SIZE
)
)
)
} }
tail = tail.copyOfRange(size, tail.size) tail = tail.copyOfRange(size, tail.size)
} }
@ -70,12 +77,14 @@ data class EapAkaAttributeRand(val payload: ByteArray) : EapAkaAttribute() {
} }
companion object { companion object {
fun parse(payload: ByteArray): EapAkaAttribute { fun parse(payload: ByteArray): EapAkaAttribute {
if (payload.size < 2 + 16) { if (payload.size < 2 + 16) {
throw MessageIOException("Could not parse RAND attribute: ${payload.toHex()}") throw MessageIOException("Could not parse RAND attribute: ${payload.toHex()}")
} }
return EapAkaAttributeRand(payload.copyOfRange(2, 2 + 16)) return EapAkaAttributeRand(payload.copyOfRange(2, 2 + 16))
} }
const val SIZE = 20 // type, size, 2 reserved bytes, payload=16 const val SIZE = 20 // type, size, 2 reserved bytes, payload=16
} }
} }
@ -110,7 +119,12 @@ data class EapAkaAttributeRes(val payload: ByteArray) : EapAkaAttribute() {
} }
override fun toByteArray(): ByteArray { override fun toByteArray(): ByteArray {
return byteArrayOf(EapAkaAttributeType.AT_RES.type, (SIZE / SIZE_MULTIPLIER).toByte(), 0, PAYLOAD_SIZE_BITS) + payload return byteArrayOf(
EapAkaAttributeType.AT_RES.type,
(SIZE / SIZE_MULTIPLIER).toByte(),
0,
PAYLOAD_SIZE_BITS
) + payload
} }
companion object { companion object {
@ -145,6 +159,7 @@ data class EapAkaAttributeCustomIV(val payload: ByteArray) : EapAkaAttribute() {
} }
return EapAkaAttributeCustomIV(payload.copyOfRange(2, 2 + 4)) return EapAkaAttributeCustomIV(payload.copyOfRange(2, 2 + 4))
} }
const val SIZE = 8 // type, size, 2 reserved bytes, payload=4 const val SIZE = 8 // type, size, 2 reserved bytes, payload=4
} }
} }
@ -156,7 +171,12 @@ data class EapAkaAttributeClientErrorCode(val payload: ByteArray) : EapAkaAttrib
} }
override fun toByteArray(): ByteArray { override fun toByteArray(): ByteArray {
return byteArrayOf(EapAkaAttributeType.AT_CLIENT_ERROR_CODE.type, (SIZE / SIZE_MULTIPLIER).toByte(), 0, 0) + payload return byteArrayOf(
EapAkaAttributeType.AT_CLIENT_ERROR_CODE.type,
(SIZE / SIZE_MULTIPLIER).toByte(),
0,
0
) + payload
} }
companion object { companion object {

View file

@ -12,17 +12,16 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.
import info.nightscout.androidaps.utils.extensions.toHex import info.nightscout.androidaps.utils.extensions.toHex
sealed class CommandSendResult sealed class CommandSendResult
object CommandSendSuccess: CommandSendResult() object CommandSendSuccess : CommandSendResult()
data class CommandSendErrorSending(val msg: String): CommandSendResult() data class CommandSendErrorSending(val msg: String) : CommandSendResult()
// This error marks the undefined state // This error marks the undefined state
data class CommandSendErrorConfirming(val msg: String): CommandSendResult() data class CommandSendErrorConfirming(val msg: String) : CommandSendResult()
sealed class CommandReceiveResult sealed class CommandReceiveResult
data class CommandReceiveSuccess(val result: Response): CommandReceiveResult() data class CommandReceiveSuccess(val result: Response) : CommandReceiveResult()
data class CommandReceiveError(val msg: String): CommandReceiveResult() data class CommandReceiveError(val msg: String) : CommandReceiveResult()
data class CommandAckError(val result: Response, val msg: String): CommandReceiveResult() data class CommandAckError(val result: Response, val msg: String) : CommandReceiveResult()
class Session( class Session(
private val aapsLogger: AAPSLogger, private val aapsLogger: AAPSLogger,
@ -45,10 +44,12 @@ class Session(
when (val sendResult = msgIO.sendMessage(msg)) { when (val sendResult = msgIO.sendMessage(msg)) {
is MessageSendSuccess -> is MessageSendSuccess ->
return CommandSendSuccess return CommandSendSuccess
is MessageSendErrorConfirming -> { is MessageSendErrorConfirming -> {
possiblyUnconfirmedCommand = true possiblyUnconfirmedCommand = true
aapsLogger.debug(LTag.PUMPBTCOMM, "Error confirming command: $sendResult") aapsLogger.debug(LTag.PUMPBTCOMM, "Error confirming command: $sendResult")
} }
is MessageSendErrorSending -> is MessageSendErrorSending ->
aapsLogger.debug(LTag.PUMPBTCOMM, "Error sending command: $sendResult") aapsLogger.debug(LTag.PUMPBTCOMM, "Error sending command: $sendResult")
} }
@ -62,7 +63,7 @@ class Session(
} }
fun readAndAckCommandResponse(): CommandReceiveResult { fun readAndAckCommandResponse(): CommandReceiveResult {
var responseMsgPacket: MessagePacket?= null var responseMsgPacket: MessagePacket? = null
for (i in 0..MAX_TRIES) { for (i in 0..MAX_TRIES) {
val responseMsg = msgIO.receiveMessage() val responseMsg = msgIO.receiveMessage()
if (responseMsg !is MessageReceiveSuccess) { if (responseMsg !is MessageReceiveSuccess) {
@ -89,7 +90,6 @@ class Session(
return CommandReceiveSuccess(response) return CommandReceiveSuccess(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]

View file

@ -89,14 +89,21 @@ class SessionEstablisher(
private fun processChallengeResponse(challengeResponse: MessagePacket) { private fun processChallengeResponse(challengeResponse: MessagePacket) {
val eapMsg = EapMessage.parse(aapsLogger, challengeResponse.payload) val eapMsg = EapMessage.parse(aapsLogger, challengeResponse.payload)
if (eapMsg.identifier != identifier ) { if (eapMsg.identifier != identifier) {
aapsLogger.debug(LTag.PUMPBTCOMM, "EAP-AKA: got incorrect identifier ${eapMsg.identifier} expected: $identifier") aapsLogger.debug(
LTag.PUMPBTCOMM,
"EAP-AKA: got incorrect identifier ${eapMsg.identifier} expected: $identifier"
)
throw SessionEstablishmentException("Received incorrect EAP identifier: ${eapMsg.identifier}") throw SessionEstablishmentException("Received incorrect EAP identifier: ${eapMsg.identifier}")
} }
if (eapMsg.attributes.size != 2) { if (eapMsg.attributes.size != 2) {
aapsLogger.debug(LTag.PUMPBTCOMM, "EAP-AKA: got message: $eapMsg") aapsLogger.debug(LTag.PUMPBTCOMM, "EAP-AKA: got message: $eapMsg")
if (eapMsg.attributes.size == 1 && eapMsg.attributes[0] is EapAkaAttributeClientErrorCode) { if (eapMsg.attributes.size == 1 && eapMsg.attributes[0] is EapAkaAttributeClientErrorCode) {
throw SessionEstablishmentException("Received CLIENT_ERROR_CODE for EAP-AKA challenge: ${eapMsg.attributes[0].toByteArray().toHex()}") throw SessionEstablishmentException(
"Received CLIENT_ERROR_CODE for EAP-AKA challenge: ${
eapMsg.attributes[0].toByteArray().toHex()
}"
)
} }
throw SessionEstablishmentException("Expecting two attributes, got: ${eapMsg.attributes.size}") throw SessionEstablishmentException("Expecting two attributes, got: ${eapMsg.attributes.size}")
} }