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 f2d0936b90..6cbcf60436 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 @@ -12,6 +12,9 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.callback import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.command.BleCommandHello 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.ltk.LTKExchanger +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.MessageIO import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.scan.PodScanner import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.status.ConnectionStatus import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.Command @@ -34,16 +37,21 @@ class OmnipodDashBleManagerImpl @Inject constructor(private val context: Context val podScanner = PodScanner(aapsLogger, bluetoothAdapter) 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"; - connect(podAddress) + val bleIO = connect(podAddress) + val msgIO = MessageIO(aapsLogger, bleIO) + val ltkExchanger = LTKExchanger(aapsLogger, msgIO) + val ltk = ltkExchanger.negociateLTKAndNonce() + + aapsLogger.info(LTag.PUMPCOMM, "Got LTK and Nonce Prefix: ${ltk}") } @Throws(FailedToConnectException::class, CouldNotSendBleException::class, InterruptedException::class, BleIOBusyException::class, TimeoutException::class, CouldNotConfirmWriteException::class, CouldNotEnableNotifications::class, DescriptorNotFoundException::class, CouldNotConfirmDescriptorWriteException::class) - private fun connect(podAddress: String) { + private fun connect(podAddress: String): BleIO { // TODO: locking? val podDevice = bluetoothAdapter.getRemoteDevice(podAddress) val incomingPackets: Map> = mapOf(CharacteristicType.CMD to LinkedBlockingDeque(), - CharacteristicType.DATA to LinkedBlockingDeque()); + CharacteristicType.DATA to LinkedBlockingDeque()) val bleCommCallbacks = BleCommCallbacks(aapsLogger, incomingPackets) aapsLogger.debug(LTag.PUMPBTCOMM, "Connecting to $podAddress") var autoConnect = true @@ -65,6 +73,7 @@ class OmnipodDashBleManagerImpl @Inject constructor(private val context: Context aapsLogger.debug(LTag.PUMPBTCOMM, "Saying hello to the pod") bleIO.sendAndConfirmPacket(CharacteristicType.CMD, BleCommandHello(CONTROLLER_ID).data) bleIO.readyToRead() + return bleIO } override fun sendCommand(cmd: Command): Response { @@ -84,6 +93,7 @@ class OmnipodDashBleManagerImpl @Inject constructor(private val context: Context } companion object { + private const val CONNECT_TIMEOUT_MS = 5000 private const val CONTROLLER_ID = 4242 // TODO read from preferences or somewhere else. } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/ServiceDiscoverer.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/ServiceDiscoverer.kt index 997a3ee1cf..a86173507f 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/ServiceDiscoverer.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/ServiceDiscoverer.kt @@ -4,9 +4,11 @@ import android.bluetooth.BluetoothGatt import android.bluetooth.BluetoothGattCharacteristic import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag + import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.callbacks.BleCommCallbacks import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.CharacteristicNotFoundException import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.ServiceNotFoundException +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.CharacteristicType import java.math.BigInteger import java.util.* 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 daf3db26a4..491f26c326 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 @@ -7,8 +7,8 @@ import android.bluetooth.BluetoothGattDescriptor import android.bluetooth.BluetoothProfile import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.CharacteristicType -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.CharacteristicType.Companion.byValue +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.CharacteristicType +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.CharacteristicType.Companion.byValue import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.CouldNotConfirmDescriptorWriteException import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.CouldNotConfirmWriteException import java.util.concurrent.BlockingQueue 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 47389b0a05..3ba0178b2e 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 @@ -1,17 +1,33 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.command -abstract class BleCommand { +open class BleCommand(val data: ByteArray) { - val data: ByteArray + constructor(type: BleCommandType) : this(byteArrayOf(type.value)) {} - constructor(type: BleCommandType) { - data = byteArrayOf(type.value) + constructor(type: BleCommandType, payload: ByteArray): this( + byteArrayOf(type.value) + payload + ) {} + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is BleCommand) return false + + if (!data.contentEquals(other.data)) return false + + return true } - constructor(type: BleCommandType, payload: ByteArray) { - val n = payload.size + 1 - data = ByteArray(n) - data[0] = type.value - System.arraycopy(payload, 0, data, 1, payload.size) + override fun hashCode(): Int { + return data.contentHashCode() } -} \ No newline at end of file +} + +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) {} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/command/BleCommandNack.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/command/BleCommandNack.kt new file mode 100644 index 0000000000..0beabce09d --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/command/BleCommandNack.kt @@ -0,0 +1,4 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.command + +class BleCommandNack { +} \ No newline at end of file diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/exceptions/CouldNotEnableNotifications.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/exceptions/CouldNotEnableNotifications.kt index 7564ab32e1..b9987da037 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/exceptions/CouldNotEnableNotifications.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/exceptions/CouldNotEnableNotifications.kt @@ -1,5 +1,5 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.CharacteristicType +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.CharacteristicType class CouldNotEnableNotifications(cmd: CharacteristicType) : Exception(cmd.value) \ No newline at end of file diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/exceptions/UnexpectedCommandException.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/exceptions/UnexpectedCommandException.kt new file mode 100644 index 0000000000..dc7a0d7c27 --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/exceptions/UnexpectedCommandException.kt @@ -0,0 +1,7 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions + +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.command.BleCommand +import java.lang.Exception + +class UnexpectedCommandException(val cmd: BleCommand): Exception("Unexpected command: ${cmd}") { +} \ No newline at end of file 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 39cca93aea..c1f2c89aef 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 @@ -5,7 +5,6 @@ import android.bluetooth.BluetoothGattCharacteristic import android.bluetooth.BluetoothGattDescriptor import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag -import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.CharacteristicType import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.callbacks.BleCommCallbacks import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.* import java.util.concurrent.BlockingQueue diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/CharacteristicType.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/io/CharacteristicType.kt similarity index 98% rename from omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/CharacteristicType.kt rename to omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/io/CharacteristicType.kt index c241a6f43b..b5b10e6f9a 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/CharacteristicType.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/io/CharacteristicType.kt @@ -1,4 +1,4 @@ -package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io import java.math.BigInteger import java.util.* diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/io/PayloadJoiner.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/io/PayloadJoiner.kt new file mode 100644 index 0000000000..a3b440d29f --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/io/PayloadJoiner.kt @@ -0,0 +1,16 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io + +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.packet.BlePacket +import java.io.ByteArrayOutputStream + +class PayloadJoiner() { + private val payload = ByteArrayOutputStream() + + fun accumulate(packet: BlePacket) { + + } + + fun bytes(): ByteArray { + return ByteArray(0); + } +} \ No newline at end of file diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/io/PayloadSplitter.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/io/PayloadSplitter.kt new file mode 100644 index 0000000000..f2eb8f3b85 --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/io/PayloadSplitter.kt @@ -0,0 +1,69 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io + +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.packet.BlePacket +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.packet.FirstBlePacket +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.packet.LastBlePacket +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.packet.LastOptionalPlusOneBlePacket +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.packet.MiddleBlePacket +import java.lang.Integer.min +import java.util.zip.CRC32 + +internal class PayloadSplitter(private val payload: ByteArray) { + fun splitInPackets(): List { + val ret = ArrayList() + val crc32 = payload.crc32(); + if (payload.size <= 18) { + val end = min(14, payload.size) + ret.add(FirstBlePacket( + totalFragments = 0, + payload = payload.copyOfRange(0, end), + size = payload.size.toByte(), + crc32 = crc32, + )) + if (payload.size > 14) { + ret.add(LastOptionalPlusOneBlePacket( + index = 1, + payload = payload.copyOfRange(end, payload.size), + )) + } + return ret; + } + val middleFragments = (payload.size-18)/19 + val rest = ((payload.size - middleFragments.toInt() * 19) - 18).toByte() + ret.add(FirstBlePacket( + totalFragments = (middleFragments + 1).toByte(), + payload = payload.copyOfRange(0, 18), + )) + for( i in 1..middleFragments ) { + val p = if (i ==1 ) { + payload.copyOfRange(18,37) + }else { + payload.copyOfRange((i-1)*19+18, (i-1)*19+18+19) + } + ret.add(MiddleBlePacket( + index = i.toByte(), + payload = p, + )) + } + val end = min(14, rest.toInt()) + ret.add(LastBlePacket( + index = (middleFragments+1).toByte(), + size = rest, + payload = payload.copyOfRange(middleFragments*19+18,middleFragments*19+18+end), + crc32 = crc32, + )) + if (rest > 14) { + ret.add(LastOptionalPlusOneBlePacket( + index = (middleFragments+2).toByte(), + payload = payload.copyOfRange(middleFragments*19+18+14, payload.size), + )) + } + return ret; + } +} + +internal fun ByteArray.crc32(): Long { + val crc = CRC32() + crc.update(this) + return crc.value +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/ltk/LTK.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/ltk/LTK.kt new file mode 100644 index 0000000000..3784ae9ffa --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/ltk/LTK.kt @@ -0,0 +1,12 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.ltk + +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.io.BleIO + +data class LTK(val ltk: ByteArray, val noncePrefix: ByteArray) { + init{ + require(ltk.size == 16) + require(noncePrefix.size == 16) + } +} + diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/ltk/LTKExchanger.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/ltk/LTKExchanger.kt new file mode 100644 index 0000000000..1b0d690ae5 --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/ltk/LTKExchanger.kt @@ -0,0 +1,23 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.ltk + +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.Address +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.MessageIO +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.PairMessage +import info.nightscout.androidaps.utils.extensions.hexStringToByteArray + +internal class LTKExchanger(private val aapsLogger: AAPSLogger,private val msgIO: MessageIO) { + + fun negociateLTKAndNonce(): LTK? { + val msg = PairMessage( + destination = Address(byteArrayOf(1,2,3,4)), + source = Address(byteArrayOf(5,6,7,8)), + payload = "5350313d0004024200032c5350323d000bffc32dbd20030e01000016".hexStringToByteArray(), + sequenceNumber = 1, + ) + msgIO.sendMesssage(msg) + + return null + } + +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/Address.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/Address.kt new file mode 100644 index 0000000000..62dc6ae156 --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/Address.kt @@ -0,0 +1,7 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message + +data class Address(val address: ByteArray) { + init { + require(address.size == 4) + } +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/Message.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/Message.kt new file mode 100644 index 0000000000..c733cd42ef --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/Message.kt @@ -0,0 +1,23 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message + +abstract class Message( + val type: MessageType, + val source: Address, + val destination: Address, + val payload: ByteArray, + val sequenceNumber: Byte, + val ack: Boolean = false, + val ackNumber: Byte = 0.toByte(), + val eqos: Short = 0.toShort(), // TODO: understand + val priority: Boolean = false, + val lastMessage: Boolean= false, + val gateway: Boolean = false, + val sas: Boolean = false, // TODO: understand + val tfs: Boolean = false, // TODO: understand + val version: Short = 0.toShort(), + ) { + + fun asByteArray(): ByteArray { + return payload; // TODO implement + } +} \ No newline at end of file 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 new file mode 100644 index 0000000000..185f3d4a7b --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/MessageIO.kt @@ -0,0 +1,43 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message + +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.BleManager +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.command.BleCommand +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.command.BleCommandCTS +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.command.BleCommandHello +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.command.BleCommandRTS +import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.UnexpectedCommandException +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.PayloadSplitter + +class MessageIO(private val aapsLogger: AAPSLogger, private val bleIO: BleIO) { + fun sendMesssage(msg: Message) { + bleIO.flushIncomingQueues(); + bleIO.sendAndConfirmPacket(CharacteristicType.CMD, BleCommandRTS().data) + val expectCTS = bleIO.receivePacket(CharacteristicType.CMD) + if (BleCommand(expectCTS) != BleCommandCTS()) { + throw UnexpectedCommandException(BleCommand(expectCTS)) + } + val payload = msg.asByteArray() + val splitter = PayloadSplitter(payload) + val packets = splitter.splitInPackets() + for (packet in packets) { + bleIO.sendAndConfirmPacket(CharacteristicType.DATA, packet.asByteArray()) + } + // TODO: peek for NACKs + val expectSuccess = bleIO.receivePacket(CharacteristicType.CMD) + if (BleCommand(expectSuccess) != BleCommandCTS()) { + throw UnexpectedCommandException(BleCommand(expectSuccess)) + } + // TODO: handle NACKS/FAILS/etc + bleIO.flushIncomingQueues(); + } + + + fun receiveMessage(): Message? { + // do the RTS/CTS/data/success dance + return null + } +} \ No newline at end of file diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/MessageType.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/MessageType.kt new file mode 100644 index 0000000000..f0a68e5cba --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/MessageType.kt @@ -0,0 +1,14 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message + +enum class MessageType(val value: Byte) { + CLEAR(0), + ENCRYPTED(1), + SESSION_ESTABLISHMENT(2), + PAIRING(3); + + companion object { + fun byValue(value: Byte): MessageType = + MessageType.values().firstOrNull() {it.value == value} + ?: throw IllegalArgumentException("Unknown MessageType: $value") + } +} \ No newline at end of file diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PairMessage.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PairMessage.kt new file mode 100644 index 0000000000..76e7802f20 --- /dev/null +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/message/PairMessage.kt @@ -0,0 +1,8 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message + +class PairMessage(source: Address, destination: Address, payload: ByteArray, sequenceNumber: Byte +) : Message( + type=MessageType.PAIRING, source, destination, payload, sequenceNumber, +) { + +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/packet/BlePacket.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/packet/BlePacket.kt index 6e8e7de891..525ca45d88 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/packet/BlePacket.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/packet/BlePacket.kt @@ -1,3 +1,34 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.packet -class BlePacket \ No newline at end of file +sealed class BlePacket { + + abstract fun asByteArray(): ByteArray +} + +data class FirstBlePacket(val totalFragments: Byte, val payload: ByteArray, val size: Byte = 0, val crc32: Long? = null) : BlePacket() { + + override fun asByteArray(): ByteArray { + TODO("Not yet implemented") + } +} + +data class MiddleBlePacket(val index: Byte, val payload: ByteArray) : BlePacket() { + + override fun asByteArray(): ByteArray { + TODO("Not yet implemented") + } +} + +data class LastBlePacket(val index: Byte, val size: Byte, val payload: ByteArray, val crc32: Long) : BlePacket() { + + override fun asByteArray(): ByteArray { + TODO("Not yet implemented") + } +} + +data class LastOptionalPlusOneBlePacket(val index: Byte, val payload: ByteArray) : BlePacket() { + + override fun asByteArray(): ByteArray { + TODO("Not yet implemented") + } +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/scan/BleDiscoveredDevice.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/scan/BleDiscoveredDevice.kt index 64e04630a0..bae65ab044 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/scan/BleDiscoveredDevice.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/scan/BleDiscoveredDevice.kt @@ -1,33 +1,34 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.scan +import android.bluetooth.le.ScanRecord import android.bluetooth.le.ScanResult import android.os.ParcelUuid import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions.DiscoveredInvalidPodException -class BleDiscoveredDevice(val scanResult: ScanResult, private val podId: Long) { +class BleDiscoveredDevice(val scanResult: ScanResult, val scanRecord: ScanRecord, private val podId: Long) { private val sequenceNo: Int private val lotNo: Long @Throws(DiscoveredInvalidPodException::class) private fun validateServiceUUIDs() { - val scanRecord = scanResult.scanRecord - ?: throw DiscoveredInvalidPodException("Scan record is null"); val serviceUuids = scanRecord.serviceUuids if (serviceUuids.size != 9) { throw DiscoveredInvalidPodException("Expected 9 service UUIDs, got" + serviceUuids.size, serviceUuids) + } if (extractUUID16(serviceUuids[0]) != MAIN_SERVICE_UUID) { // this is the service that we filtered for throw DiscoveredInvalidPodException("The first exposed service UUID should be 4024, got " + extractUUID16(serviceUuids[0]), serviceUuids) } // TODO understand what is serviceUUIDs[1]. 0x2470. Alarms? - if (extractUUID16(serviceUuids[2]) != "000a") { + if (extractUUID16(serviceUuids[2]) != UNKNOWN_THIRD_SERVICE_UUID) { // constant? throw DiscoveredInvalidPodException("The third exposed service UUID should be 000a, got " + serviceUuids[2], serviceUuids) } } @Throws(DiscoveredInvalidPodException::class) + private fun validatePodId() { val scanRecord = scanResult.scanRecord val serviceUUIDs = scanRecord.serviceUuids @@ -39,7 +40,6 @@ class BleDiscoveredDevice(val scanResult: ScanResult, private val podId: Long) { } private fun parseLotNo(): Long { - val scanRecord = scanResult.scanRecord val serviceUUIDs = scanRecord.serviceUuids val lotSeq = extractUUID16(serviceUUIDs[5]) + extractUUID16(serviceUUIDs[6]) + @@ -48,7 +48,6 @@ class BleDiscoveredDevice(val scanResult: ScanResult, private val podId: Long) { } private fun parseSeqNo(): Int { - val scanRecord = scanResult.scanRecord val serviceUUIDs = scanRecord.serviceUuids val lotSeq = extractUUID16(serviceUUIDs[7]) + extractUUID16(serviceUUIDs[8]) @@ -57,8 +56,9 @@ class BleDiscoveredDevice(val scanResult: ScanResult, private val podId: Long) { override fun toString(): String { return "BleDiscoveredDevice{" + - "scanResult=" + scanResult + + "scanRecord=" + scanRecord + ", podID=" + podId + + "scanResult=" + scanResult + ", sequenceNo=" + sequenceNo + ", lotNo=" + lotNo + '}' @@ -66,6 +66,7 @@ class BleDiscoveredDevice(val scanResult: ScanResult, private val podId: Long) { companion object { const val MAIN_SERVICE_UUID = "4024"; + const val UNKNOWN_THIRD_SERVICE_UUID = "000a" // FIXME: why is this 000a? private fun extractUUID16(uuid: ParcelUuid): String { return uuid.toString().substring(4, 8) } diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/scan/ScanCollector.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/scan/ScanCollector.kt index 0030c755eb..95286d9423 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/scan/ScanCollector.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/scan/ScanCollector.kt @@ -33,9 +33,11 @@ class ScanCollector(private val logger: AAPSLogger, private val podID: Long) : S logger.debug(LTag.PUMPBTCOMM, "ScanCollector looking for podID: $podID") for (result in found.values) { try { - val device = BleDiscoveredDevice(result, podID) - ret.add(device) - logger.debug(LTag.PUMPBTCOMM, "ScanCollector found: " + result.toString() + "Pod ID: " + podID) + result.scanRecord?.let { + val device = BleDiscoveredDevice(result, result.scanRecord, podID) + ret.add(device) + logger.debug(LTag.PUMPBTCOMM, "ScanCollector found: " + result.toString() + "Pod ID: " + podID) + } } catch (e: DiscoveredInvalidPodException) { logger.debug(LTag.PUMPBTCOMM, "ScanCollector: pod not matching$e") // this is not the POD we are looking for