使用ProcessBuilder构建的Java子进程会丢失来自串行端口的数据

时间:2013-09-17 12:39:59

标签: java linux serial-port subprocess raspberry-pi

我正在尝试从Java应用程序内的子进程中的串行端口读取数据。这是我目前正在使用的代码:

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();
    }
}

这个想法如下:我不想依赖操作系统(这里是Raspberry Pi上的Raspbian)来从串口发送原始输入。因此,我启动了一个子进程,使用stty将串口设置为RAW模式,并使用cat转发数据。这个技巧在命令行上完美运行。如果我然后将stdout重定向到Java程序,则数据会正确地流向其输入流。

这里的问题是使用这段代码将数据传递给子进程(而不是Java程序的stdin,你猜对了),我正在丢失字符。我希望用逗号分隔的10个3位数的行,我得到4到6个数字,有时后面跟一个逗号。

我认为存在缓冲问题,我的Java应用程序可能无法清空(非常有限的)串口缓冲区。

我有什么可以做Java的事情,或者我应该转向Linux内核极客来获取一些操作系统技巧吗?

谢谢,

马修

3 个答案:

答案 0 :(得分:0)

写完后尝试冲洗,我想这就是你“松散”数据的原因:))

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

答案 1 :(得分:0)

只是一个黑客,但试试这个。来自cat的stdout默认是缓冲的,但你想要的是一个无缓冲的流。尝试更改该行:

(stty raw; cat) < /dev/ttyAMA0

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

答案 2 :(得分:0)

好的,我使用了来自https://unix.stackexchange.com/questions/40005/alternate-fifo-device-for-linux-with-a-way-bigger-buffer-while-still-having-fi

的输入,使代码正常工作

我们想要的是(不是那么多字节)串口缓冲区和管道中的下一个命令之间的更大缓冲区。鉴于我期望一个82字节的行全包,我使用buffer -s 82 -b 2命令,它允许一行的两个块存储在每个扫描器nextLine调用之间的共享内存中。

这是一个完整的演示,应该让每个试图读取Java中的串行数据的Raspberry Pi所有者高兴(我是唯一一个吗?):

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();
    }
}

这需要buffer实用程序,轻松安装,输入sudo apt-get install buffer 这也依赖于一些技巧来启用板载串行端口,如https://github.com/lurch/rpi-serial-console

感谢brettw带来的输入,即使它首先不起作用。

马修