From 9c586c494287a34647c2e3d81662e48da4980d27 Mon Sep 17 00:00:00 2001 From: Andrei Vereha Date: Thu, 4 Mar 2021 18:59:03 +0100 Subject: [PATCH 01/11] dash encryption: add encryption and decryption for messsages --- .../dash/driver/comm/endecrypt/EnDecrypt.kt | 63 +++++++++++++++++++ .../driver/comm/endecrypt/EnDecryptTest.kt | 59 +++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/EnDecrypt.kt create mode 100644 omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/EnDecryptTest.kt diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/EnDecrypt.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/EnDecrypt.kt new file mode 100644 index 00000000000..a08b79bf8a2 --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/EnDecrypt.kt @@ -0,0 +1,63 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.endecrypt + +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.MessagePacket +import info.nightscout.androidaps.utils.extensions.toHex +import org.spongycastle.crypto.engines.AESEngine +import org.spongycastle.crypto.modes.CCMBlockCipher +import org.spongycastle.crypto.params.AEADParameters +import org.spongycastle.crypto.params.KeyParameter + +class EnDecrypt(private val aapsLogger: AAPSLogger, private val nonce: Nonce, private val ck: ByteArray) { + + val engine = AESEngine() + val cipher = CCMBlockCipher(engine) + + fun decrypt(msg: MessagePacket): MessagePacket { + val payload = msg.payload + val header = msg.asByteArray().copyOfRange(0, 16) + + val n = nonce.increment() + aapsLogger.debug(LTag.PUMPBTCOMM, "Decrypt header ${header.toHex()} payload: ${payload.toHex()}") + aapsLogger.debug(LTag.PUMPBTCOMM, "Decrypt NONCE ${n.toHex()}") + cipher.init( + false, AEADParameters( + KeyParameter(ck), + MAC_SIZE * 8, // in bits + n, + header + ) + ) + val decryptedPayload = ByteArray(payload.size - MAC_SIZE) + cipher.processPacket(payload, 0, payload.size, decryptedPayload, 0) + return msg.copy(payload = decryptedPayload) + } + + fun encrypt(headerMessage: MessagePacket): MessagePacket { + val payload = headerMessage.payload + val header = headerMessage.asByteArray(true).copyOfRange(0, 16) + + val n = nonce.increment() + aapsLogger.debug(LTag.PUMPBTCOMM, "Encrypt header ${header.toHex()} payload: ${payload.toHex()}") + aapsLogger.debug(LTag.PUMPBTCOMM, "Encrypt NONCE ${n.toHex()}") + val encryptedPayload = ByteArray(payload.size + MAC_SIZE) + + cipher.init( + true, AEADParameters( + KeyParameter(ck), + MAC_SIZE * 8, // in bits + n, + header + ) + ) + cipher.processPacket(payload, 0, payload.size, encryptedPayload, 0) + + return headerMessage.copy(payload = encryptedPayload) + } + + companion object { + + private val MAC_SIZE = 8 + } +} \ No newline at end of file diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/EnDecryptTest.kt b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/EnDecryptTest.kt new file mode 100644 index 00000000000..05851bd2616 --- /dev/null +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/EnDecryptTest.kt @@ -0,0 +1,59 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.endecrypt + +import info.nightscout.androidaps.logging.AAPSLoggerTest +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.MessagePacket +import info.nightscout.androidaps.utils.extensions.toHex +import org.junit.Assert +import org.junit.Test +import org.spongycastle.util.encoders.Hex + +class EnDecryptTest { + + @Test + fun decrypt() { + val aapsLogger = AAPSLoggerTest() + val enDecrypt = EnDecrypt( + aapsLogger, + Nonce( + Hex.decode("dda23c090a0a0a0a"), + Hex.decode("0000000001") + ), + Hex.decode("ba1283744b6de9fab6d9b77d95a71d6e"), + ) + val encryptedMessage = Hex.decode( + "54571101070003400242000002420001" + + "e09158bcb0285a81bf30635f3a17ee73f0afbb3286bc524a8a66" + + "fb1bc5b001e56543" + ) + val decrypted = Hex.decode("53302e303d000effffffff00060704ffffffff82b22c47302e30") + val msg = MessagePacket.parse(encryptedMessage) + val decryptedMsg = enDecrypt.decrypt(msg) + + Assert.assertEquals(decrypted.toHex(), decryptedMsg.payload.toHex()) + } + + @Test + fun encrypt() { + val aapsLogger = AAPSLoggerTest() + val enDecrypt = EnDecrypt( + aapsLogger, + Nonce( + Hex.decode("dda23c090a0a0a0a"), + Hex.decode("0000000001") + ), + Hex.decode("ba1283744b6de9fab6d9b77d95a71d6e"), + ) + val encryptedMessage = Hex.decode( + "54571101070003400242000002420001" + + "e09158bcb0285a81bf30635f3a17ee73f0afbb3286bc524a8a66" + + "fb1bc5b001e56543" + ) + val command = Hex.decode("53302e303d000effffffff00060704ffffffff82b22c47302e30") + val msg = MessagePacket.parse(encryptedMessage).copy(payload = command) // copy for the headers + + val encrypted = enDecrypt.encrypt(msg) + + Assert.assertEquals(encryptedMessage.toHex(), encrypted.asByteArray().toHex()) + + } +} \ No newline at end of file From 5647007190c4d51a488554ea8c484870c737eaea Mon Sep 17 00:00:00 2001 From: Andrei Vereha Date: Sat, 6 Mar 2021 10:58:43 +0100 Subject: [PATCH 02/11] dash/ble: remove retries for connect for now It's easier to debug for now if we stop on the first issue/error --- .../dash/driver/OmnipodDashManagerImpl.kt | 3 +- .../driver/comm/endecrypt/CryptSequence.kt | 28 +++++++++++++++++++ .../dash/driver/comm/session/EapSqn.kt | 4 +++ 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/CryptSequence.kt create mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapSqn.kt diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/OmnipodDashManagerImpl.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/OmnipodDashManagerImpl.kt index 768613ce4e0..2e3e5f62d67 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/OmnipodDashManagerImpl.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/OmnipodDashManagerImpl.kt @@ -49,7 +49,8 @@ class OmnipodDashManagerImpl @Inject constructor( private val observeConnectToPod: Observable get() = Observable.defer { - bleManager.connect().retryWithBackoff(retries = 2, delay = 3, timeUnit = TimeUnit.SECONDS) + bleManager.connect() + } // TODO are these reasonable values? private fun observeSendProgramBolusCommand( diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/CryptSequence.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/CryptSequence.kt new file mode 100644 index 00000000000..edfc2592152 --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/CryptSequence.kt @@ -0,0 +1,28 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session + +import java.nio.ByteBuffer + +class CryptSequence(var sqn: Long) { + + fun incrementForEapAka():ByteArray { + sqn++ + return ByteBuffer.allocate(8) + .putLong(sqn) + .array() + .copyOfRange(2, 8) + } + + fun incrementForEnDecrypt(podReceiving: Boolean):ByteArray{ + sqn++ + val ret = ByteBuffer.allocate(8) + .putLong(sqn) + .array() + .copyOfRange(3, 8) + if (podReceiving) { + ret[0] = (ret[0].toInt() and 127).toByte() + } else { + ret[0] = (ret[0].toInt() or 128).toByte() + } + return ret + } +} \ No newline at end of file diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapSqn.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapSqn.kt new file mode 100644 index 00000000000..1861167a50e --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapSqn.kt @@ -0,0 +1,4 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session + +class EapSqn { +} \ No newline at end of file From 5211d4ddc66fcc8a0b062ed130350f546927af5e Mon Sep 17 00:00:00 2001 From: Andrei Vereha Date: Sat, 6 Mar 2021 11:02:21 +0100 Subject: [PATCH 03/11] dash ble: implement sessions and sending commands Tested with the fake pod: ``` DEBU[0185] got command. CRC: 82b2. Type: 7 :: GET_VERSION DEBU[0185] got command. CRC: 0003. Type: 3 :: SET_UNIQUE_ID DEBU[0186] got command. CRC: 019a. Type: 19 :: PROGRAM_ALERTS DEBU[0186] got command. CRC: 0385. Type: 19 :: PROGRAM_ALERTS DEBU[0187] got command. CRC: 81f3. Type: 1a :: PROGRAM_INSULIN DEBU[0187] got command. CRC: 8178. Type: e :: GET_STATUS ``` --- .../driver/comm/OmnipodDashBleManagerImpl.kt | 79 ++++++++++----- .../driver/comm/callbacks/BleCommCallbacks.kt | 2 +- .../dash/driver/comm/command/BleCommand.kt | 21 ++-- .../driver/comm/endecrypt/CryptSequence.kt | 14 +-- .../dash/driver/comm/endecrypt/EnDecrypt.kt | 4 +- .../dash/driver/comm/endecrypt/Nonce.kt | 23 +++++ .../exceptions/FailedToConnectException.kt | 3 +- .../pump/omnipod/dash/driver/comm/io/BleIO.kt | 2 +- .../dash/driver/comm/message/MessageIO.kt | 3 +- .../dash/driver/comm/message/MessagePacket.kt | 11 ++- .../dash/driver/comm/message/PayloadJoiner.kt | 10 +- .../message/StringLengthPrefixEncoding.kt | 15 +-- .../dash/driver/comm/pair/LTKExchanger.kt | 10 +- .../dash/driver/comm/pair/PairResult.kt | 2 +- .../driver/comm/session/EapAkaAttribute.kt | 2 +- .../dash/driver/comm/session/EapSqn.kt | 16 ++- .../dash/driver/comm/session/Session.kt | 98 +++++++++++++++++++ .../driver/comm/session/SessionEstablisher.kt | 37 ++++--- .../dash/driver/comm/session/SessionKeys.kt | 6 +- .../omnipod/dash/driver/event/PodEvent.kt | 2 +- .../dash/ui/OmnipodDashOverviewFragment.kt | 9 +- .../action/DashDeactivatePodViewModel.kt | 4 +- 22 files changed, 270 insertions(+), 103 deletions(-) create mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/Nonce.kt create mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/Session.kt diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt index aa878226287..6357672cc91 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt @@ -7,22 +7,24 @@ import android.bluetooth.BluetoothProfile import android.content.Context import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag -import info.nightscout.androidaps.plugins.pump.omnipod.dash.BuildConfig import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.callbacks.BleCommCallbacks import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.command.BleCommandHello +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.endecrypt.EnDecrypt import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.* import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.BleIO import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.CharacteristicType 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.scan.PodScanner +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session.EapSqn +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session.Session import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session.SessionEstablisher +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session.SessionKeys import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.status.ConnectionStatus import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.event.PodEvent import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.Command import info.nightscout.androidaps.utils.extensions.toHex import io.reactivex.Observable -import org.apache.commons.lang3.NotImplementedException import java.util.concurrent.BlockingQueue import java.util.concurrent.LinkedBlockingDeque import java.util.concurrent.TimeoutException @@ -38,6 +40,8 @@ class OmnipodDashBleManagerImpl @Inject constructor( private val bluetoothManager: BluetoothManager = context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager private val bluetoothAdapter: BluetoothAdapter = bluetoothManager.adapter + private var sessionKeys: SessionKeys? = null + private var msgIO: MessageIO? = null @Throws( FailedToConnectException::class, @@ -60,12 +64,8 @@ class OmnipodDashBleManagerImpl @Inject constructor( ) val bleCommCallbacks = BleCommCallbacks(aapsLogger, incomingPackets) aapsLogger.debug(LTag.PUMPBTCOMM, "Connecting to $podAddress") - var autoConnect = true - if (BuildConfig.DEBUG) { - autoConnect = false - // TODO: remove this in the future - // it's easier to start testing from scratch on each run. - } + val autoConnect = false // TODO: check what to use here + val gatt = podDevice.connectGatt(context, autoConnect, bleCommCallbacks, BluetoothDevice.TRANSPORT_LE) bleCommCallbacks.waitForConnection(CONNECT_TIMEOUT_MS) val connectionState = bluetoothManager.getConnectionState(podDevice, BluetoothProfile.GATT) @@ -81,9 +81,39 @@ class OmnipodDashBleManagerImpl @Inject constructor( return bleIO } - override fun sendCommand(cmd: Command): Observable { - // TODO - return Observable.error(NotImplementedException("sendCommand is not yet implemented")) + override fun sendCommand(cmd: Command): Observable = Observable.create { emitter -> + try { + val keys = sessionKeys + val mIO = msgIO + if (keys == null || mIO == null) { + //TODO handle reconnects + throw Exception("Not connected") + } + emitter.onNext(PodEvent.CommandSending(cmd)) + // TODO switch to RX + emitter.onNext(PodEvent.CommandSent(cmd)) + + val enDecrypt = EnDecrypt( + aapsLogger, + keys.nonce, + keys.ck, + ) + + val session = Session( + aapsLogger = aapsLogger, + msgIO = mIO, + myId = Id.fromInt(CONTROLLER_ID), + podId = Id.fromInt(CONTROLLER_ID).increment(), + sessionKeys = keys, + enDecrypt = enDecrypt + ) + val response = session.sendCommand(cmd) + emitter.onNext(PodEvent.ResponseReceived(response)) + + emitter.onComplete() + } catch (ex: Exception) { + emitter.tryOnError(ex) + } } override fun getStatus(): ConnectionStatus { @@ -107,7 +137,6 @@ class OmnipodDashBleManagerImpl @Inject constructor( // emit PodEvent.AlreadyConnected, complete the observable and return from this method try { - // TODO: this is wrong and I know it aapsLogger.info(LTag.PUMPBTCOMM, "starting new pod activation") val podScanner = PodScanner(aapsLogger, bluetoothAdapter) @@ -123,24 +152,30 @@ class OmnipodDashBleManagerImpl @Inject constructor( val bleIO = connect(podAddress) emitter.onNext(PodEvent.BluetoothConnected(podAddress)) - val msgIO = MessageIO(aapsLogger, bleIO) - val ltkExchanger = LTKExchanger(aapsLogger, msgIO) + val mIO = MessageIO(aapsLogger, bleIO) + val myId = Id.fromInt(CONTROLLER_ID) + val podId = myId.increment() + + val ltkExchanger = LTKExchanger(aapsLogger, mIO) emitter.onNext(PodEvent.Pairing) val ltk = ltkExchanger.negotiateLTK() - aapsLogger.info(LTag.PUMPCOMM, "Got LTK: ${ltk.ltk.toHex()}") - emitter.onNext(PodEvent.EstablishingSession) - val eapAkaExchanger = SessionEstablisher(aapsLogger, msgIO, ltk) - val sessionKeys = eapAkaExchanger.negotiateSessionKeys() - aapsLogger.info(LTag.PUMPCOMM, "CK: ${sessionKeys.ck.toHex()}") - aapsLogger.info(LTag.PUMPCOMM, "noncePrefix: ${sessionKeys.noncePrefix.toHex()}") - aapsLogger.info(LTag.PUMPCOMM, "SQN: ${sessionKeys.sqn.toHex()}") + val eapSqn = EapSqn(1) + aapsLogger.info(LTag.PUMPCOMM, "Got LTK: ${ltk.ltk.toHex()}") + val eapAkaExchanger = SessionEstablisher(aapsLogger, mIO, ltk, eapSqn) + val keys = eapAkaExchanger.negotiateSessionKeys() + aapsLogger.info(LTag.PUMPCOMM, "CK: ${keys.ck.toHex()}") + aapsLogger.info(LTag.PUMPCOMM, "msgSequenceNumber: ${keys.msgSequenceNumber}") + aapsLogger.info(LTag.PUMPCOMM, "Nonce: ${keys.nonce}") + + sessionKeys = keys + msgIO = mIO - emitter.onNext(PodEvent.Connected(ltk.podId.toLong())) // TODO supply actual pod id + emitter.onNext(PodEvent.Connected(ltk.podId.toLong())) emitter.onComplete() } catch (ex: Exception) { diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/callbacks/BleCommCallbacks.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/callbacks/BleCommCallbacks.kt index c1d50aa8901..72282849bc1 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/callbacks/BleCommCallbacks.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/callbacks/BleCommCallbacks.kt @@ -30,7 +30,7 @@ class BleCommCallbacks( override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) { super.onConnectionStateChange(gatt, status, newState) - aapsLogger.debug(LTag.PUMPBTCOMM, "OnConnectionStateChange discovered with status/state$status/$newState") + aapsLogger.debug(LTag.PUMPBTCOMM, "OnConnectionStateChange with status/state: $status/$newState") if (newState == BluetoothProfile.STATE_CONNECTED && status == BluetoothGatt.GATT_SUCCESS) { connected.countDown() } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/command/BleCommand.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/command/BleCommand.kt index e437bd23a9a..46c19cf6c58 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/command/BleCommand.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/command/BleCommand.kt @@ -2,6 +2,15 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.command import info.nightscout.androidaps.utils.extensions.toHex +class BleCommandRTS : BleCommand(BleCommandType.RTS) + +class BleCommandCTS : BleCommand(BleCommandType.CTS) + +class BleCommandAbort : BleCommand(BleCommandType.ABORT) + +class BleCommandSuccess : BleCommand(BleCommandType.SUCCESS) + +class BleCommandFail : BleCommand(BleCommandType.FAIL) open class BleCommand(val data: ByteArray) { constructor(type: BleCommandType) : this(byteArrayOf(type.value)) @@ -26,14 +35,4 @@ open class BleCommand(val data: ByteArray) { override fun hashCode(): Int { return data.contentHashCode() } -} - -class BleCommandRTS : BleCommand(BleCommandType.RTS) - -class BleCommandCTS : BleCommand(BleCommandType.CTS) - -class BleCommandAbort : BleCommand(BleCommandType.ABORT) - -class BleCommandSuccess : BleCommand(BleCommandType.SUCCESS) - -class BleCommandFail : BleCommand(BleCommandType.FAIL) +} \ No newline at end of file diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/CryptSequence.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/CryptSequence.kt index edfc2592152..35d638c91cd 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/CryptSequence.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/CryptSequence.kt @@ -1,24 +1,16 @@ -package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.endecrypt import java.nio.ByteBuffer class CryptSequence(var sqn: Long) { - fun incrementForEapAka():ByteArray { - sqn++ - return ByteBuffer.allocate(8) - .putLong(sqn) - .array() - .copyOfRange(2, 8) - } - - fun incrementForEnDecrypt(podReceiving: Boolean):ByteArray{ + fun incrementForEnDecrypt(fromPdmToPod: Boolean): ByteArray { sqn++ val ret = ByteBuffer.allocate(8) .putLong(sqn) .array() .copyOfRange(3, 8) - if (podReceiving) { + if (fromPdmToPod) { ret[0] = (ret[0].toInt() and 127).toByte() } else { ret[0] = (ret[0].toInt() or 128).toByte() diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/EnDecrypt.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/EnDecrypt.kt index a08b79bf8a2..0d359b99528 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/EnDecrypt.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/EnDecrypt.kt @@ -18,7 +18,7 @@ class EnDecrypt(private val aapsLogger: AAPSLogger, private val nonce: Nonce, pr val payload = msg.payload val header = msg.asByteArray().copyOfRange(0, 16) - val n = nonce.increment() + val n = nonce.increment(false) aapsLogger.debug(LTag.PUMPBTCOMM, "Decrypt header ${header.toHex()} payload: ${payload.toHex()}") aapsLogger.debug(LTag.PUMPBTCOMM, "Decrypt NONCE ${n.toHex()}") cipher.init( @@ -38,7 +38,7 @@ class EnDecrypt(private val aapsLogger: AAPSLogger, private val nonce: Nonce, pr val payload = headerMessage.payload val header = headerMessage.asByteArray(true).copyOfRange(0, 16) - val n = nonce.increment() + val n = nonce.increment(true) aapsLogger.debug(LTag.PUMPBTCOMM, "Encrypt header ${header.toHex()} payload: ${payload.toHex()}") aapsLogger.debug(LTag.PUMPBTCOMM, "Encrypt NONCE ${n.toHex()}") val encryptedPayload = ByteArray(payload.size + MAC_SIZE) diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/Nonce.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/Nonce.kt new file mode 100644 index 00000000000..a9662820cce --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/Nonce.kt @@ -0,0 +1,23 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.endecrypt + +import java.nio.ByteBuffer + +data class Nonce(val prefix: ByteArray, var sqn: Long) { + init { + require(prefix.size == 8) { "Nonce prefix should be 8 bytes long" } + } + + fun increment(podReceiving: Boolean): ByteArray { + sqn++ + val ret = ByteBuffer.allocate(8) + .putLong(sqn) + .array() + .copyOfRange(3, 8) + if (podReceiving) { + ret[0] = (ret[0].toInt() and 127).toByte() + } else { + ret[0] = (ret[0].toInt() or 128).toByte() + } + return prefix + ret + } +} \ No newline at end of file diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/exceptions/FailedToConnectException.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/exceptions/FailedToConnectException.kt index 4c138d0b2e7..07aba43b339 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/exceptions/FailedToConnectException.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/exceptions/FailedToConnectException.kt @@ -1,6 +1,5 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions open class FailedToConnectException : Exception { - constructor() : super() - constructor(message: String?) : super(message) + constructor(message: String?) : super("Failed to connect: ${message ?: ""}") } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/io/BleIO.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/io/BleIO.kt index f06661da0e1..9e6e994aa46 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/io/BleIO.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/io/BleIO.kt @@ -123,6 +123,6 @@ class BleIO( companion object { - private const val DEFAULT_IO_TIMEOUT_MS = 1000 + private const val DEFAULT_IO_TIMEOUT_MS = 10000 } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/MessageIO.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/MessageIO.kt index 5c2601311fd..5308c88a715 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/MessageIO.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/MessageIO.kt @@ -12,7 +12,7 @@ import info.nightscout.androidaps.utils.extensions.toHex class MessageIO(private val aapsLogger: AAPSLogger, private val bleIO: BleIO) { - fun sendMesssage(msg: MessagePacket) { + fun sendMessage(msg: MessagePacket) { bleIO.flushIncomingQueues() bleIO.sendAndConfirmPacket(CharacteristicType.CMD, BleCommandRTS().data) val expectCTS = bleIO.receivePacket(CharacteristicType.CMD) @@ -33,7 +33,6 @@ class MessageIO(private val aapsLogger: AAPSLogger, private val bleIO: BleIO) { throw UnexpectedCommandException(BleCommand(expectSuccess)) } // TODO: handle NACKS/FAILS/etc - bleIO.flushIncomingQueues() } fun receiveMessage(): MessagePacket { diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/MessagePacket.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/MessagePacket.kt index eba676f3887..e4350db605c 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/MessagePacket.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/MessagePacket.kt @@ -24,7 +24,7 @@ data class MessagePacket( val version: Short = 0.toShort() ) { - fun asByteArray(): ByteArray { + fun asByteArray(forEncryption: Boolean = false): ByteArray { val bb = ByteBuffer.allocate(16 + payload.size) bb.put(MAGIC_PATTERN.toByteArray()) @@ -52,9 +52,10 @@ data class MessagePacket( 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()) + val size = payload.size - + if (type == MessageType.ENCRYPTED && !forEncryption) 8 else 0 + bb.put((size ushr 3).toByte()) + bb.put((size shl 5).toByte()) bb.put(this.source.address) bb.put(this.destination.address) @@ -103,7 +104,7 @@ data class MessagePacket( throw CouldNotParseMessageException(payload) } val payloadEnd = 16 + size + - if (type == MessageType.ENCRYPTED) 8 + if (type == MessageType.ENCRYPTED) 8 // TAG else 0 return MessagePacket( diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadJoiner.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadJoiner.kt index 2cc75907c19..983a60d3740 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadJoiner.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadJoiner.kt @@ -29,7 +29,7 @@ class PayloadJoiner(private val firstPacket: ByteArray) { firstPacket.size < FirstBlePacket.HEADER_SIZE_WITHOUT_MIDDLE_PACKETS -> throw IncorrectPacketException(0, firstPacket) - fullFragments == 0 -> { + fullFragments == 0 -> { crc = ByteBuffer.wrap(firstPacket.copyOfRange(2, 6)).int.toUnsignedLong() val rest = firstPacket[6] val end = min(rest + FirstBlePacket.HEADER_SIZE_WITHOUT_MIDDLE_PACKETS, BlePacket.MAX_SIZE) @@ -41,10 +41,10 @@ class PayloadJoiner(private val firstPacket: ByteArray) { } // With middle packets - firstPacket.size < BlePacket.MAX_SIZE -> + firstPacket.size < BlePacket.MAX_SIZE -> throw IncorrectPacketException(0, firstPacket) - else -> { + else -> { fragments.add( firstPacket.copyOfRange( FirstBlePacket.HEADER_SIZE_WITH_MIDDLE_PACKETS, @@ -65,7 +65,7 @@ class PayloadJoiner(private val firstPacket: ByteArray) { } expectedIndex++ when { - idx < fullFragments -> { // this is a middle fragment + idx < fullFragments -> { // this is a middle fragment if (packet.size < BlePacket.MAX_SIZE) { throw IncorrectPacketException(idx.toByte(), packet) } @@ -86,7 +86,7 @@ class PayloadJoiner(private val firstPacket: ByteArray) { fragments.add(packet.copyOfRange(LastBlePacket.HEADER_SIZE, packet.size)) } - idx > fullFragments -> { // this is the extra fragment + idx > fullFragments -> { // this is the extra fragment val size = packet[1].toInt() if (packet.size < LastOptionalPlusOneBlePacket.HEADER_SIZE + size) { throw IncorrectPacketException(idx.toByte(), packet) diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/StringLengthPrefixEncoding.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/StringLengthPrefixEncoding.kt index 786a210bfb8..efc4d637232 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/StringLengthPrefixEncoding.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/StringLengthPrefixEncoding.kt @@ -18,15 +18,15 @@ class StringLengthPrefixEncoding { var remaining = payload for ((index, key) in keys.withIndex()) { when { - remaining.size < key.length -> + remaining.size < key.length -> throw MessageIOException("Payload too short: ${payload.toHex()} for key: $key") !(remaining.copyOfRange(0, key.length).decodeToString() == key) -> throw MessageIOException("Key not found: $key in ${payload.toHex()}") // last key can be empty, no length - index == keys.size - 1 && remaining.size == key.length -> + index == keys.size - 1 && remaining.size == key.length -> return ret - remaining.size < key.length + LENGTH_BYTES -> + remaining.size < key.length + LENGTH_BYTES -> throw MessageIOException("Length not found: for $key in ${payload.toHex()}") } remaining = remaining.copyOfRange(key.length, remaining.size) @@ -43,14 +43,17 @@ class StringLengthPrefixEncoding { fun formatKeys(keys: Array, payloads: Array): ByteArray { val payloadTotalSize = payloads.fold(0) { acc, i -> acc + i.size } val keyTotalSize = keys.fold(0) { acc, i -> acc + i.length } + val zeros = payloads.fold(0) { acc, i -> acc + if (i.size == 0) 1 else 0 } - val bb = ByteBuffer.allocate(2 * keys.size + keyTotalSize + payloadTotalSize) + val bb = ByteBuffer.allocate(2 * (keys.size - zeros) + 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) + if (payload.size > 0) { + bb.putShort(payload.size.toShort()) + bb.put(payload) + } } val ret = ByteArray(bb.position()) diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/LTKExchanger.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/LTKExchanger.kt index 4e586ba5818..3cab3565a77 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/LTKExchanger.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/LTKExchanger.kt @@ -40,11 +40,11 @@ internal class LTKExchanger(private val aapsLogger: AAPSLogger, private val msgI fun negotiateLTK(): PairResult { // send SP1, SP2 val sp1sp2 = sp1sp2(nodeId.address, sp2()) - msgIO.sendMesssage(sp1sp2.messagePacket) + msgIO.sendMessage(sp1sp2.messagePacket) seq++ val sps1 = sps1() - msgIO.sendMesssage(sps1.messagePacket) + msgIO.sendMessage(sps1.messagePacket) // send SPS1 // read SPS1 @@ -55,7 +55,7 @@ internal class LTKExchanger(private val aapsLogger: AAPSLogger, private val msgI seq++ // send SPS2 val sps2 = sps2() - msgIO.sendMesssage(sps2.messagePacket) + msgIO.sendMessage(sps2.messagePacket) // read SPS2 val podSps2 = msgIO.receiveMessage() @@ -63,7 +63,7 @@ internal class LTKExchanger(private val aapsLogger: AAPSLogger, private val msgI seq++ // send SP0GP0 - msgIO.sendMesssage(sp0gp0().messagePacket) + msgIO.sendMessage(sp0gp0().messagePacket) // read P0 // TODO: failing to read or validate p0 will lead to undefined state @@ -77,7 +77,7 @@ internal class LTKExchanger(private val aapsLogger: AAPSLogger, private val msgI return PairResult( ltk = ltk, podId = nodeId, - seq = seq + msgSeq = seq, ) } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/PairResult.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/PairResult.kt index 80aed263ab5..c6d087f38dd 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/PairResult.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/PairResult.kt @@ -3,7 +3,7 @@ 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.utils.extensions.toHex -data class PairResult(val ltk: ByteArray, val podId: Id, val seq: Byte) { +data class PairResult(val ltk: ByteArray, val podId: Id, val msgSeq: Byte) { init { require(ltk.size == 16) { "LTK length must be 16 bytes. Received LTK: ${ltk.toHex()}" } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapAkaAttribute.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapAkaAttribute.kt index ad193b87b8d..726d567151b 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapAkaAttribute.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapAkaAttribute.kt @@ -44,7 +44,7 @@ sealed class EapAkaAttribute { ret.add(EapAkaAttributeRes.parse(tail.copyOfRange(2, size))) EapAkaAttributeType.AT_CUSTOM_IV -> ret.add(EapAkaAttributeCustomIV.parse(tail.copyOfRange(2, size))) - else -> + else -> throw MessageIOException("Could not parse EAP attributes: ${payload.toHex()}. Expecting only AT_RES or CUSTOM_IV attribute types from the POD") } tail = tail.copyOfRange(size, tail.size) diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapSqn.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapSqn.kt index 1861167a50e..ef1b4bdc11a 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapSqn.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapSqn.kt @@ -1,4 +1,18 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session -class EapSqn { +import java.nio.ByteBuffer + +/*** + * Eap-Aka start session sequence. + * Incremented for each new session + */ +class EapSqn(var sqn: Long) { + + fun increment(): ByteArray { + sqn++ + return ByteBuffer.allocate(8) + .putLong(sqn) + .array() + .copyOfRange(2, 8) + } } \ No newline at end of file diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/Session.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/Session.kt new file mode 100644 index 00000000000..af4f6d0c271 --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/Session.kt @@ -0,0 +1,98 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session + +import info.nightscout.androidaps.logging.AAPSLogger +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.endecrypt.EnDecrypt +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.plugins.pump.omnipod.dash.driver.comm.message.StringLengthPrefixEncoding +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.StringLengthPrefixEncoding.Companion.parseKeys +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.Command +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.NakResponse +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.Response +import info.nightscout.androidaps.utils.extensions.toHex + +class Session( + private val aapsLogger: AAPSLogger, + private val msgIO: MessageIO, + private val myId: Id, + private val podId: Id, + val sessionKeys: SessionKeys, + val enDecrypt: EnDecrypt +) { + + /** + * Used for commands: + * -> command with retries + * <- response, ACK TODO: retries? + * -> ACK + */ + fun sendCommand(cmd: Command): Response { + sessionKeys.msgSequenceNumber++ + aapsLogger.debug(LTag.PUMPBTCOMM, "Sending command: ${cmd.encoded.toHex()}") + + val msg = getCmdMessage(cmd) + aapsLogger.debug(LTag.PUMPBTCOMM, "Sending command(wrapped): ${msg.payload.toHex()}") + msgIO.sendMessage(msg) + + val responseMsg = msgIO.receiveMessage() + val decrypted = enDecrypt.decrypt(responseMsg) + aapsLogger.debug(LTag.PUMPBTCOMM, "Received response: $decrypted") + val response = parseResponse(decrypted) + + sessionKeys.msgSequenceNumber++ + val ack = getAck(responseMsg) + aapsLogger.debug(LTag.PUMPBTCOMM, "Sending ACK: ${ack.payload.toHex()}") + msgIO.sendMessage(ack) + return response + } + + private fun parseResponse(decrypted: MessagePacket): Response { + val payload = parseKeys(arrayOf(RESPONSE_PREFIX), decrypted.payload)[0] + return NakResponse(payload) + } + + private fun getAck(response: MessagePacket): MessagePacket { + val msg = MessagePacket( + type = MessageType.ENCRYPTED, + sequenceNumber = sessionKeys.msgSequenceNumber, + source = myId, + destination = podId, + payload = ByteArray(0), + eqos = 1, + ack = true, + ackNumber = response.sequenceNumber.inc(), + ) + return enDecrypt.encrypt((msg)) + } + + private fun getCmdMessage(cmd: Command): MessagePacket { + val wrapped = StringLengthPrefixEncoding.formatKeys( + arrayOf(COMMAND_PREFIX, COMMAND_SUFFIX), + arrayOf(cmd.encoded, ByteArray(0)) + ) + + aapsLogger.debug(LTag.PUMPBTCOMM, "Sending command: ${wrapped.toHex()}") + + val msg = MessagePacket( + type = MessageType.ENCRYPTED, + sequenceNumber = sessionKeys.msgSequenceNumber, + source = myId, + destination = podId, + payload = wrapped, + eqos = 1 + ) + + return enDecrypt.encrypt(msg) + } + + companion object { + + private const val COMMAND_PREFIX = "S0.0=" + private const val COMMAND_SUFFIX = ",G0.0" + private const val RESPONSE_PREFIX = "0.0=" + + } +} \ No newline at end of file diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionEstablisher.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionEstablisher.kt index e4cda0594b5..6677742ba80 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionEstablisher.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionEstablisher.kt @@ -4,25 +4,29 @@ import info.nightscout.androidaps.logging.AAPSLogger 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.OmnipodDashBleManagerImpl +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.endecrypt.Nonce import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.SessionEstablishmentException 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.plugins.pump.omnipod.dash.driver.comm.pair.PairResult import info.nightscout.androidaps.utils.extensions.toHex -import org.spongycastle.util.encoders.Hex import java.security.SecureRandom -class SessionEstablisher(private val aapsLogger: AAPSLogger, private val msgIO: MessageIO, private val ltk: PairResult) { +class SessionEstablisher( + private val aapsLogger: AAPSLogger, + private val msgIO: MessageIO, + private val ltk: PairResult, + private val eapSqn: EapSqn +) { - var seq = ltk.seq + var sequenceNumber = ltk.msgSeq private val controllerIV = ByteArray(IV_SIZE) private var nodeIV = ByteArray(IV_SIZE) private val controllerId = Id.fromInt(OmnipodDashBleManagerImpl.CONTROLLER_ID) - private val sqn = byteArrayOf(0, 0, 0, 0, 0, 2) - private val milenage = Milenage(aapsLogger, ltk.ltk, sqn) + private val milenage = Milenage(aapsLogger, ltk.ltk, eapSqn.increment()) init { aapsLogger.debug(LTag.PUMPBTCOMM, "Starting EAP-AKA") @@ -32,21 +36,24 @@ class SessionEstablisher(private val aapsLogger: AAPSLogger, private val msgIO: fun negotiateSessionKeys(): SessionKeys { // send EAP-AKA challenge - seq++ //TODO: get from pod state. This only works for activating a new pod + sequenceNumber++ //TODO: get from pod state. This only works for activating a new pod var challenge = eapAkaChallenge() - msgIO.sendMesssage(challenge) + msgIO.sendMessage(challenge) val challengeResponse = msgIO.receiveMessage() processChallengeResponse(challengeResponse) //TODO: what do we have to answer if challenge response does not validate? - seq++ + sequenceNumber++ var success = eapSuccess() - msgIO.sendMesssage(success) + msgIO.sendMessage(success) return SessionKeys( - ck=milenage.ck, - noncePrefix = controllerIV + nodeIV, - sqn=sqn + ck = milenage.ck, + nonce = Nonce( + prefix = controllerIV + nodeIV, + sqn = 0 + ), + msgSequenceNumber = sequenceNumber ) } @@ -64,7 +71,7 @@ class SessionEstablisher(private val aapsLogger: AAPSLogger, private val msgIO: ) return MessagePacket( type = MessageType.SESSION_ESTABLISHMENT, - sequenceNumber = seq, + sequenceNumber = sequenceNumber, source = controllerId, destination = ltk.podId, payload = eapMsg.toByteArray() @@ -86,7 +93,7 @@ class SessionEstablisher(private val aapsLogger: AAPSLogger, private val msgIO: } is EapAkaAttributeCustomIV -> nodeIV = attr.payload.copyOfRange(0, IV_SIZE) - else -> + else -> throw SessionEstablishmentException("Unknown attribute received: $attr") } } @@ -101,7 +108,7 @@ class SessionEstablisher(private val aapsLogger: AAPSLogger, private val msgIO: return MessagePacket( type = MessageType.SESSION_ESTABLISHMENT, - sequenceNumber = seq, + sequenceNumber = sequenceNumber, source = controllerId, destination = ltk.podId, payload = eapMsg.toByteArray() diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionKeys.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionKeys.kt index e321be9c913..e4fb6a04d5c 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionKeys.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionKeys.kt @@ -1,9 +1,9 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session -data class SessionKeys(val ck: ByteArray, val noncePrefix: ByteArray, val sqn: ByteArray) { +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.endecrypt.Nonce + +data class SessionKeys(val ck: ByteArray, val nonce: Nonce, var msgSequenceNumber: Byte) { init { require(ck.size == 16) { "CK has to be 16 bytes long" } - require(noncePrefix.size == 8) { "noncePrefix has to be 8 bytes long" } - require(sqn.size == 6) { "SQN has to be 6 bytes long" } } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/event/PodEvent.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/event/PodEvent.kt index b0429dd1d5c..75775945c72 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/event/PodEvent.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/event/PodEvent.kt @@ -18,5 +18,5 @@ sealed class PodEvent { /* Message exchange events */ class CommandSending(val command: Command) : PodEvent() class CommandSent(val command: Command) : PodEvent() - class ResponseReceived(val response: Response) : PodEvent() + class ResponseReceived(val response:Response) : PodEvent() } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/OmnipodDashOverviewFragment.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/OmnipodDashOverviewFragment.kt index 66fbfbf27a3..275e995c913 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/OmnipodDashOverviewFragment.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/OmnipodDashOverviewFragment.kt @@ -324,13 +324,8 @@ class OmnipodDashOverviewFragment : DaggerFragment() { ) } - podInfoBinding.podActiveAlerts.text = if (podStateManager.activeAlerts!!.size > 0) { - // TODO - // TextUtils.join(System.lineSeparator(), omnipodUtil.getTranslatedActiveAlerts(podStateManager)) - "TODO" - } else { - PLACEHOLDER - } + podInfoBinding.podActiveAlerts.text = PLACEHOLDER + } if (errors.size == 0) { diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/wizard/deactivation/viewmodel/action/DashDeactivatePodViewModel.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/wizard/deactivation/viewmodel/action/DashDeactivatePodViewModel.kt index 9d2ad3a8699..8a6ec925713 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/wizard/deactivation/viewmodel/action/DashDeactivatePodViewModel.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/wizard/deactivation/viewmodel/action/DashDeactivatePodViewModel.kt @@ -6,16 +6,18 @@ import info.nightscout.androidaps.data.PumpEnactResult import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.plugins.pump.omnipod.common.R import info.nightscout.androidaps.plugins.pump.omnipod.common.ui.wizard.deactivation.viewmodel.action.DeactivatePodViewModel +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.OmnipodDashManager import io.reactivex.Single import javax.inject.Inject class DashDeactivatePodViewModel @Inject constructor( + private val omnipodManager: OmnipodDashManager, injector: HasAndroidInjector, logger: AAPSLogger ) : DeactivatePodViewModel(injector, logger) { override fun doExecuteAction(): Single = Single.just( - PumpEnactResult(injector).success(false).comment("TODO") + PumpEnactResult(injector).success(true).comment("TODO") ) // TODO override fun discardPod() { From c71433ad1aa22ee7e6ec44e263a00f8e2c0c2449 Mon Sep 17 00:00:00 2001 From: Andrei Vereha Date: Sat, 6 Mar 2021 11:07:24 +0100 Subject: [PATCH 04/11] format: remove trailing commao --- .../pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt | 2 +- .../plugins/pump/omnipod/dash/driver/comm/pair/LTKExchanger.kt | 2 +- .../plugins/pump/omnipod/dash/driver/comm/session/Session.kt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt index 6357672cc91..7bc3e04008a 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt @@ -96,7 +96,7 @@ class OmnipodDashBleManagerImpl @Inject constructor( val enDecrypt = EnDecrypt( aapsLogger, keys.nonce, - keys.ck, + keys.ck ) val session = Session( diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/LTKExchanger.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/LTKExchanger.kt index 3cab3565a77..f3a9615593e 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/LTKExchanger.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/LTKExchanger.kt @@ -77,7 +77,7 @@ internal class LTKExchanger(private val aapsLogger: AAPSLogger, private val msgI return PairResult( ltk = ltk, podId = nodeId, - msgSeq = seq, + msgSeq = seq ) } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/Session.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/Session.kt index af4f6d0c271..8f4e64bd6f6 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/Session.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/Session.kt @@ -63,7 +63,7 @@ class Session( payload = ByteArray(0), eqos = 1, ack = true, - ackNumber = response.sequenceNumber.inc(), + ackNumber = response.sequenceNumber.inc() ) return enDecrypt.encrypt((msg)) } From 4046828567277a41d9e8cd3b0f3987d256184bb4 Mon Sep 17 00:00:00 2001 From: Andrei Vereha Date: Sat, 6 Mar 2021 11:10:19 +0100 Subject: [PATCH 05/11] format: ktlint --- .../driver/comm/OmnipodDashBleManagerImpl.kt | 2 +- .../dash/driver/comm/command/BleCommand.kt | 2 +- .../driver/comm/endecrypt/CryptSequence.kt | 2 +- .../dash/driver/comm/endecrypt/EnDecrypt.kt | 28 ++++++++++--------- .../dash/driver/comm/endecrypt/Nonce.kt | 2 +- .../dash/driver/comm/message/PayloadJoiner.kt | 10 +++---- .../message/StringLengthPrefixEncoding.kt | 6 ++-- .../driver/comm/session/EapAkaAttribute.kt | 2 +- .../dash/driver/comm/session/EapSqn.kt | 2 +- .../dash/driver/comm/session/Session.kt | 3 +- .../driver/comm/session/SessionEstablisher.kt | 6 ++-- .../omnipod/dash/driver/event/PodEvent.kt | 2 +- .../pod/command/ProgramInsulinCommand.kt | 2 +- .../pod/definition/AlertConfiguration.kt | 2 +- .../driver/comm/endecrypt/EnDecryptTest.kt | 3 +- 15 files changed, 37 insertions(+), 37 deletions(-) diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt index 7bc3e04008a..c14fc4e7bf3 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt @@ -86,7 +86,7 @@ class OmnipodDashBleManagerImpl @Inject constructor( val keys = sessionKeys val mIO = msgIO if (keys == null || mIO == null) { - //TODO handle reconnects + // TODO handle reconnects throw Exception("Not connected") } emitter.onNext(PodEvent.CommandSending(cmd)) diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/command/BleCommand.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/command/BleCommand.kt index 46c19cf6c58..54a45fc54d4 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/command/BleCommand.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/command/BleCommand.kt @@ -35,4 +35,4 @@ open class BleCommand(val data: ByteArray) { override fun hashCode(): Int { return data.contentHashCode() } -} \ No newline at end of file +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/CryptSequence.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/CryptSequence.kt index 35d638c91cd..1eab261f61d 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/CryptSequence.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/CryptSequence.kt @@ -17,4 +17,4 @@ class CryptSequence(var sqn: Long) { } return ret } -} \ No newline at end of file +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/EnDecrypt.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/EnDecrypt.kt index 0d359b99528..b879cf61c82 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/EnDecrypt.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/EnDecrypt.kt @@ -22,12 +22,13 @@ class EnDecrypt(private val aapsLogger: AAPSLogger, private val nonce: Nonce, pr aapsLogger.debug(LTag.PUMPBTCOMM, "Decrypt header ${header.toHex()} payload: ${payload.toHex()}") aapsLogger.debug(LTag.PUMPBTCOMM, "Decrypt NONCE ${n.toHex()}") cipher.init( - false, AEADParameters( - KeyParameter(ck), - MAC_SIZE * 8, // in bits - n, - header - ) + false, + AEADParameters( + KeyParameter(ck), + MAC_SIZE * 8, // in bits + n, + header + ) ) val decryptedPayload = ByteArray(payload.size - MAC_SIZE) cipher.processPacket(payload, 0, payload.size, decryptedPayload, 0) @@ -44,12 +45,13 @@ class EnDecrypt(private val aapsLogger: AAPSLogger, private val nonce: Nonce, pr val encryptedPayload = ByteArray(payload.size + MAC_SIZE) cipher.init( - true, AEADParameters( - KeyParameter(ck), - MAC_SIZE * 8, // in bits - n, - header - ) + true, + AEADParameters( + KeyParameter(ck), + MAC_SIZE * 8, // in bits + n, + header + ) ) cipher.processPacket(payload, 0, payload.size, encryptedPayload, 0) @@ -60,4 +62,4 @@ class EnDecrypt(private val aapsLogger: AAPSLogger, private val nonce: Nonce, pr private val MAC_SIZE = 8 } -} \ No newline at end of file +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/Nonce.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/Nonce.kt index a9662820cce..0f53731ba04 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/Nonce.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/Nonce.kt @@ -20,4 +20,4 @@ data class Nonce(val prefix: ByteArray, var sqn: Long) { } return prefix + ret } -} \ No newline at end of file +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadJoiner.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadJoiner.kt index 983a60d3740..2cc75907c19 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadJoiner.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadJoiner.kt @@ -29,7 +29,7 @@ class PayloadJoiner(private val firstPacket: ByteArray) { firstPacket.size < FirstBlePacket.HEADER_SIZE_WITHOUT_MIDDLE_PACKETS -> throw IncorrectPacketException(0, firstPacket) - fullFragments == 0 -> { + fullFragments == 0 -> { crc = ByteBuffer.wrap(firstPacket.copyOfRange(2, 6)).int.toUnsignedLong() val rest = firstPacket[6] val end = min(rest + FirstBlePacket.HEADER_SIZE_WITHOUT_MIDDLE_PACKETS, BlePacket.MAX_SIZE) @@ -41,10 +41,10 @@ class PayloadJoiner(private val firstPacket: ByteArray) { } // With middle packets - firstPacket.size < BlePacket.MAX_SIZE -> + firstPacket.size < BlePacket.MAX_SIZE -> throw IncorrectPacketException(0, firstPacket) - else -> { + else -> { fragments.add( firstPacket.copyOfRange( FirstBlePacket.HEADER_SIZE_WITH_MIDDLE_PACKETS, @@ -65,7 +65,7 @@ class PayloadJoiner(private val firstPacket: ByteArray) { } expectedIndex++ when { - idx < fullFragments -> { // this is a middle fragment + idx < fullFragments -> { // this is a middle fragment if (packet.size < BlePacket.MAX_SIZE) { throw IncorrectPacketException(idx.toByte(), packet) } @@ -86,7 +86,7 @@ class PayloadJoiner(private val firstPacket: ByteArray) { fragments.add(packet.copyOfRange(LastBlePacket.HEADER_SIZE, packet.size)) } - idx > fullFragments -> { // this is the extra fragment + idx > fullFragments -> { // this is the extra fragment val size = packet[1].toInt() if (packet.size < LastOptionalPlusOneBlePacket.HEADER_SIZE + size) { throw IncorrectPacketException(idx.toByte(), packet) diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/StringLengthPrefixEncoding.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/StringLengthPrefixEncoding.kt index efc4d637232..192edfd1fcd 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/StringLengthPrefixEncoding.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/StringLengthPrefixEncoding.kt @@ -18,15 +18,15 @@ class StringLengthPrefixEncoding { var remaining = payload for ((index, key) in keys.withIndex()) { when { - remaining.size < key.length -> + remaining.size < key.length -> throw MessageIOException("Payload too short: ${payload.toHex()} for key: $key") !(remaining.copyOfRange(0, key.length).decodeToString() == key) -> throw MessageIOException("Key not found: $key in ${payload.toHex()}") // last key can be empty, no length - index == keys.size - 1 && remaining.size == key.length -> + index == keys.size - 1 && remaining.size == key.length -> return ret - remaining.size < key.length + LENGTH_BYTES -> + remaining.size < key.length + LENGTH_BYTES -> throw MessageIOException("Length not found: for $key in ${payload.toHex()}") } remaining = remaining.copyOfRange(key.length, remaining.size) diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapAkaAttribute.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapAkaAttribute.kt index 726d567151b..ad193b87b8d 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapAkaAttribute.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapAkaAttribute.kt @@ -44,7 +44,7 @@ sealed class EapAkaAttribute { ret.add(EapAkaAttributeRes.parse(tail.copyOfRange(2, size))) EapAkaAttributeType.AT_CUSTOM_IV -> ret.add(EapAkaAttributeCustomIV.parse(tail.copyOfRange(2, size))) - else -> + else -> throw MessageIOException("Could not parse EAP attributes: ${payload.toHex()}. Expecting only AT_RES or CUSTOM_IV attribute types from the POD") } tail = tail.copyOfRange(size, tail.size) diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapSqn.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapSqn.kt index ef1b4bdc11a..03408f8735c 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapSqn.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapSqn.kt @@ -15,4 +15,4 @@ class EapSqn(var sqn: Long) { .array() .copyOfRange(2, 8) } -} \ No newline at end of file +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/Session.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/Session.kt index 8f4e64bd6f6..d5fc2739dab 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/Session.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/Session.kt @@ -93,6 +93,5 @@ class Session( private const val COMMAND_PREFIX = "S0.0=" private const val COMMAND_SUFFIX = ",G0.0" private const val RESPONSE_PREFIX = "0.0=" - } -} \ No newline at end of file +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionEstablisher.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionEstablisher.kt index 6677742ba80..8a6c2a30c44 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionEstablisher.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionEstablisher.kt @@ -36,12 +36,12 @@ class SessionEstablisher( fun negotiateSessionKeys(): SessionKeys { // send EAP-AKA challenge - sequenceNumber++ //TODO: get from pod state. This only works for activating a new pod + sequenceNumber++ // TODO: get from pod state. This only works for activating a new pod var challenge = eapAkaChallenge() msgIO.sendMessage(challenge) val challengeResponse = msgIO.receiveMessage() - processChallengeResponse(challengeResponse) //TODO: what do we have to answer if challenge response does not validate? + processChallengeResponse(challengeResponse) // TODO: what do we have to answer if challenge response does not validate? sequenceNumber++ var success = eapSuccess() @@ -93,7 +93,7 @@ class SessionEstablisher( } is EapAkaAttributeCustomIV -> nodeIV = attr.payload.copyOfRange(0, IV_SIZE) - else -> + else -> throw SessionEstablishmentException("Unknown attribute received: $attr") } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/event/PodEvent.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/event/PodEvent.kt index 75775945c72..b0429dd1d5c 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/event/PodEvent.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/event/PodEvent.kt @@ -18,5 +18,5 @@ sealed class PodEvent { /* Message exchange events */ class CommandSending(val command: Command) : PodEvent() class CommandSent(val command: Command) : PodEvent() - class ResponseReceived(val response:Response) : PodEvent() + class ResponseReceived(val response: Response) : PodEvent() } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.kt index 6aff972e180..437d52029c2 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/command/ProgramInsulinCommand.kt @@ -13,7 +13,7 @@ class ProgramInsulinCommand internal constructor( multiCommandFlag: Boolean, nonce: Int, insulinProgramElements: - List, + List, private val checksum: Short, private val byte9: Byte, private val byte10And11: Short, diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/AlertConfiguration.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/AlertConfiguration.kt index 20536b6527a..aab7cde1381 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/AlertConfiguration.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/definition/AlertConfiguration.kt @@ -35,7 +35,7 @@ class AlertConfiguration( trigger.thresholdInMicroLiters } - is AlertTrigger.TimerTrigger -> { + is AlertTrigger.TimerTrigger -> { trigger.offsetInMinutes } } diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/EnDecryptTest.kt b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/EnDecryptTest.kt index 05851bd2616..a78bd5fae19 100644 --- a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/EnDecryptTest.kt +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/EnDecryptTest.kt @@ -54,6 +54,5 @@ class EnDecryptTest { val encrypted = enDecrypt.encrypt(msg) Assert.assertEquals(encryptedMessage.toHex(), encrypted.asByteArray().toHex()) - } -} \ No newline at end of file +} From e7a9e24093d92af9be8ff4716c9a0160edc54949 Mon Sep 17 00:00:00 2001 From: Andrei Vereha Date: Sat, 6 Mar 2021 21:12:20 +0100 Subject: [PATCH 06/11] dash: start using podState for BLE implement disconnect() various fixes after testing with a real pod(cmd is 2 bytes, message joining, etc) --- .../pump/omnipod/dash/driver/comm/Id.kt | 3 + .../driver/comm/OmnipodDashBleManagerImpl.kt | 113 ++++++++++++------ .../dash/driver/comm/command/BleCommand.kt | 3 +- .../dash/driver/comm/message/PayloadJoiner.kt | 6 +- .../dash/driver/comm/pair/LTKExchanger.kt | 23 ++-- .../dash/driver/comm/pair/PairResult.kt | 2 +- .../dash/driver/comm/session/EapMessage.kt | 2 +- .../driver/comm/session/SessionEstablisher.kt | 39 +++--- .../driver/comm/status/ConnectionStatus.kt | 8 +- .../pod/state/OmnipodDashPodStateManager.kt | 4 + .../state/OmnipodDashPodStateManagerImpl.kt | 29 +++++ 11 files changed, 155 insertions(+), 77 deletions(-) diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/Id.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/Id.kt index 3847d0588c7..b78aa5ecc57 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/Id.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/Id.kt @@ -36,5 +36,8 @@ data class Id(val address: ByteArray) { fun fromInt(v: Int): Id { return Id(ByteBuffer.allocate(4).putInt(v).array()) } + fun fromLong(v: Long): Id { + return Id(ByteBuffer.allocate(8).putLong(v).array().copyOfRange(4,8)) + } } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt index c14fc4e7bf3..a7c50bff4ef 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt @@ -2,11 +2,13 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm import android.bluetooth.BluetoothAdapter import android.bluetooth.BluetoothDevice +import android.bluetooth.BluetoothGatt import android.bluetooth.BluetoothManager import android.bluetooth.BluetoothProfile import android.content.Context import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.pump.omnipod.dash.BuildConfig import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.callbacks.BleCommCallbacks import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.command.BleCommandHello import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.endecrypt.EnDecrypt @@ -16,13 +18,13 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.Chara 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.scan.PodScanner -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session.EapSqn import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session.Session import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session.SessionEstablisher import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session.SessionKeys import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.status.ConnectionStatus import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.event.PodEvent import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.Command +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager import info.nightscout.androidaps.utils.extensions.toHex import io.reactivex.Observable import java.util.concurrent.BlockingQueue @@ -34,7 +36,8 @@ import javax.inject.Singleton @Singleton class OmnipodDashBleManagerImpl @Inject constructor( private val context: Context, - private val aapsLogger: AAPSLogger + private val aapsLogger: AAPSLogger, + private val podState: OmnipodDashPodStateManager ) : OmnipodDashBleManager { private val bluetoothManager: BluetoothManager = @@ -42,6 +45,8 @@ class OmnipodDashBleManagerImpl @Inject constructor( private val bluetoothAdapter: BluetoothAdapter = bluetoothManager.adapter private var sessionKeys: SessionKeys? = null private var msgIO: MessageIO? = null + private var gatt: BluetoothGatt? = null + private var status: ConnectionStatus = ConnectionStatus.IDLE @Throws( FailedToConnectException::class, @@ -54,30 +59,29 @@ class OmnipodDashBleManagerImpl @Inject constructor( DescriptorNotFoundException::class, CouldNotConfirmDescriptorWriteException::class ) - private fun connect(podAddress: String): BleIO { - // TODO: locking? - val podDevice = bluetoothAdapter.getRemoteDevice(podAddress) + private fun connect(podDevice: BluetoothDevice): BleIO { val incomingPackets: Map> = mapOf( CharacteristicType.CMD to LinkedBlockingDeque(), CharacteristicType.DATA to LinkedBlockingDeque() ) val bleCommCallbacks = BleCommCallbacks(aapsLogger, incomingPackets) - aapsLogger.debug(LTag.PUMPBTCOMM, "Connecting to $podAddress") + aapsLogger.debug(LTag.PUMPBTCOMM, "Connecting to ${podDevice.address}") val autoConnect = false // TODO: check what to use here - val gatt = podDevice.connectGatt(context, autoConnect, bleCommCallbacks, BluetoothDevice.TRANSPORT_LE) + val gattConnection = podDevice.connectGatt(context, autoConnect, bleCommCallbacks, BluetoothDevice.TRANSPORT_LE) bleCommCallbacks.waitForConnection(CONNECT_TIMEOUT_MS) val connectionState = bluetoothManager.getConnectionState(podDevice, BluetoothProfile.GATT) aapsLogger.debug(LTag.PUMPBTCOMM, "GATT connection state: $connectionState") if (connectionState != BluetoothProfile.STATE_CONNECTED) { - throw FailedToConnectException(podAddress) + throw FailedToConnectException(podDevice.address) } - val discoverer = ServiceDiscoverer(aapsLogger, gatt, bleCommCallbacks) + val discoverer = ServiceDiscoverer(aapsLogger, gattConnection, bleCommCallbacks) val chars = discoverer.discoverServices() - val bleIO = BleIO(aapsLogger, chars, incomingPackets, gatt, bleCommCallbacks) + val bleIO = BleIO(aapsLogger, chars, incomingPackets, gattConnection, bleCommCallbacks) bleIO.sendAndConfirmPacket(CharacteristicType.CMD, BleCommandHello(CONTROLLER_ID).data) bleIO.readyToRead() + gatt = gattConnection return bleIO } @@ -117,7 +121,11 @@ class OmnipodDashBleManagerImpl @Inject constructor( } override fun getStatus(): ConnectionStatus { - TODO("not implemented") + var s: ConnectionStatus + synchronized(status) { + s = status + } + return s } @Throws( @@ -132,50 +140,77 @@ class OmnipodDashBleManagerImpl @Inject constructor( DescriptorNotFoundException::class, CouldNotConfirmDescriptorWriteException::class ) + override fun connect(): Observable = Observable.create { emitter -> // TODO: when we are already connected, // emit PodEvent.AlreadyConnected, complete the observable and return from this method - try { - aapsLogger.info(LTag.PUMPBTCOMM, "starting new pod activation") - - val podScanner = PodScanner(aapsLogger, bluetoothAdapter) - emitter.onNext(PodEvent.Scanning) - - val podAddress = podScanner.scanForPod( - PodScanner.SCAN_FOR_SERVICE_UUID, - PodScanner.POD_ID_NOT_ACTIVATED - ).scanResult.device.address - // For tests: this.podAddress = "B8:27:EB:1D:7E:BB"; + if (podState.bluetoothAddress == null) { + aapsLogger.info(LTag.PUMPBTCOMM, "starting new pod activation") + + val podScanner = PodScanner(aapsLogger, bluetoothAdapter) + emitter.onNext(PodEvent.Scanning) + + val podAddress = podScanner.scanForPod( + PodScanner.SCAN_FOR_SERVICE_UUID, + PodScanner.POD_ID_NOT_ACTIVATED + ).scanResult.device.address + // For tests: this.podAddress = "B8:27:EB:1D:7E:BB"; + podState.bluetoothAddress = podAddress + } emitter.onNext(PodEvent.BluetoothConnecting) + val podAddress = podState.bluetoothAddress ?: throw FailedToConnectException("Lost connection") + // check if already connected + val podDevice = bluetoothAdapter.getRemoteDevice(podAddress) + val connectionState = bluetoothManager.getConnectionState(podDevice, BluetoothProfile.GATT) + aapsLogger.debug(LTag.PUMPBTCOMM, "GATT connection state: $connectionState") - val bleIO = connect(podAddress) emitter.onNext(PodEvent.BluetoothConnected(podAddress)) + if (connectionState == BluetoothProfile.STATE_CONNECTED) { + podState.uniqueId ?: throw FailedToConnectException("Already connection and uniqueId is missing") + emitter.onNext(PodEvent.AlreadyConnected(podAddress, podState.uniqueId ?: 0)) + emitter.onComplete() + return@create + } + if (msgIO != null) { + disconnect() + } + val bleIO = connect(podDevice) val mIO = MessageIO(aapsLogger, bleIO) val myId = Id.fromInt(CONTROLLER_ID) val podId = myId.increment() + var msgSeq = 1.toByte() + val ltkExchanger = LTKExchanger(aapsLogger, mIO, myId, podId, Id.fromLong(PodScanner.POD_ID_NOT_ACTIVATED)) + if (podState.ltk == null) { + emitter.onNext(PodEvent.Pairing) + val pairResult = ltkExchanger.negotiateLTK() + podState.ltk = pairResult.ltk + podState.uniqueId = podId.toLong() + msgSeq = pairResult.msgSeq + podState.eapAkaSequenceNumber = 1 + if (BuildConfig.DEBUG) { + aapsLogger.info(LTag.PUMPCOMM, "Got LTK: ${pairResult.ltk.toHex()}") + } + } - val ltkExchanger = LTKExchanger(aapsLogger, mIO) - - emitter.onNext(PodEvent.Pairing) - - val ltk = ltkExchanger.negotiateLTK() + val ltk: ByteArray = podState.ltk!! emitter.onNext(PodEvent.EstablishingSession) - - val eapSqn = EapSqn(1) - aapsLogger.info(LTag.PUMPCOMM, "Got LTK: ${ltk.ltk.toHex()}") - val eapAkaExchanger = SessionEstablisher(aapsLogger, mIO, ltk, eapSqn) + val eapSqn = podState.increaseEapAkaSequenceNumber() + val eapAkaExchanger = SessionEstablisher(aapsLogger, mIO, ltk, eapSqn, myId, podId, msgSeq) val keys = eapAkaExchanger.negotiateSessionKeys() - aapsLogger.info(LTag.PUMPCOMM, "CK: ${keys.ck.toHex()}") - aapsLogger.info(LTag.PUMPCOMM, "msgSequenceNumber: ${keys.msgSequenceNumber}") - aapsLogger.info(LTag.PUMPCOMM, "Nonce: ${keys.nonce}") + podState.commitEapAkaSequenceNumber() + if (BuildConfig.DEBUG) { + aapsLogger.info(LTag.PUMPCOMM, "CK: ${keys.ck.toHex()}") + aapsLogger.info(LTag.PUMPCOMM, "msgSequenceNumber: ${keys.msgSequenceNumber}") + aapsLogger.info(LTag.PUMPCOMM, "Nonce: ${keys.nonce}") + } sessionKeys = keys msgIO = mIO - emitter.onNext(PodEvent.Connected(ltk.podId.toLong())) + emitter.onNext(PodEvent.Connected(podId.toLong())) emitter.onComplete() } catch (ex: Exception) { @@ -184,7 +219,11 @@ class OmnipodDashBleManagerImpl @Inject constructor( } override fun disconnect() { - TODO("not implemented") + val localGatt = gatt + localGatt?.close() + gatt = null + msgIO = null + sessionKeys = null } companion object { diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/command/BleCommand.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/command/BleCommand.kt index 54a45fc54d4..70d787b01e9 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/command/BleCommand.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/command/BleCommand.kt @@ -11,9 +11,10 @@ class BleCommandAbort : BleCommand(BleCommandType.ABORT) class BleCommandSuccess : BleCommand(BleCommandType.SUCCESS) class BleCommandFail : BleCommand(BleCommandType.FAIL) + open class BleCommand(val data: ByteArray) { - constructor(type: BleCommandType) : this(byteArrayOf(type.value)) + constructor(type: BleCommandType) : this(byteArrayOf(type.value, 0)) constructor(type: BleCommandType, payload: ByteArray) : this( byteArrayOf(type.value) + payload diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadJoiner.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadJoiner.kt index 2cc75907c19..e4fe95c42ee 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadJoiner.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PayloadJoiner.kt @@ -32,7 +32,7 @@ class PayloadJoiner(private val firstPacket: ByteArray) { fullFragments == 0 -> { crc = ByteBuffer.wrap(firstPacket.copyOfRange(2, 6)).int.toUnsignedLong() val rest = firstPacket[6] - val end = min(rest + FirstBlePacket.HEADER_SIZE_WITHOUT_MIDDLE_PACKETS, BlePacket.MAX_SIZE) + val end = min(rest + FirstBlePacket.HEADER_SIZE_WITHOUT_MIDDLE_PACKETS, firstPacket.size) oneExtraPacket = rest + FirstBlePacket.HEADER_SIZE_WITHOUT_MIDDLE_PACKETS > end if (end > firstPacket.size) { throw IncorrectPacketException(0, firstPacket) @@ -78,12 +78,12 @@ class PayloadJoiner(private val firstPacket: ByteArray) { } crc = ByteBuffer.wrap(packet.copyOfRange(2, 6)).int.toUnsignedLong() val rest = packet[1].toInt() - val end = min(rest + LastBlePacket.HEADER_SIZE, BlePacket.MAX_SIZE) + val end = min(rest + LastBlePacket.HEADER_SIZE, packet.size) oneExtraPacket = rest + LastBlePacket.HEADER_SIZE > end if (packet.size < end) { throw IncorrectPacketException(idx.toByte(), packet) } - fragments.add(packet.copyOfRange(LastBlePacket.HEADER_SIZE, packet.size)) + fragments.add(packet.copyOfRange(LastBlePacket.HEADER_SIZE, end)) } idx > fullFragments -> { // this is the extra fragment diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/LTKExchanger.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/LTKExchanger.kt index f3a9615593e..5965d117452 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/LTKExchanger.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/LTKExchanger.kt @@ -18,7 +18,7 @@ import org.spongycastle.crypto.macs.CMac import org.spongycastle.crypto.params.KeyParameter import java.security.SecureRandom -internal class LTKExchanger(private val aapsLogger: AAPSLogger, private val msgIO: MessageIO) { +internal class LTKExchanger(private val aapsLogger: AAPSLogger, private val msgIO: MessageIO, val myId: Id, val podId: Id, val podAddress: Id) { private val pdmPrivate = X25519.generatePrivateKey() private val pdmPublic = X25519.publicFromPrivate(pdmPrivate) @@ -27,8 +27,6 @@ internal class LTKExchanger(private val aapsLogger: AAPSLogger, private val msgI private val pdmNonce = ByteArray(NONCE_SIZE) private val pdmConf = ByteArray(CMAC_SIZE) private val podConf = ByteArray(CMAC_SIZE) - private val controllerId = Id.fromInt(OmnipodDashBleManagerImpl.CONTROLLER_ID) - val nodeId = controllerId.increment() private var seq: Byte = 1 private var ltk = ByteArray(CMAC_SIZE) @@ -39,7 +37,7 @@ internal class LTKExchanger(private val aapsLogger: AAPSLogger, private val msgI fun negotiateLTK(): PairResult { // send SP1, SP2 - val sp1sp2 = sp1sp2(nodeId.address, sp2()) + val sp1sp2 = sp1sp2(podId.address, sp2()) msgIO.sendMessage(sp1sp2.messagePacket) seq++ @@ -76,7 +74,6 @@ internal class LTKExchanger(private val aapsLogger: AAPSLogger, private val msgI return PairResult( ltk = ltk, - podId = nodeId, msgSeq = seq ) } @@ -88,8 +85,8 @@ internal class LTKExchanger(private val aapsLogger: AAPSLogger, private val msgI ) return PairMessage( sequenceNumber = seq, - source = controllerId, - destination = nodeId, + source = myId, + destination = podAddress, payload = payload ) } @@ -101,8 +98,8 @@ internal class LTKExchanger(private val aapsLogger: AAPSLogger, private val msgI ) return PairMessage( sequenceNumber = seq, - source = controllerId, - destination = nodeId, + source = myId, + destination = podAddress, payload = payload ) } @@ -125,8 +122,8 @@ internal class LTKExchanger(private val aapsLogger: AAPSLogger, private val msgI ) return PairMessage( sequenceNumber = seq, - source = controllerId, - destination = nodeId, + source = myId, + destination = podAddress, payload = payload ) } @@ -159,8 +156,8 @@ internal class LTKExchanger(private val aapsLogger: AAPSLogger, private val msgI val payload = SP0GP0.toByteArray() return PairMessage( sequenceNumber = seq, - source = controllerId, - destination = nodeId, + source = myId, + destination = podAddress, payload = payload ) } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/PairResult.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/PairResult.kt index c6d087f38dd..c23be1d0a52 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/PairResult.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/PairResult.kt @@ -3,7 +3,7 @@ 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.utils.extensions.toHex -data class PairResult(val ltk: ByteArray, val podId: Id, val msgSeq: Byte) { +data class PairResult(val ltk: ByteArray, val msgSeq: Byte) { init { require(ltk.size == 16) { "LTK length must be 16 bytes. Received LTK: ${ltk.toHex()}" } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapMessage.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapMessage.kt index 7f62c3b194b..d25802c079a 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapMessage.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapMessage.kt @@ -78,7 +78,7 @@ data class EapMessage( throw MessageIOException("Invalid eap payload. Expected AKA packet type: ${payload.toHex()}") } val attributesPayload = payload.copyOfRange(8, totalSize) - aapsLogger.debug(LTag.PUMPBTCOMM, "EAP attributes: ${attributesPayload.toByteString()}") + aapsLogger.debug(LTag.PUMPBTCOMM, "parsing EAP payload: ${payload.toHex()}") return EapMessage( code = EapCode.byValue(payload[0]), identifier = payload[1], diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionEstablisher.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionEstablisher.kt index 8a6c2a30c44..e8b89cc73c3 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionEstablisher.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionEstablisher.kt @@ -3,32 +3,33 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session import info.nightscout.androidaps.logging.AAPSLogger 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.OmnipodDashBleManagerImpl import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.endecrypt.Nonce import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.SessionEstablishmentException 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.plugins.pump.omnipod.dash.driver.comm.pair.PairResult import info.nightscout.androidaps.utils.extensions.toHex import java.security.SecureRandom class SessionEstablisher( private val aapsLogger: AAPSLogger, private val msgIO: MessageIO, - private val ltk: PairResult, - private val eapSqn: EapSqn + private val ltk: ByteArray, + private val eapSqn: ByteArray, + private val myId: Id, + private val podId: Id, + private var msgSeq: Byte ) { - var sequenceNumber = ltk.msgSeq - private val controllerIV = ByteArray(IV_SIZE) private var nodeIV = ByteArray(IV_SIZE) - private val controllerId = Id.fromInt(OmnipodDashBleManagerImpl.CONTROLLER_ID) - private val milenage = Milenage(aapsLogger, ltk.ltk, eapSqn.increment()) + private val milenage = Milenage(aapsLogger, ltk, eapSqn) init { + require(eapSqn.size == 6) {"EAP-SQN has to be 6 bytes long"} + require(ltk.size == 16) {"LTK has to be 16 bytes long"} + aapsLogger.debug(LTag.PUMPBTCOMM, "Starting EAP-AKA") val random = SecureRandom() random.nextBytes(controllerIV) @@ -36,14 +37,14 @@ class SessionEstablisher( fun negotiateSessionKeys(): SessionKeys { // send EAP-AKA challenge - sequenceNumber++ // TODO: get from pod state. This only works for activating a new pod + msgSeq++ // TODO: get from pod state. This only works for activating a new pod var challenge = eapAkaChallenge() msgIO.sendMessage(challenge) val challengeResponse = msgIO.receiveMessage() processChallengeResponse(challengeResponse) // TODO: what do we have to answer if challenge response does not validate? - sequenceNumber++ + msgSeq++ var success = eapSuccess() msgIO.sendMessage(success) @@ -53,7 +54,7 @@ class SessionEstablisher( prefix = controllerIV + nodeIV, sqn = 0 ), - msgSequenceNumber = sequenceNumber + msgSequenceNumber = msgSeq ) } @@ -66,14 +67,14 @@ class SessionEstablisher( val eapMsg = EapMessage( code = EapCode.REQUEST, - identifier = 42, // TODO: find what value we need here, it's probably random + identifier = 189.toByte(), // TODO: find what value we need here, it's probably random attributes = attributes ) return MessagePacket( type = MessageType.SESSION_ESTABLISHMENT, - sequenceNumber = sequenceNumber, - source = controllerId, - destination = ltk.podId, + sequenceNumber = msgSeq, + source = myId, + destination = podId, payload = eapMsg.toByteArray() ) } @@ -103,14 +104,14 @@ class SessionEstablisher( val eapMsg = EapMessage( code = EapCode.SUCCESS, attributes = arrayOf(), - identifier = 44 // TODO: find what value we need here + identifier = 189.toByte() // TODO: find what value we need here ) return MessagePacket( type = MessageType.SESSION_ESTABLISHMENT, - sequenceNumber = sequenceNumber, - source = controllerId, - destination = ltk.podId, + sequenceNumber = msgSeq, + source = myId, + destination = podId, payload = eapMsg.toByteArray() ) } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/status/ConnectionStatus.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/status/ConnectionStatus.kt index 8343887516a..6977f342f33 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/status/ConnectionStatus.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/status/ConnectionStatus.kt @@ -1,6 +1,10 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.status enum class ConnectionStatus { - CONNECTED, - NOT_CONNECTED; + IDLE, + BUSY, + CONNECTING, + ESTABLISHING_SESSION, + PAIRING, + RUNNING_COMMAND; } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManager.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManager.kt index 8270e1cd18e..49d3aceb79c 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManager.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManager.kt @@ -23,6 +23,8 @@ interface OmnipodDashPodStateManager { val activationTime: Long? var uniqueId: Long? // TODO make Int var bluetoothAddress: String? + var ltk: ByteArray? + var eapAkaSequenceNumber: Long val bluetoothVersion: SoftwareVersion? val firmwareVersion: SoftwareVersion? @@ -46,6 +48,8 @@ interface OmnipodDashPodStateManager { val basalProgram: BasalProgram? fun increaseMessageSequenceNumber() + fun increaseEapAkaSequenceNumber():ByteArray + fun commitEapAkaSequenceNumber() fun updateFromDefaultStatusResponse(response: DefaultStatusResponse) fun updateFromVersionResponse(response: VersionResponse) fun updateFromSetUniqueIdResponse(response: SetUniqueIdResponse) diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManagerImpl.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManagerImpl.kt index becac573450..c535536726c 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManagerImpl.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManagerImpl.kt @@ -13,6 +13,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response. import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.VersionResponse import info.nightscout.androidaps.utils.sharedPreferences.SP import java.io.Serializable +import java.nio.ByteBuffer import java.util.* import javax.inject.Inject import javax.inject.Singleton @@ -150,6 +151,32 @@ class OmnipodDashPodStateManagerImpl @Inject constructor( store() } + override var eapAkaSequenceNumber: Long + get() = podState.eapAkaSequenceNumber + set(value) { + podState.eapAkaSequenceNumber = value + store() + } + + override var ltk: ByteArray? + get() = podState.ltk + set(value) { + podState.ltk = value + store() + } + + override fun increaseEapAkaSequenceNumber():ByteArray { + podState.eapAkaSequenceNumber++ + return ByteBuffer.allocate(8) + .putLong(podState.eapAkaSequenceNumber) + .array() + .copyOfRange(2, 8) + } + + override fun commitEapAkaSequenceNumber() { + store() + } + override fun updateFromDefaultStatusResponse(response: DefaultStatusResponse) { podState.deliveryStatus = response.deliveryStatus podState.podStatus = response.podStatus @@ -262,6 +289,8 @@ class OmnipodDashPodStateManagerImpl @Inject constructor( var activationTime: Long? = null var uniqueId: Long? = null var bluetoothAddress: String? = null + var ltk: ByteArray? = null + var eapAkaSequenceNumber: Long = 1 var bleVersion: SoftwareVersion? = null var firmwareVersion: SoftwareVersion? = null From 7dd8fc1bf68e2d716e1bff8e0af9a6a7a88d1e41 Mon Sep 17 00:00:00 2001 From: Andrei Vereha Date: Sat, 6 Mar 2021 21:16:03 +0100 Subject: [PATCH 07/11] dash/ble: ktlintFormat --- .../plugins/pump/omnipod/dash/driver/comm/Id.kt | 2 +- .../omnipod/dash/driver/comm/pair/LTKExchanger.kt | 1 - .../pump/omnipod/dash/driver/comm/pair/PairResult.kt | 1 - .../omnipod/dash/driver/comm/session/EapMessage.kt | 1 - .../dash/driver/comm/session/SessionEstablisher.kt | 4 ++-- .../driver/pod/state/OmnipodDashPodStateManager.kt | 2 +- .../pod/state/OmnipodDashPodStateManagerImpl.kt | 12 ++++++------ .../omnipod/dash/ui/OmnipodDashOverviewFragment.kt | 1 - 8 files changed, 10 insertions(+), 14 deletions(-) diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/Id.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/Id.kt index b78aa5ecc57..69075572876 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/Id.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/Id.kt @@ -37,7 +37,7 @@ data class Id(val address: ByteArray) { return Id(ByteBuffer.allocate(4).putInt(v).array()) } 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)) } } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/LTKExchanger.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/LTKExchanger.kt index 5965d117452..0530aac6073 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/LTKExchanger.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/LTKExchanger.kt @@ -5,7 +5,6 @@ import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.pump.omnipod.dash.BuildConfig import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.Id -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.OmnipodDashBleManagerImpl import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.MessageIOException import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.MessageIO import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.MessagePacket diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/PairResult.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/PairResult.kt index c23be1d0a52..900065aaa40 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/PairResult.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/pair/PairResult.kt @@ -1,6 +1,5 @@ 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.utils.extensions.toHex data class PairResult(val ltk: ByteArray, val msgSeq: Byte) { diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapMessage.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapMessage.kt index d25802c079a..a6273916121 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapMessage.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapMessage.kt @@ -4,7 +4,6 @@ import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.MessageIOException import info.nightscout.androidaps.utils.extensions.toHex -import okio.ByteString.Companion.toByteString import java.nio.ByteBuffer enum class EapCode(val code: Byte) { diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionEstablisher.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionEstablisher.kt index e8b89cc73c3..a3c17a19f44 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionEstablisher.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionEstablisher.kt @@ -27,8 +27,8 @@ class SessionEstablisher( private val milenage = Milenage(aapsLogger, ltk, eapSqn) init { - require(eapSqn.size == 6) {"EAP-SQN has to be 6 bytes long"} - require(ltk.size == 16) {"LTK has to be 16 bytes long"} + require(eapSqn.size == 6) { "EAP-SQN has to be 6 bytes long" } + require(ltk.size == 16) { "LTK has to be 16 bytes long" } aapsLogger.debug(LTag.PUMPBTCOMM, "Starting EAP-AKA") val random = SecureRandom() diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManager.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManager.kt index 49d3aceb79c..75ec144593a 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManager.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManager.kt @@ -48,7 +48,7 @@ interface OmnipodDashPodStateManager { val basalProgram: BasalProgram? fun increaseMessageSequenceNumber() - fun increaseEapAkaSequenceNumber():ByteArray + fun increaseEapAkaSequenceNumber(): ByteArray fun commitEapAkaSequenceNumber() fun updateFromDefaultStatusResponse(response: DefaultStatusResponse) fun updateFromVersionResponse(response: VersionResponse) diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManagerImpl.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManagerImpl.kt index c535536726c..f8f05c729f9 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManagerImpl.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/pod/state/OmnipodDashPodStateManagerImpl.kt @@ -159,13 +159,13 @@ class OmnipodDashPodStateManagerImpl @Inject constructor( } override var ltk: ByteArray? - get() = podState.ltk - set(value) { - podState.ltk = value - store() - } + get() = podState.ltk + set(value) { + podState.ltk = value + store() + } - override fun increaseEapAkaSequenceNumber():ByteArray { + override fun increaseEapAkaSequenceNumber(): ByteArray { podState.eapAkaSequenceNumber++ return ByteBuffer.allocate(8) .putLong(podState.eapAkaSequenceNumber) diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/OmnipodDashOverviewFragment.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/OmnipodDashOverviewFragment.kt index 275e995c913..749f0d0de58 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/OmnipodDashOverviewFragment.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/ui/OmnipodDashOverviewFragment.kt @@ -325,7 +325,6 @@ class OmnipodDashOverviewFragment : DaggerFragment() { } podInfoBinding.podActiveAlerts.text = PLACEHOLDER - } if (errors.size == 0) { From 923d8d33ef5b2b025e61752d27ece20198c4b9b0 Mon Sep 17 00:00:00 2001 From: Andrei Vereha Date: Sun, 7 Mar 2021 22:33:02 +0100 Subject: [PATCH 08/11] dash eap: bugfix Shift the MSB of the lenght by 1 byte, not one bit. --- .../driver/comm/endecrypt/CryptSequence.kt | 20 ------ .../driver/comm/session/EapAkaAttribute.kt | 67 +++++++++++++++---- .../dash/driver/comm/session/EapMessage.kt | 4 +- .../driver/comm/session/SessionEstablisher.kt | 6 +- .../driver/comm/endecrypt/EnDecryptTest.kt | 4 +- .../driver/comm/session/EapMessageTest.kt | 19 ++++++ 6 files changed, 81 insertions(+), 39 deletions(-) delete mode 100644 omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/CryptSequence.kt create mode 100644 omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapMessageTest.kt diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/CryptSequence.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/CryptSequence.kt deleted file mode 100644 index 1eab261f61d..00000000000 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/CryptSequence.kt +++ /dev/null @@ -1,20 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.endecrypt - -import java.nio.ByteBuffer - -class CryptSequence(var sqn: Long) { - - fun incrementForEnDecrypt(fromPdmToPod: Boolean): ByteArray { - sqn++ - val ret = ByteBuffer.allocate(8) - .putLong(sqn) - .array() - .copyOfRange(3, 8) - if (fromPdmToPod) { - ret[0] = (ret[0].toInt() and 127).toByte() - } else { - ret[0] = (ret[0].toInt() or 128).toByte() - } - return ret - } -} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapAkaAttribute.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapAkaAttribute.kt index ad193b87b8d..701c96d5165 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapAkaAttribute.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapAkaAttribute.kt @@ -9,6 +9,7 @@ enum class EapAkaAttributeType(val type: Byte) { AT_RAND(1), AT_AUTN(2), AT_RES(3), + AT_CLIENT_ERROR_CODE(22), AT_CUSTOM_IV(126); companion object { @@ -30,7 +31,7 @@ sealed class EapAkaAttribute { fun parseAttributes(aapsLogger: AAPSLogger, payload: ByteArray): List { var tail = payload val ret = LinkedList() - while (tail.size > 0) { + while (tail.isNotEmpty()) { if (tail.size < 2) { throw MessageIOException("Could not parse EAP attributes: ${payload.toHex()}") } @@ -41,11 +42,15 @@ sealed class EapAkaAttribute { val type = EapAkaAttributeType.byValue(tail[0]) when (type) { EapAkaAttributeType.AT_RES -> - ret.add(EapAkaAttributeRes.parse(tail.copyOfRange(2, size))) + ret.add(EapAkaAttributeRes.parse(tail.copyOfRange(2, EapAkaAttributeRes.SIZE))) EapAkaAttributeType.AT_CUSTOM_IV -> - ret.add(EapAkaAttributeCustomIV.parse(tail.copyOfRange(2, size))) - else -> - throw MessageIOException("Could not parse EAP attributes: ${payload.toHex()}. Expecting only AT_RES or CUSTOM_IV attribute types from the POD") + ret.add(EapAkaAttributeCustomIV.parse(tail.copyOfRange(2, EapAkaAttributeCustomIV.SIZE))) + EapAkaAttributeType.AT_AUTN -> + ret.add(EapAkaAttributeAutn.parse(tail.copyOfRange(2, EapAkaAttributeAutn.SIZE))) + EapAkaAttributeType.AT_RAND -> + ret.add(EapAkaAttributeRand.parse(tail.copyOfRange(2, EapAkaAttributeRand.SIZE))) + EapAkaAttributeType.AT_CLIENT_ERROR_CODE -> + ret.add(EapAkaAttributeClientErrorCode.parse(tail.copyOfRange(2, EapAkaAttributeClientErrorCode.SIZE))) } tail = tail.copyOfRange(size, tail.size) } @@ -61,12 +66,17 @@ data class EapAkaAttributeRand(val payload: ByteArray) : EapAkaAttribute() { } override fun toByteArray(): ByteArray { - return byteArrayOf(EapAkaAttributeType.AT_RAND.type, SIZE, 0, 0) + payload + return byteArrayOf(EapAkaAttributeType.AT_RAND.type, (SIZE / SIZE_MULTIPLIER).toByte(), 0, 0) + payload } companion object { - - private const val SIZE = (20 / SIZE_MULTIPLIER).toByte() // type, size, 2 reserved bytes, payload=16 + fun parse(payload: ByteArray): EapAkaAttribute { + if (payload.size < 2 + 16) { + throw MessageIOException("Could not parse RAND attribute: ${payload.toHex()}") + } + return EapAkaAttributeRand(payload.copyOfRange(2, 2 + 16)) + } + const val SIZE = 20 // type, size, 2 reserved bytes, payload=16 } } @@ -77,12 +87,19 @@ data class EapAkaAttributeAutn(val payload: ByteArray) : EapAkaAttribute() { } override fun toByteArray(): ByteArray { - return byteArrayOf(EapAkaAttributeType.AT_AUTN.type, SIZE, 0, 0) + payload + return byteArrayOf(EapAkaAttributeType.AT_AUTN.type, (SIZE / SIZE_MULTIPLIER).toByte(), 0, 0) + payload } companion object { - private const val SIZE = (20 / SIZE_MULTIPLIER).toByte() // type, size, 2 reserved bytes, payload=16 + fun parse(payload: ByteArray): EapAkaAttribute { + if (payload.size < 2 + 16) { + throw MessageIOException("Could not parse AUTN attribute: ${payload.toHex()}") + } + return EapAkaAttributeAutn(payload.copyOfRange(2, 2 + 16)) + } + + const val SIZE = 20 // type, size, 2 reserved bytes, payload=16 } } @@ -93,7 +110,7 @@ data class EapAkaAttributeRes(val payload: ByteArray) : EapAkaAttribute() { } override fun toByteArray(): ByteArray { - return byteArrayOf(EapAkaAttributeType.AT_RES.type, SIZE, 0, PAYLOAD_SIZE_BITS) + payload + return byteArrayOf(EapAkaAttributeType.AT_RES.type, (SIZE / SIZE_MULTIPLIER).toByte(), 0, PAYLOAD_SIZE_BITS) + payload } companion object { @@ -105,7 +122,7 @@ data class EapAkaAttributeRes(val payload: ByteArray) : EapAkaAttribute() { return EapAkaAttributeRes(payload.copyOfRange(2, 2 + 8)) } - private const val SIZE = (12 / SIZE_MULTIPLIER).toByte() // type, size, len in bits=2, payload=8 + const val SIZE = 12 // type, size, len in bits=2, payload=8 private const val PAYLOAD_SIZE_BITS = 64.toByte() // type, size, 2 reserved bytes, payload } } @@ -117,7 +134,7 @@ data class EapAkaAttributeCustomIV(val payload: ByteArray) : EapAkaAttribute() { } override fun toByteArray(): ByteArray { - return byteArrayOf(EapAkaAttributeType.AT_CUSTOM_IV.type, SIZE, 0, 0) + payload + return byteArrayOf(EapAkaAttributeType.AT_CUSTOM_IV.type, (SIZE / SIZE_MULTIPLIER).toByte(), 0, 0) + payload } companion object { @@ -128,7 +145,29 @@ data class EapAkaAttributeCustomIV(val payload: ByteArray) : EapAkaAttribute() { } return EapAkaAttributeCustomIV(payload.copyOfRange(2, 2 + 4)) } + const val SIZE = 8 // type, size, 2 reserved bytes, payload=4 + } +} + +data class EapAkaAttributeClientErrorCode(val payload: ByteArray) : EapAkaAttribute() { + + init { + require(payload.size == 2) { "Error code hast to be 2 bytes. Payload: ${payload.toHex()}" } + } + + override fun toByteArray(): ByteArray { + return byteArrayOf(EapAkaAttributeType.AT_CLIENT_ERROR_CODE.type, (SIZE / SIZE_MULTIPLIER).toByte(), 0, 0) + payload + } + + companion object { + + fun parse(payload: ByteArray): EapAkaAttributeClientErrorCode { + if (payload.size < 2 + 2) { + throw MessageIOException("Could not parse CLIENT_ERROR_CODE attribute: ${payload.toHex()}") + } + return EapAkaAttributeClientErrorCode(payload.copyOfRange(2, 4)) + } - private const val SIZE = (8 / SIZE_MULTIPLIER).toByte() // type, size, 2 reserved bytes, payload=4 + const val SIZE = 4 // type, size=1, payload:2 } } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapMessage.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapMessage.kt index a6273916121..de5dd8c45de 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapMessage.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapMessage.kt @@ -41,7 +41,7 @@ data class EapMessage( .allocate(totalSize) .put(code.code) .put(identifier) - .put(((totalSize ushr 1) and 0XFF).toByte()) + .put(((totalSize ushr 8) and 0XFF).toByte()) .put((totalSize and 0XFF).toByte()) .put(AKA_PACKET_TYPE) .put(SUBTYPE_AKA_CHALLENGE) @@ -62,7 +62,7 @@ data class EapMessage( if (payload.size < 4) { throw MessageIOException("Invalid eap payload: ${payload.toHex()}") } - val totalSize = (payload[2].toInt() shl 1) or payload[3].toInt() + val totalSize = (payload[2].toInt() shl 8) or payload[3].toInt() if (totalSize > payload.size) { throw MessageIOException("Invalid eap payload. Too short: ${payload.toHex()}") } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionEstablisher.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionEstablisher.kt index a3c17a19f44..9eae68458e1 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionEstablisher.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionEstablisher.kt @@ -83,7 +83,11 @@ class SessionEstablisher( // TODO verify that identifier matches identifer from the Challenge val eapMsg = EapMessage.parse(aapsLogger, challengeResponse.payload) if (eapMsg.attributes.size != 2) { - aapsLogger.debug(LTag.PUMPBTCOMM, "EAP-AKA: got RES message: $eapMsg") + aapsLogger.debug(LTag.PUMPBTCOMM, "EAP-AKA: got message: $eapMsg") + if (eapMsg.attributes.size == 1 && eapMsg.attributes[0] is EapAkaAttributeClientErrorCode) { + // TODO: special exception for this + throw SessionEstablishmentException("Received CLIENT_ERROR_CODE for EAP-AKA challenge: ${eapMsg.attributes[0].toByteArray().toHex()}") + } throw SessionEstablishmentException("Expecting two attributes, got: ${eapMsg.attributes.size}") } for (attr in eapMsg.attributes) { diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/EnDecryptTest.kt b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/EnDecryptTest.kt index a78bd5fae19..4c35cc29953 100644 --- a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/EnDecryptTest.kt +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/EnDecryptTest.kt @@ -16,7 +16,7 @@ class EnDecryptTest { aapsLogger, Nonce( Hex.decode("dda23c090a0a0a0a"), - Hex.decode("0000000001") + 0 ), Hex.decode("ba1283744b6de9fab6d9b77d95a71d6e"), ) @@ -39,7 +39,7 @@ class EnDecryptTest { aapsLogger, Nonce( Hex.decode("dda23c090a0a0a0a"), - Hex.decode("0000000001") + 0 ), Hex.decode("ba1283744b6de9fab6d9b77d95a71d6e"), ) diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapMessageTest.kt b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapMessageTest.kt new file mode 100644 index 00000000000..381ca3b8365 --- /dev/null +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapMessageTest.kt @@ -0,0 +1,19 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session + +import info.nightscout.androidaps.logging.AAPSLoggerTest +import info.nightscout.androidaps.utils.extensions.toHex +import org.junit.Assert +import org.junit.Assert.* +import org.junit.Test +import org.spongycastle.util.encoders.Hex + +class EapMessageTest { + + @Test fun testParseAndBack() { + val aapsLogger = AAPSLoggerTest() + val payload = Hex.decode("01bd0038170100000205000000c55c78e8d3b9b9e935860a7259f6c001050000c2cd1248451103bd77a6c7ef88c441ba7e0200006cff5d18") + val eapMsg = EapMessage.parse(aapsLogger, payload) + val back = eapMsg.toByteArray() + Assert.assertEquals(back.toHex(), payload.toHex()) + } +} From 64aa05f7f95280c9dbc6e45e3169b87d82343ac1 Mon Sep 17 00:00:00 2001 From: Andrei Vereha Date: Sun, 7 Mar 2021 22:39:09 +0100 Subject: [PATCH 09/11] dash en/decrypt test: add comment about failing test --- .../pump/omnipod/dash/driver/comm/endecrypt/EnDecryptTest.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/EnDecryptTest.kt b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/EnDecryptTest.kt index 4c35cc29953..04c0d38f8a5 100644 --- a/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/EnDecryptTest.kt +++ b/omnipod-dash/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/EnDecryptTest.kt @@ -11,6 +11,8 @@ class EnDecryptTest { @Test fun decrypt() { + // TODO: add data received from the pod + // this test is failing because the way we increment the nonce val aapsLogger = AAPSLoggerTest() val enDecrypt = EnDecrypt( aapsLogger, From db51b762caf7cc0f5b83b9e72555c5164b85580b Mon Sep 17 00:00:00 2001 From: Andrei Vereha Date: Sun, 7 Mar 2021 22:41:51 +0100 Subject: [PATCH 10/11] dash ble: disconnect on errors --- .../pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt index a7c50bff4ef..c793c90cf40 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt @@ -214,13 +214,14 @@ class OmnipodDashBleManagerImpl @Inject constructor( emitter.onComplete() } catch (ex: Exception) { + disconnect() emitter.tryOnError(ex) } } override fun disconnect() { val localGatt = gatt - localGatt?.close() + localGatt?.close() // TODO: use disconnect? gatt = null msgIO = null sessionKeys = null From c337b52aa0b28475efe307156bdff973cf80e3ce Mon Sep 17 00:00:00 2001 From: Andrei Vereha Date: Mon, 8 Mar 2021 22:47:56 +0100 Subject: [PATCH 11/11] dash/ble: support both 1 and 2 byte command It seems that the PDM is sending 1 byte commands and the POD answers with 2 byte commands. Add logging for decrypted responses. I think `eqos` means that we are expecting an ACK for the last message. Read (and log for now) a pending message if the POD is trying to sending it back while we want to send a command. --- .../dash/driver/comm/command/BleCommand.kt | 3 +- .../driver/comm/command/BleCommandType.kt | 4 +-- .../dash/driver/comm/endecrypt/EnDecrypt.kt | 1 + .../dash/driver/comm/message/MessageIO.kt | 36 ++++++++++++++----- .../dash/driver/comm/session/Session.kt | 16 +++++---- 5 files changed, 41 insertions(+), 19 deletions(-) diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/command/BleCommand.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/command/BleCommand.kt index 70d787b01e9..1af3a918921 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/command/BleCommand.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/command/BleCommand.kt @@ -14,7 +14,7 @@ class BleCommandFail : BleCommand(BleCommandType.FAIL) open class BleCommand(val data: ByteArray) { - constructor(type: BleCommandType) : this(byteArrayOf(type.value, 0)) + constructor(type: BleCommandType) : this(byteArrayOf(type.value)) constructor(type: BleCommandType, payload: ByteArray) : this( byteArrayOf(type.value) + payload @@ -36,4 +36,5 @@ open class BleCommand(val data: ByteArray) { override fun hashCode(): Int { return data.contentHashCode() } + } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/command/BleCommandType.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/command/BleCommandType.kt index 7953cbab4b2..eb8b6bdb47d 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/command/BleCommandType.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/command/BleCommandType.kt @@ -7,9 +7,7 @@ enum class BleCommandType(val value: Byte) { ABORT(0x03.toByte()), SUCCESS(0x04.toByte()), FAIL(0x05.toByte()), - HELLO( - 0x06.toByte() - ); + HELLO(0x06.toByte()); companion object { diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/EnDecrypt.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/EnDecrypt.kt index b879cf61c82..23b7ae80543 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/EnDecrypt.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/endecrypt/EnDecrypt.kt @@ -32,6 +32,7 @@ class EnDecrypt(private val aapsLogger: AAPSLogger, private val nonce: Nonce, pr ) val decryptedPayload = ByteArray(payload.size - MAC_SIZE) cipher.processPacket(payload, 0, payload.size, decryptedPayload, 0) + aapsLogger.debug(LTag.PUMPBTCOMM, "Decrypted payload ${decryptedPayload.toHex()}") return msg.copy(payload = decryptedPayload) } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/MessageIO.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/MessageIO.kt index 5308c88a715..bd5e895f3ad 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/MessageIO.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/MessageIO.kt @@ -8,17 +8,34 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptio import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.BleIO import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.CharacteristicType import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.PayloadJoiner +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.CommandType import info.nightscout.androidaps.utils.extensions.toHex class MessageIO(private val aapsLogger: AAPSLogger, private val bleIO: BleIO) { - fun sendMessage(msg: MessagePacket) { + private fun expectCommandType(actual: BleCommand, expected: BleCommand) { + if (actual.data.isEmpty()) { + throw UnexpectedCommandException(actual) + } + // first byte is the command type + if (actual.data[0] == expected.data[0]) { + return + } + throw UnexpectedCommandException(actual) + + } + + fun sendMessage(msg: MessagePacket):MessagePacket? { bleIO.flushIncomingQueues() bleIO.sendAndConfirmPacket(CharacteristicType.CMD, BleCommandRTS().data) val expectCTS = bleIO.receivePacket(CharacteristicType.CMD) - if (BleCommand(expectCTS) != BleCommandCTS()) { + if (expectCTS.isEmpty()) { throw UnexpectedCommandException(BleCommand(expectCTS)) } + //if (expectCTS[0] == BleCommandType.RTS.value) { + //the pod is trying to send something, after we sent RTS, let's read it + //} + expectCommandType(BleCommand(expectCTS), BleCommandCTS()) val payload = msg.asByteArray() aapsLogger.debug(LTag.PUMPBTCOMM, "Sending message: ${payload.toHex()}") val splitter = PayloadSplitter(payload) @@ -29,17 +46,18 @@ class MessageIO(private val aapsLogger: AAPSLogger, private val bleIO: BleIO) { } // TODO: peek for NACKs val expectSuccess = bleIO.receivePacket(CharacteristicType.CMD) - if (BleCommand(expectSuccess) != BleCommandSuccess()) { - throw UnexpectedCommandException(BleCommand(expectSuccess)) - } + expectCommandType(BleCommand(expectSuccess), BleCommandSuccess()) // TODO: handle NACKS/FAILS/etc + return null } - fun receiveMessage(): MessagePacket { - val expectRTS = bleIO.receivePacket(CharacteristicType.CMD) - if (BleCommand(expectRTS) != BleCommandRTS()) { - throw UnexpectedCommandException(BleCommand(expectRTS)) + // TODO: use higher timeout when receiving the first packet in a message + fun receiveMessage( firstCmd: ByteArray? = null): MessagePacket { + var expectRTS = firstCmd + if (expectRTS == null) { + expectRTS = bleIO.receivePacket(CharacteristicType.CMD) } + expectCommandType(BleCommand(expectRTS), BleCommandRTS()) bleIO.sendAndConfirmPacket(CharacteristicType.CMD, BleCommandCTS().data) try { val joiner = PayloadJoiner(bleIO.receivePacket(CharacteristicType.DATA)) diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/Session.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/Session.kt index d5fc2739dab..e45c9a322a8 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/Session.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/Session.kt @@ -31,12 +31,14 @@ class Session( */ fun sendCommand(cmd: Command): Response { sessionKeys.msgSequenceNumber++ - aapsLogger.debug(LTag.PUMPBTCOMM, "Sending command: ${cmd.encoded.toHex()}") + aapsLogger.debug(LTag.PUMPBTCOMM, "Sending command: ${cmd.encoded.toHex()} in packet $cmd") val msg = getCmdMessage(cmd) aapsLogger.debug(LTag.PUMPBTCOMM, "Sending command(wrapped): ${msg.payload.toHex()}") - msgIO.sendMessage(msg) - + val reply = msgIO.sendMessage(msg) + if (reply != null) { // TODO : this means the last ACK was not received, send it again? + aapsLogger.debug(LTag.PUMPBTCOMM, "Received a message with payload instead of CTS: ${reply.payload.toHex()} in packet $reply") + } val responseMsg = msgIO.receiveMessage() val decrypted = enDecrypt.decrypt(responseMsg) aapsLogger.debug(LTag.PUMPBTCOMM, "Received response: $decrypted") @@ -44,13 +46,15 @@ class Session( sessionKeys.msgSequenceNumber++ val ack = getAck(responseMsg) - aapsLogger.debug(LTag.PUMPBTCOMM, "Sending ACK: ${ack.payload.toHex()}") + aapsLogger.debug(LTag.PUMPBTCOMM, "Sending ACK: ${ack.payload.toHex()} in packet $ack") msgIO.sendMessage(ack) return response } private fun parseResponse(decrypted: MessagePacket): Response { + val payload = parseKeys(arrayOf(RESPONSE_PREFIX), decrypted.payload)[0] + aapsLogger.info(LTag.PUMPBTCOMM, "Received decrypted response: ${payload.toHex()} in packet: $decrypted") return NakResponse(payload) } @@ -61,9 +65,9 @@ class Session( source = myId, destination = podId, payload = ByteArray(0), - eqos = 1, + eqos = 0, ack = true, - ackNumber = response.sequenceNumber.inc() + ackNumber = (response.sequenceNumber.toInt()+1).toByte() ) return enDecrypt.encrypt((msg)) }