Replace magic numbers with named constants, move remaining hardcoded strings to strings.xml
This commit is contained in:
parent
c46db32cc7
commit
106bd25e41
6 changed files with 32 additions and 15 deletions
|
|
@ -5,7 +5,8 @@
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30"/>
|
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30"/>
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
|
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
|
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
|
||||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:maxSdkVersion="30" />
|
||||||
|
|
||||||
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
|
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
|
||||||
<uses-feature android:name="android.hardware.usb.host" android:required="false"/>
|
<uses-feature android:name="android.hardware.usb.host" android:required="false"/>
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ class BleRelayManager(
|
||||||
private const val MAX_SCAN_RETRIES = 3
|
private const val MAX_SCAN_RETRIES = 3
|
||||||
private const val HMAC_PKT_SIZE = 37
|
private const val HMAC_PKT_SIZE = 37
|
||||||
private const val HMAC_LEN = 32
|
private const val HMAC_LEN = 32
|
||||||
|
private const val BLE_MTU = 256
|
||||||
}
|
}
|
||||||
|
|
||||||
private var bluetoothGatt: BluetoothGatt? = null
|
private var bluetoothGatt: BluetoothGatt? = null
|
||||||
|
|
@ -55,6 +56,7 @@ class BleRelayManager(
|
||||||
private val scanRunnable = Runnable { startScan() }
|
private val scanRunnable = Runnable { startScan() }
|
||||||
private var scanTimeoutRunnable: Runnable? = null
|
private var scanTimeoutRunnable: Runnable? = null
|
||||||
|
|
||||||
|
@SuppressLint("MissingPermission")
|
||||||
private val scanCallback = object : ScanCallback() {
|
private val scanCallback = object : ScanCallback() {
|
||||||
override fun onScanResult(callbackType: Int, result: ScanResult) {
|
override fun onScanResult(callbackType: Int, result: ScanResult) {
|
||||||
val device = result.device ?: return
|
val device = result.device ?: return
|
||||||
|
|
@ -139,6 +141,7 @@ class BleRelayManager(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("MissingPermission")
|
||||||
fun destroy() {
|
fun destroy() {
|
||||||
handler.removeCallbacksAndMessages(null)
|
handler.removeCallbacksAndMessages(null)
|
||||||
stopScan()
|
stopScan()
|
||||||
|
|
@ -220,7 +223,7 @@ class BleRelayManager(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
Log.d(TAG, "Services discovered, requesting MTU...")
|
Log.d(TAG, "Services discovered, requesting MTU...")
|
||||||
gatt.requestMtu(256)
|
gatt.requestMtu(BLE_MTU)
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("MissingPermission")
|
@SuppressLint("MissingPermission")
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,10 @@ class EspFlasher(private val context: Context) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "EspFlasher"
|
private const val TAG = "EspFlasher"
|
||||||
|
private const val USB_SETTLE_MS = 500L
|
||||||
|
private const val KB = 1024
|
||||||
|
private const val FLASH_RESET_PCT = 95
|
||||||
|
private const val FLASH_DONE_PCT = 100
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FlashCallback {
|
interface FlashCallback {
|
||||||
|
|
@ -48,7 +52,7 @@ class EspFlasher(private val context: Context) {
|
||||||
)
|
)
|
||||||
|
|
||||||
private suspend fun doFlash(usbManager: UsbManager, device: UsbDevice, callback: FlashCallback) {
|
private suspend fun doFlash(usbManager: UsbManager, device: UsbDevice, callback: FlashCallback) {
|
||||||
kotlinx.coroutines.delay(500)
|
kotlinx.coroutines.delay(USB_SETTLE_MS)
|
||||||
coroutineContext.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
|
|
||||||
val connection = usbManager.openDevice(device)
|
val connection = usbManager.openDevice(device)
|
||||||
|
|
@ -108,20 +112,20 @@ class EspFlasher(private val context: Context) {
|
||||||
for (step in steps) {
|
for (step in steps) {
|
||||||
coroutineContext.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
val stepName = context.getString(step.nameResId)
|
val stepName = context.getString(step.nameResId)
|
||||||
val sizeStr = if (step.data.size > 1024) "${step.data.size / 1024}KB" else "${step.data.size} bytes"
|
val sizeStr = if (step.data.size > KB) "${step.data.size / KB}KB" else "${step.data.size} bytes"
|
||||||
callback.onProgress(step.baseProgress, "$stepName schrijven ($sizeStr)...")
|
callback.onProgress(step.baseProgress, context.getString(R.string.flash_writing, stepName, sizeStr))
|
||||||
|
|
||||||
val writeStub = if (step.compress) stub.withCompression(true) else stub.withCompression(false)
|
val writeStub = if (step.compress) stub.withCompression(true) else stub.withCompression(false)
|
||||||
writeStub.writeFlash(step.address, step.data)
|
writeStub.writeFlash(step.address, step.data)
|
||||||
|
|
||||||
val endProgress = step.baseProgress + step.range
|
val endProgress = step.baseProgress + step.range
|
||||||
callback.onProgress(endProgress.coerceAtMost(95), "$stepName geschreven")
|
callback.onProgress(endProgress.coerceAtMost(FLASH_RESET_PCT), context.getString(R.string.flash_written, stepName))
|
||||||
}
|
}
|
||||||
|
|
||||||
callback.onProgress(95, "ESP resetten...")
|
callback.onProgress(FLASH_RESET_PCT, context.getString(R.string.flash_resetting))
|
||||||
stub.reset()
|
stub.reset()
|
||||||
|
|
||||||
callback.onProgress(100, context.getString(R.string.flash_done))
|
callback.onProgress(FLASH_DONE_PCT, context.getString(R.string.flash_done))
|
||||||
} finally {
|
} finally {
|
||||||
connection.close()
|
connection.close()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,11 @@ class SettingsActivity : AppCompatActivity() {
|
||||||
private const val ACTION_USB_PERMISSION = "com.eddy.atomrelay.USB_PERMISSION"
|
private const val ACTION_USB_PERMISSION = "com.eddy.atomrelay.USB_PERMISSION"
|
||||||
private const val STYLE_SPINNER = 0
|
private const val STYLE_SPINNER = 0
|
||||||
private const val STYLE_HORIZONTAL = 1
|
private const val STYLE_HORIZONTAL = 1
|
||||||
|
private const val USB_READ_BUF_SIZE = 512
|
||||||
|
private const val HMAC_HEX_LEN = 64
|
||||||
|
private const val UUID_HEX_LEN = 32
|
||||||
|
private const val UUID_BYTE_COUNT = 16
|
||||||
|
private const val HMAC_BYTE_COUNT = 32
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum class UsbAction { NONE, EXCHANGE_KEY, FLASH }
|
private enum class UsbAction { NONE, EXCHANGE_KEY, FLASH }
|
||||||
|
|
@ -480,8 +485,8 @@ class SettingsActivity : AppCompatActivity() {
|
||||||
if (keyLine != null && uuidLine != null) {
|
if (keyLine != null && uuidLine != null) {
|
||||||
val hexKey = keyLine.removePrefix("HMAC_KEY:").trim()
|
val hexKey = keyLine.removePrefix("HMAC_KEY:").trim()
|
||||||
val hexUuid = uuidLine.removePrefix("DEVICE_ID:").trim()
|
val hexUuid = uuidLine.removePrefix("DEVICE_ID:").trim()
|
||||||
if (hexKey.length == 64 && hexKey.all { it in "0123456789ABCDEFabcdef" } &&
|
if (hexKey.length == HMAC_HEX_LEN && hexKey.all { it in "0123456789ABCDEFabcdef" } &&
|
||||||
hexUuid.length == 32 && hexUuid.all { it in "0123456789ABCDEFabcdef" }) {
|
hexUuid.length == UUID_HEX_LEN && hexUuid.all { it in "0123456789ABCDEFabcdef" }) {
|
||||||
val espKeyUpper = hexKey.uppercase()
|
val espKeyUpper = hexKey.uppercase()
|
||||||
val espUuidUpper = hexUuid.uppercase()
|
val espUuidUpper = hexUuid.uppercase()
|
||||||
if (appUuid != null && appKey != null &&
|
if (appUuid != null && appKey != null &&
|
||||||
|
|
@ -502,7 +507,7 @@ class SettingsActivity : AppCompatActivity() {
|
||||||
} else {
|
} else {
|
||||||
Log.d(TAG, "Both have no keys, generating new pair")
|
Log.d(TAG, "Both have no keys, generating new pair")
|
||||||
newKey = generateRandomHexKey()
|
newKey = generateRandomHexKey()
|
||||||
newUuid = generateRandomHex(16)
|
newUuid = generateRandomHex(UUID_BYTE_COUNT)
|
||||||
}
|
}
|
||||||
|
|
||||||
val setKeyCmd = "SET_KEY:$newKey\n".toByteArray(StandardCharsets.US_ASCII)
|
val setKeyCmd = "SET_KEY:$newKey\n".toByteArray(StandardCharsets.US_ASCII)
|
||||||
|
|
@ -551,7 +556,7 @@ class SettingsActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun flushReadBuffer(connection: UsbDeviceConnection, epIn: UsbEndpoint) {
|
private fun flushReadBuffer(connection: UsbDeviceConnection, epIn: UsbEndpoint) {
|
||||||
val buf = ByteArray(512)
|
val buf = ByteArray(USB_READ_BUF_SIZE)
|
||||||
while (true) {
|
while (true) {
|
||||||
val len = connection.bulkTransfer(epIn, buf, buf.size, FLUSH_TIMEOUT_MS)
|
val len = connection.bulkTransfer(epIn, buf, buf.size, FLUSH_TIMEOUT_MS)
|
||||||
if (len <= 0) break
|
if (len <= 0) break
|
||||||
|
|
@ -560,7 +565,7 @@ class SettingsActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun readResponse(connection: UsbDeviceConnection, epIn: UsbEndpoint, timeoutMs: Long): String {
|
private fun readResponse(connection: UsbDeviceConnection, epIn: UsbEndpoint, timeoutMs: Long): String {
|
||||||
val buf = ByteArray(512)
|
val buf = ByteArray(USB_READ_BUF_SIZE)
|
||||||
val sb = StringBuilder()
|
val sb = StringBuilder()
|
||||||
val startTime = System.currentTimeMillis()
|
val startTime = System.currentTimeMillis()
|
||||||
|
|
||||||
|
|
@ -613,7 +618,7 @@ class SettingsActivity : AppCompatActivity() {
|
||||||
|
|
||||||
private fun generateRandomHexKey(): String {
|
private fun generateRandomHexKey(): String {
|
||||||
val random = SecureRandom()
|
val random = SecureRandom()
|
||||||
val bytes = ByteArray(32)
|
val bytes = ByteArray(HMAC_BYTE_COUNT)
|
||||||
random.nextBytes(bytes)
|
random.nextBytes(bytes)
|
||||||
return bytes.joinToString("") { "%02X".format(it) }
|
return bytes.joinToString("") { "%02X".format(it) }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ class UsbSerialTransport(
|
||||||
companion object {
|
companion object {
|
||||||
private const val USB_TIMEOUT_MS = 5000
|
private const val USB_TIMEOUT_MS = 5000
|
||||||
private const val CONTROL_LINE_TIMEOUT_MS = 1000
|
private const val CONTROL_LINE_TIMEOUT_MS = 1000
|
||||||
|
private const val MIN_USB_PACKET = 64
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun read(buffer: ByteArray, length: Int): Int {
|
override fun read(buffer: ByteArray, length: Int): Int {
|
||||||
|
|
@ -42,6 +43,6 @@ class UsbSerialTransport(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun readBufferSize(): Int {
|
override fun readBufferSize(): Int {
|
||||||
return epIn.maxPacketSize.coerceAtLeast(64)
|
return epIn.maxPacketSize.coerceAtLeast(MIN_USB_PACKET)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -86,6 +86,9 @@
|
||||||
<string name="flash_chip">Chip: %s</string>
|
<string name="flash_chip">Chip: %s</string>
|
||||||
<string name="flash_stub">Stub laden…</string>
|
<string name="flash_stub">Stub laden…</string>
|
||||||
<string name="flash_done">Firmware geflashed!</string>
|
<string name="flash_done">Firmware geflashed!</string>
|
||||||
|
<string name="flash_writing">%s schrijven (%s)…</string>
|
||||||
|
<string name="flash_written">%s geschreven</string>
|
||||||
|
<string name="flash_resetting">ESP resetten…</string>
|
||||||
|
|
||||||
<!-- Label customization -->
|
<!-- Label customization -->
|
||||||
<string name="section_labels">Knoptekst</string>
|
<string name="section_labels">Knoptekst</string>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue