【问题标题】:continuing communication with serial device using RXTX and Java使用 RXTX 和 Java 继续与串行设备通信
【发布时间】:2012-12-05 13:50:31
【问题描述】:

我需要修改 RXTX“基于事件的双向通信”(请参阅​​http://rxtx.qbang.org/wiki/index.php/Event_based_two_way_Communication),以便我能够将特定响应写回串行设备,了解其先前的消息。

我通过发送第一个命令开始通信。到目前为止一切正常。现在我从串行设备得到答案。我用进一步的命令对答案做出反应。但是我不能再写了,因为写线程已经结束了。

有人知道如何处理这个问题吗? 非常感谢!

public class TwoWaySerialComm {
    public TwoWaySerialComm() {
        super();
    }

public static void main(String[] args) {
        try {

            // 0. call connect()
            (new TwoWaySerialComm()).connect("COM1");

        } catch (Exception e) {
            e.printStackTrace();
        }
}

void connect(String portName) throws Exception {

                // 1. get CommPortIdentifier, open etc...

                // 2. then do
                InputStream in = serialPort.getInputStream();
                OutputStream out = serialPort.getOutputStream();

                // 4. start writer thread
                (new Thread(new SerialWriter(out))).start();

                // 5. instantiate SerialReader 
                serialPort.addEventListener(new SerialReader(in));
                serialPort.notifyOnDataAvailable(true);

}

public static class SerialWriter implements Runnable {

        OutputStream out;

        public SerialWriter(OutputStream out) {
            this.out = out;
        }

        public void run() {
            try {

                // establish a communication by sending the first command. the serial device will answer!   
                String toSend = "blablabla";
                this.out.write(toSend);

                // thread ended???

}

public static class SerialReader implements SerialPortEventListener {

        private InputStream in;

        public SerialReader(InputStream in) {
            this.in = in;

        }

        public void serialEvent(SerialPortEvent arg0) {

            // event occurs beacause device answers after writing.

            int data;

            try {

                StringBuffer sb = new StringBuffer();
                String LineOfData=null;

                while ((data = in.read()) > -1) {

                    if (data == '\n') {
                        break;
                    }

                    sb.append(Integer.toHexString(data));
                    LineOfData = sb.toString();

                }
                // I store the answer and send it to an EventIterpreter. Regarding the answer, it creates an appropriate response itselves.
                EventInterpreter e = new EventInterpreter(LineOfData);  
                String result = e.getData

HERE >> // Now I want to send this response back to the device. But the thread is already ended.


            } catch (IOException e) {
                e.printStackTrace();
                System.exit(-1);
            }
        }

  }

}

【问题讨论】:

    标签: java serial-port rxtx


    【解决方案1】:

    不要让运行 SerialWriter 的线程结束。

    在原始示例中,您会注意到SerialWriterrun() 方法内部有一个while (System.in.read() != -1)。这很重要。运行它的线程在read()阻塞,然后,一旦它有一些数据要读取,它就会做一些工作,然后循环回到同一个位置,等待更多的输入。这是一个不应该在正常情况下完成的线程。

    至关重要的是,编写器的非守护线程正在运行这一事实意味着,当您的主线程(JVM 用来启动程序的线程)用完 connect() 方法中的语句时,JVM 不会立即关闭。

    串口在自己的线程上回调你

    serialPort 调用侦听器的public void serialEvent(SerialPortEvent) 方法时,它会在自己的线程中这样做

    您现在的任务是尽快离开serialPort 的线程。几乎,读取数据,将其粘贴在缓冲区中,您的另一个线程可以在空闲时对其进行解析和操作,同时让 serialPort 继续处理通信。你当然不应该尝试在它自己的线程上调用你时写入串行端口。它没有任何状态回复你,因为它在等待你完成!

    你希望你的“作家”线程“等待”,直到有东西要回复

    您可以通过提供“锁定”对象来进行安排。由于这些都是现代的,请使用:

    import java.util.concurrent.locks.*;
    
    // accessible to both reader and writer
    ...
    Lock lock = new ReentrantLock();
    Condition dataAvailable = lock.newCondition();
    byte[] buffer;
    
    // in the writer
    ...
    public void run() {
        while(true) {
            lock.lock();
            try {
                dataAvailable.await();  // writer thread dozes
                doStuff(buffer);
            } finally {
                lock.unlock();
            }
        }
    }
    
    
    // in the reader
    ...
    public void onEvent() {
        lock.lock();
        try {
            buffer = readData();
            dataAvailable.signal();   // writer thread wakes up
        } finally {
            lock.unlock();
        }
    }
    

    阅读一本关于并发的好书

    并发很棘手。你会想阅读Java Concurrency in Practice

    当您尝试剪切粘贴上面的代码示例时,您会注意到Condition#await() 抛出InterruptedException。究竟该怎么做超出了这个答案的范围。 :-) while(true) 也有点狡猾。

    【讨论】:

    • 感谢您的回答。我在 SerialReader 中插入了 while 循环。 ` public void run() { try { int c = 0; while ( ( c = System.in.read()) > -1 ) { String toSend = "blablabla"; this.out.write(toSend); } ` 但是作者没有进入while。也许是因为之前没有写入任何数据而没有数据进入?为什么它是 System.in.read() 而在 Reader 中它只是 in.read()?您是否看到除了 java.util.concurrent 之外的任何其他选项,因为该应用程序适用于本机 Java 1.4 环境?
    • 是的,你必须通过你的操作系统输入一些东西,否则 System.in.read() 将返回 -1 并退出循环。大多数操作系统进程都有“输入”和“输出”管道的概念。例如。 Unix shell 中的cat /var/opt/myfile | less 将 myfile 的内容连接到“less”命令。不过,在您的场景中,您确实希望编写器线程等待读取器线程设置的条件。
    • Java 1.4?哇,那是很久以前的事了。在这种情况下,请阅读Doug Lea's 书籍Concurrent Programming in Java,他将向您展示如何使用java.lang.Threadsynchronized 关键字以及Object.wait()Object.notify() 完成它。给它一两个星期的时间来解决它。 :-) 这是好东西。但是,您可能仍想阅读 Java Concurency in Practice 一书的早期章节,因为它涉及到 1.4 后 JVM 中有关内存一致性的一些更改。
    • Doug Lea 有一些 concurrency utilities,它们构成了 J2SE 5.0 SDK 中 java.util.concurrent 实用程序的基础。它们提供了一个ReentrantLock,它实现了Sync 接口,这与我上面提到的Lock 类非常相似。他在书中详细介绍了它们是如何使用的,它们应该与 1.4 一起使用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多