简体   繁体   中英

continuing communication with serial device using RXTX and Java

I need to modify the RXTX "Event Based Two Way Communication" (see http://rxtx.qbang.org/wiki/index.php/Event_based_two_way_Communication ) so that I am able to write a specific response back to the serial deivce regarding its previous message.

I start the communication by sending the first command. everything works fine so far. now I get an answer from the serial deivce. I react to the answer with a further command. But I can't write it anymore because the write-thread is already ended.

Anybody an idea how to handle this? Thanks a lot!

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

  }

}

Don't let the thread running the SerialWriter finish.

In the original example you'll notice that there is a while (System.in.read() != -1) inside the run() method of the SerialWriter . That's important. The thread running it blocks on the read() and then, once it has some data to read, it does some work and then loops back to the same spot, waiting for some more input. It's a thread that isn't supposed to finish under normal conditions.

Critically, the fact that the writer's non-daemon thread is running means that, when your main thread (the thread the JVM used to start your program) runs out of statements in the connect() method, the JVM doesn't shut down immediately.

The serial port is calling you back on its own thread

When the serialPort invokes your listener's public void serialEvent(SerialPortEvent) method, it does so on its own thread .

Your mission is now to get off the serialPort's thread as fast as you can. Pretty much, read the data, stick it in a buffer where another thread of yours can parse and act on it at leisure, while letting the serialPort get on with handling comms. You certainly shouldn't try writing to the serial port while it's calling you on its own thread. It's in no state to respond to you, because it's waiting for you to finish!

You want your 'writer' thread to 'wait', until there is something to reply to

You arrange for that, by providing a 'lock' object. Since these are modern days, use:

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

Read a good book on concurrency

Concurrency is tricky. You'll want to read Java Concurrency in Practice .

When you try to cut'n'paste the code samples above, you'll notice that Condition#await() throws InterruptedException . Exactly what to do with that is beyond the scope of this answer. :-) The while(true) is a bit dodgy, too.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM