diff --git a/java_console/io/src/com/rusefi/binaryprotocol/BinaryProtocol.java b/java_console/io/src/com/rusefi/binaryprotocol/BinaryProtocol.java index 2ce9df93d3..17c6e60f3b 100644 --- a/java_console/io/src/com/rusefi/binaryprotocol/BinaryProtocol.java +++ b/java_console/io/src/com/rusefi/binaryprotocol/BinaryProtocol.java @@ -63,6 +63,7 @@ public class BinaryProtocol { private final IncomingDataBuffer incomingData; private boolean isBurnPending; + // todo: this ioLock needs better documentation! private final Object ioLock = new Object(); private final Object imageLock = new Object(); private ConfigurationImage controller; @@ -199,6 +200,7 @@ public class BinaryProtocol { dropPending(); stream.write((SWITCH_TO_BINARY_COMMAND + "\n").getBytes()); + // todo: document why is ioLock needed here? synchronized (ioLock) { boolean isTimeout = incomingData.waitForBytes(2, start, "switch to binary"); if (isTimeout) { diff --git a/java_console/jssc/jssc.iml b/java_console/jssc/jssc.iml new file mode 100644 index 0000000000..c90834f2d6 --- /dev/null +++ b/java_console/jssc/jssc.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/java_console/jssc/jssc.jar b/java_console/jssc/jssc.jar new file mode 100644 index 0000000000..fbeb225b4b Binary files /dev/null and b/java_console/jssc/jssc.jar differ diff --git a/java_console/jssc/readme.txt b/java_console/jssc/readme.txt new file mode 100644 index 0000000000..892eed6987 --- /dev/null +++ b/java_console/jssc/readme.txt @@ -0,0 +1 @@ +this is custom build of JSSC with additional logging - it's only useful during debugging. \ No newline at end of file diff --git a/java_console/jssc/src/jssc/SerialNativeInterface.java b/java_console/jssc/src/jssc/SerialNativeInterface.java new file mode 100644 index 0000000000..c5264f5e8a --- /dev/null +++ b/java_console/jssc/src/jssc/SerialNativeInterface.java @@ -0,0 +1,486 @@ +/* jSSC (Java Simple Serial Connector) - serial port communication library. + * © Alexey Sokolov (scream3r), 2010-2014. + * + * 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 . + * + * 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; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.InputStreamReader; + +/** + * + * @author scream3r + */ +public class SerialNativeInterface { + + private static final String libVersion = "2.8"; //jSSC-2.8.0 Release from 24.01.2014 + private static final String libMinorSuffix = "0"; //since 0.9.0 + + public static final int OS_LINUX = 0; + public static final int OS_WINDOWS = 1; + public static final int OS_SOLARIS = 2;//since 0.9.0 + public static final int OS_MAC_OS_X = 3;//since 0.9.0 + + private static int osType = -1; + + /** + * @since 2.3.0 + */ + public static final long ERR_PORT_BUSY = -1; + /** + * @since 2.3.0 + */ + public static final long ERR_PORT_NOT_FOUND = -2; + /** + * @since 2.3.0 + */ + public static final long ERR_PERMISSION_DENIED = -3; + /** + * @since 2.3.0 + */ + public static final long ERR_INCORRECT_SERIAL_PORT = -4; + + /** + * @since 2.6.0 + */ + public static final String PROPERTY_JSSC_NO_TIOCEXCL = "JSSC_NO_TIOCEXCL"; + /** + * @since 2.6.0 + */ + public static final String PROPERTY_JSSC_IGNPAR = "JSSC_IGNPAR"; + /** + * @since 2.6.0 + */ + public static final String PROPERTY_JSSC_PARMRK = "JSSC_PARMRK"; + + static { + String libFolderPath; + String libName; + + String osName = System.getProperty("os.name"); + String architecture = System.getProperty("os.arch"); + String userHome = System.getProperty("user.home"); + String fileSeparator = System.getProperty("file.separator"); + String tmpFolder = System.getProperty("java.io.tmpdir"); + + //since 2.3.0 -> + String libRootFolder = new File(userHome).canWrite() ? userHome : tmpFolder; + //<- since 2.3.0 + + String javaLibPath = System.getProperty("java.library.path");//since 2.1.0 + + if(osName.equals("Linux")){ + osName = "linux"; + osType = OS_LINUX; + } + else if(osName.startsWith("Win")){ + osName = "windows"; + osType = OS_WINDOWS; + }//since 0.9.0 -> + else if(osName.equals("SunOS")){ + osName = "solaris"; + osType = OS_SOLARIS; + } + else if(osName.equals("Mac OS X") || osName.equals("Darwin")){//os.name "Darwin" since 2.6.0 + osName = "mac_os_x"; + osType = OS_MAC_OS_X; + }//<- since 0.9.0 + + if(architecture.equals("i386") || architecture.equals("i686")){ + architecture = "x86"; + } + else if(architecture.equals("amd64") || architecture.equals("universal")){//os.arch "universal" since 2.6.0 + architecture = "x86_64"; + } + else if(architecture.equals("arm")) {//since 2.1.0 + String floatStr = "sf"; + if(javaLibPath.toLowerCase().contains("gnueabihf") || javaLibPath.toLowerCase().contains("armhf")){ + floatStr = "hf"; + } + else { + try { + Process readelfProcess = Runtime.getRuntime().exec("readelf -A /proc/self/exe"); + BufferedReader reader = new BufferedReader(new InputStreamReader(readelfProcess.getInputStream())); + String buffer = ""; + while((buffer = reader.readLine()) != null && !buffer.isEmpty()){ + if(buffer.toLowerCase().contains("Tag_ABI_VFP_args".toLowerCase())){ + floatStr = "hf"; + break; + } + } + reader.close(); + } + catch (Exception ex) { + //Do nothing + } + } + architecture = "arm" + floatStr; + } + + libFolderPath = libRootFolder + fileSeparator + ".jssc" + fileSeparator + osName; + libName = "jSSC-" + libVersion + "_" + architecture; + libName = System.mapLibraryName(libName); + + if(libName.endsWith(".dylib")){//Since 2.1.0 MacOSX 10.8 fix + libName = libName.replace(".dylib", ".jnilib"); + } + + boolean loadLib = false; + + if(isLibFolderExist(libFolderPath)){ + if(isLibFileExist(libFolderPath + fileSeparator + libName)){ + loadLib = true; + } + else { + if(extractLib((libFolderPath + fileSeparator + libName), osName, libName)){ + loadLib = true; + } + } + } + else { + if(new File(libFolderPath).mkdirs()){ + if(extractLib((libFolderPath + fileSeparator + libName), osName, libName)){ + loadLib = true; + } + } + } + + if (loadLib) { + System.load(libFolderPath + fileSeparator + libName); + String versionBase = getLibraryBaseVersion(); + String versionNative = getNativeLibraryVersion(); + if (!versionBase.equals(versionNative)) { + System.err.println("Warning! jSSC Java and Native versions mismatch (Java: " + versionBase + ", Native: " + versionNative + ")"); + } + } + } + + /** + * Is library folder exists + * + * @param libFolderPath + * + * @since 0.8 + */ + private static boolean isLibFolderExist(String libFolderPath) { + boolean returnValue = false; + File folder = new File(libFolderPath); + if(folder.exists() && folder.isDirectory()){ + returnValue = true; + } + return returnValue; + } + + /** + * Is library file exists + * + * @param libFilePath + * + * @since 0.8 + */ + private static boolean isLibFileExist(String libFilePath) { + boolean returnValue = false; + File folder = new File(libFilePath); + if(folder.exists() && folder.isFile()){ + returnValue = true; + } + return returnValue; + } + + /** + * Extract lib to lib folder + * + * @param libFilePath + * @param osName + * @param libName + * + * @since 0.8 + */ + private static boolean extractLib(String libFilePath, String osName, String libName) { + boolean returnValue = false; + File libFile = new File(libFilePath); + InputStream input = null; + FileOutputStream output = null; + input = SerialNativeInterface.class.getResourceAsStream("/libs/" + osName + "/" + libName); + if(input != null){ + int read; + byte[] buffer = new byte[4096]; + try { + output = new FileOutputStream(libFilePath); + while((read = input.read(buffer)) != -1){ + output.write(buffer, 0, read); + } + output.close(); + input.close(); + returnValue = true; + } + catch (Exception ex) { + try { + output.close(); + if(libFile.exists()){ + libFile.delete(); + } + } + catch (Exception ex_out) { + //Do nothing + } + try { + input.close(); + } + catch (Exception ex_in) { + //Do nothing + } + } + } + return returnValue; + } + + /** + * Get OS type (OS_LINUX || OS_WINDOWS || OS_SOLARIS) + * + * @since 0.8 + */ + public static int getOsType() { + return osType; + } + + /** + * Get jSSC version. The version of library is Base Version + Minor Suffix + * + * @since 0.8 + */ + public static String getLibraryVersion() { + return libVersion + "." + libMinorSuffix; + } + + /** + * Get jSSC Base Version + * + * @since 0.9.0 + */ + public static String getLibraryBaseVersion() { + return libVersion; + } + + /** + * Get jSSC minor suffix. For example in version 0.8.1 - 1 is a minor suffix + * + * @since 0.9.0 + */ + public static String getLibraryMinorSuffix() { + return libMinorSuffix; + } + + /** + * Get jSSC native library version + * + * @return native lib version (for jSSC-2.8.0 should be 2.8 for example) + * + * @since 2.8.0 + */ + public static native String getNativeLibraryVersion(); + + /** + * Open port + * + * @param portName name of port for opening + * @param useTIOCEXCL enable/disable using of TIOCEXCL. Take effect only on *nix based systems + * + * @return handle of opened port or -1 if opening of the port was unsuccessful + */ + public native long openPort(String portName, boolean useTIOCEXCL); + + /** + * Setting the parameters of opened port + * + * @param handle handle of opened 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) + * @param flags additional Native settings. Take effect only on *nix based systems + * + * @return If the operation is successfully completed, the method returns true, otherwise false + */ + public native boolean setParams(long handle, int baudRate, int dataBits, int stopBits, int parity, boolean setRTS, boolean setDTR, int flags); + + /** + * Purge of input and output buffer + * + * @param handle handle of opened port + * @param flags flags specifying required actions for purgePort method + * + * @return If the operation is successfully completed, the method returns true, otherwise false + */ + public native boolean purgePort(long handle, int flags); + + /** + * Close port + * + * @param handle handle of opened port + * + * @return If the operation is successfully completed, the method returns true, otherwise false + */ + public native boolean closePort(long handle); + + /** + * Set events mask + * + * @param handle handle of opened port + * @param mask events mask + * + * @return If the operation is successfully completed, the method returns true, otherwise false + */ + public native boolean setEventsMask(long handle, int mask); + + /** + * Get events mask + * + * @param handle handle of opened port + * + * @return Method returns event mask as a variable of int type + */ + public native int getEventsMask(long handle); + + /** + * Wait events + * + * @param handle handle of opened port + * + * @return Method returns two-dimensional array containing event types and their values + * (events[i][0] - event type, events[i][1] - event value). + */ + public native int[][] waitEvents(long handle); + + /** + * Change RTS line state + * + * @param handle handle of opened port + * @param value true - ON, false - OFF + * + * @return If the operation is successfully completed, the method returns true, otherwise false + */ + public native boolean setRTS(long handle, boolean value); + + /** + * Change DTR line state + * + * @param handle handle of opened port + * @param value true - ON, false - OFF + * + * @return If the operation is successfully completed, the method returns true, otherwise false + */ + public native boolean setDTR(long handle, boolean value); + + /** + * Read data from port + * + * @param handle handle of opened port + * @param byteCount count of bytes required to read + * + * @return Method returns the array of read bytes + */ + public native byte[] readBytes(long handle, int byteCount); + + /** + * Write data to port + * + * @param handle handle of opened port + * @param buffer array of bytes to write + * + * @return If the operation is successfully completed, the method returns true, otherwise false + */ + public native boolean writeBytes(long handle, byte[] buffer); + + /** + * Get bytes count in buffers of port + * + * @param handle handle of opened port + * + * @return Method returns the array that contains info about bytes count in buffers: + *
element 0 - input buffer
+ *
element 1 - output buffer
+ * + * @since 0.8 + */ + public native int[] getBuffersBytesCount(long handle); + + /** + * Set flow control mode + * + * @param handle handle of opened port + * @param mask mask of flow control mode + * + * @return If the operation is successfully completed, the method returns true, otherwise false + * + * @since 0.8 + */ + public native boolean setFlowControlMode(long handle, int mask); + + /** + * Get flow control mode + * + * @param handle handle of opened port + * + * @return Mask of setted flow control mode + * + * @since 0.8 + */ + public native int getFlowControlMode(long handle); + + /** + * Get serial port names like an array of String + * + * @return unsorted array of String with port names + */ + public native String[] getSerialPortNames(); + + /** + * Getting lines states + * + * @param handle handle of opened port + * + * @return Method returns the array containing information about lines in following order: + *
element 0 - CTS line state
+ *
element 1 - DSR line state
+ *
element 2 - RING line state
+ *
element 3 - RLSD line state
+ */ + public native int[] getLinesStatus(long handle); + + /** + * Send Break singnal for setted duration + * + * @param handle handle of opened port + * @param duration duration of Break signal + * @return If the operation is successfully completed, the method returns true, otherwise false + * + * @since 0.8 + */ + public native boolean sendBreak(long handle, int duration); +} diff --git a/java_console/jssc/src/jssc/SerialPort.java b/java_console/jssc/src/jssc/SerialPort.java new file mode 100644 index 0000000000..7bf43887c6 --- /dev/null +++ b/java_console/jssc/src/jssc/SerialPort.java @@ -0,0 +1,1343 @@ +/* jSSC (Java Simple Serial Connector) - serial port communication library. + * © Alexey Sokolov (scream3r), 2010-2014. + * + * 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 . + * + * 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; + +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Method; +import java.nio.charset.Charset; +import java.util.Date; + +/** + * + * @author scream3r + */ +public class SerialPort { + + private SerialNativeInterface serialInterface; + private SerialPortEventListener eventListener; + private long portHandle; + private String portName; + private boolean portOpened = false; + private boolean maskAssigned = false; + private boolean eventListenerAdded = false; + + //since 2.2.0 -> + private Method methodErrorOccurred = null; + //<- since 2.2.0 + + 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 + + //since 2.6.0 -> + private static final int PARAMS_FLAG_IGNPAR = 1; + private static final int PARAMS_FLAG_PARMRK = 2; + //<- since 2.6.0 + + public SerialPort(String portName) { + log("init " + 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 + *

+ * Note: If port busy TYPE_PORT_BUSY exception will be thrown. + * If port not found TYPE_PORT_NOT_FOUND exception will be thrown. + * + * @return If the operation is successfully completed, the method returns true + * + * @throws SerialPortException + */ + public boolean openPort() throws SerialPortException { + Throwable e = new Throwable(); + e.printStackTrace(); + log("openPort"); + if(portOpened){ + throw new SerialPortException(portName, "openPort()", SerialPortException.TYPE_PORT_ALREADY_OPENED); + } + if(portName != null){ + boolean useTIOCEXCL = (System.getProperty(SerialNativeInterface.PROPERTY_JSSC_NO_TIOCEXCL) == null && + System.getProperty(SerialNativeInterface.PROPERTY_JSSC_NO_TIOCEXCL.toLowerCase()) == null); + portHandle = serialInterface.openPort(portName, useTIOCEXCL);//since 2.3.0 -> (if JSSC_NO_TIOCEXCL defined, exclusive lock for serial port will be disabled) + } + else { + throw new SerialPortException(portName, "openPort()", SerialPortException.TYPE_NULL_NOT_PERMITTED);//since 2.1.0 -> NULL port name fix + } + if(portHandle == SerialNativeInterface.ERR_PORT_BUSY){ + throw new SerialPortException(portName, "openPort()", SerialPortException.TYPE_PORT_BUSY); + } + else if(portHandle == SerialNativeInterface.ERR_PORT_NOT_FOUND){ + throw new SerialPortException(portName, "openPort()", SerialPortException.TYPE_PORT_NOT_FOUND); + } + else if(portHandle == SerialNativeInterface.ERR_PERMISSION_DENIED){ + throw new SerialPortException(portName, "openPort()", SerialPortException.TYPE_PERMISSION_DENIED); + } + else if(portHandle == SerialNativeInterface.ERR_INCORRECT_SERIAL_PORT){ + throw new SerialPortException(portName, "openPort()", SerialPortException.TYPE_INCORRECT_SERIAL_PORT); + } + 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 { + return setParams(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 { + log("setParams " + baudRate + " " + dataBits + " " + stopBits + " " + parity + " " + setRTS + " " + setDTR); + checkPortOpened("setParams()"); + if(stopBits == 1){ + stopBits = 0; + } + else if(stopBits == 3){ + stopBits = 1; + } + int flags = 0; + if(System.getProperty(SerialNativeInterface.PROPERTY_JSSC_IGNPAR) != null || System.getProperty(SerialNativeInterface.PROPERTY_JSSC_IGNPAR.toLowerCase()) != null){ + flags |= PARAMS_FLAG_IGNPAR; + } + if(System.getProperty(SerialNativeInterface.PROPERTY_JSSC_PARMRK) != null || System.getProperty(SerialNativeInterface.PROPERTY_JSSC_PARMRK.toLowerCase()) != null){ + flags |= PARAMS_FLAG_PARMRK; + } + return serialInterface.setParams(portHandle, baudRate, dataBits, stopBits, parity, setRTS, setDTR, flags); + } + + /** + * Purge of input and output buffer. Required flags shall be sent to the input. Variables with prefix + * "PURGE_", for example "PURGE_RXCLEAR". Sent parameter "flags" is additive value, + * so addition of flags is allowed. For example, if input or output buffer shall be purged, + * parameter "PURGE_RXCLEAR | PURGE_TXCLEAR". + *
Note: 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 { + log("purgePort " + flags); + 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 + * "MASK_", shall be used as flags, for example "MASK_RXCHAR". + * 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 - "MASK_RXCHAR | MASK_CTS | MASK_DSR" + * + * @return If the operation is successfully completed, the method returns true, otherwise false + * + * @throws SerialPortException + */ + public boolean setEventsMask(int mask) throws SerialPortException { + Throwable e = new Throwable(); + e.printStackTrace(); + log("setEventsMask " + mask); + 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 { + log("setRTS " + enabled); + 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 { + log("setDTR " + enabled); + 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 String to port + * + * @return If the operation is successfully completed, the method returns true, otherwise false + * + * @throws SerialPortException + * + * @since 2.8.0 + */ + public boolean writeString(String string, String charsetName) throws SerialPortException, UnsupportedEncodingException { + checkPortOpened("writeString()"); + return writeBytes(string.getBytes(charsetName)); + } + + /** + * 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 { + log("readBytes " + byteCount); + 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 0A 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::0A::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; + } + + private void waitBytesWithTimeout(String methodName, int byteCount, int timeout) throws SerialPortException, SerialPortTimeoutException { + checkPortOpened("waitBytesWithTimeout()"); + boolean timeIsOut = true; + long startTime = System.currentTimeMillis(); + while((System.currentTimeMillis() - startTime) < timeout){ + if(getInputBufferBytesCount() >= byteCount){ + timeIsOut = false; + break; + } + try { + Thread.sleep(0, 100);//Need to sleep some time to prevent high CPU loading + } + catch (InterruptedException ex) { + //Do nothing + } + } + if(timeIsOut){ + throw new SerialPortTimeoutException(portName, methodName, timeout); + } + } + + /** + * Read byte array from port + * + * @param byteCount count of bytes for reading + * @param timeout timeout in milliseconds + * + * @return byte array with "byteCount" length + * + * @throws SerialPortException + * @throws SerialPortTimeoutException + * + * @since 2.0 + */ + public byte[] readBytes(int byteCount, int timeout) throws SerialPortException, SerialPortTimeoutException { + log("readBytes " + byteCount + " " + timeout); + checkPortOpened("readBytes()"); + waitBytesWithTimeout("readBytes()", byteCount, timeout); + return readBytes(byteCount); + } + + public static void log(String s) { + System.out.println(new Date() + ": custom JSSC " + s); + } + + /** + * Read string from port + * + * @param byteCount count of bytes for reading + * @param timeout timeout in milliseconds + * + * @return byte array with "byteCount" length converted to String + * + * @throws SerialPortException + * @throws SerialPortTimeoutException + * + * @since 2.0 + */ + public String readString(int byteCount, int timeout) throws SerialPortException, SerialPortTimeoutException { + checkPortOpened("readString()"); + waitBytesWithTimeout("readString()", byteCount, timeout); + return readString(byteCount); + } + + /** + * Read Hex string from port (example: FF 0A FF). Separator by default is a space + * + * @param byteCount count of bytes for reading + * @param timeout timeout in milliseconds + * + * @return byte array with "byteCount" length converted to Hexadecimal String + * + * @throws SerialPortException + * @throws SerialPortTimeoutException + * + * @since 2.0 + */ + public String readHexString(int byteCount, int timeout) throws SerialPortException, SerialPortTimeoutException { + checkPortOpened("readHexString()"); + waitBytesWithTimeout("readHexString()", byteCount, timeout); + return readHexString(byteCount); + } + + /** + * Read Hex string from port with setted separator (example if separator is "::": FF::0A::FF) + * + * @param byteCount count of bytes for reading + * @param timeout timeout in milliseconds + * + * @return byte array with "byteCount" length converted to Hexadecimal String + * + * @throws SerialPortException + * @throws SerialPortTimeoutException + * + * @since 2.0 + */ + public String readHexString(int byteCount, String separator, int timeout) throws SerialPortException, SerialPortTimeoutException { + checkPortOpened("readHexString()"); + waitBytesWithTimeout("readHexString()", byteCount, timeout); + return readHexString(byteCount, separator); + } + + /** + * Read Hex String array from port + * + * @param byteCount count of bytes for reading + * @param timeout timeout in milliseconds + * + * @return String array with "byteCount" length and Hexadecimal String values + * + * @throws SerialPortException + * @throws SerialPortTimeoutException + * + * @since 2.0 + */ + public String[] readHexStringArray(int byteCount, int timeout) throws SerialPortException, SerialPortTimeoutException { + checkPortOpened("readHexStringArray()"); + waitBytesWithTimeout("readHexStringArray()", byteCount, timeout); + return readHexStringArray(byteCount); + } + + /** + * Read int array from port + * + * @param byteCount count of bytes for reading + * @param timeout timeout in milliseconds + * + * @return int array with values in range from 0 to 255 + * + * @throws SerialPortException + * @throws SerialPortTimeoutException + * + * @since 2.0 + */ + public int[] readIntArray(int byteCount, int timeout) throws SerialPortException, SerialPortTimeoutException { + checkPortOpened("readIntArray()"); + waitBytesWithTimeout("readIntArray()", byteCount, timeout); + return readIntArray(byteCount); + } + + /** + * Read all available bytes from port like a byte array + * + * @return If input buffer is empty null 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 null 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 null 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 null 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 null 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 null 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("readIntArray()"); + 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()"); + int result = serialInterface.getBuffersBytesCount(portHandle)[0]; + log("getInputBufferBytesCount=" + result); + return result; + } + + /** + * 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()"); + int result = serialInterface.getBuffersBytesCount(portHandle)[1]; + log("getInputBufferBytesCount=" + result); + return result; + } + + /** + * Set flow control mode. For required mode use variables with prefix "FLOWCONTROL_". + * 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 { + log("setFlowControlMode " + mask); + 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 { + log("sendBreak"); + 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: + *
element 0 - CTS line state
+ *
element 1 - DSR line state
+ *
element 2 - RING line state
+ *
element 3 - RLSD line state
+ * + * @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 { + log("isCTS"); + 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 { + log("isDSR"); + 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 { + log("isRING"); + 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 { + log("isRLSD"); + checkPortOpened("isRLSD()"); + if(serialInterface.getLinesStatus(portHandle)[3] == 1){ + return true; + } + else { + return false; + } + } + + /** + * Add event listener. Object of "SerialPortEventListener" 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 "MASK_RXCHAR" state if it was not set beforehand + * + * @throws SerialPortException + */ + public void addEventListener(SerialPortEventListener listener) throws SerialPortException { + log("addEventListener " + listener); + addEventListener(listener, MASK_RXCHAR, false); + } + + /** + * Add event listener. Object of "SerialPortEventListener" 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 "MASK_" for example "MASK_RXCHAR" + * + * @see #setEventsMask(int) setEventsMask(int mask) + * + * @throws SerialPortException + */ + public void addEventListener(SerialPortEventListener listener, int mask) throws SerialPortException { + log("addEventListener " + listener + " " + mask); + addEventListener(listener, mask, true); + } + + /** + * Internal method. Add event listener. Object of "SerialPortEventListener" 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 "MASK_" for example "MASK_RXCHAR". If + * overwriteMask == true and mask has been already assigned it value will be rewrited by mask + * value, if overwriteMask == false and mask has been already assigned the new mask value will be ignored, + * if there is no assigned mask to this serial port the mask value will be used for setting it up in spite of + * overwriteMask value + * + * @see #setEventsMask(int) setEventsMask(int mask) + * + * @throws SerialPortException + */ + private void addEventListener(SerialPortEventListener listener, int mask, boolean overwriteMask) throws SerialPortException { + checkPortOpened("addEventListener()"); + if(!eventListenerAdded){ + if((maskAssigned && overwriteMask) || !maskAssigned) { + setEventsMask(mask); + } + eventListener = listener; + eventThread = getNewEventThread(); + eventThread.setName("EventThread " + portName); + //since 2.2.0 -> + try { + Method method = eventListener.getClass().getMethod("errorOccurred", new Class[]{SerialPortException.class}); + method.setAccessible(true); + methodErrorOccurred = method; + } + catch (SecurityException ex) { + //Do nothing + } + catch (NoSuchMethodException ex) { + //Do nothing + } + //<- since 2.2.0 + 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); + } + } + } + methodErrorOccurred = null; + 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])); + //FIXME + /*if(methodErrorOccurred != null){ + try { + methodErrorOccurred.invoke(eventListener, new Object[]{new SerialPortException("port", "method", "exception")}); + } + catch (Exception ex) { + System.out.println(ex); + } + }*/ + } + } + } + } + + 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 + } + } + } + } +} diff --git a/java_console/jssc/src/jssc/SerialPortEvent.java b/java_console/jssc/src/jssc/SerialPortEvent.java new file mode 100644 index 0000000000..dd167ded22 --- /dev/null +++ b/java_console/jssc/src/jssc/SerialPortEvent.java @@ -0,0 +1,193 @@ +/* jSSC (Java Simple Serial Connector) - serial port communication library. + * © Alexey Sokolov (scream3r), 2010-2014. + * + * 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 . + * + * 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 SerialPortEvent { + + private String portName; + private int eventType; + private int eventValue; + + public static final int RXCHAR = 1; + public static final int RXFLAG = 2; + public static final int TXEMPTY = 4; + public static final int CTS = 8; + public static final int DSR = 16; + public static final int RLSD = 32; + public static final int BREAK = 64; + public static final int ERR = 128; + public static final int RING = 256; + + public SerialPortEvent(String portName, int eventType, int eventValue){ + SerialPort.log("SerialPortEvent " + portName + " " + eventType + " " + eventValue); + this.portName = portName; + this.eventType = eventType; + this.eventValue = eventValue; + } + + /** + * Getting port name which sent the event + */ + public String getPortName() { + return portName; + } + + /** + * Getting event type + */ + public int getEventType() { + return eventType; + } + + /** + * Getting event value + *

+ *
Event values depending on their types:
+ *
RXCHAR - bytes count in input buffer
+ *
RXFLAG - bytes count in input buffer (Not supported in Linux)
+ *
TXEMPTY - bytes count in output buffer
+ *
CTS - state of CTS line (0 - OFF, 1 - ON)
+ *
DSR - state of DSR line (0 - OFF, 1 - ON)
+ *
RLSD - state of RLSD line (0 - OFF, 1 - ON)
+ *
BREAK - 0
+ *
RING - state of RING line (0 - OFF, 1 - ON)
+ *
ERR - mask of errors
+ */ + public int getEventValue() { + return eventValue; + } + + /** + * Method returns true if event of type "RXCHAR" is received and otherwise false + */ + public boolean isRXCHAR() { + if(eventType == RXCHAR){ + return true; + } + else { + return false; + } + } + + /** + * Method returns true if event of type "RXFLAG" is received and otherwise false + */ + public boolean isRXFLAG() { + if(eventType == RXFLAG){ + return true; + } + else { + return false; + } + } + + /** + * Method returns true if event of type "TXEMPTY" is received and otherwise false + */ + public boolean isTXEMPTY() { + if(eventType == TXEMPTY){ + return true; + } + else { + return false; + } + } + + /** + * Method returns true if event of type "CTS" is received and otherwise false + */ + public boolean isCTS() { + if(eventType == CTS){ + return true; + } + else { + return false; + } + } + + /** + * Method returns true if event of type "DSR" is received and otherwise false + */ + public boolean isDSR() { + if(eventType == DSR){ + return true; + } + else { + return false; + } + } + + /** + * Method returns true if event of type "RLSD" is received and otherwise false + */ + public boolean isRLSD() { + if(eventType == RLSD){ + return true; + } + else { + return false; + } + } + + /** + * Method returns true if event of type "BREAK" is received and otherwise false + */ + public boolean isBREAK() { + if(eventType == BREAK){ + return true; + } + else { + return false; + } + } + + /** + * Method returns true if event of type "ERR" is received and otherwise false + */ + public boolean isERR() { + if(eventType == ERR){ + return true; + } + else { + return false; + } + } + + /** + * Method returns true if event of type "RING" is received and otherwise false + */ + public boolean isRING() { + if(eventType == RING){ + return true; + } + else { + return false; + } + } +} diff --git a/java_console/jssc/src/jssc/SerialPortEventListener.java b/java_console/jssc/src/jssc/SerialPortEventListener.java new file mode 100644 index 0000000000..9a2441aa87 --- /dev/null +++ b/java_console/jssc/src/jssc/SerialPortEventListener.java @@ -0,0 +1,34 @@ +/* jSSC (Java Simple Serial Connector) - serial port communication library. + * © Alexey Sokolov (scream3r), 2010-2014. + * + * 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 . + * + * 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 interface SerialPortEventListener { + + public abstract void serialEvent(SerialPortEvent serialPortEvent); +} diff --git a/java_console/jssc/src/jssc/SerialPortException.java b/java_console/jssc/src/jssc/SerialPortException.java new file mode 100644 index 0000000000..18aca2f937 --- /dev/null +++ b/java_console/jssc/src/jssc/SerialPortException.java @@ -0,0 +1,95 @@ +/* jSSC (Java Simple Serial Connector) - serial port communication library. + * © Alexey Sokolov (scream3r), 2010-2014. + * + * 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 . + * + * 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 SerialPortException extends Exception { + + final public static String TYPE_PORT_ALREADY_OPENED = "Port already opened"; + final public static String TYPE_PORT_NOT_OPENED = "Port not opened"; + final public static String TYPE_CANT_SET_MASK = "Can't set mask"; + final public static String TYPE_LISTENER_ALREADY_ADDED = "Event listener already added"; + final public static String TYPE_LISTENER_THREAD_INTERRUPTED = "Event listener thread interrupted"; + final public static String TYPE_CANT_REMOVE_LISTENER = "Can't remove event listener, because listener not added"; + /** + * @since 0.8 + */ + final public static String TYPE_PARAMETER_IS_NOT_CORRECT = "Parameter is not correct"; + /** + * @since 0.8 + */ + final public static String TYPE_NULL_NOT_PERMITTED = "Null not permitted"; + /** + * @since 0.9.0 + */ + final public static String TYPE_PORT_BUSY = "Port busy"; + /** + * @since 0.9.0 + */ + final public static String TYPE_PORT_NOT_FOUND = "Port not found"; + /** + * @since 2.2.0 + */ + final public static String TYPE_PERMISSION_DENIED = "Permission denied"; + /** + * @since 2.3.0 + */ + final public static String TYPE_INCORRECT_SERIAL_PORT = "Incorrect serial port"; + + private String portName; + private String methodName; + private String exceptionType; + + public SerialPortException(String portName, String methodName, String exceptionType){ + super("Port name - " + portName + "; Method name - " + methodName + "; Exception type - " + exceptionType + "."); + this.portName = portName; + this.methodName = methodName; + this.exceptionType = exceptionType; + } + + /** + * Getting port name during operation with which the exception was called + */ + public String getPortName(){ + return portName; + } + + /** + * Getting method name during execution of which the exception was called + */ + public String getMethodName(){ + return methodName; + } + + /** + * Getting exception type + */ + public String getExceptionType(){ + return exceptionType; + } +} diff --git a/java_console/jssc/src/jssc/SerialPortList.java b/java_console/jssc/src/jssc/SerialPortList.java new file mode 100644 index 0000000000..5af9a95ea0 --- /dev/null +++ b/java_console/jssc/src/jssc/SerialPortList.java @@ -0,0 +1,348 @@ +/* jSSC (Java Simple Serial Connector) - serial port communication library. + * © Alexey Sokolov (scream3r), 2010-2014. + * + * 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 . + * + * 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; + +import java.io.File; +import java.util.Comparator; +import java.util.TreeSet; +import java.util.regex.Pattern; + +/** + * + * @author scream3r + */ +public class SerialPortList { + + private static SerialNativeInterface serialInterface; + private static final Pattern PORTNAMES_REGEXP; + private static final String PORTNAMES_PATH; + + static { + serialInterface = new SerialNativeInterface(); + switch (SerialNativeInterface.getOsType()) { + case SerialNativeInterface.OS_LINUX: { + PORTNAMES_REGEXP = Pattern.compile("(ttyS|ttyUSB|ttyACM|ttyAMA|rfcomm|ttyO)[0-9]{1,3}"); + PORTNAMES_PATH = "/dev/"; + break; + } + case SerialNativeInterface.OS_SOLARIS: { + PORTNAMES_REGEXP = Pattern.compile("[0-9]*|[a-z]*"); + PORTNAMES_PATH = "/dev/term/"; + break; + } + case SerialNativeInterface.OS_MAC_OS_X: { + PORTNAMES_REGEXP = Pattern.compile("tty.(serial|usbserial|usbmodem).*"); + PORTNAMES_PATH = "/dev/"; + break; + } + case SerialNativeInterface.OS_WINDOWS: { + PORTNAMES_REGEXP = Pattern.compile(""); + PORTNAMES_PATH = ""; + break; + } + default: { + PORTNAMES_REGEXP = null; + PORTNAMES_PATH = null; + break; + } + } + } + + //since 2.1.0 -> Fully rewrited port name comparator + private static final Comparator PORTNAMES_COMPARATOR = new Comparator() { + + @Override + public int compare(String valueA, String valueB) { + + if(valueA.equalsIgnoreCase(valueB)){ + return valueA.compareTo(valueB); + } + + int minLength = Math.min(valueA.length(), valueB.length()); + + int shiftA = 0; + int shiftB = 0; + + for(int i = 0; i < minLength; i++){ + char charA = valueA.charAt(i - shiftA); + char charB = valueB.charAt(i - shiftB); + if(charA != charB){ + if(Character.isDigit(charA) && Character.isDigit(charB)){ + int[] resultsA = getNumberAndLastIndex(valueA, i - shiftA); + int[] resultsB = getNumberAndLastIndex(valueB, i - shiftB); + + if(resultsA[0] != resultsB[0]){ + return resultsA[0] - resultsB[0]; + } + + if(valueA.length() < valueB.length()){ + i = resultsA[1]; + shiftB = resultsA[1] - resultsB[1]; + } + else { + i = resultsB[1]; + shiftA = resultsB[1] - resultsA[1]; + } + } + else { + if(Character.toLowerCase(charA) - Character.toLowerCase(charB) != 0){ + return Character.toLowerCase(charA) - Character.toLowerCase(charB); + } + } + } + } + return valueA.compareToIgnoreCase(valueB); + } + + /** + * Evaluate port index/number from startIndex to the number end. For example: + * for port name serial-123-FF you should invoke this method with startIndex = 7 + * + * @return If port index/number correctly evaluated it value will be returned
+ * returnArray[0] = index/number
+ * returnArray[1] = stopIndex
+ * + * If incorrect:
+ * returnArray[0] = -1
+ * returnArray[1] = startIndex
+ * + * For this name serial-123-FF result is: + * returnArray[0] = 123
+ * returnArray[1] = 10
+ */ + private int[] getNumberAndLastIndex(String str, int startIndex) { + String numberValue = ""; + int[] returnValues = {-1, startIndex}; + for(int i = startIndex; i < str.length(); i++){ + returnValues[1] = i; + char c = str.charAt(i); + if(Character.isDigit(c)){ + numberValue += c; + } + else { + break; + } + } + try { + returnValues[0] = Integer.valueOf(numberValue); + } + catch (Exception ex) { + //Do nothing + } + return returnValues; + } + }; + //<-since 2.1.0 + + /** + * Get sorted array of serial ports in the system using default settings:
+ * + * Search path
+ * Windows - ""(always ignored)
+ * Linux - "/dev/"
+ * Solaris - "/dev/term/"
+ * MacOSX - "/dev/"
+ * + * RegExp
+ * Windows - ""
+ * Linux - "(ttyS|ttyUSB|ttyACM|ttyAMA|rfcomm)[0-9]{1,3}"
+ * Solaris - "[0-9]*|[a-z]*"
+ * MacOSX - "tty.(serial|usbserial|usbmodem).*"
+ * + * @return String array. If there is no ports in the system String[] + * with zero length will be returned (since jSSC-0.8 in previous versions null will be returned) + */ + public static String[] getPortNames() { + return getPortNames(PORTNAMES_PATH, PORTNAMES_REGEXP, PORTNAMES_COMPARATOR); + } + + /** + * Get sorted array of serial ports in the system located on searchPath + * + * @param searchPath Path for searching serial ports (not null)
+ * The default search paths:
+ * Linux, MacOSX: /dev/
+ * Solaris: /dev/term/
+ * Windows: this parameter ingored + * + * @return String array. If there is no ports in the system String[] + * + * @since 2.3.0 + */ + public static String[] getPortNames(String searchPath) { + return getPortNames(searchPath, PORTNAMES_REGEXP, PORTNAMES_COMPARATOR); + } + + /** + * Get sorted array of serial ports in the system matched pattern + * + * @param pattern RegExp pattern for matching port names (not null) + * + * @return String array. If there is no ports in the system String[] + * + * @since 2.3.0 + */ + public static String[] getPortNames(Pattern pattern) { + return getPortNames(PORTNAMES_PATH, pattern, PORTNAMES_COMPARATOR); + } + + /** + * Get sorted array of serial ports in the system matched pattern + * + * @param comparator Comparator for sotring port names (not null) + * + * @return String array. If there is no ports in the system String[] + * + * @since 2.3.0 + */ + public static String[] getPortNames(Comparator comparator) { + return getPortNames(PORTNAMES_PATH, PORTNAMES_REGEXP, comparator); + } + + /** + * Get sorted array of serial ports in the system located on searchPath, matched pattern + * + * @param searchPath Path for searching serial ports (not null)
+ * The default search paths:
+ * Linux, MacOSX: /dev/
+ * Solaris: /dev/term/
+ * Windows: this parameter ingored + * @param pattern RegExp pattern for matching port names (not null) + * + * @return String array. If there is no ports in the system String[] + * + * @since 2.3.0 + */ + public static String[] getPortNames(String searchPath, Pattern pattern) { + return getPortNames(searchPath, pattern, PORTNAMES_COMPARATOR); + } + + /** + * Get sorted array of serial ports in the system located on searchPath and sorted by comparator + * + * @param searchPath Path for searching serial ports (not null)
+ * The default search paths:
+ * Linux, MacOSX: /dev/
+ * Solaris: /dev/term/
+ * Windows: this parameter ingored + * @param comparator Comparator for sotring port names (not null) + * + * @return String array. If there is no ports in the system String[] + * + * @since 2.3.0 + */ + public static String[] getPortNames(String searchPath, Comparator comparator) { + return getPortNames(searchPath, PORTNAMES_REGEXP, comparator); + } + + /** + * Get sorted array of serial ports in the system matched pattern and sorted by comparator + * + * @param pattern RegExp pattern for matching port names (not null) + * @param comparator Comparator for sotring port names (not null) + * + * @return String array. If there is no ports in the system String[] + * + * @since 2.3.0 + */ + public static String[] getPortNames(Pattern pattern, Comparator comparator) { + return getPortNames(PORTNAMES_PATH, pattern, comparator); + } + + /** + * Get sorted array of serial ports in the system located on searchPath, matched pattern and sorted by comparator + * + * @param searchPath Path for searching serial ports (not null)
+ * The default search paths:
+ * Linux, MacOSX: /dev/
+ * Solaris: /dev/term/
+ * Windows: this parameter ingored + * @param pattern RegExp pattern for matching port names (not null) + * @param comparator Comparator for sotring port names (not null) + * + * @return String array. If there is no ports in the system String[] + * + * @since 2.3.0 + */ + public static String[] getPortNames(String searchPath, Pattern pattern, Comparator comparator) { + if(searchPath == null || pattern == null || comparator == null){ + return new String[]{}; + } + if(SerialNativeInterface.getOsType() == SerialNativeInterface.OS_WINDOWS){ + return getWindowsPortNames(pattern, comparator); + } + return getUnixBasedPortNames(searchPath, pattern, comparator); + } + + /** + * Get serial port names in Windows + * + * @since 2.3.0 + */ + private static String[] getWindowsPortNames(Pattern pattern, Comparator comparator) { + String[] portNames = serialInterface.getSerialPortNames(); + if(portNames == null){ + return new String[]{}; + } + TreeSet ports = new TreeSet(comparator); + for(String portName : portNames){ + if(pattern.matcher(portName).find()){ + ports.add(portName); + } + } + return ports.toArray(new String[ports.size()]); + } + + /** + * Universal method for getting port names of _nix based systems + */ + private static String[] getUnixBasedPortNames(String searchPath, Pattern pattern, Comparator comparator) { + searchPath = (searchPath.equals("") ? searchPath : (searchPath.endsWith("/") ? searchPath : searchPath + "/")); + String[] returnArray = new String[]{}; + File dir = new File(searchPath); + if(dir.exists() && dir.isDirectory()){ + File[] files = dir.listFiles(); + if(files.length > 0){ + TreeSet portsTree = new TreeSet(comparator); + for(File file : files){ + String fileName = file.getName(); + if(!file.isDirectory() && !file.isFile() && pattern.matcher(fileName).find()){ + String portName = searchPath + fileName; + long portHandle = serialInterface.openPort(portName, false);//Open port without TIOCEXCL + if(portHandle < 0 && portHandle != SerialNativeInterface.ERR_PORT_BUSY){ + continue; + } + else if(portHandle != SerialNativeInterface.ERR_PORT_BUSY) { + serialInterface.closePort(portHandle); + } + portsTree.add(portName); + } + } + returnArray = portsTree.toArray(returnArray); + } + } + return returnArray; + } +} diff --git a/java_console/jssc/src/jssc/SerialPortTimeoutException.java b/java_console/jssc/src/jssc/SerialPortTimeoutException.java new file mode 100644 index 0000000000..802535c3ad --- /dev/null +++ b/java_console/jssc/src/jssc/SerialPortTimeoutException.java @@ -0,0 +1,64 @@ +/* jSSC (Java Simple Serial Connector) - serial port communication library. + * © Alexey Sokolov (scream3r), 2010-2014. + * + * 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 . + * + * 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 SerialPortTimeoutException extends Exception { + + private String portName; + private String methodName; + private int timeoutValue; + + public SerialPortTimeoutException(String portName, String methodName, int timeoutValue) { + super("Port name - " + portName + "; Method name - " + methodName + "; Serial port operation timeout (" + timeoutValue + " ms)."); + this.portName = portName; + this.methodName = methodName; + this.timeoutValue = timeoutValue; + } + + /** + * Getting port name during operation with which the exception was called + */ + public String getPortName(){ + return portName; + } + + /** + * Getting method name during execution of which the exception was called + */ + public String getMethodName(){ + return methodName; + } + + /** + * Getting timeout value in millisecond + */ + public int getTimeoutValue(){ + return timeoutValue; + } +}