Робота з пристроями на LibUsb з-під Android

Як то-одного разу мені знадобилося, щоб один прилад, який управлявся через USB з десктопної програми, також міг управлятися через Android додаток. Особливість була в тому, що не використовувалися HID, CDC та інші стандартні класи пристроїв. Передача даних здійснювалася через Bulk transfer і кінцеві точки. В основі роботи з usb лежала бібліотека libusb.

Зробимо тестове додаток, за допомогою якого можна буде передати і отримати довільні дані з приладу.

Я торкнуся ключові моменти, а посилання на повний код буде в кінці.

Для початку діємо згідно офіційній документації для роботи з UsbHost.
В маніфест додаємо рядок

<uses-feature android:name="android.hardware.usb.host"/>

Якщо ми хочемо, щоб пристрій автоматично визначався і запускалося додаток, тоді в маніфесті для головної актівіті пишемо наступне.

<intent-filter>
 <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter"/>

Вказуємо для нашого пристрою його VID і PID у файлі з ресурсами device_filter.xml

<resources>
<usb-device
product id="0037"
vendor id="8742"/>
</resources>

Usb менеджер ми отримуємо в методі onCreate.

mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);

Далі отримуємо список підключених до USB-пристроїв, і серед них шукаємо потрібну нам пристрій класу USB_CLASS_PER_INTERFACE.

UsbDevice findDevice(UsbManager usbManager) {
 for (UsbDevice usbDevice : usbManager.getDeviceList().values()) {
 if (usbDevice.getDeviceClass() == UsbConstants.USB_CLASS_PER_INTERFACE) {
 return usbDevice;
 } else {
 UsbInterface usbInterface = findInterface(usbDevice);
 if (usbInterface != null) return usbDevice;
}
}
 return null;
}

UsbInterface findInterface(UsbDevice usbDevice) {
 for (int nIf = 0; nIf < usbDevice.getInterfaceCount(); nIf++) {
 UsbInterface usbInterface = usbDevice.getInterface(nIf);
 if (usbInterface.getInterfaceClass() == 
 UsbConstants.USB_CLASS_PER_INTERFACE) {
 return usbInterface;
}
}
 return null;
}

Далі ми знаходимо потрібний нам інтерфейс, не забуваємо перевірити дозволи, перебираємо всі його контрольні точки, серед них вибираємо точки на читання і запис і, нарешті, підключаємося.

private void initUsbDevice() {
 PendingIntent mPermissionIntent = 
 PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);

 IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
 registerReceiver(mUsbReceiver, filter);
 mUsbManager.requestPermission(mUsbDevice, mPermissionIntent);

 mUsbInterface = findInterface(mUsbDevice);

 for (int nEp = 0; nEp < mUsbInterface.getEndpointCount(); nEp++) {
 UsbEndpoint tmpEndpoint = mUsbInterface.getEndpoint(nEp);
 if (tmpEndpoint.getType() != UsbConstants.USB_ENDPOINT_XFER_BULK) 
continue;
 if ((mOutEndpoint == null)
 && (tmpEndpoint.getDirection() == UsbConstants.USB_DIR_OUT)) {
 mOutEndpoint = tmpEndpoint;
 } else if ((mInEndpoint == null)
 && (tmpEndpoint.getDirection() == UsbConstants.USB_DIR_IN)) {
 mInEndpoint = tmpEndpoint;
}
}
 if (mOutEndpoint == null) {
 Toast.makeText(this, "no endpoints", Toast.LENGTH_LONG).show();
}
 mConnection = mUsbManager.openDevice(mUsbDevice);
 if (mConnection == null) {
 Toast.makeText(this, "can't open device", Toast.LENGTH_SHORT).show();
return;
}
 mConnection.claimInterface(mUsbInterface, true);
startIoManager();
}

Для роботи з операціями вводу-виводу, буферизації даних, асинхронності та інших зручних речей використовується допоміжний клас-менеджер, але по суті обмін даними зводиться до наступного коду.

Читайте також  FreeMarker шаблони

Читання:

mConnection.bulkTransfer(mInEndpoint, data, size, READ_TIMEOUT);

Запис:

int bytesWritten = mConnection.bulkTransfer(mOutEndpoint,
 Arrays.copyOfRange(data, offset, offset + size), size, WRITE_TIMEOUT);

Таким чином передаються і приймаються BulkTransfer пакети.

В результаті наше просте додаток може передавати і приймати довільні дані.

Працює!

Степан Лютий

Обожнюю технології в сучасному світі. Хоча частенько і замислююся над тим, як далеко вони нас заведуть. Не те, щоб я прям і знаюся на ядрах, пікселях, коллайдерах і інших парсеках. Просто приходжу в захват від того, що може в творчому пориві вигадати людський розум.

You may also like...

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *