[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