2

In SerialPort.java, I would like to know the following on writeBytes and readBytes methods:

  • Would those block?
  • How to interpret the return --boolean-- code?
dsolimano
  • 8,870
  • 3
  • 48
  • 63

1 Answers1

3

For reading (I'm using version 2.8.0) there are also methods like readBytes(int byteCount, int timeout) where you can specify a timeout. For reading the better approach might be to register a SerialPortEventListener. In fact I have never tried to uses readBytes directly outside of it.

The boolean return code must be true for the writing methods. The reason for this is the return code coming from the C++ JNI implementation behind. No exception is thrown in the JNI part, better would be also an exception here.

If you look into the Java code of e.g. writeBytes(byte[] buffer) only the first line is throwing a SerialPortException, the actual transmission is handled with the boolean return code:

this.checkPortOpened("writeBytes()");
return this.serialInterface.writeBytes(this.portHandle, buffer);

The write part can block, e.g. if the serial port is not responding. I have used a thread to prevent this, something like this:

private static class BackgroundWriter implements Callable<Boolean> {

    private SerialPort serialPort;

    private String atCommand;

    public BackgroundWriter(SerialPort serialPort, String atCommand) {
        this.serialPort = serialPort;
        this.atCommand = atCommand;
    }

    @Override
    public Boolean call() throws Exception {
        // add carriage return
        boolean success = serialPort.writeString(atCommand+"\r");
        return success;
    }
}

and later call it with a timeout:

ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<Boolean> writeResult = executorService.submit(new BackgroundWriter(serialPort, atCommand));
boolean success;
try {
    success = writeResult.get(writeTimeout, TimeUnit.MILLISECONDS);
} catch (Exception e) {
    if (serialPort != null && serialPort.isOpened()) {
        try {
            serialPort.closePort();
        } catch (SerialPortException e2) {
            LOGGER.warn("Could not close serial port after timeout.", e2);
        }
    }
    throw new IOException("Could not write to serial port due to timeout.", e);
}
if (!success) {
    throw new IOException("Could not write to serial port [" + serialPort.getPortName() + "]");
}
k_o_
  • 5,143
  • 1
  • 34
  • 43
  • I get a whole bunch of Background Writer threads left behind with this approach - one for every attempt at writing to the serial port with nothing attached. Is there a nice way of interrupting them? – Julian Wright Oct 22 '18 at 11:27
  • The `ExecutorService executorService = Executors.newSingleThreadExecutor();` should be only called once globally somewhere. My expectation would be then that only single thread is executed and all submitted `BackgroundWriter` are garbage collected later if the JVM needs memory. Otherwise there is something hanging a a not removed reference preventing this. – k_o_ Oct 22 '18 at 19:40