Fazecast / jSerialComm

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

InputStream.read() returns SerialPortTimeoutException instead of -1 when end of stream is reached #534

Closed mvalla closed 8 months ago

mvalla commented 11 months ago

I have a test case when, after receving a LISTENING_EVENT_DATA_RECEIVED event, I read() the InputStream in a while loop ultil there is data to read. But instead of receiving -1 (since there are no more byes being received on the SerialPort), I get a SerialPortTimeoutException. This behavior is differenent from, for example, RxTx (NRJavaSerial) where a -1 is received instead when the end of stream is reached. Also, form the documentation it is written that: _Also note that if the serial port has an event-based data listener actively registered for the event type LISTENING_EVENT_DATA_RECEIVED, all serial port timeout settings are ignored._ So why a SerialPortTimeoutException is thrown?

hedgecrw commented 11 months ago

About the documentation note that "all serial port timeout settings are ignored" when using LISTENING_EVENT_DATA_RECEIVED, that means that all of the user-specified timeout settings are ignored...there are still library-enforced timeouts being used under the hood. The reason you are encountering this issue is that you are trying to mix event-based data reading with synchronous data reading (e.g., waiting for LISTENING_EVENT_DATA_RECEIVED while also using read()). The intent here is for you to use one or the other.

If you want to use event-based data reading, then only handle the data passed to you explicitly in your event listener callback function. If you want to use synchronous reading, but you only want to read when there is data available, then change your listener to respond to LISTENING_EVENT_DATA_AVAILABLE messages instead.

mvalla commented 11 months ago

Ok I changed to LISTENING_EVENT_DATA_AVAILABLE + InputStream.read() in a while(true) loop. However, differently from RxTx (NRJavaSerial) where a -1 is returned by read() when the end of stream is reached (=no more data to read in the InputStream), here with jSerialComm -1 is never returned. Why -1 is never returned? Isn't it defined in the InputStream contract? How should I then detect when to exit the while(true) loop to read the InputStream? Thanks for any suggestion.

hedgecrw commented 11 months ago

This library interprets "end of stream" as meaning that there is no additional data that might come in on the stream (in other words, when the stream is closed). If the stream is not closed, then reading using an InputStream will simply wait for the next data byte to come in or until the read has timed out according to any timeouts you may have specified in setComPortTimeouts().

The solution is to either:

  1. Not use an InputStream within an asynchronous callback. Instead, read the exact amount of bytes available to you as shown in the Usage Example: https://github.com/Fazecast/jSerialComm/wiki/Event-Based-Reading-Usage-Example#data-available-for-reading-example
  2. Set a read timeout on the port, so that your InputStream.read() call will throw a SerialPortTimeoutException when no data is available after some time.

Of the above two options, Option 1 is much preferred as it is generally a bad idea to make a blocking call within an asynchronous callback. Hope that helps!

hedgecrw commented 8 months ago

Closing as "nothing to fix"