从另一个线程传输数据,与 Java 和 RXTX 库的慢速串行链接

Posted

技术标签:

【中文标题】从另一个线程传输数据,与 Java 和 RXTX 库的慢速串行链接【英文标题】:Transmitting data from another thread, slow serial link with Java and RXTX library 【发布时间】:2014-12-30 19:51:57 【问题描述】:

好的,我会尽量说明我的问题。 我正在通过非常慢的无线电链路传输串行数据(使用树莓派上的 UART 控制器和自制无线电)。它适用于一个非常具体的项目,其中要求拼写为 long range 并且速度不太重要。 该程序 (Radio.java) 正在运行两个线程。一个线程(接收器)使用 TCP 套接字(速度非常快,实际上是 100mbit)从另一个程序接收遥测数据。该线程不断地将它在 TCP 套接字上接收到的数据保存在 ArrayBlockingQueue(大小 = 1)中,以便其他线程(发送器)可以访问该数据。 Receiver-thread 接收数据的速率非常高。现在,我希望 Transmitter-thread 传输数据完成后我希望它再次从 Receiver-thread 获取最新数据并通过慢速无线电链路再次传输。 所以在发射器线程中我希望它像这样工作:

    从 Receiver-thread 获取最新数据

    通过无线电链路传输数据(使用串行端口)

    在数据实际传输之前不要做任何事情。

    重复。

现在,当我运行程序时,有关接收器线程的所有内容都可以正常工作。但在发射器线程内,“this.out.write(output.getBytes());”行只需在几毫秒内将所有内容放入 OutputStream 中,然后再次执行相同的操作。数据没有机会被传输!

我在这里尝试了示例(仅使用“SerialWriter”-thread): http://rxtx.qbang.org/wiki/index.php/Two_way_communcation_with_the_serial_port

并且使用长的“Lirum Ipsum”-文本在 50 波特传输时一切正常。所以基本上,我希望我的程序中的行为与使用 System.in.read > -1... 相同(我猜这是阻塞,它起作用的原因???)。

我该怎么办?

2015-01-01 编辑开始

我发现了问题! SRobertz 带领我走向正确的方向!问题实际上不在于 UART 缓冲区的写入速度。运行“TwoWayComm”示例和我自己的代码之间的区别在于我正在运行连接到 Raspberry Pi 的 UART-RX 端口的 GPS。要从 GPS 读取数据,请使用“GPSD”软件(以 JSON 格式输出数据)。 GPSD 软件以 9600 波特(专门用于这个 GPS 单元)连接到 GPS,而我在同一端口上切换到 50 波特(没有关闭 GPSD 正在运行的开放连接)!试图以两种不同的波特率打开 ​​UART 是把一切都搞砸了。 我重写了代码,以便:

    以 9600 波特打开 UART 读取 GPS 数据 关闭 UART 以 50 波特打开 UART 将遥测数据传输到 UART 关闭UART 重复

现在一切都像一个魅力......

2015-01-01 编辑结束

所以...这里是代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ArrayBlockingQueue;

import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;

public class RADIO 
    ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<String>(1);

    void connect(String portName) throws Exception 

        CommPortIdentifier portIdentifier = CommPortIdentifier
                .getPortIdentifier(portName);
        if (portIdentifier.isCurrentlyOwned()) 
            System.out.println("Error: Port is currently in use");
         else 
            int timeout = 2000;
            CommPort commPort = portIdentifier.open(this.getClass().getName(),
                    timeout);

            if (commPort instanceof SerialPort) 
                SerialPort serialPort = (SerialPort) commPort;
                serialPort.setSerialPortParams(50, SerialPort.DATABITS_7,
                        SerialPort.STOPBITS_2, SerialPort.PARITY_NONE);

                // Open outputstream to write to the serial port
                OutputStream out = serialPort.getOutputStream();

                (new Thread(new Receiver(queue))).start();
                (new Thread(new Transmitter(out, queue))).start();

             else 
                System.err.println("Error: Not serial port.");
            
        
    

    public static class Receiver implements Runnable 
        OutputStream out;
        protected ArrayBlockingQueue<String> queue = null;

        public Receiver(ArrayBlockingQueue<String> queue) 
            this.queue = queue;
        

        public void run() 
            // Open TCP-connection
            try 
                ServerSocket serverSocket = new ServerSocket(1002);

                Socket clientSocket = serverSocket.accept(); // Wait for the client to start up
                BufferedReader in = new BufferedReader(new InputStreamReader(
                        clientSocket.getInputStream()));
                String inputLine, outputLine;

                while ((inputLine = in.readLine()) != null) 
                    queue.clear();
                    queue.put(inputLine);
                
             catch (IOException e) 
                e.printStackTrace();
             catch (InterruptedException e) 
                // TODO Auto-generated catch block
                e.printStackTrace();
            

        
    

    public static class Transmitter implements Runnable 
        OutputStream out;
        protected ArrayBlockingQueue<String> queue = null;
        String output = "";

        public Transmitter(OutputStream out, ArrayBlockingQueue<String> queue) 
            this.out = out;
            this.queue = queue;
        

        public void run() 
            try 
                while (true) 
                    output = queue.take();
                    this.out.write(output.getBytes());
                

             catch (InterruptedException e) 
                // TODO Auto-generated catch block
                e.printStackTrace();
             catch (IOException e) 
                // TODO Auto-generated catch block
                e.printStackTrace();
            
        

    

    public static void main(String[] args) 
        try 
            (new RADIO()).connect("/dev/ttyAMA0");
         catch (Exception e) 
            e.printStackTrace();
        
    

【问题讨论】:

【参考方案1】:

(一个小警告:我没有在树莓派上使用过 gnu.io)

首先,为了隔离问题,我会在发送线程中放一个相当长的sleep,在this.out.write...之后验证问题是不是在等待串口 完成传输。

如果可行,那么您可以尝试等待OUTPUT_BUFFER_EMPTY,方法是添加一个 SerialPortEventListener 和设置notifyOnOutputEmpty(true),让你的 SerialPortEventListener 类似的监视器

class ExampleMonitor implements SerialPortEventListener 
  boolean condition;

  public synchronized serialEvent(SerialPortEvent ev) 
    condition = true;
    notifyAll();
  

  public synchronized void awaitCondition() throws InterruptedException 
    while(!condition) wait();
    condition = false;
  

然后做

myExampleMonitor.awaitCondition() 而不是传输线程中的sleep

请参阅http://rxtx.qbang.org/wiki/index.php/Event_based_two_way_Communication 了解事件的反向使用(请注意,那里没有监视器,也没有等待;相反,工作是在侦听器/回调中完成的。)

【讨论】:

糟糕,我的监视器示例中有错字,现在已编辑。对不起。

以上是关于从另一个线程传输数据,与 Java 和 RXTX 库的慢速串行链接的主要内容,如果未能解决你的问题,请参考以下文章

Linux 下开源RXTX库的配置与使用

使用RXTX获取电脑串口

Java串口通信——RXTX

java 串口通信 rxtx的使用

用java多线程实现服务器与客户端之间的文件传输的代码!!!急!!!!

java串口助手开发记录