gary-rowe / hid4java

A cross-platform Java Native Access (JNA) wrapper for the libusb/hidapi library. Works out of the box on Windows/Mac/Linux.
MIT License
229 stars 71 forks source link

Reopen device #32

Closed xgonc closed 8 years ago

xgonc commented 8 years ago

Hello,

I developed a desktop application based on your wonderful library (many thanks!!).

I start the connection using:

public void open() throws IOException {
        if (!this.dev.open()) {
            throw new IOException();
        } else {
            report_size = dev.getFeatureReport(new byte[1000], report_id);
            if (report_size < 0) {
                throw new IOException();
            }
        }
    }

And close the connection like this:

public void close() {
        while (dev.isOpen()) {
            this.dev.close();
        }
    }

note that dev is of class HidDevice.

The device only uses the Feature Report to dialog with the host.

Sometimes (many times), the dev.open() method fails (return false), especially when the connection is opened a few seconds after it has been closed.

Physically the cables or device is not touched. This happens when the user chooses a device to connect (the application can handle several connections, one at a time), or, when the application is closed, and the connection is also closed (before the application).

The workaround is disconnect and reconnect the USB cable on the device....

My question, is if this is the proper way to close a connection? Is there something else that I should do to prevent errors in a re-connection?

Thanks.

gary-rowe commented 8 years ago

Hi @xgonc. Glad that you're finding the library useful. I've added some formatting to your issue.

There are a couple of things to note in your code example. You might want to add some extra error information through the dev.getLastErrorMessage(). The use of the open() and close() methods is the correct way to dispose of the resources being used and should be repeatable without error.

Are you using Windows 10 by any chance? It is possible that you may have run foul of the endless FILE_SHARE_READ | FILE_SHARE_WRITE requirement that prevents exclusive access by the low level hidapi native code. See https://github.com/signal11/hidapi/issues/231 for some background.

If that's the case then you may need to be more forceful when closing the library and also include a HidApi.exit(). This will unload the JNA wrapping library, and the low level hidapi native code and should free up the virtual file handles. You can then restart with HidApi.init() - this is especially true if you are using multiple threads/executors.

xgonc commented 8 years ago

Thanks for your advice. I was using Windows 7 and 8. I solved the issue by instantiating only one time the HidServices class. I was creating a new object every time the user wanted a connection.

begonaalvarezd commented 7 years ago

Hello! I am writing you because I have been days struggling with an error. I am experiencing the same issue as @xgonc . There is one special funcionality (all others work crossplatform but this one is not working on windows 7) that I have developed to update the firmware of a control board with which I am communicating with using your library. To be able to access the flashing mode of the board, I have to disconnect first from the board in normal mode (which has a productId = 0x0001 for example), and access the bootloader mode that lasts 2 seconds after the board is restarted, being this mode with productId = 0x1001. To do so, I send a restart command to the board, wait, and try to connect to the bootloader mode. This is working well under Ubuntu 14, Windows 8.1 and Windows 10 so far, but under Windows 7 it always throw the same exception:

java.io.IOException: Cannot read from USB device!

So, the error jumps in when I never unplug the usb but just send a restart command and try to connect ,BUT if I unplug and plug it again and try to flash the board withing those 2 seconds that the mode is open...it works!

This error seems very weird to me beacuse after deep debugging for days I have managed to see that when trying to connect to this bootloader mode after the restart command, which involves a disconnection of previous mode and re-connection to another mode (for the program a new USB device), the detection actually works but is the read() which fails returning getLastErrorMessage(): "device is not connected".

When trying to communicate I first do: `device = hidServices.getHidDevice(VENDOR_ID, deviceMode.getValue(), null);

if (device != null) { System.out.println("CONNECTED"); }`

Which prints CONNECTED on the bootloader mode!

But then, deviceRead() throws java.io.IOException: Cannot read from USB device!

`public byte[] deviceRead() throws IOException { final byte[] data = new byte[200]; int read = 0;

    read = this.device.read(data, 250);

    /* Error occurred - nothing read */
    if (read < 0){
        throw new IOException("Cannot read from USB device!");
        //read = 0;
        //System.err.println("USBHID LAST ERROR MESSAGE: " + device.getLastErrorMessage());
    }

    byte[] ret_val = new byte[read];
    for (int i = 0; i < read; i++)
        ret_val[i] = data[i];

    return ret_val;
}`

Due to

public static HidDeviceStructure open(String path) { Pointer p = hidApiLibrary.hid_open_path(path); return (p == null ? null : new HidDeviceStructure(p)); }

Is returning P = null.

Any help/idea/holy-light would be really really helpful. I am breaking my mind here trying to understand why is not working and I am pretty sure I am missing something important relating to your library proper use.

Have a great day!