Merge branch 'fix/espflasher-cancellable': cancellable flasher + dialog fixes + key exchange reliability

This commit is contained in:
eddy 2026-07-26 17:24:40 +02:00
commit a80abc5c0c
2 changed files with 27 additions and 7 deletions

View file

@ -25,7 +25,15 @@ class EspFlasher(private val context: Context) {
private val handler = Handler(Looper.getMainLooper()) private val handler = Handler(Looper.getMainLooper())
@Volatile
private var cancelled = false
fun cancel() {
cancelled = true
}
fun flashDevice(usbManager: UsbManager, device: UsbDevice, callback: FlashCallback) { fun flashDevice(usbManager: UsbManager, device: UsbDevice, callback: FlashCallback) {
cancelled = false
Thread { Thread {
try { try {
doFlash(usbManager, device, callback) doFlash(usbManager, device, callback)
@ -47,6 +55,7 @@ class EspFlasher(private val context: Context) {
private fun doFlash(usbManager: UsbManager, device: UsbDevice, callback: FlashCallback) { private fun doFlash(usbManager: UsbManager, device: UsbDevice, callback: FlashCallback) {
Thread.sleep(500) Thread.sleep(500)
if (cancelled) return
val connection = usbManager.openDevice(device) val connection = usbManager.openDevice(device)
?: throw IOException("Kan USB-apparaat niet openen") ?: throw IOException("Kan USB-apparaat niet openen")
@ -67,6 +76,7 @@ class EspFlasher(private val context: Context) {
postProgress(callback, 0, "Verbinden met ESP bootloader...") postProgress(callback, 0, "Verbinden met ESP bootloader...")
val transport = UsbSerialTransport(connection, epOut, epIn) val transport = UsbSerialTransport(connection, epOut, epIn)
if (cancelled) return
val assets = context.assets val assets = context.assets
val bootloader = assets.open("firmware/bootloader.bin").readBytes() val bootloader = assets.open("firmware/bootloader.bin").readBytes()
@ -107,6 +117,7 @@ class EspFlasher(private val context: Context) {
stub.eraseFlash() stub.eraseFlash()
for (step in steps) { for (step in steps) {
if (cancelled) return
val sizeStr = if (step.data.size > 1024) "${step.data.size / 1024}KB" else "${step.data.size} bytes" val sizeStr = if (step.data.size > 1024) "${step.data.size / 1024}KB" else "${step.data.size} bytes"
postProgress(callback, step.baseProgress, "${step.name} schrijven ($sizeStr)...") postProgress(callback, step.baseProgress, "${step.name} schrijven ($sizeStr)...")

View file

@ -43,6 +43,7 @@ class SettingsActivity : AppCompatActivity() {
private var currentAction = UsbAction.NONE private var currentAction = UsbAction.NONE
private var progressDialog: AlertDialog? = null private var progressDialog: AlertDialog? = null
private var dialog: AlertDialog? = null private var dialog: AlertDialog? = null
private var flasher: EspFlasher? = null
private val handler = Handler(Looper.getMainLooper()) private val handler = Handler(Looper.getMainLooper())
private val usbAttachedReceiver = object : BroadcastReceiver() { private val usbAttachedReceiver = object : BroadcastReceiver() {
@ -120,6 +121,8 @@ class SettingsActivity : AppCompatActivity() {
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
currentAction = UsbAction.NONE currentAction = UsbAction.NONE
flasher?.cancel()
flasher = null
try { unregisterReceiver(usbAttachedReceiver) } catch (e: Exception) {} try { unregisterReceiver(usbAttachedReceiver) } catch (e: Exception) {}
try { unregisterReceiver(usbPermissionReceiver) } catch (e: Exception) {} try { unregisterReceiver(usbPermissionReceiver) } catch (e: Exception) {}
try { unregisterReceiver(usbDetachedReceiver) } catch (e: Exception) {} try { unregisterReceiver(usbDetachedReceiver) } catch (e: Exception) {}
@ -166,11 +169,11 @@ class SettingsActivity : AppCompatActivity() {
finish() finish()
} }
is KeyResult.Error -> { is KeyResult.Error -> {
Toast.makeText(this, result.message, Toast.LENGTH_LONG).show() Toast.makeText(this, "Sleutel uitwisselen mislukt - probeer opnieuw", Toast.LENGTH_LONG).show()
cleanupAction() cleanupAction()
} }
null -> { null -> {
Toast.makeText(this, "Sleutel niet gevonden", Toast.LENGTH_SHORT).show() Toast.makeText(this, "Sleutel uitwisselen mislukt - probeer opnieuw", Toast.LENGTH_SHORT).show()
cleanupAction() cleanupAction()
} }
} }
@ -201,10 +204,12 @@ class SettingsActivity : AppCompatActivity() {
} }
private fun doFlashing(usbManager: UsbManager, device: UsbDevice) { private fun doFlashing(usbManager: UsbManager, device: UsbDevice) {
dialog?.dismiss()
dialog = null
showProgressDialog("Firmware Flashen", "Initialiseren...", STYLE_HORIZONTAL) showProgressDialog("Firmware Flashen", "Initialiseren...", STYLE_HORIZONTAL)
val flasher = EspFlasher(this) flasher = EspFlasher(this)
flasher.flashDevice(usbManager, device, object : EspFlasher.FlashCallback { flasher?.flashDevice(usbManager, device, object : EspFlasher.FlashCallback {
override fun onProgress(percent: Int, message: String) { override fun onProgress(percent: Int, message: String) {
runOnUiThread { runOnUiThread {
val d = progressDialog ?: return@runOnUiThread val d = progressDialog ?: return@runOnUiThread
@ -282,6 +287,10 @@ class SettingsActivity : AppCompatActivity() {
progressDialog = AlertDialog.Builder(this) progressDialog = AlertDialog.Builder(this)
.setTitle(title) .setTitle(title)
.setView(view) .setView(view)
.setNegativeButton("Annuleren") { _, _ ->
flasher?.cancel()
cleanupAction()
}
.setCancelable(false) .setCancelable(false)
.show() .show()
} }
@ -335,8 +344,8 @@ class SettingsActivity : AppCompatActivity() {
try { try {
setupCdcControl(connection, device) setupCdcControl(connection, device)
for (attempt in 1..3) { for (attempt in 1..5) {
Thread.sleep(500) Thread.sleep(1000L)
flushReadBuffer(connection, epIn) flushReadBuffer(connection, epIn)
@ -389,7 +398,7 @@ class SettingsActivity : AppCompatActivity() {
Log.w(TAG, "Attempt $attempt: no KEY response, retrying") Log.w(TAG, "Attempt $attempt: no KEY response, retrying")
} }
return KeyResult.Error("Geen sleutel gevonden na 3 pogingen") return KeyResult.Error("Geen sleutel gevonden na 5 pogingen")
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "Key exchange error", e) Log.e(TAG, "Key exchange error", e)
return KeyResult.Error("Fout: ${e.message}") return KeyResult.Error("Fout: ${e.message}")