-
Notifications
You must be signed in to change notification settings - Fork 1.6k
This is a collection of FAQ-style troubleshooting tips.
Check with an App that uses this library and shows all USB devices, e.g. Serial USB Terminal. The Serial Example app in this project is not sufficient, as it does not show devices where no driver is detected.
If still no USB device is shown, check the web for USB Host Mode aka. USB OTG support for your Android device. Missing support is more likely for older devices.
For an incomplete list of Android devices with known issues look here.
The library includes a list of USB vendor and device ID's (VID/PID) that are typically used by the supported chips. In case of unusual ID's, use a Custom Prober or specify a fixed driver.
Non USB-to-Serial devices like mass-storage, mouse, GPC receivers, ... and rarely used USB-to-Serial chips including Hoitek HE2325U and FTDI FT312D are not supported.
A common issue is wrong baud rate.
Not all drivers / devices support non-standard baud rates. See Feature Matrix for details.
Most Arduinos with CDC driver use the DTR line to determine serial channel readiness. In your Android code, call setDTR(true);
You don't. /dev/tty*
is the Linux kernel's driver interface to various serial devices. Certain devices and custom ROMs may expose serial devices this way, but this library does not use this interface.
You can connect to multiple devices and to multiple ports of a multi-port device in one App.
- When connecting to different ports in a multi-port device, each connection needs it's own
UsbDeviceConnection
, else the firstclose
will also close all other ports. - Distinguishing identical devices has some challenges:
- Use devices with different VIDs/PIDs or devices where it can be programmed like FTDI or CP210x .
- Use
UsbDevice.getSerialNumber()
and devices that come with a unique serial or devices where it can be programmed like FTDI or CP210x.
Note: Starting with Android 10, the serial number is only accessible after device access permission has been granted. - Using
UsbDevice.getDeviceName()
orUsbDevice.getDeviceId()
is not an option as the numbers increase when re-attaching a device.
The protocol layer does not guarantee that all bytes will arrive in a single message. In fact the protocol layer doesn't have any knowledge of what your "message" is — it is just an interface for sending a serial stream of bytes.
To reduce the number of USB requests, devices usually buffer data until some size or idle time is reached. Therefore request sizes heavily depend on the device type and actual data transfer pattern.
For example, to receive a 100 byte string, you might read 64 bytes, then 36 bytes, instead of a single message of 100 bytes. You need to account for this problem when designing your protocol. Some common techniques:
- Fixed length messages: If you a message is always going to be 100 bytes, just keep reading until you have all 100.
- Length-prefixed messages: Prefix every message with a fixed-length
size
value; your message is complete after you've readsize
more bytes. - Newline-terminated messages: Read until you see a
\n
(or any other "terminal" character).
Android is not a real time OS. The thread responsible for receiving data might not be scheduled by the OS or garbage collection might be ongoing or … Therefore data loss can happen for continues read at high baud rates. If data is lost, typically some smaller fragments in the middle of the data are missing.
This effect is more likely for slower Android device and USB devices with smaller buffer size and typically starts with higher baud rates like 115k2 baud, but is hardly predictable. For low baud rates or non-continuous transfers this issue was not observed as the USB device will not run into a read buffer overflow before the next USB read transfer.
Using a higher thread priority (default for SerialInputOutputManager
since usb-serial-for-android v3.1.0) and offloading work from onNewData
to other threads can mitigates the issue.
Data loss can also occur with inappropriate buffer size, as shown in next Question.
USB data transfers have a fixed packet size which is 64 for most devices. You can get the respective size with port.getReadEndpoint().getMaxPacketSize()
, and it's recommended to use it as buffer size.
A smaller buffer size is ok, as long as the received messages fits into the buffer. If it doesn't fit into the buffer, read
returns an empty result. Due to poor error propagation in Android USB code, this cannot be distinguished from timeout or real communication errors.
A larger buffer size can make your app lagging. In particular FTDI devices tend to queue data until the buffer is completely filled on continous transfer at higher baud rates. This can be mitigated by choosing appropriate buffer size and setting the latency timer as also recommended by FTDI.
When using smaller buffer sizes with FTDI devices, you have to take into account that each response starts with 2 header bytes. The header bytes will be stripped from the final result.
read
timeout should not be shorter then 200 to 500 milliseconds, if possible use infinite timeout.
-
read
with infinite timeout blocks until data is available, so it should be avoided in the UI thread, instead useSerialInputOutputManager
to be notified on new data. -
read
with timeout is typically used in the UI thread, if you send a request and know that there is a timely response and the blocking time is acceptable.
write
timeout should typically be significantly larger than the required send time.
-
write
with short timeout is ok, if you useport.getReadEndpoint().getMaxPacketSize()
as buffer size and resend the remaining data after getting aSerialTimeoutException
. With larger buffer size, the packeting is done in the Linux kernel which returns -1 instead of the written size, so there is no chance to resume writing.
It's typically not.
Write consists of 2 phases:
- from android to usb device
- from usb device to serial port
Waiting for write completion is typically done with application specific protocols, like request-response pattern.
If your framework can import Java .jar files, look here for instructions about creating a .jar file.
Basic Features are supported by all drivers / devices
Method / Feature | Supported |
---|---|
open , close
|
🟢 |
setParameters
|
🟢 |
read , write
|
🟢 |
event based read with SerialInputOutputManager
|
🟢 |
Some Features are not supported by all drivers / devices
Feature | FTDI | CH34x | CP210x | PL2303 | CDC |
---|---|---|---|---|---|
setParameters with non-standard baud rates
|
🟢 | 🟢 |
🟢 for CP2105 🔴 for CP2102. fallback to unknown baud rate without exception |
🟢 | 🟢 |
set BREAK condition | 🟢 | 🟢 |
🟢 for CP2102, CP2105 first port 🔴 for CP2105 second port. resends last byte without exception |
🟢 | 🟢 |
set/get flow control lines RTS, CTS, DTR, DSR, CD, RI | 🟢 | 🟢 | 🟢 | 🟢 | 🟡 only output lines RTS, DTR |
purgeHwBuffers
|
🟢 | 🔴 | 🟢 | 🟢 | 🟢 |
multi port devices | 🟢 | n.a. | 🟢 | n.a. | 🟢 |
device specific methods |
get/setLatencyTimer
|
- | - | - | - |
Some Features are not implemented (yet)
Feature | Supported |
---|---|
flow control (RTS/CTS or DTS/DTR or XON/XOFF based flow control) | 🔴 |