Fazecast / jSerialComm

Platform-independent serial port access for Java
GNU Lesser General Public License v3.0
1.35k stars 287 forks source link

serialPort.closePort() hangs #237

Closed jacob3636 closed 5 years ago

jacob3636 commented 5 years ago

I am using Windows 10 64bit, JDK 12, jSerialComm-2.5.1.jar, and using addDataListener() to read from the port. I tried to close without removeDataListener() and it hangs on closePort(), when I try removeDataListener just before the close it hangs on the removeDataListener. Here is the code I use:

public void closeConnection() throws IOException { if (jsserialPort != null) {

        try {
            outputStream.flush();
            outputStream.close();
            inStream.close();
        } catch (IOException e) {
            LOGGER.log(Level.WARNING, "When flushing output before closing serial.", e);
        }

    // Note: with removeDataListner() it hangs here
        jsserialPort.removeDataListener();

    // Note: if I remove removeDataListner() it hangs on closePort
        jsserialPort.closePort();
        jsserialPort = null;
    }

}

hedgecrw commented 5 years ago

Afternoon! I have the same setup as you and am unable to replicate. Would you mind posting your full code listing (just the parts relevant to jSerialComm functionality)? Also, what kind of device are you reading from?

jacob3636 commented 5 years ago

Thanks a bunch for your quick response.

Since the hang occurs only at a particular condition, I created a test bed which you can use to duplicate the problem I am having. The following github link provides the source code and instruction on how to run the test: https://github.com/aba36/jSerialCommTestBed

Let me know if you need anything else.

hedgecrw commented 5 years ago

Wow, thanks so much for putting this together! Will make debugging much simpler. I will let you know what I find.

hedgecrw commented 5 years ago

OK, here's what I found. The problem is that the event handling method inside your data listener (private void serialEvent()) never returns once it starts reading. This is due to the port being set up to block forever until at least one byte is read and the following line in parseInput(BufferedReader inBuf): while ((rawInput = inBuf.read()) != -1). Essentially, once you start reading, this inner while-loop will block forever waiting for the next byte to come in, which means that jSerialComm is unable to remove the data listener since it is in active use (and closing the port before removing your listener would result in exceptions in your listener due to it trying to reference a no-longer open port).

The quickest fix would be to ensure that your listener is allowed to return after all available bytes have been read by simply changing the line while ((rawInput = inBuf.read()) != -1) to if ((rawInput = inBuf.read()) != -1)

A better solution would be to remove the parseInput(BufferedReader inBuf) method and all of the BufferedReader stuff altogether, and simply perform all reading directly from the InputStream in your readSerial() method, like so:

private void readSerial()
{
    int rawInput = -1;
    try {
        while ((inStream.available() > 0) && ((rawInput = inStream.read()) != -1))
            System.out.print((char) rawInput);
    }
    catch (IOException e) {
        e.printStackTrace();
    }
}

Hope that helps!

jacob3636 commented 5 years ago

Hi Will, Thanks a bunch for your attentiveness and quick response to my problem. Your suggestion worked perfectly.

As a courtesy to other developers who may find it difficult to get all of the serial port little details for a fully working project, I updated the test bed as per your recommendations. The test bed can now be used as a fully working project to show all of the details required to write, read, and close a serial port. the project also includes a plug for jSerialComm which is working very well for me.

Please feel free to link to the test bed from the jSerialComm web site. The github link is: https://github.com/aba36/jSerialCommTestBed

Thanks a bunch for all of your hard work. Jacob