diff --git a/app/build.gradle b/app/build.gradle index 49e8b7a97..9f8ea3398 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -43,8 +43,8 @@ android { applicationId "com.geeksville.mesh" minSdkVersion 21 // The oldest emulator image I have tried is 22 (though 21 probably works) targetSdkVersion 30 - versionCode 20342 // format is Mmmss (where M is 1+the numeric major number - versionName "1.3.42" + versionCode 20343 // format is Mmmss (where M is 1+the numeric major number + versionName "1.3.43" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" // per https://developer.android.com/studio/write/vector-asset-studio diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 535d6953d..bbd202024 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -137,7 +137,7 @@ @@ -146,11 +146,11 @@ diff --git a/app/src/main/java/com/geeksville/mesh/MainActivity.kt b/app/src/main/java/com/geeksville/mesh/MainActivity.kt index 0ec7b5716..8d728cd34 100644 --- a/app/src/main/java/com/geeksville/mesh/MainActivity.kt +++ b/app/src/main/java/com/geeksville/mesh/MainActivity.kt @@ -40,6 +40,7 @@ import com.geeksville.mesh.model.BluetoothViewModel import com.geeksville.mesh.model.ChannelSet import com.geeksville.mesh.model.DeviceVersion import com.geeksville.mesh.model.UIViewModel +import com.geeksville.mesh.repository.radio.BluetoothInterface import com.geeksville.mesh.repository.radio.RadioInterfaceService import com.geeksville.mesh.repository.radio.SerialInterface import com.geeksville.mesh.service.* @@ -416,6 +417,7 @@ class MainActivity : BaseActivity(), Logging { /** Show an alert that may contain HTML */ private fun showAlert(titleText: Int, messageText: Int) { + // make links clickable per https://stackoverflow.com/a/62642807 // val messageStr = getText(messageText) @@ -476,6 +478,8 @@ class MainActivity : BaseActivity(), Logging { } } } + } else if (BluetoothInterface.invalidVersion) { + showAlert(R.string.firmware_too_old, R.string.firmware_old) } } catch (ex: RemoteException) { warn("Abandoning connect $ex, because we probably just lost device connection") diff --git a/app/src/main/java/com/geeksville/mesh/model/ChannelSet.kt b/app/src/main/java/com/geeksville/mesh/model/ChannelSet.kt index 9789bdb13..3d6a6c356 100644 --- a/app/src/main/java/com/geeksville/mesh/model/ChannelSet.kt +++ b/app/src/main/java/com/geeksville/mesh/model/ChannelSet.kt @@ -15,7 +15,7 @@ data class ChannelSet( ) : Logging { companion object { - const val prefix = "https://www.meshtastic.org/e/#" + const val prefix = "https://meshtastic.org/e/#" private const val base64Flags = Base64.URL_SAFE + Base64.NO_WRAP + Base64.NO_PADDING @@ -65,7 +65,7 @@ data class ChannelSet( // We encode as UPPER case for the QR code URL because QR codes are more efficient for that special case val bitMatrix = multiFormatWriter.encode( - getChannelUrl(true).toString(), + getChannelUrl(false).toString(), BarcodeFormat.QR_CODE, 960, 960 diff --git a/app/src/main/java/com/geeksville/mesh/repository/radio/BluetoothInterface.kt b/app/src/main/java/com/geeksville/mesh/repository/radio/BluetoothInterface.kt index d77dab876..3c843a9c7 100644 --- a/app/src/main/java/com/geeksville/mesh/repository/radio/BluetoothInterface.kt +++ b/app/src/main/java/com/geeksville/mesh/repository/radio/BluetoothInterface.kt @@ -99,6 +99,10 @@ class BluetoothInterface( /// this service UUID is publically visible for scanning val BTM_SERVICE_UUID: UUID = UUID.fromString("6ba1b218-15a8-461f-9fa8-5dcae273eafd") + var invalidVersion = false + val EOL_FROMRADIO_CHARACTER: UUID = + UUID.fromString("8ba2bcc2-ee02-4a55-a531-c525c5e454d5") + val BTM_FROMRADIO_CHARACTER: UUID = UUID.fromString("2c55e69e-4993-11ed-b878-0242ac120002") val BTM_TORADIO_CHARACTER: UUID = @@ -149,6 +153,7 @@ class BluetoothInterface( ?: throw RadioNotConnectedException("BLE service not found") private lateinit var fromNum: BluetoothGattCharacteristic + private lateinit var fromRadio: BluetoothGattCharacteristic /** * With the new rev2 api, our first send is to start the configure readbacks. In that case, @@ -228,7 +233,6 @@ class BluetoothInterface( /// Attempt to read from the fromRadio mailbox, if data is found broadcast it to android apps private fun doReadFromRadio(firstRead: Boolean) { safe?.let { s -> - val fromRadio = getCharacteristic(BTM_FROMRADIO_CHARACTER) s.asyncReadCharacteristic(fromRadio) { try { val b = it.getOrThrow() @@ -357,6 +361,16 @@ class BluetoothInterface( fromNum = getCharacteristic(BTM_FROMNUM_CHARACTER) + // We changed UUIDs to be able to identify old firmware (<1.3.43) + fromRadio = if (bservice.characteristics.map { it.uuid } + .contains(EOL_FROMRADIO_CHARACTER)) { + invalidVersion = true + getCharacteristic(EOL_FROMRADIO_CHARACTER) + } else { + invalidVersion = false + getCharacteristic(BTM_FROMRADIO_CHARACTER) + } + // We treat the first send by a client as special isFirstSend = true diff --git a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt index dbb34d822..66de2ef58 100644 --- a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt +++ b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt @@ -1391,6 +1391,9 @@ class MeshService : Service(), Logging { configNonce += 1 newNodes.clear() newMyNodeInfo = null + + if (BluetoothInterface.invalidVersion) onHasSettings() // Device firmware is too old + debug("Starting config nonce=$configNonce") sendToRadio(ToRadio.newBuilder().apply { diff --git a/app/src/main/java/com/geeksville/mesh/ui/ChannelFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/ChannelFragment.kt index a04cbc066..5684be78a 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/ChannelFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/ChannelFragment.kt @@ -313,12 +313,12 @@ class ChannelFragment : ScreenFragment("Channel"), Logging { } // No matter what apply the speed selection from the user - val newLoRaConfig = loRaConfig { + val newLoRaConfig = model.config.lora.copy { usePreset = true modemPreset = newModemPreset - region = model.region - txEnabled = model.txEnabled - txPower = model.config.lora.txPower + bandwidth = 0 + spreadFactor = 0 + codingRate = 0 } val humanName = Channel(newSettings, newLoRaConfig).humanName diff --git a/app/src/test/java/com/geeksville/mesh/model/ChannelSetTest.kt b/app/src/test/java/com/geeksville/mesh/model/ChannelSetTest.kt index 524b23ff0..a70c0bbd8 100644 --- a/app/src/test/java/com/geeksville/mesh/model/ChannelSetTest.kt +++ b/app/src/test/java/com/geeksville/mesh/model/ChannelSetTest.kt @@ -8,7 +8,7 @@ class ChannelSetTest { /** make sure we match the python and device code behavior */ @Test fun matchPython() { - val url = Uri.parse("https://www.meshtastic.org/e/#CgUYAiIBAQ") + val url = Uri.parse("https://meshtastic.org/e/#CgUYAiIBAQ") val cs = ChannelSet(url) Assert.assertEquals("LongFast", cs.primaryChannel!!.name) Assert.assertEquals("#LongFast-K", cs.primaryChannel!!.humanName)