diff --git a/app/src/main/java/com/geeksville/mesh/model/Channel.kt b/app/src/main/java/com/geeksville/mesh/model/Channel.kt index 745fe2853..cb8c5c1f8 100644 --- a/app/src/main/java/com/geeksville/mesh/model/Channel.kt +++ b/app/src/main/java/com/geeksville/mesh/model/Channel.kt @@ -8,7 +8,6 @@ import com.google.zxing.BarcodeFormat import com.google.zxing.MultiFormatWriter import com.journeyapps.barcodescanner.BarcodeEncoder import java.net.MalformedURLException -import kotlin.experimental.xor /** Utility function to make it easy to declare byte arrays - FIXME move someplace better */ fun byteArrayOfInts(vararg ints: Int) = ByteArray(ints.size) { pos -> ints[pos].toByte() } @@ -60,7 +59,7 @@ data class Channel( */ val humanName: String get() { - val code = settings.psk.fold(0.toByte(), { acc, x -> acc xor x }) + val code = settings.psk.fold(0, { acc, x -> acc xor (x.toInt() and 0xff) }) return "#${settings.name}-${'A' + (code % 26)}" } 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 eb256d149..d5582696d 100644 --- a/app/src/main/java/com/geeksville/mesh/service/BluetoothInterface.kt +++ b/app/src/main/java/com/geeksville/mesh/service/BluetoothInterface.kt @@ -176,7 +176,9 @@ class BluetoothInterface(val service: RadioInterfaceService, val address: String /// Our BLE device - val device get() = safe?.gatt ?: throw RadioNotConnectedException("No GATT") + val device + get() = (safe ?: throw RadioNotConnectedException("No SafeBluetooth")).gatt + ?: throw RadioNotConnectedException("No GATT") /// Our service - note - it is possible to get back a null response for getService if the device services haven't yet been found val bservice @@ -314,10 +316,15 @@ class BluetoothInterface(val service: RadioInterfaceService, val address: String fromNumChanged = true debug("fromNum changed") service.serviceScope.handledLaunch { - if (fromNumChanged) { - fromNumChanged = false - debug("fromNum changed, so we are reading new messages") - doReadFromRadio(false) + try { + if (fromNumChanged) { + fromNumChanged = false + debug("fromNum changed, so we are reading new messages") + doReadFromRadio(false) + } + } catch (e: RadioNotConnectedException) { + // Don't report autobugs for this, getting an exception here is expected behavior + errormsg("Ending FromNum read, radio not connected", e) } } } diff --git a/app/src/main/java/com/geeksville/mesh/service/SerialInterface.kt b/app/src/main/java/com/geeksville/mesh/service/SerialInterface.kt index 914708dbd..9637f8bf3 100644 --- a/app/src/main/java/com/geeksville/mesh/service/SerialInterface.kt +++ b/app/src/main/java/com/geeksville/mesh/service/SerialInterface.kt @@ -69,7 +69,7 @@ class SerialInterface(private val service: RadioInterfaceService, val address: S debug("A USB device was detached") val device: UsbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)!! if (uart?.device == device) - onDeviceDisconnect() + onDeviceDisconnect(true) } if (UsbManager.ACTION_USB_DEVICE_ATTACHED == intent.action) { @@ -78,7 +78,7 @@ class SerialInterface(private val service: RadioInterfaceService, val address: S val manager = context.getSystemService(Context.USB_SERVICE) as UsbManager if (assumePermission || manager.hasPermission(device)) { // reinit the port from scratch and reopen - onDeviceDisconnect() + onDeviceDisconnect(true) connect() } else { warn("We don't have permissions for this USB device") @@ -109,21 +109,41 @@ class SerialInterface(private val service: RadioInterfaceService, val address: S override fun close() { debug("Closing serial port for good") service.unregisterReceiver(usbReceiver) - onDeviceDisconnect() + onDeviceDisconnect(true) } - /** Tell MeshService our device has gone away, but wait for it to come back */ - fun onDeviceDisconnect() { - debug("USB device disconnected, but it might come back") + /** Tell MeshService our device has gone away, but wait for it to come back + * + * @param waitForStopped if true we should wait for the manager to finish - must be false if called from inside the manager callbacks + * */ + fun onDeviceDisconnect(waitForStopped: Boolean) { + ignoreException { + ioManager?.let { + debug("USB device disconnected, but it might come back") + it.stop() + + // Allow a short amount of time for the manager to quit (so the port can be cleanly closed) + if (waitForStopped) { + val msecSleep = 50L + var numTries = 1000 / msecSleep + while (it.state != SerialInputOutputManager.State.STOPPED && numTries > 0) { + debug("Waiting for USB manager to stop...") + Thread.sleep(msecSleep) + numTries -= 1 + } + } + + ioManager = null + } + } - ignoreException { ioManager?.let { it.stop() } } - ioManager = null ignoreException { uart?.apply { ports[0].close() // This will cause the reader thread to exit + + uart = null } } - uart = null service.onDisconnect(isPermanent = true) // if USB device disconnects it is definitely permantently gone, not sleeping) } @@ -134,7 +154,8 @@ class SerialInterface(private val service: RadioInterfaceService, val address: S if (device != null) { info("Opening $device") - val connection = manager.openDevice(device.device) + val connection = + manager.openDevice(device.device) // This can fail with "Control Transfer failed" if port was aleady open if (connection == null) { // FIXME add UsbManager.requestPermission(device, ..) handling to activity errormsg("Need permissions for port") @@ -256,9 +277,8 @@ class SerialInterface(private val service: RadioInterfaceService, val address: S */ override fun onRunError(e: java.lang.Exception) { errormsg("Serial error: $e") - // FIXME - try to reconnect to the device when it comes back - onDeviceDisconnect() + onDeviceDisconnect(false) } /** diff --git a/app/src/main/java/com/geeksville/mesh/service/SoftwareUpdateService.kt b/app/src/main/java/com/geeksville/mesh/service/SoftwareUpdateService.kt index 9bf8e843b..6a132e20c 100644 --- a/app/src/main/java/com/geeksville/mesh/service/SoftwareUpdateService.kt +++ b/app/src/main/java/com/geeksville/mesh/service/SoftwareUpdateService.kt @@ -9,7 +9,6 @@ import androidx.core.app.JobIntentService import com.geeksville.android.Logging import com.geeksville.mesh.MainActivity import com.geeksville.mesh.R -import com.geeksville.util.Exceptions import com.geeksville.util.exceptionReporter import java.util.* import java.util.zip.CRC32 @@ -208,7 +207,7 @@ class SoftwareUpdateService : JobIntentService(), Logging { (curVer > deviceVersion) && (deviceVersion >= minVer) // true } catch (ex: Exception) { - Exceptions.report(ex, "Error finding swupdate info") + errormsg("Error finding swupdate info", ex) false // If we fail parsing our update info }