OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/extensions/api/serial/serial_port_enumerator.h" | |
6 | |
7 #include "base/file_util.h" | |
8 #include "base/files/file_enumerator.h" | |
9 #include "base/files/file_path.h" | |
10 #include "base/strings/string_util.h" | |
11 #include "content/public/browser/browser_thread.h" | |
12 | |
13 using content::BrowserThread; | |
14 | |
15 namespace extensions { | |
16 | |
17 // static | |
18 SerialPortEnumerator::StringSet SerialPortEnumerator::GenerateValidPatterns() { | |
19 // TODO(miket): the set of patterns should be larger. See the rxtx project. | |
20 // | |
21 // TODO(miket): The list of patterns tested at runtime should also be | |
22 // OS-dependent. | |
23 const char* VALID_PATTERNS[] = { | |
24 "/dev/*Bluetooth*", | |
25 "/dev/*Modem*", | |
26 "/dev/*bluetooth*", | |
27 "/dev/*modem*", | |
28 "/dev/*serial*", | |
29 "/dev/ttyACM*", | |
30 "/dev/ttyS*", | |
31 "/dev/ttyUSB*", | |
32 "/dev/tty.SLAB_*", | |
33 "/dev/cu.SLAB_*", | |
34 }; | |
35 | |
36 StringSet valid_patterns; | |
37 for (size_t i = 0; i < arraysize(VALID_PATTERNS); ++i) | |
38 valid_patterns.insert(VALID_PATTERNS[i]); | |
39 | |
40 return valid_patterns; | |
41 } | |
42 | |
43 // static | |
44 // | |
45 // TODO(miket): Investigate udev. Search for equivalent solutions on OSX. | |
46 // Continue to examine rxtx code. | |
47 // | |
48 // On a fairly ordinary Linux machine, ls -l /dev | wc -l returned about 200 | |
49 // items. So we're doing about N(VALID_PATTERNS) * 200 = 1,600 MatchPattern | |
50 // calls to find maybe a dozen serial ports in a small number of milliseconds | |
51 // (a single trial of SerialPortEnumeratorTest.ValidPortNames took 6ms to run). | |
52 // It's not cheap, but then again, we don't expect users of this API to be | |
53 // enumerating too often (at worst on every click of a UI element that displays | |
54 // the generated list). | |
55 // | |
56 // An upside-down approach would instead take each pattern and turn it into a | |
57 // string generator (something like /dev/ttyS[0-9]{0,3}) and then expanding | |
58 // that into a series of possible paths, perhaps early-outing if we knew that | |
59 // port patterns were contiguous (e.g., /dev/ttyS1 can't exist if /dev/ttyS0 | |
60 // doesn't exist). | |
61 // | |
62 // Caching seems undesirable. Many devices can be dynamically added to and | |
63 // removed from the system, so we really do want to regenerate the set each | |
64 // time. | |
65 // | |
66 // TODO(miket): this might be refactorable into serial_connection.cc, if | |
67 // Windows serial-port enumeration also entails looking through a directory. | |
68 SerialPortEnumerator::StringSet | |
69 SerialPortEnumerator::GenerateValidSerialPortNames() { | |
70 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
71 const base::FilePath kDevRoot("/dev"); | |
72 const int kFilesAndSymLinks = | |
73 base::FileEnumerator::FILES | | |
74 base::FileEnumerator::SHOW_SYM_LINKS; | |
75 | |
76 StringSet valid_patterns = GenerateValidPatterns(); | |
77 StringSet name_set; | |
78 base::FileEnumerator enumerator(kDevRoot, false, kFilesAndSymLinks); | |
79 do { | |
80 const base::FilePath next_device_path(enumerator.Next()); | |
81 const std::string next_device = next_device_path.value(); | |
82 if (next_device.empty()) | |
83 break; | |
84 | |
85 StringSet::const_iterator i = valid_patterns.begin(); | |
86 for (; i != valid_patterns.end(); ++i) { | |
87 if (MatchPattern(next_device, *i)) { | |
88 name_set.insert(next_device); | |
89 break; | |
90 } | |
91 } | |
92 } while (true); | |
93 | |
94 return name_set; | |
95 } | |
96 | |
97 } // namespace extensions | |
OLD | NEW |