Работа с устройствами USB в Android
В недавней статье на Geektimes в комментариях возник вопрос о поддержке в ОС Android периферии, подключенной к шине USB. Действительно, большинство вендорского ПО, к примеру, для работы с принтерами и МФУ, поддерживает только подключение по сети. Однако это не означает, что в самой ОС Android нет такой возможности — это означает лишь то, что большинство устройств не имеют полноценного USB хоста, и далеко не все имеют поддержку OTG. По сети же могут работать абсолютно все без исключения.
Большинство устройств на Android при наличии порта OTG поддерживают на уровне системы (ядра Linux или стандартных компонентов Android) следующие классы устройств:
- Устройства ввода — клавиатуры, мыши, джойстики (HID)
- Накопители (Mass Storage)
Несколько реже:
- Сотовые модемы
- Сетевые адаптеры
- Вебкамеры
Хабы поддерживаются при наличии полноценных хост-портов, но не поддерживаются на портах OTG.
Подробнее список устройств, поддерживаемых на уровне ядра Linux, можно получить в sysfs:
$ ls /sys/bus/usb/drivers
Если же модуль в принципе доступен в исходниках ядра Linux, но не включен в Android — не стоит рассчитывать на то, что его получится собрать и расставить на все целевые системы.
Однако, начиная с Android 3.1 (API 12), в системе содержатся средства, достаточные для поддержки на уровне приложения любой USB периферии. Данные средства описаны в разделе USB Host руководства по Android API. Здесь же я хочу привести примеры реальной работы с некоторыми видами устройств.
Права доступа
Как и для прочих действий, Android требует, чтобы приложение получило разрешение на доступ к USB периферии. Существует 2 способа получить такое разрешение:
- Задекларировать список устройств в AndroidManifest
- Явно показать пользователю диалог “разрешить”
Поскольку для моих задач лишние вопросы к пользователю были нежелательны, я использовал первый способ.
Итак, нам необходимо добавить в манифест следующее:
А в res/xml/device_filter.xml вписать следующее:
Отмечу, что хотя общепринято указывать VID:PID в 16-ричной системе счисления, здесь они должны быть указаны в десятичной. В документации заявляется, что возможно указание только класса, без VID и PID, но у меня это не стало работать.
Принтеры
На примере принтера я покажу, как непосредственно использовать API android.hardware.usb. На уровне передачи данных все принтеры поддерживают стандартый класс USB устройств:
Класс предельно простой. В рамках этого класса устройство должно поддерживать:
- Обязательный bulk out endpoind для отправки данных на принтер
- Опциональный bulk in endpoind для получения статуса принтера
- 3 управляющих запроса
Код, приведенный ниже, предоставляет функциональность, аналогичную устройству /dev/usb/lp в Linux. Далее нам нужен фильтр, преобразующий исходный документ в пакет данных, понятный конкретной модели принтера. Но это тема иной статьи. Как один из вариантов — можно собрать ghostscript с помощью NDK.
Для работы с устройством нам в первую очередь нужно:
1. Найти устройство. В примере для простоты я ищу первый попавшийся:
2. Получить endpoint’ы:
3. Непосредсвенно открыть устройство:
4. После этого мы можем читать и писать в устройство:
5. По завершении работы — закрыть устройство:
Преобразователи USB-Serial
В отличие от притеров, преобразователи USB-Serial гораздо менее стандартизированы. Существует несколько распространенных чипов, для которых существенно отличается установка параметров последовательного порта — битрейта, чётности и проч. К счастью, есть библиотека github.com/mik3y/usb-serial-for-android, поддерживающая практически все существующие чипы. Библиотека полностью скрывает USB API, сводя все необходимые действия к минимуму вызовов с минимумом параметров.
1. Найти и открыть устройство:
2. Установить параметры последовательного порта:
3. Читать и писать в порт:
4. По завершении работы — закрыть порт:
Резюме
Надеюсь, что мне удалось показать, что работа с USB периферией достаточно проста и логична. Безусловно, реализация протоколов некоторых конкретных устройств не блещет простотой — но это проявится в любой системе в одинаковой степени.
Все приведенные примеры я взял из реального проекта, лишь исключил очевидные проверки, оставив только ключевые строки.
Источник
Android usb serial library
Copy raw contents
Copy raw contents
This is a driver library for communication with Arduinos and other USB serial hardware on Android, using the Android USB Host Mode (OTG) available since Android 3.1 and working reliably since Android 4.2.
No root access, ADK, or special kernel drivers are required; all drivers are implemented in Java. You get a raw serial port with read() , write() , and other functions for use with your own protocols.
1. Add library to your project:
Add jitpack.io repository to your root build.gradle:
Add library to dependencies
2. If the app should be notified when a device is attached, add device_filter.xml to your project’s res/xml/ directory and configure in your AndroidManifest.xml .
3. Use it! Example code snippet:
then use direct read/write
or direct write + event driven read:
For a simple example, see UsbSerialExamples folder in this project.
For a more complete example with background service to stay connected while the app is not visible or rotating, see separate github project SimpleUsbTerminal.
Probing for Unrecognized Devices
Sometimes you may need to do a little extra work to support devices which usb-serial-for-android doesn’t (yet) know about — but which you know to be compatible with one of the built-in drivers. This may be the case for a brand new device or for one using a custom VID/PID pair.
UsbSerialProber is a class to help you find and instantiate compatible UsbSerialDrivers from the tree of connected UsbDevices. Normally, you will use the default prober returned by UsbSerialProber.getDefaultProber() , which uses the built-in list of well-known VIDs and PIDs that are supported by our drivers.
To use your own set of rules, create and use a custom prober:
Of course, nothing requires you to use UsbSerialProber at all: you can instantiate driver classes directly if you know what you’re doing; just supply a compatible UsbDevice.
This library supports USB to serial converter chips:
- FTDI FT232R, FT232H, FT2232H, FT4232H, FT230X, FT231X, FT234XD
- Prolific PL2303
- Silabs CP2102 and all other CP210x
- Qinheng CH340, CH341A
and devices implementing the CDC/ACM protocol like
- Arduino using ATmega32U4
- Digispark using V-USB software USB
- BBC micro:bit using ARM mbed DAPLink firmware
- .
For common problems, see the FAQ wiki page.
Are you using the library? Add your project to ProjectsUsingUsbSerialForAndroid.
Источник
Android usb serial library
UsbSerial
UsbSerial wiki available. Read it first
CP210X devices Default: 9600,8,1,None,flow off
CDC devices Default 115200,8,1,None,flow off
FTDI devices Default: 9600,8,1,None,flow off
PL2303 devices Default 9600,8,1,None,flow off
CH34x devices Default 9600,8,1,None,flow off
Due to a bug in Android itself, it’s highly recommended to not use it with a device running Android 5.1.1 Lollipop. See issue #142 for more details.
Instantiate a new object of the UsbSerialDevice class
Open the device and set it up as desired
If flow control is needed (currently only supported in CP201x and FTDI devices)
There is no need to be polling if you want to perform a bulk transaction to a IN endpoint. Define a simply callback
And pass a reference of it
Changes in the CTS and DSR lines will be received in the same manner. Define a callback and pass a reference of it.
Raise the state of the RTS or DTR lines
Close the device:
I recommend using UsbSerial as shown above but if you want to perform write and read operations in synchronous way it is possible using these methods:
In Android usb api, when a usb device has been close it must be reopened
How to use the SPI interface (BETA)
Support for USB to SPI devices was added recently but it is still in beta. Although I tried to keep the api as close to standard UsbSerial api as possible, be aware because the beta nature of this feature this api may change in the future. Only CP2130 chipset is supported at the moment.
Источник
Android usb serial library
This is a driver library for communication with Arduinos and other USB serial hardware on Android, using the Android USB Host Mode (OTG) available since Android 3.1 and working reliably since Android 4.2.
No root access, ADK, or special kernel drivers are required; all drivers are implemented in Java. You get a raw serial port with read() , write() , and other functions for use with your own protocols.
1. Add library to your project:
Add jitpack.io repository to your root build.gradle:
Add library to dependencies
2. If the app should be notified when a device is attached, add device_filter.xml to your project’s res/xml/ directory and configure in your AndroidManifest.xml .
3. Use it! Example code snippet:
then use direct read/write
or direct write + event driven read:
For a simple example, see UsbSerialExamples folder in this project.
For a more complete example with background service to stay connected while the app is not visible or rotating, see separate github project SimpleUsbTerminal.
Probing for Unrecognized Devices
Sometimes you may need to do a little extra work to support devices which usb-serial-for-android doesn’t (yet) know about — but which you know to be compatible with one of the built-in drivers. This may be the case for a brand new device or for one using a custom VID/PID pair.
UsbSerialProber is a class to help you find and instantiate compatible UsbSerialDrivers from the tree of connected UsbDevices. Normally, you will use the default prober returned by UsbSerialProber.getDefaultProber() , which uses the built-in list of well-known VIDs and PIDs that are supported by our drivers.
To use your own set of rules, create and use a custom prober:
Of course, nothing requires you to use UsbSerialProber at all: you can instantiate driver classes directly if you know what you’re doing; just supply a compatible UsbDevice.
This library supports USB to serial converter chips:
- FTDI FT232R, FT232H, FT2232H, FT4232H, FT230X, FT231X, FT234XD
- Prolific PL2303
- Silabs CP2102 and all other CP210x
- Qinheng CH340, CH341A
and devices implementing the CDC/ACM protocol like
- Arduino using ATmega32U4
- Digispark using V-USB software USB
- BBC micro:bit using ARM mbed DAPLink firmware
- .
For common problems, see the FAQ wiki page.
Are you using the library? Add your project to ProjectsUsingUsbSerialForAndroid.
About
Android USB host serial driver library for CDC, FTDI, Arduino and other devices.
Источник
Android usb serial library
- Ch34x baud rate 921600 calculation
Assets
- restore FT2232C support that got lost with v3.0.0
Assets
- support PL2303GC/GB/GT/GL/GE/GS
- custom baud rates for PL2303TA/TB
- added VID 0x0483, PID 0x5740 to preconfigured CDC devices, as it is frequently used as STMicroelectronics virtual COM port
Assets
- new SerialInputOutputManager.start() method for starting ioManager thread
- Previously recommended start action Executors.newSingleThreadExecutor().submit(ioManager) did not shutdown the executor, which caused a thread leak.
Use new SerialInputOutputManager.start() method instead. It’s still possible to use old style start, as SerialInputOutputManager continues to implement Runnable interface. - read w/o timeout now only throws exception on connection lost. Reverted buffer to small handling from f4166f3, as there might be unkown reasons for empty response
Assets
- use optimal read buffer size in SerialInputOutputManager to reduce latency for FTDI and CH34x
- getReadEndpoint() and getWriteEndpoint() methods moved to UsbSerialPort interface
- read w/o timeout now throws exception on connection lost or buffer to small (when using SerialInputOutputManager the exception was already thrown before this change, because the next read failed)
- Use monotonic clock for timeout calculation, to avoid issues when time is adjusted
Assets
- new SerialTimeoutException class
- new getReadEndpoint() and getWriteEndpoint() methods in CommonUsbSerialPort class
- distinguish generic IO error and timeout in write()
- Return type of write() method changed to void. The return value was redundant before, as it was always the request length or an exception was thrown
- If timeout is reached, write() now throws a SerialTimeoutException with ex.bytesTransferred filled with known transferred bytes
- Optimal write buffer size can be set with port.setWriteBufferSize(port.getWriteEndpoint().getMaxPacketSize())
- By default the write buffer size is > MaxPacketSize and the Linux kernel splits writes in chunks. When the timeout occurs, it’s unknown how many chunks have already been transferred and 0 is returned in SerialTimeoutException.bytesTransferred . With optimal write buffer size, this value is known and returned in SerialTimeoutException.bytesTransferred as the chunking is done in this library, but due to more kernel round trips write() might take slightly longer and cause more CPU load
- introduced IntDef annotation @Parity at setParameters(. @Parity int parity) parameter for better warnings
- disable debug logging in SerialInputOutputManager by default. Can be enabled with public static boolean DEBUG;
- set thread priority in SerialInputOutputManager.run
- improve error handling in close
- Return type of write() method changed to void. The return value was redundant before, as it was always the request length or an exception was thrown
Assets
- support BREAK with setBreak(boolean) method
- fix PL2303 initial input control line values
Assets
- PL2303 support non-standard baud rates
Assets
- read with timeout now throws error on connection lost, e.g. device disconnected
- Prolific input control line methods now throw error on connection lost
- SerialInputOutputManager with configurable buffer size
- SerialInputOutputManager with configurable threadpriority and higher default to prevent data loss
- FTDI read now waits until timeout. previously returned after periodic FTDI status response (default 16 msec)
If you relied on this early return, you should adapt your timeout values
Assets
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Источник