Subversion Repositories Programming Utils

Rev

Rev 61 | Rev 63 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

package com.rm5248.serial;

import java.io.IOException;
import java.io.InputStream;

/**
 * Okay, so the problem here is that we need to be continually reading from the serial port,
 * because on Windows we can't simultaneously listen for events and listen for changes on
 * the serial port.  We can only do that in one place.  So, to get around that problem,
 * this BufferedSerialInputStream simply wraps the normal SerialInputStream and only
 * returns actual data.  SerialInputStream gives us back data on the status of the serial line,
 * as well as if the byte it gave us is real or not.
 *
 * @author rm5248
 *
 */

class BufferedSerialInputStream extends InputStream implements Runnable {

        private SerialInputStream stream;
        private byte[] buffer;
        private int bufferBegin;
        private int bufferEnd;
        private SerialPort callback;
        private IOException exceptionToThrow;

        BufferedSerialInputStream( SerialInputStream s, SerialPort callback ){
                stream = s;
                buffer = new byte[ 500 ];
                bufferBegin = 0;
                bufferEnd = 0;
                this.callback = callback;
                exceptionToThrow = null;
        }

        @Override
        public int read() throws IOException {
                int byteToReturn;

                if( bufferBegin != bufferEnd ){
                        //we already have a character
                        byteToReturn = buffer[ bufferBegin++ ];
                        if( bufferBegin >= buffer.length ){
                                //wrap around to the start of the array
                                bufferBegin = 0;
                        }
                }else{
                        synchronized( buffer ){
                                try {
                                        buffer.wait();
                                } catch (InterruptedException e) {
                                        e.printStackTrace();
                                }

                                if( exceptionToThrow != null ){
                                        throw exceptionToThrow;
                                }
                        }

                        byteToReturn = buffer[ bufferBegin++ ];
                        if( bufferBegin >= buffer.length ){
                                //wrap around to the start of the array
                                bufferBegin = 0;
                        }
                }

                return byteToReturn;
        }

        @Override
        public void run() {
                while( true ){
                        int byteRead = 0;
                        SerialLineState s = new SerialLineState();
                        int avail;
                       
                        //Okay, this here is rather ugly.
                        //but what we're going to do is to poll every 100 ms for the serial line state
                        //to change.  that way, we can triggr
                        try{
                                Thread.sleep( 100 );
                        }catch( InterruptedException ex ){}
                       
                        try {
                                avail = stream.available();
                        } catch (IOException e1) {
                                break;
                        }

                        if( avail > 0 ){
                                try {
                                        byteRead = stream.read();
                                } catch (IOException e) {
                                        synchronized( buffer ){
                                                exceptionToThrow = e;
                                                buffer.notify();
                                        }
                                        break;
                                }

                                if( ( byteRead & ( 0x01 << 9) ) > 0 ){
                                        s.carrierDetect = true;
                                }else if( ( byteRead & (0x01 << 10 ) ) > 0  ){
                                        s.clearToSend = true;
                                }else if( ( byteRead & (0x01 << 11 ) ) > 0  ){
                                        s.dataSetReady = true;
                                }else if( ( byteRead & (0x01 << 12 ) ) > 0  ){
                                        s.dataTerminalReady = true;
                                }else if( ( byteRead & (0x01 << 13 ) ) > 0  ){
                                        s.requestToSend = true;
                                }else if( ( byteRead & (0x01 << 14 ) ) > 0  ){
                                        s.ringIndicator = true;
                                }

                                if( ( byteRead & ( 0x01 << 15 ) ) > 0 ){
                                        //this is a valid byte
                                        synchronized( buffer ){
                                                if( bufferEnd + 1 >= buffer.length ){
                                                        //loop back around to the beginning
                                                        bufferEnd = 0;
                                                }
                                                buffer[ bufferEnd++ ] = (byte)( byteRead & 0xFF );
                                                if( bufferEnd == bufferBegin ){
                                                        //the end has wrapped around, increment the beginning
                                                        bufferBegin++;

                                                        if( bufferBegin >= buffer.length ){
                                                                bufferBegin = 0;
                                                        }
                                                }

                                                buffer.notify();
                                        }
                                }
                        }else{
                                try {
                                        callback.postSerialChangedEvent( callback.getSerialLineState() );
                                } catch (IOException e) {
                                        break;
                                }
                        }

                        callback.postSerialChangedEvent( s );
                }
        }

        @Override
        public int available(){
                if( bufferEnd < bufferBegin ){
                        //special case - we have looped around
                        return ( buffer.length - bufferBegin ) + bufferEnd;
                }else{
                        return bufferEnd - bufferBegin;
                }
        }

        @Override
        public int read( byte[] b, int off, int len ) throws IOException{
                int readSoFar = 0;

                if( len == 0 ){
                        return 0;
                }

                for( int x = off; x < len; x++ ){
                        b[x] = (byte)read();
                        readSoFar++;
                        if( readSoFar > 0 && available() == 0 ){
                                break;
                        }
                }

                return readSoFar;
        }

}