2016-05-11 1 views
2

Je suis en train d'extraire des données en temps réel à partir d'un Wacom Inklingl'ingénierie inverse une poignée de main HID en examinant les octets sur USB

Roel Janssen a déjà examiné les paquets here:

// Some kind of handshaking. 
// Values obtained by sniffing the USB connection between SketchManager and the device. 
unsigned char usb_data[33]; 
memset (&usb_data, '\0', 33); 
int bytes = 0; 

memcpy (&usb_data, "\x80\x01\x03\x01\x02\x00\x00\x00", 8); 
bytes += libusb_control_transfer (handle, 
            0x21,   // bmRequestType 
            9,   // bRequest 
            0x0380,  // wValue 
            0,   // wIndex 
            usb_data,  // data 
            33,   // wLength 
            0);   // timeout 

memcpy (&usb_data, "\x80\x01\x0a\x01\x01\x0b\x01\x00", 8); 
bytes += libusb_control_transfer (handle, 0x21, 9, 0x0380, 0, usb_data, 33, 0); 

memset (&usb_data, '\0', 33); 
bytes += libusb_control_transfer (handle, 0xa1, 1, 0x0380, 0, usb_data, 33, 0); 

memcpy (&usb_data, "\x80\x01\x0b\x01\x00\x00\x00\x00", 8); 
bytes += libusb_control_transfer (handle, 0x21, 9, 0x0380, 0, usb_data, 33, 0); 

memcpy (&usb_data, "\x80\x01\x02\x01\x01\x00\x00\x00", 8); 
bytes += libusb_control_transfer (handle, 0x21, 9, 0x0380, 0, usb_data, 33, 0); 

memcpy (&usb_data, "\x80\x01\x0a\x01\x01\x02\x01\x00", 8); 
bytes += libusb_control_transfer (handle, 0x21, 9, 0x0380, 0, usb_data, 33, 0); 

memset (&usb_data, '\0', 33); 
bytes += libusb_control_transfer (handle, 0xa1, 1, 0x0380, 0, usb_data, 33, 0); 

Je suis tente de réécrire ce code à l'aide HID API qui a une API très minime (here)

Je vais essayer d'utiliser simplement hid_write pour l'instant, mais il y a peut-être une chance ce handsh ake envoie un feature report ...?

Y at-il quelqu'un là-bas qui peut regarder ce bytestream et voir ce qui se passe?

EDIT: Il semble que l'Inkling expose une interface FlashDrive et HID, donc je devine que ce bytecode doit sélectionner l'interface HID et lui dire de commencer à envoyer des données. Mais puis-je le coder sous une forme plus élégante/lisible par l'homme?

EDIT: Je l'ai fonctionné! Les deux hid_write et hid_send_feature_report fonctionnent!

hid_device* handle = hid_open(inklingVendorId, inklingProductId, NULL); 
jassert(handle != nullptr); 

int bytes_written = 
    hid_send_feature_report(handle, (const unsigned char *)"\x80\x01\x03\x01\x02\x00\x00\x00", 8) + 
    hid_send_feature_report(handle, (const unsigned char *)"\x80\x01\x0a\x01\x01\x0b\x01\x00", 8) + 
    hid_send_feature_report(handle, (const unsigned char *)"\x80\x01\x0b\x01\x00\x00\x00\x00", 8) + 
    hid_send_feature_report(handle, (const unsigned char *)"\x80\x01\x02\x01\x01\x00\x00\x00", 8) + 
    hid_send_feature_report(handle, (const unsigned char *)"\x80\x01\x0a\x01\x01\x02\x01\x00", 8); 
jassert(bytes_written == 5*8); 

const int enable_nonblocking = 1, disable_nonblocking = 0; 
jassert(hid_set_nonblocking(handle, disable_nonblocking) != FAIL); // want to block 

while(true) { 
    int bytes_got = hid_read(handle, usb_data, 10); 

... Cependant je voudrais toujours comprendre ce qui se passe. C'est plutôt hacky.

EDIT: Sortie de lsusb (de Roel, je n'ai pas Linux à la main):

Bus 003 Device 002: ID 056a:0221 Wacom Co., Ltd 
Device Descriptor: 
    bLength    18 
    bDescriptorType   1 
    bcdUSB    2.00 
    bDeviceClass   0 (Defined at Interface level) 
    bDeviceSubClass   0 
    bDeviceProtocol   0 
    bMaxPacketSize0  64 
    idVendor   0x056a Wacom Co., Ltd 
    idProduct   0x0221 
    bcdDevice   12.56 
    iManufacturer   1 (error) 
    iProduct    2 MSC Device 
    iSerial     5 4833000045C5549C0002DD012DA5549C 
    bNumConfigurations  1 
    Configuration Descriptor: 
    bLength     9 
    bDescriptorType   2 
    wTotalLength   57 
    bNumInterfaces   2 
    bConfigurationValue  1 
    iConfiguration   3 USB/MSC Inkling 
    bmAttributes   0x80 
     (Bus Powered) 
    MaxPower    500mA 
    Interface Descriptor: 
     bLength     9 
     bDescriptorType   4 
     bInterfaceNumber  0 
     bAlternateSetting  0 
     bNumEndpoints   1 
     bInterfaceClass   3 Human Interface Device 
     bInterfaceSubClass  0 No Subclass 
     bInterfaceProtocol  2 Mouse 
     iInterface    0 
     HID Device Descriptor: 
      bLength     9 
      bDescriptorType  33 
      bcdHID    1.01 
      bCountryCode   0 Not supported 
      bNumDescriptors   1 
      bDescriptorType  34 Report 
      wDescriptorLength  215 
      Report Descriptor: (length is 215) 
      Item(Global): Usage Page, data= [ 0x0d ] 13 
          Digitizer 
      Item(Local): Usage, data= [ 0x02 ] 2 
          Pen 
      Item(Main ): Collection, data= [ 0x01 ] 1 
          Application 
      Item(Global): Report ID, data= [ 0x02 ] 2 
      Item(Local): Usage, data= [ 0x02 ] 2 
          Pen 
      Item(Main ): Collection, data= [ 0x00 ] 0 
          Physical 
      Item(Global): Usage Page, data= [ 0x01 ] 1 
          Generic Desktop Controls 
      Item(Local): Usage, data= [ 0x30 ] 48 
          Direction-X 
      Item(Local): Usage, data= [ 0x31 ] 49 
          Direction-Y 
      Item(Global): Logical Minimum, data= [ 0x00 ] 0 
      Item(Global): Logical Maximum, data= [ 0x80 0x07 ] 1920 
      Item(Global): Physical Minimum, data= [ 0x00 ] 0 
      Item(Global): Physical Maximum, data= [ 0x00 0x78 ] 30720 
      Item(Global): Unit, data= [ 0x11 ] 17 
          System: SI Linear, Unit: Centimeter 
      Item(Global): Unit Exponent, data= [ 0x0e ] 14 
          Unit Exponent: 14 
      Item(Global): Report Size, data= [ 0x10 ] 16 
      Item(Global): Report Count, data= [ 0x02 ] 2 
      Item(Main ): Input, data= [ 0x02 ] 2 
          Data Variable Absolute No_Wrap Linear 
          Preferred_State No_Null_Position Non_Volatile Bitfield 
      Item(Global): Usage Page, data= [ 0x0d ] 13 
          Digitizer 
      Item(Local): Usage, data= [ 0x42 ] 66 
          Tip Switch 
      Item(Local): Usage, data= [ 0x45 ] 69 
          Eraser 
      Item(Local): Usage, data= [ 0x44 ] 68 
          Barrel Switch 
      Item(Local): Usage, data= [ 0x32 ] 50 
          In Range 
      Item(Global): Logical Minimum, data= [ 0x00 ] 0 
      Item(Global): Logical Maximum, data= [ 0x01 ] 1 
      Item(Global): Report Size, data= [ 0x01 ] 1 
      Item(Global): Report Count, data= [ 0x04 ] 4 
      Item(Global): Unit, data= [ 0x00 ] 0 
          System: None, Unit: (None) 
      Item(Main ): Input, data= [ 0x02 ] 2 
          Data Variable Absolute No_Wrap Linear 
          Preferred_State No_Null_Position Non_Volatile Bitfield 
      Item(Global): Usage Page, data= [ 0x09 ] 9 
          Buttons 
      Item(Local): Usage Minimum, data= [ 0x01 ] 1 
          Button 1 (Primary) 
      Item(Local): Usage Maximum, data= [ 0x04 ] 4 
          Button 4 
      Item(Global): Logical Minimum, data= [ 0x00 ] 0 
      Item(Global): Logical Maximum, data= [ 0x01 ] 1 
      Item(Global): Report Size, data= [ 0x01 ] 1 
      Item(Global): Report Count, data= [ 0x04 ] 4 
      Item(Main ): Input, data= [ 0x02 ] 2 
          Data Variable Absolute No_Wrap Linear 
          Preferred_State No_Null_Position Non_Volatile Bitfield 
      Item(Global): Usage Page, data= [ 0x0d ] 13 
          Digitizer 
      Item(Local): Usage, data= [ 0x30 ] 48 
          Tip Pressure 
      Item(Global): Logical Minimum, data= [ 0x00 ] 0 
      Item(Global): Logical Maximum, data= [ 0x00 0x04 ] 1024 
      Item(Global): Report Size, data= [ 0x10 ] 16 
      Item(Global): Report Count, data= [ 0x01 ] 1 
      Item(Main ): Input, data= [ 0x02 ] 2 
          Data Variable Absolute No_Wrap Linear 
          Preferred_State No_Null_Position Non_Volatile Bitfield 
      Item(Global): Usage Page, data= [ 0x0d ] 13 
          Digitizer 
      Item(Local): Usage, data= [ 0x3d ] 61 
          X Tilt 
      Item(Local): Usage, data= [ 0x3e ] 62 
          Y Tilt 
      Item(Global): Logical Minimum, data= [ 0x81 ] 129 
      Item(Global): Logical Maximum, data= [ 0x7f ] 127 
      Item(Global): Report Size, data= [ 0x08 ] 8 
      Item(Global): Report Count, data= [ 0x02 ] 2 
      Item(Main ): Input, data= [ 0x02 ] 2 
          Data Variable Absolute No_Wrap Linear 
          Preferred_State No_Null_Position Non_Volatile Bitfield 
      Item(Main ): End Collection, data=none 
      Item(Global): Usage Page, data= [ 0x01 ] 1 
          Generic Desktop Controls 
      Item(Local): Usage, data= [ 0x00 ] 0 
          Undefined 
      Item(Global): Report ID, data= [ 0x04 ] 4 
      Item(Global): Logical Minimum, data= [ 0x00 ] 0 
      Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255 
      Item(Global): Report Size, data= [ 0x08 ] 8 
      Item(Global): Report Count, data= [ 0x0c ] 12 
      Item(Main ): Input, data= [ 0x02 ] 2 
          Data Variable Absolute No_Wrap Linear 
          Preferred_State No_Null_Position Non_Volatile Bitfield 
      Item(Global): Usage Page, data= [ 0x01 ] 1 
          Generic Desktop Controls 
      Item(Local): Usage, data= [ 0x00 ] 0 
          Undefined 
      Item(Global): Report ID, data= [ 0x08 ] 8 
      Item(Global): Logical Minimum, data= [ 0x00 ] 0 
      Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255 
      Item(Global): Report Size, data= [ 0x08 ] 8 
      Item(Global): Report Count, data= [ 0x3b ] 59 
      Item(Main ): Input, data= [ 0x02 ] 2 
          Data Variable Absolute No_Wrap Linear 
          Preferred_State No_Null_Position Non_Volatile Bitfield 
      Item(Local): Usage, data= [ 0x01 ] 1 
          Pointer 
      Item(Global): Report ID, data= [ 0x80 ] 128 
      Item(Global): Report Size, data= [ 0x08 ] 8 
      Item(Global): Report Count, data= [ 0x20 ] 32 
      Item(Main ): Feature, data= [ 0x02 ] 2 
          Data Variable Absolute No_Wrap Linear 
          Preferred_State No_Null_Position Non_Volatile Bitfield 
      Item(Main ): End Collection, data=none 
      Item(Global): Usage Page, data= [ 0x01 ] 1 
          Generic Desktop Controls 
      Item(Local): Usage, data= [ 0x02 ] 2 
          Mouse 
      Item(Main ): Collection, data= [ 0x01 ] 1 
          Application 
      Item(Global): Report ID, data= [ 0x01 ] 1 
      Item(Local): Usage, data= [ 0x01 ] 1 
          Pointer 
      Item(Main ): Collection, data= [ 0x00 ] 0 
          Physical 
      Item(Global): Usage Page, data= [ 0x01 ] 1 
          Generic Desktop Controls 
      Item(Local): Usage, data= [ 0x30 ] 48 
          Direction-X 
      Item(Local): Usage, data= [ 0x31 ] 49 
          Direction-Y 
      Item(Global): Logical Minimum, data= [ 0x00 ] 0 
      Item(Global): Logical Maximum, data= [ 0x80 0x07 ] 1920 
      Item(Global): Physical Minimum, data= [ 0x00 ] 0 
      Item(Global): Physical Maximum, data= [ 0x00 0x78 ] 30720 
      Item(Global): Unit, data= [ 0x11 ] 17 
          System: SI Linear, Unit: Centimeter 
      Item(Global): Unit Exponent, data= [ 0x0e ] 14 
          Unit Exponent: 14 
      Item(Global): Report Size, data= [ 0x10 ] 16 
      Item(Global): Report Count, data= [ 0x02 ] 2 
      Item(Main ): Input, data= [ 0x02 ] 2 
          Data Variable Absolute No_Wrap Linear 
          Preferred_State No_Null_Position Non_Volatile Bitfield 
      Item(Global): Usage Page, data= [ 0x09 ] 9 
          Buttons 
      Item(Local): Usage Minimum, data= [ 0x01 ] 1 
          Button 1 (Primary) 
      Item(Local): Usage Maximum, data= [ 0x03 ] 3 
          Button 3 (Tertiary) 
      Item(Global): Logical Minimum, data= [ 0x00 ] 0 
      Item(Global): Logical Maximum, data= [ 0x01 ] 1 
      Item(Global): Report Size, data= [ 0x01 ] 1 
      Item(Global): Report Count, data= [ 0x03 ] 3 
      Item(Global): Unit, data= [ 0x00 ] 0 
          System: None, Unit: (None) 
      Item(Main ): Input, data= [ 0x02 ] 2 
          Data Variable Absolute No_Wrap Linear 
          Preferred_State No_Null_Position Non_Volatile Bitfield 
      Item(Global): Report Count, data= [ 0x05 ] 5 
      Item(Main ): Input, data= [ 0x01 ] 1 
          Constant Array Absolute No_Wrap Linear 
          Preferred_State No_Null_Position Non_Volatile Bitfield 
      Item(Main ): End Collection, data=none 
      Item(Main ): End Collection, data=none 
     Endpoint Descriptor: 
     bLength     7 
     bDescriptorType   5 
     bEndpointAddress  0x83 EP 3 IN 
     bmAttributes   3 
      Transfer Type   Interrupt 
      Synch Type    None 
      Usage Type    Data 
     wMaxPacketSize  0x0040 1x 64 bytes 
     bInterval    4 
    Interface Descriptor: 
     bLength     9 
     bDescriptorType   4 
     bInterfaceNumber  1 
     bAlternateSetting  0 
     bNumEndpoints   2 
     bInterfaceClass   8 Mass Storage 
     bInterfaceSubClass  6 SCSI 
     bInterfaceProtocol  80 Bulk-Only 
     iInterface    4 USB/MSC Inkling 
     Endpoint Descriptor: 
     bLength     7 
     bDescriptorType   5 
     bEndpointAddress  0x81 EP 1 IN 
     bmAttributes   2 
      Transfer Type   Bulk 
      Synch Type    None 
      Usage Type    Data 
     wMaxPacketSize  0x0200 1x 512 bytes 
     bInterval    0 
     Endpoint Descriptor: 
     bLength     7 
     bDescriptorType   5 
     bEndpointAddress  0x02 EP 2 OUT 
     bmAttributes   2 
      Transfer Type   Bulk 
      Synch Type    None 
      Usage Type    Data 
     wMaxPacketSize  0x0200 1x 512 bytes 
     bInterval    0 
Device Qualifier (for other device speed): 
    bLength    10 
    bDescriptorType   6 
    bcdUSB    2.00 
    bDeviceClass   0 (Defined at Interface level) 
    bDeviceSubClass   0 
    bDeviceProtocol   0 
    bMaxPacketSize0  64 
    bNumConfigurations  2 
Device Status:  0x0000 
    (Bus Powered) 

Répondre

2

1) Vérifiez que le Inkling utilise la classe de périphérique USB HID. Essayez lsusb -v et vérifiez le champ ou bInterfaceClass dans la sortie (La classe d'interface d'interface utilisateur USB peut être utilisée pour décrire à la fois les classes d'interface et de périphérique.La classe d'interface est utilisée lorsqu'un périphérique USB peut contenir plusieurs fonctions from https://en.wikipedia.org/wiki/USB_human_interface_device_class) Dans le manuel (https://www.wacom.com/~/media/files/store-manuals/inkling-manual-english.pdf) est dit que c'est un lecteur flash USB, dans ce cas, il utilise la classe de périphérique de stockage de masse USB (transfert BULK)

2) S'il s'agit d'une classe d'appareil USB HID, vous pouvez essayer d'obtenir les rapports de fonctionnalité (si la pépinière envoie tout) similaire à ce site Web http://libusb.6.n5.nabble.com/How-to-get-HID-report-td4628.html

libusb_get_descriptorfait standard demandes GET_DESCRIPTOR , où le champ bmRequestTypeest 0x80. La demande de descripteur DT_REPORT doit indiquer que le destinataire est une interface qui nécessite bmRequestTypeêtre 0x81.

Vous avez deux bons choix. Les descripteurs de rapport sont tous inclus dans le descripteur de configuration, vous devriez donc être en mesure d'extraire le descripteur de configuration en masse et l'analyser pour extraire les descripteurs de rapport .

Alternativement,libusb_get_descriptorest une couche très mince sur libusb_control_transfer, vous pouvez donc l'étendre à la main:

res = libusb_control_transfer(devh, LIBUSB_ENDPOINT_IN | 
LIBUSB_RECIPIENT_INTERFACE, 
LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_REPORT << 8) | 0, 0, buf, 
sizeof(buf), 1000); 

plus de liens: - http://eleccelerator.com/tutorial-about-usb-hid-report-descriptors/ http://www.beyondlogic.org/usbnutshell/usb1.shtml

---------------------------------------------------------------------------------

libusb_control_transfer exécute Transferts de contrôle USB. transferts de contrôle sont utilisés pour les opérations de commande et d'état, voir ce http://libusb.sourceforge.net/api-1.0/group__syncio.html et ce http://www.beyondlogic.org/usbnutshell/usb4.shtml#Control

demandes de contrôle USB sont un sous-type de USB demande, voir http://www.beyondlogic.org/usbnutshell/usb6.shtml

usb_data semble être l'USB envoyer tampon, il est toujours rempli avec les octets de données, puis le libusb_control_transfer est envoyer

Ceci est le commenté forme de la demande de commande USB (http://www.beyondlogic.org/usbnutshell/usb6.shtml)

memcpy (&usb_data, "\x80\x01\x03\x01\x02\x00\x00\x00", 8); 
bytes += libusb_control_transfer (handle, 
            0x21,   // bmRequestType 
            9,   // bRequest 
            0x0380,  // wValue 
            0,   // wIndex 
            usb_data,  // data 
            33,   // wLength 
            0);   // timeout 

Ceci est la forme courte de la demande de commande USB

memcpy (&usb_data, "\x80\x01\x0a\x01\x01\x0b\x01\x00", 8); 
bytes += libusb_control_transfer (handle, 0x21, 9, 0x0380, 0, usb_data, 33, 0); 

Donc, toutes les séquences d'octets comme "\x80\x01\x03\x01\x02\x00\x00\x00" sont des commandes codes qui sont utilisé pour configurer l'Inkling ('handshake') et seulement les Inkling et les Wacom comprennent ...

+0

Merci pour cela, pendant que je digère l'information ici, j'ai mis à jour ma question principalement pour confirmer ce que vous avez dit à propos de lsusb. –

+0

mise à jour réponse ... –

1

Donc c'est un single rapport que vous envoyez sur USB:

80 01 03 01 02 00 00 00 .... (in total the buffer is 1+32 = 33 bytes) 
^^      Report ID 

Ceci est la partie pertinente du descripteur HID:

... 
Item(Global): Report ID, data= [ 0x80 ] 128 
Item(Global): Report Size, data= [ 0x08 ] 8 
Item(Global): Report Count, data= [ 0x20 ] 32 
Item(Main ): Feature, data= [ 0x02 ] 2 
       Data Variable Absolute No_Wrap Linear 
       Preferred_State No_Null_Position Non_Volatile Bitfield 

doit être interprété Ceci signifie que vos données pour le rapport ID 0x80 comme 32 fois un octet (il est la signification est à la hauteur du pilote je suppose). C'est une caractéristique qui signifie qu'il peut configurer l'appareil via les rapports GET_FEATURE/SET_FEATURE sur le point d'extrémité de contrôle.

Pour plus d'informations sur l'interprétation de ce descripteur, voir la spécification HID v1.1 de http://www.usb.org/developers/hidpage/.