Subversion Repositories Programming Utils

Compare Revisions

Ignore whitespace Rev 43 → Rev 44

/branches/JavaSerial/0.1/LICENSE
0,0 → 1,7
Copyright (c) 2013 rm5248
 
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/branches/JavaSerial/0.1/src/com/rm5248/serial/NoSuchPortException.java
0,0 → 1,24
package com.rm5248.serial;
 
/**
* This exception is thrown when you attempt to open up a port that does not exist.
*
* @author rm5248
*
*/
public class NoSuchPortException extends Exception {
 
/**
* Generated by Eclipse
*/
private static final long serialVersionUID = -5218448691940726352L;
 
/**
* Create a new exception with the specified error.
*
* @param status
*/
public NoSuchPortException( String status ){
super( status );
}
}
/branches/JavaSerial/0.1/src/com/rm5248/serial/SerialPort.java
0,0 → 1,776
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.
*
* @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 boolean stop;
private SerialChangeListener listen;
SerialStateListener( SerialChangeListener listen ){
stop = false;
this.listen = listen;
}
 
@Override
public void run() {
while( !stop ){
synchronized( serialListenSync ){
try {
serialListenSync.wait();
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 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( 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;
}else if( ( state & (0x01 << 1 ) ) > 0 ){
s.clearToSend = true;
}else if( ( state & (0x01 << 2 ) ) > 0 ){
s.dataSetReady = true;
}else if( ( state & (0x01 << 3 ) ) > 0 ){
s.dataTerminalReady = true;
}else if( ( state & (0x01 << 4 ) ) > 0 ){
s.requestToSend = true;
}else 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 Buad 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 Buad 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 Buad 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 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
* @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;
 
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;
}else if( ( state & (0x01 << 1 ) ) > 0 ){
s.clearToSend = true;
}else if( ( state & (0x01 << 2 ) ) > 0 ){
s.dataSetReady = true;
}else if( ( state & (0x01 << 3 ) ) > 0 ){
s.dataTerminalReady = true;
}else if( ( state & (0x01 << 4 ) ) > 0 ){
s.requestToSend = true;
}else 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
* @throws IllegalStateException if the port has already been closed.
*/
public void setBaudRate( BaudRate rate ){
int myRate = 0;
 
if( closed ){
throw new IllegalStateException( "Cannot set the BaudRate once the port has been closed." );
}
 
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.
* @throws IllegalStateException if the port has already been closed.
*/
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.
* @throws IllegalStateException if the port has already been closed.
*/
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();
}
 
/**
* 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
* @throws IllegalStateException if the port has already been closed.
*/
public void setStopBits( StopBits stop ){
int myStop = 0;
 
if( closed ){
throw new IllegalStateException( "Cannot set the StopBits once the port has been closed." );
}
 
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
* @throws IllegalStateException if the port has already been closed.
*/
public void setDataSize( DataBits data ){
int myData = 0;
 
if( closed ){
throw new IllegalStateException( "Cannot set the DataBits once the port has been closed." );
}
 
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
* @throws IllegalStateException if the port has been closed.
*/
public void setParity( Parity parity ){
int myParity = 0;
 
if( closed ){
throw new IllegalStateException( "Cannot set the parity once the port has been closed." );
}
 
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;
}else if( ( gotState & (0x01 << 1 ) ) > 0 ){
s.clearToSend = true;
}else if( ( gotState & (0x01 << 2 ) ) > 0 ){
s.dataSetReady = true;
}else if( ( gotState & (0x01 << 3 ) ) > 0 ){
s.dataTerminalReady = true;
}else if( ( gotState & (0x01 << 4 ) ) > 0 ){
s.requestToSend = true;
}else 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 ){
setSerialLineStateInternal( state );
}
 
/**
* Get the baud rate of the serial port.
*
* @return
*/
public SerialPort.BaudRate getBaudRate(){
int baudRate = getBaudRateInternal();
BaudRate 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 = getCharSizeInternal();
DataBits 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 = getStopBitsInternal();
StopBits 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 = getParityInternal();
Parity 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 = getFlowControlInternal();
FlowControl 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 ){
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.
*
* @param listen The listener which gets events
*/
public void setSerialChangeListener( SerialChangeListener listen ){
if( serialListen != null ){
serialListen.doStop();
}
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 );
 
}
/branches/JavaSerial/0.1/src/com/rm5248/serial/NotASerialPortException.java
0,0 → 1,23
package com.rm5248.serial;
 
/**
* This exception is thrown when the device that you have opened is not a serial port.
*
* @author rm5248
*
*/
public class NotASerialPortException extends Exception {
 
/**
* Generated by Eclipse
*/
private static final long serialVersionUID = 5606767768689212862L;
 
/** Create a new exception if this is not a serial port
*
* @param message
*/
public NotASerialPortException( String message ){
super( message );
}
}
/branches/JavaSerial/0.1/src/com/rm5248/serial/SerialLineState.java
0,0 → 1,56
package com.rm5248.serial;
 
/**
* This class represents the current state of the lines on the serial port.
* You can also use this class to set the state of the serial port.
*
* Note that all of these options may not be available depending on the
* serial port that is in use, and/or the platform that you are running on.
*
*/
public class SerialLineState {
public boolean carrierDetect;
public boolean clearToSend;
public boolean dataSetReady;
public boolean dataTerminalReady;
public boolean ringIndicator;
public boolean requestToSend;
public SerialLineState(){
carrierDetect = false;
clearToSend = false;
dataSetReady = false;
dataTerminalReady = false;
ringIndicator = false;
requestToSend = false;
}
@Override
public boolean equals( Object o ){
if( o instanceof SerialLineState ){
SerialLineState s = (SerialLineState)o;
return ( s.carrierDetect == carrierDetect ) &&
( s.clearToSend == clearToSend ) &&
( s.dataSetReady == dataSetReady ) &&
( s.dataTerminalReady == dataTerminalReady ) &&
( s.ringIndicator == ringIndicator ) &&
( s.requestToSend == requestToSend );
}
return false;
}
@Override
public String toString(){
return "[SerialLineState: " +
"CD: " + carrierDetect +
" CTS: " + clearToSend +
" DSR: " + dataSetReady +
" DTR: " + dataTerminalReady +
" RI: " + ringIndicator +
" RTS: " + requestToSend + "]";
}
 
}
/branches/JavaSerial/0.1/src/com/rm5248/serial/SerialOutputStream.java
0,0 → 1,28
package com.rm5248.serial;
 
import java.io.IOException;
import java.io.OutputStream;
 
class SerialOutputStream extends OutputStream{
/* The handle to write to */
@SuppressWarnings("unused")
private int handle;
 
SerialOutputStream( int handle ){
this.handle = handle;
}
 
@Override
public void write(int b) throws IOException {
writeByte( b );
}
@Override
public void write( byte[] arr ) throws IOException{
writeByteArray( arr );
}
 
private native void writeByte( int toWrite ) throws IOException;
private native void writeByteArray( byte[] array ) throws IOException;
}
/branches/JavaSerial/0.1/src/com/rm5248/serial/SerialInputStream.java
0,0 → 1,32
package com.rm5248.serial;
 
import java.io.IOException;
import java.io.InputStream;
 
/**
* Input stream for the serial port.
*/
class SerialInputStream extends InputStream{
/* The handle to read from. Needed for native implementation */
@SuppressWarnings("unused")
private int handle;
 
SerialInputStream( 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;
}
/branches/JavaSerial/0.1/src/com/rm5248/serial/BufferedSerialInputStream.java
0,0 → 1,127
package com.rm5248.serial;
 
import java.io.IOException;
import java.io.InputStream;
 
/**
* Okay, so the problem here is that we need to be continually reading from the serial port,
* because on Windows we can't simultaneously listen for events and listen for changes on
* the serial port. We can only do that in one place. So, to get around that problem,
* this BufferedSerialInputStream simply wraps the normal SerialInputStream and only
* returns actual data. SerialInputStream gives us back data on the status of the serial line,
* as well as if the byte it gave us is real or not.
*
* @author Rob
*
*/
class BufferedSerialInputStream extends InputStream implements Runnable {
 
private SerialInputStream stream;
private byte[] buffer;
private int bufferBegin;
private int bufferEnd;
private SerialPort callback;
private IOException exceptionToThrow;
 
BufferedSerialInputStream( SerialInputStream s, SerialPort callback ){
stream = s;
buffer = new byte[ 100 ];
bufferBegin = 0;
bufferEnd = 0;
this.callback = callback;
exceptionToThrow = null;
}
 
@Override
public int read() throws IOException {
int byteToReturn;
if( bufferBegin != bufferEnd ){
//we already have a character
byteToReturn = buffer[ bufferBegin++ ];
if( bufferBegin >= buffer.length ){
//wrap around to the start of the array
bufferBegin = 0;
}
}else{
synchronized( buffer ){
try {
buffer.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
if( exceptionToThrow != null ){
throw exceptionToThrow;
}
}
byteToReturn = buffer[ bufferBegin++ ];
if( bufferBegin >= buffer.length ){
//wrap around to the start of the array
bufferBegin = 0;
}
}
return byteToReturn;
}
 
@Override
public void run() {
while( true ){
int byteRead = 0;
try {
byteRead = stream.read();
} catch (IOException e) {
synchronized( buffer ){
exceptionToThrow = e;
buffer.notify();
}
break;
}
SerialLineState s = new SerialLineState();
 
if( ( byteRead & ( 0x01 << 9) ) > 0 ){
s.carrierDetect = true;
}else if( ( byteRead & (0x01 << 10 ) ) > 0 ){
s.clearToSend = true;
}else if( ( byteRead & (0x01 << 11 ) ) > 0 ){
s.dataSetReady = true;
}else if( ( byteRead & (0x01 << 12 ) ) > 0 ){
s.dataTerminalReady = true;
}else if( ( byteRead & (0x01 << 13 ) ) > 0 ){
s.requestToSend = true;
}else if( ( byteRead & (0x01 << 14 ) ) > 0 ){
s.ringIndicator = true;
}
 
if( ( byteRead & ( 0x01 << 15 ) ) > 0 ){
//this is a valid byte
synchronized( buffer ){
if( bufferEnd + 1 >= buffer.length ){
//loop back around to the beginning
bufferEnd = 0;
}
buffer[ bufferEnd++ ] = (byte)( byteRead & 0xFF );
if( bufferEnd == bufferBegin ){
//the end has wrapped around, increment the beginning
bufferBegin++;
}
buffer.notify();
}
}
callback.postSerialChangedEvent( s );
}
}
@Override
public int available(){
if( bufferEnd < bufferBegin ){
//special case - we have looped around
return ( buffer.length - bufferBegin ) + bufferEnd;
}else{
return bufferEnd - bufferBegin;
}
}
 
}
/branches/JavaSerial/0.1/src/com/rm5248/serial/SerialChangeListener.java
0,0 → 1,16
package com.rm5248.serial;
 
/**
* This interface lets the user do something when the serial line state changes.
* The state is defined by how the lines are currently set.
*
*/
public interface SerialChangeListener {
 
/**
* Fired when the state on the serial line changes.
*
* @param state
*/
public void serialStateChanged( SerialLineState state );
}
/branches/JavaSerial/0.1/README
0,0 → 1,8
Java Serial
=========================================
 
This software is open-source software.
 
The home of Java Serial is at http://svn.rm5248.com/RMProgrammingUtilities/?page_id=19
 
Use of this code is subject to license terms as laid out in LICENSE
/branches/JavaSerial/0.1/NativeCode/com_rm5248_serial_SerialOutputStream.h
0,0 → 1,29
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_rm5248_serial_SerialOutputStream */
 
#ifndef _Included_com_rm5248_serial_SerialOutputStream
#define _Included_com_rm5248_serial_SerialOutputStream
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_rm5248_serial_SerialOutputStream
* Method: writeByte
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_com_rm5248_serial_SerialOutputStream_writeByte
(JNIEnv *, jobject, jint);
 
/*
* Class: com_rm5248_serial_SerialOutputStream
* Method: writeByteArray
* Signature: ([B)V
*/
JNIEXPORT void JNICALL Java_com_rm5248_serial_SerialOutputStream_writeByteArray
(JNIEnv *, jobject, jbyteArray);
 
#ifdef __cplusplus
}
#endif
#endif
/branches/JavaSerial/0.1/NativeCode/SerialPortImpl.c
0,0 → 1,1779
#ifdef _WIN32
#include <windows.h>
#define SPEED_SWITCH(SPD,io) case SPD: io.BaudRate = CBR_##SPD; break;
#define GET_SPEED_SWITCH(SPD,io) case CBR_##SPD: return SPD;
#define GET_SERIAL_PORT_STRUCT( port, io_name ) DCB io_name = {0};\
io_name.DCBlength = sizeof( io_name ); \
if (!GetCommState( port, &io_name ) ) { \
printf("bad get comm\n");\
return -1;\
}
#define SET_SERIAL_PORT_STRUCT( port, io_name ) if( !SetCommState( port, &io_name ) ){\
printf("bad set comm\n");\
return 0;\
}
#else
#include <termio.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
 
#ifdef CRTSCTS
#define HW_FLOW CRTSCTS
#elif CNEW_RTSCTS
#define HW_FLOW CNEW_RTSCTS
#endif
#define SPEED_SWITCH(SPD,io) case SPD: cfsetospeed( &io, B##SPD ); cfsetispeed( &io, B##SPD ); break;
#define GET_SPEED_SWITCH(SPD,io) case B##SPD: return SPD;
#define GET_SERIAL_PORT_STRUCT( port, io_name ) struct termios io_name; \
if( tcgetattr( port, &io_name ) < 0 ){ \
return -1; \
}
#define SET_SERIAL_PORT_STRUCT( port, io_name ) if( tcsetattr( port, TCSANOW, &io_name ) < 0 ){\
return 0;\
}
#endif
 
#include <stdlib.h>
#include <errno.h>
#include <string.h>
 
//
// Local Includes
//
#include "com_rm5248_serial_SerialPort.h"
#include "com_rm5248_serial_SerialInputStream.h"
#include "com_rm5248_serial_SerialOutputStream.h"
 
//
// Struct Definitions
//
struct port_descriptor{
#ifdef _WIN32
HANDLE port;
#else
int port;
#endif
};
 
//
// Local Variables
//
struct port_descriptor** port_list = NULL;
int port_list_size;
 
//
// Helper Methods
//
static jint get_handle(JNIEnv * env, jobject obj){
jfieldID fid;
jint array_pos;
jclass cls = (*env)->GetObjectClass( env, obj );
 
fid = (*env)->GetFieldID( env, cls, "handle", "I" );
if( fid == 0 ){
return -1;
}
 
array_pos = (*env)->GetIntField( env, obj, fid );
 
return array_pos;
}
 
static jboolean get_bool( JNIEnv* env, jobject obj, const char* name ){
jfieldID fid;
jboolean boolVal;
jclass cls = (*env)->GetObjectClass( env, obj );
 
fid = (*env)->GetFieldID( env, cls, name, "Z" );
if( fid == 0 ){
return 0; //not really sure what error to set here...
}
 
boolVal = (*env)->GetBooleanField( env, obj, fid );
 
return boolVal;
}
 
static int set_baud_rate( struct port_descriptor* desc, int baud_rate ){
GET_SERIAL_PORT_STRUCT( desc->port, newio );
 
switch( baud_rate ){
#ifndef _WIN32
/* Note that Windows only supports speeds of 110 and above */
SPEED_SWITCH(0,newio);
SPEED_SWITCH(50,newio);
SPEED_SWITCH(75,newio);
#endif
SPEED_SWITCH(110,newio);
#ifndef _WIN32
/* Windows does not support speeds of 134, 150, or 200 */
SPEED_SWITCH(134,newio);
SPEED_SWITCH(150,newio);
SPEED_SWITCH(200,newio);
#endif
SPEED_SWITCH(300,newio);
SPEED_SWITCH(600,newio);
SPEED_SWITCH(1200,newio);
#ifndef _WIN32
/* Windows does not support 1800 */
SPEED_SWITCH(1800,newio);
#endif
SPEED_SWITCH(2400,newio);
SPEED_SWITCH(4800,newio);
SPEED_SWITCH(9600,newio);
SPEED_SWITCH(19200,newio);
SPEED_SWITCH(38400,newio);
SPEED_SWITCH(115200,newio);
}
 
SET_SERIAL_PORT_STRUCT( desc->port, newio );
 
return 1;
}
 
static int set_raw_input( struct port_descriptor* desc ){
GET_SERIAL_PORT_STRUCT( desc->port, newio );
 
#ifdef _WIN32
newio.fBinary = TRUE;
newio.fParity = TRUE;
newio.fOutxCtsFlow = FALSE;
newio.fOutxDsrFlow = FALSE;
newio.fDtrControl = DTR_CONTROL_DISABLE;
newio.fDsrSensitivity = FALSE;
newio.fOutX = FALSE;
newio.fInX = FALSE;
newio.fNull = FALSE;
newio.fRtsControl = FALSE;
//Set the timeouts
{
COMMTIMEOUTS timeouts = {0};
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 0;
if( SetCommTimeouts( desc->port, &timeouts ) == 0 ){
printf("bad timeout\n"); fflush(stdout);}
}
#else
newio.c_iflag |= IGNBRK;
newio.c_iflag &= ~BRKINT;
newio.c_iflag &= ~ICRNL;
newio.c_oflag = 0;
newio.c_lflag = 0;
newio.c_cc[VTIME] = 0;
newio.c_cc[VMIN] = 1;
#endif
SET_SERIAL_PORT_STRUCT( desc->port, newio );
 
return 1;
}
 
/**
* @param data_bits The number of data bits
*/
static int set_data_bits( struct port_descriptor* desc, int data_bits ){
GET_SERIAL_PORT_STRUCT( desc->port, newio );
 
#ifdef _WIN32
newio.ByteSize = data_bits;
#else
newio.c_cflag &= ~CSIZE;
if( data_bits == 8 ){
newio.c_cflag |= CS8;
}else if( data_bits == 7 ){
newio.c_cflag |= CS7;
}else if( data_bits == 6 ){
newio.c_cflag |= CS6;
}else if( data_bits == 5 ){
newio.c_cflag |= CS5;
}
#endif
SET_SERIAL_PORT_STRUCT( desc->port, newio );
 
return 1;
}
 
/**
* @param stop_bits 1 for 1, 2 for 2
*/
static int set_stop_bits( struct port_descriptor* desc, int stop_bits ){
GET_SERIAL_PORT_STRUCT( desc->port, newio );
 
#ifdef _WIN32
if( stop_bits == 1 ){
newio.StopBits = ONESTOPBIT;
}else if( stop_bits == 2 ){
newio.StopBits = TWOSTOPBITS;
}
#else
if( stop_bits == 1 ){
newio.c_cflag &= ~CSTOPB;
}else if( stop_bits == 2 ){
newio.c_cflag |= CSTOPB;
}
#endif
SET_SERIAL_PORT_STRUCT( desc->port, newio );
 
return 1;
}
 
/**
* @param parity 0 for no parity, 1 for odd parity, 2 for even parity
*/
static int set_parity( struct port_descriptor* desc, int parity ){
GET_SERIAL_PORT_STRUCT( desc->port, newio );
 
#ifdef _WIN32
if( parity == 0 ){
newio.Parity = NOPARITY;
}else if( parity == 1 ){
newio.Parity = ODDPARITY;
}else if( parity == 2 ){
newio.Parity = EVENPARITY;
}
#else
if( parity == 0 ){
newio.c_cflag |= IGNPAR;
}else if( parity == 1 ){
newio.c_cflag |= PARODD;
}else if( parity == 2 ){
newio.c_cflag |= PARENB;
}
#endif
SET_SERIAL_PORT_STRUCT( desc->port, newio );
 
return 1;
}
 
/**
* @param flow_control 0 for none, 1 for hardware, 2 for software
*/
static int set_flow_control( struct port_descriptor* desc, int flow_control ){
GET_SERIAL_PORT_STRUCT( desc->port, newio );
 
#ifdef _WIN32
if( flow_control == 0 ){
newio.fOutxCtsFlow = FALSE;
newio.fRtsControl = FALSE;
newio.fOutX = FALSE;
newio.fInX = FALSE;
}else if( flow_control == 1 ){
newio.fOutxCtsFlow = TRUE;
newio.fRtsControl = TRUE;
newio.fOutX = FALSE;
newio.fInX = FALSE;
}else if( flow_control == 2 ){
newio.fOutxCtsFlow = FALSE;
newio.fRtsControl = FALSE;
newio.fOutX = TRUE;
newio.fInX = TRUE;
}
#else
if( flow_control == 0 ){
newio.c_cflag &= ~( IXON | IXOFF | IXANY );
}else if( flow_control == 1 ){
newio.c_cflag |= HW_FLOW;
}else if( flow_control == 2 ){
newio.c_cflag |= ( IXON | IXOFF | IXANY );
}
#endif
SET_SERIAL_PORT_STRUCT( desc->port, newio );
 
return 1;
}
 
static void throw_io_exception( JNIEnv * env, int errorNumber ){
#ifdef _WIN32
LPTSTR error_text = NULL;
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "java/io/IOException");
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
errorNumber,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&error_text,
0,
NULL );
(*env)->ThrowNew(env, exception_class, error_text );
LocalFree( error_text );
#else
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "java/io/IOException");
(*env)->ThrowNew(env, exception_class, strerror( errorNumber ) );
#endif /* _WIN32 */
}
 
static void throw_io_exception_message( JNIEnv * env, const char* message ){
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "java/io/IOException");
(*env)->ThrowNew(env, exception_class, message );
}
 
//
// JNI Methods
//
 
/*
* Class: com_rm5248_serial_SerialPort
* Method: openPort
* Signature: (Ljava/lang/String;IIIII)I
*/
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialPort_openPort
(JNIEnv * env, jobject obj, jstring port, jint baudRate, jint dataBits, jint stopBits, jint parity, jint flowControl){
struct port_descriptor* new_port;
int list_pos;
int found = 0;
const char* port_to_open;
jboolean iscopy;
 
port_to_open = (*env)->GetStringUTFChars( env, port, &iscopy );
 
if( port_list == NULL ){
port_list = malloc( sizeof( struct port_descriptor* ) * 10 );
port_list_size = 10;
for( list_pos = 0; list_pos < port_list_size; ++list_pos ){
port_list[ list_pos ] = NULL;
}
}
 
//Search thru the port_list, find the first one that is NULL
for( list_pos = 0; list_pos < port_list_size; ++list_pos ){
if( port_list[ list_pos ] == NULL ){
found = 1;
break;
}
}
 
if( !found ){
//no free slots. Expand our array by 10 elements
struct port_descriptor** tmpPortDesc;
tmpPortDesc = malloc( sizeof( struct port_descriptor* ) * ( port_list_size + 10 ) );
 
//put all elements into the new array
for( list_pos = 0; list_pos < port_list_size; ++list_pos ){
tmpPortDesc[ list_pos ] = port_list[ list_pos ];
}
++list_pos; //put the place to insert the new record one past the old records
 
port_list_size += 10;
//free the old array, set it to the new one
free( port_list );
port_list = tmpPortDesc;
}
 
//at this point, list_pos points to a NULL location in our array
new_port = malloc( sizeof( struct port_descriptor ) );
 
//Now, let's get to the actual opening of our port
#ifdef _WIN32
new_port->port = CreateFile( port_to_open, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0 );
if( new_port->port == INVALID_HANDLE_VALUE ){
if( GetLastError() == ERROR_FILE_NOT_FOUND ){
LPTSTR error_text = NULL;
jclass exception_class;
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&error_text,
0,
NULL );
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "com/rm5248/serial/NoSuchPortException");
(*env)->ThrowNew(env, exception_class, error_text );
free( new_port );
LocalFree( error_text );
return -1;
}
}
{
//Let's check to see if this is a serial port
DCB io_name = {0};
io_name.DCBlength = sizeof( io_name );
if (!GetCommState( new_port->port, &io_name ) ) {
LPTSTR error_text = NULL;
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "com/rm5248/serial/NotASerialPortException");
(*env)->ThrowNew(env, exception_class, "You are attempting to open something which is not a serial port" );
free( new_port );
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&error_text,
0,
NULL );
printf("error is %s\n", error_text );
LocalFree( error_text );
return -1;
}
}
#else
new_port->port = open( port_to_open, O_RDWR );
if( new_port->port < 0 && errno == ENOENT ){
//That's not a valid serial port, error out
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "com/rm5248/serial/NoSuchPortException");
(*env)->ThrowNew(env, exception_class, strerror( errno ) );
free( new_port );
return -1;
}else if( new_port->port < 0 ){
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "com/rm5248/serial/NoSuchPortException");
(*env)->ThrowNew(env, exception_class, strerror( errno ) );
free( new_port );
return -1;
}
{
struct termios io_name;
if( tcgetattr( new_port->port, &io_name ) < 0 ){
if( errno == ENOTTY ){
//This is apparently not a serial port
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "com/rm5248/serial/NotASerialPortException");
(*env)->ThrowNew(env, exception_class, "You are attempting to open something which is not a serial port" );
free( new_port );
return -1;
}
}
}
#endif /* __WIN32 */
 
 
//Set the baud rate
set_baud_rate( new_port, baudRate );
set_raw_input( new_port );
//Set the data bits( character size )
set_data_bits( new_port, dataBits );
//Set the stop bits
set_stop_bits( new_port, stopBits );
//Set the parity
set_parity( new_port, parity );
//Set the flow control
set_flow_control( new_port, flowControl );
 
//Only set the new_port to be in our array as the last instruction
//If there are any errors, we will have returned long before this
port_list[ list_pos ] = new_port;
return list_pos;
}
 
/*
* Class: com_rm5248_serial_SerialPort
* Method: openPort
* Signature: (Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialPort_openPort__Ljava_lang_String_2
(JNIEnv * env, jobject obj, jstring port){
struct port_descriptor* new_port;
int list_pos;
int found = 0;
const char* port_to_open;
jboolean iscopy;
 
port_to_open = (*env)->GetStringUTFChars( env, port, &iscopy );
 
if( port_list == NULL ){
port_list = malloc( sizeof( struct port_descriptor* ) * 10 );
port_list_size = 10;
for( list_pos = 0; list_pos < port_list_size; ++list_pos ){
port_list[ list_pos ] = NULL;
}
}
 
//Search thru the port_list, find the first one that is NULL
for( list_pos = 0; list_pos < port_list_size; ++list_pos ){
if( port_list[ list_pos ] == NULL ){
found = 1;
break;
}
}
 
if( !found ){
//no free slots. Expand our array by 10 elements
struct port_descriptor** tmpPortDesc;
tmpPortDesc = malloc( sizeof( struct port_descriptor* ) * ( port_list_size + 10 ) );
 
//put all elements into the new array
for( list_pos = 0; list_pos < port_list_size; ++list_pos ){
tmpPortDesc[ list_pos ] = port_list[ list_pos ];
}
++list_pos; //put the place to insert the new record one past the old records
 
port_list_size += 10;
//free the old array, set it to the new one
free( port_list );
port_list = tmpPortDesc;
}
 
//at this point, list_pos points to a NULL location in our array
new_port = malloc( sizeof( struct port_descriptor ) );
 
//Now, let's get to the actual opening of our port
#ifdef _WIN32
new_port->port = CreateFile( port_to_open, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0 );
if( new_port->port == INVALID_HANDLE_VALUE ){
if( GetLastError() == ERROR_FILE_NOT_FOUND ){
LPTSTR error_text = NULL;
jclass exception_class;
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&error_text,
0,
NULL );
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "com/rm5248/serial/NoSuchPortException");
(*env)->ThrowNew(env, exception_class, error_text );
free( new_port );
LocalFree( error_text );
return -1;
}
}
{
//Let's check to see if this is a serial port
DCB io_name = {0};
io_name.DCBlength = sizeof( io_name );
if (!GetCommState( new_port->port, &io_name ) ) {
LPTSTR error_text = NULL;
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "com/rm5248/serial/NotASerialPortException");
(*env)->ThrowNew(env, exception_class, "You are attempting to open something which is not a serial port" );
free( new_port );
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&error_text,
0,
NULL );
printf("error is %s\n", error_text );
LocalFree( error_text );
return -1;
}
}
#else
new_port->port = open( port_to_open, O_RDWR );
if( new_port->port < 0 && errno == ENOENT ){
//That's not a valid serial port, error out
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "com/rm5248/serial/NoSuchPortException");
(*env)->ThrowNew(env, exception_class, strerror( errno ) );
free( new_port );
return -1;
}else if( new_port->port < 0 ){
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "com/rm5248/serial/NoSuchPortException");
(*env)->ThrowNew(env, exception_class, strerror( errno ) );
free( new_port );
return -1;
}
{
struct termios io_name;
if( tcgetattr( new_port->port, &io_name ) < 0 ){
if( errno == ENOTTY ){
//This is apparently not a serial port
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "com/rm5248/serial/NotASerialPortException");
(*env)->ThrowNew(env, exception_class, "You are attempting to open something which is not a serial port" );
free( new_port );
return -1;
}
}
}
#endif /* __WIN32 */
 
//Only set the new_port to be in our array as the last instruction
//If there are any errors, we will have returned long before this
port_list[ list_pos ] = new_port;
 
return list_pos;
}
 
/*
* Class: com_rm5248_serial_SerialPort
* Method: doClose
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_rm5248_serial_SerialPort_doClose
(JNIEnv * env, jobject obj){
jint array_pos;
struct port_descriptor* desc;
 
array_pos = get_handle( env, obj );
if( array_pos < 0 || array_pos > port_list_size ){
return;
}
 
desc = port_list[ array_pos ];
if( desc == NULL ){
return;
}
 
close( desc->port );
free( desc );
port_list[ array_pos ] = NULL;
}
 
/*
* Class: com_rm5248_serial_SerialPort
* Method: setBaudRate
* Signature: (I)Z
*/
JNIEXPORT jboolean JNICALL Java_com_rm5248_serial_SerialPort_setBaudRate
(JNIEnv * env, jobject obj, jint baud_rate ){
jint array_pos;
struct port_descriptor* desc;
 
array_pos = get_handle( env, obj );
 
if( array_pos < 0 ){
//throw new exception
int errNum;
#ifdef _WIN32
errNum = GetLastError();
#else
errNum = errno;
#endif /* _WIN32 */
throw_io_exception( env, errNum );
return 0;
}
 
desc = port_list[ array_pos ];
 
if( desc == NULL ){
//throw new exception
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "java/io/IOException");
(*env)->ThrowNew(env, exception_class, "Given bad positon in array. Internal SerialPort error." );
return 0;
}
 
return set_baud_rate( desc, baud_rate );
}
 
/*
* Class: com_rm5248_serial_SerialPort
* Method: getBaudRateInternal
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialPort_getBaudRateInternal
(JNIEnv * env, jobject obj){
jint array_pos;
struct port_descriptor* desc;
 
array_pos = get_handle( env, obj );
 
if( array_pos < 0 ){
//throw new exception
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "java/io/IOException");
(*env)->ThrowNew(env, exception_class, strerror( errno ) );
return 0;
}
 
desc = port_list[ array_pos ];
 
if( desc == NULL ){
//throw new exception
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "java/io/IOException");
(*env)->ThrowNew(env, exception_class, strerror( errno ) );
return 0;
}
 
//Now, let's get the baud rate information
{
GET_SERIAL_PORT_STRUCT( desc->port, newio );
#ifdef _WIN32
GetCommState( desc->port, &newio );
switch( newio.BaudRate ){
#else
switch( cfgetispeed( &newio ) ){
GET_SPEED_SWITCH( 0, newio );
GET_SPEED_SWITCH( 50, newio );
GET_SPEED_SWITCH( 75, newio );
#endif /* _WIN32 */
GET_SPEED_SWITCH( 110, newio );
#ifndef _WIN32
GET_SPEED_SWITCH( 134, newio );
GET_SPEED_SWITCH( 150, newio );
GET_SPEED_SWITCH( 200, newio );
#endif /* _WIN32 */
GET_SPEED_SWITCH( 300, newio );
GET_SPEED_SWITCH( 600, newio );
GET_SPEED_SWITCH( 1200, newio );
#ifndef _WIN32
GET_SPEED_SWITCH( 1800, newio );
#endif /* _WIN32 */
GET_SPEED_SWITCH( 2400, newio );
GET_SPEED_SWITCH( 4800, newio );
GET_SPEED_SWITCH( 9600, newio );
GET_SPEED_SWITCH( 19200, newio );
GET_SPEED_SWITCH( 38400, newio );
GET_SPEED_SWITCH( 115200, newio );
default:
return 0;
} /* end switch */
}
 
}
 
/*
* Class: com_rm5248_serial_SerialPort
* Method: setStopBits
* Signature: (I)Z
*/
JNIEXPORT jboolean JNICALL Java_com_rm5248_serial_SerialPort_setStopBits
(JNIEnv * env, jobject obj, jint bits){
jint array_pos;
struct port_descriptor* desc;
 
array_pos = get_handle( env, obj );
 
desc = port_list[ array_pos ];
if( desc == NULL ){
return 0;
}
return set_stop_bits( desc, bits );
}
 
/*
* Class: com_rm5248_serial_SerialPort
* Method: getStopBitsInternal
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialPort_getStopBitsInternal
(JNIEnv * env, jobject obj){
jint array_pos;
struct port_descriptor* desc;
 
array_pos = get_handle( env, obj );
 
if( array_pos < 0 ){
//throw new exception
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "java/io/IOException");
(*env)->ThrowNew(env, exception_class, strerror( errno ) );
return 0;
}
 
desc = port_list[ array_pos ];
 
if( desc == NULL ){
//throw new exception
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "java/io/IOException");
(*env)->ThrowNew(env, exception_class, strerror( errno ) );
return 0;
}
 
{
GET_SERIAL_PORT_STRUCT( desc->port, newio );
#ifdef _WIN32
if( newio.StopBits == 1 ){
return 1;
}else if( newio.StopBits == 2 ){
return 2;
}else{
return -1;
}
#else
if( newio.c_cflag & CSTOPB ){
return 2;
}else{
return 1;
}
#endif
}
}
/*
* Class: com_rm5248_serial_SerialPort
* Method: setCharSize
* Signature: (I)Z
*/
JNIEXPORT jboolean JNICALL Java_com_rm5248_serial_SerialPort_setCharSize
(JNIEnv * env, jobject obj, jint size){
jint array_pos;
struct port_descriptor* desc;
 
array_pos = get_handle( env, obj );
 
desc = port_list[ array_pos ];
if( desc == NULL ){
return 0;
}
return set_data_bits( desc, size );
}
 
/*
* Class: com_rm5248_serial_SerialPort
* Method: getCharSizeInternal
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialPort_getCharSizeInternal
(JNIEnv * env, jobject obj){
jint array_pos;
struct port_descriptor* desc;
 
array_pos = get_handle( env, obj );
 
if( array_pos < 0 ){
//throw new exception
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "java/io/IOException");
(*env)->ThrowNew(env, exception_class, strerror( errno ) );
return 0;
}
 
desc = port_list[ array_pos ];
 
if( desc == NULL ){
//throw new exception
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "java/io/IOException");
(*env)->ThrowNew(env, exception_class, strerror( errno ) );
return 0;
}
 
//Now get the char size
{
GET_SERIAL_PORT_STRUCT( desc->port, newio );
#ifdef _WIN32
return newio.ByteSize;
#else
if( ( newio.c_cflag | CS8 ) == CS8 ){
return 8;
}else if( ( newio.c_cflag | CS7 ) == CS7 ){
return 7;
}else if( ( newio.c_cflag | CS6 ) == CS6 ){
return 6;
}else if( ( newio.c_cflag | CS5 ) == CS5 ){
return 5;
}else{
return 0;
}
#endif
}
 
}
 
/*
* Class: com_rm5248_serial_SerialPort
* Method: setParity
* Signature: (I)Z
*/
JNIEXPORT jboolean JNICALL Java_com_rm5248_serial_SerialPort_setParity
(JNIEnv * env, jobject obj, jint parity){
jint array_pos;
struct port_descriptor* desc;
 
array_pos = get_handle( env, obj );
if( array_pos < 0 ){
//throw new exception
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "java/io/IOException");
(*env)->ThrowNew(env, exception_class, strerror( errno ) );
return 0;
}
 
desc = port_list[ array_pos ];
 
if( desc == NULL ){
//throw new exception
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "java/io/IOException");
(*env)->ThrowNew(env, exception_class, strerror( errno ) );
return 0;
}
return set_parity( desc, parity );
}
 
/*
* Class: com_rm5248_serial_SerialPort
* Method: getParityInternal
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialPort_getParityInternal
(JNIEnv * env, jobject obj){
jint array_pos;
struct port_descriptor* desc;
 
array_pos = get_handle( env, obj );
 
if( array_pos < 0 ){
//throw new exception
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "java/io/IOException");
(*env)->ThrowNew(env, exception_class, strerror( errno ) );
return 0;
}
 
desc = port_list[ array_pos ];
 
if( desc == NULL ){
//throw new exception
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "java/io/IOException");
(*env)->ThrowNew(env, exception_class, strerror( errno ) );
return 0;
}
 
{
GET_SERIAL_PORT_STRUCT( desc->port, newio );
#ifdef _WIN32
if( newio.Parity == NOPARITY ){
return 0;
}else if( newio.Parity == ODDPARITY ){
return 1;
}else if( newio.Parity == EVENPARITY ){
return 2;
}else{
return -1;
}
#else
if( !( newio.c_cflag & PARENB ) ){
//No parity
return 0;
}else if( newio.c_cflag & PARODD ){
//Odd parity
return 1;
}else if( !( newio.c_cflag & PARODD ) ){
//Even parity
return 2;
}else{
return -1;
}
#endif
}
 
}
 
/*
* Class: com_rm5248_serial_SerialPort
* Method: setFlowControl
* Signature: (I)Z
*/
JNIEXPORT jboolean JNICALL Java_com_rm5248_serial_SerialPort_setFlowControl
(JNIEnv * env, jobject obj, jint flow){
jint array_pos;
struct port_descriptor* desc;
array_pos = get_handle( env, obj );
if( array_pos < 0 ){
//throw new exception
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "java/io/IOException");
(*env)->ThrowNew(env, exception_class, strerror( errno ) );
return 0;
}
 
desc = port_list[ array_pos ];
 
if( desc == NULL ){
//throw new exception
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "java/io/IOException");
(*env)->ThrowNew(env, exception_class, strerror( errno ) );
return 0;
}
return set_flow_control( desc, flow );
}
 
/*
* Class: com_rm5248_serial_SerialPort
* Method: getFlowControlInternal
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialPort_getFlowControlInternal
(JNIEnv * env, jobject obj){
jint array_pos;
struct port_descriptor* desc;
 
array_pos = get_handle( env, obj );
if( array_pos < 0 ){
//throw new exception
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "java/io/IOException");
(*env)->ThrowNew(env, exception_class, strerror( errno ) );
return 0;
}
 
desc = port_list[ array_pos ];
 
if( desc == NULL ){
//throw new exception
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "java/io/IOException");
(*env)->ThrowNew(env, exception_class, strerror( errno ) );
return 0;
}
{
GET_SERIAL_PORT_STRUCT( desc->port, newio );
#ifdef _WIN32
if( newio.fOutX == TRUE && newio.fInX == TRUE ){
return 2;
}else if( newio.fRtsControl == TRUE && newio.fOutxCtsFlow == TRUE ){
return 1;
}else{
return 0;
}
#else
if( newio.c_cflag & ~( IXON ) &&
newio.c_cflag & ~( IXOFF ) &&
newio.c_cflag & ~( IXANY ) ){
return 0;
}else if( newio.c_cflag & HW_FLOW ){
return 1;
}else if( newio.c_cflag & ( IXON ) &&
newio.c_cflag & ( IXOFF ) &&
newio.c_cflag & ( IXANY ) ){
return 2;
}
#endif /* _WIN32 */
}
 
return -1;
}
 
/*
* Class: com_rm5248_serial_SerialPort
* Method: getSerialLineStateInternalNonblocking
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialPort_getSerialLineStateInternalNonblocking
(JNIEnv * env, jobject obj ){
jint array_pos;
struct port_descriptor* desc;
jint ret_val;
 
array_pos = get_handle( env, obj );
if( array_pos < 0 ){
//throw new exception
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "java/io/IOException");
(*env)->ThrowNew(env, exception_class, strerror( errno ) );
return 0;
}
 
desc = port_list[ array_pos ];
 
if( desc == NULL ){
//throw new exception
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "java/io/IOException");
(*env)->ThrowNew(env, exception_class, strerror( errno ) );
return 0;
}
 
ret_val = 0;
{
#ifdef _WIN32
DWORD get_val;
if( GetCommModemStatus( desc->port, &get_val ) == 0 ){
throw_io_exception( env, GetLastError() );
return -1;
}
if( get_val & MS_CTS_ON ){
// CTS
ret_val |= ( 0x01 << 1 );
}
if( get_val & MS_DSR_ON ){
// Data Set Ready
ret_val |= ( 0x01 << 2 );
}
if( get_val & MS_RING_ON ){
// Ring Indicator
ret_val |= ( 0x01 << 5 );
}
#else
int get_val;
if( ioctl( desc->port, TIOCMGET, &get_val ) < 0 ){
throw_io_exception( env, errno );
return -1;
}
 
if( get_val & TIOCM_CD ){
// Carrier detect
ret_val |= 0x01;
}
 
if( get_val & TIOCM_CTS ){
// CTS
ret_val |= ( 0x01 << 1 );
}
 
if( get_val & TIOCM_DSR ){
// Data Set Ready
ret_val |= ( 0x01 << 2 );
}
 
if( get_val & TIOCM_DTR ){
// Data Terminal Ready
ret_val |= ( 0x01 << 3 );
}
 
if( get_val & TIOCM_RTS ){
// Request To Send
ret_val |= ( 0x01 << 4 );
}
 
if( get_val & TIOCM_RI ){
// Ring Indicator
ret_val |= ( 0x01 << 5 );
}
#endif
}
 
return ret_val;
}
 
/*
* Class: com_rm5248_serial_SerialPort
* Method: setSerialLineStateInternal
* Signature: (Lcom/rm5248/serial/SerialLineState;)I
*/
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialPort_setSerialLineStateInternal
(JNIEnv * env, jobject obj, jobject serial){
jint array_pos;
struct port_descriptor* desc;
jint ret_val;
 
array_pos = get_handle( env, obj );
if( array_pos < 0 ){
//throw new exception
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "java/io/IOException");
(*env)->ThrowNew(env, exception_class, strerror( errno ) );
return 0;
}
 
desc = port_list[ array_pos ];
 
if( desc == NULL ){
//throw new exception
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "java/io/IOException");
(*env)->ThrowNew(env, exception_class, strerror( errno ) );
return 0;
}
 
ret_val = 0;
#ifdef _WIN32
//Can't set CD on Windows
if( get_bool( env, serial, "carrierDetect" ) ){
}else{
}
 
//Can't set CTS on Windows
if( get_bool( env, serial, "clearToSend" ) ){
}else{
}
 
//Can't set in Windows
if( get_bool( env, serial, "dataSetReady" ) ){
}else{
}
 
if( get_bool( env, serial, "dataTerminalReady" ) ){
if( !EscapeCommFunction( desc->port, SETDTR ) ){
throw_io_exception_message( env, "Could not set DTR" );
return -1;
}
}else{
if( !EscapeCommFunction( desc->port, CLRDTR ) ){
throw_io_exception_message( env, "Could not set DTR" );
return -1;
}
}
 
//Can't set in Windows
if( get_bool( env, serial, "ringIndicator" ) ){
}else{
}
 
if( get_bool( env, serial, "requestToSend" ) ){
if( !EscapeCommFunction( desc->port, SETRTS ) ){
throw_io_exception_message( env, "Could not set RTS" );
return -1;
}
}else{
if( !EscapeCommFunction( desc->port, CLRRTS ) ){
throw_io_exception_message( env, "Could not set RTS" );
return -1;
}
}
#else
if( get_bool( env, serial, "carrierDetect" ) ){
if( ioctl( desc->port, TIOCMBIS, TIOCM_CD ) < 0 ){
throw_io_exception_message( env, "Could not set CD" );
return -1;
}
}else{
if( ioctl( desc->port, TIOCMBIC, TIOCM_CD ) < 0 ){
throw_io_exception_message( env, "Could not set CD" );
return -1;
}
}
 
if( get_bool( env, serial, "clearToSend" ) ){
if( ioctl( desc->port, TIOCMBIS, TIOCM_CTS ) < 0 ){
throw_io_exception_message( env, "Could not set CTS" );
return -1;
}
}else{
if( ioctl( desc->port, TIOCMBIC, TIOCM_CTS ) < 0 ){
throw_io_exception_message( env, "Could not set CTS" );
return -1;
}
}
 
if( get_bool( env, serial, "dataSetReady" ) ){
if( ioctl( desc->port, TIOCMBIS, TIOCM_LE ) < 0 ){
throw_io_exception_message( env, "Could not set DSR" );
return -1;
}
}else{
if( ioctl( desc->port, TIOCMBIC, TIOCM_LE ) < 0 ){
throw_io_exception_message( env, "Could not set DSR" );
return -1;
}
}
 
if( get_bool( env, serial, "dataTerminalReady" ) ){
if( ioctl( desc->port, TIOCMBIS, TIOCM_DTR ) < 0 ){
throw_io_exception_message( env, "Could not set DTR" );
return -1;
}
}else{
if( ioctl( desc->port, TIOCMBIC, TIOCM_DTR ) < 0 ){
throw_io_exception_message( env, "Could not set DTR" );
return -1;
}
}
 
if( get_bool( env, serial, "ringIndicator" ) ){
if( ioctl( desc->port, TIOCMBIS, TIOCM_RNG ) < 0 ){
throw_io_exception_message( env, "Could not set Ring" );
return -1;
}
}else{
if( ioctl( desc->port, TIOCMBIC, TIOCM_RNG ) < 0 ){
throw_io_exception_message( env, "Could not set Ring" );
return -1;
}
}
 
if( get_bool( env, serial, "requestToSend" ) ){
if( ioctl( desc->port, TIOCMBIS, TIOCM_RTS ) < 0 ){
throw_io_exception_message( env, "Could not set RTS" );
return -1;
}
}else{
if( ioctl( desc->port, TIOCMBIC, TIOCM_RTS ) < 0 ){
throw_io_exception_message( env, "Could not set RTS" );
return -1;
}
}
#endif
 
return ret_val;
}
 
//
// ------------------------------------------------------------------------
// ------------------Input/Output methods below here-----------------------
// ------------------------------------------------------------------------
//
 
/*
* Class: com_rm5248_serial_SerialInputStream
* Method: readByte
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialInputStream_readByte
(JNIEnv * env, jobject obj){
int stat;
int ret_val;
jint array_pos;
struct port_descriptor* desc;
int get_val = 0;
#ifdef _WIN32
DWORD ret = 0;
OVERLAPPED overlap = {0};
int current_available = 0;
#endif
 
array_pos = get_handle( env, obj );
if( array_pos < 0 ){
//throw new exception
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "java/io/IOException");
(*env)->ThrowNew(env, exception_class, strerror( errno ) );
return -1;
}
 
desc = port_list[ array_pos ];
 
if( desc == NULL ){
//throw new exception
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "java/io/IOException");
(*env)->ThrowNew(env, exception_class, strerror( errno ) );
return -1;
}
ret_val = 0;
 
#ifdef _WIN32
{
DWORD comErrors = {0};
COMSTAT portStatus = {0};
if( !ClearCommError( desc->port, &comErrors, &portStatus ) ){
//return value zero = fail
throw_io_exception( env, GetLastError() );
return -1;
}else{
current_available = portStatus.cbInQue;
}
}
if( !current_available ){
//If nothing is currently available, wait until we get an event of some kind.
//This could be the serial lines changing state, or it could be some data
//coming into the system.
overlap.hEvent = CreateEvent( 0, TRUE, 0, 0 );
SetCommMask( desc->port, EV_RXCHAR | EV_CTS | EV_DSR | EV_RING );
WaitCommEvent( desc->port, &ret, &overlap );
WaitForSingleObject( overlap.hEvent, INFINITE );
}else{
//Data is available; set the RXCHAR mask so we try to read from the port
ret = EV_RXCHAR;
}
if( ret & EV_RXCHAR ){
if( !ReadFile( desc->port, &ret_val, 1, &stat, &overlap) ){
throw_io_exception( env, GetLastError() );
return -1;
}
//This is a valid byte, set our valid bit
ret_val |= ( 0x01 << 15 );
}
//Always get the com lines no matter what
if( GetCommModemStatus( desc->port, &get_val ) == 0 ){
throw_io_exception( env, GetLastError() );
return -1;
}
if( get_val & MS_CTS_ON ){
// CTS
ret_val |= ( 0x01 << 10 );
}
if( get_val & MS_DSR_ON ){
// Data Set Ready
ret_val |= ( 0x01 << 11 );
}
if( get_val & MS_RING_ON ){
// Ring Indicator
ret_val |= ( 0x01 << 14 );
}
#else
fd_set fdset;
 
FD_ZERO( &fdset );
FD_SET( desc->port, &fdset );
 
if( select( desc->port + 1, &fdset, NULL, NULL, NULL ) < 0 ){
throw_io_exception( env, errno );
return -1;
}
if( FD_ISSET( desc->port, &fdset ) ){
stat = read( desc->port, &ret_val, sizeof( ret_val ) );
if( stat < 0 ){
//throw new exception
throw_io_exception( env, errno );
return -1;
}
//This is a valid byte, set our valid bit
ret_val |= ( 0x01 << 15 );
}
 
//Now that we have read in the character, let's get the serial port line state.
//If it has changed, we will fire an event in Java.
//Now, because we only read one byte at a time, we will use the lower 8 bytes to
//return the character that we read. The other bytes will be used to return
//information on our serial port state.
if( ioctl( desc->port, TIOCMGET, &get_val ) < 0 ){
throw_io_exception( env, errno );
return -1;
}
 
if( get_val & TIOCM_CD ){
// Carrier detect
ret_val |= ( 0x01 << 9 );
}
 
if( get_val & TIOCM_CTS ){
// CTS
ret_val |= ( 0x01 << 10 );
}
 
if( get_val & TIOCM_DSR ){
// Data Set Ready
ret_val |= ( 0x01 << 11 );
}
 
if( get_val & TIOCM_DTR ){
// Data Terminal Ready
ret_val |= ( 0x01 << 12 );
}
if( get_val & TIOCM_RTS ){
// Request To Send
ret_val |= ( 0x01 << 13 );
}
if( get_val & TIOCM_RI ){
// Ring Indicator
ret_val |= ( 0x01 << 14 );
}
#endif
 
return ret_val;
}
 
/*
* Class: com_rm5248_serial_SerialInputStream
* Method: getAvailable
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialInputStream_getAvailable
(JNIEnv * env, jobject obj){
jint ret_val;
jint array_pos;
struct port_descriptor* desc;
 
array_pos = get_handle( env, obj );
if( array_pos < 0 ){
//throw new exception
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "java/io/IOException");
(*env)->ThrowNew(env, exception_class, strerror( errno ) );
return -1;
}
 
desc = port_list[ array_pos ];
 
if( desc == NULL ){
//throw new exception
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "java/io/IOException");
(*env)->ThrowNew(env, exception_class, strerror( errno ) );
return -1;
}
 
#ifdef _WIN32
{
DWORD comErrors = {0};
COMSTAT portStatus = {0};
if( !ClearCommError( desc->port, &comErrors, &portStatus ) ){
//return value zero = fail
throw_io_exception( env, GetLastError() );
return -1;
}else{
ret_val = portStatus.cbInQue;
}
}
#else
if( ioctl( desc->port, FIONREAD, &ret_val ) < 0 ){
//throw new exception
throw_io_exception( env, errno );
return -1;
}
#endif
return ret_val;
}
 
/*
* Class: com_rm5248_serial_SerialOutputStream
* Method: writeByte
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_com_rm5248_serial_SerialOutputStream_writeByte
(JNIEnv * env, jobject obj, jint byte){
struct port_descriptor* desc;
jint array_pos;
char byte_write;
#ifdef _WIN32
DWORD bytes_written;
OVERLAPPED overlap;
#else
int bytes_written;
#endif
 
byte_write = byte;
 
array_pos = get_handle( env, obj );
if( array_pos < 0 ){
//throw new exception
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "java/io/IOException");
(*env)->ThrowNew(env, exception_class, strerror( errno ) );
return;
}
 
desc = port_list[ array_pos ];
 
if( desc == NULL ){
//throw new exception
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "java/io/IOException");
(*env)->ThrowNew(env, exception_class, strerror( errno ) );
return;
}
 
#ifdef _WIN32
memset( &overlap, 0, sizeof( overlap ) );
overlap.hEvent = CreateEvent( 0, TRUE, 0, 0 );
if( !WriteFile( desc->port, &byte_write, sizeof( byte_write ), &bytes_written, &overlap ) ){
if( GetLastError() == ERROR_IO_PENDING ){
//Not in fact an error, we're just doing this asynchronously
WaitForSingleObject( overlap.hEvent, INFINITE );
}else{
//throw new exception
throw_io_exception( env, GetLastError() );
return;
}
}
#else
bytes_written = write( desc->port, &byte_write, sizeof( byte_write ) );
if( bytes_written < 0 ){
//throw new exception
throw_io_exception( env, errno );
return;
}
#endif
 
}
 
/*
* Class: com_rm5248_serial_SerialOutputStream
* Method: writeByteArray
* Signature: ([B)V
*/
JNIEXPORT void JNICALL Java_com_rm5248_serial_SerialOutputStream_writeByteArray
(JNIEnv * env, jobject obj, jbyteArray arr){
jbyte* data;
jint len;
jint array_pos;
int my_errnum;
struct port_descriptor* desc;
#ifdef _WIN32
DWORD bytes_written;
OVERLAPPED overlap;
#else
int bytes_written;
#endif
 
array_pos = get_handle( env, obj );
if( array_pos < 0 ){
//throw new exception
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "java/io/IOException");
(*env)->ThrowNew(env, exception_class, strerror( errno ) );
return;
}
 
desc = port_list[ array_pos ];
 
if( desc == NULL ){
//throw new exception
jclass exception_class;
(*env)->ExceptionDescribe( env );
(*env)->ExceptionClear( env );
exception_class = (*env)->FindClass(env, "java/io/IOException");
(*env)->ThrowNew(env, exception_class, strerror( errno ) );
return;
}
 
len = (*env)->GetArrayLength( env, arr );
data = (*env)->GetByteArrayElements(env, arr, 0);
 
#ifdef _WIN32
memset( &overlap, 0, sizeof( overlap ) );
overlap.hEvent = CreateEvent( 0, TRUE, 0, 0 );
if( !WriteFile( desc->port, data, len, &bytes_written, &overlap ) ){
if( GetLastError() == ERROR_IO_PENDING ){
//Not in fact an error, we're just doing this asynchronously
WaitForSingleObject( overlap.hEvent, INFINITE );
}else{
my_errnum = GetLastError();
}
}
#else
bytes_written = write( desc->port, data, len );
if( bytes_written < 0 ){
my_errnum = errno;
}
#endif
 
(*env)->ReleaseByteArrayElements(env, arr, data, 0);
 
if( bytes_written != len ){
//OH SNAP AN ERROR
throw_io_exception( env, my_errnum );
}
}
 
//BOOL EscapeCommFunction(HANDLE, DWORD).
/*
1. CLRDTR
2. SETDTR
3. SETRTS
4. CLRRTS
5. SETBREAK
6. CLRBREAK
*/
 
/branches/JavaSerial/0.1/NativeCode/com_rm5248_serial_SerialPort.h
0,0 → 1,133
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_rm5248_serial_SerialPort */
 
#ifndef _Included_com_rm5248_serial_SerialPort
#define _Included_com_rm5248_serial_SerialPort
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_rm5248_serial_SerialPort
* Method: openPort
* Signature: (Ljava/lang/String;IIIII)I
*/
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialPort_openPort__Ljava_lang_String_2IIIII
(JNIEnv *, jobject, jstring, jint, jint, jint, jint, jint);
 
/*
* Class: com_rm5248_serial_SerialPort
* Method: openPort
* Signature: (Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialPort_openPort__Ljava_lang_String_2
(JNIEnv *, jobject, jstring);
 
/*
* Class: com_rm5248_serial_SerialPort
* Method: doClose
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_rm5248_serial_SerialPort_doClose
(JNIEnv *, jobject);
 
/*
* Class: com_rm5248_serial_SerialPort
* Method: setBaudRate
* Signature: (I)Z
*/
JNIEXPORT jboolean JNICALL Java_com_rm5248_serial_SerialPort_setBaudRate
(JNIEnv *, jobject, jint);
 
/*
* Class: com_rm5248_serial_SerialPort
* Method: getBaudRateInternal
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialPort_getBaudRateInternal
(JNIEnv *, jobject);
 
/*
* Class: com_rm5248_serial_SerialPort
* Method: setStopBits
* Signature: (I)Z
*/
JNIEXPORT jboolean JNICALL Java_com_rm5248_serial_SerialPort_setStopBits
(JNIEnv *, jobject, jint);
 
/*
* Class: com_rm5248_serial_SerialPort
* Method: getStopBitsInternal
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialPort_getStopBitsInternal
(JNIEnv *, jobject);
 
/*
* Class: com_rm5248_serial_SerialPort
* Method: setCharSize
* Signature: (I)Z
*/
JNIEXPORT jboolean JNICALL Java_com_rm5248_serial_SerialPort_setCharSize
(JNIEnv *, jobject, jint);
 
/*
* Class: com_rm5248_serial_SerialPort
* Method: getCharSizeInternal
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialPort_getCharSizeInternal
(JNIEnv *, jobject);
 
/*
* Class: com_rm5248_serial_SerialPort
* Method: setParity
* Signature: (I)Z
*/
JNIEXPORT jboolean JNICALL Java_com_rm5248_serial_SerialPort_setParity
(JNIEnv *, jobject, jint);
 
/*
* Class: com_rm5248_serial_SerialPort
* Method: getParityInternal
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialPort_getParityInternal
(JNIEnv *, jobject);
 
/*
* Class: com_rm5248_serial_SerialPort
* Method: setFlowControl
* Signature: (I)Z
*/
JNIEXPORT jboolean JNICALL Java_com_rm5248_serial_SerialPort_setFlowControl
(JNIEnv *, jobject, jint);
 
/*
* Class: com_rm5248_serial_SerialPort
* Method: getFlowControlInternal
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialPort_getFlowControlInternal
(JNIEnv *, jobject);
 
/*
* Class: com_rm5248_serial_SerialPort
* Method: getSerialLineStateInternalNonblocking
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialPort_getSerialLineStateInternalNonblocking
(JNIEnv *, jobject);
 
/*
* Class: com_rm5248_serial_SerialPort
* Method: setSerialLineStateInternal
* Signature: (Lcom/rm5248/serial/SerialLineState;)I
*/
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialPort_setSerialLineStateInternal
(JNIEnv *, jobject, jobject);
 
#ifdef __cplusplus
}
#endif
#endif
/branches/JavaSerial/0.1/NativeCode/Makefile
0,0 → 1,98
#
# Created by gmakemake x86 (Feb 24 2012) on Sat Aug 4 19:31:04 2012
#
 
#
# Definitions
#
 
.SUFFIXES:
.SUFFIXES: .a .o .c .C .cpp .s .S
.c.o:
$(COMPILE.c) $< -o $@
.C.o:
$(COMPILE.cc) $< -o $@
.cpp.o:
$(COMPILE.cc) $< -o $@
.S.s:
$(CPP) -o $*.s $<
.s.o:
$(COMPILE.cc) $< -o $@
.c.a:
$(COMPILE.c) -o $% $<
$(AR) $(ARFLAGS) $@ $%
.C.a:
$(COMPILE.cc) -o $% $<
$(AR) $(ARFLAGS) $@ $%
.cpp.a:
$(COMPILE.cc) -o $% $<
$(AR) $(ARFLAGS) $@ $%
 
CC = gcc
CXX = g++
 
RM = rm -f
AR = ar
LINK.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS)
LINK.cc = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS)
COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) -c
COMPILE.cc = $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c
 
########## Default flags (redefine these with a header.mak file if desired)
CPPFLAGS = -DPIC -I$(JNI_INCLUDE_DIR) -I$(JNI_INCLUDE_DIR)/linux
CXXFLAGS =
CFLAGS = -FPIC -Wall
CLIBFLAGS = -lm
CCLIBFLAGS =
########## End of default flags
 
 
CPP_FILES =
C_FILES = SerialPortImpl.c
PS_FILES =
S_FILES =
H_FILES = com_rm5248_serial_SerialPort.h com_rm5248_serial_SerialPort_SerialInputStream.h com_rm5248_serial_SerialPort_SerialOutputStream.h
SOURCEFILES = $(H_FILES) $(CPP_FILES) $(C_FILES) $(S_FILES)
.PRECIOUS: $(SOURCEFILES)
OBJFILES = SerialPortImpl.o
 
JNI_INCLUDE_DIR = /usr/lib/jvm/java-7-sun/include
JNI_INCLUDE_DIR_WIN=C:\Program Files (x86)\Java\jdk1.6.0_18\include
 
#
# Main targets
#
linux: SerialPortImpl.o
gcc -o libjavaserial.so -shared -Wl,-soname,libjavaserial.so -I$(JNI_INCLUDE_DIR) -I$(JNI_INCLUDE_DIR)/linux -static -lc $(OBJFILES)
 
windows:
cl -I"$(JNI_INCLUDE_DIR_WIN)" -I"$(JNI_INCLUDE_DIR_WIN)\win32" -I"." -MT -LD SerialPortImpl.c -Fejavaserial.dll
#
# Dependencies
#
 
SerialPortImpl.o: SerialPortImpl.c com_rm5248_serial_SerialPort.h \
com_rm5248_serial_SerialInputStream.h \
com_rm5248_serial_SerialOutputStream.h
 
#
# Installation Targets
#
 
install:
/usr/bin/install /usr/bin
 
#
# Housekeeping
#
 
Archive: archive.tgz
 
archive.tgz: $(SOURCEFILES) Makefile
tar cf - $(SOURCEFILES) Makefile | gzip > archive.tgz
 
clean:
-/bin/rm $(OBJFILES) core 2> /dev/null
 
realclean: clean
-/bin/rm -rf
/branches/JavaSerial/0.1/NativeCode/com_rm5248_serial_SerialInputStream.h
0,0 → 1,31
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_rm5248_serial_SerialInputStream */
 
#ifndef _Included_com_rm5248_serial_SerialInputStream
#define _Included_com_rm5248_serial_SerialInputStream
#ifdef __cplusplus
extern "C" {
#endif
#undef com_rm5248_serial_SerialInputStream_SKIP_BUFFER_SIZE
#define com_rm5248_serial_SerialInputStream_SKIP_BUFFER_SIZE 2048L
/*
* Class: com_rm5248_serial_SerialInputStream
* Method: readByte
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialInputStream_readByte
(JNIEnv *, jobject);
 
/*
* Class: com_rm5248_serial_SerialInputStream
* Method: getAvailable
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_rm5248_serial_SerialInputStream_getAvailable
(JNIEnv *, jobject);
 
#ifdef __cplusplus
}
#endif
#endif
/branches/JavaSerial/0.1/.classpath
0,0 → 1,6
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="output" path="bin"/>
</classpath>
/branches/JavaSerial/0.1/.project
0,0 → 1,17
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>JavaSerial</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>