[libhid-discuss] libhid with python: help appreciated

Charles Lepple clepple at ghz.cc
Fri Sep 9 23:08:56 UTC 2011


On Sep 9, 2011, at 9:37 AM, JamesPK wrote:

> Great - thanks for the feedback. Comments online below:
>
> On 09/09/11 03:22, Charles Lepple wrote:
>>> Hi,
>>>
>>> Apologies for what might be a basic libhid question.
>>>
>>> I'm running Ubuntu, and using libhid via Python to communicate  
>>> with a HID device (and have used 'lsusb' to glean all the details  
>>> of the device).
>>>
>>> I've started out with the example code here: http://anonscm.debian.org/viewvc/libhid/trunk/swig/test_libhid.py 
>>>  .I added  the vendor and product ID and the example code itself  
>>> worked FINE.
>>>
>>> I then added some code to the example. From the 'snooping' on the  
>>> communication with the device under Windows it needs a control  
>>> message with an initialisation string to initialise the device,  
>>> which I thought would be:
>>
>> Not to sound too nit-picky, but is it an actual USB control  
>> transfer, or is it just a message that is being sent to the device?
>>
>> USB has the notion of Control endpoints (EP0 IN and OUT), and also  
>> Interrupt endpoints. Not all devices have interrupt endpoints, but  
>> if you post the output of 'lsusb -v' (run as root, preferably after  
>> something like libhid has detached the kernel HID driver), we can  
>> see which endpoints are available.
>
> Good question - I'm not sure if its a control message required??? I  
> expect it might just be a normal 'write'  message (as on double  
> checking the on the windows output the 'request' filed was set as  
> listed as 'set report' )

Again, with several endpoints possible, the destination of the message  
matters. (Windows apparently masks this difference when reading or  
writing to HID interfaces - it uses an interrupt endpoint if  
available, otherwise it issues a request on EP0.)

 From below, you only have "EP 1 IN" (plus the always-present EP0 IN/ 
OUT).

You probably want to use hid_set_output_report():

    http://libhid.alioth.debian.org/doc/hid__exchange_8c.html#7eb62286840ff33db4f68d58682bc4ad

And the path is going to look like { 0xFF000001, 0xFF000002 } (depth 2  
since there are two elements). See the comments in the example source  
code (or the archives of this list) for the derivation.

An alternate way of approaching this is to use one of the tools which  
converts USBSnoop (or similar) log files to sequences of direct libusb  
calls. Since your HID device is simply using the HID transport layer  
to pass 8-byte messages around, you might find it easier to just use  
libusb directly.

Look under "USB sniff log parser": http://www.piclist.com/techref/usbs.htm

> Ok - 'lsusb -v' is at base of post.
>
>>> ret = hid_interrupt_write(hid, 0, INIT_SEQ, 8)
>>> if ret != HID_RET_SUCCESS:
>>>       log_error("hid_set_output_report", ret)
>>>
>>> But when I added the above spinet to the example and run it I get:
>>> (ALL messages fine up to here)
>>> ---------------------
>>> NOTICE: hid_force_open(): successfully opened USB device 006/002[0].
>>> TRACE: hid_reset_parser(): resetting the HID parser for USB device  
>>> 006/002[0]...
>>> TRACE: hid_dump_tree(): iterating the parse tree for USB device  
>>> 006/002[0]...
>>> TRACE: hid_reset_parser(): resetting the HID parser for USB device  
>>> 006/002[0]...
>>> TRACE: hid_interrupt_write(): writing interrupt report to device  
>>> 006/002[0] ...
>>> WARNING: hid_interrupt_write(): failed to perform interrupt write  
>>> to device 006/002[0]: error submitting URB: No such file or  
>>> directory
>>> ---------------------
>>
>> Ah, I think I see what's going on: you passed endpoint 0 to  
>> hid_interrupt_write() - it should be 1 or higher. Again, lsusb  
>> output will pin this down.
>>
>
> Thanks.
>
> James
> -----------------------------------------------------------------
> jamespk at hal:~/project/driver/hidapi$ sudo lsusb -v -d 0fde:ca01
>
> Bus 006 Device 002: ID 0fde:ca01
> Device Descriptor:
>  bLength                18
>  bDescriptorType         1
>  bcdUSB               1.10
>  bDeviceClass            0 (Defined at Interface level)
>  bDeviceSubClass         0
>  bDeviceProtocol         0
>  bMaxPacketSize0         8
>  idVendor           0x0fde
>  idProduct          0xca01
>  bcdDevice            3.02
>  iManufacturer           0
>  iProduct                1 Universal Bridge
>  iSerial                 0
>  bNumConfigurations      1
>  Configuration Descriptor:
>    bLength                 9
>    bDescriptorType         2
>    wTotalLength           34
>    bNumInterfaces          1
>    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      34
>          Report Descriptor: (length is 34)
>            Item(Global): Usage Page, data= [ 0x00 0xff ] 65280
>                            (null)
>            Item(Local ): Usage, data= [ 0x01 ] 1
>                            (null)
>            Item(Main  ): Collection, data= [ 0x01 ] 1
>                            Application
>            Item(Local ): Usage, data= [ 0x01 ] 1
>                            (null)
>            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= [ 0x08 ] 8
>            Item(Main  ): Input, data= [ 0x00 ] 0
>                            Data Array Absolute No_Wrap Linear
>                            Preferred_State No_Null_Position  
> Non_Volatile Bitfield

^ Up to 8 bytes of input to the PC, probably requested on either EP 1  
IN, or EP0 via the GetReport message.

>            Item(Local ): Usage, data= [ 0x02 ] 2
>                            (null)
>            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= [ 0x08 ] 8
>            Item(Main  ): Output, data= [ 0x02 ] 2
>                            Data Variable Absolute No_Wrap Linear
>                            Preferred_State No_Null_Position  
> Non_Volatile Bitfield

^ Up to 8 bytes of output from the PC, accepted only on EP0 via the  
SetReport message.

>            Item(Main  ): End Collection, data=none
>      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
> Device Status:     0x0000
>  (Bus Powered)
> --------------------------------------------
>
>




More information about the libhid-discuss mailing list