@@ -8,6 +8,8 @@ import android.bluetooth.BluetoothGattDescriptor
88import android.bluetooth.BluetoothGattService
99import android.bluetooth.BluetoothProfile
1010import android.content.SharedPreferences
11+ import android.os.Handler
12+ import android.os.Looper
1113import com.nightscout.eversense.enums.EversenseSecurityType
1214import com.nightscout.eversense.exceptions.EversenseWriteException
1315import com.nightscout.eversense.packets.EversenseBasePacket
@@ -22,10 +24,13 @@ import com.nightscout.eversense.packets.Eversense365Communicator
2224import com.nightscout.eversense.packets.e365.AuthIdentityPacket
2325import com.nightscout.eversense.packets.e365.AuthStartPacket
2426import com.nightscout.eversense.packets.e365.AuthWhoAmIPacket
27+ import com.nightscout.eversense.packets.e365.Eversense365Packets
28+ import com.nightscout.eversense.packets.e365.KeepAlivePacket
2529import com.nightscout.eversense.util.EversenseCrypto365Util
2630import com.nightscout.eversense.util.EversenseHttp365Util
2731import com.nightscout.eversense.util.EversenseLogger
2832import com.nightscout.eversense.util.StorageKeys
33+ import java.util.concurrent.TimeUnit
2934
3035class EversenseGattCallback (
3136 private val plugin : EversenseCGMPlugin ,
@@ -46,6 +51,7 @@ class EversenseGattCallback(
4651 }
4752
4853 private val executor = Executors .newSingleThreadExecutor()
54+ private val handler = Handler (Looper .getMainLooper())
4955 private var bluetoothGatt: BluetoothGatt ? = null
5056 private var eversenseBluetoothService: BluetoothGattService ? = null
5157 private var requestCharacteristic: BluetoothGattCharacteristic ? = null
@@ -62,7 +68,7 @@ class EversenseGattCallback(
6268
6369 @SuppressLint(" MissingPermission" )
6470 override fun onConnectionStateChange (gatt : BluetoothGatt , status : Int , newState : Int ) {
65- EversenseLogger .info(TAG , " Connection state changed - state: $status , newState: $newState " )
71+ EversenseLogger .info(TAG , " Connection state changed - state: $status , newState: $newState , ${gatt.device.name} " )
6672
6773 if (status == BluetoothGatt .GATT_SUCCESS && newState == BluetoothProfile .STATE_CONNECTED ) {
6874 bluetoothGatt = gatt
@@ -71,8 +77,10 @@ class EversenseGattCallback(
7177 putString(StorageKeys .REMOTE_DEVICE_KEY , gatt.device.address)
7278 }
7379
74- for (watcher in plugin.watchers) {
75- watcher.onConnectionChanged(true )
80+ handler.post {
81+ plugin.watchers.forEach {
82+ it.onConnectionChanged(true )
83+ }
7684 }
7785
7886 if (! gatt.requestMtu(512 )) {
@@ -93,14 +101,14 @@ class EversenseGattCallback(
93101
94102 @SuppressLint(" MissingPermission" )
95103 override fun onMtuChanged (gatt : BluetoothGatt ? , mtu : Int , status : Int ) {
96- if (status == 0 ) {
97- payloadSize = mtu - 3
98- EversenseLogger .debug(TAG , " New payload size: $payloadSize " )
99- } else {
100- payloadSize = 20
104+ if (status != 0 ) {
101105 EversenseLogger .error(TAG , " Failed to set payload size - status: $status " )
106+ return
102107 }
103108
109+ payloadSize = mtu - 3
110+ EversenseLogger .debug(TAG , " New payload size: $payloadSize " )
111+
104112 val success = gatt?.discoverServices()
105113 EversenseLogger .info(TAG , " Trigger discover services - success: $success " )
106114 }
@@ -173,13 +181,28 @@ class EversenseGattCallback(
173181 }
174182 }
175183
184+ @Deprecated(" " )
185+ @SuppressLint(" MissingPermission" )
176186 @OptIn(ExperimentalStdlibApi ::class )
177187 override fun onCharacteristicChanged (gatt : BluetoothGatt , characteristic : BluetoothGattCharacteristic ) {
178188 EversenseLogger .debug(TAG , " Received data: ${characteristic.value.toHexString()} " )
179189
180190 var data = characteristic.value
181191 if (security == EversenseSecurityType .SecureV2 ) {
182192 data = data.drop(3 ).toByteArray()
193+
194+ if (data[0 ] != Eversense365Packets .AuthenticateResponseId ) {
195+ data = cryptoUtil.decrypt(data)
196+ EversenseLogger .debug(TAG , " Decrypted data -> ${data.toHexString()} " )
197+ if (data.isEmpty()) {
198+ EversenseLogger .error(TAG , " Failed do decrypt data..." )
199+
200+ // Delete keys to redo security handshake on next connection
201+ cryptoUtil.disallowUseShortcut()
202+ gatt.disconnect()
203+ return
204+ }
205+ }
183206 }
184207
185208 if (EversenseE3Packets .isPushPacket(data[0 ])) {
@@ -191,6 +214,27 @@ class EversenseGattCallback(
191214 return
192215 }
193216
217+ if (Eversense365Packets .isKeepAlivePacket(data[0 ], data[1 ])) {
218+ EversenseLogger .debug(TAG , " Keep Alive packet received!" )
219+
220+ val packet = KeepAlivePacket ()
221+ packet.appendData(data.toUByteArray())
222+ val response = packet.parseResponse() ? : return
223+
224+ val fourHalfMinAgo = System .currentTimeMillis() - TimeUnit .SECONDS .toMillis(270 )
225+ if (response.glucoseDatetime > fourHalfMinAgo) {
226+ executor.submit {
227+ Eversense365Communicator .readGlucose(this , preferences, plugin.watchers)
228+ Eversense365Communicator .fullSync(this , preferences, plugin.watchers)
229+ }
230+ }
231+
232+ return
233+ } else if (Eversense365Packets .isNotificationPacket(data[0 ])) {
234+ EversenseLogger .warning(TAG , " Unknown notification packet received..." )
235+ return
236+ }
237+
194238 val packet = currentPacket ? : run {
195239 EversenseLogger .warning(TAG , " currentPacket is empty -> Skip packet..." )
196240 return
@@ -208,15 +252,20 @@ class EversenseGattCallback(
208252 return
209253 }
210254
211- if (packetAnnotation.responseId != data[0 ]) {
212- EversenseLogger .warning(TAG , " Incorrect responseId received - Expected: ${packetAnnotation.responseId} , got: ${data[0 ]} " )
213- return
214- }
215-
216255 if (security == EversenseSecurityType .None ) {
256+ if (packetAnnotation.responseId != data[0 ]) {
257+ EversenseLogger .warning(TAG , " Incorrect responseId received - Expected: ${packetAnnotation.responseId} , got: ${data[0 ]} " )
258+ return
259+ }
260+
217261 packet.appendData(data.toUByteArray())
218262 packet.notifyAll()
219263 } else {
264+ if (packetAnnotation.responseId != data[0 ]) {
265+ EversenseLogger .warning(TAG , " Incorrect responseId received - Expected: ${packetAnnotation.responseId} , got: ${data[0 ]} " )
266+ return
267+ }
268+
220269 if (packetAnnotation.typeId != data[1 ]) {
221270 EversenseLogger .warning(TAG , " Incorrect responseType received - Expected: ${packetAnnotation.typeId} , got: ${data[1 ]} " )
222271 return
@@ -241,7 +290,7 @@ class EversenseGattCallback(
241290 throw EversenseWriteException (" requestCharacteristic is empty" )
242291 }
243292
244- val requestData = packet.buildRequest(cryptoUtil) ? : run {
293+ val requestData = packet.buildRequest(cryptoUtil, payloadSize ) ? : run {
245294 throw EversenseWriteException (" Failed to build request data..." )
246295 }
247296
@@ -264,7 +313,7 @@ class EversenseGattCallback(
264313 return try {
265314 val response = packet.parseResponse()
266315 currentPacket = null
267- response as ? T ? : throw EversenseWriteException (" Unable to cast response" )
316+ response as ? T ? : throw EversenseWriteException (" Unable to cast response - packet: ${packet.getAnnotation()?.responseId} " )
268317 } catch (e: Exception ) {
269318 throw EversenseWriteException (" Failed to parse response - exception: $e " )
270319 }
@@ -293,7 +342,8 @@ class EversenseGattCallback(
293342 }
294343
295344 if (! cryptoUtil.canUseShortcut()) {
296- val whoAmI = writePacket<AuthWhoAmIPacket .Response >(AuthWhoAmIPacket ())
345+ val clientId = cryptoUtil.getClientId()
346+ val whoAmI = writePacket<AuthWhoAmIPacket .Response >(AuthWhoAmIPacket (clientId))
297347
298348 val authSession = EversenseHttp365Util .login(preferences) ? : run {
299349 bluetoothGatt?.disconnect()
@@ -330,6 +380,7 @@ class EversenseGattCallback(
330380 Eversense365Communicator .fullSync(this , preferences, plugin.watchers)
331381 } catch (exception: Exception ) {
332382 EversenseLogger .error(TAG , " [365] Failed to do authV2 - $exception " )
383+ exception.printStackTrace()
333384 bluetoothGatt?.disconnect()
334385 }
335386 }
0 commit comments