从另一个线程传输数据,与 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 库的慢速串行链接的主要内容,如果未能解决你的问题,请参考以下文章