/*------------------------------------------------------------------------- | rxtx is a native interface to serial ports in java. | Copyright 1997-2003 by Trent Jarvi taj@www.linux.org.uk. | | This library is free software; you can redistribute it and/or | modify it under the terms of the GNU Library General Public | License as published by the Free Software Foundation; either | version 2 of the License, or (at your option) any later version. | | This library is distributed in the hope that it will be useful, | but WITHOUT ANY WARRANTY; without even the implied warranty of | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | Library General Public License for more details. | | You should have received a copy of the GNU Library General Public | License along with this library; if not, write to the Free | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA --------------------------------------------------------------------------*/ package gnu.io; import java.io.InputStream; import java.io.OutputStream; import java.io.IOException; import java.util.TooManyListenersException; import java.lang.Math; /** * An extension of gnu.io.SerialPort * @see gnu.io.SerialPort */ final public class RXTXPort extends SerialPort { /* I had a report that some JRE's complain when MonitorThread tries to access private variables */ protected final static boolean debug = false; protected final static boolean debug_read = false; protected final static boolean debug_read_results = false; protected final static boolean debug_write = false; protected final static boolean debug_events = false; protected final static boolean debug_verbose = false; private static Zystem z; static { try { z = new Zystem( Zystem.PRINT_MODE ); } catch ( Exception e ) {}; if(debug ) z.reportln( "RXTXPort {}"); /* System.loadLibrary( "rxtxSerial" ); */ Initialize(); } /** Initialize the native library */ private native static void Initialize(); boolean MonitorThreadAlive=false; /** * Open the named port * @param name the name of the device to open * @throws PortInUseException * @see gnu.io.SerialPort */ public RXTXPort( String name ) throws PortInUseException { if (debug) z.reportln( "RXTXPort:RXTXPort("+name+") called"); /* commapi/javadocs/API_users_guide.html specifies that whenever an application tries to open a port in use by another application the PortInUseException will be thrown I know some didnt like it this way but I'm not sure how to avoid it. We will just be writing to a bogus fd if we catch the exeption Trent */ // try { fd = open( name ); this.name = name; MonitorThreadLock = true; monThread = new MonitorThread(); monThread.start(); waitForTheNativeCodeSilly(); MonitorThreadAlive=true; // } catch ( PortInUseException e ){} timeout = -1; /* default disabled timeout */ if (debug) z.reportln( "RXTXPort:RXTXPort("+name+") returns with fd = " + fd); } private native synchronized int open( String name ) throws PortInUseException; /** File descriptor */ protected int fd = 0; /** a pointer to the event info structure used to share information between threads so write threads can send output buffer empty from a pthread if need be. */ int eis = 0; /** pid for lock files */ int pid = 0; /** DSR flag **/ static boolean dsrFlag = false; /** Output stream */ private final SerialOutputStream out = new SerialOutputStream(); /** * get the OutputStream * @return OutputStream */ public OutputStream getOutputStream() { if (debug) z.reportln( "RXTXPort:getOutputStream() called and returning"); return out; } /** Input stream */ private final SerialInputStream in = new SerialInputStream(); /** * get the InputStream * @return InputStream * @see java.io.InputStream */ public InputStream getInputStream() { if (debug) z.reportln( "RXTXPort:getInputStream() called and returning"); return in; } /** * Set the SerialPort parameters * 1.5 stop bits requires 5 databits * @param b baudrate * @param d databits * @param s stopbits * @param p parity * @throws UnsupportedCommOperationException * @see gnu.io.UnsupportedCommOperationException * If speed is not a predifined speed it is assumed to be * the actual speed desired. */ private native int nativeGetParity( int fd ); private native int nativeGetFlowControlMode( int fd ); public synchronized void setSerialPortParams( int b, int d, int s, int p ) throws UnsupportedCommOperationException { if (debug) z.reportln( "RXTXPort:setSerialPortParams(" + b + " " + d + " " + s + " " + p + ") called"); if ( nativeSetSerialPortParams( b, d, s, p ) ) throw new UnsupportedCommOperationException( "Invalid Parameter" ); speed = b; if( s== STOPBITS_1_5 ) dataBits = DATABITS_5; else dataBits = d; stopBits = s; parity = p; z.reportln( "RXTXPort:setSerialPortParams(" + b + " " + d + " " + s + " " + p + ") returning"); } /** * Set the native serial port parameters * If speed is not a predifined speed it is assumed to be * the actual speed desired. */ private native boolean nativeSetSerialPortParams( int speed, int dataBits, int stopBits, int parity ) throws UnsupportedCommOperationException; /** Line speed in bits-per-second */ protected int speed=9600; /** * @return int representing the baudrate * This will not behave as expected with custom speeds */ public int getBaudRate() { if (debug) z.reportln( "RXTXPort:getBaudRate() called and returning " + speed); return speed; } /** Data bits port parameter */ protected int dataBits=DATABITS_8; /** * @return int representing the databits */ public int getDataBits() { if (debug) z.reportln( "RXTXPort:getDataBits() called and returning " + dataBits); return dataBits; } /** Stop bits port parameter */ protected int stopBits=SerialPort.STOPBITS_1; /** * @return int representing the stopbits */ public int getStopBits() { if (debug) z.reportln( "RXTXPort:getStopBits() called and returning " + stopBits); return stopBits; } /** Parity port parameter */ protected int parity= SerialPort.PARITY_NONE; /** * @return int representing the parity */ public int getParity() { if (debug) z.reportln( "RXTXPort:getParity() called and returning " + parity ); return parity; } /** Flow control */ protected int flowmode = SerialPort.FLOWCONTROL_NONE; /** * @param flowcontrol FLOWCONTROL_NONE is default * @see gnu.io.SerialPort#FLOWCONTROL_NONE */ public void setFlowControlMode( int flowcontrol ) { if (debug) z.reportln( "RXTXPort:setFlowControlMode( " + flowcontrol + " ) called"); if(monThreadisInterrupted) { if( debug_events ) z.reportln( "RXTXPort:setFlowControlMode MonThread is Interrupeted returning" ); return; } try { setflowcontrol( flowcontrol ); } catch( IOException e ) { e.printStackTrace(); return; } flowmode=flowcontrol; if (debug) z.reportln( "RXTXPort:setFlowControlMode( " + flowcontrol + " ) returning"); } /** * @return int representing the flowmode */ public int getFlowControlMode() { if (debug) z.reportln( "RXTXPort:getFlowControlMode() returning " + flowmode ); return flowmode; } native void setflowcontrol( int flowcontrol ) throws IOException; /* linux/drivers/char/n_hdlc.c? FIXME taj@www.linux.org.uk */ /** * Receive framing control * @param f framming * @throws UnsupportedCommOperationException */ public void enableReceiveFraming( int f ) throws UnsupportedCommOperationException { if (debug) z.reportln( "RXTXPort:enableReceiveFramming() throwing exception"); throw new UnsupportedCommOperationException( "Not supported" ); } /** */ public void disableReceiveFraming() { if (debug) z.reportln( "RXTXPort:disableReceiveFramming() called and returning (noop)"); } /** * @returns true if framing is enabled */ public boolean isReceiveFramingEnabled() { if (debug) z.reportln( "RXTXPort:isReceiveFrammingEnabled() called and returning " + false ); return false; } /** * @return int representing the framing byte */ public int getReceiveFramingByte() { if (debug) z.reportln( "RXTXPort:getReceiveFrammingByte() called and returning " + 0 ); return 0; } /** Receive timeout control */ protected int timeout; /** * @return int the timeout */ public native int NativegetReceiveTimeout(); /** * @return bloolean true if recieve timeout is enabled */ private native boolean NativeisReceiveTimeoutEnabled(); /** * @param time * @param threshold * @param InputBuffer */ private native void NativeEnableReceiveTimeoutThreshold(int time, int threshold,int InputBuffer); /** */ public void disableReceiveTimeout() { if (debug) z.reportln( "RXTXPort:disableReceiveTimeout() called"); timeout = -1; NativeEnableReceiveTimeoutThreshold( timeout , threshold, InputBuffer ); if (debug) z.reportln( "RXTXPort:disableReceiveTimeout() returning"); } /** * @param time */ public void enableReceiveTimeout( int time ) { if (debug) z.reportln( "RXTXPort:enableReceiveTimeout() called"); if( time >= 0 ) { timeout = time; NativeEnableReceiveTimeoutThreshold( time , threshold, InputBuffer ); } else { throw new IllegalArgumentException ( "Unexpected negative timeout value" ); } if (debug) z.reportln( "RXTXPort:enableReceiveTimeout() returning"); } /** * @return boolean true if recieve timeout is enabled */ public boolean isReceiveTimeoutEnabled() { if (debug) z.reportln( "RXTXPort:isReceiveTimeoutEnabled() called and returning " + NativeisReceiveTimeoutEnabled() ); return( NativeisReceiveTimeoutEnabled() ); } /** * @return int the timeout */ public int getReceiveTimeout() { if (debug) z.reportln( "RXTXPort:getReceiveTimeout() called and returning " + NativegetReceiveTimeout() ); return(NativegetReceiveTimeout( )); } /** Receive threshold control */ private int threshold = 0; /** * @param thresh threshold */ public void enableReceiveThreshold( int thresh ) { if (debug) z.reportln( "RXTXPort:enableReceiveThreshold( " + thresh + " ) called"); if(thresh >=0) { threshold=thresh; NativeEnableReceiveTimeoutThreshold(timeout, threshold, InputBuffer); } else /* invalid thresh */ { throw new IllegalArgumentException ( "Unexpected negative threshold value" ); } if (debug) z.reportln( "RXTXPort:enableReceiveThreshold( " + thresh + " ) returned"); } /** */ public void disableReceiveThreshold() { if (debug) z.reportln( "RXTXPort:disableReceiveThreshold() called and returning"); enableReceiveThreshold(0); } /** * @return int the recieve threshold */ public int getReceiveThreshold() { if (debug) z.reportln( "RXTXPort:getReceiveThreshold() called and returning " + threshold); return threshold; } /** * @return boolean true if receive threshold is enabled */ public boolean isReceiveThresholdEnabled() { if (debug) z.reportln( "RXTXPort:isReceiveThresholdEnable() called and returning" + (threshold > 0) ); return(threshold>0); } /** Input/output buffers */ /** FIXME I think this refers to FOPEN(3)/SETBUF(3)/FREAD(3)/FCLOSE(3) taj@www.linux.org.uk These are native stubs... */ private int InputBuffer=0; private int OutputBuffer=0; /** * @param size */ public void setInputBufferSize( int size ) { if (debug) z.reportln( "RXTXPort:setInputBufferSize( " + size + ") called"); if( size < 0 ) throw new IllegalArgumentException ( "Unexpected negative buffer size value" ); else InputBuffer=size; if (debug) z.reportln( "RXTXPort:setInputBufferSize( " + size + ") returning"); } /** */ public int getInputBufferSize() { if (debug) z.reportln( "RXTXPort:getInputBufferSize() called and returning " + InputBuffer ); return(InputBuffer); } /** * @param size */ public void setOutputBufferSize( int size ) { if (debug) z.reportln( "RXTXPort:setOutputBufferSize( " + size + ") called"); if( size < 0 ) throw new IllegalArgumentException ( "Unexpected negative buffer size value" ); else OutputBuffer=size; if (debug) z.reportln( "RXTXPort:setOutputBufferSize( " + size + ") returned"); } /** * @return in the output buffer size */ public int getOutputBufferSize() { if (debug) z.reportln( "RXTXPort:getOutputBufferSize() called and returning " + OutputBuffer ); return(OutputBuffer); } /* =================== cleaned messages to here */ /** * Line status methods */ /** * @returns true if DTR is set */ public native boolean isDTR(); /** * @param state */ public native void setDTR( boolean state ); /** * @param state */ public native void setRTS( boolean state ); private native void setDSR( boolean state ); /** * @return boolean true if CTS is set */ public native boolean isCTS(); /** * @return boolean true if DSR is set */ public native boolean isDSR(); /** * @return boolean true if CD is set */ public native boolean isCD(); /** * @return boolean true if RI is set */ public native boolean isRI(); /** * @return boolean true if RTS is set */ public native boolean isRTS(); /** * Write to the port * @param duration */ public native void sendBreak( int duration ); protected native void writeByte( int b, boolean i ) throws IOException; protected native void writeArray( byte b[], int off, int len, boolean i ) throws IOException; protected native boolean nativeDrain( boolean i ) throws IOException; /** RXTXPort read methods */ protected native int nativeavailable() throws IOException; protected native int readByte() throws IOException; protected native int readArray( byte b[], int off, int len ) throws IOException; /** Serial Port Event listener */ private SerialPortEventListener SPEventListener; /** Thread to monitor data */ private MonitorThread monThread; /** Process SerialPortEvents */ native void eventLoop(); /** * @return boolean true if monitor thread is interrupted */ boolean monThreadisInterrupted=true; private native void interruptEventLoop( ); public boolean checkMonitorThread() { if (debug) z.reportln( "RXTXPort:checkMonitorThread()"); if(monThread != null) { if ( debug ) z.reportln( "monThreadisInterrupted = " + monThreadisInterrupted ); return monThreadisInterrupted; } if ( debug ) z.reportln( "monThread is null " ); return(true); } /** * @param event * @param state * @return boolean true if the port is closing */ public boolean sendEvent( int event, boolean state ) { if (debug_events) z.report( "RXTXPort:sendEvent("); /* Let the native side know its time to die */ if ( fd == 0 || SPEventListener == null || monThread == null) { return(true); } switch( event ) { case SerialPortEvent.DATA_AVAILABLE: if( debug_events ) z.reportln( "DATA_AVAILABLE " + monThread.Data + ")" ); break; case SerialPortEvent.OUTPUT_BUFFER_EMPTY: if( debug_events ) z.reportln( "OUTPUT_BUFFER_EMPTY " + monThread.Output + ")" ); break; case SerialPortEvent.CTS: if( debug_events ) z.reportln( "CTS " + monThread.CTS + ")" ); break; case SerialPortEvent.DSR: if( debug_events ) z.reportln( "DSR " + monThread.Output + ")" ); break; case SerialPortEvent.RI: if( debug_events ) z.reportln( "RI " + monThread.RI + ")" ); break; case SerialPortEvent.CD: if( debug_events ) z.reportln( "CD " + monThread.CD + ")" ); break; case SerialPortEvent.OE: if( debug_events ) z.reportln( "OE " + monThread.OE + ")" ); break; case SerialPortEvent.PE: if( debug_events ) z.reportln( "PE " + monThread.PE + ")" ); break; case SerialPortEvent.FE: if( debug_events ) z.reportln( "FE " + monThread.FE + ")" ); break; case SerialPortEvent.BI: if( debug_events ) z.reportln( "BI " + monThread.BI + ")" ); break; default: if( debug_events ) z.reportln( "XXXXXXXXXXXXXX " + event + ")" ); break; } if( debug_events && debug_verbose ) z.reportln( " checking flags " ); switch( event ) { case SerialPortEvent.DATA_AVAILABLE: if( monThread.Data ) break; return(false); case SerialPortEvent.OUTPUT_BUFFER_EMPTY: if( monThread.Output ) break; return(false); case SerialPortEvent.CTS: if( monThread.CTS ) break; return(false); case SerialPortEvent.DSR: if( monThread.DSR ) break; return(false); case SerialPortEvent.RI: if( monThread.RI ) break; return(false); case SerialPortEvent.CD: if( monThread.CD ) break; return(false); case SerialPortEvent.OE: if( monThread.OE ) break; return(false); case SerialPortEvent.PE: if( monThread.PE ) break; return(false); case SerialPortEvent.FE: if( monThread.FE ) break; return(false); case SerialPortEvent.BI: if( monThread.BI ) break; return(false); default: System.err.println( "unknown event: " + event); return(false); } if( debug_events && debug_verbose ) z.reportln( " getting event" ); SerialPortEvent e = new SerialPortEvent(this, event, !state, state ); if( debug_events && debug_verbose ) z.reportln( " sending event" ); if(monThreadisInterrupted) { if( debug_events ) z.reportln( " sendEvent return" ); return(true); } if( SPEventListener != null ) { SPEventListener.serialEvent( e ); } if( debug_events && debug_verbose ) z.reportln( " sendEvent return" ); if (fd == 0 || SPEventListener == null || monThread == null) { return(true); } else { return(false); } } /** * Add an event listener * @param lsnr SerialPortEventListener * @throws TooManyListenersException */ boolean MonitorThreadLock = true; boolean MonitorThreadCloseLock = true; public void addEventListener( SerialPortEventListener lsnr ) throws TooManyListenersException { /* Don't let and notification requests happen until the Eventloop is ready */ if (debug) z.reportln( "RXTXPort:addEventListener()"); if( SPEventListener != null ) { throw new TooManyListenersException(); } SPEventListener = lsnr; if( !MonitorThreadAlive ) { MonitorThreadLock = true; monThread = new MonitorThread(); monThread.start(); waitForTheNativeCodeSilly(); MonitorThreadAlive=true; } if (debug) z.reportln( "RXTXPort:Interrupt=false"); } /** * Remove the serial port event listener */ public void removeEventListener() { if (debug) z.reportln( "RXTXPort:removeEventListener() called"); waitForTheNativeCodeSilly(); //if( monThread != null && monThread.isAlive() ) if( monThreadisInterrupted == true ) { z.reportln( " RXTXPort:removeEventListener() already interrupted"); monThread = null; SPEventListener = null; Runtime.getRuntime().gc(); return; } else if( monThread != null && monThread.isAlive() ) { if (debug) z.reportln( " RXTXPort:Interrupt=true"); monThreadisInterrupted=true; /* Notify all threads in this PID that something is up They will call back to see if its their thread using isInterrupted(). */ MonitorThreadCloseLock = true; if (debug) z.reportln( " RXTXPort:calling interruptEventLoop"); interruptEventLoop( ); if (debug) z.reportln(" RXTXPort:waiting on closelock"); while( MonitorThreadCloseLock ) { if (debug) z.reportln(" ."); try { Thread.sleep(100); } catch( Exception e ) {} } if (debug) z.reportln(" RXTXPort:set closelock"); if (debug) z.reportln( " RXTXPort:calling monThread.join()"); try { monThread.join(1000); } catch (Exception ex) { /* yikes */ ex.printStackTrace(); } if (debug) z.reportln( " RXTXPort:waiting on isAlive()"); while( monThread.isAlive() ) { if ( debug ) z.reportln( " MonThread is still alive!"); try { monThread.join(1000); Thread.sleep( 1000 ); } catch( Exception e ){} //monThread.stop(); } } if (debug) z.reportln( " RXTXPort:calling gc()"); monThread = null; SPEventListener = null; Runtime.getRuntime().gc(); MonitorThreadLock = false; MonitorThreadAlive=false; z.reportln( "RXTXPort:removeEventListener() returning"); } /** * Give the native code a chance to start listening to the hardware * or should we say give the native code control of the issue. * * This is important for applications that flicker the Monitor * thread while keeping the port open. * In worst case test cases this loops once or twice every time. */ protected void waitForTheNativeCodeSilly() { while( MonitorThreadLock ) { try { Thread.sleep(100); } catch( Exception e ) {} } } /** * @param enable */ private native void nativeSetEventFlag( int fd, int event, boolean flag ); public void notifyOnDataAvailable( boolean enable ) { if (debug) z.reportln( "RXTXPort:notifyOnDataAvailable( " + enable+" )"); waitForTheNativeCodeSilly(); MonitorThreadLock = true; nativeSetEventFlag( fd, SerialPortEvent.DATA_AVAILABLE, enable ); monThread.Data = enable; MonitorThreadLock = false; } /** * @param enable */ public void notifyOnOutputEmpty( boolean enable ) { if (debug) z.reportln( "RXTXPort:notifyOnOutputEmpty( " + enable+" )"); waitForTheNativeCodeSilly(); MonitorThreadLock = true; nativeSetEventFlag( fd, SerialPortEvent.OUTPUT_BUFFER_EMPTY, enable ); monThread.Output = enable; MonitorThreadLock = false; } /** * @param enable */ public void notifyOnCTS( boolean enable ) { if (debug) z.reportln( "RXTXPort:notifyOnCTS( " + enable+" )"); waitForTheNativeCodeSilly(); MonitorThreadLock = true; nativeSetEventFlag( fd, SerialPortEvent.CTS, enable ); monThread.CTS = enable; MonitorThreadLock = false; } /** * @param enable */ public void notifyOnDSR( boolean enable ) { if (debug) z.reportln( "RXTXPort:notifyOnDSR( " + enable+" )"); waitForTheNativeCodeSilly(); MonitorThreadLock = true; nativeSetEventFlag( fd, SerialPortEvent.DSR, enable ); monThread.DSR = enable; MonitorThreadLock = false; } /** * @param enable */ public void notifyOnRingIndicator( boolean enable ) { if (debug) z.reportln( "RXTXPort:notifyOnRingIndicator( " + enable+" )"); waitForTheNativeCodeSilly(); MonitorThreadLock = true; nativeSetEventFlag( fd, SerialPortEvent.RI, enable ); monThread.RI = enable; MonitorThreadLock = false; } /** * @param enable */ public void notifyOnCarrierDetect( boolean enable ) { if (debug) z.reportln( "RXTXPort:notifyOnCarrierDetect( " + enable+" )"); waitForTheNativeCodeSilly(); MonitorThreadLock = true; nativeSetEventFlag( fd, SerialPortEvent.CD, enable ); monThread.CD = enable; MonitorThreadLock = false; } /** * @param enable */ public void notifyOnOverrunError( boolean enable ) { if (debug) z.reportln( "RXTXPort:notifyOnOverrunError( " + enable+" )"); waitForTheNativeCodeSilly(); MonitorThreadLock = true; nativeSetEventFlag( fd, SerialPortEvent.OE, enable ); monThread.OE = enable; MonitorThreadLock = false; } /** * @param enable */ public void notifyOnParityError( boolean enable ) { if (debug) z.reportln( "RXTXPort:notifyOnParityError( " + enable+" )"); waitForTheNativeCodeSilly(); MonitorThreadLock = true; nativeSetEventFlag( fd, SerialPortEvent.PE, enable ); monThread.PE = enable; MonitorThreadLock = false; } /** * @param enable */ public void notifyOnFramingError( boolean enable ) { if (debug) z.reportln( "RXTXPort:notifyOnFramingError( " + enable+" )"); waitForTheNativeCodeSilly(); MonitorThreadLock = true; nativeSetEventFlag( fd, SerialPortEvent.FE, enable ); monThread.FE = enable; MonitorThreadLock = false; } /** * @param enable */ public void notifyOnBreakInterrupt( boolean enable ) { if (debug) z.reportln( "RXTXPort:notifyOnBreakInterrupt( " + enable+" )"); waitForTheNativeCodeSilly(); MonitorThreadLock = true; nativeSetEventFlag( fd, SerialPortEvent.BI, enable ); monThread.BI = enable; MonitorThreadLock = false; } /** Close the port */ private native void nativeClose( String name ); /** */ boolean closeLock = false; public synchronized void close() { if (debug) z.reportln( "RXTXPort:close( " + this.name + " )"); if( closeLock ) return; closeLock = true; if ( fd <= 0 ) { z.reportln( "RXTXPort:close detected bad File Descriptor" ); return; } setDTR(false); setDSR(false); if (debug) z.reportln( "RXTXPort:close( " + this.name + " ) setting monThreadisInterrupted"); if ( ! monThreadisInterrupted ) { removeEventListener(); } if (debug) z.reportln( "RXTXPort:close( " + this.name + " ) calling nativeClose"); nativeClose( this.name ); if (debug) z.reportln( "RXTXPort:close( " + this.name + " ) calling super.close"); super.close(); if (debug) z.reportln( "RXTXPort:close( " + this.name + " ) calling System.gc"); fd = 0; Runtime.getRuntime().gc(); closeLock = false; if (debug) z.reportln( "RXTXPort:close( " + this.name + " ) leaving"); } /** Finalize the port */ protected void finalize() { if (debug) z.reportln( "RXTXPort:finalize()"); if( fd > 0 ) close(); z.finalize(); } /** Inner class for SerialOutputStream */ class SerialOutputStream extends OutputStream { /** * @param b * @throws IOException */ public void write( int b ) throws IOException { if (debug_write) z.reportln( "RXTXPort:SerialOutputStream:write(int)"); if( speed == 0 ) return; /* hmm this turns out to be a very bad idea if ( monThreadisInterrupted == true ) { throw new IOException( "Port has been Closed" ); } */ waitForTheNativeCodeSilly(); if ( fd == 0 ) throw new IOException(); writeByte( b, monThreadisInterrupted ); if (debug_write) z.reportln( "Leaving RXTXPort:SerialOutputStream:write( int )"); } /** * @param b[] * @throws IOException */ public void write( byte b[] ) throws IOException { if (debug_write) { z.reportln( "Entering RXTXPort:SerialOutputStream:write(" + b.length + ") "/* + new String(b)*/ ); } if( speed == 0 ) return; /* hmm this turns out to be a very bad idea if ( monThreadisInterrupted == true ) { throw new IOException( "Port has been Closed" ); } */ if ( fd == 0 ) throw new IOException(); waitForTheNativeCodeSilly(); writeArray( b, 0, b.length, monThreadisInterrupted ); if (debug_write) z.reportln( "Leaving RXTXPort:SerialOutputStream:write(" +b.length +")"); } /** * @param b[] * @param off * @param len * @throws IOException */ public void write( byte b[], int off, int len ) throws IOException { if( speed == 0 ) return; if( off + len > b.length ) { throw new IndexOutOfBoundsException( "Invalid offset/length passed to read" ); } byte send[] = new byte[len]; System.arraycopy( b, off, send, 0, len ); if (debug_write) { z.reportln( "Entering RXTXPort:SerialOutputStream:write(" + send.length + " " + off + " " + len + " " +") " /*+ new String(send) */ ); } if ( fd == 0 ) throw new IOException(); /* hmm this turns out to be a very bad idea if ( monThreadisInterrupted == true ) { throw new IOException( "Port has been Closed" ); } */ waitForTheNativeCodeSilly(); writeArray( send, 0, len, monThreadisInterrupted ); if( debug_write ) z.reportln( "Leaving RXTXPort:SerialOutputStream:write(" + send.length + " " + off + " " + len + " " +") " /*+ new String(send)*/ ); } /** */ public void flush() throws IOException { if (debug) z.reportln( "RXTXPort:SerialOutputStream:flush() enter"); if( speed == 0 ) return; if ( fd == 0 ) throw new IOException(); /* hmm this turns out to be a very bad idea if ( monThreadisInterrupted == true ) { return; // FIXME Trent this breaks //throw new IOException( "flush() Port has been Closed" ); } */ waitForTheNativeCodeSilly(); /* this is probably good on all OS's but for now just sendEvent from java on Sol */ if ( nativeDrain( monThreadisInterrupted ) ) sendEvent( SerialPortEvent.OUTPUT_BUFFER_EMPTY, true ); if (debug) z.reportln( "RXTXPort:SerialOutputStream:flush() leave"); } } /** Inner class for SerialInputStream */ class SerialInputStream extends InputStream { /** * @return int the int read * @throws IOException * @see java.io.InputStream * *timeout threshold Behavior *------------------------------------------------------------------------ *0 0 blocks until 1 byte is available timeout > 0, * threshold = 0, blocks until timeout occurs, returns -1 * on timeout *>0 >0 blocks until timeout, returns - 1 on timeout, magnitude * of threshold doesn't play a role. *0 >0 Blocks until 1 byte, magnitude of threshold doesn't * play a role */ public synchronized int read() throws IOException { if (debug_read) z.reportln( "RXTXPort:SerialInputStream:read() called"); if ( fd == 0 ) throw new IOException(); waitForTheNativeCodeSilly(); if ( monThreadisInterrupted ) z.reportln( "+++++++++ read() monThreadisInterrupted" ); int result = readByte(); if (debug_read_results) z.reportln( "RXTXPort:SerialInputStrea:read() returns byte = " + result ); return( result ); } /** * @param b[] * @return int number of bytes read * @throws IOException * *timeout threshold Behavior *------------------------------------------------------------------------ *0 0 blocks until 1 byte is available *>0 0 blocks until timeout occurs, returns 0 on timeout *>0 >0 blocks until timeout or reads threshold bytes, returns 0 on timeout *0 >0 blocks until reads threshold bytes */ public synchronized int read( byte b[] ) throws IOException { int result; if (debug_read) z.reportln( "RXTXPort:SerialInputStream:read(" + b.length + ") called"); /* hmm this turns out to be a very bad idea if ( monThreadisInterrupted == true ) { throw new IOException( "Port has been Closed" ); } */ waitForTheNativeCodeSilly(); result = read( b, 0, b.length); if (debug_read_results) z.reportln( "RXTXPort:SerialInputStream:read() returned " + result + " bytes" ); return( result ); } /* read(byte b[], int, int) Documentation is at http://java.sun.com/products/jdk/1.2/docs/api/java/io/InputStream.html#read(byte[], int, int) */ /** * @param b[] * @param off * @param len * @return int number of bytes read * @throws IOException * *timeout threshold Behavior *------------------------------------------------------------------------ *0 0 blocks until 1 byte is available *>0 0 blocks until timeout occurs, returns 0 on timeout *>0 >0 blocks until timeout or reads threshold bytes, returns 0 on timeout *0 >0 blocks until either threshold # of bytes or len bytes, whichever was lower. */ public synchronized int read( byte b[], int off, int len ) throws IOException { if (debug_read) z.reportln( "RXTXPort:SerialInputStream:read(" + b.length + " " + off + " " + len + ") called" /*+ new String(b) */ ); int result; /* * Some sanity checks */ if ( fd == 0 ) { z.reportln("+++++++ IOException()\n"); throw new IOException(); } if( b==null ) { z.reportln("+++++++ NullPointerException()\n"); throw new NullPointerException(); } if( (off < 0) || (len < 0) || (off+len > b.length)) { z.reportln("+++++++ IndexOutOfBoundsException()\n"); throw new IndexOutOfBoundsException(); } /* * Return immediately if len==0 */ if( len==0 ) return 0; /* * See how many bytes we should read */ int Minimum = len; if( threshold==0 ) { /* * If threshold is disabled, read should return as soon * as data are available (up to the amount of available * bytes in order to avoid blocking) * Read may return earlier depending of the receive time * out. */ int a = nativeavailable(); if( a == 0 ) Minimum = 1; else Minimum = Math.min( Minimum, a ); } else { /* * Threshold is enabled. Read should return when * 'threshold' bytes have been received (or when the * receive timeout expired) */ Minimum = Math.min(Minimum, threshold); } /* hmm this turns out to be a very bad idea if ( monThreadisInterrupted == true ) { throw new IOException( "Port has been Closed" ); } */ waitForTheNativeCodeSilly(); result = readArray( b, off, Minimum); if (debug_read_results) z.reportln( "RXTXPort:SerialInputStream:read(" + b.length + " " + off + " " + len + ") returned " + result + " bytes" /*+ new String(b) */); return( result ); } /** * @return int bytes available * @throws IOException */ public synchronized int available() throws IOException { /* hmm this turns out to be a very bad idea if ( monThreadisInterrupted == true ) { throw new IOException( "Port has been Closed" ); } */ if ( debug_verbose ) z.reportln( "RXTXPort:available() called" ); int r = nativeavailable(); if ( debug_verbose ) z.reportln( "RXTXPort:available() returning " + r ); return r; } } /** */ class MonitorThread extends Thread { /** Note: these have to be separate boolean flags because the SerialPortEvent constants are NOT bit-flags, they are just defined as integers from 1 to 10 -DPL */ private volatile boolean CTS=false; private volatile boolean DSR=false; private volatile boolean RI=false; private volatile boolean CD=false; private volatile boolean OE=false; private volatile boolean PE=false; private volatile boolean FE=false; private volatile boolean BI=false; private volatile boolean Data=false; private volatile boolean Output=false; MonitorThread() { if (debug) z.reportln( "RXTXPort:MontitorThread:MonitorThread()"); } /** * run the thread and call the event loop. */ public void run() { if (debug) z.reportln( "RXTXPort:MontitorThread:run()"); monThreadisInterrupted=false; eventLoop(); if (debug) z.reportln( "eventLoop() returned"); } protected void finalize() throws Throwable { if (debug) z.reportln( "RXTXPort:MonitorThread exiting"); } } /** * A dummy method added so RXTX compiles on Kaffee * @deprecated deprecated but used in Kaffe */ public void setRcvFifoTrigger(int trigger){}; /*------------------------ END OF CommAPI -----------------------------*/ private native static void nativeStaticSetSerialPortParams( String f, int b, int d, int s, int p ) throws UnsupportedCommOperationException; private native static boolean nativeStaticSetDSR( String port, boolean flag ) throws UnsupportedCommOperationException; private native static boolean nativeStaticSetDTR( String port, boolean flag ) throws UnsupportedCommOperationException; private native static boolean nativeStaticSetRTS( String port, boolean flag ) throws UnsupportedCommOperationException; private native static boolean nativeStaticIsDSR( String port ) throws UnsupportedCommOperationException; private native static boolean nativeStaticIsDTR( String port ) throws UnsupportedCommOperationException; private native static boolean nativeStaticIsRTS( String port ) throws UnsupportedCommOperationException; private native static boolean nativeStaticIsCTS( String port ) throws UnsupportedCommOperationException; private native static boolean nativeStaticIsCD( String port ) throws UnsupportedCommOperationException; private native static boolean nativeStaticIsRI( String port ) throws UnsupportedCommOperationException; private native static int nativeStaticGetBaudRate( String port ) throws UnsupportedCommOperationException; private native static int nativeStaticGetDataBits( String port ) throws UnsupportedCommOperationException; private native static int nativeStaticGetParity( String port ) throws UnsupportedCommOperationException; private native static int nativeStaticGetStopBits( String port ) throws UnsupportedCommOperationException; private native byte nativeGetParityErrorChar( ) throws UnsupportedCommOperationException; private native boolean nativeSetParityErrorChar( byte b ) throws UnsupportedCommOperationException; private native byte nativeGetEndOfInputChar( ) throws UnsupportedCommOperationException; private native boolean nativeSetEndOfInputChar( byte b ) throws UnsupportedCommOperationException; private native boolean nativeSetUartType(String type, boolean test) throws UnsupportedCommOperationException; native String nativeGetUartType() throws UnsupportedCommOperationException; private native boolean nativeSetBaudBase(int BaudBase) throws UnsupportedCommOperationException; private native int nativeGetBaudBase() throws UnsupportedCommOperationException; private native boolean nativeSetDivisor(int Divisor) throws UnsupportedCommOperationException; private native int nativeGetDivisor() throws UnsupportedCommOperationException; private native boolean nativeSetLowLatency() throws UnsupportedCommOperationException; private native boolean nativeGetLowLatency() throws UnsupportedCommOperationException; private native boolean nativeSetCallOutHangup(boolean NoHup) throws UnsupportedCommOperationException; private native boolean nativeGetCallOutHangup() throws UnsupportedCommOperationException; /** * Extension to CommAPI * This is an extension to CommAPI. It may not be supported on * all operating systems. * * This is only accurate up to 38600 baud currently. * * @param port the name of the port thats been preopened * @return BaudRate on success * @throws UnsupportedCommOperationException; * This will not behave as expected with custom speeds * */ public static int staticGetBaudRate( String port ) throws UnsupportedCommOperationException { if ( debug ) z.reportln( "RXTXPort:staticGetBaudRate( " + port + " )"); return(nativeStaticGetBaudRate( port )); } /** * Extension to CommAPI * This is an extension to CommAPI. It may not be supported on * all operating systems. * * @param port the name of the port thats been preopened * @return DataBits on success * @throws UnsupportedCommOperationException; * */ public static int staticGetDataBits( String port ) throws UnsupportedCommOperationException { if ( debug ) z.reportln( "RXTXPort:staticGetDataBits( " + port + " )"); return(nativeStaticGetDataBits( port ) ); } /** * Extension to CommAPI * This is an extension to CommAPI. It may not be supported on * all operating systems. * * @param port the name of the port thats been preopened * @return Parity on success * @throws UnsupportedCommOperationException; * */ public static int staticGetParity( String port ) throws UnsupportedCommOperationException { if ( debug ) z.reportln( "RXTXPort:staticGetParity( " + port + " )"); return( nativeStaticGetParity( port ) ); } /** * Extension to CommAPI * This is an extension to CommAPI. It may not be supported on * all operating systems. * * @param port the name of the port thats been preopened * @return StopBits on success * @throws UnsupportedCommOperationException; * */ public static int staticGetStopBits( String port ) throws UnsupportedCommOperationException { if ( debug ) z.reportln( "RXTXPort:staticGetStopBits( " + port + " )"); return(nativeStaticGetStopBits( port ) ); } /** * Extension to CommAPI * This is an extension to CommAPI. It may not be supported on * all operating systems. * * Set the SerialPort parameters * 1.5 stop bits requires 5 databits * @param f filename * @param b baudrate * @param d databits * @param s stopbits * @param p parity * * @throws UnsupportedCommOperationException * @see gnu.io.UnsupportedCommOperationException */ public static void staticSetSerialPortParams( String f, int b, int d, int s, int p ) throws UnsupportedCommOperationException { if ( debug ) z.reportln( "RXTXPort:staticSetSerialPortParams( " + f + " " + b + " " + d + " " + s + " " + p ); nativeStaticSetSerialPortParams( f, b, d, s, p ); } /** * Extension to CommAPI * This is an extension to CommAPI. It may not be supported on * all operating systems. * * Open the port and set DSR. remove lockfile and do not close * This is so some software can appear to set the DSR before 'opening' * the port a second time later on. * * @return true on success * @throws UnsupportedCommOperationException; * */ public static boolean staticSetDSR( String port, boolean flag ) throws UnsupportedCommOperationException { if ( debug ) z.reportln( "RXTXPort:staticSetDSR( " + port + " " + flag ); return( nativeStaticSetDSR( port, flag ) ); } /** * Extension to CommAPI * This is an extension to CommAPI. It may not be supported on * all operating systems. * * Open the port and set DTR. remove lockfile and do not close * This is so some software can appear to set the DTR before 'opening' * the port a second time later on. * * @return true on success * @throws UnsupportedCommOperationException; * */ public static boolean staticSetDTR( String port, boolean flag ) throws UnsupportedCommOperationException { if ( debug ) z.reportln( "RXTXPort:staticSetDTR( " + port + " " + flag ); return( nativeStaticSetDTR( port, flag ) ); } /** * Extension to CommAPI * This is an extension to CommAPI. It may not be supported on * all operating systems. * * Open the port and set RTS. remove lockfile and do not close * This is so some software can appear to set the RTS before 'opening' * the port a second time later on. * * @return none * @throws UnsupportedCommOperationException; * */ public static boolean staticSetRTS( String port, boolean flag ) throws UnsupportedCommOperationException { if ( debug ) z.reportln( "RXTXPort:staticSetRTS( " + port + " " + flag ); return( nativeStaticSetRTS( port, flag ) ); } /** * Extension to CommAPI * This is an extension to CommAPI. It may not be supported on * all operating systems. * * find the fd and return RTS without using a Java open() call * * @param String port * @return boolean true if asserted * @throws UnsupportedCommOperationException; * */ public static boolean staticIsRTS( String port ) throws UnsupportedCommOperationException { if ( debug ) z.reportln( "RXTXPort:staticIsRTS( " + port + " )" ); return( nativeStaticIsRTS( port ) ); } /** * Extension to CommAPI * This is an extension to CommAPI. It may not be supported on * all operating systems. * * find the fd and return CD without using a Java open() call * * @param String port * @return boolean true if asserted * @throws UnsupportedCommOperationException; * */ public static boolean staticIsCD( String port ) throws UnsupportedCommOperationException { if ( debug ) z.reportln( "RXTXPort:staticIsCD( " + port + " )" ); return( nativeStaticIsCD( port ) ); } /** * Extension to CommAPI * This is an extension to CommAPI. It may not be supported on * all operating systems. * * find the fd and return CTS without using a Java open() call * * @param String port * @return boolean true if asserted * @throws UnsupportedCommOperationException; * */ public static boolean staticIsCTS( String port ) throws UnsupportedCommOperationException { if ( debug ) z.reportln( "RXTXPort:staticIsCTS( " + port + " )" ); return( nativeStaticIsCTS( port ) ); } /** * Extension to CommAPI * This is an extension to CommAPI. It may not be supported on * all operating systems. * * find the fd and return DSR without using a Java open() call * * @param String port * @return boolean true if asserted * @throws UnsupportedCommOperationException; * */ public static boolean staticIsDSR( String port ) throws UnsupportedCommOperationException { if ( debug ) z.reportln( "RXTXPort:staticIsDSR( " + port + " )" ); return( nativeStaticIsDSR( port ) ); } /** * Extension to CommAPI * This is an extension to CommAPI. It may not be supported on * all operating systems. * * find the fd and return DTR without using a Java open() call * * @param String port * @return boolean true if asserted * @throws UnsupportedCommOperationException; * */ public static boolean staticIsDTR( String port ) throws UnsupportedCommOperationException { if ( debug ) z.reportln( "RXTXPort:staticIsDTR( " + port + " )" ); return( nativeStaticIsDTR( port ) ); } /** * Extension to CommAPI * This is an extension to CommAPI. It may not be supported on * all operating systems. * * find the fd and return RI without using a Java open() call * * @param String port * @return boolean true if asserted * @throws UnsupportedCommOperationException; * */ public static boolean staticIsRI( String port ) throws UnsupportedCommOperationException { if ( debug ) z.reportln( "RXTXPort:staticIsRI( " + port + " )" ); return( nativeStaticIsRI( port ) ); } /** * Extension to CommAPI * This is an extension to CommAPI. It may not be supported on * all operating systems. * @return int the Parity Error Character * @throws UnsupportedCommOperationException; * * Anyone know how to do this in Unix? */ public byte getParityErrorChar( ) throws UnsupportedCommOperationException { byte ret; if ( debug ) z.reportln( "getParityErrorChar()" ); ret = nativeGetParityErrorChar(); if ( debug ) z.reportln( "getParityErrorChar() returns " + ret ); return( ret ); } /** * Extension to CommAPI * This is an extension to CommAPI. It may not be supported on * all operating systems. * @param b Parity Error Character * @return boolean true on success * @throws UnsupportedCommOperationException; * * Anyone know how to do this in Unix? */ public boolean setParityErrorChar( byte b ) throws UnsupportedCommOperationException { if ( debug ) z.reportln( "setParityErrorChar(" + b + ")" ); return( nativeSetParityErrorChar( b ) ); } /** * Extension to CommAPI * This is an extension to CommAPI. It may not be supported on * all operating systems. * @return int the End of Input Character * @throws UnsupportedCommOperationException; * * Anyone know how to do this in Unix? */ public byte getEndOfInputChar( ) throws UnsupportedCommOperationException { byte ret; if ( debug ) z.reportln( "getEndOfInputChar()" ); ret = nativeGetEndOfInputChar(); if ( debug ) z.reportln( "getEndOfInputChar() returns " + ret ); return( ret ); } /** * Extension to CommAPI * This is an extension to CommAPI. It may not be supported on * all operating systems. * @param b End Of Input Character * @return boolean true on success * @throws UnsupportedCommOperationException; */ public boolean setEndOfInputChar( byte b ) throws UnsupportedCommOperationException { if ( debug ) z.reportln( "setEndOfInputChar(" + b + ")" ); return( nativeSetEndOfInputChar( b ) ); } /** * Extension to CommAPI * This is an extension to CommAPI. It may not be supported on * all operating systems. * @param type String representation of the UART type which mayb * be "none", "8250", "16450", "16550", "16550A", "16650", "16550V2" * or "16750". * @param test boolean flag to determin if the UART should be tested. * @return boolean true on success * @throws UnsupportedCommOperationException; */ public boolean setUARTType(String type, boolean test) throws UnsupportedCommOperationException { if ( debug ) z.reportln( "RXTXPort:setUARTType()"); return nativeSetUartType(type, test); } /** * Extension to CommAPI * This is an extension to CommAPI. It may not be supported on * all operating systems. * @return type String representation of the UART type which mayb * be "none", "8250", "16450", "16550", "16550A", "16650", "16550V2" * or "16750". * @throws UnsupportedCommOperationException; */ public String getUARTType() throws UnsupportedCommOperationException { return nativeGetUartType(); } /** * Extension to CommAPI * @param int BaudBase The clock frequency divided by 16. Default * BaudBase is 115200. * @return boolean true on success * @throws UnsupportedCommOperationException */ public boolean setBaudBase(int BaudBase) throws UnsupportedCommOperationException { if ( debug ) z.reportln( "RXTXPort:setBaudBase()"); return nativeSetBaudBase(BaudBase); } /** * Extension to CommAPI * @return int BaudBase * @throws UnsupportedCommOperationException */ public int getBaudBase() throws UnsupportedCommOperationException { if ( debug ) z.reportln( "RXTXPort:getBaudBase()"); return nativeGetBaudBase(); } /** * Extension to CommAPI * @param int Divisor; * @throws UnsupportedCommOperationException */ public boolean setDivisor(int Divisor) throws UnsupportedCommOperationException { if ( debug ) z.reportln( "RXTXPort:setDivisor()"); return nativeSetDivisor(Divisor); } /** * Extension to CommAPI * @returns int Divisor; * @throws UnsupportedCommOperationException */ public int getDivisor() throws UnsupportedCommOperationException { if ( debug ) z.reportln( "RXTXPort:getDivisor()"); return nativeGetDivisor(); } /** * Extension to CommAPI * returns boolean true on success * @throws UnsupportedCommOperationException */ public boolean setLowLatency() throws UnsupportedCommOperationException { if ( debug ) z.reportln( "RXTXPort:setLowLatency()"); return nativeSetLowLatency(); } /** * Extension to CommAPI * returns boolean true on success * @throws UnsupportedCommOperationException */ public boolean getLowLatency() throws UnsupportedCommOperationException { if ( debug ) z.reportln( "RXTXPort:getLowLatency()"); return nativeGetLowLatency(); } /** * Extension to CommAPI * returns boolean true on success * @throws UnsupportedCommOperationException */ public boolean setCallOutHangup(boolean NoHup) throws UnsupportedCommOperationException { if ( debug ) z.reportln( "RXTXPort:setCallOutHangup()"); return nativeSetCallOutHangup(NoHup); } /** * Extension to CommAPI * returns boolean true on success * @throws UnsupportedCommOperationException */ public boolean getCallOutHangup() throws UnsupportedCommOperationException { if ( debug ) z.reportln( "RXTXPort:getCallOutHangup()"); return nativeGetCallOutHangup(); } /*------------------------ END OF CommAPI Extensions -----------------------*/ }