list_ports_linux.cc
Go to the documentation of this file.
1 #if defined(__linux__)
2 
3 /*
4  * Copyright (c) 2014 Craig Lilley <cralilley@gmail.com>
5  * This software is made available under the terms of the MIT licence.
6  * A copy of the licence can be obtained from:
7  * http://opensource.org/licenses/MIT
8  */
9 
10 #include <vector>
11 #include <string>
12 #include <sstream>
13 #include <stdexcept>
14 #include <iostream>
15 #include <fstream>
16 #include <cstdio>
17 #include <cstdarg>
18 #include <cstdlib>
19 
20 #include <glob.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <unistd.h>
24 
25 #include "serial/serial.h"
26 
27 using serial::PortInfo;
28 using std::istringstream;
29 using std::ifstream;
30 using std::getline;
31 using std::vector;
32 using std::string;
33 using std::cout;
34 using std::endl;
35 
36 static vector<string> glob(const vector<string>& patterns);
37 static string basename(const string& path);
38 static string dirname(const string& path);
39 static bool path_exists(const string& path);
40 static string realpath(const string& path);
41 static string usb_sysfs_friendly_name(const string& sys_usb_path);
42 static vector<string> get_sysfs_info(const string& device_path);
43 static string read_line(const string& file);
44 static string usb_sysfs_hw_string(const string& sysfs_path);
45 static string format(const char* format, ...);
46 
47 vector<string>
48 glob(const vector<string>& patterns)
49 {
50  vector<string> paths_found;
51 
52  if(patterns.size() == 0)
53  return paths_found;
54 
55  glob_t glob_results;
56 
57  int glob_retval = glob(patterns[0].c_str(), 0, NULL, &glob_results);
58 
59  vector<string>::const_iterator iter = patterns.begin();
60 
61  while(++iter != patterns.end())
62  {
63  glob_retval = glob(iter->c_str(), GLOB_APPEND, NULL, &glob_results);
64  }
65 
66  for(int path_index = 0; path_index < glob_results.gl_pathc; path_index++)
67  {
68  paths_found.push_back(glob_results.gl_pathv[path_index]);
69  }
70 
71  globfree(&glob_results);
72 
73  return paths_found;
74 }
75 
76 string
77 basename(const string& path)
78 {
79  size_t pos = path.rfind("/");
80 
81  if(pos == std::string::npos)
82  return path;
83 
84  return string(path, pos+1, string::npos);
85 }
86 
87 string
88 dirname(const string& path)
89 {
90  size_t pos = path.rfind("/");
91 
92  if(pos == std::string::npos)
93  return path;
94  else if(pos == 0)
95  return "/";
96 
97  return string(path, 0, pos);
98 }
99 
100 bool
101 path_exists(const string& path)
102 {
103  struct stat sb;
104 
105  if( stat(path.c_str(), &sb ) == 0 )
106  return true;
107 
108  return false;
109 }
110 
111 string
112 realpath(const string& path)
113 {
114  char* real_path = realpath(path.c_str(), NULL);
115 
116  string result;
117 
118  if(real_path != NULL)
119  {
120  result = real_path;
121 
122  free(real_path);
123  }
124 
125  return result;
126 }
127 
128 string
129 usb_sysfs_friendly_name(const string& sys_usb_path)
130 {
131  unsigned int device_number = 0;
132 
133  istringstream( read_line(sys_usb_path + "/devnum") ) >> device_number;
134 
135  string manufacturer = read_line( sys_usb_path + "/manufacturer" );
136 
137  string product = read_line( sys_usb_path + "/product" );
138 
139  string serial = read_line( sys_usb_path + "/serial" );
140 
141  if( manufacturer.empty() && product.empty() && serial.empty() )
142  return "";
143 
144  return format("%s %s %s", manufacturer.c_str(), product.c_str(), serial.c_str() );
145 }
146 
147 vector<string>
148 get_sysfs_info(const string& device_path)
149 {
150  string device_name = basename( device_path );
151 
152  string friendly_name;
153 
154  string hardware_id;
155 
156  string sys_device_path = format( "/sys/class/tty/%s/device", device_name.c_str() );
157 
158  if( device_name.compare(0,6,"ttyUSB") == 0 )
159  {
160  sys_device_path = dirname( dirname( realpath( sys_device_path ) ) );
161 
162  if( path_exists( sys_device_path ) )
163  {
164  friendly_name = usb_sysfs_friendly_name( sys_device_path );
165 
166  hardware_id = usb_sysfs_hw_string( sys_device_path );
167  }
168  }
169  else if( device_name.compare(0,6,"ttyACM") == 0 )
170  {
171  sys_device_path = dirname( realpath( sys_device_path ) );
172 
173  if( path_exists( sys_device_path ) )
174  {
175  friendly_name = usb_sysfs_friendly_name( sys_device_path );
176 
177  hardware_id = usb_sysfs_hw_string( sys_device_path );
178  }
179  }
180  else
181  {
182  // Try to read ID string of PCI device
183 
184  string sys_id_path = sys_device_path + "/id";
185 
186  if( path_exists( sys_id_path ) )
187  hardware_id = read_line( sys_id_path );
188  }
189 
190  if( friendly_name.empty() )
191  friendly_name = device_name;
192 
193  if( hardware_id.empty() )
194  hardware_id = "n/a";
195 
196  vector<string> result;
197  result.push_back(friendly_name);
198  result.push_back(hardware_id);
199 
200  return result;
201 }
202 
203 string
204 read_line(const string& file)
205 {
206  ifstream ifs(file.c_str(), ifstream::in);
207 
208  string line;
209 
210  if(ifs)
211  {
212  getline(ifs, line);
213  }
214 
215  return line;
216 }
217 
218 string
219 format(const char* format, ...)
220 {
221  va_list ap;
222 
223  size_t buffer_size_bytes = 256;
224 
225  string result;
226 
227  char* buffer = (char*)malloc(buffer_size_bytes);
228 
229  if( buffer == NULL )
230  return result;
231 
232  bool done = false;
233 
234  unsigned int loop_count = 0;
235 
236  while(!done)
237  {
238  va_start(ap, format);
239 
240  int return_value = vsnprintf(buffer, buffer_size_bytes, format, ap);
241 
242  if( return_value < 0 )
243  {
244  done = true;
245  }
246  else if( return_value >= buffer_size_bytes )
247  {
248  // Realloc and try again.
249 
250  buffer_size_bytes = return_value + 1;
251 
252  char* new_buffer_ptr = (char*)realloc(buffer, buffer_size_bytes);
253 
254  if( new_buffer_ptr == NULL )
255  {
256  done = true;
257  }
258  else
259  {
260  buffer = new_buffer_ptr;
261  }
262  }
263  else
264  {
265  result = buffer;
266  done = true;
267  }
268 
269  va_end(ap);
270 
271  if( ++loop_count > 5 )
272  done = true;
273  }
274 
275  free(buffer);
276 
277  return result;
278 }
279 
280 string
281 usb_sysfs_hw_string(const string& sysfs_path)
282 {
283  string serial_number = read_line( sysfs_path + "/serial" );
284 
285  if( serial_number.length() > 0 )
286  {
287  serial_number = format( "SNR=%s", serial_number.c_str() );
288  }
289 
290  string vid = read_line( sysfs_path + "/idVendor" );
291 
292  string pid = read_line( sysfs_path + "/idProduct" );
293 
294  return format("USB VID:PID=%s:%s %s", vid.c_str(), pid.c_str(), serial_number.c_str() );
295 }
296 
297 vector<PortInfo>
299 {
300  vector<PortInfo> results;
301 
302  vector<string> search_globs;
303  search_globs.push_back("/dev/ttyACM*");
304  search_globs.push_back("/dev/ttyS*");
305  search_globs.push_back("/dev/ttyUSB*");
306  search_globs.push_back("/dev/tty.*");
307  search_globs.push_back("/dev/cu.*");
308  search_globs.push_back("/dev/rfcomm*");
309 
310  vector<string> devices_found = glob( search_globs );
311 
312  vector<string>::iterator iter = devices_found.begin();
313 
314  while( iter != devices_found.end() )
315  {
316  string device = *iter++;
317 
318  vector<string> sysfs_info = get_sysfs_info( device );
319 
320  string friendly_name = sysfs_info[0];
321 
322  string hardware_id = sysfs_info[1];
323 
324  PortInfo device_entry;
325  device_entry.port = device;
326  device_entry.description = friendly_name;
327  device_entry.hardware_id = hardware_id;
328 
329  results.push_back( device_entry );
330 
331  }
332 
333  return results;
334 }
335 
336 #endif // defined(__linux__)
serial
Definition: unix.h:47
serial::list_ports
std::vector< PortInfo > list_ports()
serial::PortInfo
Definition: serial.h:750
serial.h


serial
Author(s): William Woodall , John Harrison
autogenerated on Wed Mar 9 2022 03:10:03