Android Things Uart 中的 Uart 回调问题

Problem in Uart callback in Android Things Uart

我正在使用 Odroid N2+ 板从 UART 发送和接收数据以及打开和关闭 GPIO。 GPIO 部分工作正常。当我只输入传输代码时,没有问题。但是,当我将代码用于接收时,应用程序崩溃了。

我得到的 logcat 错误说

2021-04-14 15:50:47.623 5127-5127/com.example.androidthings E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.androidthings, PID: 5127
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.androidthings/com.example.androidthings.MainActivity}: java.io.IOException: Uart Callback feature is not implemented
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2951)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3086)
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1816)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:193)
    at android.app.ActivityThread.main(ActivityThread.java:6718)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
 Caused by: java.io.IOException: Uart Callback feature is not implemented
    at com.google.android.things.pio.impl.UartImpl.registerUartDeviceCallback(UartImpl.java:261)
    at com.example.androidthings.MainActivity.onCreate(MainActivity.kt:85)
    at android.app.Activity.performCreate(Activity.java:7144)
    at android.app.Activity.performCreate(Activity.java:7135)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2931)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3086) 
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78) 
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108) 
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1816) 
    at android.os.Handler.dispatchMessage(Handler.java:106) 
    at android.os.Looper.loop(Looper.java:193) 
    at android.app.ActivityThread.main(ActivityThread.java:6718) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) 

我查看了 Uart 回调实现、Handler 实现和 HandlerThread 实现,它们看起来都很好,但我看不出问题的根源。

是否有一些实现或我在这里缺少的东西?看起来 UartDeviceCallback 无法识别。

我的实现如下:

class MainActivity : AppCompatActivity() 
{
    val TAG = "PeripActivity"
    private lateinit var bind: ActivityMainBinding
    private lateinit var gpio: Gpio
    private lateinit var gpioList: List<String>
    private lateinit var uart: UartDevice
    lateinit var inputThread: HandlerThread
    lateinit var handler: Handler
    private lateinit var pManager: PeripheralManager
    val maxCount = 128

    private val uartDeviceCallback: UartDeviceCallback = object: UartDeviceCallback {
        override fun onUartDeviceDataAvailable(uart: UartDevice): Boolean {
            // Loop until there is no more data in the RX buffer.
            transferUartData()
            // Continue listening for more interrupts
            return true
        }

        override fun onUartDeviceError(uart: UartDevice?, error: Int) {
            Log.w(TAG, "$uart: Error event $error")
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        bind = ActivityMainBinding.inflate(layoutInflater)
        setContentView(bind.root)

        pManager = PeripheralManager.getInstance()
        gpioList = pManager.gpioList
        gpio = pManager.openGpio(gpioList[0]).apply {
            setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW)
        }

        var uartlist = pManager.uartDeviceList
        for(item in uartlist)
            Log.d(TAG, "Uarts: $item\n")

        inputThread = HandlerThread("InputThread")
        inputThread.start()
        handler = Handler(inputThread.looper)

        uart = openUart(uartlist[0], 115200)
        uart.registerUartDeviceCallback(handler, uartDeviceCallback)
        // Read any initially buffered data
        handler.post { transferUartData() }

        bind.gpioSwitch.setOnCheckedChangeListener { _, isChecked ->
            if (isChecked) {
                Toast.makeText(this, "GPIO HIGH", Toast.LENGTH_SHORT).show()
                gpio.value = true
            }
            else {
                Toast.makeText(this, "GPIO LOW", Toast.LENGTH_SHORT).show()
                gpio.value = false
            }
        }
        bind.btnUart.setOnClickListener {
            writeUartData("Odroid says hello\n");
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.d(TAG, "Loopback Destroyed")

        // Terminate the worker thread
        inputThread.quitSafely()

        // Attempt to close the UART device
        uart.unregisterUartDeviceCallback(uartDeviceCallback)
        uart.close()
    }

    private fun writeUartData(str: String){
        val bytes = str.toByteArray()
        val count = uart.write(bytes, bytes.size)
        Log.d(TAG, "Wrote $count bytes to peripheral")
        Toast.makeText(this, "message send : $str", Toast.LENGTH_SHORT).show()
    }
    private fun openUart(name: String, baudRate: Int): UartDevice {
        return pManager.openUartDevice(name).apply {
            // Configure the UART
            setBaudrate(baudRate)
            setDataSize(8)
            setParity(UartDevice.PARITY_NONE)
            setStopBits(1)
        }
    }
    private fun transferUartData() {
        // Loop until there is no more data in the RX buffer.
        val buffer = ByteArray(maxCount)
        do {
            val read = uart.read(buffer, buffer.size)
            if (read > 0) {
                Log.w(TAG, "received data:\n${buffer}")
            }
        } while (read > 0)
    }
}

查看 UartDeviceCallback 的实现后,window 打开并在顶部显示消息。

我选择了下载源,但没有任何反应。 我在这里遗漏了任何 files/libraries ?

我使用 Runnable Interface 读取 Uart 数据解决了这个问题。

private lateinit var handler: Handler
private lateinit var rThread: Thread
private lateinit var eRunnable: ExampleRunnable

inner class ExampleRunnable (pUart: UartDevice): Runnable{
    val maxlen = 128
    var inneruart = pUart
    val TAG = "Uart_Activity"

    @Volatile var threadRunning = true;

    override fun run(){
        Log.d(TAG, "Uart receive start")
        while(threadRunning){
            readUart()
        }
    }

    private fun readUart() {
        // Loop until there is no more data in the RX buffer.
        val buffer = ByteArray(maxlen)
        do {
            val read = inneruart.read(buffer, buffer.size)
            if (read > 0) {
                val sub = buffer.copyOfRange(0,read)
                var readString = String(sub)
                Log.w("Uart_Activity", "received data bytes ($read):\n${readString}")
                handler.post(object : Runnable{
                    override fun run() {
                        var cat:String = bind.peripheralMsg.text.toString() + readString
                        bind.peripheralMsg.text = cat
                    }

                })
            }
        } while (read > 0)
    }

    fun setRunning(state: Boolean){
        threadRunning = state
    }
}

在上面的代码中,

bind.peripheralMsg.text = cat

在UI中显示接收到的数据。

在主程序的onCreate函数中,我做了如下操作:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    // Other stuffs

    handler = Handler(Looper.getMainLooper())
    eRunnable = ExampleRunnable(uart)
    rThread = Thread(eRunnable)
    rThread.start()

    // Other stuffs

}

override fun onStop() {
    super.onStop()
    eRunnable.setRunning(false)
}