1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 package net.sf.atmodem4j.spsw;
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 import java.io.File;
56 import java.io.IOException;
57 import java.util.Collections;
58 import java.util.Comparator;
59 import java.util.Set;
60 import java.util.TreeSet;
61 import java.util.logging.Level;
62 import java.util.logging.Logger;
63 import java.util.regex.Pattern;
64
65
66
67
68
69 public class SerialPortList {
70
71 private final static Logger LOG = Logger.getLogger("net.sf.atmodem4j.spsw");
72
73 private static final Pattern PORTNAMES_REGEXP;
74 private static final String PORTNAMES_PATH;
75
76 static {
77 switch (AbstractSerialPortSocket.getOsName()) {
78 case "linux": {
79 PORTNAMES_REGEXP = Pattern.compile("(ttyS|ttyUSB|ttyACM|ttyAMA|rfcomm|ttyO)[0-9]{1,3}");
80 PORTNAMES_PATH = "/dev/";
81 break;
82 }
83 case "SunOS": {
84 PORTNAMES_REGEXP = Pattern.compile("[0-9]*|[a-z]*");
85 PORTNAMES_PATH = "/dev/term/";
86 break;
87 }
88 case "Mac OS X":
89 case "Darwin": {
90 PORTNAMES_REGEXP = Pattern.compile("tty.(serial|usbserial|usbmodem).*");
91 PORTNAMES_PATH = "/dev/";
92 break;
93 }
94 case "windows": {
95 PORTNAMES_REGEXP = Pattern.compile("");
96 PORTNAMES_PATH = "";
97 break;
98 }
99 default: {
100 LOG.log(Level.SEVERE, "Unknown OS, os.name: {0} mapped to: {1}", new Object[]{System.getProperty("os.name"), AbstractSerialPortSocket.getOsName()});
101 PORTNAMES_REGEXP = null;
102 PORTNAMES_PATH = null;
103 break;
104 }
105 }
106 }
107
108
109 private static final Comparator<String> PORTNAMES_COMPARATOR = new Comparator<String>() {
110
111 @Override
112 public int compare(String valueA, String valueB) {
113
114 if (valueA.equalsIgnoreCase(valueB)) {
115 return valueA.compareTo(valueB);
116 }
117
118 int minLength = Math.min(valueA.length(), valueB.length());
119
120 int shiftA = 0;
121 int shiftB = 0;
122
123 for (int i = 0; i < minLength; i++) {
124 char charA = valueA.charAt(i - shiftA);
125 char charB = valueB.charAt(i - shiftB);
126 if (charA != charB) {
127 if (Character.isDigit(charA) && Character.isDigit(charB)) {
128 int[] resultsA = getNumberAndLastIndex(valueA, i - shiftA);
129 int[] resultsB = getNumberAndLastIndex(valueB, i - shiftB);
130
131 if (resultsA[0] != resultsB[0]) {
132 return resultsA[0] - resultsB[0];
133 }
134
135 if (valueA.length() < valueB.length()) {
136 i = resultsA[1];
137 shiftB = resultsA[1] - resultsB[1];
138 } else {
139 i = resultsB[1];
140 shiftA = resultsB[1] - resultsA[1];
141 }
142 } else {
143 if (Character.toLowerCase(charA) - Character.toLowerCase(charB) != 0) {
144 return Character.toLowerCase(charA) - Character.toLowerCase(charB);
145 }
146 }
147 }
148 }
149 return valueA.compareToIgnoreCase(valueB);
150 }
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170 private int[] getNumberAndLastIndex(String str, int startIndex) {
171 String numberValue = "";
172 int[] returnValues = {-1, startIndex};
173 for (int i = startIndex; i < str.length(); i++) {
174 returnValues[1] = i;
175 char c = str.charAt(i);
176 if (Character.isDigit(c)) {
177 numberValue += c;
178 } else {
179 break;
180 }
181 }
182 try {
183 returnValues[0] = Integer.valueOf(numberValue);
184 } catch (Exception ex) {
185
186 }
187 return returnValues;
188 }
189 };
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212 public static Set<String> getPortNames(boolean hideBusyPorts) {
213 return getPortNames(PORTNAMES_PATH, PORTNAMES_REGEXP, PORTNAMES_COMPARATOR, hideBusyPorts);
214 }
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229 public static Set<String> getPortNames(String searchPath, boolean hideBusyPorts) {
230 return getPortNames(searchPath, PORTNAMES_REGEXP, PORTNAMES_COMPARATOR, hideBusyPorts);
231 }
232
233
234
235
236
237
238
239
240
241
242 public static Set<String> getPortNames(Pattern pattern, boolean hideBusyPorts) {
243 return getPortNames(PORTNAMES_PATH, pattern, PORTNAMES_COMPARATOR, hideBusyPorts);
244 }
245
246
247
248
249
250
251
252
253
254
255 public static Set<String> getPortNames(Comparator<String> comparator, boolean hideBusyPorts) {
256 return getPortNames(PORTNAMES_PATH, PORTNAMES_REGEXP, comparator, hideBusyPorts);
257 }
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274 public static Set<String> getPortNames(String searchPath, Pattern pattern, boolean hideBusyPorts) {
275 return getPortNames(searchPath, pattern, PORTNAMES_COMPARATOR, hideBusyPorts);
276 }
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293 public static Set<String> getPortNames(String searchPath, Comparator<String> comparator, boolean hideBusyPorts) {
294 return getPortNames(searchPath, PORTNAMES_REGEXP, comparator, hideBusyPorts);
295 }
296
297
298
299
300
301
302
303
304
305
306
307
308 public static Set<String> getPortNames(Pattern pattern, Comparator<String> comparator, boolean hideBusyPorts) {
309 return getPortNames(PORTNAMES_PATH, pattern, comparator, hideBusyPorts);
310 }
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329 public static Set<String> getPortNames(String searchPath, Pattern pattern, Comparator<String> comparator, boolean hideBusyPorts) {
330 if (searchPath == null || pattern == null || comparator == null) {
331 return Collections.emptySet();
332 }
333 switch (AbstractSerialPortSocket.getOsName()) {
334 case "windows":
335 if (!AbstractSerialPortSocket.isLibLoaded()) {
336
337 AbstractSerialPortSocket.loadNativeLib();
338 }
339 return getWindowsPortNames(pattern, comparator, hideBusyPorts);
340 default:
341 return getUnixBasedPortNames(searchPath, pattern, comparator, hideBusyPorts);
342 }
343 }
344
345
346
347
348
349
350 private static Set<String> getWindowsPortNames(Pattern pattern, Comparator<String> comparator, boolean hideBusyPorts) {
351 try {
352 String[] portNames = getWindowsBasedPortNames(hideBusyPorts);
353 if (portNames == null) {
354 return Collections.emptySet();
355 }
356 TreeSet<String> ports = new TreeSet<>(comparator);
357 for (String portName : portNames) {
358 if (pattern.matcher(portName).find()) {
359 ports.add(portName);
360 }
361 }
362 return ports;
363 } catch (IOException ex) {
364 throw new RuntimeException(ex);
365 }
366 }
367
368
369
370
371
372
373 private static native String[] getWindowsBasedPortNames(boolean hideBusyPorts) throws IOException;
374
375
376
377
378 private static Set<String> getUnixBasedPortNames(String searchPath, Pattern pattern, Comparator<String> comparator, boolean hideBusyPorts) {
379 searchPath = (searchPath.equals("") ? searchPath : (searchPath.endsWith("/") ? searchPath : searchPath + "/"));
380 File dir = new File(searchPath);
381 if (dir.exists() && dir.isDirectory()) {
382 File[] files = dir.listFiles();
383 if (files.length > 0) {
384 TreeSet<String> portsTree = new TreeSet<>(comparator);
385 for (File file : files) {
386 String fileName = file.getName();
387 if (!file.isDirectory() && !file.isFile() && pattern.matcher(fileName).find()) {
388 String portName = searchPath + fileName;
389 if (hideBusyPorts) {
390 try (SerialPortSocket sp = SerialPortSocket.FACTORY.createSerialPortSocket(portName)) {
391 sp.openAsIs();
392 portsTree.add(portName);
393 } catch (IOException ex) {
394 LOG.log(Level.FINEST, "find busy ports: "+ portName, ex);
395 }
396 } else {
397 portsTree.add(portName);
398 }
399 }
400 }
401 return portsTree;
402 }
403 }
404 return Collections.emptySet();
405 }
406 }