Writing this down so that others (and me too when I’ve forgotten about it again) could hopefully save an hour or two when trying to figure out a problem they are having with serial port communication using the rxtx libraries. Some hits on this on Google but not many(any?) with the complete description and solution of the problem.
The problem
If you ever tried using the serial port libraries for java, rxtx.org, you might have encountered a … different way of (sort of) handling blocking I/O. It can sort of be non-blocking, returning –1 on reads if nothing is available.
The rxtx way
But surely the rxtx library has thought of this and there is some way of setting this up or use it so it works for the simple blocking read case? Of course. This is how it is supposed to work: You have two parameters to play with: timeout and threshold. According to the source code setting the timeout to 0 (none) and threshold to 1 (requiring at least 1 byte before returning) should give us normal, by InputStream defined, blocking reads.
Still doesn’t work!
The problem is that even when setting it up like this there is a bug in the current stable release (2.1.7r2). The threshold parameter is always set to 0!From the source code:
/* TESTING ttyset.c_cc[ VMIN ] = threshold; */
ttyset.c_cc[ VMIN ] = 0;
The confusing part is that this was also the case in 2004 and reported on the mailing list and fixed, but it was either not really fixed or has come back again (a regression). There is actually a new bug report that for some reason I couldn’t find at first. I eventually found it going throw the pre-release package source code and found an otherwise not published change log (the web page doesn’t show change logs after the last stable version, its available in CVS though).
Solution
- It is fixed on HEAD, so you can use the latest pre-release version (2.2-series) or compile it from CVS.
- Make an ugly workaround along the lines of:
int read(InputStream in) throws IOException {
int b;
while ((b=in.read()) == -1) {
try { Thread.sleep(10); } catch (InterruptedException e) { }}
return b;
}
Then you do: read(in) instead of in.read().
And/or do a readFully version for byte arrays, read(byte[]) or similar:
byte[] data = new byte[length];
int read = 0;
do {
int n = in.read(data, read, length-read);
read += n;
} while (read < length);