Travailler avec des appareils LibUsb sous Android

Un jour, j'avais besoin d'un appareil contrôlé via USB à partir d'un programme de bureau pour être également contrôlé via une application Android. La particularité était que HID, CDC et d'autres classes de périphériques standard n'étaient pas utilisés. Le transfert de données a été effectué via le transfert en masse et les points finaux. La base du travail avec usb était la bibliothèque libusb.

Nous allons créer une application de test avec laquelle il sera possible de transférer et de recevoir des données arbitraires de l'appareil.

Je vais aborder les points clés et le lien vers le code complet sera à la fin.

Pour commencer, nous agissons conformément à la documentation officielle pour travailler avec UsbHost.
Ajouter une ligne au manifeste

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

Si nous voulons que l'appareil soit automatiquement détecté et que l'application démarre, alors dans le manifeste de l'activité principale, nous écrivons ce qui suit.

 <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"/> 

Spécifiez pour notre appareil son VID et son PID dans le fichier avec les ressources device_filter.xml

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

Nous obtenons le gestionnaire USB dans la méthode onCreate.

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

Ensuite, nous obtenons une liste des périphériques connectés à USB, et parmi eux, nous recherchons un périphérique de la classe USB_CLASS_PER_INTERFACE dont nous avons besoin.

 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; } 

Ensuite, nous trouvons l'interface dont nous avons besoin, n'oubliez pas de vérifier les autorisations, nous trions tous ses points de contrôle, parmi eux nous sélectionnons les points de lecture et d'écriture, et enfin nous connectons.

 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(); } 

Pour travailler avec les E / S, la mise en mémoire tampon des données, l'asynchronie et d'autres choses pratiques, une classe de gestionnaire auxiliaire est utilisée, mais essentiellement, l'échange de données est réduit au code suivant.

Lecture:

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

Record:

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

De cette façon, les paquets BulkTransfer sont transmis et reçus.

En conséquence, notre application simple peut transmettre et recevoir des données arbitraires.





Ça marche!

Le projet de cette application de test sur GitHub

Liens utiles:

  1. Bibliothèque pour travailler avec FT232 et d'autres appareils CDC sur Android.
  2. La documentation Android officielle pour travailler avec UsbHost.

Source: https://habr.com/ru/post/fr426697/


All Articles