1119 lines
38 KiB
Java
1119 lines
38 KiB
Java
/* jSSC (Java Simple Serial Connector) - serial port communication library.
|
||
* © Alexey Sokolov (scream3r), 2010-2011.
|
||
*
|
||
* This file is part of jSSC.
|
||
*
|
||
* jSSC is free software: you can redistribute it and/or modify
|
||
* it under the terms of the GNU Lesser General Public License as published by
|
||
* the Free Software Foundation, either version 3 of the License, or
|
||
* (at your option) any later version.
|
||
*
|
||
* jSSC is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
* GNU Lesser General Public License for more details.
|
||
*
|
||
* You should have received a copy of the GNU Lesser General Public License
|
||
* along with jSSC. If not, see <http://www.gnu.org/licenses/>.
|
||
*
|
||
* If you use jSSC in public project you can inform me about this by e-mail,
|
||
* of course if you want it.
|
||
*
|
||
* e-mail: scream3r.org@gmail.com
|
||
* web-site: http://scream3r.org | http://code.google.com/p/java-simple-serial-connector/
|
||
*/
|
||
package jssc;
|
||
|
||
/**
|
||
*
|
||
* @author scream3r
|
||
*/
|
||
public class SerialPort {
|
||
|
||
private SerialNativeInterface serialInterface;
|
||
private SerialPortEventListener eventListener;
|
||
private int portHandle;
|
||
private String portName;
|
||
private boolean portOpened = false;
|
||
private boolean maskAssigned = false;
|
||
private boolean eventListenerAdded = false;
|
||
|
||
|
||
public static final int BAUDRATE_110 = 110;
|
||
public static final int BAUDRATE_300 = 300;
|
||
public static final int BAUDRATE_600 = 600;
|
||
public static final int BAUDRATE_1200 = 1200;
|
||
public static final int BAUDRATE_4800 = 4800;
|
||
public static final int BAUDRATE_9600 = 9600;
|
||
public static final int BAUDRATE_14400 = 14400;
|
||
public static final int BAUDRATE_19200 = 19200;
|
||
public static final int BAUDRATE_38400 = 38400;
|
||
public static final int BAUDRATE_57600 = 57600;
|
||
public static final int BAUDRATE_115200 = 115200;
|
||
public static final int BAUDRATE_128000 = 128000;
|
||
public static final int BAUDRATE_256000 = 256000;
|
||
|
||
|
||
public static final int DATABITS_5 = 5;
|
||
public static final int DATABITS_6 = 6;
|
||
public static final int DATABITS_7 = 7;
|
||
public static final int DATABITS_8 = 8;
|
||
|
||
|
||
public static final int STOPBITS_1 = 1;
|
||
public static final int STOPBITS_2 = 2;
|
||
public static final int STOPBITS_1_5 = 3;
|
||
|
||
|
||
public static final int PARITY_NONE = 0;
|
||
public static final int PARITY_ODD = 1;
|
||
public static final int PARITY_EVEN = 2;
|
||
public static final int PARITY_MARK = 3;
|
||
public static final int PARITY_SPACE = 4;
|
||
|
||
|
||
public static final int PURGE_RXABORT = 0x0002;
|
||
public static final int PURGE_RXCLEAR = 0x0008;
|
||
public static final int PURGE_TXABORT = 0x0001;
|
||
public static final int PURGE_TXCLEAR = 0x0004;
|
||
|
||
|
||
public static final int MASK_RXCHAR = 1;
|
||
public static final int MASK_RXFLAG = 2;
|
||
public static final int MASK_TXEMPTY = 4;
|
||
public static final int MASK_CTS = 8;
|
||
public static final int MASK_DSR = 16;
|
||
public static final int MASK_RLSD = 32;
|
||
public static final int MASK_BREAK = 64;
|
||
public static final int MASK_ERR = 128;
|
||
public static final int MASK_RING = 256;
|
||
|
||
|
||
//since 0.8 ->
|
||
public static final int FLOWCONTROL_NONE = 0;
|
||
public static final int FLOWCONTROL_RTSCTS_IN = 1;
|
||
public static final int FLOWCONTROL_RTSCTS_OUT = 2;
|
||
public static final int FLOWCONTROL_XONXOFF_IN = 4;
|
||
public static final int FLOWCONTROL_XONXOFF_OUT = 8;
|
||
//<- since 0.8
|
||
|
||
//since 0.8 ->
|
||
public static final int ERROR_FRAME = 0x0008;
|
||
public static final int ERROR_OVERRUN = 0x0002;
|
||
public static final int ERROR_PARITY = 0x0004;
|
||
//<- since 0.8
|
||
|
||
public SerialPort(String portName) {
|
||
this.portName = portName;
|
||
serialInterface = new SerialNativeInterface();
|
||
}
|
||
|
||
/**
|
||
* Getting port name under operation
|
||
*
|
||
* @return Method returns port name under operation as a String
|
||
*/
|
||
public String getPortName(){
|
||
return portName;
|
||
}
|
||
|
||
/**
|
||
* Getting port state
|
||
*
|
||
* @return Method returns true if port is open, otherwise false
|
||
*/
|
||
public boolean isOpened() {
|
||
return portOpened;
|
||
}
|
||
|
||
/**
|
||
* Port opening
|
||
* <br><br>
|
||
* <b>Note: </b>If port busy <b>TYPE_PORT_BUSY</b> exception will be thrown.
|
||
* If port not found <b>TYPE_PORT_NOT_FOUND</b> exception will be thrown.
|
||
*
|
||
* @return If the operation is successfully completed, the method returns true
|
||
*
|
||
* @throws SerialPortException
|
||
*/
|
||
public boolean openPort() throws SerialPortException {
|
||
if(portOpened){
|
||
throw new SerialPortException(portName, "openPort()", SerialPortException.TYPE_PORT_ALREADY_OPENED);
|
||
}
|
||
portHandle = serialInterface.openPort(portName);
|
||
//since 0.9.0 ->
|
||
if(portHandle == -1){
|
||
throw new SerialPortException(portName, "openPort()", SerialPortException.TYPE_PORT_BUSY);
|
||
}
|
||
else if(portHandle == -2){
|
||
throw new SerialPortException(portName, "openPort()", SerialPortException.TYPE_PORT_NOT_FOUND);
|
||
}
|
||
//<- since 0.9.0
|
||
portOpened = true;
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* Setting the parameters of port. RTS and DTR lines are enabled by default
|
||
*
|
||
* @param baudRate data transfer rate
|
||
* @param dataBits number of data bits
|
||
* @param stopBits number of stop bits
|
||
* @param parity parity
|
||
*
|
||
* @return If the operation is successfully completed, the method returns true, otherwise false
|
||
*
|
||
* @throws SerialPortException
|
||
*/
|
||
public boolean setParams(int baudRate, int dataBits, int stopBits, int parity) throws SerialPortException {
|
||
checkPortOpened("setParams()");
|
||
if(stopBits == 1){
|
||
stopBits = 0;
|
||
}
|
||
else if(stopBits == 3){
|
||
stopBits = 1;
|
||
}
|
||
return serialInterface.setParams(portHandle, baudRate, dataBits, stopBits, parity, true, true);
|
||
}
|
||
|
||
/**
|
||
* Setting the parameters of port
|
||
*
|
||
* @param baudRate data transfer rate
|
||
* @param dataBits number of data bits
|
||
* @param stopBits number of stop bits
|
||
* @param parity parity
|
||
* @param setRTS initial state of RTS line(ON/OFF)
|
||
* @param setDTR initial state of DTR line(ON/OFF)
|
||
*
|
||
* @return If the operation is successfully completed, the method returns true, otherwise false
|
||
*
|
||
* @throws SerialPortException
|
||
*
|
||
* @since 0.8
|
||
*/
|
||
public boolean setParams(int baudRate, int dataBits, int stopBits, int parity, boolean setRTS, boolean setDTR) throws SerialPortException {
|
||
checkPortOpened("setParams()");
|
||
if(stopBits == 1){
|
||
stopBits = 0;
|
||
}
|
||
else if(stopBits == 3){
|
||
stopBits = 1;
|
||
}
|
||
return serialInterface.setParams(portHandle, baudRate, dataBits, stopBits, parity, setRTS, setDTR);
|
||
}
|
||
|
||
/**
|
||
* Purge of input and output buffer. Required flags shall be sent to the input. Variables with prefix
|
||
* <b>"PURGE_"</b>, for example <b>"PURGE_RXCLEAR"</b>. Sent parameter "flags" is additive value,
|
||
* so addition of flags is allowed. For example, if input or output buffer shall be purged,
|
||
* parameter <b>"PURGE_RXCLEAR | PURGE_TXCLEAR"</b>.
|
||
* <br><b>Note: </b>some devices or drivers may not support this function
|
||
*
|
||
* @return If the operation is successfully completed, the method returns true, otherwise false.
|
||
*
|
||
* @throws SerialPortException
|
||
*/
|
||
public boolean purgePort(int flags) throws SerialPortException {
|
||
checkPortOpened("purgePort()");
|
||
return serialInterface.purgePort(portHandle, flags);
|
||
}
|
||
|
||
/**
|
||
* Events mask for Linux OS
|
||
*
|
||
* @since 0.8
|
||
*/
|
||
private int linuxMask;
|
||
|
||
/**
|
||
* Set events mask. Required flags shall be sent to the input. Variables with prefix
|
||
* <b>"MASK_"</b>, shall be used as flags, for example <b>"MASK_RXCHAR"</b>.
|
||
* Sent parameter "mask" is additive value, so addition of flags is allowed.
|
||
* For example if messages about data receipt and CTS and DSR status changing
|
||
* shall be received, it is required to set the mask - <b>"MASK_RXCHAR | MASK_CTS | MASK_DSR"</b>
|
||
*
|
||
* @return If the operation is successfully completed, the method returns true, otherwise false
|
||
*
|
||
* @throws SerialPortException
|
||
*/
|
||
public boolean setEventsMask(int mask) throws SerialPortException {
|
||
checkPortOpened("setEventsMask()");
|
||
if(SerialNativeInterface.getOsType() == SerialNativeInterface.OS_LINUX ||
|
||
SerialNativeInterface.getOsType() == SerialNativeInterface.OS_SOLARIS ||
|
||
SerialNativeInterface.getOsType() == SerialNativeInterface.OS_MAC_OS_X){//since 0.9.0
|
||
linuxMask = mask;
|
||
if(mask > 0){
|
||
maskAssigned = true;
|
||
}
|
||
else {
|
||
maskAssigned = false;
|
||
}
|
||
return true;
|
||
}
|
||
boolean returnValue = serialInterface.setEventsMask(portHandle, mask);
|
||
if(!returnValue){
|
||
throw new SerialPortException(portName, "setEventsMask()", SerialPortException.TYPE_CANT_SET_MASK);
|
||
}
|
||
if(mask > 0){
|
||
maskAssigned = true;
|
||
}
|
||
else {
|
||
maskAssigned = false;
|
||
}
|
||
return returnValue;
|
||
}
|
||
|
||
/**
|
||
* Getting events mask for the port
|
||
*
|
||
* @return Method returns events mask as int type variable. This variable is an additive value
|
||
*
|
||
* @throws SerialPortException
|
||
*/
|
||
public int getEventsMask() throws SerialPortException {
|
||
checkPortOpened("getEventsMask()");
|
||
if(SerialNativeInterface.getOsType() == SerialNativeInterface.OS_LINUX ||
|
||
SerialNativeInterface.getOsType() == SerialNativeInterface.OS_SOLARIS ||
|
||
SerialNativeInterface.getOsType() == SerialNativeInterface.OS_MAC_OS_X){//since 0.9.0
|
||
return linuxMask;
|
||
}
|
||
return serialInterface.getEventsMask(portHandle);
|
||
}
|
||
|
||
/**
|
||
* Getting events mask for the port is Linux OS (for internal use)
|
||
*
|
||
* @since 0.8
|
||
*/
|
||
private int getLinuxMask() {
|
||
return linuxMask;
|
||
}
|
||
|
||
/**
|
||
* Change RTS line state. Set "true" for switching ON and "false" for switching OFF RTS line
|
||
*
|
||
* @return If the operation is successfully completed, the method returns true, otherwise false
|
||
*
|
||
* @throws SerialPortException
|
||
*/
|
||
public boolean setRTS(boolean enabled) throws SerialPortException {
|
||
checkPortOpened("setRTS()");
|
||
return serialInterface.setRTS(portHandle, enabled);
|
||
}
|
||
|
||
/**
|
||
* Change DTR line state. Set "true" for switching ON and "false" for switching OFF DTR line
|
||
*
|
||
* @return If the operation is successfully completed, the method returns true, otherwise false
|
||
*
|
||
* @throws SerialPortException
|
||
*/
|
||
public boolean setDTR(boolean enabled) throws SerialPortException {
|
||
checkPortOpened("setDTR()");
|
||
return serialInterface.setDTR(portHandle, enabled);
|
||
}
|
||
|
||
/**
|
||
* Write byte array to port
|
||
*
|
||
* @return If the operation is successfully completed, the method returns true, otherwise false
|
||
*
|
||
* @throws SerialPortException
|
||
*/
|
||
public boolean writeBytes(byte[] buffer) throws SerialPortException {
|
||
checkPortOpened("writeBytes()");
|
||
return serialInterface.writeBytes(portHandle, buffer);
|
||
}
|
||
|
||
/**
|
||
* Write single byte to port
|
||
*
|
||
* @return If the operation is successfully completed, the method returns true, otherwise false
|
||
*
|
||
* @throws SerialPortException
|
||
*
|
||
* @since 0.8
|
||
*/
|
||
public boolean writeByte(byte singleByte) throws SerialPortException {
|
||
checkPortOpened("writeByte()");
|
||
return writeBytes(new byte[]{singleByte});
|
||
}
|
||
|
||
/**
|
||
* Write String to port
|
||
*
|
||
* @return If the operation is successfully completed, the method returns true, otherwise false
|
||
*
|
||
* @throws SerialPortException
|
||
*
|
||
* @since 0.8
|
||
*/
|
||
public boolean writeString(String string) throws SerialPortException {
|
||
checkPortOpened("writeString()");
|
||
return writeBytes(string.getBytes());
|
||
}
|
||
|
||
/**
|
||
* Write int value (in range from 0 to 255 (0x00 - 0xFF)) to port
|
||
*
|
||
* @return If the operation is successfully completed, the method returns true, otherwise false
|
||
*
|
||
* @throws SerialPortException
|
||
*
|
||
* @since 0.8
|
||
*/
|
||
public boolean writeInt(int singleInt) throws SerialPortException {
|
||
checkPortOpened("writeInt()");
|
||
return writeBytes(new byte[]{(byte)singleInt});
|
||
}
|
||
|
||
/**
|
||
* Write int array (in range from 0 to 255 (0x00 - 0xFF)) to port
|
||
*
|
||
* @return If the operation is successfully completed, the method returns true, otherwise false
|
||
*
|
||
* @throws SerialPortException
|
||
*
|
||
* @since 0.8
|
||
*/
|
||
public boolean writeIntArray(int[] buffer) throws SerialPortException {
|
||
checkPortOpened("writeIntArray()");
|
||
byte[] byteArray = new byte[buffer.length];
|
||
for(int i = 0; i < buffer.length; i++){
|
||
byteArray[i] = (byte)buffer[i];
|
||
}
|
||
return writeBytes(byteArray);
|
||
}
|
||
|
||
/**
|
||
* Read byte array from port
|
||
*
|
||
* @param byteCount count of bytes for reading
|
||
*
|
||
* @return byte array with "byteCount" length
|
||
*
|
||
* @throws SerialPortException
|
||
*/
|
||
public byte[] readBytes(int byteCount) throws SerialPortException {
|
||
checkPortOpened("readBytes()");
|
||
return serialInterface.readBytes(portHandle, byteCount);
|
||
}
|
||
|
||
/**
|
||
* Read string from port
|
||
*
|
||
* @param byteCount count of bytes for reading
|
||
*
|
||
* @return byte array with "byteCount" length converted to String
|
||
*
|
||
* @throws SerialPortException
|
||
*
|
||
* @since 0.8
|
||
*/
|
||
public String readString(int byteCount) throws SerialPortException {
|
||
checkPortOpened("readString()");
|
||
return new String(readBytes(byteCount));
|
||
}
|
||
|
||
/**
|
||
* Read Hex string from port (example: FF OA FF). Separator by default is a space
|
||
*
|
||
* @param byteCount count of bytes for reading
|
||
*
|
||
* @return byte array with "byteCount" length converted to Hexadecimal String
|
||
*
|
||
* @throws SerialPortException
|
||
*
|
||
* @since 0.8
|
||
*/
|
||
public String readHexString(int byteCount) throws SerialPortException {
|
||
checkPortOpened("readHexString()");
|
||
return readHexString(byteCount, " ");
|
||
}
|
||
|
||
/**
|
||
* Read Hex string from port with setted separator (example if separator is "::": FF::OA::FF)
|
||
*
|
||
* @param byteCount count of bytes for reading
|
||
*
|
||
* @return byte array with "byteCount" length converted to Hexadecimal String
|
||
*
|
||
* @throws SerialPortException
|
||
*
|
||
* @since 0.8
|
||
*/
|
||
public String readHexString(int byteCount, String separator) throws SerialPortException {
|
||
checkPortOpened("readHexString()");
|
||
String[] strBuffer = readHexStringArray(byteCount);
|
||
String returnString = "";
|
||
boolean insertSeparator = false;
|
||
for(String value : strBuffer){
|
||
if(insertSeparator){
|
||
returnString += separator;
|
||
}
|
||
returnString += value;
|
||
insertSeparator = true;
|
||
}
|
||
return returnString;
|
||
}
|
||
|
||
/**
|
||
* Read Hex String array from port
|
||
*
|
||
* @param byteCount count of bytes for reading
|
||
*
|
||
* @return String array with "byteCount" length and Hexadecimal String values
|
||
*
|
||
* @throws SerialPortException
|
||
*
|
||
* @since 0.8
|
||
*/
|
||
public String[] readHexStringArray(int byteCount) throws SerialPortException {
|
||
checkPortOpened("readHexStringArray()");
|
||
int[] intBuffer = readIntArray(byteCount);
|
||
String[] strBuffer = new String[intBuffer.length];
|
||
for(int i = 0; i < intBuffer.length; i++){
|
||
String value = Integer.toHexString(intBuffer[i]).toUpperCase();
|
||
if(value.length() == 1) {
|
||
value = "0" + value;
|
||
}
|
||
strBuffer[i] = value;
|
||
}
|
||
return strBuffer;
|
||
}
|
||
|
||
/**
|
||
* Read int array from port
|
||
*
|
||
* @param byteCount count of bytes for reading
|
||
*
|
||
* @return int array with values in range from 0 to 255
|
||
*
|
||
* @throws SerialPortException
|
||
*
|
||
* @since 0.8
|
||
*/
|
||
public int[] readIntArray(int byteCount) throws SerialPortException {
|
||
checkPortOpened("readIntArray()");
|
||
byte[] buffer = readBytes(byteCount);
|
||
int[] intBuffer = new int[buffer.length];
|
||
for(int i = 0; i < buffer.length; i++){
|
||
if(buffer[i] < 0){
|
||
intBuffer[i] = 256 + buffer[i];
|
||
}
|
||
else {
|
||
intBuffer[i] = buffer[i];
|
||
}
|
||
}
|
||
return intBuffer;
|
||
}
|
||
|
||
/**
|
||
* Read all available bytes from port like a byte array
|
||
*
|
||
* @return If input buffer is empty <b>null</b> will be returned, else byte array with all data from port
|
||
*
|
||
* @throws SerialPortException
|
||
*
|
||
* @since 0.8
|
||
*/
|
||
public byte[] readBytes() throws SerialPortException {
|
||
checkPortOpened("readBytes()");
|
||
int byteCount = getInputBufferBytesCount();
|
||
if(byteCount <= 0){
|
||
return null;
|
||
}
|
||
return readBytes(byteCount);
|
||
}
|
||
|
||
/**
|
||
* Read all available bytes from port like a String
|
||
*
|
||
* @return If input buffer is empty <b>null</b> will be returned, else byte array with all data from port converted to String
|
||
*
|
||
* @throws SerialPortException
|
||
*
|
||
* @since 0.8
|
||
*/
|
||
public String readString() throws SerialPortException {
|
||
checkPortOpened("readString()");
|
||
int byteCount = getInputBufferBytesCount();
|
||
if(byteCount <= 0){
|
||
return null;
|
||
}
|
||
return readString(byteCount);
|
||
}
|
||
|
||
/**
|
||
* Read all available bytes from port like a Hex String
|
||
*
|
||
* @return If input buffer is empty <b>null</b> will be returned, else byte array with all data from port converted to Hex String
|
||
*
|
||
* @throws SerialPortException
|
||
*
|
||
* @since 0.8
|
||
*/
|
||
public String readHexString() throws SerialPortException {
|
||
checkPortOpened("readHexString()");
|
||
int byteCount = getInputBufferBytesCount();
|
||
if(byteCount <= 0){
|
||
return null;
|
||
}
|
||
return readHexString(byteCount);
|
||
}
|
||
|
||
/**
|
||
* Read all available bytes from port like a Hex String with setted separator
|
||
*
|
||
* @return If input buffer is empty <b>null</b> will be returned, else byte array with all data from port converted to Hex String
|
||
*
|
||
* @throws SerialPortException
|
||
*
|
||
* @since 0.8
|
||
*/
|
||
public String readHexString(String separator) throws SerialPortException {
|
||
checkPortOpened("readHexString()");
|
||
int byteCount = getInputBufferBytesCount();
|
||
if(byteCount <= 0){
|
||
return null;
|
||
}
|
||
return readHexString(byteCount, separator);
|
||
}
|
||
|
||
/**
|
||
* Read all available bytes from port like a Hex String array
|
||
*
|
||
* @return If input buffer is empty <b>null</b> will be returned, else byte array with all data from port converted to Hex String array
|
||
*
|
||
* @throws SerialPortException
|
||
*
|
||
* @since 0.8
|
||
*/
|
||
public String[] readHexStringArray() throws SerialPortException {
|
||
checkPortOpened("readHexStringArray()");
|
||
int byteCount = getInputBufferBytesCount();
|
||
if(byteCount <= 0){
|
||
return null;
|
||
}
|
||
return readHexStringArray(byteCount);
|
||
}
|
||
|
||
/**
|
||
* Read all available bytes from port like a int array (values in range from 0 to 255)
|
||
*
|
||
* @return If input buffer is empty <b>null</b> will be returned, else byte array with all data from port converted to int array
|
||
*
|
||
* @throws SerialPortException
|
||
*
|
||
* @since 0.8
|
||
*/
|
||
public int[] readIntArray() throws SerialPortException {
|
||
checkPortOpened("readHex()");
|
||
int byteCount = getInputBufferBytesCount();
|
||
if(byteCount <= 0){
|
||
return null;
|
||
}
|
||
return readIntArray(byteCount);
|
||
}
|
||
|
||
/**
|
||
* Get count of bytes in input buffer
|
||
*
|
||
* @return Count of bytes in input buffer or -1 if error occured
|
||
*
|
||
* @throws SerialPortException
|
||
*
|
||
* @since 0.8
|
||
*/
|
||
public int getInputBufferBytesCount() throws SerialPortException {
|
||
checkPortOpened("getInputBufferBytesCount()");
|
||
return serialInterface.getBuffersBytesCount(portHandle)[0];
|
||
}
|
||
|
||
/**
|
||
* Get count of bytes in output buffer
|
||
*
|
||
* @return Count of bytes in output buffer or -1 if error occured
|
||
*
|
||
* @throws SerialPortException
|
||
*
|
||
* @since 0.8
|
||
*/
|
||
public int getOutputBufferBytesCount() throws SerialPortException {
|
||
checkPortOpened("getOutputBufferBytesCount()");
|
||
return serialInterface.getBuffersBytesCount(portHandle)[1];
|
||
}
|
||
|
||
/**
|
||
* Set flow control mode. For required mode use variables with prefix <b>"FLOWCONTROL_"</b>.
|
||
* Example of hardware flow control mode(RTS/CTS): setFlowControlMode(FLOWCONTROL_RTSCTS_IN | FLOWCONTROL_RTSCTS_OUT);
|
||
*
|
||
* @return If the operation is successfully completed, the method returns true, otherwise false
|
||
*
|
||
* @throws SerialPortException
|
||
*
|
||
* @since 0.8
|
||
*/
|
||
public boolean setFlowControlMode(int mask) throws SerialPortException {
|
||
checkPortOpened("setFlowControlMode()");
|
||
return serialInterface.setFlowControlMode(portHandle, mask);
|
||
}
|
||
|
||
/**
|
||
* Get flow control mode
|
||
*
|
||
* @return Mask of setted flow control mode
|
||
*
|
||
* @throws SerialPortException
|
||
*
|
||
* @since 0.8
|
||
*/
|
||
public int getFlowControlMode() throws SerialPortException {
|
||
checkPortOpened("getFlowControlMode()");
|
||
return serialInterface.getFlowControlMode(portHandle);
|
||
}
|
||
|
||
/**
|
||
* Send Break singnal for setted duration
|
||
*
|
||
* @param duration duration of Break signal
|
||
*
|
||
* @return If the operation is successfully completed, the method returns true, otherwise false
|
||
*
|
||
* @throws SerialPortException
|
||
*
|
||
* @since 0.8
|
||
*/
|
||
public boolean sendBreak(int duration)throws SerialPortException {
|
||
checkPortOpened("sendBreak()");
|
||
return serialInterface.sendBreak(portHandle, duration);
|
||
}
|
||
|
||
private int[][] waitEvents() {
|
||
return serialInterface.waitEvents(portHandle);
|
||
}
|
||
|
||
/**
|
||
* Check port opened (since jSSC-0.8 String "EMPTY" was replaced with "portName" variable)
|
||
*
|
||
* @param methodName method name
|
||
*
|
||
* @throws SerialPortException
|
||
*/
|
||
private void checkPortOpened(String methodName) throws SerialPortException {
|
||
if(!portOpened){
|
||
throw new SerialPortException(portName, methodName, SerialPortException.TYPE_PORT_NOT_OPENED);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Getting lines status. Lines status is sent as 0 – OFF and 1 - ON
|
||
*
|
||
* @return Method returns the array containing information about lines in following order:
|
||
* <br><b>element 0</b> - <b>CTS</b> line state</br>
|
||
* <br><b>element 1</b> - <b>DSR</b> line state</br>
|
||
* <br><b>element 2</b> - <b>RING</b> line state</br>
|
||
* <br><b>element 3</b> - <b>RLSD</b> line state</br>
|
||
*
|
||
* @throws SerialPortException
|
||
*/
|
||
public int[] getLinesStatus() throws SerialPortException {
|
||
checkPortOpened("getLinesStatus()");
|
||
return serialInterface.getLinesStatus(portHandle);
|
||
}
|
||
|
||
/**
|
||
* Get state of CTS line
|
||
*
|
||
* @return If line is active, method returns true, otherwise false
|
||
*
|
||
* @throws SerialPortException
|
||
*/
|
||
public boolean isCTS() throws SerialPortException {
|
||
checkPortOpened("isCTS()");
|
||
if(serialInterface.getLinesStatus(portHandle)[0] == 1){
|
||
return true;
|
||
}
|
||
else {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Get state of DSR line
|
||
*
|
||
* @return If line is active, method returns true, otherwise false
|
||
*
|
||
* @throws SerialPortException
|
||
*/
|
||
public boolean isDSR() throws SerialPortException {
|
||
checkPortOpened("isDSR()");
|
||
if(serialInterface.getLinesStatus(portHandle)[1] == 1){
|
||
return true;
|
||
}
|
||
else {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Get state of RING line
|
||
*
|
||
* @return If line is active, method returns true, otherwise false
|
||
*
|
||
* @throws SerialPortException
|
||
*/
|
||
public boolean isRING() throws SerialPortException {
|
||
checkPortOpened("isRING()");
|
||
if(serialInterface.getLinesStatus(portHandle)[2] == 1){
|
||
return true;
|
||
}
|
||
else {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Get state of RLSD line
|
||
*
|
||
* @return If line is active, method returns true, otherwise false
|
||
*
|
||
* @throws SerialPortException
|
||
*/
|
||
public boolean isRLSD() throws SerialPortException {
|
||
checkPortOpened("isRLSD()");
|
||
if(serialInterface.getLinesStatus(portHandle)[3] == 1){
|
||
return true;
|
||
}
|
||
else {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Add event listener. Object of <b>"SerialPortEventListener"</b> type shall
|
||
* be sent to the method. This object shall be properly described, as it will
|
||
* be in charge for handling of occurred events. This method will independently
|
||
* set the mask in <b>"MASK_RXCHAR"</b> state if it was not set beforehand
|
||
*
|
||
* @throws SerialPortException
|
||
*/
|
||
public void addEventListener(SerialPortEventListener listener) throws SerialPortException {
|
||
checkPortOpened("addEventListener()");
|
||
if(!eventListenerAdded){
|
||
if(maskAssigned){
|
||
eventListener = listener;
|
||
eventThread = getNewEventThread();
|
||
eventThread.setName("EventThread " + portName);
|
||
eventThread.start();
|
||
eventListenerAdded = true;
|
||
}
|
||
else {
|
||
setEventsMask(MASK_RXCHAR);
|
||
eventListener = listener;
|
||
eventThread = getNewEventThread();
|
||
eventThread.setName("EventThread " + portName);
|
||
eventThread.start();
|
||
eventListenerAdded = true;
|
||
}
|
||
}
|
||
else {
|
||
throw new SerialPortException(portName, "addEventListener()", SerialPortException.TYPE_LISTENER_ALREADY_ADDED);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Add event listener. Object of <b>"SerialPortEventListener"</b> type shall be sent
|
||
* to the method. This object shall be properly described, as it will be in
|
||
* charge for handling of occurred events. Also events mask shall be sent to
|
||
* this method, to do it use variables with prefix <b>"MASK_"</b> for example <b>"MASK_RXCHAR"</b>
|
||
*
|
||
* @see #setEventsMask(int) setEventsMask(int mask)
|
||
*
|
||
* @throws SerialPortException
|
||
*/
|
||
public void addEventListener(SerialPortEventListener listener, int mask) throws SerialPortException {
|
||
checkPortOpened("addEventListener()");
|
||
if(!eventListenerAdded){
|
||
setEventsMask(mask);
|
||
eventListener = listener;
|
||
eventThread = getNewEventThread();
|
||
eventThread.setName("EventThread " + portName);
|
||
eventThread.start();
|
||
eventListenerAdded = true;
|
||
}
|
||
else {
|
||
throw new SerialPortException(portName, "addEventListener()", SerialPortException.TYPE_LISTENER_ALREADY_ADDED);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Create new EventListener Thread depending on the type of operating system
|
||
*
|
||
* @since 0.8
|
||
*/
|
||
private EventThread getNewEventThread() {
|
||
if(SerialNativeInterface.getOsType() == SerialNativeInterface.OS_LINUX ||
|
||
SerialNativeInterface.getOsType() == SerialNativeInterface.OS_SOLARIS ||
|
||
SerialNativeInterface.getOsType() == SerialNativeInterface.OS_MAC_OS_X){//since 0.9.0
|
||
return new LinuxEventThread();
|
||
}
|
||
return new EventThread();
|
||
}
|
||
|
||
/**
|
||
* Delete event listener. Mask is set to 0. So at the next addition of event
|
||
* handler you shall set required event mask again
|
||
*
|
||
* @return If the operation is successfully completed, the method returns true, otherwise false
|
||
*
|
||
* @throws SerialPortException
|
||
*/
|
||
public boolean removeEventListener() throws SerialPortException {
|
||
checkPortOpened("removeEventListener()");
|
||
if(!eventListenerAdded){
|
||
throw new SerialPortException(portName, "removeEventListener()", SerialPortException.TYPE_CANT_REMOVE_LISTENER);
|
||
}
|
||
eventThread.terminateThread();
|
||
setEventsMask(0);
|
||
if(Thread.currentThread().getId() != eventThread.getId()){
|
||
if(eventThread.isAlive()){
|
||
try {
|
||
eventThread.join(5000);
|
||
}
|
||
catch (InterruptedException ex) {
|
||
throw new SerialPortException(portName, "removeEventListener()", SerialPortException.TYPE_LISTENER_THREAD_INTERRUPTED);
|
||
}
|
||
}
|
||
}
|
||
eventListenerAdded = false;
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* Close port. This method deletes event listener first, then closes the port
|
||
*
|
||
* @return If the operation is successfully completed, the method returns true, otherwise false
|
||
*
|
||
* @throws SerialPortException
|
||
*/
|
||
public boolean closePort() throws SerialPortException {
|
||
checkPortOpened("closePort()");
|
||
if(eventListenerAdded){
|
||
removeEventListener();
|
||
}
|
||
boolean returnValue = serialInterface.closePort(portHandle);
|
||
if(returnValue){
|
||
maskAssigned = false;
|
||
portOpened = false;
|
||
}
|
||
return returnValue;
|
||
}
|
||
|
||
private EventThread eventThread;
|
||
|
||
private class EventThread extends Thread {
|
||
|
||
private boolean threadTerminated = false;
|
||
|
||
@Override
|
||
public void run() {
|
||
while(!threadTerminated){
|
||
int[][] eventArray = waitEvents();
|
||
for(int i = 0; i < eventArray.length; i++){
|
||
if(eventArray[i][0] > 0 && !threadTerminated){
|
||
eventListener.serialEvent(new SerialPortEvent(portName, eventArray[i][0], eventArray[i][1]));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private void terminateThread(){
|
||
threadTerminated = true;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* EventListener for Linux OS
|
||
*
|
||
* @since 0.8
|
||
*/
|
||
private class LinuxEventThread extends EventThread {
|
||
|
||
//Essential interruptions for events: BREAK, ERR, TXEMPTY
|
||
private final int INTERRUPT_BREAK = 512;
|
||
private final int INTERRUPT_TX = 1024;
|
||
private final int INTERRUPT_FRAME = 2048;
|
||
private final int INTERRUPT_OVERRUN = 4096;
|
||
private final int INTERRUPT_PARITY = 8192;
|
||
|
||
//Count of interruptions
|
||
private int interruptBreak;
|
||
private int interruptTX;
|
||
private int interruptFrame;
|
||
private int interruptOverrun;
|
||
private int interruptParity;
|
||
|
||
//Previous states if lines (then state change event will be generated)
|
||
private int preCTS;
|
||
private int preDSR;
|
||
private int preRLSD;
|
||
private int preRING;
|
||
|
||
//Need to get initial states
|
||
public LinuxEventThread(){
|
||
int[][] eventArray = waitEvents();
|
||
for(int i = 0; i < eventArray.length; i++){
|
||
int eventType = eventArray[i][0];
|
||
int eventValue = eventArray[i][1];
|
||
switch(eventType){
|
||
case INTERRUPT_BREAK:
|
||
interruptBreak = eventValue;
|
||
break;
|
||
case INTERRUPT_TX:
|
||
interruptTX = eventValue;
|
||
break;
|
||
case INTERRUPT_FRAME:
|
||
interruptFrame = eventValue;
|
||
break;
|
||
case INTERRUPT_OVERRUN:
|
||
interruptOverrun = eventValue;
|
||
break;
|
||
case INTERRUPT_PARITY:
|
||
interruptParity = eventValue;
|
||
break;
|
||
case MASK_CTS:
|
||
preCTS = eventValue;
|
||
break;
|
||
case MASK_DSR:
|
||
preDSR = eventValue;
|
||
break;
|
||
case MASK_RING:
|
||
preRING = eventValue;
|
||
break;
|
||
case MASK_RLSD:
|
||
preRLSD = eventValue;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
@Override
|
||
public void run() {
|
||
while(!super.threadTerminated){
|
||
int[][] eventArray = waitEvents();
|
||
int mask = getLinuxMask();
|
||
boolean interruptTxChanged = false;
|
||
int errorMask = 0;
|
||
for(int i = 0; i < eventArray.length; i++){
|
||
boolean sendEvent = false;
|
||
int eventType = eventArray[i][0];
|
||
int eventValue = eventArray[i][1];
|
||
if(eventType > 0 && !super.threadTerminated){
|
||
switch(eventType){
|
||
case INTERRUPT_BREAK:
|
||
if(eventValue != interruptBreak){
|
||
interruptBreak = eventValue;
|
||
if((mask & MASK_BREAK) == MASK_BREAK){
|
||
eventType = MASK_BREAK;
|
||
eventValue = 0;
|
||
sendEvent = true;
|
||
}
|
||
}
|
||
break;
|
||
case INTERRUPT_TX:
|
||
if(eventValue != interruptTX){
|
||
interruptTX = eventValue;
|
||
interruptTxChanged = true;
|
||
}
|
||
break;
|
||
case INTERRUPT_FRAME:
|
||
if(eventValue != interruptFrame){
|
||
interruptFrame = eventValue;
|
||
errorMask |= ERROR_FRAME;
|
||
}
|
||
break;
|
||
case INTERRUPT_OVERRUN:
|
||
if(eventValue != interruptOverrun){
|
||
interruptOverrun = eventValue;
|
||
errorMask |= ERROR_OVERRUN;
|
||
}
|
||
break;
|
||
case INTERRUPT_PARITY:
|
||
if(eventValue != interruptParity){
|
||
interruptParity = eventValue;
|
||
errorMask |= ERROR_PARITY;
|
||
}
|
||
if((mask & MASK_ERR) == MASK_ERR && errorMask != 0){
|
||
eventType = MASK_ERR;
|
||
eventValue = errorMask;
|
||
sendEvent = true;
|
||
}
|
||
break;
|
||
case MASK_CTS:
|
||
if(eventValue != preCTS){
|
||
preCTS = eventValue;
|
||
if((mask & MASK_CTS) == MASK_CTS){
|
||
sendEvent = true;
|
||
}
|
||
}
|
||
break;
|
||
case MASK_DSR:
|
||
if(eventValue != preDSR){
|
||
preDSR = eventValue;
|
||
if((mask & MASK_DSR) == MASK_DSR){
|
||
sendEvent = true;
|
||
}
|
||
}
|
||
break;
|
||
case MASK_RING:
|
||
if(eventValue != preRING){
|
||
preRING = eventValue;
|
||
if((mask & MASK_RING) == MASK_RING){
|
||
sendEvent = true;
|
||
}
|
||
}
|
||
break;
|
||
case MASK_RLSD: /*DCD*/
|
||
if(eventValue != preRLSD){
|
||
preRLSD = eventValue;
|
||
if((mask & MASK_RLSD) == MASK_RLSD){
|
||
sendEvent = true;
|
||
}
|
||
}
|
||
break;
|
||
case MASK_RXCHAR:
|
||
if(((mask & MASK_RXCHAR) == MASK_RXCHAR) && (eventValue > 0)){
|
||
sendEvent = true;
|
||
}
|
||
break;
|
||
/*case MASK_RXFLAG:
|
||
//Do nothing at this moment
|
||
if(((mask & MASK_RXFLAG) == MASK_RXFLAG) && (eventValue > 0)){
|
||
sendEvent = true;
|
||
}
|
||
break;*/
|
||
case MASK_TXEMPTY:
|
||
if(((mask & MASK_TXEMPTY) == MASK_TXEMPTY) && (eventValue == 0) && interruptTxChanged){
|
||
sendEvent = true;
|
||
}
|
||
break;
|
||
}
|
||
if(sendEvent){
|
||
eventListener.serialEvent(new SerialPortEvent(portName, eventType, eventValue));
|
||
}
|
||
}
|
||
}
|
||
//Need to sleep some time
|
||
try {
|
||
Thread.sleep(0, 100);
|
||
}
|
||
catch (Exception ex) {
|
||
//Do nothing
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|