[libhid-discuss] Still can't interrupt_read() properly

Marian Aldenhoevel marian.aldenhoevel at marian-aldenhoevel.de
Wed Sep 3 14:44:51 UTC 2008


Hi,

I am still not smart enough to do interrupt_read() properly.

The device I am trying to talking to takes commands and answers with replies.

I have used "Snoopy Pro" to spy on the conversation with my device while a 
Windows-Program that uses the device is running. It sends two commands and 
receives two replies. The full log in Snoopy-Format is attached, excerpts
from it are made in plain text.

Please bear with me as I first show what the Windows-program registers in 
Snoopy and then what my Linux-Code using libhid tries to do and where it fails.

The short summary is that I can only get one response using interrupt_read() 
every follow up comes up empty.

I send the first command. Called "Initial reset":

In Snoopy this registers as two entries:

 >19	??? down	n/a	17.225	BULK_OR_INTERRUPT_TRANSFER	-	
 >URB Header (length: 72)
 >SequenceNumber: 19
 >Function: 0009 (BULK_OR_INTERRUPT_TRANSFER)
 >TransferFlags: 0x00000003
 >
 >No TransferBuffer
 >
 >20	out down	n/a	17.238	CLASS_INTERFACE	02 00 03 43 30 30 00 >00	
 >URB Header (length: 80)
 >SequenceNumber: 20
 >Function: 001b (CLASS_INTERFACE)
 >PipeHandle: 00000000
 >
 >SetupPacket:
 >0000: 22 09 02 02 00 00 00 00
 >bmRequestType: 22
 >  DIR: Host-To-Device
 >  TYPE: Class
 >  RECIPIENT: Endpoint
 >bRequest: 09
 >
 >
 >TransferBuffer: 0x0000000c (12) length
 >0000: 02 00 03 43 30 30 00 00 00 00 00 00

I recognize the data here. It's the device-specific protocol:

   02 is the report ID.
   00 03 is the command length. 3 bytes.
   43 is 'C' for Command
   30 30 is '00' and is the code für "Initial reset".
   The rest is padding. Reports are of fixed size, Report ID 02 is
   11 bytes.

The device acts on this command, it cycles a solenoid which is very audible 
and proves that the command went through OK.

Now it answers:

 >20	out up	n/a	17.241	CONTROL_TRANSFER	-	0x00000000
 >URB Header (length: 80)
 >SequenceNumber: 20
 >Function: 0008 (CONTROL_TRANSFER)
 >PipeHandle: 887ea618
 >
 >SetupPacket:
 >0000: 21 09 02 02 00 00 0c 00
 >bmRequestType: 21
 >  DIR: Host-To-Device
 >  TYPE: Class
 >  RECIPIENT: Interface
 >bRequest: 09
 >
 >
No TransferBuffer
 >
 >8	??? up	n/a	17.689	BULK_OR_INTERRUPT_TRANSFER	42 00 05 50 30 >30 30 30 
0x00000000
 >URB Header (length: 72)
 >SequenceNumber: 8
 >Function: 0009 (BULK_OR_INTERRUPT_TRANSFER)
 >TransferFlags: 0x00000003
 >
 >TransferBuffer: 0x0000000c (12) length
 >0000: 42 00 05 50 30 30 30 30 48 42 55 2d

Again, the data decoded using docs from the Vendor:

   42 The report ID.
   00 05 Length of the response.
   50 'P' Positive response.
   30 30 '00' repeats the command the response is for.
   30 30 Two bytes of status, '00' represents the status of internal sensors.

So this was OK.

The next command goes like this:

 >21	??? down	n/a	17.689	BULK_OR_INTERRUPT_TRANSFER	-	
 >URB Header (length: 72)
 >SequenceNumber: 21
 >Function: 0009 (BULK_OR_INTERRUPT_TRANSFER)
 >TransferFlags: 0x00000003
 >
 >No TransferBuffer
 >
 >22	out down	n/a	24.666	CLASS_INTERFACE	02 00 03 43 56 30 00 >00	
 >URB Header (length: 80)
 >SequenceNumber: 22
 >Function: 001b (CLASS_INTERFACE)
 >PipeHandle: 00000000
 >
 >SetupPacket:
 >0000: 22 09 02 02 00 00 00 00
 >bmRequestType: 22
 >  DIR: Host-To-Device
 >  TYPE: Class
 >  RECIPIENT: Endpoint
 >bRequest: 09
 >
 >
 >TransferBuffer: 0x0000000c (12) length
 >0000: 02 00 03 43 56 30 00 00 00 00 00 00

Very much like the 'Initial reset':

   02 is the report ID.
   00 03 is the command length. 3 bytes.
   43 is 'C' for Command
   56 30 is 'V0' and is the code für "read version data".
   The rest is padding. Reports are of fixed size, Report ID 02 is
   11 bytes.

The response is larger this time:

 >22	out up	n/a	24.671	CONTROL_TRANSFER	-	0x00000000
 >URB Header (length: 80)
 >SequenceNumber: 22
 >Function: 0008 (CONTROL_TRANSFER)
 >PipeHandle: 887ea618
 >
 >SetupPacket:
 >0000: 21 09 02 02 00 00 0c 00
 >bmRequestType: 21
 >  DIR: Host-To-Device
 >  TYPE: Class
 >  RECIPIENT: Interface
 >bRequest: 09
 >
 >
 >No TransferBuffer
 >
 >19	??? up	n/a	24.697	BULK_OR_INTERRUPT_TRANSFER	45 00 43 50 56 >30 30 30 
0x00000000
 >URB Header (length: 72)
 >SequenceNumber: 19
 >Function: 0009 (BULK_OR_INTERRUPT_TRANSFER)
 >TransferFlags: 0x00000003
 >
 >TransferBuffer: 0x0000004c (76) length
 >0000: 45 00 43 50 56 30 30 30 48 42 55 2d 4e 41 31 34
 >0010: 35 20 20 20 42 20 37 44 34 42 45 46 20 20 20 20
 >0020: 20 20 20 20 20 20 20 20 20 20 30 30 30 30 30 30
 >0030: 48 42 55 2d 4e 41 31 34 36 20 20 20 45 20 30 30
 >0040: 45 42 31 39 39 34 00 00 00 00 00 00

   45 Report ID.
   00 43 Length of the response.
   50 'P' positive response.
   56 30 Repeats the command.
   Then response data.
   Then padding.

So this works fine. Using the windows sample software that ships with the device.

Now my program using libhid:

 > NOTICE: hid_prepare_parser(): successfully set up the HID parser for USB 
device 001/007[0].
 >  TRACE: hid_force_open(): add open device to list...
 > NOTICE: hid_force_open(): successfully opened USB device 001/007[0].
 >[DEBUG]: (V4KU) Command (00) Initial reset
 >[DEBUG]: (V4KU) Sending report ID 0x02, report size is 12 bytes
 >[DEBUG]: (libHID) hid_set_output_report() writing 12 bytes
 >[DATA ]: (libHID) S: 0x02 0x00 0x03 0x43 0x30 0x30 0x00 0x00 0x00 0x00
 >[DATA ]: (libHID) S: 0x00 0x00
 >  TRACE: hid_set_output_report(): looking up report ID...
 >  TRACE: hid_prepare_parse_path(): preparing search path of depth 3 for 
parse tree of USB device 001/007[0]...
 >  TRACE: hid_prepare_parse_path(): search path prepared for parse tree of 
USB device 001/007[0].
 > NOTICE: hid_find_object(): found requested item.
 >  TRACE: hid_set_output_report(): sending report ID 0x02 (length: 12) to USB 
device 001/007[0]...
 > NOTICE: hid_set_output_report(): successfully sent report to USB device 
001/007[0].

This sends the same 12 bytes as the windows-software does. The device cycles 
it's solenoid and thus I have feedback that the command went through. Now my 
program is waiting for the response.

I learned that I am supposed to fetch all the data for the reply in one go. So 
I first calculate the size of data (from the docs, specific to a command), and 
from that I derive the report-ID and from that the amount of bytes to request.

This is logged by my code and then libhid as such:

 > [DEBUG]: (V4KU) Expecting 5 bytes of data, handled by report ID 0x42, 
report should be 12 bytes
 > hid_interrupt_read(): retrieving interrupt report from device 001/007[0]...
 > NOTICE: hid_interrupt_read(): successfully got interrupt report from device 
001/007[0]
 >[DEBUG]: (libHID) hid_interrupt_read() read 12 bytes
 >[DATA ]: (libHID) R: 0x42 0x00 0x05 0x50 0x30 0x30 0x30 0x30 0x48 0x42
 >[DATA ]: (libHID) R: 0x55 0x2d

I do get my 12 bytes and they are the same as when using windows. Even the 
ones that are supposed to be padding and thus unuseable are identical. Fine.

Trying the second command:

 > [DEBUG]: (V4KU) command received positive result
 > [DEBUG]: (V4KU) Command (V0) Version read
 > [DEBUG]: (V4KU) Sending report ID 0x02, report size is 12 bytes
 > [DEBUG]: (libHID) hid_set_output_report() writing 12 bytes
 > [DATA ]: (libHID) S: 0x02 0x00 0x03 0x43 0x56 0x30 0x00 0x00 0x00 0x00
 > [DATA ]: (libHID) S: 0x00 0x00
 >  TRACE: hid_set_output_report(): looking up report ID...
 >  TRACE: hid_prepare_parse_path(): preparing search path of depth 3 for 
parse tree of USB device 001/007[0]...
 >  TRACE: hid_prepare_parse_path(): search path prepared for parse tree of 
USB device 001/007[0].
 > NOTICE: hid_find_object(): found requested item.
 >  TRACE: hid_set_output_report(): sending report ID 0x02 (length: 12) to USB 
device 001/007[0]...
 > NOTICE: hid_set_output_report(): successfully sent report to USB device 
001/007[0].

Same data as in Windows.

But now the trouble starts. I cannot get the response. Note that my code first 
calculates that it will expect Report ID 0x45 for a total of 76 bytes which 
again matches the windows snoop log:

 > [DEBUG]: (V4KU) Expecting 67 bytes of data, handled by report ID 0x45, 
report should be 76 bytes
 >  TRACE: hid_interrupt_read(): retrieving interrupt report from device 
001/007[0] ...
 >WARNING: hid_interrupt_read(): failed to get all of interrupt report from 
device 001/007[0]; requested: 76 bytes, sent: 0 bytes.
 >2008-09-03 16:22:32 [FATAL]: (libHID) hid_interrupt_read() failed (21: 
HID_RET_FAIL_INT_READ)

Got no data.

More observations:

I have experimented with a number of timeout options. Short, long, very long. 
So I do not think this is because of the time the device needs to process the 
second command.

I have also tried sending "initial reset" twice. I can hear the solenoid cycle 
twice but still I only receive one positive result, the second read returns 0 
bytes. From this I follow that it's the reading not the writing that is at 
fault: The second command does go through but the response is never received.

I then tried sending the same command three times. There are three clicks from 
the solenoid, but only one reply on interrupt_read() both others fail. So all 
three command were received by the device. This time the second one to fail 
returns HID_RETURN_TIMEOUT instead of FAIL_INT_READ.

The docs for the device say that if I send a new command before I fetched the 
result of a previous command the new command will be ignored. As I can send 
many commands down the line and see them being processed I think the device 
has actually answered or thinks it has answered but the reply has been lost. 
Again that points to the reading of the data and thus to my usage of libhid.

Any hints on what I could change?

Ciao, MM


More information about the libhid-discuss mailing list