Forum Programmation.c++ Test de communication avec un device USB en utilisant libusb

Posté par . Licence CC by-sa
1
30
avr.
2015

Bonsoir tout le monde,

J'ai un device USB dont lsusb me renvoit la description suivante (c'est long, je suis désolé):

Bus 001 Device 004: ID 0fde:0105  
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               1.10
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0         8
  idVendor           0x0fde 
  idProduct          0x0105 
  bcdDevice            1.00
  iManufacturer           0 
  iProduct                2 Tenx Nonstandard Device
  iSerial                 0 
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           59
    bNumInterfaces          2
    bConfigurationValue     1
    iConfiguration          0 
    bmAttributes         0x80
      (Bus Powered)
    MaxPower              100mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      0 No Subclass
      bInterfaceProtocol      0 None
      iInterface              0 
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.10
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength      41
         Report Descriptors: 
           ** UNAVAILABLE **
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval               1
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        1
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      0 No Subclass
      bInterfaceProtocol      0 None
      iInterface              0 
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.10
          bCountryCode           33 US
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength      23
          Report Descriptor: (length is 23)
            Item(Global): Usage Page, data= [ 0x01 ] 1
                            Generic Desktop Controls
            Item(Local ): Usage, data= [ 0x03 ] 3
                            (null)
            Item(Main  ): Collection, data= [ 0x01 ] 1
                            Application
            Item(Global): Logical Minimum, data= [ 0x00 ] 0
            Item(Global): Logical Maximum, data= [ 0x01 ] 1
            Item(Global): Report Count, data= [ 0x40 ] 64
            Item(Global): Report Size, data= [ 0x01 ] 1
            Item(Global): Usage Page, data= [ 0x08 ] 8
                            LEDs
            Item(Local ): Usage Minimum, data= [ 0x01 ] 1
                            NumLock
            Item(Local ): Usage Maximum, data= [ 0x40 ] 64
                            Indicator Fast Blink
            Item(Main  ): Output, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Main  ): End Collection, data=none
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x82  EP 2 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval               1
Device Status:     0x0000
  (Bus Powered)

Si je lis bien, j'ai deux endpoints de type "Interrupt":
* Un sur l'interface 0 défini à 0x81
* Un deuxième sur l'interface 1 défini à 0x82

J'ai écrit un petit programme en C++ afin d'essayer de communiquer avec. Cependant, j'ai essayé sur les 2 endpoints en revendiquant ("claimant") bien l'interface correspondante.

Ce qui est étonnant, c'est que quand j'essai de taper sur le endpoint 0x82, ça crashe lors de l'appel de la fonction libusb_interrupt_transfer et je n'arrive pas du tout à savoir pourquoi. Par contre, j'ai une erreur dans le dmesg qui apparait:

[10011.039485] TestLibUSB[1794]: segfault at 0 ip 00007f0d5416331a sp 00007ffd61279ff0 error 6 in libusb-1.0.so.0.1.0[7f0d54159000+16000]

Et voici la sortie de mon application quand je définie libusb en debug:

[ 0.000691] [00000794] libusb: debug [libusb_get_device_list]
[ 0.000713] [00000794] libusb: debug [discovered_devs_append] need to increase capacity
[ 0.000716] [00000794] libusb: debug [libusb_get_device_list]
[ 0.000717] [00000794] libusb: debug [discovered_devs_append] need to increase capacity
[ 0.000719] [00000794] libusb: debug [libusb_get_device_descriptor]
[ 0.000720] [00000794] libusb: debug [libusb_get_device_descriptor]
[ 0.000720] [00000794] libusb: debug [libusb_get_device_descriptor]
[ 0.000721] [00000794] libusb: debug [libusb_get_device_descriptor]
[ 0.000721] [00000794] libusb: debug [libusb_get_device_descriptor]
[ 0.000722] [00000794] libusb: debug [libusb_get_device_descriptor]
[ 0.000722] [00000794] libusb: debug [libusb_get_device_descriptor]
[ 0.000723] [00000794] libusb: debug [libusb_get_device_descriptor]
[ 0.000724] [00000794] libusb: debug [libusb_open] open 1.4
[ 0.000734] [00000794] libusb: debug [usbi_add_pollfd] add fd 11 events 4
[ 0.000739] [00000794] libusb: debug [libusb_kernel_driver_active] interface 1
[ 0.000742] [00000794] libusb: debug [libusb_claim_interface] interface 0
[ 0.000743] [00000794] libusb: debug [libusb_claim_interface] interface 1
[ 0.000754] [00000794] libusb: debug [submit_bulk_transfer] need 1 urbs for new transfer with length 8
[ 0.000763] [00000794] libusb: debug [libusb_handle_events_timeout_completed] doing our own event handling
[ 0.000764] [00000794] libusb: debug [handle_events] poll() 4 fds with timeout in 60000ms
[ 0.003052] [00000794] libusb: debug [handle_events] poll() returned 1
[ 0.003061] [00000794] libusb: debug [reap_for_handle] urb type=1 status=-71 transferred=0
[ 0.003063] [00000794] libusb: debug [handle_bulk_completion] handling completion status -71 of bulk urb 1/1
[ 0.003064] [00000794] libusb: debug [handle_bulk_completion] low level error -71
[ 0.003066] [00000794] libusb: debug [disarm_timerfd]
[ 0.003070] [00000794] libusb: debug [usbi_handle_transfer_completion] transfer 0x175fbc0 has callback 0x7f493c8c81d0
[ 0.003071] [00000794] libusb: debug [sync_transfer_cb] actual_length=0
The program has unexpectedly finished.

Alors que si j'essai de taper sur 0x81, j'ai bien le retour de la fonction dont le code d'erreur est LIBUSB_ERROR_IO. Même chose quand je veux taper vers d'autres endpoints qui n'apparaissent pas dans la sortie de lsusb. Par contre, voici la sortie de l'application quand je définie libusb en debug:

[ 0.000683] [00000780] libusb: debug [libusb_get_device_list]
[ 0.000705] [00000780] libusb: debug [discovered_devs_append] need to increase capacity
[ 0.000708] [00000780] libusb: debug [libusb_get_device_list]
[ 0.000709] [00000780] libusb: debug [discovered_devs_append] need to increase capacity
[ 0.000710] [00000780] libusb: debug [libusb_get_device_descriptor]
[ 0.000711] [00000780] libusb: debug [libusb_get_device_descriptor]
[ 0.000712] [00000780] libusb: debug [libusb_get_device_descriptor]
[ 0.000712] [00000780] libusb: debug [libusb_get_device_descriptor]
[ 0.000713] [00000780] libusb: debug [libusb_get_device_descriptor]
[ 0.000713] [00000780] libusb: debug [libusb_get_device_descriptor]
[ 0.000714] [00000780] libusb: debug [libusb_get_device_descriptor]
[ 0.000715] [00000780] libusb: debug [libusb_get_device_descriptor]
[ 0.000715] [00000780] libusb: debug [libusb_open] open 1.4
[ 0.000726] [00000780] libusb: debug [usbi_add_pollfd] add fd 11 events 4
[ 0.000731] [00000780] libusb: debug [libusb_kernel_driver_active] interface 1
[ 0.000734] [00000780] libusb: debug [libusb_claim_interface] interface 0
[ 0.000735] [00000780] libusb: debug [libusb_claim_interface] interface 1
[ 0.000745] [00000780] libusb: debug [submit_bulk_transfer] need 1 urbs for new transfer with length 8
[ 0.000747] [00000780] libusb: error [submit_bulk_transfer] submiturb failed error -1 errno=2
[ 0.000748] [00000780] libusb: debug [submit_bulk_transfer] first URB failed, easy peasy
[ 0.000749] [00000780] libusb: debug [disarm_timerfd]
Failed to transfer data 0x0 0x7ffc305266f0 LIBUSB_ERROR_IO
[ 0.000848] [00000780] libusb: debug [libusb_release_interface] interface 0
[ 0.000850] [00000780] libusb: debug [libusb_release_interface] interface 1
[ 0.000856] [00000780] libusb: debug [libusb_close]
[ 0.000858] [00000780] libusb: debug [usbi_remove_pollfd] remove fd 11
[ 0.000861] [00000780] libusb: debug [libusb_exit]
[ 0.000862] [00000780] libusb: debug [libusb_exit] destroying default context

Voici un petit morceau de code afin d'effectuer mon appel:

libusb_claim_interface(deviceHandle, 1);
unsigned char question[8];
int *actualLength = 0;
int ret = libusb_interrupt_transfer(deviceHandle, 0x81, question, 8, actualLength, 0); // ca crash ici

En sauriez-vous plus sur le problème ? Est-ce la bibliothèque qui est bugguée ? Ai-je fait quelque chose de mal dans le code ?

  • # interface HID pas déjà gérée par un pilote ?

    Posté par . Évalué à 1. Dernière modification le 01/05/15 à 11:25.

    Qu'est-ce que renvoi libusb_claim_interface() ?

    Car en général les périphériques type HID sont directement pris en charge par un driver noyau. Et comme une interface ne peut être utilisée que par un logiciel à la fois, ça risque de poser problème.

    Dans ce cas, il faudrait tenter un libusb_detach_kernel_driver(deviceHandle,1) au démarrage du programme, qui renverra 0 ou LIBUSB_ERROR_NOT_FOUND si aucun driver n'utilisait l'interface en question.
    S'il a renvoyé 0, tu sera prié de faire un libusb_attach_kernel_driver(deviceHandle,1) avant de fermer le programme.

    Sinon concernant les bugs, j'ai déjà eu ça sur les transferts bulk avec la version fournie par la distribution (Ubuntu 8.04). Le bug avait été corrigé en upstream, mais la distribution n'a jamais distribué la mise à jours. Donc il faut toujours se méfier.

    edit: pour détacher le driver, il faut bien évidement être root (donc programme à lancer avec sudo)

    • [^] # Re: interface HID pas déjà gérée par un pilote ?

      Posté par . Évalué à 2.

      Hello,

      Voici mes messages de logs:

      libusb_kernel_driver_active return 1 (if 1, so kernel driver active)
      libusb_detach_kernel_driver return 0 (if 0, success)
      libusb_claim_interface return 0 LIBUSB_SUCCESS / LIBUSB_TRANSFER_COMPLETED

      J'ai regardé dans /dev et j'ai bien 2 nouvelles entrées qui apparaissent lorsque je branche le device:
      * /dev/hidraw3
      * /dev/hidraw4

      Et /dev/hidraw4 disparait lorsque je lance mon programme et ce, surement à cause du detach_kernel_driver et de l'impossibilité de refaire un attach puisque le programme crash lors de l'appel de libusb_interrupt_transfer.

      Du coup, si 2 entrées dans /dev/ apparaissent, c'est que le pilote intégré dans le noyau Linux est ok ? Et que je peux utiliser ces 2 /dev comme des simples device de type char ?
      L'inconvénient c'est qu'il semblerait que ce ne soit que les endpoints de type IN (device to host) (les 2 décrits par lsusb) et je ne voit pas d'autre endpoint de type OUT (qui devrait être le endpoint par défaut, c'est-à-dire 0x00 d'après le tutoriel : http://matthias.vallentin.net/blog/2007/04/writing-a-linux-kernel-driver-for-an-unknown-usb-device/)

      • [^] # Re: interface HID pas déjà gérée par un pilote ?

        Posté par . Évalué à 1.

        Il y avait un driver attaché à l'interface, donc ça ne risquait donc pas de marcher.

        Pour info, la méthode "propre" serait de créer une règle UDEV pour empêcher le driver de prendre le périphérique comme ça il n'y aurait plus besoin d'être root pour lancer le programme. Par contre, je ne l'ai jamais fait donc je ne peut pas te donner la ligne.

        Normalement, si le périphérique est conforme à la norme HID, le driver noyau devrait être suffisant.
        Mais c'est quand même bizarre pour un lance-roquette USB d'avoir juste des endpoints de type IN. Est-ce qu'il n'y aurait pas un bouton dessus ? Sinon je ne vois pas l'intérêt d'être HID.

        Il ne faut pas oublier que l'endpoint 0, qui est présent sur tous les périphériques USB, n'apparaît jamais dans le lsusb. C'est un endpoint de type "control" donc il faut utiliser les fonctions qui vont bien dans libusb.

        Par contre tout ça n'explique pas le plantage.

        • [^] # Re: interface HID pas déjà gérée par un pilote ?

          Posté par . Évalué à 1.

          En fait, ce n'est pas un lance roquette USB mais un "cardio connect" que l'on trouve à Décathlon qui stocke les performances cardiaques lorsque tu vas courir. Et mon but est de récupérer les informations qui ont été stockées dessus.

          Du coup, si je comprend bien, il faudrait que je tape sur le endpoint 0 pour lui dire que je veux récupérer les informations et il me les repasserait au travers des endpoints 0x81 et 0x82 ?

          Concernant le driver, je le détachait à chaque fois avec libusb_detach_kernel_driver avant de pouvoir l'utiliser. Cependant, si je dois taper une première fois sur le endpoint 0, je ne sais pas vraiment comment faire :/
          D'après le tuto que j'ai donné en lien de le message précédent, il semblerait qu'il ai un device de type char dans /dev, dans lequel il peut écrire ses instructions. Cependant, moi j'en ai 2 et je pense que ce sont les 2 endpoint qui sont de type OUT et donc, là où je pourrai récupérer les informations. Penses-tu que ma théorie est bonne ?

          Je vais jeter un coup d'oeil à l'API de libusb pour trouver le moyen de taper sur le endpoint 0

          En tout cas, merci beaucoup de tes explications. :)

          • [^] # Re: interface HID pas déjà gérée par un pilote ?

            Posté par . Évalué à 1.

            ok, je comprend mieux,

            C'est pas évident qu'il faille faire une requête via l'endpoint 0, peut-être qu'il donne les mesures dès qu'on fait une requête.
            Selon la sortie lsusb que tu as fourni, il n'y a pas d'endpoint de type OUT, donc il n'y a pas à écrire dans les périphériques hidraw3 et hidraw4.

            Pour moi le gros problème vient du plantage de libusb. Le seul cas où il peut crasher serait si tu tape sur un endpoint ou une interface qui n'existe pas. A ce niveau là, il faudrait voir le code complet.

            Il vaut mieux éviter d'attaquer l'endpoint 0 sans savoir exactement ce qu'on fait, sinon tu risque de briquer ton appareil.

            D'ailleurs, le mieux serait de le déconnecter totalement du driver, de lancer un Windows dans une machine virtuelle et de dumper les transferts via Wireshark. Bon courage…

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.