Closed Laivindur closed 4 years ago
Hi @Laivindur.
It might be that your Linux kernel doesn't have hidraw support enabled. hid4java
uses the hidraw variant of hidapi
on Linux so that Bluetooth devices can be picked up as a useful side effect. This is equivalent to compiling hidapi
and using the linux
libraries rather than the libusb
variants.
Devices matching hidraw will show up as something like: /dev/hidraw0
and conform the to udev rules. You might want to change these as follows:
KERNEL=="hidraw*", ATTRS{idVendor}=="0438", ATTRS{idProduct}=="5750", MODE="0666", GROUP="plugdev", TAG+="uaccess", TAG+="udev-acl"
(The TAG
entries are there for compatibility with systemd
)
Let me know if this helps.
Hi Gary
Thank you for answering the question so quickly. I think you hit the nail on the head. If I attach the HID to my laptop (Ubuntu 16 Xenial) (no matter the USB port), no /dev/hidraw*
is shown. Linux keeps treating the device as a usbfs
device and link it to /dev/bus/usb/00X
, I guess this is why Hid4java can not open the connection. There's no path to /dev/hidraw
.
I have edited my rules but, as expected, it didn't cause any change.
I also have installed hidraw libs for Ubuntu Xenial, restarted the computer, but nothing happened. So looks like I would have to compile the kernel, allowing compatibility with hidraw.
I've just pushed a variant of hid4java on the issue-97
branch. Can you check that out in git and build it locally using mvn clean install
. It'll appear in downstream projects as a local version of develop-SNAPSHOT
. It's a shot in the dark, but it may just solve the problem (and lead me to build a libusb/hidraw switch in the configuration for later).
Done.
Now, the lib is unable to find attached devices. hidServices.getAttachedHidDevices()
returns an empty list. I went back to the version 0.5.0 and executed the same test, and I got devices. Then back to the 0.6.1-SNAPSHOT and no devices were found.
OK, that's good to know. Thank you for getting back so quickly on this. I'll need a bit more time to think on why 0.5.0 works and this version doesn't.
FYI
We have tried the version 0.5.0 on Linux CenteOS. We have applied the rules as you have posted here. We gave grants to the user, installed the OS lib libusb
and finally we have executed the test. It worked!
We have inspected /dev
and indeed, there was an entry such as /dev/hidraw0
- We also have validated the device attached to the path and both vendor and product id matched with the expected ones.
On one hand, these are good news because it means hid4java should work in production. On the other hand, we still need to make it work in local, for us to develop the product.
That said, we appreciate your support. Hope we could take it forward one way or another.
Thank you in advance!
Hi @Laivindur,
I'll just summarise where we are with this:
/dev/hidraw*
entries, fails on all versions0.5.0
(using udev rules posted here and installing libusb
), fails with 0.6.0
and 0.6.1-SNAPSHOT
Is the above correct?
One thing that I just want to clear up. You mentioned a 0.6.1-SNAPSHOT
version. This was a temporary version on the master
branch and shouldn't appear anywhere as a test version. Can I verify that you are using branch issue-97
and its develop-SNAPSHOT
(built locally) for testing on Ubuntu 16.0? That version contains libraries for linux-amd64
and linux-x86-64
operating systems using libusb
rather than hidraw
.
If you run the UsbHidEnumerationExample
from the project using
mvn clean test exec:java -Dexec.classpathScope="test" -Dexec.mainClass="org.hid4java.examples.UsbHidEnumerationExample"
then the platform and architecture will be displayed to allow confirmation that the correct libraries are being used (it may be that we need versions for linux-aarch64
or something.
Just covering all bases here.
Hi Gary.
Regarding O.S, yes. Most of us use Ubuntu (laptops and desktops) and Test, Pre-Production and Production environments run on CenteOS.
Regarding the version 0.6.1-SNAPSHOT
, I checked out development
and immediately I checked out the branch issue-97
, then I compiled just with mvn clean package
.
After your last answer, I have executed your Maven statement and the output has been.
[...]
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Results :
Tests run: 0, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] --- exec-maven-plugin:3.0.0:java (default-cli) @ hid4java ---
Platform architecture: x86-64
Resource prefix: linux-x86-64
Starting HID services.
Enumerating attached devices...
Waiting 30s to demonstrate attach/detach handling. Watch for slow response after write if configured.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 32.728 s
[INFO] Finished at: 2020-08-07T14:33:06+02:00
[INFO] Final Memory: 26M/307M
[INFO] ------------------------------------------------------------------------
The build ends after 30 seconds. During this waiting time, I have plugged and unplugged the device with no result.
@gary-rowe had same issue, fixed by running with root
@iqorqua Did you run the code in the issue-97
branch as that is libusb specific. If not then you may need to adjust your udev rules for hidraw.
Hi @Laivindur. I've set up a CentOS 8 virtual machine to try to replicate your situation, but the out of the box installation supports hidraw
. I'm not quite sure how I can replicate your situation unless you can give me some further details.
You may be interested in issue #99 (see branch issue-99
) which covers a general purpose approach for activating libusb
libraries on Linux. It's kind of similar to the quick fix I knocked up earlier in terms of hidapi
compilation but it might help fix your issue.
Try the following
issue-99
branch.mvn clean install
to ensure all packages are downloaded and cached locally.LibusbEnumerationExample
code:
mvn clean test exec:java -Dexec.classpathScope="test" -Dexec.mainClass="org.hid4java.examples.LibusbEnumerationExample"
Note the use of HidApi.useLibUsbVariant = true;
within the example code. This triggers the variant selection during the init()
call.
Let me know how you get on.
Hi Gary. Sorry for the delate. I have been out for vacations.
Regarding CenteOS, you are right. It supports hidraw
by default and hid4java
works as intended. The problem is on Ubuntu, which has no hidraw
support out of the box. The mvn
output on my last post, I got it executing the maven statement on Ubuntu.
Summarizing
CenteOS
hid4java 0.5.0 works as intended. No security errors. Device detected. Allowed to read and write. Now we have to figure out how to read and write properly a device with I/O endpoints based on interruptions. Looks like we have to interact with the device in order to send data to the bus and pull the data from the Java app.
hid4java 0.6.0-SNAPSHOT not tested on CenteOS
Ubuntu 16
Right now, I'm still on vacations. I will be back the next week. As soon as I get to the office, (where I have the device we test with) I will proceed with the new branch issue-99
as you suggest and test on both O.S. I will let you know about the results asap.
Thank you again for the support and apologize for the inconveniences!
No problem. I'll leave this issue open. Let me know when you have to chance to review issue-99 as a potential fix.
Hi Gary.
I have tested issue-99
on Ubuntu Linux and this is what I got
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Results :
Tests run: 0, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] --- exec-maven-plugin:3.0.0:java (default-cli) @ hid4java ---
Platform architecture: x86-64
Resource prefix: linux-x86-64
Libusb activation: true
Starting HID services.
Enumerating attached devices...
Device attached: HidServicesEvent{hidDevice=HidDevice [path=0001:0008:00, vendorId=0x483, productId=0x5750, serialNumber=STM3210, releaseNumber=0x200, manufacturer=STMicroelectronics, product=STM32 Custm HID, usagePage=0x0, usage=0x0, interfaceNumber=0]}
HidDevice [path=0001:0008:00, vendorId=0x483, productId=0x5750, serialNumber=STM3210, releaseNumber=0x200, manufacturer=STMicroelectronics, product=STM32 Custm HID, usagePage=0x0, usage=0x0, interfaceNumber=0]
Waiting 30s to demonstrate attach/detach handling. Watch for slow response after write if configured.
So far, with the new flag and loading LibUsb native API, Hid4java is capable of detecting the device.
After this test, I have tried to use this new version in my proof of concept. I have tried to write a message
[INFO ] 2020-09-01 11:16:50.373 [main] Hid4JavaUtils - Starting HID services.
[INFO ] 2020-09-01 11:16:50.395 [main] UAHidDevice - HidDevice [path=0001:0008:00, vendorId=0x483, productId=0x5750, serialNumber=STM3210, releaseNumber=0x200, manufacturer=STMicroelectronics, product=STM32 Custm HID, usagePage=0x0, usage=0x0, interfaceNumber=0]
[INFO ] 2020-09-01 11:16:50.395 [main] UAHidConnectivityTest - UA: net.opentrends.abaxis.lab.ua.hid.UAHidDevice@e98770d
[INFO ] 2020-09-01 11:16:52.190 [main] UAHidDevice - is UA device open? false
Exception in thread "main" java.lang.IllegalStateException: Device has not been opened
at org.hid4java.HidDevice.write(HidDevice.java:395)
at net.opentrends.abaxis.lab.ua.hid.UAHidDevice.write(UAHidDevice.java:64)
at net.opentrends.abaxis.lab.ua.hid.UAHidDevice.process(UAHidDevice.java:27)
at net.opentrends.abaxis.lab.ua.hid.UAHidConnectivityTest.main(UAHidConnectivityTest.java:18)
Same error as with 0.5.0-RELEASE. Devices are detected but I'm unable to open connection. The statement HidApi.open(path);
keeps returning null for the device path 0001:0008:00
.
I have checked /dev
and the bus is there
cyeste@PR213:/dev/bus/usb/001$ lisa
total 0
139 0 drwxr-xr-x 2 root root 140 sep 1 10:52 .
138 0 drwxr-xr-x 3 root root 60 sep 1 07:59 ..
140 0 crw-rw-r-- 1 root root 189, 0 sep 1 07:59 001
322 0 crw-rw-r-- 1 root root 189, 1 sep 1 07:59 002
324 0 crw-rw-r-- 1 root plugdev 189, 2 sep 1 11:21 003
364 0 crw-rw-r-- 1 root root 189, 4 sep 1 07:59 005
575 0 crw-rw-rw- 1 root users 189, 7 sep 1 11:16 008
I achieved some progress
I went back to the 0.5.0 version on Ubuntu. I have tried to write and read and, of course, it didn't work because no connection was open.
I have compared lsusb -t
on both CenteOS and Ubuntu and I have realised that on CenteOS there was no driver assigned by the OS
/: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ehci-pci/8p, 480M
|__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/4p, 480M
|__ Port 1: Dev 3, If 0, Class=Hub, Driver=hub/4p, 480M
|__ Port 3: Dev 5, If 0, Class=Human Interface Device, Driver=, 12M
However, Ubuntu does bind the device to usbfs
driver
/: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ehci-pci/3p, 480M
|__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/8p, 480M
|__ Port 2: Dev 11, If 0, Class=Human Interface Device, Driver=usbfs, 12M
|__ Port 6: Dev 3, If 0, Class=Vendor Specific Class, Driver=, 12M
|__ Port 8: Dev 5, If 0, Class=Video, Driver=uvcvideo, 480M
|__ Port 8: Dev 5, If 1, Class=Video, Driver=uvcvideo, 480M
I have unbound my device from usbfs driver
root@PR213:~# echo -n "1-1.2:1.0" > /sys/bus/usb/drivers/usbfs/unbind
Once unbound, I have executed the proof of concept and it worked. The connection was open and I was allowed to write a message and read the response. Now I have to figure out how to read and write properly with buffers of 64 length
I have also discovered why Linux Ubuntu doesn't bind my device to usbhid
driver.
It's a bug related with fwupd. Sadly, I'm not sure I can upgrade this service in Ubuntu 16, since I already have the latest version for this distro/version. The fix is available for Ubuntu 18 and later.
So, If I stop fwupd
and then I attach the device, it's automatically bound to the usbhid
driver and mounted in /dev/hidraw0
.
cyeste@PR213:/etc/udev/rules.d$ lsusb -t
/: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ehci-pci/3p, 480M
|__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/8p, 480M
|__ Port 2: Dev 7, If 0, Class=Human Interface Device, Driver=usbhid, 12M
|__ Port 6: Dev 3, If 0, Class=Vendor Specific Class, Driver=, 12M
|__ Port 8: Dev 5, If 0, Class=Video, Driver=uvcvideo, 480M
|__ Port 8: Dev 5, If 1, Class=Video, Driver=uvcvideo, 480M
This time, I didn't unbind the device from the driver (usbhid). I have executed the same tests and worked properly.
Looks like the issue is not in the hid4java API. It's rather in the OS.
Hi @Laivindur - you've done some great investigative work here, well done!
Given that this problem seems to lie within Ubuntu 16 and appears to be fixed from Ubuntu 18 onwards I think this issue can be closed.
Hi @gary-rowe If you don't mind, I will summarize the steps to follow to solve this issue on Ubuntu 16 or earlier versions. Hope it helps.
On Ubuntu 16 (and probably earlier versions too), the device mentioned is only mounted as an usb
node (/dev/bus/usb/001/0XX
) and the OS assigns usbfs
driver to it. Due to this, hid4java
0.6.0 doesn't find any device attached.
A walkaround consists of downgrading hid4java
to 0.5.0
and unbind the device manually (/sys/bus/usb/drivers/usbfs/unbind
).
If we have created our udev
rules and the group and mode were loaded properly, at this point we should we able to detect attached devices, send and read data from them. If hid4java
find devices but it can't open connections, do review the udev
rules, you might be missing some matching. I have shared mines (step 4) for you to have a reference.
The real issue is at fwupd
service (Firmware updater) for versions prior to 1.0.1
. For more details, see my previous comment and follow the link.
Here the steps to follow to end up with a working environment compatible with hid4java
Stop fwupd
$> systemctl stop fwupd
Note: We can disable it too.
Create a new group named plugdev
.
$> groupadd plugdev
I assume we can skip this step if we already have a group for the user executing the java app.
Add the OS user to the new group (or the existing one)
$> sudo usermod -a -G <user_name> plugdev
Create /etc/udev/rules.d/50-my-hid.rules
(or choose any other file name, but don't change the prefix 50-
atm.)
$> sudo touch /etc/udev/rules.d/50-my-hid.rules
If you want to overwrite existing rules, change the prefix 50-
with 99-
. These files are loaded in alphabetical order.
Add the following rules to the rules files
KERNEL=="hidraw*", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="5750", MODE="0666", GROUP="plugdev", SYMLINK+="vetscan_ua_hidraw%n"
SUBSYSTEM=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="5750", MODE="0666", GROUP="plugdev", SYMLINK+="vetscan_ua_usb%n"
The first rule corresponds to the hidraw
node and the second to the usb
node of the same device. Each rule creates a different symlink. Both rules assign the same group and permissions to their corresponding nodes.
SYMLINK
are optional. I have created them for testing and because other USB libs for Java allow me to choose the path to the device.
Detach your device(s)
Reload udev rules
$> sudo udevadm trigger
Attach your device(s) again
Check the driver bound to the device (it should be usbhid
)
$> lsusb -t
/: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ehci-pci/3p, 480M
|__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/8p, 480M
|__ Port 2: Dev 17, If 0, Class=Human Interface Device, Driver=usbhid, 12M
|__ Port 6: Dev 3, If 0, Class=Vendor Specific Class, Driver=, 12M
|__ Port 8: Dev 5, If 0, Class=Video, Driver=uvcvideo, 480M
|__ Port 8: Dev 5, If 1, Class=Video, Driver=uvcvideo, 480M
Check /dev
$> ls -lisa /dev/hidraw*
572 0 crw-rw-rw- 1 root plugdev 242, 0 sep 3 11:04 /dev/hidraw0
$> ls -lisa /dev/vetscan_ua_*
577 0 lrwxrwxrwx 1 root root 7 sep 3 11:04 /dev/vetscan_ua_hidraw0 -> hidraw0
574 0 lrwxrwxrwx 1 root root 15 sep 3 11:04 /dev/vetscan_ua_usb2 -> bus/usb/001/017
Execute org.hid4java.examples.UsbHidEnumerationExample
Platform architecture: x86-64
Resource prefix: linux-x86-64
Starting HID services.
Enumerating attached devices...
HidDevice [path=/dev/hidraw0, vendorId=0x483, productId=0x5750, serialNumber=STM3210, releaseNumber=0x200, manufacturer=STMicroelectronics, product=STM32 Custm HID, usagePage=0x0, usage=0x0, interfaceNumber=0]
Waiting 30s to demonstrate attach/detach handling. Watch for slow response after write if configured.
Device detached: HidServicesEvent{hidDevice=HidDevice [path=/dev/hidraw0, vendorId=0x483, productId=0x5750, serialNumber=STM3210, releaseNumber=0x200, manufacturer=STMicroelectronics, product=STM32 Custm HID, usagePage=0x0, usage=0x0, interfaceNumber=0]}
Device attached: HidServicesEvent{hidDevice=HidDevice [path=/dev/hidraw0, vendorId=0x483, productId=0x5750, serialNumber=STM3210, releaseNumber=0x200, manufacturer=STMicroelectronics, product=STM32 Custm HID, usagePage=0x0, usage=0x0, interfaceNumber=0]}
Device detached: HidServicesEvent{hidDevice=HidDevice [path=/dev/hidraw0, vendorId=0x483, productId=0x5750, serialNumber=STM3210, releaseNumber=0x200, manufacturer=STMicroelectronics, product=STM32 Custm HID, usagePage=0x0, usage=0x0, interfaceNumber=0]}
Device attached: HidServicesEvent{hidDevice=HidDevice [path=/dev/hidraw0, vendorId=0x483, productId=0x5750, serialNumber=STM3210, releaseNumber=0x200, manufacturer=STMicroelectronics, product=STM32 Custm HID, usagePage=0x0, usage=0x0, interfaceNumber=0]}
Try to send data to the device and read the response.
If we combine usb4java and hid4java we will find that when usb4java's class UsbDevice claims the interface, the OS releases the hid node. In consequence, /dev/hidraw0
is no longer available and hid4java (0.6.0) no longer finds device attached.
We can use usb4java
to detect attachments and detachments, to get access to the device attributes such as idVendor
, idProvider
and serialNumber
and use these values to find our hid device via hid4java
. But if use usb4java
to read and write, we might find that hid4java
no longer finds devices or those that were loaded and connected are no longer available.
hid4java
to connect with USB devices with hid
nodes (interfaces)usb4java
to connect with USB devices with usb
nodes (interface)No problem. I'm thinking of moving a lot of information in the README into the project's wiki, so if you're OK I'll include your analysis above (with all credit to you for your work).
Sure, get all the info you need, just don't copy & paste. My English is horrible.
Hello Gary!
I have recently tried to add Hid4Java to our project since we will start to work with some custom HID device. We need to be able to detect attachments, detachments and, how not, send and receive data.
Following your examples, we concluded that hid4java allows us to detect attachments and detachments, but for some reason, we are unable to open the connection with the device.
As shown in your examples, we first start the service, iterate over the current attachments, we filter by vendor and product ids to find our HID and finally proceed to open the connection. But we get "false" from HidDevice.open().
Debugging the code, we find that
HidApi.open(path)
is also returning null. There's apath
to look for, but for some reason,HidApiLibrary.hid_open_path(path)
is not returning aPointer
, hence noHidDeviceStructure
is built and no connection is possible.As suggested, we also added our rules in /etc/udev/rules.d since we are working with Linux. Ubuntu and CenteOS mainly.
These are the outputs of some of the OS tools
Note that the OS bound the driver usbfs not hid nor hid-generic.
And
What do you think it's happening? What else can we do/try/test ?
Feel free to ask me for anything you need.
Thank you in advance