diff --git a/app/src/cc/arduino/packages/discoverers/SerialDiscovery.java b/app/src/cc/arduino/packages/discoverers/SerialDiscovery.java index 936588969..a5f6d4f92 100644 --- a/app/src/cc/arduino/packages/discoverers/SerialDiscovery.java +++ b/app/src/cc/arduino/packages/discoverers/SerialDiscovery.java @@ -29,16 +29,16 @@ package cc.arduino.packages.discoverers; -import cc.arduino.packages.BoardPort; -import cc.arduino.packages.Discovery; -import jssc.SerialPortList; -import processing.app.Base; -import processing.app.Platform; -import processing.app.helpers.PreferencesMap; - import java.util.ArrayList; import java.util.List; +import processing.app.Base; +import processing.app.Platform; +import processing.app.Serial; +import processing.app.helpers.PreferencesMap; +import cc.arduino.packages.BoardPort; +import cc.arduino.packages.Discovery; + public class SerialDiscovery implements Discovery { @Override @@ -48,7 +48,7 @@ public class SerialDiscovery implements Discovery { List res = new ArrayList(); - String[] ports = SerialPortList.getPortNames(); + List ports = Serial.list(); for (String port : ports) { String boardName = os.resolveDeviceAttachedTo(port, Base.packages, devicesListOutput); diff --git a/app/src/processing/app/Serial.java b/app/src/processing/app/Serial.java index d8e6eef0d..a5d826896 100644 --- a/app/src/processing/app/Serial.java +++ b/app/src/processing/app/Serial.java @@ -24,14 +24,17 @@ package processing.app; -import jssc.*; -import processing.app.debug.MessageConsumer; +import static processing.app.I18n._; import java.io.IOException; import java.util.Arrays; import java.util.List; -import static processing.app.I18n._; +import jssc.SerialPort; +import jssc.SerialPortEvent; +import jssc.SerialPortEventListener; +import jssc.SerialPortException; +import processing.app.debug.MessageConsumer; public class Serial implements SerialPortEventListener { diff --git a/app/src/processing/app/SerialPortList.java b/app/src/processing/app/SerialPortList.java new file mode 100644 index 000000000..57f833cfa --- /dev/null +++ b/app/src/processing/app/SerialPortList.java @@ -0,0 +1,355 @@ +/* jSSC (Java Simple Serial Connector) - serial port communication library. + * (C) Alexey Sokolov (scream3r), 2010-2014. + * + * Patched for Arduino by Cristian Maglie. + * + * 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 processing.app; + +import java.io.File; +import java.util.Comparator; +import java.util.TreeSet; +import java.util.regex.Pattern; + +import jssc.SerialNativeInterface; + +/** + * + * @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|cu)\\..*"); + 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; + // For linux ttyS0..31 serial ports check existence by opening each of them + if (fileName.startsWith("ttyS")) { + 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; + } +}