Wednesday, March 10, 2010

rxtx and blocking

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

  1. It is fixed on HEAD, so you can use the latest pre-release version (2.2-series) or compile it from CVS.
  2. 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);

4 comments:

  1. Did you ever have any problem with the available() method hanging on the InputStream provided by the SerialPort object?

    ReplyDelete
  2. No, but I never really use available. Sounds rather buggy as the purpose of available() is to know how much to read without blocking!

    ReplyDelete
  3. I guess my problem is similar, I am using RXTX library to read from Serial Port, even though I have data on the Serial port but all it reads is -1. But when I user comm.jar I am able to read the data from the serial port.

    Do I need to set these values threshold and timeout to be able to read data from SerialPort using RXTX

    ReplyDelete
  4. Yes you need to try either solution 1 or 2 above. That or go for the 2.2 release where I think it is fixed. But still need to set threshold to 1 and timeout to 0.

    ReplyDelete