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.

Advertisements

20 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()); } } [/sourcecode]

    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

  13. Hi!!
    I think your blog is fantastic, it is a pity there is no a static board like a forum, in which people can register and join it…

    Anyaway, I have a very tedious problem:

    I like programming pics (microchip microcontrollers) and I want to create an interface whch dialogs directly with them.

    I realized 3 classes here:
    the “main” class:

    import java.util.Enumeration;
    import gnu.io.CommPortIdentifier;
    
    public class RS232Base {
    
    	private Enumeration portList = null;
    	private CommPortIdentifier portId = null;
    	private String defaultPort = null;
    	private boolean portFound = false;
    	private int baudRate = 0;
    	
    	/*******************************
    	* Constructor for the base class
    	* ******************************/
    	public RS232Base(String defaultPort, int baudRate){
    		this.defaultPort = defaultPort;
    		this.baudRate = baudRate;
    	}
    	/********************************
    	 * Methode to check the presence
    	 * of ports on this system
    	 *******************************/
    	public void checkPorts(){
    		
    		/***************************************
    		 * Get a list of all ports on the system
    		 **************************************/
    		portList = CommPortIdentifier.getPortIdentifiers();
    		System.out.println("List of all serial ports on this system:");
    		
    		while(portList.hasMoreElements()){
    			portId = (CommPortIdentifier)portList.nextElement();
    			if(portId.getName().equals(defaultPort)){
    				portFound = true;
    				System.out.println("Port found on: " + defaultPort);
    
    				new SerialProgram(portId, baudRate);  // If port found, create a new class
    			}	
    		}
    		
    		if(!portFound){
    			System.out.println("No serial port found!!!");
    		}
    	}
    	
    	
    	
    	public static void main(String[] args) {
    
    		RS232Base serial = new RS232Base("/dev/ttyUSB0", 9600);
    		serial.checkPorts();
    	}
    
    }
    

    the subclass serial:

    import java.io.DataInputStream;
    import java.io.IOException;
    import java.util.TooManyListenersException;
    import gnu.io.CommPortIdentifier;
    import gnu.io.PortInUseException;
    import gnu.io.SerialPort;
    import gnu.io.UnsupportedCommOperationException;
    
    
    public class SerialProgram implements Runnable{
    	
    	private CommPortIdentifier portId = null;
    	private SerialPort serialPort = null;
    	private DataInputStream is;
    	private int baudRate = 0;
    	
    	private Thread readThread;
    	
    	
    	
    	/************************
    	 * Constructor definition
    	 ***********************/
    	public SerialProgram(CommPortIdentifier portId, int baudRate){
    		
    		this.portId = portId;
    		this.baudRate = baudRate;
    		
    		
    		/**********************
    		 * Open the serial port
    		 *********************/
    		try{
    			serialPort = (SerialPort)portId.open("Artificial Horizont", 2000);
    		} catch (PortInUseException ex){
    			System.err.println("Port already in use!");
    		}
    		
    		// Get input stream
    		try{
    			is = new DataInputStream(serialPort.getInputStream());
    		} catch (IOException e){
    			System.err.println("Cannot open Input Stream " + e);
    			is =null;
    		}
    		
    		
    		try{
    			serialPort.setSerialPortParams(baudRate,
    					                       SerialPort.DATABITS_8,
    					                       SerialPort.STOPBITS_1,
                                               SerialPort.PARITY_NONE);
    		} catch (UnsupportedCommOperationException ex){
    			System.err.println("Wrong settings for the serial port: " + ex.getMessage());
    		}
    		
    		
    		try{
    			serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);
    		} catch (UnsupportedCommOperationException ex){
    			System.err.println("Check the flow control setting: " + ex.getMessage());
    		}
    		
    		// Add an event Listener
    		try{
    			serialPort.addEventListener(new SerialReader(is));
    		} catch (TooManyListenersException ev){
    			System.err.println("Too many Listeners! " + ev);
    		}
    		
    		// Advise if data available to be read on the port
    		serialPort.notifyOnDataAvailable(true);
    
    		// Define a Thread for reading
    		readThread = new Thread(this);
    		readThread.start();
    	}
    
    
    
    	@Override
    	public void run() {
    		try {
    		    Thread.sleep(20000);
    		} catch (InterruptedException e) {}
    	   
    	}
    
    }
    

    and the event class in case of receiving input from the pic:

    import gnu.io.SerialPortEvent;
    import gnu.io.SerialPortEventListener;
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    
    
    public class SerialReader implements SerialPortEventListener{
    
    	private BufferedReader inStream;
    	
    	
    	// Constructor
    	public SerialReader(InputStream is){
    		inStream = new BufferedReader(new InputStreamReader(is));
    	}
    	
    	
    	
    	@Override
    	public void serialEvent(SerialPortEvent event) {
    		
    		String rawInput = null;
    		
    		switch(event.getEventType()){
    		case SerialPortEvent.BI:
    		case SerialPortEvent.CD:
    		case SerialPortEvent.CTS:
    		case SerialPortEvent.DSR:
    		case SerialPortEvent.FE:
    		case SerialPortEvent.OE:
    		case SerialPortEvent.PE:
    		case SerialPortEvent.RI:
    		case SerialPortEvent.OUTPUT_BUFFER_EMPTY:
    			break;
    			
    		case SerialPortEvent.DATA_AVAILABLE:
    			try {
    				rawInput = inStream.readLine();
    				if(rawInput == null){
    					System.out.println("No input on serial port");
    					System.exit(0);
    				}
    				
    				System.out.println(rawInput);
    				
    			} catch (IOException e) {
    				e.printStackTrace();
    				System.exit(-1);
    			}
    			break;
    			
    		default:
    			break;
    			
    		}
    				
    	}
    }
    

    Since I did use the event drive mode an interrupt will be generate every time I receive a string from the pic (I need only to receive and not to send any data).

    The program works and very good!!!

    the only problem is the latency oin the port….since I m going to read angular degrees on the port (like 0 or 78 or -45 etc….)
    I receive those value 2-3 seconds too late as they are sent….( I tried with another program like cutecom on debian 64 bit JMV 1.6.12 and there is no problem for the pic to send datas in real time…so they are received perfectly on time on the srial port)
    But running this program in java I get them all the time too late…

    I suppose the problem is with the bufferedreader function to get all data input stream…

    could you please help me to find the solution to this problem?
    how can I deal with it????

    Thank you very much

    Bye!!!!!

    Comment by Dave — December 26, 2009 @ 1:50 am

  14. I haven’t done this for a long time, but I guess you should remove inStream.readLine() and replace it with inStream.read() method, since readLine() will wait until ‘\n’ or ‘\r\n’ returned inside the buffer.

    Comment by kunilkuda — December 26, 2009 @ 10:21 am

  15. Hi!
    back from my holiday I read your post and…yes you are right but not 100%..
    I created a BufferedReader and a inputStream as in the following code:

    import gnu.io.SerialPortEvent;
    import gnu.io.SerialPortEventListener;
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;

    public class SerialReader implements SerialPortEventListener{

    private BufferedReader inStream;

    // Constructor
    public SerialReader(InputStream is){

    inStream = new BufferedReader(new InputStreamReader(is), 5);
    }

    @Override
    public void serialEvent(SerialPortEvent event) {

    String rawInput = null;

    switch(event.getEventType()){
    case SerialPortEvent.BI:
    case SerialPortEvent.CD:
    case SerialPortEvent.CTS:
    case SerialPortEvent.DSR:
    case SerialPortEvent.FE:
    case SerialPortEvent.OE:
    case SerialPortEvent.PE:
    case SerialPortEvent.RI:
    case SerialPortEvent.OUTPUT_BUFFER_EMPTY:
    break;

    case SerialPortEvent.DATA_AVAILABLE:
    try {
    while((rawInput = inStream.readLine()) != null){
    System.out.println(rawInput);
    }

    inStream.close();

    } catch (IOException e) {
    e.printStackTrace();
    System.exit(-1);
    }
    break;

    default:
    break;

    }

    }
    }

    and now the code is working perfectly!!!!!
    Please see that I used the bufferedreder with a specific lenght (5 in my case because I receive a string of max 4 character + \n )
    The reading on the input port are exactly in “real time” absolut no latency is found on any my experiments 🙂 🙂 🙂

    I hope this could help to everyone wants to deal with serial ports, java and rxtx…and I want to thank you for your suggestion and your help….

    Thanks!

    Cheeeers!!!!

    Comment by Dave — January 13, 2010 @ 3:47 am

  16. Hello!

    Dave, I used your code to read from COM5 and I get this error:

    Native lib Version = RXTX-2.1-7
    Java lib Version = RXTX-2.1-7
    List of all serial ports on this system:
    Port found on: COM5
    �vy�&
    java.io.IOException: Underlying input stream returned zero bytes
    at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:268)
    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
    at java.io.InputStreamReader.read(InputStreamReader.java:167)
    at java.io.BufferedReader.fill(BufferedReader.java:136)
    at java.io.BufferedReader.readLine(BufferedReader.java:299)
    at java.io.BufferedReader.readLine(BufferedReader.java:362)
    at caixanegra.SerialReader.serialEvent(SerialReader.java:48)
    at gnu.io.RXTXPort.sendEvent(RXTXPort.java:732)
    at gnu.io.RXTXPort.eventLoop(Native Method)
    at gnu.io.RXTXPort$MonitorThread.run(RXTXPort.java:1575)
    Java Result: -1

    Do you have any idea what seems to be the problem?

    Thanks!!

    Comment by Maria — February 18, 2010 @ 11:17 pm

  17. Hi Maria..
    mhmh I dunno.
    Make sure you have the rxtx installed and not other driver (sun com for istance)
    Can you give me more infos?
    When happens the error?
    Whoch JDK or JRE are you using?

    Ciao!

    Comment by Dave — April 21, 2010 @ 3:42 am

  18. i read a serial connected device. it produces data in a specified time intervals. length of produced data is 9. such as; it sends one packet (its length 9 characters) to com port by every 10 seconds. i use a simulator, it reads data correctly, namely simulator shows 9 length of new data in every 10 seconds.

    on the other hand i developed an event based java program that uses rxtx 2.1.7 but i cannot get the correct data every time. my code like yours. what am i missing?

    i want to illustrate my problem with an example;
    sometimes i read data part by part.
    at first, i read 5 length of data, then the other part of 4 length, i read. it makes 9. but simulator reads once everytime.

    and the other problem is;
    sometimes i read the same data again.
    at first, i read 9 length of data. then a part of this data, such as 7 length of the same data, i read again. my real problem is that.

    any help is appreciated.

    Comment by Berat Sencer — March 17, 2011 @ 9:39 pm

  19. Hi, nice post…

    Unfortunately I am having a problem similar to RAR (post no.11)

    The basic problem is that I’m losing some chars when reading from a serial port and occasionally these won’t come through as ASCII; which I think means I am missing the occasional bit. I can confirm the data isn’t corrupted on the GPS, as I can pull it down properly using the Screen terminal app. It is sporadic and doesn’t always happen with the same chars.

    Comment by beaujoh — April 11, 2012 @ 9:20 am

  20. i am not able to read data from serial port, please help me to comeover it. 😦

    Comment by Aniket — May 16, 2012 @ 5:02 pm


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: