简体   繁体   中英

Java subprocess built using ProcessBuilder looses data from serial port

I'm trying to read data from the serial port in a subprocess inside a Java application. Here is the code I'm currently using:

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;

public class Text {
    public static void main(String... arguments) throws IOException, InterruptedException {
        Process pb = new ProcessBuilder().command("/bin/sh", "-c", "(stty raw; cat) < /dev/ttyAMA0").start();
        final Scanner scanner = new Scanner(new InputStreamReader(new BufferedInputStream(pb.getInputStream())));

        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                while (scanner.hasNextLine()) {
                    System.out.println(scanner.nextLine());
                }
            }
        });

        t.start();
        pb.waitFor();
    }
}

The idea is the following: I wan't to rely on the operating system (here a Raspbian on a Raspberry Pi) to send me raw input from the serial port. I therefore launch a subprocess that sets the serial port to RAW mode using stty, and forward data using cat. This trick works perfectly on the command line. If I then redirect stdout to a Java program, data flows correctly to its input stream.

The problem here is that using this code to get data to a subprocess (not the stdin of the Java programm, you guessed it), I'm loosing characters. I expect lines of 10 numbers of 3 digits, separated by commas, and I get between 4 and 6 numbers, sometimes followed by a comma.

I think there's a buffering issue, my Java application might not be able to empty the (very limited) serial port buffer.

Is there something I could do Java wise, or should I turn to the Linux kernel geeks for some OS tricks here?

Thanks,

Mathieu

Try to flush after writing, I guess that this is why you "loose" data :)

while (scanner.hasNextLine()) {
    System.out.println(scanner.nextLine());
    System.out.flush();
}

Just a hack, but try this. The stdout from cat is buffered by default, but what you want is an unbuffered stream . Try to change the line:

(stty raw; cat) < /dev/ttyAMA0

to

(stty raw; cat -u) < /dev/ttyAMA0

Ok, I got the code working, using input from there: https://unix.stackexchange.com/questions/40005/alternate-fifo-device-for-linux-with-a-way-bigger-buffer-while-still-having-fi

What we want here is a bigger buffer between the (not so many bytes) serial port buffer and the next command in the pipe. Given I expect a 82 bytes line all inclusive, I use the buffer -s 82 -b 2 command, which allows two blocks of one line to be stored in shared memory between every scanner nextLine call.

Here is the full demo, which should delight every Raspberry Pi owner trying to read serial data in Java (am I the only one?):

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;

public class Text2 {
    public static void main(String... arguments) throws IOException, InterruptedException {
        Process pb = new ProcessBuilder().command("/bin/sh", "-c", "(stty raw; cat | buffer -s 82 -b 2) < /dev/ttyAMA0").start();
        final Scanner scanner = new Scanner(new InputStreamReader(new BufferedInputStream(pb.getInputStream())));

        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                while (scanner.hasNextLine()) {
                    System.out.println(scanner.nextLine());
                }
            }
        });

        t.start();
        pb.waitFor();
    }
}

This expects the buffer utility, easily installed typing sudo apt-get install buffer This also relies on some tricks to enable onboard serial port as in https://github.com/lurch/rpi-serial-console

Thanks brettw for the input that led there, even if it didn't work in the first place.

Mathieu

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM