Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sainsmart16 HID path is not stable #26

Closed
derekatkins opened this issue Aug 20, 2018 · 29 comments
Closed

Sainsmart16 HID path is not stable #26

derekatkins opened this issue Aug 20, 2018 · 29 comments

Comments

@derekatkins
Copy link
Contributor

Apparently the HID path for my sainsmart16 is not stable.
If I unplug the device and then plug it back in again, the path is different.
I can see this in dmesg as I remove and re-insert the device into my machine:

[2332915.679529] hid-generic 0003:0416:5020.0005: input,hidraw0: USB HID v1.10 Device [Nuvoton HID Transfer] on usb-0000:00:14.0-4/input0
[2333625.965356] hid-generic 0003:0416:5020.0006: input,hidraw0: USB HID v1.10 Device [Nuvoton HID Transfer] on usb-0000:00:14.0-4/input0
[2336516.928041] hid-generic 0003:0416:5020.0007: input,hidraw0: USB HID v1.10 Device [Nuvoton HID Transfer] on usb-0000:00:14.0-4/input0
[2337168.447530] hid-generic 0003:0416:5020.0008: input,hidraw0: USB HID v1.10 Device [Nuvoton HID Transfer] on usb-0000:00:14.0-1/input0

I cannot see a good way in the HID API to find the underlying USB path, which as you can see IS stable "usb-0000:00:14.0-4" (and my second device on "usb-0000:00:14.0-1". I am open to suggestions?

@ondrej1024
Copy link
Owner

You are right. When i tried this here I was only looking at the USB path, not at the HID id which seems to be associated differently by the HID driver.

Anyway, the best way to identify a relay card would be to use it's internal serial number which is usually supplied by the card itself. All other cards supported by crelay provide such a serial number and a method to access it. The 1/2/4/8 HIDAPI relays for example send this string together with the status report (see relay_drv_hidapi.c for details).

For the Sainsmart 16 channel HID relay card @khilman and I were not able to find a way to access the serial number, nor do we know if it actually provides one. There are 2 bytes in the status response which have unknown meaning but it is probably too short for a serial number. There might be another command besides READ and WRITE which provides the serial number in response. Maybe it's worth to do some testing to find that out.

@derekatkins
Copy link
Contributor Author

I tried using the hidapi get_serial_string API, but it just returned garbage (and worse, both cards returned the same data). Do we even know if this card has a serial number? I really wish there were a way to read the underlying USB interface path, which does not change, but is abstracted away. I wonder if there's a libusb method to read it? Clearly the kernel has that information, so it's just a question of gaining access to it.

I'll go explore some more.

@derekatkins
Copy link
Contributor Author

Just an update -- I sent a support request to sainsmart and got a reply back:

Here is the documentation for this relay kit:
http://wiki.sainsmart.com/index.php/101-70-C09
Each device has an unique serial number that can be obtained through the program GuiApp_Chinese.exe or the GuiApp_ English.exe .

So.. Clearly there is a way to obtain it, it's just a question of figuring out how from the "documentation". I can't tell if there is actual source code for the GUI Apps. I'll keep looking, but maybe this will help others (you and @khilman) too?

@ondrej1024
Copy link
Owner

Great, this is more documentation than I expected Sainsmart to provide. Can you run the GuiApp and check if it really reads the serial number from the card? If it does it should be possible to sniff the USB traffic of this operation.

@derekatkins
Copy link
Contributor Author

That would imply finding a windows platform to run it. I'll see what I can do -- I don't really have any M$ products lying around. I might have a VM I can leverage -- but then I'm not sure how to sniff the USB bus. This is definitely getting to be beyond my current know-how. But willing to learn ;)

@ondrej1024
Copy link
Owner

You could try running the program with Wine under Linux. Otherwise you will have to use a Win VM. Sniffing the USB traffic should be possible with Wireshark, but I never tried that myself.

@derekatkins
Copy link
Contributor Author

Found a VM. Of course the app doesn't run because the VM is missing msvcr100.dll. sigh
Wireshark does have a usbmon choice (well, two of them).
Who knows if it'll be able to sniff a VM, tho.
We'll see. -- Once I get M$ into shape. :(

@derekatkins
Copy link
Contributor Author

derekatkins commented Aug 22, 2018

So I finally got it to run, but I don't see an actual "serial number" in there. All it displays is "Realy_NO1" (sic) which doesn't seem very helpful to me. :( I'll go ask them again to clarify.
The other option is to still see if there is a way to access the underlying USB port data. Or perhaps I just need to set a udev rule to stabilize the device? I know if will always be plugged into the same USB port in the final stage.

@derekatkins
Copy link
Contributor Author

Oh. LOVELY. I just plugged the second unit into the VM, and they BOTH return "Realy_NO1". So both units have the same serial number, apparently. :(

@derekatkins
Copy link
Contributor Author

Here is some of the wireshark USB monitor output for supposedly reading the serial number (which I guess is the same on both of my cards). This was a "probe" and then flipping a relay on and then off again. You can see the "response" in packet 33 (although it comes from 1.6.4 instead of 1.6.5 -- and all other communication is with 1.6.5). Maybe this can help? I'm not sure how to decipher this.
`

     31 14.885427      host                  1.6.5                 USB      128    URB_INTERRUPT out
0000  c0 96 3b 1a 3b 98 ff ff 53 01 05 06 01 00 2d 00   ..;.;...S.....-.
0010  00 6e 7d 5b 00 00 00 00 e0 cf 04 00 8d ff ff ff   .n}[............
0020  40 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00   @...@...........
0030  01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0040  71 0e 71 00 00 00 11 11 11 11 48 49 44 43 4c 02   q.q.......HIDCL.
0050  00 00 cc cc cc cc cc cc cc cc cc cc cc cc cc cc   ................
0060  cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc   ................
0070  cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc   ................
     32 14.885825      1.6.5                 host                  USB      64     URB_INTERRUPT out
0000  c0 96 3b 1a 3b 98 ff ff 43 01 05 06 01 00 2d 3e   ..;.;...C.....->
0010  00 6e 7d 5b 00 00 00 00 6e d1 04 00 00 00 00 00   .n}[....n.......
0020  40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   @...............
0030  01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
     33 14.886791      1.6.4                 host                  USB      128    URB_INTERRUPT in
0000  80 07 5c a8 3a 98 ff ff 43 01 84 06 01 00 2d 00   ..\.:...C.....-.
0010  00 6e 7d 5b 00 00 00 00 34 d5 04 00 00 00 00 00   .n}[....4.......
0020  40 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00   @...@...........
0030  01 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00   ................
0040  71 15 10 52 65 61 6c 79 5f 4e 4f 31 00 00 00 00   q..Realy_NO1....
0050  00 00 00 00 00 aa 00 00 00 00 00 00 00 00 00 00   ................
0060  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0070  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
     34 14.888689      host                  1.6.4                 USB      64     URB_INTERRUPT in
0000  00 29 8d f8 37 98 ff ff 53 01 84 06 01 00 2d 3c   .)..7...S.....-<
0010  00 6e 7d 5b 00 00 00 00 9e dc 04 00 8d ff ff ff   .n}[............
0020  40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   @...............
0030  01 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00   ................
     35 30.605293      host                  1.6.5                 USB      128    URB_INTERRUPT out
0000  80 31 42 c8 38 98 ff ff 53 01 05 06 01 00 2d 00   .1B.8...S.....-.
0010  10 6e 7d 5b 00 00 00 00 9a 89 00 00 8d ff ff ff   .n}[............
0020  40 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00   @...@...........
0030  01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0040  d2 0e 11 11 11 11 11 11 11 11 48 49 44 43 80 02   ..........HIDC..
0050  00 00 cc cc cc cc cc cc cc cc cc cc cc cc cc cc   ................
0060  cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc   ................
0070  cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc   ................
     36 30.606113      1.6.5                 host                  USB      64     URB_INTERRUPT out
0000  80 31 42 c8 38 98 ff ff 43 01 05 06 01 00 2d 3e   .1B.8...C.....->
0010  10 6e 7d 5b 00 00 00 00 ce 8c 00 00 00 00 00 00   .n}[............
0020  40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   @...............
0030  01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
     37 30.607066      1.6.4                 host                  USB      128    URB_INTERRUPT in
0000  40 4b a9 a9 3a 98 ff ff 43 01 84 06 01 00 2d 00   @K..:...C.....-.
0010  10 6e 7d 5b 00 00 00 00 87 90 00 00 00 00 00 00   .n}[............
0020  40 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00   @...@...........
0030  01 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00   ................
0040  d2 0b 00 00 aa 61 6c 79 5f 4e 4f 31 00 00 00 00   .....aly_NO1....
0050  00 00 00 00 00 aa 00 00 00 00 00 00 00 00 00 00   ................
0060  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0070  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
     38 30.608587      host                  1.6.4                 USB      64     URB_INTERRUPT in
0000  80 31 42 c8 38 98 ff ff 53 01 84 06 01 00 2d 3c   .1B.8...S.....-<
0010  10 6e 7d 5b 00 00 00 00 78 96 00 00 8d ff ff ff   .n}[....x.......
0020  40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   @...............
0030  01 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00   ................
     39 33.126644      host                  1.6.5                 USB      128    URB_INTERRUPT out
0000  80 01 5c a8 3a 98 ff ff 53 01 05 06 01 00 2d 00   ..\.:...S.....-.
0010  12 6e 7d 5b 00 00 00 00 21 7e 08 00 8d ff ff ff   .n}[....!~......
0020  40 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00   @...@...........
0030  01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0040  c3 0e 01 00 00 00 00 00 00 00 48 49 44 43 ea 01   ..........HIDC..
0050  00 00 cc cc cc cc cc cc cc cc cc cc cc cc cc cc   ................
0060  cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc   ................
0070  cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc   ................
     40 33.127160      1.6.5                 host                  USB      64     URB_INTERRUPT out
0000  80 01 5c a8 3a 98 ff ff 43 01 05 06 01 00 2d 3e   ..\.:...C.....->
0010  12 6e 7d 5b 00 00 00 00 25 80 08 00 00 00 00 00   .n}[....%.......
0020  40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   @...............
0030  01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
     41 34.242362      host                  1.6.5                 USB      128    URB_INTERRUPT out
0000  80 97 3b 1a 3b 98 ff ff 53 01 05 06 01 00 2d 00   ..;.;...S.....-.
0010  13 6e 7d 5b 00 00 00 00 27 42 0a 00 8d ff ff ff   .n}[....'B......
0020  40 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00   @...@...........
0030  01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0040  c3 0e 00 00 00 00 00 00 00 00 48 49 44 43 e9 01   ..........HIDC..
0050  00 00 cc cc cc cc cc cc cc cc cc cc cc cc cc cc   ................
0060  cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc   ................
0070  cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc   ................
     42 34.243199      1.6.5                 host                  USB      64     URB_INTERRUPT out
0000  80 97 3b 1a 3b 98 ff ff 43 01 05 06 01 00 2d 3e   ..;.;...C.....->
0010  13 6e 7d 5b 00 00 00 00 6c 45 0a 00 00 00 00 00   .n}[....lE......
0020  40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   @...............
0030  01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
     43 37.186732      host                  1.6.5                 USB      128    URB_INTERRUPT out
0000  80 97 3b 1a 3b 98 ff ff 53 01 05 06 01 00 2d 00   ..;.;...S.....-.
0010  16 6e 7d 5b 00 00 00 00 d9 68 09 00 8d ff ff ff   .n}[.....h......
0020  40 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00   @...@...........
0030  01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0040  c3 0e 00 00 00 00 00 00 00 00 48 49 44 43 e9 01   ..........HIDC..
0050  00 00 cc cc cc cc cc cc cc cc cc cc cc cc cc cc   ................
0060  cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc   ................
0070  cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc   ................
     44 37.187226      1.6.5                 host                  USB      64     URB_INTERRUPT out
0000  80 97 3b 1a 3b 98 ff ff 43 01 05 06 01 00 2d 3e   ..;.;...C.....->
0010  16 6e 7d 5b 00 00 00 00 c7 6a 09 00 00 00 00 00   .n}[.....j......
0020  40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   @...............
0030  01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
     45 37.188929      host                  1.6.5                 USB      128    URB_INTERRUPT out
0000  80 97 3b 1a 3b 98 ff ff 53 01 05 06 01 00 2d 00   ..;.;...S.....-.
0010  16 6e 7d 5b 00 00 00 00 6e 71 09 00 8d ff ff ff   .n}[....nq......
0020  40 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00   @...@...........
0030  01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0040  71 0e 71 00 00 00 11 11 00 00 48 49 44 43 2a 02   q.q.......HIDC*.
0050  00 00 cc cc cc cc cc cc cc cc cc cc cc cc cc cc   ................
0060  cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc   ................
0070  cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc   ................
     46 37.189219      1.6.5                 host                  USB      64     URB_INTERRUPT out
0000  80 97 3b 1a 3b 98 ff ff 43 01 05 06 01 00 2d 3e   ..;.;...C.....->
0010  16 6e 7d 5b 00 00 00 00 90 72 09 00 00 00 00 00   .n}[.....r......
0020  40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   @...............
0030  01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................

@ondrej1024
Copy link
Owner

Ok, that looks good.I'm not on my pc right now but will try to make some sense out of this later on.

@derekatkins
Copy link
Contributor Author

Another thing I discovered is that if there were a way to access the underlying libusb_dev object, using libusb_get_bus_number() and libusb_get_port_numbers() APIs do provide a stable identifier. Those values remain constant across multiple plug-ins, even while the "path" changes each time.

@ondrej1024
Copy link
Owner

With the GUIApp, did you try to connect both your cards and then push "Find Device" ? What happens?

@derekatkins
Copy link
Contributor Author

I did. They both come in as Realy_NO1 (as I reported ~8 hours ago).

@ondrej1024
Copy link
Owner

Oh sorry, I hadn't understood that you plugged in both at the same time. So in that case, if they report the same serial (or Id), then it is impossible to control the second card with the GUIApp. You should report that to Sainsmart. I assume your cards were not programmed properly with the serial numbers.
In the documentation "HID manual-11.25.doc" there is an example which reports the hex string afEd5 as possible serial number.

@ondrej1024
Copy link
Owner

ondrej1024 commented Aug 23, 2018

I figured out how to interpret the USB traces from the traffic between PC and relay card.

Basically there are 2 frames for each request and additional 2 frames for a request which expects a reply (e.g. a status read request).

host                  1.6.5
1.6.5                 host 
1.6.4                 host 
host                  1.6.4

The actual payload of the request is at offset 0040 of the first frame and the response (if any) is at offset 0040 of the third frame. The other stuff is probably the overhead of the HID protocol.

To confirm that in your traces there is the read request in frame 35:
0040 d2 0e 11 11 11 11 11 11 11 11 48 49 44 43 80 02

and the corresponding response in frame 37:
0040 d2 0b 00 00 aa 61 6c 79 5f 4e 4f 31 00 00 00 00

A write request in frame 39:
0040 c3 0e 01 00 00 00 00 00 00 00 48 49 44 43 ea 01

and frame 41:
0040 c3 0e 00 00 00 00 00 00 00 00 48 49 44 43 e9 01

These request are according to the format we use in crelay.

What most interesting though, there is a new request in frame 31 which we didn't know yet, which is probably the serial number / Id request:
0040 71 0e 71 00 00 00 11 11 11 11 48 49 44 43 4c 02

And the corresponding response in frame 33:
0040 71 15 10 52 65 61 6c 79 5f 4e 4f 31 00 00 00 00

which reports the weird Realy_NO1 serial number.

@ondrej1024
Copy link
Owner

So in conclusion that means we could now implement the proper request for the serial number in crelay. But we need to be sure that the cards DO have a real serial number programmed, otherwise we will read only useless data.

@derekatkins
Copy link
Contributor Author

Alas, both cards seem to report the same data. I have requested more information from SainSmart in the interim, but they have to "research" it more and wont get back to me until at least Monday. I think the answer is going to be "uh oh".

On the other hand, I have found a workaround, sort of, by modifying hidapi to use libusb_get_port_numbers() instead of libusb_get_device_address() in building the path. This provides a stable path based on the actual physical location of the device. I just don't know if there is a way we could do that in crelay without a modified hidapi. There does not appear to be a way to get to the underlying libusb_device from the exported hidapi data structure.

@derekatkins
Copy link
Contributor Author

Sorry, I missed a bit of your response. Where do you see the afEd5 in the trace?

And yes, with both cards plugged in I could only control one of them with their Gui App! I have (to some degree) reported this to them. I told them both cards showed up as Realy_NO1 in the drop down, but neglected to mention that I could only control one. I'll let them know.

And for the record, yes, Frame 31 and 33 is the serial-id request/response which I got by pushing the "Find Cards" button in their Gui App. Then I selected Relay 1 and turned it on and the off (the two requests you see in 35/37/39/41.

@derekatkins
Copy link
Contributor Author

Ugggh. Got the following reply from Sainsmart:

 The MAC address of these items are same and you can not change the MAC  
 address. That is, you only can control one module and can not control   
 two modules at the same time.                                           

On to plan B -- changing hidapi to return a stable path. C.f. https://github.com/derekatkins/hidapi

@ondrej1024
Copy link
Owner

Ugggh. Got the following reply from Sainsmart:

This response doesn't make sense, of course. If the GUIApp provides a way of selecting the serial number than it should be possible to control each connected relay card. The documentation "HID manual-11.25.doc" explicitely mentions the use of a serial number:

例如:For instance

  1. 打开序列号afEd5设备的第一路继电器Open the first relay of series number of Device afEd5
    CommandApp_USBRelay afEd5 open 01
  2. 打开序列号afEd5设备的所有继电器Open all relays of series number of Device afEd5
    CommandApp_USBRelay afEd5 open 255
  3. 关闭序列号afEd5设备的第一路继电器Close the first relay of series number of Device afEd5
    CommandApp_USBRelay afEd5 close 01
  4. 关闭序列号afEd5设备的所有继电器Close all relays of series number of Device afEd5
    CommandApp_USBRelay afEd5 close 255

So I'm pretty sure your cards were not programmed correctly and are missing the serial number.

On to plan B -- changing hidapi to return a stable path. C.f. https://github.com/derekatkins/hidapi

The problem I see with this is that crelay would depend on this modified HIDAPI library and installation would be more complicated. Unless you can get your modifications accepted in the official version of this library.

@khilman
Copy link

khilman commented Aug 29, 2018

FWIW, the response from SainSmart doesn't surprise me. I had a similar conversation with them about the RJ45 network connectors for the relay boards. They ship every one with identical MAC address, so you can't use 2 of them on the same LAN. :(

@ondrej1024
Copy link
Owner

It's a shame that they put these kind of faulty products on the market. I'm almost inclined to not support the Sainsmart crap anymore. By working around these defects with tools like crelay we only help them sell even more of that. 😞

@derekatkins
Copy link
Contributor Author

Sorry for the delay in responding -- been travelling and then the holiday weekend.

The problem I see with this is that crelay would depend on this modified HIDAPI library and installation would be more complicated. Unless you can get your modifications accepted in the official version of this library.

Considering the HIDAPI library has not been touched in over 2 years, that might be challenging. I've submitted a PR, but of course there are like 60 or more outstanding PRs to hidapi.

I'm happy to have it solved for me.. I agree that right now it's not a problem that crelay can solve. :(

@derekatkins
Copy link
Contributor Author

C.f. signal11/hidapi#406

@khilman
Copy link

khilman commented Sep 4, 2018

So there's no hacks or workaround with udev rules to make it work without the modified hidapi?

@derekatkins
Copy link
Contributor Author

So there's no hacks or workaround with udev rules to make it work without the modified hidapi?

HIDAPI has two backends, the "linux" backend and the "libusb" backend. Which backend is in use in apparently a compile-time option (which means you're at the mercy of whomever builds it). On Fedora, for example, it uses libusb. When using libusb, the path is a monotonically-increasing number without my patch. If it uses the linux driver then it's a dev/XXX path, which definitely can be made stable with udev.

I have not played with udev and libusb to see if it will create a stabilized path. I have a feeling the answer is no.

On the other hand, it also appears that hidapi is currently "unmaintained".

@ondrej1024
Copy link
Owner

The 16 channel HID compatible relay card which is discussed here has been discontinued by Sainsmart. Therefore no further effort will be spent to support this device.

@derekatkins
Copy link
Contributor Author

For the record, it looks like my changes to libhid/libusb have been pulled into a forked upstream, so I suspect this will take care of itself. Just because Sainsmart isn't selling these now doesn't mean people don't have them (I have multiple of them!).

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants