/trunk/JavaSerial/src/com/rm5248/serial/SerialPort.java |
---|
1,951 → 1,195 |
package com.rm5248.serial; |
import java.io.Closeable; |
import java.io.IOException; |
import java.io.InputStream; |
import java.io.OutputStream; |
/** |
* A SerialPort object represents a SerialPort object on the system. |
* |
* When creating a SerialPort object, you give the SerialPort the name of the port that you |
* wish to open. |
* |
* When opening a SerialPort and setting values, an {@link IllegalArgumentException} may be thrown |
* if any of the values are NULL. |
* |
* When getting and settings the properties of the SerialPort using one of the {@code getXXX() } |
* or {@code setXXX() } methods, an IllegalStateException will be thrown if the port has been closed. |
* |
* @author rm5248 |
* |
*/ |
public class SerialPort implements Closeable { |
static{ |
System.loadLibrary( "javaserial" ); |
} |
/** |
* Represents the BaudRate that the SerialPort uses. |
*/ |
public enum BaudRate{ |
/** Not available in Windows */ |
B0, |
/** Not available in Windows */ |
B50, |
/** Not available in Windows */ |
B75, |
B110, |
/** Not available in Windows */ |
B134, |
/** Not available in Windows */ |
B150, |
B200, |
B300, |
B600, |
B1200, |
/** Not available in Windows */ |
B1800, |
B2400, |
B4800, |
B9600, |
B38400, |
B115200 |
} |
/** |
* Represents the number of bits that the serial port uses. |
* Typically, this is 8-bit characters. |
*/ |
public enum DataBits{ |
DATABITS_5, |
DATABITS_6, |
DATABITS_7, |
DATABITS_8 |
} |
/** |
* The number of stop bits for data. Typically this is 1. |
*/ |
public enum StopBits{ |
STOPBITS_1, |
STOPBITS_2 |
} |
/** |
* The parity bit for the data. Typically None. |
*/ |
public enum Parity{ |
NONE, |
EVEN, |
ODD |
} |
/** |
* The Flow control scheme for the data, typically None. |
*/ |
public enum FlowControl{ |
NONE, |
HARDWARE, |
SOFTWARE |
} |
private class SerialStateListener implements Runnable{ |
private volatile boolean stop; |
private SerialChangeListener listen; |
SerialStateListener( SerialChangeListener listen ){ |
stop = false; |
this.listen = listen; |
} |
@Override |
public void run() { |
while( !stop ){ |
synchronized( serialListenSync ){ |
try { |
serialListenSync.wait(); |
if( stop ){ |
break; |
} |
listen.serialStateChanged( state ); |
} catch (Exception e) {} |
} |
} |
} |
void doStop(){ |
stop = true; |
} |
} |
/* The handle to our internal data structure which keeps track of the port settings. |
* We need a special structure, as on windows we have a HANDLE type, which is void*, |
* yet on Linux we have a file descriptor, which is an int. |
* This is not just a pointer to memory, because if we're running on a 64-bit |
* system, then we might have problems putting it in 32-bits. Better safe than sorry. |
*/ |
private int handle; |
/* The input stream that user code uses to read from the serial port. */ |
private SerialInputStream inputStream; |
/* The buffered serial input stream which filters out events for us. */ |
private BufferedSerialInputStream bis; |
/* The output stream that user code uses to write to the serial port. */ |
private SerialOutputStream outputStream; |
/* Make sure we don't close ourselves twice */ |
private boolean closed; |
/* The name of the port that's currently open */ |
private String portName; |
/* Cache of the last gotten serial line state */ |
private volatile SerialLineState state; |
/* Runs in the background to check for serial port events */ |
private SerialStateListener serialListen; |
/* Used for synchronizing serialListen */ |
private Object serialListenSync; |
/** |
* Open the specified port, 9600 baud, 8 data bits, 1 stop bit, no parity, no flow control |
* |
* @param portName The name of the port to open |
* @throws NoSuchPortException If this port does not exist |
* @throws NotASerialPortException If the specified port is not a serial port |
*/ |
public SerialPort( String portName ) throws NoSuchPortException, NotASerialPortException { |
this( portName, BaudRate.B9600 ); |
} |
/** |
* Open up a serial port, but allow the user to keep the current settings of the serial port. |
* |
* @param portName The port to open |
* @param keepSettings If true, will simply open the serial port without setting anything. If false, this method |
* acts the same as {@link #SerialPort(String) SerialPort( String portName ) } |
* @throws NoSuchPortException If the port does not exist |
* @throws NotASerialPortException If the port is not in fact a serial port |
*/ |
public SerialPort( String portName, boolean keepSettings ) throws NoSuchPortException, NotASerialPortException{ |
if( portName == null ){ |
throw new IllegalArgumentException( "portName must not be null" ); |
} |
if( keepSettings ){ |
this.handle = openPort( portName ); |
this.portName = portName; |
inputStream = new SerialInputStream( handle ); |
bis = new BufferedSerialInputStream( inputStream, this ); |
outputStream = new SerialOutputStream( handle ); |
closed = false; |
SerialLineState s = new SerialLineState(); |
int state = getSerialLineStateInternalNonblocking(); |
// do some sort of bitwise operations here.... |
if( ( state & 0x01 ) > 0 ){ |
s.carrierDetect = true; |
} |
if( ( state & (0x01 << 1 ) ) > 0 ){ |
s.clearToSend = true; |
} |
if( ( state & (0x01 << 2 ) ) > 0 ){ |
s.dataSetReady = true; |
} |
if( ( state & (0x01 << 3 ) ) > 0 ){ |
s.dataTerminalReady = true; |
} |
if( ( state & (0x01 << 4 ) ) > 0 ){ |
s.requestToSend = true; |
} |
if( ( state & (0x01 << 5 ) ) > 0 ){ |
s.ringIndicator = true; |
} |
this.state = s; |
serialListenSync = new Object(); |
}else{ |
this.handle = openPort( portName, 9600, 8, 1, 0, 0 ); |
} |
new Thread( bis, "BufferedSerialReader" ).start(); |
} |
/** |
* Open the specified port, no flow control |
* |
* @param portName The name of the port to open |
* @param rate The Baud Rate to open this port at |
* @throws NoSuchPortException If this port does not exist |
* @throws NotASerialPortException If the specified port is not a serial port |
*/ |
public SerialPort( String portName, BaudRate rate )throws NoSuchPortException, NotASerialPortException { |
this( portName, rate, DataBits.DATABITS_8 ); |
} |
/** |
* Open the specified port, no flow control |
* |
* @param portName The name of the port to open |
* @param rate The Baud Rate to open this port at |
* @param data The number of data bits |
* @throws NoSuchPortException If this port does not exist |
* @throws NotASerialPortException If the specified port is not a serial port |
*/ |
public SerialPort( String portName, BaudRate rate, DataBits data ) throws NoSuchPortException, NotASerialPortException { |
this( portName, rate, data, StopBits.STOPBITS_1 ); |
} |
/** |
* Open the specified port, no parity or flow control |
* |
* @param portName The name of the port to open |
* @param rate The Baud Rate to open this port at |
* @param data The number of data bits |
* @param stop The number of stop bits |
* @throws NoSuchPortException If this port does not exist |
* @throws NotASerialPortException If the specified port is not a serial port |
*/ |
public SerialPort( String portName, BaudRate rate, DataBits data, StopBits stop ) throws NoSuchPortException, NotASerialPortException { |
this( portName, rate, data, stop, Parity.NONE ); |
} |
/** |
* Open the specified port, no flow control |
* |
* @param portName The name of the port to open |
* @param rate The Baud Rate to open this port at |
* @param data The number of data bits |
* @param stop The number of stop bits |
* @param parity The parity of the line |
* @throws NoSuchPortException If this port does not exist |
* @throws NotASerialPortException If the specified port is not a serial port |
*/ |
public SerialPort( String portName, BaudRate rate, DataBits data, StopBits stop, Parity parity ) throws NoSuchPortException, NotASerialPortException { |
this( portName, rate, data, stop, parity, FlowControl.NONE ); |
} |
/** |
* Open the specified port, defining all options |
* |
* @param portName The name of the port to open |
* @param rate The Buad Rate to open this port at |
* @param data The number of data bits |
* @param stop The number of stop bits |
* @param parity The parity of the line |
* @param flow The flow control of the line |
* @throws NoSuchPortException If this port does not exist |
* @throws NotASerialPortException If the specified port is not a serial port |
*/ |
public SerialPort( String portName, BaudRate rate, DataBits data, StopBits stop, Parity parity, FlowControl flow ) throws NoSuchPortException, NotASerialPortException { |
int myRate = 0; |
int myData = 0; |
int myStop = 0; |
int myParity = 0; |
int myFlow = 0; |
SerialLineState s; |
int state; |
//Check for null values in our arguments |
if( portName == null ){ |
throw new IllegalArgumentException( "portName must not be null" ); |
} |
if( rate == null ){ |
throw new IllegalArgumentException( "rate must not be null" ); |
} |
if( data == null ){ |
throw new IllegalArgumentException( "data must not be null" ); |
} |
if( stop == null ){ |
throw new IllegalArgumentException( "stop must not be null" ); |
} |
if( parity == null ){ |
throw new IllegalArgumentException( "parity must not be null" ); |
} |
if( flow == null ){ |
throw new IllegalArgumentException( "flow must not be null" ); |
} |
//Okay, looks like we're good! |
this.portName = portName; |
closed = false; |
switch( rate ){ |
case B0 : myRate = 0; break; |
case B50 : myRate = 50; break; |
case B75 : myRate = 75; break; |
case B110 : myRate = 110; break; |
case B134 : myRate = 134; break; |
case B150 : myRate = 150; break; |
case B200 : myRate = 200; break; |
case B300 : myRate = 300; break; |
case B600 : myRate = 600; break; |
case B1200 : myRate = 1200; break; |
case B1800 : myRate = 1800; break; |
case B2400 : myRate = 2400; break; |
case B4800 : myRate = 4800; break; |
case B9600 : myRate = 9600; break; |
case B38400 : myRate = 38400; break; |
case B115200: myRate = 115200; break; |
} |
switch( data ){ |
case DATABITS_5: myData = 5; break; |
case DATABITS_6: myData = 6; break; |
case DATABITS_7: myData = 7; break; |
case DATABITS_8: myData = 8; break; |
} |
switch( stop ){ |
case STOPBITS_1: myStop = 1; break; |
case STOPBITS_2: myStop = 2; break; |
} |
switch( parity ){ |
case NONE: myParity = 0; break; |
case ODD: myParity = 1; break; |
case EVEN: myParity = 2; break; |
} |
switch( flow ){ |
case NONE: myFlow = 0; break; |
case HARDWARE: myFlow = 1; break; |
case SOFTWARE: myFlow = 2; break; |
} |
handle = openPort(portName, myRate, myData, myStop, myParity, myFlow); |
inputStream = new SerialInputStream( handle ); |
bis = new BufferedSerialInputStream( inputStream, this ); |
outputStream = new SerialOutputStream( handle ); |
s = new SerialLineState(); |
state = getSerialLineStateInternalNonblocking(); |
if( ( state & 0x01 ) > 0 ){ |
s.carrierDetect = true; |
} |
if( ( state & (0x01 << 1 ) ) > 0 ){ |
s.clearToSend = true; |
} |
if( ( state & (0x01 << 2 ) ) > 0 ){ |
s.dataSetReady = true; |
} |
if( ( state & (0x01 << 3 ) ) > 0 ){ |
s.dataTerminalReady = true; |
} |
if( ( state & (0x01 << 4 ) ) > 0 ){ |
s.requestToSend = true; |
} |
if( ( state & (0x01 << 5 ) ) > 0 ){ |
s.ringIndicator = true; |
} |
this.state = s; |
serialListenSync = new Object(); |
new Thread( bis, "BufferedSerialReader" ).start(); |
} |
/** |
* Set the Baud Rate for this port. |
* |
* @param rate |
*/ |
public void setBaudRate( BaudRate rate ){ |
int myRate = 0; |
if( closed ){ |
throw new IllegalStateException( "Cannot set the BaudRate once the port has been closed." ); |
} |
if( rate == null ){ |
throw new IllegalArgumentException( "rate must not be null" ); |
} |
switch( rate ){ |
case B0 : myRate = 0; break; |
case B50 : myRate = 50; break; |
case B75 : myRate = 75; break; |
case B110 : myRate = 110; break; |
case B134 : myRate = 134; break; |
case B150 : myRate = 150; break; |
case B200 : myRate = 200; break; |
case B300 : myRate = 300; break; |
case B600 : myRate = 600; break; |
case B1200 : myRate = 1200; break; |
case B1800 : myRate = 1800; break; |
case B2400 : myRate = 2400; break; |
case B4800 : myRate = 4800; break; |
case B9600 : myRate = 9600; break; |
case B38400 : myRate = 38400; break; |
case B115200: myRate = 115200; break; |
} |
setBaudRate( myRate ); |
} |
/** |
* Get the input stream to be used to read from this SerialPort. |
* |
* @return The input stream. |
*/ |
public InputStream getInputStream(){ |
if( closed ){ |
throw new IllegalStateException( "Cannot get the input stream once the port has been closed." ); |
} |
return bis; |
} |
/** Get the output stream used to write data to this device. |
* |
* @return The output stream. |
*/ |
public OutputStream getOutputStream(){ |
if( closed ){ |
throw new IllegalStateException( "Cannot get the output stream once the port has been closed." ); |
} |
return outputStream; |
} |
/** |
* Close the serial port, and all input streams |
*/ |
public void close(){ |
if( closed ) return; |
closed = true; |
doClose(); |
if( serialListen != null ){ |
serialListen.doStop(); |
} |
synchronized( serialListenSync ){ |
serialListenSync.notify(); |
} |
} |
/** |
* See if the port has been closed already. |
* @return |
*/ |
public boolean isClosed(){ |
return closed; |
} |
public void finalize(){ |
close(); |
} |
/** |
* Set the stop bits of the serial port, after the port has been opened. |
* |
* @param stop |
*/ |
public void setStopBits( StopBits stop ){ |
int myStop = 0; |
if( closed ){ |
throw new IllegalStateException( "Cannot set the StopBits once the port has been closed." ); |
} |
if( stop == null ){ |
throw new IllegalArgumentException( "stop must not be null" ); |
} |
switch( stop ){ |
case STOPBITS_1: myStop = 1; break; |
case STOPBITS_2: myStop = 2; break; |
} |
setStopBits( myStop ); |
} |
/** |
* Set the data bits size, after the port has been opened. |
* |
* @param data |
*/ |
public void setDataSize( DataBits data ){ |
int myData = 0; |
if( closed ){ |
throw new IllegalStateException( "Cannot set the DataBits once the port has been closed." ); |
} |
if( data == null ){ |
throw new IllegalArgumentException( "data must not be null" ); |
} |
switch( data ){ |
case DATABITS_5: myData = 5; break; |
case DATABITS_6: myData = 6; break; |
case DATABITS_7: myData = 7; break; |
case DATABITS_8: myData = 8; break; |
} |
setCharSize( myData ); |
} |
/** |
* Set the parity of the serial port, after the port has been opened. |
* |
* @param parity |
*/ |
public void setParity( Parity parity ){ |
int myParity = 0; |
if( closed ){ |
throw new IllegalStateException( "Cannot set the parity once the port has been closed." ); |
} |
if( parity == null ){ |
throw new IllegalArgumentException( "parity must not be null" ); |
} |
switch( parity ){ |
case NONE: myParity = 0; break; |
case ODD: myParity = 1; break; |
case EVEN: myParity = 2; break; |
} |
setParity( myParity ); |
} |
/** |
* Get the serial line state for the specified serial port. |
* |
* @return |
*/ |
public SerialLineState getSerialLineState() throws IOException{ |
if( closed ){ |
throw new IllegalStateException( "Cannot get the serial line state once the port has been closed." ); |
} |
int gotState = getSerialLineStateInternalNonblocking(); |
SerialLineState s = new SerialLineState(); |
// do some sort of bitwise operations here.... |
if( ( gotState & 0x01 ) > 0 ){ |
s.carrierDetect = true; |
} |
if( ( gotState & (0x01 << 1 ) ) > 0 ){ |
s.clearToSend = true; |
} |
if( ( gotState & (0x01 << 2 ) ) > 0 ){ |
s.dataSetReady = true; |
} |
if( ( gotState & (0x01 << 3 ) ) > 0 ){ |
s.dataTerminalReady = true; |
} |
if( ( gotState & (0x01 << 4 ) ) > 0 ){ |
s.requestToSend = true; |
} |
if( ( gotState & (0x01 << 5 ) ) > 0 ){ |
s.ringIndicator = true; |
} |
return s; |
} |
/** |
* Set the serial line state to the parameters given. |
* |
* @param state |
*/ |
public void setSerialLineState( SerialLineState state ){ |
if( closed ){ |
throw new IllegalStateException( "Cannot set the serial line state once the port has been closed." ); |
} |
setSerialLineStateInternal( state ); |
//Now, because Windows is weird, we need to post a serial changed event here. |
//however, since we can only set DTR and RTS, only post an event if those are |
//the things that changed |
if( this.state.dataTerminalReady != state.dataTerminalReady || |
this.state.requestToSend != state.requestToSend ){ |
this.postSerialChangedEvent( state ); |
} |
} |
/** |
* Get the baud rate of the serial port. |
* |
* @return |
*/ |
public SerialPort.BaudRate getBaudRate(){ |
int baudRate; |
BaudRate toReturn; |
if( closed ){ |
throw new IllegalStateException( "Cannot get the baud rate once the port has been closed." ); |
} |
baudRate = getBaudRateInternal(); |
toReturn = BaudRate.B0; |
switch( baudRate ){ |
case 0 : toReturn = BaudRate.B0 ; break; |
case 50 : toReturn = BaudRate.B50 ; break; |
case 75 : toReturn = BaudRate.B75 ; break; |
case 110 : toReturn = BaudRate.B110 ; break; |
case 134 : toReturn = BaudRate.B134 ; break; |
case 150 : toReturn = BaudRate.B150 ; break; |
case 200 : toReturn = BaudRate.B200 ; break; |
case 300 : toReturn = BaudRate.B300 ; break; |
case 600 : toReturn = BaudRate.B600 ; break; |
case 1200 : toReturn = BaudRate.B1200 ; break; |
case 1800 : toReturn = BaudRate.B1800 ; break; |
case 2400 : toReturn = BaudRate.B2400 ; break; |
case 4800 : toReturn = BaudRate.B4800 ; break; |
case 9600 : toReturn = BaudRate.B9600 ; break; |
case 38400 : toReturn = BaudRate.B38400 ; break; |
case 115200: toReturn = BaudRate.B115200; break; |
} |
return toReturn; |
} |
/** |
* Get the number of data bits. |
* |
* @return |
*/ |
public SerialPort.DataBits getDataBits(){ |
int dataBits; |
DataBits bits; |
if( closed ){ |
throw new IllegalStateException( "Cannot get the data bits once the port has been closed." ); |
} |
dataBits = getCharSizeInternal(); |
bits = DataBits.DATABITS_8; |
switch( dataBits ){ |
case 8: bits = DataBits.DATABITS_8; break; |
case 7: bits = DataBits.DATABITS_7; break; |
case 6: bits = DataBits.DATABITS_6; break; |
case 5: bits = DataBits.DATABITS_5; break; |
} |
return bits; |
} |
/** |
* Get the number of stop bits. |
* |
* @return |
*/ |
public SerialPort.StopBits getStopBits(){ |
int stopBits; |
StopBits bits; |
if( closed ){ |
throw new IllegalStateException( "Cannot get stop bits once the port has been closed." ); |
} |
stopBits = getStopBitsInternal(); |
bits = StopBits.STOPBITS_1; |
switch( stopBits ){ |
case 1: bits = StopBits.STOPBITS_1; break; |
case 2: bits = StopBits.STOPBITS_2; break; |
} |
return bits; |
} |
/** |
* Get the parity of the serial port. |
* |
* @return |
*/ |
public SerialPort.Parity getParity(){ |
int parity; |
Parity par; |
if( closed ){ |
throw new IllegalStateException( "Cannot get the parity once the port has been closed." ); |
} |
parity = getParityInternal(); |
par = Parity.NONE; |
switch( parity ){ |
case 0: par = Parity.NONE; break; |
case 1: par = Parity.ODD; break; |
case 2: par = Parity.EVEN; break; |
} |
return par; |
} |
/** |
* Get the flow control for the serial port. |
* |
* @return |
*/ |
public SerialPort.FlowControl getFlowControl(){ |
int flowControl; |
FlowControl cont; |
if( closed ){ |
throw new IllegalStateException( "Cannot get the flow once the port has been closed." ); |
} |
flowControl = getFlowControlInternal(); |
cont = FlowControl.NONE; |
switch( flowControl ){ |
case 0: cont = FlowControl.NONE; break; |
case 1: cont = FlowControl.HARDWARE; break; |
case 2: cont = FlowControl.SOFTWARE; break; |
} |
return cont; |
} |
/** |
* Set the flow control for the serial port |
* |
* @param flow |
*/ |
public void setFlowControl( FlowControl flow ){ |
if( closed ){ |
throw new IllegalStateException( "Cannot set flow once the port has been closed." ); |
} |
switch( flow ){ |
case HARDWARE: setFlowControl( 1 ); break; |
case NONE: setFlowControl( 0 ); break; |
case SOFTWARE: setFlowControl( 2 ); break; |
} |
} |
/** |
* Set the listener which will get events when there is activity on the serial port. |
* Note that this activity does NOT include receive and transmit events - this is |
* changes on the lines of the serial port, such as RI, DSR, and DTR. |
* |
* If listen is null, will remove the listener. |
* |
* @param listen The listener which gets events |
*/ |
public void setSerialChangeListener( SerialChangeListener listen ){ |
if( serialListen != null ){ |
serialListen.doStop(); |
} |
if( listen != null ){ |
serialListen = new SerialStateListener( listen ); |
new Thread( serialListen, "SerialListen" ).start(); |
} |
} |
public String toString(){ |
return "Serial Port " + portName + ":" + getBaudRate(); |
} |
/** |
* Get the name of the serial port that this object represents. |
* @return |
*/ |
public String getPortName(){ |
return portName; |
} |
/** |
* This method is called when the state of the serial lines is changed. |
* |
* @param newState |
*/ |
void postSerialChangedEvent( SerialLineState newState ){ |
if( !state.equals( newState ) ){ |
state = newState; |
synchronized( serialListenSync ){ |
serialListenSync.notify(); |
} |
} |
} |
/** |
* Open the specified port, return an internal handle to the data structure for this port. |
* |
* @param portName |
* @return |
*/ |
private native int openPort( String portName, int baudRate, int dataBits, int stopBits, int parity, int flowControl ) throws NoSuchPortException, NotASerialPortException; |
/** |
* Open the specified port, return an internal handle for the data of this port. |
* This method DOES NOT set any of the serial port settings |
* |
* @param portName The port to open |
* @return |
*/ |
private native int openPort( String portName ) throws NoSuchPortException, NotASerialPortException; |
/** |
* Close this port, release all native resources |
*/ |
private native void doClose(); |
/** |
* Set the baud rate in the native code. |
* |
* @param baudRate |
* @return |
*/ |
private native boolean setBaudRate( int baudRate ); |
private native int getBaudRateInternal(); |
/** |
* Set the number of stop bits, once the port has been opened. |
* |
* @param stopBits |
* @return |
*/ |
private native boolean setStopBits( int stopBits ); |
private native int getStopBitsInternal(); |
/** |
* Set the character size, once the port has been opened. |
* This should probably be called 'setDataBits' |
* |
* @param charSize |
* @return |
*/ |
private native boolean setCharSize( int charSize ); |
private native int getCharSizeInternal(); |
/** Set the parity once the port has been opened. |
* |
* @param parity 0 = None, 1 = Odd, 2 = Even |
* @return |
*/ |
private native boolean setParity( int parity ); |
private native int getParityInternal(); |
/** Set the flow control once the port has been opened. |
* |
* |
* @param flowControl 0 = None, 1 = hardware, 2 = software |
* @return |
*/ |
private native boolean setFlowControl( int flowControl ); |
private native int getFlowControlInternal(); |
/** Get the serial line state, but don't block when getting it |
* |
* @return |
*/ |
private native int getSerialLineStateInternalNonblocking(); |
/** |
* Set the state of the serial line. |
* @return |
*/ |
private native int setSerialLineStateInternal( SerialLineState s ); |
// |
// Static Methods |
// |
/** |
* Get the major version of this library. For example, if this is version |
* 0.2, this returns 0 |
*/ |
public static int getMajorVersion(){ |
return 0; |
} |
/** |
* Get the minor version of this library. For example, if this is version |
* 0.2, this returns 2. |
*/ |
public static int getMinorVersion(){ |
return 4; |
} |
/** |
* Get the major version of the native code. This should match up with |
* {@link #getMajorVersion() getMajorVersion()}, although this is not |
* guaranteed. For example, if this is version 0.2, this returns 0 |
*/ |
public static native int getMajorNativeVersion(); |
/** |
* Get the minor version of the native code. This should match up with |
* {@link #getMinorVersion() getMinorVersion()}, although this is not |
* guaranteed. For example, if this is version 0.2, this returns 2. |
*/ |
public static native int getMinorNativeVersion(); |
/** |
* <p> |
* Get an array of all the serial ports on the system. For example, on |
* Windows this will return {@code { "COM1", "COM3", .... } } depending on how |
* many serial devices you have plugged in. On Linux, this returns |
* {@code { "/dev/ttyS0", "/dev/ttyUSB0", "/dev/symlink", ... } } |
* It will not resolve symlinks, such that if there is a symlink |
* from {@code /dev/symlink } to {@code /dev/ttyUSB0 }, they will both show up. |
* </p> |
* <p> |
* <b>NOTE:</b> this will only return ports that you have permissions to |
* open. |
* </p> |
* |
* @return |
*/ |
public static native String[] getSerialPorts(); |
} |
package com.rm5248.serial; |
import java.io.IOException; |
/** |
* A SerialPort represents a serial port on the system. |
* |
* All SerialPorts must implement this class. |
* |
* See the documentation for the subclasses on how to create |
* a specific instance of a SerialPort. |
* |
* @author rm5248 |
* |
*/ |
public interface SerialPort { |
/** |
* Represents the BaudRate that the SerialPort uses. |
*/ |
public enum BaudRate{ |
/** Not available in Windows */ |
B0, |
/** Not available in Windows */ |
B50, |
/** Not available in Windows */ |
B75, |
B110, |
/** Not available in Windows */ |
B134, |
/** Not available in Windows */ |
B150, |
B200, |
B300, |
B600, |
B1200, |
/** Not available in Windows */ |
B1800, |
B2400, |
B4800, |
B9600, |
B38400, |
B115200 |
} |
/** |
* Represents the number of bits that the serial port uses. |
* Typically, this is 8-bit characters. |
*/ |
public enum DataBits{ |
DATABITS_5, |
DATABITS_6, |
DATABITS_7, |
DATABITS_8 |
} |
/** |
* The number of stop bits for data. Typically this is 1. |
*/ |
public enum StopBits{ |
STOPBITS_1, |
STOPBITS_2 |
} |
/** |
* The parity bit for the data. Typically None. |
*/ |
public enum Parity{ |
NONE, |
EVEN, |
ODD |
} |
/** |
* The Flow control scheme for the data, typically None. |
*/ |
public enum FlowControl{ |
NONE, |
HARDWARE, |
SOFTWARE |
} |
/** |
* Set the Baud Rate for this port. |
* |
* @param rate |
*/ |
public abstract void setBaudRate(BaudRate rate); |
/** |
* Close the serial port, and all input streams |
*/ |
public abstract void close(); |
/** |
* See if the port has been closed already. |
* @return |
*/ |
public abstract boolean isClosed(); |
/** |
* Set the stop bits of the serial port, after the port has been opened. |
* |
* @param stop |
*/ |
public abstract void setStopBits(StopBits stop); |
/** |
* Set the data bits size, after the port has been opened. |
* |
* @param data |
*/ |
public abstract void setDataSize(DataBits data); |
/** |
* Set the parity of the serial port, after the port has been opened. |
* |
* @param parity |
*/ |
public abstract void setParity(Parity parity); |
/** |
* Get the serial line state for the specified serial port. |
* |
* @return |
*/ |
public abstract SerialLineState getSerialLineState() throws IOException; |
/** |
* Set the serial line state to the parameters given. |
* |
* @param state |
*/ |
public abstract void setSerialLineState(SerialLineState state); |
/** |
* Get the baud rate of the serial port. |
* |
* @return |
*/ |
public abstract IOSerialPort.BaudRate getBaudRate(); |
/** |
* Get the number of data bits. |
* |
* @return |
*/ |
public abstract IOSerialPort.DataBits getDataBits(); |
/** |
* Get the number of stop bits. |
* |
* @return |
*/ |
public abstract IOSerialPort.StopBits getStopBits(); |
/** |
* Get the parity of the serial port. |
* |
* @return |
*/ |
public abstract IOSerialPort.Parity getParity(); |
/** |
* Get the flow control for the serial port. |
* |
* @return |
*/ |
public abstract IOSerialPort.FlowControl getFlowControl(); |
/** |
* Set the flow control for the serial port |
* |
* @param flow |
*/ |
public abstract void setFlowControl(FlowControl flow); |
/** |
* Set the listener which will get events when there is activity on the serial port. |
* Note that this activity does NOT include receive and transmit events - this is |
* changes on the lines of the serial port, such as RI, DSR, and DTR. |
* |
* If listen is null, will remove the listener. |
* |
* @param listen The listener which gets events |
*/ |
public abstract void setSerialChangeListener(SerialChangeListener listen); |
/** |
* Get the name of the serial port that this object represents. |
* @return |
*/ |
public abstract String getPortName(); |
} |
/trunk/JavaSerial/src/com/rm5248/serial/NIOSerialPort.java |
---|
0,0 → 1,111 |
package com.rm5248.serial; |
import java.io.IOException; |
/** |
* An implementation of a serial port that uses NIO. |
* Note that this <b>DOES NOT</b> automatically listen for changes in |
* the serial line state. |
* |
* @author rm5248 |
* |
*/ |
public class NIOSerialPort implements SerialPort { |
@Override |
public void setBaudRate(BaudRate rate) { |
// TODO Auto-generated method stub |
} |
@Override |
public void close() { |
// TODO Auto-generated method stub |
} |
@Override |
public boolean isClosed() { |
// TODO Auto-generated method stub |
return false; |
} |
@Override |
public void setStopBits(StopBits stop) { |
// TODO Auto-generated method stub |
} |
@Override |
public void setDataSize(DataBits data) { |
// TODO Auto-generated method stub |
} |
@Override |
public void setParity(Parity parity) { |
// TODO Auto-generated method stub |
} |
@Override |
public SerialLineState getSerialLineState() throws IOException { |
// TODO Auto-generated method stub |
return null; |
} |
@Override |
public void setSerialLineState(SerialLineState state) { |
// TODO Auto-generated method stub |
} |
@Override |
public BaudRate getBaudRate() { |
// TODO Auto-generated method stub |
return null; |
} |
@Override |
public DataBits getDataBits() { |
// TODO Auto-generated method stub |
return null; |
} |
@Override |
public StopBits getStopBits() { |
// TODO Auto-generated method stub |
return null; |
} |
@Override |
public Parity getParity() { |
// TODO Auto-generated method stub |
return null; |
} |
@Override |
public FlowControl getFlowControl() { |
// TODO Auto-generated method stub |
return null; |
} |
@Override |
public void setFlowControl(FlowControl flow) { |
// TODO Auto-generated method stub |
} |
@Override |
public void setSerialChangeListener(SerialChangeListener listen) { |
// TODO Auto-generated method stub |
} |
@Override |
public String getPortName() { |
// TODO Auto-generated method stub |
return null; |
} |
} |
/trunk/JavaSerial/src/com/rm5248/serial/SerialInputStream.java |
---|
4,7 → 4,9 |
import java.io.InputStream; |
/** |
* Input stream for the serial port. |
* Input stream for the serial port. This implementation passes back the |
* status of the control lines in the upper bits of {@code read()}, and |
* thus must be parsed properly. |
*/ |
class SerialInputStream extends InputStream{ |
/* The handle to read from. Needed for native implementation */ |
29,4 → 31,33 |
private native int readByte() throws IOException; |
private native int getAvailable() throws IOException; |
} |
/** |
* A SimpleSerialInputStream does not pass back the status of the control |
* lines on the serial port - just the raw bytes. |
*/ |
class SimpleSerialInputStream extends InputStream { |
/* The handle to read from. Needed for native implementation */ |
@SuppressWarnings("unused") |
private int handle; |
SimpleSerialInputStream( int handle ){ |
this.handle = handle; |
} |
@Override |
public int read() throws IOException{ |
return readByte(); |
} |
@Override |
public int available() throws IOException{ |
return getAvailable(); |
} |
private native int readByte() throws IOException; |
private native int getAvailable() throws IOException; |
} |
/trunk/JavaSerial/src/com/rm5248/serial/IOSerialPort.java |
---|
0,0 → 1,894 |
package com.rm5248.serial; |
import java.io.Closeable; |
import java.io.IOException; |
import java.io.InputStream; |
import java.io.OutputStream; |
/** |
* A SerialPort object represents a SerialPort object on the system. This implementation uses |
* the STREAMS(IO) based method of accessing a serial port. |
* |
* When creating a SerialPort object, you give the SerialPort the name of the port that you |
* wish to open. |
* |
* When opening a SerialPort and setting values, an {@link IllegalArgumentException} may be thrown |
* if any of the values are NULL. |
* |
* When getting and settings the properties of the SerialPort using one of the {@code getXXX() } |
* or {@code setXXX() } methods, an IllegalStateException will be thrown if the port has been closed. |
* |
* @author rm5248 |
* |
*/ |
public class IOSerialPort implements Closeable, SerialPort { |
static{ |
System.loadLibrary( "javaserial" ); |
} |
private class SerialStateListener implements Runnable{ |
private volatile boolean stop; |
private SerialChangeListener listen; |
SerialStateListener( SerialChangeListener listen ){ |
stop = false; |
this.listen = listen; |
} |
@Override |
public void run() { |
while( !stop ){ |
synchronized( serialListenSync ){ |
try { |
serialListenSync.wait(); |
if( stop ){ |
break; |
} |
listen.serialStateChanged( state ); |
} catch (Exception e) {} |
} |
} |
} |
void doStop(){ |
stop = true; |
} |
} |
/* The handle to our internal data structure which keeps track of the port settings. |
* We need a special structure, as on windows we have a HANDLE type, which is void*, |
* yet on Linux we have a file descriptor, which is an int. |
* This is not just a pointer to memory, because if we're running on a 64-bit |
* system, then we might have problems putting it in 32-bits. Better safe than sorry. |
*/ |
private int handle; |
/* The input stream that user code uses to read from the serial port. */ |
private InputStream inputStream; |
/* The buffered serial input stream which filters out events for us. */ |
private BufferedSerialInputStream bis; |
/* The output stream that user code uses to write to the serial port. */ |
private SerialOutputStream outputStream; |
/* Make sure we don't close ourselves twice */ |
private boolean closed; |
/* The name of the port that's currently open */ |
private String portName; |
/* Cache of the last gotten serial line state */ |
private volatile SerialLineState state; |
/* Runs in the background to check for serial port events */ |
private SerialStateListener serialListen; |
/* Used for synchronizing serialListen */ |
private Object serialListenSync; |
/* Depending on if we have a BufferedSerialInputStream or a normal InputStream, |
* this will be set. |
* Note that 'ignoring control lines' really means that we ignore CHANGES on |
* the control lines; it should still be possible to get the state of the lines, |
* you just won't be notified immediately. |
*/ |
private boolean ignoringControlLines; |
/** |
* Open the specified port, 9600 baud, 8 data bits, 1 stop bit, no parity, no flow control, |
* not ignoring control lines |
* |
* @param portName The name of the port to open |
* @throws NoSuchPortException If this port does not exist |
* @throws NotASerialPortException If the specified port is not a serial port |
*/ |
public IOSerialPort( String portName ) throws NoSuchPortException, NotASerialPortException { |
this( portName, BaudRate.B9600 ); |
} |
/** |
* Open up a serial port, but allow the user to keep the current settings of the serial port. |
* |
* @param portName The port to open |
* @param keepSettings If true, will simply open the serial port without setting anything. If false, this method |
* acts the same as {@link #SerialPort(String) SerialPort( String portName ) } |
* @param ignoreControlLines If true, all control line changes will be ignored and not propogated |
* back through a {@link SerialChangeListener}. |
* @throws NoSuchPortException If the port does not exist |
* @throws NotASerialPortException If the port is not in fact a serial port |
*/ |
public IOSerialPort( String portName, boolean keepSettings, boolean ignoreControlLines ) throws NoSuchPortException, NotASerialPortException{ |
if( portName == null ){ |
throw new IllegalArgumentException( "portName must not be null" ); |
} |
if( keepSettings ){ |
this.handle = openPort( portName ); |
this.portName = portName; |
this.ignoringControlLines = ignoreControlLines; |
if( ignoreControlLines ){ |
SimpleSerialInputStream ssis = new SimpleSerialInputStream( handle ); |
inputStream = ssis; |
}else{ |
SerialInputStream sis = new SerialInputStream( handle ); |
inputStream = sis; |
bis = new BufferedSerialInputStream( sis, this ); |
} |
outputStream = new SerialOutputStream( handle ); |
closed = false; |
SerialLineState s = new SerialLineState(); |
int state = getSerialLineStateInternalNonblocking(); |
// do some sort of bitwise operations here.... |
if( ( state & 0x01 ) > 0 ){ |
s.carrierDetect = true; |
} |
if( ( state & (0x01 << 1 ) ) > 0 ){ |
s.clearToSend = true; |
} |
if( ( state & (0x01 << 2 ) ) > 0 ){ |
s.dataSetReady = true; |
} |
if( ( state & (0x01 << 3 ) ) > 0 ){ |
s.dataTerminalReady = true; |
} |
if( ( state & (0x01 << 4 ) ) > 0 ){ |
s.requestToSend = true; |
} |
if( ( state & (0x01 << 5 ) ) > 0 ){ |
s.ringIndicator = true; |
} |
this.state = s; |
serialListenSync = new Object(); |
}else{ |
this.handle = openPort( portName, 9600, 8, 1, 0, 0 ); |
} |
if( !ignoreControlLines ){ |
new Thread( bis, "BufferedSerialReader-" + portName ).start(); |
} |
} |
/** |
* Open the specified port, no flow control |
* |
* @param portName The name of the port to open |
* @param rate The Baud Rate to open this port at |
* @throws NoSuchPortException If this port does not exist |
* @throws NotASerialPortException If the specified port is not a serial port |
*/ |
public IOSerialPort( String portName, BaudRate rate )throws NoSuchPortException, NotASerialPortException { |
this( portName, rate, DataBits.DATABITS_8 ); |
} |
/** |
* Open the specified port, no flow control |
* |
* @param portName The name of the port to open |
* @param rate The Baud Rate to open this port at |
* @param data The number of data bits |
* @throws NoSuchPortException If this port does not exist |
* @throws NotASerialPortException If the specified port is not a serial port |
*/ |
public IOSerialPort( String portName, BaudRate rate, DataBits data ) throws NoSuchPortException, NotASerialPortException { |
this( portName, rate, data, StopBits.STOPBITS_1 ); |
} |
/** |
* Open the specified port, no parity or flow control |
* |
* @param portName The name of the port to open |
* @param rate The Baud Rate to open this port at |
* @param data The number of data bits |
* @param stop The number of stop bits |
* @throws NoSuchPortException If this port does not exist |
* @throws NotASerialPortException If the specified port is not a serial port |
*/ |
public IOSerialPort( String portName, BaudRate rate, DataBits data, StopBits stop ) throws NoSuchPortException, NotASerialPortException { |
this( portName, rate, data, stop, Parity.NONE ); |
} |
/** |
* Open the specified port, no flow control |
* |
* @param portName The name of the port to open |
* @param rate The Baud Rate to open this port at |
* @param data The number of data bits |
* @param stop The number of stop bits |
* @param parity The parity of the line |
* @throws NoSuchPortException If this port does not exist |
* @throws NotASerialPortException If the specified port is not a serial port |
*/ |
public IOSerialPort( String portName, BaudRate rate, DataBits data, StopBits stop, Parity parity ) throws NoSuchPortException, NotASerialPortException { |
this( portName, rate, data, stop, parity, FlowControl.NONE ); |
} |
/** |
* Open the specified port, defining all options |
* |
* @param portName The name of the port to open |
* @param rate The Buad Rate to open this port at |
* @param data The number of data bits |
* @param stop The number of stop bits |
* @param parity The parity of the line |
* @param flow The flow control of the line |
* @throws NoSuchPortException If this port does not exist |
* @throws NotASerialPortException If the specified port is not a serial port |
*/ |
public IOSerialPort( String portName, BaudRate rate, DataBits data, StopBits stop, Parity parity, FlowControl flow ) throws NoSuchPortException, NotASerialPortException { |
int myRate = 0; |
int myData = 0; |
int myStop = 0; |
int myParity = 0; |
int myFlow = 0; |
SerialLineState s; |
int state; |
SerialInputStream sis; |
//Check for null values in our arguments |
if( portName == null ){ |
throw new IllegalArgumentException( "portName must not be null" ); |
} |
if( rate == null ){ |
throw new IllegalArgumentException( "rate must not be null" ); |
} |
if( data == null ){ |
throw new IllegalArgumentException( "data must not be null" ); |
} |
if( stop == null ){ |
throw new IllegalArgumentException( "stop must not be null" ); |
} |
if( parity == null ){ |
throw new IllegalArgumentException( "parity must not be null" ); |
} |
if( flow == null ){ |
throw new IllegalArgumentException( "flow must not be null" ); |
} |
//Okay, looks like we're good! |
this.portName = portName; |
closed = false; |
ignoringControlLines = false; |
switch( rate ){ |
case B0 : myRate = 0; break; |
case B50 : myRate = 50; break; |
case B75 : myRate = 75; break; |
case B110 : myRate = 110; break; |
case B134 : myRate = 134; break; |
case B150 : myRate = 150; break; |
case B200 : myRate = 200; break; |
case B300 : myRate = 300; break; |
case B600 : myRate = 600; break; |
case B1200 : myRate = 1200; break; |
case B1800 : myRate = 1800; break; |
case B2400 : myRate = 2400; break; |
case B4800 : myRate = 4800; break; |
case B9600 : myRate = 9600; break; |
case B38400 : myRate = 38400; break; |
case B115200: myRate = 115200; break; |
} |
switch( data ){ |
case DATABITS_5: myData = 5; break; |
case DATABITS_6: myData = 6; break; |
case DATABITS_7: myData = 7; break; |
case DATABITS_8: myData = 8; break; |
} |
switch( stop ){ |
case STOPBITS_1: myStop = 1; break; |
case STOPBITS_2: myStop = 2; break; |
} |
switch( parity ){ |
case NONE: myParity = 0; break; |
case ODD: myParity = 1; break; |
case EVEN: myParity = 2; break; |
} |
switch( flow ){ |
case NONE: myFlow = 0; break; |
case HARDWARE: myFlow = 1; break; |
case SOFTWARE: myFlow = 2; break; |
} |
handle = openPort(portName, myRate, myData, myStop, myParity, myFlow); |
sis = new SerialInputStream( handle ); |
inputStream = sis; |
bis = new BufferedSerialInputStream( sis, this ); |
outputStream = new SerialOutputStream( handle ); |
s = new SerialLineState(); |
state = getSerialLineStateInternalNonblocking(); |
if( ( state & 0x01 ) > 0 ){ |
s.carrierDetect = true; |
} |
if( ( state & (0x01 << 1 ) ) > 0 ){ |
s.clearToSend = true; |
} |
if( ( state & (0x01 << 2 ) ) > 0 ){ |
s.dataSetReady = true; |
} |
if( ( state & (0x01 << 3 ) ) > 0 ){ |
s.dataTerminalReady = true; |
} |
if( ( state & (0x01 << 4 ) ) > 0 ){ |
s.requestToSend = true; |
} |
if( ( state & (0x01 << 5 ) ) > 0 ){ |
s.ringIndicator = true; |
} |
this.state = s; |
serialListenSync = new Object(); |
new Thread( bis, "BufferedSerialReader" ).start(); |
} |
/* (non-Javadoc) |
* @see com.rm5248.serial.SerialPortI#setBaudRate(com.rm5248.serial.SerialPort.BaudRate) |
*/ |
@Override |
public void setBaudRate( BaudRate rate ){ |
int myRate = 0; |
if( closed ){ |
throw new IllegalStateException( "Cannot set the BaudRate once the port has been closed." ); |
} |
if( rate == null ){ |
throw new IllegalArgumentException( "rate must not be null" ); |
} |
switch( rate ){ |
case B0 : myRate = 0; break; |
case B50 : myRate = 50; break; |
case B75 : myRate = 75; break; |
case B110 : myRate = 110; break; |
case B134 : myRate = 134; break; |
case B150 : myRate = 150; break; |
case B200 : myRate = 200; break; |
case B300 : myRate = 300; break; |
case B600 : myRate = 600; break; |
case B1200 : myRate = 1200; break; |
case B1800 : myRate = 1800; break; |
case B2400 : myRate = 2400; break; |
case B4800 : myRate = 4800; break; |
case B9600 : myRate = 9600; break; |
case B38400 : myRate = 38400; break; |
case B115200: myRate = 115200; break; |
} |
setBaudRate( myRate ); |
} |
/** |
* Get the input stream used to talk to this device. |
*/ |
public InputStream getInputStream(){ |
if( closed ){ |
throw new IllegalStateException( "Cannot get the input stream once the port has been closed." ); |
} |
if( ignoringControlLines ){ |
return inputStream; |
} |
return bis; |
} |
/** |
* Get the OutputStream used to talk to this device. |
*/ |
public OutputStream getOutputStream(){ |
if( closed ){ |
throw new IllegalStateException( "Cannot get the output stream once the port has been closed." ); |
} |
return outputStream; |
} |
/* (non-Javadoc) |
* @see com.rm5248.serial.SerialPortI#close() |
*/ |
@Override |
public void close(){ |
if( closed ) return; |
closed = true; |
doClose(); |
if( serialListen != null ){ |
serialListen.doStop(); |
} |
synchronized( serialListenSync ){ |
serialListenSync.notify(); |
} |
} |
/* (non-Javadoc) |
* @see com.rm5248.serial.SerialPortI#isClosed() |
*/ |
@Override |
public boolean isClosed(){ |
return closed; |
} |
public void finalize(){ |
close(); |
} |
/* (non-Javadoc) |
* @see com.rm5248.serial.SerialPortI#setStopBits(com.rm5248.serial.SerialPort.StopBits) |
*/ |
@Override |
public void setStopBits( StopBits stop ){ |
int myStop = 0; |
if( closed ){ |
throw new IllegalStateException( "Cannot set the StopBits once the port has been closed." ); |
} |
if( stop == null ){ |
throw new IllegalArgumentException( "stop must not be null" ); |
} |
switch( stop ){ |
case STOPBITS_1: myStop = 1; break; |
case STOPBITS_2: myStop = 2; break; |
} |
setStopBits( myStop ); |
} |
/* (non-Javadoc) |
* @see com.rm5248.serial.SerialPortI#setDataSize(com.rm5248.serial.SerialPort.DataBits) |
*/ |
@Override |
public void setDataSize( DataBits data ){ |
int myData = 0; |
if( closed ){ |
throw new IllegalStateException( "Cannot set the DataBits once the port has been closed." ); |
} |
if( data == null ){ |
throw new IllegalArgumentException( "data must not be null" ); |
} |
switch( data ){ |
case DATABITS_5: myData = 5; break; |
case DATABITS_6: myData = 6; break; |
case DATABITS_7: myData = 7; break; |
case DATABITS_8: myData = 8; break; |
} |
setCharSize( myData ); |
} |
/* (non-Javadoc) |
* @see com.rm5248.serial.SerialPortI#setParity(com.rm5248.serial.SerialPort.Parity) |
*/ |
@Override |
public void setParity( Parity parity ){ |
int myParity = 0; |
if( closed ){ |
throw new IllegalStateException( "Cannot set the parity once the port has been closed." ); |
} |
if( parity == null ){ |
throw new IllegalArgumentException( "parity must not be null" ); |
} |
switch( parity ){ |
case NONE: myParity = 0; break; |
case ODD: myParity = 1; break; |
case EVEN: myParity = 2; break; |
} |
setParity( myParity ); |
} |
/* (non-Javadoc) |
* @see com.rm5248.serial.SerialPortI#getSerialLineState() |
*/ |
@Override |
public SerialLineState getSerialLineState() throws IOException{ |
if( closed ){ |
throw new IllegalStateException( "Cannot get the serial line state once the port has been closed." ); |
} |
int gotState = getSerialLineStateInternalNonblocking(); |
SerialLineState s = new SerialLineState(); |
// do some sort of bitwise operations here.... |
if( ( gotState & 0x01 ) > 0 ){ |
s.carrierDetect = true; |
} |
if( ( gotState & (0x01 << 1 ) ) > 0 ){ |
s.clearToSend = true; |
} |
if( ( gotState & (0x01 << 2 ) ) > 0 ){ |
s.dataSetReady = true; |
} |
if( ( gotState & (0x01 << 3 ) ) > 0 ){ |
s.dataTerminalReady = true; |
} |
if( ( gotState & (0x01 << 4 ) ) > 0 ){ |
s.requestToSend = true; |
} |
if( ( gotState & (0x01 << 5 ) ) > 0 ){ |
s.ringIndicator = true; |
} |
return s; |
} |
/* (non-Javadoc) |
* @see com.rm5248.serial.SerialPortI#setSerialLineState(com.rm5248.serial.SerialLineState) |
*/ |
@Override |
public void setSerialLineState( SerialLineState state ){ |
if( closed ){ |
throw new IllegalStateException( "Cannot set the serial line state once the port has been closed." ); |
} |
setSerialLineStateInternal( state ); |
//Now, because Windows is weird, we need to post a serial changed event here. |
//however, since we can only set DTR and RTS, only post an event if those are |
//the things that changed |
if( this.state.dataTerminalReady != state.dataTerminalReady || |
this.state.requestToSend != state.requestToSend ){ |
this.postSerialChangedEvent( state ); |
} |
} |
/* (non-Javadoc) |
* @see com.rm5248.serial.SerialPortI#getBaudRate() |
*/ |
@Override |
public IOSerialPort.BaudRate getBaudRate(){ |
int baudRate; |
BaudRate toReturn; |
if( closed ){ |
throw new IllegalStateException( "Cannot get the baud rate once the port has been closed." ); |
} |
baudRate = getBaudRateInternal(); |
toReturn = BaudRate.B0; |
switch( baudRate ){ |
case 0 : toReturn = BaudRate.B0 ; break; |
case 50 : toReturn = BaudRate.B50 ; break; |
case 75 : toReturn = BaudRate.B75 ; break; |
case 110 : toReturn = BaudRate.B110 ; break; |
case 134 : toReturn = BaudRate.B134 ; break; |
case 150 : toReturn = BaudRate.B150 ; break; |
case 200 : toReturn = BaudRate.B200 ; break; |
case 300 : toReturn = BaudRate.B300 ; break; |
case 600 : toReturn = BaudRate.B600 ; break; |
case 1200 : toReturn = BaudRate.B1200 ; break; |
case 1800 : toReturn = BaudRate.B1800 ; break; |
case 2400 : toReturn = BaudRate.B2400 ; break; |
case 4800 : toReturn = BaudRate.B4800 ; break; |
case 9600 : toReturn = BaudRate.B9600 ; break; |
case 38400 : toReturn = BaudRate.B38400 ; break; |
case 115200: toReturn = BaudRate.B115200; break; |
} |
return toReturn; |
} |
/* (non-Javadoc) |
* @see com.rm5248.serial.SerialPortI#getDataBits() |
*/ |
@Override |
public IOSerialPort.DataBits getDataBits(){ |
int dataBits; |
DataBits bits; |
if( closed ){ |
throw new IllegalStateException( "Cannot get the data bits once the port has been closed." ); |
} |
dataBits = getCharSizeInternal(); |
bits = DataBits.DATABITS_8; |
switch( dataBits ){ |
case 8: bits = DataBits.DATABITS_8; break; |
case 7: bits = DataBits.DATABITS_7; break; |
case 6: bits = DataBits.DATABITS_6; break; |
case 5: bits = DataBits.DATABITS_5; break; |
} |
return bits; |
} |
/* (non-Javadoc) |
* @see com.rm5248.serial.SerialPortI#getStopBits() |
*/ |
@Override |
public IOSerialPort.StopBits getStopBits(){ |
int stopBits; |
StopBits bits; |
if( closed ){ |
throw new IllegalStateException( "Cannot get stop bits once the port has been closed." ); |
} |
stopBits = getStopBitsInternal(); |
bits = StopBits.STOPBITS_1; |
switch( stopBits ){ |
case 1: bits = StopBits.STOPBITS_1; break; |
case 2: bits = StopBits.STOPBITS_2; break; |
} |
return bits; |
} |
/* (non-Javadoc) |
* @see com.rm5248.serial.SerialPortI#getParity() |
*/ |
@Override |
public IOSerialPort.Parity getParity(){ |
int parity; |
Parity par; |
if( closed ){ |
throw new IllegalStateException( "Cannot get the parity once the port has been closed." ); |
} |
parity = getParityInternal(); |
par = Parity.NONE; |
switch( parity ){ |
case 0: par = Parity.NONE; break; |
case 1: par = Parity.ODD; break; |
case 2: par = Parity.EVEN; break; |
} |
return par; |
} |
/* (non-Javadoc) |
* @see com.rm5248.serial.SerialPortI#getFlowControl() |
*/ |
@Override |
public IOSerialPort.FlowControl getFlowControl(){ |
int flowControl; |
FlowControl cont; |
if( closed ){ |
throw new IllegalStateException( "Cannot get the flow once the port has been closed." ); |
} |
flowControl = getFlowControlInternal(); |
cont = FlowControl.NONE; |
switch( flowControl ){ |
case 0: cont = FlowControl.NONE; break; |
case 1: cont = FlowControl.HARDWARE; break; |
case 2: cont = FlowControl.SOFTWARE; break; |
} |
return cont; |
} |
/* (non-Javadoc) |
* @see com.rm5248.serial.SerialPortI#setFlowControl(com.rm5248.serial.SerialPort.FlowControl) |
*/ |
@Override |
public void setFlowControl( FlowControl flow ){ |
if( closed ){ |
throw new IllegalStateException( "Cannot set flow once the port has been closed." ); |
} |
switch( flow ){ |
case HARDWARE: setFlowControl( 1 ); break; |
case NONE: setFlowControl( 0 ); break; |
case SOFTWARE: setFlowControl( 2 ); break; |
} |
} |
/* (non-Javadoc) |
* @see com.rm5248.serial.SerialPortI#setSerialChangeListener(com.rm5248.serial.SerialChangeListener) |
*/ |
@Override |
public void setSerialChangeListener( SerialChangeListener listen ){ |
if( serialListen != null ){ |
serialListen.doStop(); |
} |
if( listen != null ){ |
serialListen = new SerialStateListener( listen ); |
new Thread( serialListen, "SerialListen" ).start(); |
} |
} |
public String toString(){ |
return "Serial Port " + portName + ":" + getBaudRate(); |
} |
/* (non-Javadoc) |
* @see com.rm5248.serial.SerialPortI#getPortName() |
*/ |
@Override |
public String getPortName(){ |
return portName; |
} |
/** |
* This method is called when the state of the serial lines is changed. |
* |
* @param newState |
*/ |
void postSerialChangedEvent( SerialLineState newState ){ |
if( !state.equals( newState ) ){ |
state = newState; |
synchronized( serialListenSync ){ |
serialListenSync.notify(); |
} |
} |
} |
/** |
* Open the specified port, return an internal handle to the data structure for this port. |
* |
* @param portName |
* @return |
*/ |
private native int openPort( String portName, int baudRate, int dataBits, int stopBits, int parity, int flowControl ) throws NoSuchPortException, NotASerialPortException; |
/** |
* Open the specified port, return an internal handle for the data of this port. |
* This method DOES NOT set any of the serial port settings |
* |
* @param portName The port to open |
* @return |
*/ |
private native int openPort( String portName ) throws NoSuchPortException, NotASerialPortException; |
/** |
* Close this port, release all native resources |
*/ |
private native void doClose(); |
/** |
* Set the baud rate in the native code. |
* |
* @param baudRate |
* @return |
*/ |
private native boolean setBaudRate( int baudRate ); |
private native int getBaudRateInternal(); |
/** |
* Set the number of stop bits, once the port has been opened. |
* |
* @param stopBits |
* @return |
*/ |
private native boolean setStopBits( int stopBits ); |
private native int getStopBitsInternal(); |
/** |
* Set the character size, once the port has been opened. |
* This should probably be called 'setDataBits' |
* |
* @param charSize |
* @return |
*/ |
private native boolean setCharSize( int charSize ); |
private native int getCharSizeInternal(); |
/** Set the parity once the port has been opened. |
* |
* @param parity 0 = None, 1 = Odd, 2 = Even |
* @return |
*/ |
private native boolean setParity( int parity ); |
private native int getParityInternal(); |
/** Set the flow control once the port has been opened. |
* |
* |
* @param flowControl 0 = None, 1 = hardware, 2 = software |
* @return |
*/ |
private native boolean setFlowControl( int flowControl ); |
private native int getFlowControlInternal(); |
/** Get the serial line state, but don't block when getting it |
* |
* @return |
*/ |
private native int getSerialLineStateInternalNonblocking(); |
/** |
* Set the state of the serial line. |
* @return |
*/ |
private native int setSerialLineStateInternal( SerialLineState s ); |
// |
// Static Methods |
// |
/** |
* Get the major version of this library. For example, if this is version |
* 0.2, this returns 0 |
*/ |
public static int getMajorVersion(){ |
return 0; |
} |
/** |
* Get the minor version of this library. For example, if this is version |
* 0.2, this returns 2. |
*/ |
public static int getMinorVersion(){ |
return 4; |
} |
/** |
* Get the major version of the native code. This should match up with |
* {@link #getMajorVersion() getMajorVersion()}, although this is not |
* guaranteed. For example, if this is version 0.2, this returns 0 |
*/ |
public static native int getMajorNativeVersion(); |
/** |
* Get the minor version of the native code. This should match up with |
* {@link #getMinorVersion() getMinorVersion()}, although this is not |
* guaranteed. For example, if this is version 0.2, this returns 2. |
*/ |
public static native int getMinorNativeVersion(); |
/** |
* <p> |
* Get an array of all the serial ports on the system. For example, on |
* Windows this will return {@code { "COM1", "COM3", .... } } depending on how |
* many serial devices you have plugged in. On Linux, this returns |
* {@code { "/dev/ttyS0", "/dev/ttyUSB0", "/dev/symlink", ... } } |
* It will not resolve symlinks, such that if there is a symlink |
* from {@code /dev/symlink } to {@code /dev/ttyUSB0 }, they will both show up. |
* </p> |
* <p> |
* <b>NOTE:</b> this will only return ports that you have permissions to |
* open. |
* </p> |
* |
* @return |
*/ |
public static native String[] getSerialPorts(); |
} |
/trunk/JavaSerial/src/com/rm5248/serial/BufferedSerialInputStream.java |
---|
20,10 → 20,10 |
private byte[] buffer; |
private int bufferBegin; |
private int bufferEnd; |
private SerialPort callback; |
private IOSerialPort callback; |
private IOException exceptionToThrow; |
BufferedSerialInputStream( SerialInputStream s, SerialPort callback ){ |
BufferedSerialInputStream( SerialInputStream s, IOSerialPort callback ){ |
stream = s; |
buffer = new byte[ 500 ]; |
bufferBegin = 0; |