Embedded Freaks..

August 13, 2008

Reading from serial port (using rxtx)

Filed under: java — Tags: , , — kunilkuda @ 9:29 am

Once you’ve got the serial InputStream, reading would be easy. Here’s an example of code to read the serial port using InputStream:

/**
 * Buffer to hold the reading
 */
private byte[] readBuffer = new byte[400];

private void readSerial() {
    try {
        int availableBytes = inStream.available();
        if (availableBytes > 0) {
            // Read the serial port
            inStream.read(readBuffer, 0, availableBytes);

            // Print it out
            System.out.println(
                    new String(readBuffer, 0, availableBytes));
        }
    } catch (IOException e) {
    }
}

But the real problem comes from the place where you should place the code.

You can put inside the SerialPortEvent.DATA_AVAILABLE: event, like this:

private class SerialEventHandler implements SerialPortEventListener {
    public void serialEvent(SerialPortEvent event) {
        switch (event.getEventType()) {
            case SerialPortEvent.DATA_AVAILABLE:
                readSerial();
                break;
        }
    }
}

Don’t forget to register the event handler, before you run the application

/**
 * Set the serial event handler
 */
private void setSerialEventHandler(SerialPort serialPort) {
    try {
        // Add the serial port event listener
        serialPort.addEventListener(new SerialEventHandler());
        serialPort.notifyOnDataAvailable(true);
    } catch (TooManyListenersException ex) {
        System.err.println(ex.getMessage());
    }
}

The result is the read procedure is only called when new data is accepted.

The other way to read the serial port data continously is by using other thread to read:

private class ReadThread implements Runnable {
    public void run() {
        while(true) {
            readSerial();
        }
    }
}

Here’s how you start the thread:

public void setSerialListener() {
    new Thread(new ReadThread()).start();
}

Conclusion

So, which one that is better, put the reading inside different thread or in the event handler ? Well..I don’t know about it yet. I’ll post it once I found the answer.

12 Comments »

  1. Thanks for the code, its helped me verify/clarify some of my own.

    I’m currently working on the event driven model but I’m running into some runtime issues where the string is getting all jumbled up. These problems mysteriously disappear when I run the code in a debugger so I believe this is essentially a threading/timing issue – the event appears to be getting called a subsequent time before the previous event has completed processing causing all sorts of issues.

    I guess I’ll have to go to the other read approach or put a lock around the inputstream – I’m still not sure the later will correct the problem.

    I’m interested in knowing if you run into the same issue and your thoughts for a work around.

    Comment by arduino and rxtx guy — August 22, 2008 @ 3:59 pm

  2. Hi,

    Thanks for your comment.

    What’s your OS platform and RXTX version ? I’m using Linux 2.6 SLED 10 and RXTX 2.1.7, and I dont have such problem (or I haven’t test it thoroughly).

    Comment by kunilkuda — August 22, 2008 @ 8:49 pm

  3. [...] on August 28, 2008. Filed under: java | Tags: java, java serial port | One comment that I had in this site said that the RXTX library is not very reliable in the receiving part (using data available [...]

    Pingback by RXTX Loopback Test Program(1) « Embedded Freaks.. — August 28, 2008 @ 11:42 am

  4. I’m also using the eventbased reading of serial input and find myself in a pickle:
    1. The data is coming in sporadic (1-4 chars in a read), i’ve solved this by looking for my delimiter char ‘$’ (code posted below)
    2. I don’t have enough time to parse the entire string ($XXX,XX,..,XX) before a new one arrives and the DATA_AVAILABLE trigger again, leaving me with half a parsed string. The parser is in a thread of its own but apparently that won’t help me :(
    3. I’ve tried to force the parsing with a

    "boolean keep_running = true;
    while(keep_running) {
      // parse entire string
      keep_runnning = false;
    }
    

    but the DATA_AVAILABLE event triggers and the loop is not allowed to finish (what gives!?)

    Any ideas? The only thing that comes to my mind is trying to optimize the parser to finish before new data arrives….

    My code for reading a line from the serial port:

        private byte[] buffer = new byte[200];
        private int bufferpointer=0;
    
        protected void dataAvailable(SerialPortEvent event) {
            int numBytes;
            boolean keep_running = true;
            byte[] bufferfinal;
            String read_str;
            try {
                // Determining how many bytes are actualy available
                int length = in.available();
                byte[] c = new byte[length];
                numBytes = in.read(c);
                while(keep_running){
                    for (int i=0;i < numBytes;i++){
                        if ((char)c[i] == '$'){
                            bufferfinal = new byte[bufferpointer];
                            System.arraycopy(buffer, 0, bufferfinal, 0, bufferpointer);
                            read_str = new String(bufferfinal);
                            print(read_str);
                            new Thread(new Parser(this,read_str));
                            buffer = new byte[200];
                            bufferpointer=0;
                            buffer[bufferpointer] = c[i];
                            bufferpointer++;
                        }
                        else {
                            //middle of stream
                            if ((char)c[i] == '\n'){} //no newline
                            else if ((char)c[i] == '\r'){} //no return
                            else {
                                buffer[bufferpointer] = c[i];   //append
                                bufferpointer++;                //increment
                            }
                        }
                    }
                    keep_running = false;
                    //printDebug("End for loop");
                }
            }
            catch (IOException e) {
                printDebug("dataAvailable():"+e.getMessage());
            }
        }
    

    Comment by Andreas Christensen — November 13, 2008 @ 11:20 pm

  5. Hi Andreas,

    Sorry if I have to format your comment a bit. Anyway, don’t be too pessimistic. Your case is a classic example of “processing data in interrupt handler”.

    While some processing in interrupt handler is allowed, it’s not a very good practice, since you may miss the incoming interrupt.

    Second problem in your program is that you created a lot of thread

    new Thread(new Parser(this,read_str))

    Some thread may come with full packet, but I bet most of it comes with partial packet data.

    Third problem, which is the worst, you didn’t start the thread at all. It suppose to be

    new Thread(new Parser(this,read_str)).start();

    The fourth problem, a minor one, you should check whether it’s a DATA_AVAILABLE event or not. There might be some other event that comes from serial port (other idiots in the company may accidentally activate it, causing problem in your side).

    My suggestion is change the DATA_AVAILABLE interrupt handler (or event listener as they call it in Java) just to read the data and put it in the buffer. Then when you detect the end of packet, signal the other thread to parse the buffer.

    Don’t create too much of thread. It will slow down the system. Just run 1-thread (other than the main one), and have it wait for the signal to start the parsing.

    Hope that helps

    Comment by kunilkuda — November 14, 2008 @ 10:34 am

  6. Thanks kunilkuda, i’ll try to read up on the thread-lessons my java skills are dusty at best :)

    Comment by Andreas Christensen — November 18, 2008 @ 9:21 pm

  7. Hi! I’m studying a little about serial port. I would like of read the data of serial port of the more simple way possible (in the case without thread and many class). I’m using RXTX library, JDK 1.6 update 11 and NetBeans 6.5. I’m using a simple serial mouse to test the answer of the port. It’s possible of realize? Very interesting article, it’s very useful. Thanks!

    Comment by Abraao — January 26, 2009 @ 12:24 pm

  8. My suggestion for you is to read the serial port first using the available serial port terminal (such as Hyperterminal in Windows), so you can find out the correct settings for the serial mouse (baud rate, data bits, parity, stop bits, handshake).

    Reading the serial port without multiple thread is possible. But you will risk losing the incoming data, if your data processing is too slow compare to the rate of the incoming data.

    Comment by kunilkuda — January 28, 2009 @ 11:13 am

  9. hi Kunilkuda,

    I have adopted your code for reading a serial port event…but the thing is that, being a beginner in this field, i am unable to understand where do i embed the code to run and test the code.
    I am trying to capture the event of a serial mouse….

    kindly reply at the earliest else i’d be in BIG trouble…

    Thank You.

    PS.: You can also reply to my mail.

    Awaiting your reply…

    Comment by Utsav — May 29, 2009 @ 7:37 pm

  10. hi

    I am not able to close the serial port… I want release the COM port once the data is received…

    Below is my code..

    import java.io.*;
    import java.util.*;
    import gnu.io.*;

    public class ReadCommPort implements SerialPortEventListener {

    static CommPortIdentifier portId;
    static Enumeration portList;
    InputStream inputStream;
    OutputStream outputStream;
    public SerialPort serialPort;
    List byteList = new ArrayList();
    public static Message message = null;

    public void readData() {
    boolean portFound = false;
    String defaultPort = “COM1″;
    portList = CommPortIdentifier.getPortIdentifiers();

    while ( portList.hasMoreElements() ) {
    portId = ( CommPortIdentifier )portList.nextElement();
    if ( portId.getPortType() == CommPortIdentifier.PORT_SERIAL ) {
    if ( portId.getName().equals( defaultPort ) ) {
    System.out.println( “Found port: ” + defaultPort );
    portFound = true;
    buildSerialPort();
    }
    }
    }
    if ( ! portFound ) {
    System.out.println( “port ” + defaultPort + ” not found.” );
    }
    }

    public void buildSerialPort() {
    try {
    serialPort = (SerialPort) portId.open( “ReadCommPort”, 1 );
    inputStream = serialPort.getInputStream();
    outputStream = serialPort.getOutputStream();
    serialPort.addEventListener( this );
    serialPort.notifyOnDataAvailable(true);
    serialPort.setSerialPortParams( 2400, SerialPort.DATABITS_7, SerialPort.STOPBITS_1,

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

    @SuppressWarnings(“unchecked”)
    public void serialEvent( SerialPortEvent event ) {

    switch ( event.getEventType() ) {
    case SerialPortEvent.BI:
    System.out.println( “BI”);
    break;

    case SerialPortEvent.OE:
    System.out.println( “OE”);
    break;

    case SerialPortEvent.FE:
    System.out.println( “FE”);
    break;

    case SerialPortEvent.PE:
    System.out.println( “PE”);
    break;

    case SerialPortEvent.CD:
    System.out.println( “CD”);
    break;

    case SerialPortEvent.CTS:
    System.out.println( “CTS”);
    break;

    case SerialPortEvent.DSR:
    System.out.println( “DSR”);
    break;

    case SerialPortEvent.RI:
    System.out.println( “RI”);
    break;

    case SerialPortEvent.OUTPUT_BUFFER_EMPTY:
    System.out.println( “OUTPUT_BUFFER_EMPTY”);
    break;

    case SerialPortEvent.DATA_AVAILABLE :
    try {
    int len = inputStream.available();
    byte[] readBuffer = new byte[ len ];
    // processing data code..
    // close the port
    // release all resources…
    serialPort.removeEventListener();
    try {
    serialPort.addEventListener( null );
    }
    catch (TooManyListenersException e) {
    e.printStackTrace();
    }
    inputStream.close();
    outputStream.close();
    serialPort.close();
    }
    catch ( IOException e )
    {
    e.printStackTrace();
    }
    break;
    }
    }

    public static void main(String[] args) {
    new ReadCommPort().readData();
    } }

    Comment by sunil — June 8, 2009 @ 12:48 pm

  11. Hi,

    I’m having a problem using this lib. I’m losing some chars when reading from a serial port. This usually happens when a number of lines come very quickly. It doesn’t happen always or with the same chars.

    Can’t find the problem since the listener declared for the port only reads a line from it and copy it to a LinkedList.
    The LinkedList consumer is a thread which processes each line in it.

    I’d appreciate if you could give me some help.
    Thanks

    Comment by RAR — June 20, 2009 @ 6:12 am

  12. Hi! I was surfing and found your blog post… nice! I love your blog. :) Cheers! Sandra. R.

    Comment by sandrar — September 10, 2009 @ 9:47 pm


RSS feed for comments on this post. TrackBack URI

Leave a comment

Blog at WordPress.com.