Discussion:
[libhid-discuss] HID_Interrupt_write reports OK, but no action on device..
Neil Sutton
2009-08-31 20:24:54 UTC
Permalink
Hi All,

I have been bashing my head against the keyboard all day trying to make my
little USB relay work under Linux (Ubuntu Jaunty if it matters)
I don't have a great deal of experience with linux but after some reading I
discovered that the best way to talk to the relay (which detects as a HID
device) was to use the libhid library.

So far I have tweaked the example code so that it looks for my device and
set up the commands to make an interrupt write to try and enable the relays.

In Windows I successfully control the device using VB and issue the commands
to control the relays using Convert.ToByte(Int)
The board has 4 relays and by issuing Convert.ToByte(6) for example I can
open a single relay, Convert.ToByte(5) closes the relay.
(7) and (8) control another relay.. you get the idea.

Now the example code reports back ok when I issue the interrupt write but
nothing happens on the device.
I think I may be sending the wrong commands but I'm not too sure..
I figured that I should send one byte, of 8 bits..? so I have tried to send
0xFF and also 255 but neither does anything.

The lsusb output is here for my device;
http://pastebin.com/m48287552

Here is the modified hid_test.c that I'm currently using;
http://pastebin.com/d1a6f40da

Any pointers would be appreciated!

Thanks
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.alioth.debian.org/pipermail/libhid-discuss/attachments/20090831/a0be15ab/attachment.htm>
Charles Lepple
2009-08-31 23:02:27 UTC
Permalink
[Please subscribe to the list:
http://lists.alioth.debian.org/mailman/listinfo/libhid-discuss
Thanks.]
Post by Neil Sutton
Hi All,
I have been bashing my head against the keyboard all day trying to
make my little USB relay work under Linux (Ubuntu Jaunty if it
matters)
I don't have a great deal of experience with linux but after some
reading I discovered that the best way to talk to the relay (which
detects as a HID device) was to use the libhid library.
So far I have tweaked the example code so that it looks for my
device and set up the commands to make an interrupt write to try and
enable the relays.
In Windows I successfully control the device using VB and issue the
commands to control the relays using Convert.ToByte(Int)
The board has 4 relays and by issuing Convert.ToByte(6) for example
I can open a single relay, Convert.ToByte(5) closes the relay.
(7) and (8) control another relay.. you get the idea.
In that case, you probably want to send 6 and 5, or 7 and 8.
Post by Neil Sutton
Now the example code reports back ok when I issue the interrupt
write but nothing happens on the device.
I think I may be sending the wrong commands but I'm not too sure..
Are you sure that the Windows code is using an interrupt write, and
not a control transfer? Is it using an output usage rather than a
feature usage?

Also, what timeout are you using under Windows?
Post by Neil Sutton
I figured that I should send one byte, of 8 bits..? so I have tried
to send 0xFF and also 255 but neither does anything.
0xff and 255 get converted to the same 8-bit quantity when sent.
Post by Neil Sutton
The lsusb output is here for my device;
http://pastebin.com/m48287552
Here is the modified hid_test.c that I'm currently using;
http://pastebin.com/d1a6f40da
Any pointers would be appreciated!
Thanks
_______________________________________________
libhid-discuss mailing list
libhid-discuss at lists.alioth.debian.org
http://lists.alioth.debian.org/mailman/listinfo/libhid-discuss
http://libhid.alioth.debian.org/
Neil Sutton
2009-09-01 09:28:08 UTC
Permalink
Thanks for the advice Wingnut I will try out USBSnoop when I get home
tonight..
In Windows I successfully control the device using VB and issue the
Post by Neil Sutton
commands to control the relays using Convert.ToByte(Int)
The board has 4 relays and by issuing Convert.ToByte(6) for example I can
open a single relay, Convert.ToByte(5) closes the relay.
(7) and (8) control another relay.. you get the idea.
In that case, you probably want to send 6 and 5, or 7 and 8.
Would just sending 0x35 via libhid be the equivilent of using .net's
Convert.ToByte(5) ?
I have really confused myself with how the data should be presented to
libhid..
Now the example code reports back ok when I issue the interrupt write but
Post by Neil Sutton
nothing happens on the device.
I think I may be sending the wrong commands but I'm not too sure..
Are you sure that the Windows code is using an interrupt write, and not a
control transfer? Is it using an output usage rather than a feature usage?
Also, what timeout are you using under Windows?
Looking at the code I'm using for Windows (sample code .net from Lake View
Research - www.lvr.com) It does appear to be using a control transfer.
I'm not sure about output / feature usage.. as that was something I never
dealt with using the LVR code, I just had to point it at the VID/PID and
enter the data to send.
I did intially use the output report method in libhid but I wasn't sure of
the output path since I couldn't make much sense of the comments in the
example.
Then I noticed that the output of lsusb said the method was Interrupt so I
presumed I should be using that..?
I figured that I should send one byte, of 8 bits..? so I have tried to
Post by Neil Sutton
send 0xFF and also 255 but neither does anything.
0xff and 255 get converted to the same 8-bit quantity when sent.
The lsusb output is here for my device;
Post by Neil Sutton
http://pastebin.com/m48287552
Here is the modified hid_test.c that I'm currently using;
http://pastebin.com/d1a6f40da
Any pointers would be appreciated!
Thanks
_______________________________________________
libhid-discuss mailing list
libhid-discuss at lists.alioth.debian.org
http://lists.alioth.debian.org/mailman/listinfo/libhid-discuss
http://libhid.alioth.debian.org/
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.alioth.debian.org/pipermail/libhid-discuss/attachments/20090901/843596b8/attachment.htm>
Charles Lepple
2009-09-01 11:33:52 UTC
Permalink
Post by Neil Sutton
In Windows I successfully control the device using VB and issue the
commands to control the relays using Convert.ToByte(Int)
The board has 4 relays and by issuing Convert.ToByte(6) for example
I can open a single relay, Convert.ToByte(5) closes the relay.
(7) and (8) control another relay.. you get the idea.
In that case, you probably want to send 6 and 5, or 7 and 8.
Would just sending 0x35 via libhid be the equivilent of
using .net's Convert.ToByte(5) ?
I have really confused myself with how the data should be
presented to libhid..
I would assume that if the argument to Convert.ToByte() is an integer
less than 255, then the C equivalent would be that same integer. I
think you would only use 0x35 if you were passing a string "5" to
Convert.ToByte(). Someone who actually knows .NET can feel free to
correct me, though.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.alioth.debian.org/pipermail/libhid-discuss/attachments/20090901/084aa4bb/attachment.htm>
Neil Sutton
2009-09-01 16:47:00 UTC
Permalink
I would assume that if the argument to Convert.ToByte() is an integer less
than 255, then the C equivalent would be that same integer. I think you
would only use 0x35 if you were passing a string "5" to Convert.ToByte().
Someone who actually knows .NET can feel free to correct me, though.
I think you're right Charles, I went back to the working example from LVR
and stepped through everything. If I send Hex 0x05 to the device using an
Output report it works under windows.. so my data needs to be a single byte
of 0x05.
Also if I echo back the result of Convert.ToByte(5) it is indeed 5..

Could you advise on how the output usage path is calculated from my lsusb
-vv output ? (http://pastebin.com/m48287552)
I am going to try and get things working using output reports instead of
interrupt_write because I know this works under Windows, but even after
reading the example text I don't know how to calculate the PATH_IN /
PATH_OUT values.
I think if I can get those right then my problems will be solved.

Many Thanks
Neil
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.alioth.debian.org/pipermail/libhid-discuss/attachments/20090901/b2752c99/attachment.htm>
Charles Lepple
2009-09-01 22:43:40 UTC
Permalink
Post by Charles Lepple
I would assume that if the argument to Convert.ToByte() is an
integer less than 255, then the C equivalent would be that same
integer. I think you would only use 0x35 if you were passing a
string "5" to Convert.ToByte(). Someone who actually knows .NET can
feel free to correct me, though.
I think you're right Charles, I went back to the working example
from LVR and stepped through everything. If I send Hex 0x05 to the
device using an Output report it works under windows.. so my data
needs to be a single byte of 0x05.
Also if I echo back the result of Convert.ToByte(5) it is indeed 5..
Could you advise on how the output usage path is calculated from my
lsusb -vv output ? (http://pastebin.com/m48287552)
I am going to try and get things working using output reports
instead of interrupt_write because I know this works under Windows,
but even after reading the example text I don't know how to
calculate the PATH_IN / PATH_OUT values.
I think if I can get those right then my problems will be solved.
Your original code pastebin expired, but I think you were close.

Item(Global): Usage Page, data= [ 0xa0 0xff ] 65440
Item(Local ): Usage, data= [ 0x01 ] 1
Item(Main ): Collection, data= [ 0x01 ] 1
Item(Local ): Usage, data= [ 0x03 ] 3
Item(Global): Logical Minimum, data= [ 0x00 ] 0
Item(Global): Logical Maximum, data= [ 0x00 0xff ] 65280
Item(Global): Report Size, data= [ 0x08 ] 8
Item(Global): Report Count, data= [ 0x01 ] 1
[...]
Item(Main ): Output, data= [ 0x02 ] 2
Data Variable Absolute No_Wrap Linear
Preferred_State No_Null_Position
Non_Volatile Bitfield
Item(Local ): Usage, data= [ 0x05 ] 5

The "usage page" part is the upper 16 bits of each entry in the
"path". If there are no other Usage Pages listed, then that part
(0xffa0) doesn't change.

The bold items above are what you need.

I think the path should be "0xffa00001, 0xffa00003, 0xffa00005". I
forget if the HID parser drops the very first usage (since it is
outside a collection).
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.alioth.debian.org/pipermail/libhid-discuss/attachments/20090901/1a73e5ca/attachment.htm>
Neil Sutton
2009-09-01 23:53:31 UTC
Permalink
Hi Charles,

Thanks for the clarification, that now makes a little more sense to me.
I tried the output path suggested but even though it reported sent ok
nothing happened.

I've been tinkering some more and thought I'd give the interrupt write
another go and it's now working :)
I think I must have had the packet length wrong the first time I tried it as
I've haven't really altered much else!

Thanks very much for your assistance in getting this going.. I'm so pleased
I finally got there ! :)

Kind Regards
Neil
Post by Neil Sutton
I would assume that if the argument to Convert.ToByte() is an integer less
than 255, then the C equivalent would be that same integer. I think you
would only use 0x35 if you were passing a string "5" to Convert.ToByte().
Someone who actually knows .NET can feel free to correct me, though.
I think you're right Charles, I went back to the working example from LVR
and stepped through everything. If I send Hex 0x05 to the device using an
Output report it works under windows.. so my data needs to be a single byte
of 0x05.
Also if I echo back the result of Convert.ToByte(5) it is indeed 5..
Could you advise on how the output usage path is calculated from my lsusb
-vv output ? (http://pastebin.com/m48287552)
I am going to try and get things working using output reports instead of
interrupt_write because I know this works under Windows, but even after
reading the example text I don't know how to calculate the PATH_IN /
PATH_OUT values.
I think if I can get those right then my problems will be solved.
Your original code pastebin expired, but I think you were close.
* Item(Global): Usage Page, data= [ 0xa0 0xff ] 65440*
* Item(Local ): Usage, data= [ 0x01 ] 1*
Item(Main ): Collection, data= [ 0x01 ] 1
* Item(Local ): Usage, data= [ 0x03 ] 3*
Item(Global): Logical Minimum, data= [ 0x00 ] 0
Item(Global): Logical Maximum, data= [ 0x00 0xff ] 65280
Item(Global): Report Size, data= [ 0x08 ] 8
Item(Global): Report Count, data= [ 0x01 ] 1
[...]
Item(Main ): Output, data= [ 0x02 ] 2
Data Variable Absolute No_Wrap Linear
Preferred_State No_Null_Position Non_Volatile
Bitfield
Item(Local ): Usage, data= [ 0x05 ] 5
The "usage page" part is the upper 16 bits of each entry in the "path". If
there are no other Usage Pages listed, then that part (0xffa0) doesn't
change.
The bold items above are what you need.
I think the path should be "0xffa00001, 0xffa00003, 0xffa00005". I forget
if the HID parser drops the very first usage (since it is outside a
collection).
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.alioth.debian.org/pipermail/libhid-discuss/attachments/20090902/43b5aeac/attachment-0001.htm>
Wingnut Wingnut
2009-09-01 01:04:34 UTC
Permalink
Post by Neil Sutton
Hi All,
I have been bashing my head against the keyboard all day trying to make my
little USB relay work under Linux (Ubuntu Jaunty if it matters)
I don't have a great deal of experience with linux but after some reading I
discovered that the best way to talk to the relay (which detects as a HID
device) was to use the libhid library.
In your reading, did you run across the USBSnoop program:
http://www.pcausa.com/Utilities/UsbSnoop/

This was tremendously helpful for me when I was trying to write my driver.
Once you start monitoring, look for the BULK_OR_INTERRUPT_TRANSFER to your
output endpoint (as you've reported by lsusb, this is endpoint 1). Here's a
sample, and some info on dissecting it:

1 [43094 ms] >>> URB 11 going down >>>
2 -- URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
3 PipeHandle = e79e99c8 [endpoint 0x00000001]
4 TransferFlags = 00000002 (USBD_TRANSFER_DIRECTION_OUT,
USBD_SHORT_TRANSFER_OK)
5 TransferBufferLength = 00000040
6 TransferBuffer = e51f12da
7 TransferBufferMDL = 00000000
8 00000000: 03 08 81 00 00 00 00 00 00 00 00 00 00 00 00 00
9 00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
10 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
11 00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
12 UrbLink = 00000000
13 [43096 ms] UsbSnoop - MyInternalIOCTLCompletion(e2d37ddc) :
fido=ff503830, Irp=ff4719b0, Context=e7


In my case, on line 3, the PipeHandle shows that the destination is endpoint
0x01, the transfer buffer length is 0x40 bytes (64 bytes), and the
TransferBufferMDL raw data shows the information sent. It turns out that I
had to send a control byte, length, and address as the first, second and
third byte before sending data (as described in the device datasheet).

Perhaps by snooping and replaying the traffic you can discover the operation
of the device? Or perhaps find the manufacturers datasheet for the part and
see how the bus is used?

Wingnut
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.alioth.debian.org/pipermail/libhid-discuss/attachments/20090831/19d7ca2f/attachment-0001.htm>
Loading...