Dana-i BLE5 support
This commit is contained in:
parent
23c23ea0b8
commit
fd19c6bf8e
10 changed files with 147 additions and 76 deletions
|
@ -156,7 +156,7 @@ class DanaPump @Inject constructor(
|
||||||
|
|
||||||
// DanaRS specific
|
// DanaRS specific
|
||||||
var rsPassword = ""
|
var rsPassword = ""
|
||||||
var v3RSPump = false
|
var ignoreUserPassword = false // true if replaced by enhanced encryption
|
||||||
|
|
||||||
// User settings
|
// User settings
|
||||||
var timeDisplayType24 = false
|
var timeDisplayType24 = false
|
||||||
|
@ -169,6 +169,7 @@ class DanaPump @Inject constructor(
|
||||||
var lowReservoirRate = 0
|
var lowReservoirRate = 0
|
||||||
var cannulaVolume = 0
|
var cannulaVolume = 0
|
||||||
var refillAmount = 0
|
var refillAmount = 0
|
||||||
|
var target = 0 // mgdl 40~400 mmol 2.2~22 => 220~2200
|
||||||
var userOptionsFrompump: ByteArray? = null
|
var userOptionsFrompump: ByteArray? = null
|
||||||
var initialBolusAmount = 0.0
|
var initialBolusAmount = 0.0
|
||||||
|
|
||||||
|
@ -274,7 +275,7 @@ class DanaPump @Inject constructor(
|
||||||
get() = password == sp.getInt(R.string.key_danar_password, -2)
|
get() = password == sp.getInt(R.string.key_danar_password, -2)
|
||||||
|
|
||||||
val isRSPasswordOK: Boolean
|
val isRSPasswordOK: Boolean
|
||||||
get() = rsPassword.equals(sp.getString(R.string.key_danars_password, ""), ignoreCase = true) || v3RSPump
|
get() = rsPassword.equals(sp.getString(R.string.key_danars_password, ""), ignoreCase = true) || ignoreUserPassword
|
||||||
|
|
||||||
fun reset() {
|
fun reset() {
|
||||||
aapsLogger.debug(LTag.PUMP, "DanaRPump reset")
|
aapsLogger.debug(LTag.PUMP, "DanaRPump reset")
|
||||||
|
@ -293,7 +294,8 @@ class DanaPump @Inject constructor(
|
||||||
if (protocol < 10) "DanaRS"
|
if (protocol < 10) "DanaRS"
|
||||||
else "DanaRS v3"
|
else "DanaRS v3"
|
||||||
0x06 -> "DanaRS Korean"
|
0x06 -> "DanaRS Korean"
|
||||||
0x07 -> "Dana-i"
|
0x07 -> "Dana-i (BLE4.2)"
|
||||||
|
0x09 -> "Dana-i (BLE5)"
|
||||||
else -> "Unknown Dana pump"
|
else -> "Unknown Dana pump"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,54 +18,24 @@ class DanaRS_Packet_Option_Get_User_Option(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleMessage(data: ByteArray) {
|
override fun handleMessage(data: ByteArray) {
|
||||||
var dataIndex = DATA_START
|
danaPump.timeDisplayType24 = intFromBuff(data, 0, 1) == 0
|
||||||
var dataSize = 1
|
danaPump.buttonScrollOnOff = intFromBuff(data, 1, 1) == 1
|
||||||
danaPump.timeDisplayType24 = byteArrayToInt(getBytes(data, dataIndex, dataSize)) == 0
|
danaPump.beepAndAlarm = intFromBuff(data, 2, 1)
|
||||||
dataIndex += dataSize
|
danaPump.lcdOnTimeSec = intFromBuff(data, 3, 1)
|
||||||
dataSize = 1
|
danaPump.backlightOnTimeSec = intFromBuff(data, 4, 1)
|
||||||
danaPump.buttonScrollOnOff = byteArrayToInt(getBytes(data, dataIndex, dataSize)) == 1
|
danaPump.selectedLanguage = intFromBuff(data, 5, 1)
|
||||||
dataIndex += dataSize
|
danaPump.units = intFromBuff(data, 6, 1)
|
||||||
dataSize = 1
|
danaPump.shutdownHour = intFromBuff(data, 7, 1)
|
||||||
danaPump.beepAndAlarm = byteArrayToInt(getBytes(data, dataIndex, dataSize))
|
danaPump.lowReservoirRate = intFromBuff(data, 8, 1)
|
||||||
dataIndex += dataSize
|
danaPump.cannulaVolume = intFromBuff(data, 9, 2)
|
||||||
dataSize = 1
|
danaPump.refillAmount = intFromBuff(data, 11, 2)
|
||||||
danaPump.lcdOnTimeSec = byteArrayToInt(getBytes(data, dataIndex, dataSize))
|
val selectableLanguage1 = intFromBuff(data, 13, 1)
|
||||||
dataIndex += dataSize
|
val selectableLanguage2 = intFromBuff(data, 14, 1)
|
||||||
dataSize = 1
|
val selectableLanguage3 = intFromBuff(data, 15, 1)
|
||||||
danaPump.backlightOnTimeSec = byteArrayToInt(getBytes(data, dataIndex, dataSize))
|
val selectableLanguage4 = intFromBuff(data, 16, 1)
|
||||||
dataIndex += dataSize
|
val selectableLanguage5 = intFromBuff(data, 17, 1)
|
||||||
dataSize = 1
|
if (data.size >= 22) // hw 7+
|
||||||
danaPump.selectedLanguage = byteArrayToInt(getBytes(data, dataIndex, dataSize))
|
danaPump.target = intFromBuff(data, 18, 2)
|
||||||
dataIndex += dataSize
|
|
||||||
dataSize = 1
|
|
||||||
danaPump.units = byteArrayToInt(getBytes(data, dataIndex, dataSize))
|
|
||||||
dataIndex += dataSize
|
|
||||||
dataSize = 1
|
|
||||||
danaPump.shutdownHour = byteArrayToInt(getBytes(data, dataIndex, dataSize))
|
|
||||||
dataIndex += dataSize
|
|
||||||
dataSize = 1
|
|
||||||
danaPump.lowReservoirRate = byteArrayToInt(getBytes(data, dataIndex, dataSize))
|
|
||||||
dataIndex += dataSize
|
|
||||||
dataSize = 2
|
|
||||||
danaPump.cannulaVolume = byteArrayToInt(getBytes(data, dataIndex, dataSize))
|
|
||||||
dataIndex += dataSize
|
|
||||||
dataSize = 2
|
|
||||||
danaPump.refillAmount = byteArrayToInt(getBytes(data, dataIndex, dataSize))
|
|
||||||
dataIndex += dataSize
|
|
||||||
dataSize = 1
|
|
||||||
val selectableLanguage1 = byteArrayToInt(getBytes(data, dataIndex, dataSize))
|
|
||||||
dataIndex += dataSize
|
|
||||||
dataSize = 1
|
|
||||||
val selectableLanguage2 = byteArrayToInt(getBytes(data, dataIndex, dataSize))
|
|
||||||
dataIndex += dataSize
|
|
||||||
dataSize = 1
|
|
||||||
val selectableLanguage3 = byteArrayToInt(getBytes(data, dataIndex, dataSize))
|
|
||||||
dataIndex += dataSize
|
|
||||||
dataSize = 1
|
|
||||||
val selectableLanguage4 = byteArrayToInt(getBytes(data, dataIndex, dataSize))
|
|
||||||
dataIndex += dataSize
|
|
||||||
dataSize = 1
|
|
||||||
val selectableLanguage5 = byteArrayToInt(getBytes(data, dataIndex, dataSize))
|
|
||||||
// Pump's screen on time can't be less than 5
|
// Pump's screen on time can't be less than 5
|
||||||
failed = danaPump.lcdOnTimeSec < 5
|
failed = danaPump.lcdOnTimeSec < 5
|
||||||
aapsLogger.debug(LTag.PUMPCOMM, "timeDisplayType24: " + danaPump.timeDisplayType24)
|
aapsLogger.debug(LTag.PUMPCOMM, "timeDisplayType24: " + danaPump.timeDisplayType24)
|
||||||
|
@ -77,12 +47,14 @@ class DanaRS_Packet_Option_Get_User_Option(
|
||||||
aapsLogger.debug(LTag.PUMPCOMM, "Pump units: " + if (danaPump.units == DanaPump.UNITS_MGDL) "MGDL" else "MMOL")
|
aapsLogger.debug(LTag.PUMPCOMM, "Pump units: " + if (danaPump.units == DanaPump.UNITS_MGDL) "MGDL" else "MMOL")
|
||||||
aapsLogger.debug(LTag.PUMPCOMM, "shutdownHour: " + danaPump.shutdownHour)
|
aapsLogger.debug(LTag.PUMPCOMM, "shutdownHour: " + danaPump.shutdownHour)
|
||||||
aapsLogger.debug(LTag.PUMPCOMM, "lowReservoirRate: " + danaPump.lowReservoirRate)
|
aapsLogger.debug(LTag.PUMPCOMM, "lowReservoirRate: " + danaPump.lowReservoirRate)
|
||||||
|
aapsLogger.debug(LTag.PUMPCOMM, "cannulaVolume: " + danaPump.cannulaVolume)
|
||||||
aapsLogger.debug(LTag.PUMPCOMM, "refillAmount: " + danaPump.refillAmount)
|
aapsLogger.debug(LTag.PUMPCOMM, "refillAmount: " + danaPump.refillAmount)
|
||||||
aapsLogger.debug(LTag.PUMPCOMM, "selectableLanguage1: $selectableLanguage1")
|
aapsLogger.debug(LTag.PUMPCOMM, "selectableLanguage1: $selectableLanguage1")
|
||||||
aapsLogger.debug(LTag.PUMPCOMM, "selectableLanguage2: $selectableLanguage2")
|
aapsLogger.debug(LTag.PUMPCOMM, "selectableLanguage2: $selectableLanguage2")
|
||||||
aapsLogger.debug(LTag.PUMPCOMM, "selectableLanguage3: $selectableLanguage3")
|
aapsLogger.debug(LTag.PUMPCOMM, "selectableLanguage3: $selectableLanguage3")
|
||||||
aapsLogger.debug(LTag.PUMPCOMM, "selectableLanguage4: $selectableLanguage4")
|
aapsLogger.debug(LTag.PUMPCOMM, "selectableLanguage4: $selectableLanguage4")
|
||||||
aapsLogger.debug(LTag.PUMPCOMM, "selectableLanguage5: $selectableLanguage5")
|
aapsLogger.debug(LTag.PUMPCOMM, "selectableLanguage5: $selectableLanguage5")
|
||||||
|
aapsLogger.debug(LTag.PUMPCOMM, "target: ${if (danaPump.units == DanaPump.UNITS_MGDL) danaPump.target else danaPump.target / 100}")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getFriendlyName(): String {
|
override fun getFriendlyName(): String {
|
||||||
|
|
|
@ -26,8 +26,12 @@ class DanaRS_Packet_Option_Set_User_Option(
|
||||||
+ "\nlcdOnTimeSec:" + danaPump.lcdOnTimeSec
|
+ "\nlcdOnTimeSec:" + danaPump.lcdOnTimeSec
|
||||||
+ "\nbacklight:" + danaPump.backlightOnTimeSec
|
+ "\nbacklight:" + danaPump.backlightOnTimeSec
|
||||||
+ "\ndanaRPumpUnits:" + danaPump.units
|
+ "\ndanaRPumpUnits:" + danaPump.units
|
||||||
+ "\nlowReservoir:" + danaPump.lowReservoirRate)
|
+ "\nlowReservoir:" + danaPump.lowReservoirRate
|
||||||
val request = ByteArray(13)
|
+ "\ncannulaVolume:" + danaPump.cannulaVolume
|
||||||
|
+ "\nrefillAmount:" + danaPump.refillAmount
|
||||||
|
+ "\ntarget:" + danaPump.target)
|
||||||
|
val size = if (danaPump.hwModel >= 7) 15 else 13
|
||||||
|
val request = ByteArray(size)
|
||||||
request[0] = if (danaPump.timeDisplayType24) 0.toByte() else 1.toByte()
|
request[0] = if (danaPump.timeDisplayType24) 0.toByte() else 1.toByte()
|
||||||
request[1] = if (danaPump.buttonScrollOnOff) 1.toByte() else 0.toByte()
|
request[1] = if (danaPump.buttonScrollOnOff) 1.toByte() else 0.toByte()
|
||||||
request[2] = (danaPump.beepAndAlarm and 0xff).toByte()
|
request[2] = (danaPump.beepAndAlarm and 0xff).toByte()
|
||||||
|
@ -41,6 +45,10 @@ class DanaRS_Packet_Option_Set_User_Option(
|
||||||
request[10] = (danaPump.cannulaVolume ushr 8 and 0xff).toByte()
|
request[10] = (danaPump.cannulaVolume ushr 8 and 0xff).toByte()
|
||||||
request[11] = (danaPump.refillAmount and 0xff).toByte()
|
request[11] = (danaPump.refillAmount and 0xff).toByte()
|
||||||
request[12] = (danaPump.refillAmount ushr 8 and 0xff).toByte()
|
request[12] = (danaPump.refillAmount ushr 8 and 0xff).toByte()
|
||||||
|
if (danaPump.hwModel >= 7) {
|
||||||
|
request[13] = (danaPump.target and 0xff).toByte()
|
||||||
|
request[14] = (danaPump.target ushr 8 and 0xff).toByte()
|
||||||
|
}
|
||||||
return request
|
return request
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -126,7 +126,9 @@ public class BleEncryption {
|
||||||
|
|
||||||
private static native void setPairingKeysJni(byte[] pairingKey, byte[] randomPairingKey, byte randomSyncKey);
|
private static native void setPairingKeysJni(byte[] pairingKey, byte[] randomPairingKey, byte randomSyncKey);
|
||||||
|
|
||||||
private static native void setEnhancedEncryptionJni(boolean isSecurityVersion);
|
private static native void setBle5KeyJni(byte[] ble5Key);
|
||||||
|
|
||||||
|
private static native void setEnhancedEncryptionJni(int securityVersion);
|
||||||
|
|
||||||
private static native byte[] encryptSecondLevelPacketJni(Object context, byte[] bytes);
|
private static native byte[] encryptSecondLevelPacketJni(Object context, byte[] bytes);
|
||||||
|
|
||||||
|
@ -144,8 +146,12 @@ public class BleEncryption {
|
||||||
setPairingKeysJni(pairingKey, randomPairingKey, randomSyncKey);
|
setPairingKeysJni(pairingKey, randomPairingKey, randomSyncKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setEnhancedEncryption(boolean isSecureVersion) {
|
public void setBle5Key(byte[] ble5Key) {
|
||||||
setEnhancedEncryptionJni(isSecureVersion);
|
setBle5KeyJni(ble5Key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnhancedEncryption(EncryptionType securityVersion) {
|
||||||
|
setEnhancedEncryptionJni(securityVersion.ordinal());
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] encryptSecondLevelPacket(byte[] bytes) {
|
public byte[] encryptSecondLevelPacket(byte[] bytes) {
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package info.nightscout.androidaps.danars.encryption
|
||||||
|
|
||||||
|
enum class EncryptionType(val type: Int) {
|
||||||
|
ENCRYPTION_DEFAULT(0),
|
||||||
|
ENCRYPTION_RSv3(1),
|
||||||
|
ENCRYPTION_BLE5(2)
|
||||||
|
}
|
|
@ -15,6 +15,7 @@ import info.nightscout.androidaps.danars.comm.DanaRSMessageHashTable
|
||||||
import info.nightscout.androidaps.danars.comm.DanaRS_Packet
|
import info.nightscout.androidaps.danars.comm.DanaRS_Packet
|
||||||
import info.nightscout.androidaps.danars.comm.DanaRS_Packet_Etc_Keep_Connection
|
import info.nightscout.androidaps.danars.comm.DanaRS_Packet_Etc_Keep_Connection
|
||||||
import info.nightscout.androidaps.danars.encryption.BleEncryption
|
import info.nightscout.androidaps.danars.encryption.BleEncryption
|
||||||
|
import info.nightscout.androidaps.danars.encryption.EncryptionType
|
||||||
import info.nightscout.androidaps.danars.events.EventDanaRSPairingSuccess
|
import info.nightscout.androidaps.danars.events.EventDanaRSPairingSuccess
|
||||||
import info.nightscout.androidaps.events.EventPumpStatusChanged
|
import info.nightscout.androidaps.events.EventPumpStatusChanged
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
|
@ -56,9 +57,13 @@ class BLEComm @Inject internal constructor(
|
||||||
private const val WRITE_DELAY_MILLIS: Long = 50
|
private const val WRITE_DELAY_MILLIS: Long = 50
|
||||||
private const val UART_READ_UUID = "0000fff1-0000-1000-8000-00805f9b34fb"
|
private const val UART_READ_UUID = "0000fff1-0000-1000-8000-00805f9b34fb"
|
||||||
private const val UART_WRITE_UUID = "0000fff2-0000-1000-8000-00805f9b34fb"
|
private const val UART_WRITE_UUID = "0000fff2-0000-1000-8000-00805f9b34fb"
|
||||||
|
private const val UART_BLE5_UUID = "00002902-0000-1000-8000-00805f9b34fb"
|
||||||
|
|
||||||
private const val PACKET_START_BYTE = 0xA5.toByte()
|
private const val PACKET_START_BYTE = 0xA5.toByte()
|
||||||
private const val PACKET_END_BYTE = 0x5A.toByte()
|
private const val PACKET_END_BYTE = 0x5A.toByte()
|
||||||
|
|
||||||
|
private const val BLE5_PACKET_START_BYTE = 0x73.toByte()
|
||||||
|
private const val BLE5_PACKET_END_BYTE = 0xBF.toByte()
|
||||||
}
|
}
|
||||||
|
|
||||||
private var scheduledDisconnection: ScheduledFuture<*>? = null
|
private var scheduledDisconnection: ScheduledFuture<*>? = null
|
||||||
|
@ -69,7 +74,7 @@ class BLEComm @Inject internal constructor(
|
||||||
private var connectDeviceName: String? = null
|
private var connectDeviceName: String? = null
|
||||||
private var bluetoothGatt: BluetoothGatt? = null
|
private var bluetoothGatt: BluetoothGatt? = null
|
||||||
|
|
||||||
private var v3Encryption: Boolean = false
|
private var encryption: EncryptionType = EncryptionType.ENCRYPTION_DEFAULT
|
||||||
set(newValue) {
|
set(newValue) {
|
||||||
bleEncryption.setEnhancedEncryption(newValue)
|
bleEncryption.setEnhancedEncryption(newValue)
|
||||||
field = newValue
|
field = newValue
|
||||||
|
@ -116,7 +121,7 @@ class BLEComm @Inject internal constructor(
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
isConnected = false
|
isConnected = false
|
||||||
v3Encryption = false
|
encryption = EncryptionType.ENCRYPTION_DEFAULT
|
||||||
encryptedDataRead = false
|
encryptedDataRead = false
|
||||||
encryptedCommandSent = false
|
encryptedCommandSent = false
|
||||||
isConnecting = true
|
isConnecting = true
|
||||||
|
@ -136,7 +141,7 @@ class BLEComm @Inject internal constructor(
|
||||||
fun disconnect(from: String) {
|
fun disconnect(from: String) {
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "disconnect from: $from")
|
aapsLogger.debug(LTag.PUMPBTCOMM, "disconnect from: $from")
|
||||||
|
|
||||||
if (!encryptedDataRead && encryptedCommandSent && v3Encryption) {
|
if (!encryptedDataRead && encryptedCommandSent && encryption == EncryptionType.ENCRYPTION_RSv3) {
|
||||||
// there was no response from pump after started encryption
|
// there was no response from pump after started encryption
|
||||||
// assume pairing keys are invalid
|
// assume pairing keys are invalid
|
||||||
val lastClearRequest = sp.getLong(R.string.key_rs_last_clear_key_request, 0)
|
val lastClearRequest = sp.getLong(R.string.key_rs_last_clear_key_request, 0)
|
||||||
|
@ -185,8 +190,6 @@ class BLEComm @Inject internal constructor(
|
||||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||||
findCharacteristic()
|
findCharacteristic()
|
||||||
}
|
}
|
||||||
sendConnect()
|
|
||||||
// 1st message sent to pump after connect
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCharacteristicRead(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) {
|
override fun onCharacteristicRead(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) {
|
||||||
|
@ -204,7 +207,7 @@ class BLEComm @Inject internal constructor(
|
||||||
override fun onCharacteristicWrite(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) {
|
override fun onCharacteristicWrite(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) {
|
||||||
// for v3 after initial handshake it's encrypted - useless
|
// for v3 after initial handshake it's encrypted - useless
|
||||||
// aapsLogger.debug(LTag.PUMPBTCOMM, "onCharacteristicWrite: " + DanaRS_Packet.toHexString(characteristic.value))
|
// aapsLogger.debug(LTag.PUMPBTCOMM, "onCharacteristicWrite: " + DanaRS_Packet.toHexString(characteristic.value))
|
||||||
Thread(Runnable {
|
Thread {
|
||||||
synchronized(mSendQueue) {
|
synchronized(mSendQueue) {
|
||||||
// after message sent, check if there is the rest of the message waiting and send it
|
// after message sent, check if there is the rest of the message waiting and send it
|
||||||
if (mSendQueue.size > 0) {
|
if (mSendQueue.size > 0) {
|
||||||
|
@ -213,7 +216,14 @@ class BLEComm @Inject internal constructor(
|
||||||
writeCharacteristicNoResponse(uartWriteBTGattChar, bytes)
|
writeCharacteristicNoResponse(uartWriteBTGattChar, bytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).start()
|
}.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDescriptorWrite(gatt: BluetoothGatt?, descriptor: BluetoothGattDescriptor?, status: Int) {
|
||||||
|
super.onDescriptorWrite(gatt, descriptor, status)
|
||||||
|
//aapsLogger.debug(LTag.PUMPBTCOMM, "onDescriptorWrite " + status)
|
||||||
|
sendConnect()
|
||||||
|
// 1st message sent to pump after connect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,6 +239,11 @@ class BLEComm @Inject internal constructor(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
bluetoothGatt?.setCharacteristicNotification(characteristic, enabled)
|
bluetoothGatt?.setCharacteristicNotification(characteristic, enabled)
|
||||||
|
// Dana-i BLE5 specific
|
||||||
|
characteristic?.getDescriptor(UUID.fromString(UART_BLE5_UUID))?.let {
|
||||||
|
it.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
|
||||||
|
bluetoothGatt?.writeDescriptor(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
|
@ -299,7 +314,7 @@ class BLEComm @Inject internal constructor(
|
||||||
close()
|
close()
|
||||||
isConnected = false
|
isConnected = false
|
||||||
isConnecting = false
|
isConnecting = false
|
||||||
v3Encryption = false
|
encryption = EncryptionType.ENCRYPTION_DEFAULT
|
||||||
encryptedDataRead = false
|
encryptedDataRead = false
|
||||||
encryptedCommandSent = false
|
encryptedCommandSent = false
|
||||||
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED))
|
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED))
|
||||||
|
@ -331,7 +346,7 @@ class BLEComm @Inject internal constructor(
|
||||||
var inputBuffer: ByteArray? = null
|
var inputBuffer: ByteArray? = null
|
||||||
|
|
||||||
// decrypt 2nd level after successful connection
|
// decrypt 2nd level after successful connection
|
||||||
val incomingBuffer = if (v3Encryption && isConnected)
|
val incomingBuffer = if (encryption == EncryptionType.ENCRYPTION_RSv3 && isConnected)
|
||||||
bleEncryption.decryptSecondLevelPacket(receivedData).also {
|
bleEncryption.decryptSecondLevelPacket(receivedData).also {
|
||||||
encryptedDataRead = true
|
encryptedDataRead = true
|
||||||
sp.putLong(R.string.key_rs_last_clear_key_request, 0L)
|
sp.putLong(R.string.key_rs_last_clear_key_request, 0L)
|
||||||
|
@ -342,7 +357,6 @@ class BLEComm @Inject internal constructor(
|
||||||
while (isProcessing) {
|
while (isProcessing) {
|
||||||
var length = 0
|
var length = 0
|
||||||
synchronized(readBuffer) {
|
synchronized(readBuffer) {
|
||||||
|
|
||||||
// Find packet start [A5 A5]
|
// Find packet start [A5 A5]
|
||||||
if (bufferLength >= 6) {
|
if (bufferLength >= 6) {
|
||||||
for (idxStartByte in 0 until bufferLength - 2) {
|
for (idxStartByte in 0 until bufferLength - 2) {
|
||||||
|
@ -370,6 +384,36 @@ class BLEComm @Inject internal constructor(
|
||||||
packetIsValid = true
|
packetIsValid = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// packet can be BLE5 encrypted too
|
||||||
|
if (!packetIsValid && encryption == EncryptionType.ENCRYPTION_BLE5) {
|
||||||
|
var startIndex: Int = -1
|
||||||
|
// Find encrypted packet start [73 73]
|
||||||
|
if (bufferLength >= 6) {
|
||||||
|
for (idxStartByte in 0 until bufferLength - 2) {
|
||||||
|
if (readBuffer[idxStartByte] == BLE5_PACKET_START_BYTE && readBuffer[idxStartByte + 1] == BLE5_PACKET_START_BYTE) {
|
||||||
|
if (idxStartByte > 0) {
|
||||||
|
// if buffer doesn't start with signature remove the leading trash
|
||||||
|
aapsLogger.debug(LTag.PUMPBTCOMM, "Shifting the input buffer by $idxStartByte bytes")
|
||||||
|
System.arraycopy(readBuffer, idxStartByte, readBuffer, 0, bufferLength - idxStartByte)
|
||||||
|
bufferLength -= idxStartByte
|
||||||
|
}
|
||||||
|
startIndex = idxStartByte
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 73 73 ENCRYPTED CONTENT BF BF
|
||||||
|
if (startIndex != -1) {
|
||||||
|
for (idxEndByte in 5..bufferLength - 2) {
|
||||||
|
if (readBuffer[idxEndByte] == BLE5_PACKET_END_BYTE && readBuffer[idxEndByte + 1] == BLE5_PACKET_END_BYTE) {
|
||||||
|
length = idxEndByte - startIndex + 2 - 7
|
||||||
|
packetIsValid = true
|
||||||
|
encryptedDataRead = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (packetIsValid) {
|
if (packetIsValid) {
|
||||||
inputBuffer = ByteArray(length + 7)
|
inputBuffer = ByteArray(length + 7)
|
||||||
// copy packet to input buffer
|
// copy packet to input buffer
|
||||||
|
@ -385,7 +429,11 @@ class BLEComm @Inject internal constructor(
|
||||||
// now we have encrypted packet in inputBuffer
|
// now we have encrypted packet in inputBuffer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (packetIsValid && encryptedDataRead && encryption == EncryptionType.ENCRYPTION_BLE5) {
|
||||||
|
inputBuffer = bleEncryption.decryptSecondLevelPacket(inputBuffer)
|
||||||
|
}
|
||||||
if (packetIsValid) {
|
if (packetIsValid) {
|
||||||
|
// aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< PROCESSING: " + DanaRS_Packet.toHexString(inputBuffer))
|
||||||
// decrypt the packet
|
// decrypt the packet
|
||||||
bleEncryption.getDecryptedPacket(inputBuffer)?.let { decryptedBuffer ->
|
bleEncryption.getDecryptedPacket(inputBuffer)?.let { decryptedBuffer ->
|
||||||
if (decryptedBuffer[0] == BleEncryption.DANAR_PACKET__TYPE_ENCRYPTION_RESPONSE.toByte()) {
|
if (decryptedBuffer[0] == BleEncryption.DANAR_PACKET__TYPE_ENCRYPTION_RESPONSE.toByte()) {
|
||||||
|
@ -453,8 +501,8 @@ class BLEComm @Inject internal constructor(
|
||||||
// response OK v1
|
// response OK v1
|
||||||
if (decryptedBuffer.size == 4 && decryptedBuffer[2] == 'O'.toByte() && decryptedBuffer[3] == 'K'.toByte()) {
|
if (decryptedBuffer.size == 4 && decryptedBuffer[2] == 'O'.toByte() && decryptedBuffer[3] == 'K'.toByte()) {
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__PUMP_CHECK (OK)" + " " + DanaRS_Packet.toHexString(decryptedBuffer))
|
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__PUMP_CHECK (OK)" + " " + DanaRS_Packet.toHexString(decryptedBuffer))
|
||||||
v3Encryption = false
|
encryption = EncryptionType.ENCRYPTION_DEFAULT
|
||||||
danaPump.v3RSPump = false
|
danaPump.ignoreUserPassword = false
|
||||||
// Grab pairing key from preferences if exists
|
// Grab pairing key from preferences if exists
|
||||||
val pairingKey = sp.getString(resourceHelper.gs(R.string.key_danars_pairingkey) + danaRSPlugin.mDeviceName, "")
|
val pairingKey = sp.getString(resourceHelper.gs(R.string.key_danars_pairingkey) + danaRSPlugin.mDeviceName, "")
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Using stored pairing key: $pairingKey")
|
aapsLogger.debug(LTag.PUMPBTCOMM, "Using stored pairing key: $pairingKey")
|
||||||
|
@ -467,8 +515,8 @@ class BLEComm @Inject internal constructor(
|
||||||
// response OK v3
|
// response OK v3
|
||||||
} else if (decryptedBuffer.size == 9 && decryptedBuffer[2] == 'O'.toByte() && decryptedBuffer[3] == 'K'.toByte()) {
|
} else if (decryptedBuffer.size == 9 && decryptedBuffer[2] == 'O'.toByte() && decryptedBuffer[3] == 'K'.toByte()) {
|
||||||
// v3 2nd layer encryption
|
// v3 2nd layer encryption
|
||||||
v3Encryption = true
|
encryption = EncryptionType.ENCRYPTION_RSv3
|
||||||
danaPump.v3RSPump = true
|
danaPump.ignoreUserPassword = true
|
||||||
danaPump.hwModel = decryptedBuffer[5].toInt()
|
danaPump.hwModel = decryptedBuffer[5].toInt()
|
||||||
danaPump.protocol = decryptedBuffer[7].toInt()
|
danaPump.protocol = decryptedBuffer[7].toInt()
|
||||||
// grab randomSyncKey
|
// grab randomSyncKey
|
||||||
|
@ -483,6 +531,21 @@ class BLEComm @Inject internal constructor(
|
||||||
// Dana RS Easy
|
// Dana RS Easy
|
||||||
sendEasyMenuCheck()
|
sendEasyMenuCheck()
|
||||||
}
|
}
|
||||||
|
// response OK BLE5
|
||||||
|
} else if (decryptedBuffer.size == 14 && decryptedBuffer[2] == 'O'.toByte() && decryptedBuffer[3] == 'K'.toByte()) {
|
||||||
|
// v3 2nd layer encryption
|
||||||
|
encryption = EncryptionType.ENCRYPTION_BLE5
|
||||||
|
danaPump.ignoreUserPassword = true
|
||||||
|
danaPump.hwModel = decryptedBuffer[5].toInt()
|
||||||
|
danaPump.protocol = decryptedBuffer[7].toInt()
|
||||||
|
val pairingKey = DanaRS_Packet.asciiStringFromBuff(decryptedBuffer, 8, 6) // used while bonding
|
||||||
|
|
||||||
|
if (danaPump.hwModel == 0x09) {
|
||||||
|
bleEncryption.setBle5Key(pairingKey.encodeToByteArray())
|
||||||
|
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__PUMP_CHECK BLE5 (OK)" + " " + DanaRS_Packet.toHexString(decryptedBuffer))
|
||||||
|
// Dana-i BLE5 Pump
|
||||||
|
sendBLE5PairingInformation()
|
||||||
|
}
|
||||||
// response PUMP : error status
|
// response PUMP : error status
|
||||||
} else if (decryptedBuffer.size == 6 && decryptedBuffer[2] == 'P'.toByte() && decryptedBuffer[3] == 'U'.toByte() && decryptedBuffer[4] == 'M'.toByte() && decryptedBuffer[5] == 'P'.toByte()) {
|
} else if (decryptedBuffer.size == 6 && decryptedBuffer[2] == 'P'.toByte() && decryptedBuffer[3] == 'U'.toByte() && decryptedBuffer[4] == 'M'.toByte() && decryptedBuffer[5] == 'P'.toByte()) {
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__PUMP_CHECK (PUMP)" + " " + DanaRS_Packet.toHexString(decryptedBuffer))
|
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__PUMP_CHECK (PUMP)" + " " + DanaRS_Packet.toHexString(decryptedBuffer))
|
||||||
|
@ -501,8 +564,8 @@ class BLEComm @Inject internal constructor(
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__PUMP_CHECK (ERROR)" + " " + DanaRS_Packet.toHexString(decryptedBuffer))
|
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__PUMP_CHECK (ERROR)" + " " + DanaRS_Packet.toHexString(decryptedBuffer))
|
||||||
mSendQueue.clear()
|
mSendQueue.clear()
|
||||||
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED, resourceHelper.gs(R.string.connectionerror)))
|
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED, resourceHelper.gs(R.string.connectionerror)))
|
||||||
sp.remove(resourceHelper.gs(R.string.key_danars_pairingkey) + danaRSPlugin.mDeviceName)
|
danaRSPlugin.clearPairing()
|
||||||
val n = Notification(Notification.WRONGSERIALNUMBER, resourceHelper.gs(R.string.wrongpassword), Notification.URGENT)
|
val n = Notification(Notification.WRONGSERIALNUMBER, resourceHelper.gs(R.string.password_cleared), Notification.URGENT)
|
||||||
rxBus.send(EventNewNotification(n))
|
rxBus.send(EventNewNotification(n))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -544,6 +607,14 @@ class BLEComm @Inject internal constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2nd packet BLE5
|
||||||
|
private fun sendBLE5PairingInformation() {
|
||||||
|
val params = ByteArray(4) { 0.toByte() }
|
||||||
|
val bytes: ByteArray = bleEncryption.getEncryptedPacket(BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__TIME_INFORMATION, params, null)
|
||||||
|
aapsLogger.debug(LTag.PUMPBTCOMM, ">>>>> " + "ENCRYPTION__TIME_INFORMATION BLE5" + " " + DanaRS_Packet.toHexString(bytes))
|
||||||
|
writeCharacteristicNoResponse(uartWriteBTGattChar, bytes)
|
||||||
|
}
|
||||||
|
|
||||||
private fun sendV3PairingInformation(requestNewPairing: Int) {
|
private fun sendV3PairingInformation(requestNewPairing: Int) {
|
||||||
val params = byteArrayOf(requestNewPairing.toByte())
|
val params = byteArrayOf(requestNewPairing.toByte())
|
||||||
val bytes: ByteArray = bleEncryption.getEncryptedPacket(BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__TIME_INFORMATION, params, null)
|
val bytes: ByteArray = bleEncryption.getEncryptedPacket(BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__TIME_INFORMATION, params, null)
|
||||||
|
@ -553,8 +624,12 @@ class BLEComm @Inject internal constructor(
|
||||||
|
|
||||||
// 2nd packet response
|
// 2nd packet response
|
||||||
private fun processEncryptionResponse(decryptedBuffer: ByteArray) {
|
private fun processEncryptionResponse(decryptedBuffer: ByteArray) {
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__TIME_INFORMATION " + /*message.getMessageName() + " " + */DanaRS_Packet.toHexString(decryptedBuffer))
|
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__TIME_INFORMATION " + DanaRS_Packet.toHexString(decryptedBuffer))
|
||||||
if (v3Encryption) {
|
if (encryption == EncryptionType.ENCRYPTION_BLE5) {
|
||||||
|
isConnected = true
|
||||||
|
isConnecting = false
|
||||||
|
aapsLogger.debug(LTag.PUMPBTCOMM, "Connect !!")
|
||||||
|
} else if (encryption == EncryptionType.ENCRYPTION_RSv3) {
|
||||||
// decryptedBuffer[2] : 0x00 OK 0x01 Error, No pairing
|
// decryptedBuffer[2] : 0x00 OK 0x01 Error, No pairing
|
||||||
if (decryptedBuffer[2] == 0x00.toByte()) {
|
if (decryptedBuffer[2] == 0x00.toByte()) {
|
||||||
val randomPairingKey = sp.getString(resourceHelper.gs(R.string.key_danars_v3_randompairingkey) + danaRSPlugin.mDeviceName, "")
|
val randomPairingKey = sp.getString(resourceHelper.gs(R.string.key_danars_v3_randompairingkey) + danaRSPlugin.mDeviceName, "")
|
||||||
|
@ -656,7 +731,7 @@ class BLEComm @Inject internal constructor(
|
||||||
isUnitUD = decryptedBuffer[3] == 0x01.toByte()
|
isUnitUD = decryptedBuffer[3] == 0x01.toByte()
|
||||||
|
|
||||||
// request time information
|
// request time information
|
||||||
if (v3Encryption) sendV3PairingInformation()
|
if (encryption == EncryptionType.ENCRYPTION_RSv3) sendV3PairingInformation()
|
||||||
else sendTimeInfo()
|
else sendTimeInfo()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -668,7 +743,8 @@ class BLEComm @Inject internal constructor(
|
||||||
val params = message.requestParams
|
val params = message.requestParams
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, ">>>>> " + message.friendlyName + " " + DanaRS_Packet.toHexString(command) + " " + DanaRS_Packet.toHexString(params))
|
aapsLogger.debug(LTag.PUMPBTCOMM, ">>>>> " + message.friendlyName + " " + DanaRS_Packet.toHexString(command) + " " + DanaRS_Packet.toHexString(params))
|
||||||
var bytes = bleEncryption.getEncryptedPacket(message.opCode, params, null)
|
var bytes = bleEncryption.getEncryptedPacket(message.opCode, params, null)
|
||||||
if (v3Encryption)
|
// aapsLogger.debug(LTag.PUMPBTCOMM, ">>>>> " + DanaRS_Packet.toHexString(bytes))
|
||||||
|
if (encryption != EncryptionType.ENCRYPTION_DEFAULT)
|
||||||
bytes = bleEncryption.encryptSecondLevelPacket(bytes)
|
bytes = bleEncryption.encryptSecondLevelPacket(bytes)
|
||||||
// If there is another message not completely sent, add to queue only
|
// If there is another message not completely sent, add to queue only
|
||||||
if (mSendQueue.size > 0) {
|
if (mSendQueue.size > 0) {
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in a new issue