diff --git a/android/app/src/main/java/com/eddy/atomrelay/MainActivity.kt b/android/app/src/main/java/com/eddy/atomrelay/MainActivity.kt index 74dce13..edf1543 100644 --- a/android/app/src/main/java/com/eddy/atomrelay/MainActivity.kt +++ b/android/app/src/main/java/com/eddy/atomrelay/MainActivity.kt @@ -43,6 +43,9 @@ class MainActivity : AppCompatActivity() { private const val HMAC_LEN = 32 private const val REQUEST_SETTINGS = 1 private const val SCAN_TIMEOUT_MS = 10000L + private const val RECONNECT_DELAY_MS = 2000L + private const val POST_SETTINGS_RESCAN_MS = 500L + private const val ON_RESUME_SCAN_DELAY_MS = 300L } private var bluetoothGatt: BluetoothGatt? = null @@ -92,7 +95,7 @@ class MainActivity : AppCompatActivity() { bluetoothGatt = null relayCharacteristic = null seq = 1 - handler.postDelayed(scanRunnable, 2000) + handler.postDelayed(scanRunnable, RECONNECT_DELAY_MS) } } @@ -170,7 +173,7 @@ class MainActivity : AppCompatActivity() { relayCharacteristic = null seq = 1 loadState() - handler.postDelayed(scanRunnable, 500) + handler.postDelayed(scanRunnable, POST_SETTINGS_RESCAN_MS) } } @@ -186,7 +189,7 @@ class MainActivity : AppCompatActivity() { if (hmacKey == null) { statusText.text = getString(R.string.status_no_key) } else if (!isScanning && bluetoothGatt == null) { - handler.postDelayed(scanRunnable, 300) + handler.postDelayed(scanRunnable, ON_RESUME_SCAN_DELAY_MS) } } diff --git a/android/app/src/main/java/com/eddy/atomrelay/SettingsActivity.kt b/android/app/src/main/java/com/eddy/atomrelay/SettingsActivity.kt index 9ea18b5..7ba86a8 100644 --- a/android/app/src/main/java/com/eddy/atomrelay/SettingsActivity.kt +++ b/android/app/src/main/java/com/eddy/atomrelay/SettingsActivity.kt @@ -44,6 +44,9 @@ class SettingsActivity : AppCompatActivity() { private const val KEY_SETTLE_MS = 1000L private const val RESPONSE_WAIT_MS = 500L private const val USB_BULK_TIMEOUT_MS = 1000 + private const val FLUSH_TIMEOUT_MS = 100 + private const val READ_CHUNK_TIMEOUT_MS = 500 + private const val CDC_CONTROL_TIMEOUT_MS = 500 private const val ACTION_USB_PERMISSION = "com.eddy.atomrelay.USB_PERMISSION" private const val STYLE_SPINNER = 0 private const val STYLE_HORIZONTAL = 1 @@ -472,7 +475,7 @@ class SettingsActivity : AppCompatActivity() { private fun flushReadBuffer(connection: UsbDeviceConnection, epIn: UsbEndpoint) { val buf = ByteArray(512) while (true) { - val len = connection.bulkTransfer(epIn, buf, buf.size, 100) + val len = connection.bulkTransfer(epIn, buf, buf.size, FLUSH_TIMEOUT_MS) if (len <= 0) break Log.d(TAG, "Flushed $len bytes from read buffer") } @@ -484,7 +487,7 @@ class SettingsActivity : AppCompatActivity() { val startTime = System.currentTimeMillis() while (System.currentTimeMillis() - startTime < timeoutMs) { - val len = connection.bulkTransfer(epIn, buf, buf.size, 500) + val len = connection.bulkTransfer(epIn, buf, buf.size, READ_CHUNK_TIMEOUT_MS) if (len > 0) { sb.append(String(buf, 0, len, StandardCharsets.US_ASCII)) if ((sb.contains("HMAC_KEY:") || sb.contains("NO_KEY") || sb.contains("OK")) && sb.contains("\n")) { @@ -506,8 +509,24 @@ class SettingsActivity : AppCompatActivity() { 0x00.toByte(), 0xC2.toByte(), 0x01.toByte(), 0x00.toByte(), 0x00.toByte(), 0x00.toByte(), 0x08.toByte() ) - connection.controlTransfer(0x21, 0x20, 0, ctrlIntf.id, lineCoding, lineCoding.size, 500) - connection.controlTransfer(0x21, 0x22, 3, ctrlIntf.id, null, 0, 500) + connection.controlTransfer( + UsbUtils.CDC_REQUEST_TYPE, + UsbUtils.CDC_SET_LINE_CODING, + 0, + ctrlIntf.id, + lineCoding, + lineCoding.size, + CDC_CONTROL_TIMEOUT_MS + ) + connection.controlTransfer( + UsbUtils.CDC_REQUEST_TYPE, + UsbUtils.CDC_SET_CONTROL_LINE_STATE, + UsbUtils.CDC_DTR or UsbUtils.CDC_RTS, + ctrlIntf.id, + null, + 0, + CDC_CONTROL_TIMEOUT_MS + ) Log.d(TAG, "CDC control interface configured") } else { Log.w(TAG, "No CDC control interface found, trying without") diff --git a/android/app/src/main/java/com/eddy/atomrelay/UsbSerialTransport.kt b/android/app/src/main/java/com/eddy/atomrelay/UsbSerialTransport.kt index 96e718c..2513822 100644 --- a/android/app/src/main/java/com/eddy/atomrelay/UsbSerialTransport.kt +++ b/android/app/src/main/java/com/eddy/atomrelay/UsbSerialTransport.kt @@ -15,6 +15,7 @@ class UsbSerialTransport( companion object { private const val USB_TIMEOUT_MS = 5000 + private const val CONTROL_LINE_TIMEOUT_MS = 1000 } override fun read(buffer: ByteArray, length: Int): Int { @@ -31,12 +32,12 @@ class UsbSerialTransport( override fun setControlLines(dtr: Boolean, rts: Boolean) { connection.controlTransfer( UsbConstants.USB_DIR_OUT or UsbConstants.USB_TYPE_CLASS or 0x01, - 0x22, - (if (dtr) 0x01 else 0x00) or (if (rts) 0x02 else 0x00), + UsbUtils.CDC_SET_CONTROL_LINE_STATE, + (if (dtr) UsbUtils.CDC_DTR else 0x00) or (if (rts) UsbUtils.CDC_RTS else 0x00), 0, null, 0, - 1000 + CONTROL_LINE_TIMEOUT_MS ) } diff --git a/android/app/src/main/java/com/eddy/atomrelay/UsbUtils.kt b/android/app/src/main/java/com/eddy/atomrelay/UsbUtils.kt index 5ec1f01..56e5836 100644 --- a/android/app/src/main/java/com/eddy/atomrelay/UsbUtils.kt +++ b/android/app/src/main/java/com/eddy/atomrelay/UsbUtils.kt @@ -9,6 +9,13 @@ import android.hardware.usb.UsbInterface object UsbUtils { private const val CDC_DATA_INTERFACE_CLASS = 0x0A + // CDC-ACM class-specific control request constants (USB CDC 1.20 spec) + const val CDC_REQUEST_TYPE = 0x21 + const val CDC_SET_LINE_CODING = 0x20 + const val CDC_SET_CONTROL_LINE_STATE = 0x22 + const val CDC_DTR = 0x01 + const val CDC_RTS = 0x02 + fun findCdcDataInterface(device: UsbDevice): UsbInterface? { for (i in 0 until device.interfaceCount) { val intf = device.getInterface(i) @@ -28,4 +35,4 @@ object UsbUtils { } return null } -} +} \ No newline at end of file