I am using Odroid N2+ board for transmitting and receiving data from UART and turning GPIO ON and OFF. The GPIO part is working alright. When I put the code for transmitting only, there was no problem. But when I put code to receive , the app crashes.
The logcat error I get says
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)
I looked at Uart callback implementation, Handler implementation and HandlerThread implementation and they all look fine but I can't see the source of the problem.
Is there some implementation or somethings that I am missing here ? It looks like UartDeviceCallback is not recognized.
My implementation is as follows:
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)
}
}
Upon looking at the implementation of UartDeviceCallback, the window open with message on top.
I chose Download Sources but nothing happened. I am missing any files/libraries over here ?
I solved the problem using Runnable Interface to read the Uart data.
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
}
}
In the above code,
bind.peripheralMsg.text = cat
display received data in UI.
In the main program, in onCreate function, I did as follows:
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)
}