我需要修改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);
}
}
}
}
答案 0 :(得分:1)
在原始示例中,您会注意到while (System.in.read() != -1)
的{{1}}方法中有run()
。这很重要。在SerialWriter
上运行它的线程阻止然后,一旦它有一些数据需要读取,它会做一些工作,然后循环回到同一个地方,等待更多的输入。这是一个在正常条件下不能假设的线程。
重要的是,编写器的非守护程序线程正在运行这一事实意味着,当您的主线程(JVM用于启动程序的线程)用完connect()方法中的语句时,JVM不会立即关闭。
当read()
调用您的侦听器的serialPort
方法时,会在其自己的线程上执行此操作。
您的任务现在是尽快离开serialPort的线程。几乎,读取数据,将其粘贴在缓冲区中,您的另一个线程可以在其中解析并在闲暇时对其进行操作,同时让serialPort继续处理通信。当你在自己的线程上调用时,你当然不应该尝试写入串口。没有任何状态可以回复你,因为它等着你完成!
通过提供“锁定”对象来安排。由于这些是现代的,请使用:
public void serialEvent(SerialPortEvent)
并发很棘手。您需要阅读Java Concurrency in Practice。
当您尝试切断上面的代码示例时,您会注意到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();
}
}
抛出Condition#await()
。究竟如何处理这个问题超出了这个答案的范围。 :-) InterruptedException
也有点狡猾。