From 2780a089310df59cbeee85c17a9018c400beecb9 Mon Sep 17 00:00:00 2001 From: geeksville Date: Thu, 25 Jun 2020 15:53:17 -0700 Subject: [PATCH 1/3] The android Gatt caching bug on old phones (based on my reading of the android C code) needs a small delay after calling refresh() because otherwise the (stale) BLE handles are not discarded until _after_ we start using the connected service. --- TODO.md | 7 ++- .../mesh/service/BluetoothInterface.kt | 52 ++++++++++--------- 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/TODO.md b/TODO.md index 21fe9d566..8ecab12d3 100644 --- a/TODO.md +++ b/TODO.md @@ -1,7 +1,12 @@ # Remaining tasks before declaring 1.0 +- disable software update button after update finishes +- check BLE handle stability across sleep - stress test sleep/wake +- @feh123 Sony Xperia Z1 C6903 running Android 5.1.1 +- first message sent is still doubled for some people +- Android frontend should refetch the android messages from backend service on Resume +- let users set arbitrary params in android * add a low level settings screen (let user change any of the RadioConfig parameters) -* add play store link with https://developers.google.com/analytics/devguides/collection/android/v4/campaigns#google-play-url-builder and the play icon Things for the betaish period. diff --git a/app/src/main/java/com/geeksville/mesh/service/BluetoothInterface.kt b/app/src/main/java/com/geeksville/mesh/service/BluetoothInterface.kt index 4c79387fd..bbc3089e5 100644 --- a/app/src/main/java/com/geeksville/mesh/service/BluetoothInterface.kt +++ b/app/src/main/java/com/geeksville/mesh/service/BluetoothInterface.kt @@ -384,32 +384,36 @@ class BluetoothInterface(val service: RadioInterfaceService, val address: String // This callback is invoked after we are connected connRes.getOrThrow() - info("Connected to radio!") - if (needForceRefresh) { // Our ESP32 code doesn't properly generate "service changed" indications. Therefore we need to force a refresh on initial start - //needForceRefresh = false // In fact, because of tearing down BLE in sleep on the ESP32, our handle # assignments are not stable across sleep - so we much refetch every time - forceServiceRefresh() - } - - // we begin by setting our MTU size as high as it can go (if we can) - if (shouldSetMtu) - safe!!.asyncRequestMtu(512) { mtuRes -> - try { - mtuRes.getOrThrow() // FIXME - why sometimes is the result Unit!?! - debug("MTU change attempted") - - // throw BLEException("Test MTU set failed") - - doDiscoverServicesAndInit() - } catch (ex: BLEException) { - shouldSetMtu = false - scheduleReconnect( - "Giving up on setting MTUs, forcing disconnect $ex" - ) - } + service.serviceScope.handledLaunch { + info("Connected to radio!") + + if (needForceRefresh) { // Our ESP32 code doesn't properly generate "service changed" indications. Therefore we need to force a refresh on initial start + //needForceRefresh = false // In fact, because of tearing down BLE in sleep on the ESP32, our handle # assignments are not stable across sleep - so we much refetch every time + forceServiceRefresh() // this article says android should not be caching, but it does on some phones: https://punchthrough.com/attribute-caching-in-ble-advantages-and-pitfalls/ + delay(200) // From looking at the android C code it seems that we need to give some time for the refresh message to reach that worked _before_ we try to set mtu/get services } - else - doDiscoverServicesAndInit() + + // we begin by setting our MTU size as high as it can go (if we can) + if (shouldSetMtu) + safe!!.asyncRequestMtu(512) { mtuRes -> + try { + mtuRes.getOrThrow() // FIXME - why sometimes is the result Unit!?! + debug("MTU change attempted") + + // throw BLEException("Test MTU set failed") + + doDiscoverServicesAndInit() + } catch (ex: BLEException) { + shouldSetMtu = false + scheduleReconnect( + "Giving up on setting MTUs, forcing disconnect $ex" + ) + } + } + else + doDiscoverServicesAndInit() + } } From 1fd80c06d88cf7d6bf050087d5d9cada5a60e170 Mon Sep 17 00:00:00 2001 From: geeksville Date: Thu, 25 Jun 2020 17:56:31 -0700 Subject: [PATCH 2/3] Fix #67, see that issue for writeup. gatt needs to be @Volatile --- .../java/com/geeksville/mesh/service/BluetoothInterface.kt | 5 +++-- .../main/java/com/geeksville/mesh/service/SafeBluetooth.kt | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/geeksville/mesh/service/BluetoothInterface.kt b/app/src/main/java/com/geeksville/mesh/service/BluetoothInterface.kt index bbc3089e5..3ec512a2e 100644 --- a/app/src/main/java/com/geeksville/mesh/service/BluetoothInterface.kt +++ b/app/src/main/java/com/geeksville/mesh/service/BluetoothInterface.kt @@ -322,7 +322,8 @@ class BluetoothInterface(val service: RadioInterfaceService, val address: String val s = safe if (s != null) { warn("Forcing disconnect and hopefully device will comeback (disabling forced refresh)") - hasForcedRefresh = true + hasForcedRefresh = + true // We've already tossed any old service caches, no need to do it again ignoreException { s.closeConnection() } @@ -387,7 +388,7 @@ class BluetoothInterface(val service: RadioInterfaceService, val address: String service.serviceScope.handledLaunch { info("Connected to radio!") - + if (needForceRefresh) { // Our ESP32 code doesn't properly generate "service changed" indications. Therefore we need to force a refresh on initial start //needForceRefresh = false // In fact, because of tearing down BLE in sleep on the ESP32, our handle # assignments are not stable across sleep - so we much refetch every time forceServiceRefresh() // this article says android should not be caching, but it does on some phones: https://punchthrough.com/attribute-caching-in-ble-advantages-and-pitfalls/ diff --git a/app/src/main/java/com/geeksville/mesh/service/SafeBluetooth.kt b/app/src/main/java/com/geeksville/mesh/service/SafeBluetooth.kt index 7c1407767..02ae7d193 100644 --- a/app/src/main/java/com/geeksville/mesh/service/SafeBluetooth.kt +++ b/app/src/main/java/com/geeksville/mesh/service/SafeBluetooth.kt @@ -38,6 +38,7 @@ class SafeBluetooth(private val context: Context, private val device: BluetoothD var timeoutMsec = 15 * 1000L /// Users can access the GATT directly as needed + @Volatile var gatt: BluetoothGatt? = null @Volatile From d75f7d37215490ff26c41679eb6ad26880848bb4 Mon Sep 17 00:00:00 2001 From: geeksville Date: Thu, 25 Jun 2020 17:58:48 -0700 Subject: [PATCH 3/3] 0.7.81 --- TODO.md | 2 -- app/build.gradle | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/TODO.md b/TODO.md index 8ecab12d3..b952f2245 100644 --- a/TODO.md +++ b/TODO.md @@ -1,8 +1,6 @@ # Remaining tasks before declaring 1.0 - disable software update button after update finishes -- check BLE handle stability across sleep - stress test sleep/wake -- @feh123 Sony Xperia Z1 C6903 running Android 5.1.1 - first message sent is still doubled for some people - Android frontend should refetch the android messages from backend service on Resume - let users set arbitrary params in android diff --git a/app/build.gradle b/app/build.gradle index 2c161247a..73914bcb9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -17,8 +17,8 @@ android { applicationId "com.geeksville.mesh" minSdkVersion 21 // The oldest emulator image I have tried is 22 (though 21 probably works) targetSdkVersion 29 - versionCode 10780 // format is Mmmss (where M is 1+the numeric major number - versionName "0.7.80" + versionCode 10781 // format is Mmmss (where M is 1+the numeric major number + versionName "0.7.81" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes {