Move all user-facing strings to strings.xml, add user-facing-text.md reference
This commit is contained in:
parent
5fb67fdcf0
commit
c46db32cc7
6 changed files with 195 additions and 55 deletions
|
|
@ -39,7 +39,7 @@ class EspFlasher(private val context: Context) {
|
|||
}
|
||||
|
||||
private class FlashStep(
|
||||
val name: String,
|
||||
val nameResId: Int,
|
||||
val address: Int,
|
||||
val data: ByteArray,
|
||||
val baseProgress: Int,
|
||||
|
|
@ -52,22 +52,22 @@ class EspFlasher(private val context: Context) {
|
|||
coroutineContext.ensureActive()
|
||||
|
||||
val connection = usbManager.openDevice(device)
|
||||
?: throw IOException("Kan USB-apparaat niet openen")
|
||||
?: throw IOException(context.getString(R.string.err_usb_open))
|
||||
|
||||
try {
|
||||
val intf = UsbUtils.findCdcDataInterface(device)
|
||||
?: throw IOException("Geen CDC data interface gevonden")
|
||||
?: throw IOException(context.getString(R.string.err_no_cdc))
|
||||
|
||||
if (!connection.claimInterface(intf, true)) {
|
||||
throw IOException("Kan USB interface niet claimen")
|
||||
throw IOException(context.getString(R.string.err_usb_claim))
|
||||
}
|
||||
|
||||
val epOut = UsbUtils.findBulkEndpoint(intf, UsbConstants.USB_DIR_OUT)
|
||||
?: throw IOException("Geen USB OUT endpoint gevonden")
|
||||
?: throw IOException(context.getString(R.string.err_no_out))
|
||||
val epIn = UsbUtils.findBulkEndpoint(intf, UsbConstants.USB_DIR_IN)
|
||||
?: throw IOException("Geen USB IN endpoint gevonden")
|
||||
?: throw IOException(context.getString(R.string.err_no_in))
|
||||
|
||||
callback.onProgress(0, "Verbinden met ESP bootloader...")
|
||||
callback.onProgress(0, context.getString(R.string.flash_connecting))
|
||||
|
||||
val transport = UsbSerialTransport(connection, epOut, epIn)
|
||||
coroutineContext.ensureActive()
|
||||
|
|
@ -78,20 +78,14 @@ class EspFlasher(private val context: Context) {
|
|||
val bootApp0 = assets.open("firmware/boot_app0.bin").readBytes()
|
||||
val firmware = assets.open("firmware/firmware.bin").readBytes()
|
||||
|
||||
// Flash sectie layout (partition table check):
|
||||
// NVS 0x9000-0xDFFF — NIET overschreven (key/UUID blijft behouden)
|
||||
// otadata 0xE000-0xFFFF — overschreven door boot_app0
|
||||
// app0 0x10000-... — firmware overschrijft
|
||||
// Alleen schrijven naar benodigde adressen, geen full erase
|
||||
|
||||
val steps = listOf(
|
||||
FlashStep("Bootloader", 0x0, bootloader, 30, 10, false),
|
||||
FlashStep("Partitie tabel", 0x8000, partitions, 40, 10, false),
|
||||
FlashStep("Boot app0", 0xe000, bootApp0, 50, 10, false),
|
||||
FlashStep("Firmware", 0x10000, firmware, 60, 35, true)
|
||||
FlashStep(R.string.flash_step_bootloader, 0x0, bootloader, 30, 10, false),
|
||||
FlashStep(R.string.flash_step_partitions, 0x8000, partitions, 40, 10, false),
|
||||
FlashStep(R.string.flash_step_boot_app0, 0xe000, bootApp0, 50, 10, false),
|
||||
FlashStep(R.string.flash_step_firmware, 0x10000, firmware, 60, 35, true)
|
||||
)
|
||||
|
||||
callback.onProgress(5, "Sync met bootloader...")
|
||||
callback.onProgress(5, context.getString(R.string.flash_sync))
|
||||
val api = EspFlasherApi.connect(transport)
|
||||
.withCallBack(object : ProgressCallback {
|
||||
override fun onProgress(pct: Float) {
|
||||
|
|
@ -102,31 +96,32 @@ class EspFlasher(private val context: Context) {
|
|||
}
|
||||
})
|
||||
|
||||
callback.onProgress(10, "Chip detecteren...")
|
||||
callback.onProgress(10, context.getString(R.string.flash_detect))
|
||||
val detected = api.chipDetect()
|
||||
val chipId = detected.getChipId()
|
||||
Log.i(TAG, "Detected chip: $chipId")
|
||||
callback.onProgress(15, "Chip: ${chipId.readableName}")
|
||||
callback.onProgress(15, context.getString(R.string.flash_chip, chipId.readableName))
|
||||
|
||||
callback.onProgress(20, "Stub laden...")
|
||||
callback.onProgress(20, context.getString(R.string.flash_stub))
|
||||
val stub = detected.loadStub()
|
||||
|
||||
for (step in steps) {
|
||||
coroutineContext.ensureActive()
|
||||
val stepName = context.getString(step.nameResId)
|
||||
val sizeStr = if (step.data.size > 1024) "${step.data.size / 1024}KB" else "${step.data.size} bytes"
|
||||
callback.onProgress(step.baseProgress, "${step.name} schrijven ($sizeStr)...")
|
||||
callback.onProgress(step.baseProgress, "$stepName schrijven ($sizeStr)...")
|
||||
|
||||
val writeStub = if (step.compress) stub.withCompression(true) else stub.withCompression(false)
|
||||
writeStub.writeFlash(step.address, step.data)
|
||||
|
||||
val endProgress = step.baseProgress + step.range
|
||||
callback.onProgress(endProgress.coerceAtMost(95), "${step.name} geschreven")
|
||||
callback.onProgress(endProgress.coerceAtMost(95), "$stepName geschreven")
|
||||
}
|
||||
|
||||
callback.onProgress(95, "ESP resetten...")
|
||||
stub.reset()
|
||||
|
||||
callback.onProgress(100, "Firmware geflashed!")
|
||||
callback.onProgress(100, context.getString(R.string.flash_done))
|
||||
} finally {
|
||||
connection.close()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -278,7 +278,8 @@ class SettingsActivity : AppCompatActivity() {
|
|||
showConflictDialog(usbManager, device, result.espUuid, result.espKey, appKey ?: "")
|
||||
}
|
||||
is KeyResult.Error -> {
|
||||
Toast.makeText(this@SettingsActivity, getString(R.string.key_exchange_failed), Toast.LENGTH_LONG).show()
|
||||
val msg = if (result.arg != null) getString(result.resId, result.arg!!) else getString(result.resId)
|
||||
Toast.makeText(this@SettingsActivity, msg, Toast.LENGTH_LONG).show()
|
||||
cleanupAction()
|
||||
}
|
||||
null -> {
|
||||
|
|
@ -431,25 +432,25 @@ class SettingsActivity : AppCompatActivity() {
|
|||
sealed class KeyResult {
|
||||
data class Success(val deviceUuid: String, val hexKey: String) : KeyResult()
|
||||
data class Conflict(val espUuid: String, val espKey: String) : KeyResult()
|
||||
data class Error(val message: String) : KeyResult()
|
||||
data class Error(val resId: Int, val arg: String? = null) : KeyResult()
|
||||
}
|
||||
|
||||
private fun readKeyFromEsp(usbManager: UsbManager, device: UsbDevice, appUuid: String?, appKey: String?): KeyResult? {
|
||||
val intf = UsbUtils.findCdcDataInterface(device)
|
||||
?: return KeyResult.Error("Geen CDC interface gevonden")
|
||||
?: return KeyResult.Error(R.string.err_no_cdc)
|
||||
|
||||
val connection = usbManager.openDevice(device)
|
||||
?: return KeyResult.Error("Kan USB apparaat niet openen")
|
||||
?: return KeyResult.Error(R.string.err_usb_open)
|
||||
|
||||
if (!connection.claimInterface(intf, true)) {
|
||||
connection.close()
|
||||
return KeyResult.Error("Kan USB interface niet claimen")
|
||||
return KeyResult.Error(R.string.err_usb_claim)
|
||||
}
|
||||
|
||||
val epOut = UsbUtils.findBulkEndpoint(intf, UsbConstants.USB_DIR_OUT)
|
||||
?: run { connection.close(); return KeyResult.Error("Geen USB OUT endpoint gevonden") }
|
||||
?: run { connection.close(); return KeyResult.Error(R.string.err_no_out) }
|
||||
val epIn = UsbUtils.findBulkEndpoint(intf, UsbConstants.USB_DIR_IN)
|
||||
?: run { connection.close(); return KeyResult.Error("Geen USB IN endpoint gevonden") }
|
||||
?: run { connection.close(); return KeyResult.Error(R.string.err_no_in) }
|
||||
|
||||
try {
|
||||
setupCdcControl(connection, device)
|
||||
|
|
@ -489,7 +490,7 @@ class SettingsActivity : AppCompatActivity() {
|
|||
}
|
||||
return KeyResult.Success(espUuidUpper, espKeyUpper)
|
||||
} else {
|
||||
return KeyResult.Error("Ongeldig sleutel/UUID formaat")
|
||||
return KeyResult.Error(R.string.err_invalid_key)
|
||||
}
|
||||
} else if (noKey) {
|
||||
val newKey: String
|
||||
|
|
@ -508,7 +509,7 @@ class SettingsActivity : AppCompatActivity() {
|
|||
val w = connection.bulkTransfer(epOut, setKeyCmd, setKeyCmd.size, USB_BULK_TIMEOUT_MS)
|
||||
Log.d(TAG, "Sent SET_KEY ($w bytes)")
|
||||
if (w < 0) {
|
||||
return KeyResult.Error("SET_KEY schrijven mislukt")
|
||||
return KeyResult.Error(R.string.err_set_key_write)
|
||||
}
|
||||
|
||||
Thread.sleep(RESPONSE_WAIT_MS)
|
||||
|
|
@ -516,14 +517,14 @@ class SettingsActivity : AppCompatActivity() {
|
|||
Log.d(TAG, "SET_KEY response: ${okKeyResponse.take(200)}")
|
||||
|
||||
if (!okKeyResponse.contains("OK")) {
|
||||
return KeyResult.Error("ESP bevestigde sleutel niet")
|
||||
return KeyResult.Error(R.string.err_key_not_ack)
|
||||
}
|
||||
|
||||
val setIdCmd = "SET_ID:$newUuid\n".toByteArray(StandardCharsets.US_ASCII)
|
||||
val w2 = connection.bulkTransfer(epOut, setIdCmd, setIdCmd.size, USB_BULK_TIMEOUT_MS)
|
||||
Log.d(TAG, "Sent SET_ID ($w2 bytes)")
|
||||
if (w2 < 0) {
|
||||
return KeyResult.Error("SET_ID schrijven mislukt")
|
||||
return KeyResult.Error(R.string.err_set_id_write)
|
||||
}
|
||||
|
||||
Thread.sleep(RESPONSE_WAIT_MS)
|
||||
|
|
@ -533,17 +534,17 @@ class SettingsActivity : AppCompatActivity() {
|
|||
if (okUuidResponse.contains("OK")) {
|
||||
return KeyResult.Success(newUuid, newKey)
|
||||
} else {
|
||||
return KeyResult.Error("ESP bevestigde UUID niet")
|
||||
return KeyResult.Error(R.string.err_uuid_not_ack)
|
||||
}
|
||||
}
|
||||
|
||||
Log.w(TAG, "Attempt $attempt: no KEY response, retrying")
|
||||
}
|
||||
|
||||
return KeyResult.Error("Geen sleutel gevonden na 5 pogingen")
|
||||
return KeyResult.Error(R.string.err_key_retries)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Key exchange error", e)
|
||||
return KeyResult.Error("Fout: ${e.message}")
|
||||
return KeyResult.Error(R.string.err_generic, e.message)
|
||||
} finally {
|
||||
try { connection.close() } catch (_: Exception) {}
|
||||
}
|
||||
|
|
@ -692,7 +693,8 @@ class SettingsActivity : AppCompatActivity() {
|
|||
finish()
|
||||
}
|
||||
is KeyResult.Error -> {
|
||||
Toast.makeText(this@SettingsActivity, result.message, Toast.LENGTH_LONG).show()
|
||||
val msg = if (result.arg != null) getString(result.resId, result.arg!!) else getString(result.resId)
|
||||
Toast.makeText(this@SettingsActivity, msg, Toast.LENGTH_LONG).show()
|
||||
cleanupAction()
|
||||
}
|
||||
else -> {
|
||||
|
|
@ -707,20 +709,20 @@ class SettingsActivity : AppCompatActivity() {
|
|||
private fun writeKeysToEsp(usbManager: UsbManager, device: UsbDevice,
|
||||
appKey: String, appUuid: String): KeyResult? {
|
||||
val intf = UsbUtils.findCdcDataInterface(device)
|
||||
?: return KeyResult.Error("Geen CDC interface gevonden")
|
||||
?: return KeyResult.Error(R.string.err_no_cdc)
|
||||
|
||||
val connection = usbManager.openDevice(device)
|
||||
?: return KeyResult.Error("Kan USB apparaat niet openen")
|
||||
?: return KeyResult.Error(R.string.err_usb_open)
|
||||
|
||||
if (!connection.claimInterface(intf, true)) {
|
||||
connection.close()
|
||||
return KeyResult.Error("Kan USB interface niet claimen")
|
||||
return KeyResult.Error(R.string.err_usb_claim)
|
||||
}
|
||||
|
||||
val epOut = UsbUtils.findBulkEndpoint(intf, UsbConstants.USB_DIR_OUT)
|
||||
?: run { connection.close(); return KeyResult.Error("Geen USB OUT endpoint gevonden") }
|
||||
?: run { connection.close(); return KeyResult.Error(R.string.err_no_out) }
|
||||
val epIn = UsbUtils.findBulkEndpoint(intf, UsbConstants.USB_DIR_IN)
|
||||
?: run { connection.close(); return KeyResult.Error("Geen USB IN endpoint gevonden") }
|
||||
?: run { connection.close(); return KeyResult.Error(R.string.err_no_in) }
|
||||
|
||||
try {
|
||||
setupCdcControl(connection, device)
|
||||
|
|
@ -729,20 +731,20 @@ class SettingsActivity : AppCompatActivity() {
|
|||
|
||||
val setKeyCmd = "SET_KEY:$appKey\n".toByteArray(StandardCharsets.US_ASCII)
|
||||
val w = connection.bulkTransfer(epOut, setKeyCmd, setKeyCmd.size, USB_BULK_TIMEOUT_MS)
|
||||
if (w < 0) return KeyResult.Error("SET_KEY schrijven mislukt")
|
||||
if (w < 0) return KeyResult.Error(R.string.err_set_key_write)
|
||||
Log.d(TAG, "Sent SET_KEY ($w bytes)")
|
||||
|
||||
Thread.sleep(RESPONSE_WAIT_MS)
|
||||
val okKeyResponse = readResponse(connection, epIn, SET_KEY_TIMEOUT_MS)
|
||||
if (!okKeyResponse.contains("OK")) return KeyResult.Error("ESP bevestigde sleutel niet")
|
||||
if (!okKeyResponse.contains("OK")) return KeyResult.Error(R.string.err_key_not_ack)
|
||||
|
||||
val setIdCmd = "SET_ID:$appUuid\n".toByteArray(StandardCharsets.US_ASCII)
|
||||
val w2 = connection.bulkTransfer(epOut, setIdCmd, setIdCmd.size, USB_BULK_TIMEOUT_MS)
|
||||
if (w2 < 0) return KeyResult.Error("SET_ID schrijven mislukt")
|
||||
if (w2 < 0) return KeyResult.Error(R.string.err_set_id_write)
|
||||
|
||||
Thread.sleep(RESPONSE_WAIT_MS)
|
||||
val okUuidResponse = readResponse(connection, epIn, SET_KEY_TIMEOUT_MS)
|
||||
if (!okUuidResponse.contains("OK")) return KeyResult.Error("ESP bevestigde UUID niet")
|
||||
if (!okUuidResponse.contains("OK")) return KeyResult.Error(R.string.err_uuid_not_ack)
|
||||
|
||||
val prefs = PrefsHelper.getPrefs(this)
|
||||
prefs.edit()
|
||||
|
|
@ -752,7 +754,7 @@ class SettingsActivity : AppCompatActivity() {
|
|||
return KeyResult.Success(appUuid, appKey)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Write keys error", e)
|
||||
return KeyResult.Error("Fout: ${e.message}")
|
||||
return KeyResult.Error(R.string.err_generic, e.message)
|
||||
} finally {
|
||||
try { connection.close() } catch (_: Exception) {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
android:layout_gravity="end|top"
|
||||
android:src="@drawable/ic_settings"
|
||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="Instellingen" />
|
||||
android:contentDescription="@string/cd_settings" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
|
|
@ -46,7 +46,7 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|start"
|
||||
android:text="Disconnected"
|
||||
android:text="@string/status_default"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</FrameLayout>
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sluit de ESP aan op USB en kies een actie."
|
||||
android:text="@string/msg_settings_intro"
|
||||
android:textSize="16sp"
|
||||
android:layout_marginBottom="24dp" />
|
||||
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
android:id="@+id/exchangeKeyButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sleutel Uitwisselen" />
|
||||
android:text="@string/button_key_exchange" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
|
|
@ -28,7 +28,7 @@
|
|||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Zet de ESP in download-modus (houd reset 2s in tot de groene LED aangaat) en tik op 'Firmware Flashen'."
|
||||
android:text="@string/msg_flash_mode_help"
|
||||
android:textSize="14sp"
|
||||
android:layout_marginBottom="16dp" />
|
||||
|
||||
|
|
@ -36,7 +36,7 @@
|
|||
android:id="@+id/flashFirmwareButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Firmware Flashen" />
|
||||
android:text="@string/button_firmware_flash" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
<string name="settings">Instellingen</string>
|
||||
|
||||
<!-- MainActivity status -->
|
||||
<string name="status_default">Disconnected</string>
|
||||
<string name="status_discovering_services">Verbonden, services zoeken…</string>
|
||||
<string name="status_connecting">Verbinden…</string>
|
||||
<string name="status_connected">Connected</string>
|
||||
|
|
@ -19,11 +20,16 @@
|
|||
<string name="button_retry_scan">Opnieuw scannen</string>
|
||||
|
||||
<!-- MainActivity UI -->
|
||||
<string name="cd_settings">Instellingen</string>
|
||||
<string name="button_on">ON</string>
|
||||
<string name="button_hold">HOLD</string>
|
||||
|
||||
<!-- SettingsActivity -->
|
||||
<string name="title_settings">Instellingen</string>
|
||||
<string name="msg_settings_intro">Sluit de ESP aan op USB en kies een actie.</string>
|
||||
<string name="button_key_exchange">Sleutel Uitwisselen</string>
|
||||
<string name="msg_flash_mode_help">Zet de ESP in download-modus (houd reset 2s in tot de groene LED aangaat) en tik op Firmware Flashen.</string>
|
||||
<string name="button_firmware_flash">Firmware Flashen</string>
|
||||
<string name="build_number">Buildnummer: %s</string>
|
||||
<string name="usb_access_denied">USB-toegang geweigerd</string>
|
||||
<string name="key_read_success">Beveiligingssleutel gelezen</string>
|
||||
|
|
@ -55,6 +61,32 @@
|
|||
<string name="button_close">Sluiten</string>
|
||||
<string name="button_cancel">Annuleren</string>
|
||||
|
||||
<!-- SettingsActivity error messages -->
|
||||
<string name="err_no_cdc">Geen CDC interface gevonden</string>
|
||||
<string name="err_usb_open">Kan USB apparaat niet openen</string>
|
||||
<string name="err_usb_claim">Kan USB interface niet claimen</string>
|
||||
<string name="err_no_out">Geen USB OUT endpoint gevonden</string>
|
||||
<string name="err_no_in">Geen USB IN endpoint gevonden</string>
|
||||
<string name="err_invalid_key">Ongeldig sleutel/UUID formaat</string>
|
||||
<string name="err_key_retries">Geen sleutel gevonden na 5 pogingen</string>
|
||||
<string name="err_generic">Fout: %s</string>
|
||||
<string name="err_set_key_write">SET_KEY schrijven mislukt</string>
|
||||
<string name="err_set_id_write">SET_ID schrijven mislukt</string>
|
||||
<string name="err_key_not_ack">ESP bevestigde sleutel niet</string>
|
||||
<string name="err_uuid_not_ack">ESP bevestigde UUID niet</string>
|
||||
|
||||
<!-- EspFlasher -->
|
||||
<string name="flash_connecting">Verbinden met ESP bootloader…</string>
|
||||
<string name="flash_step_bootloader">Bootloader</string>
|
||||
<string name="flash_step_partitions">Partitie tabel</string>
|
||||
<string name="flash_step_boot_app0">Boot app0</string>
|
||||
<string name="flash_step_firmware">Firmware</string>
|
||||
<string name="flash_sync">Sync met bootloader…</string>
|
||||
<string name="flash_detect">Chip detecteren…</string>
|
||||
<string name="flash_chip">Chip: %s</string>
|
||||
<string name="flash_stub">Stub laden…</string>
|
||||
<string name="flash_done">Firmware geflashed!</string>
|
||||
|
||||
<!-- Label customization -->
|
||||
<string name="section_labels">Knoptekst</string>
|
||||
<string name="hint_label_relay1">Relay 1</string>
|
||||
|
|
|
|||
Loading…
Reference in a new issue