list_ports_linux.cc
Go to the documentation of this file.
00001 #if defined(__linux__)
00002 
00003 /*
00004  * Copyright (c) 2014 Craig Lilley <cralilley@gmail.com>
00005  * This software is made available under the terms of the MIT licence.
00006  * A copy of the licence can be obtained from:
00007  * http://opensource.org/licenses/MIT
00008  */
00009 
00010 #include <vector>
00011 #include <string>
00012 #include <sstream>
00013 #include <stdexcept>
00014 #include <iostream>
00015 #include <fstream>
00016 #include <cstdio>
00017 #include <cstdarg>
00018 #include <cstdlib>
00019 
00020 #include <glob.h>
00021 #include <sys/types.h>
00022 #include <sys/stat.h>
00023 #include <unistd.h>
00024 
00025 #include "serial/serial.h"
00026 
00027 using serial::PortInfo;
00028 using std::istringstream;
00029 using std::ifstream;
00030 using std::getline;
00031 using std::vector;
00032 using std::string;
00033 using std::cout;
00034 using std::endl;
00035 
00036 static vector<string> glob(const vector<string>& patterns);
00037 static string basename(const string& path);
00038 static string dirname(const string& path);
00039 static bool path_exists(const string& path);
00040 static string realpath(const string& path);
00041 static string usb_sysfs_friendly_name(const string& sys_usb_path);
00042 static vector<string> get_sysfs_info(const string& device_path);
00043 static string read_line(const string& file);
00044 static string usb_sysfs_hw_string(const string& sysfs_path);
00045 static string format(const char* format, ...);
00046 
00047 vector<string>
00048 glob(const vector<string>& patterns)
00049 {
00050     vector<string> paths_found;
00051 
00052         if(patterns.size() == 0)
00053             return paths_found;
00054 
00055     glob_t glob_results;
00056 
00057     int glob_retval = glob(patterns[0].c_str(), 0, NULL, &glob_results);
00058 
00059     vector<string>::const_iterator iter = patterns.begin();
00060 
00061     while(++iter != patterns.end())
00062     {
00063         glob_retval = glob(iter->c_str(), GLOB_APPEND, NULL, &glob_results);
00064     }
00065 
00066     for(int path_index = 0; path_index < glob_results.gl_pathc; path_index++)
00067     {
00068         paths_found.push_back(glob_results.gl_pathv[path_index]);
00069     }
00070 
00071     globfree(&glob_results);
00072 
00073     return paths_found;
00074 }
00075 
00076 string
00077 basename(const string& path)
00078 {
00079     size_t pos = path.rfind("/");
00080 
00081     if(pos == std::string::npos)
00082         return path;
00083 
00084     return string(path, pos+1, string::npos);
00085 }
00086 
00087 string
00088 dirname(const string& path)
00089 {
00090     size_t pos = path.rfind("/");
00091 
00092     if(pos == std::string::npos)
00093         return path;
00094     else if(pos == 0)
00095         return "/";
00096 
00097     return string(path, 0, pos);
00098 }
00099 
00100 bool
00101 path_exists(const string& path)
00102 {
00103     struct stat sb;
00104 
00105     if( stat(path.c_str(), &sb ) == 0 )
00106         return true;
00107 
00108     return false;
00109 }
00110 
00111 string
00112 realpath(const string& path)
00113 {
00114     char* real_path = realpath(path.c_str(), NULL);
00115 
00116     string result;
00117 
00118     if(real_path != NULL)
00119     {
00120         result = real_path;
00121 
00122         free(real_path);
00123     }
00124 
00125     return result;
00126 }
00127 
00128 string
00129 usb_sysfs_friendly_name(const string& sys_usb_path)
00130 {
00131     unsigned int device_number = 0;
00132 
00133     istringstream( read_line(sys_usb_path + "/devnum") ) >> device_number;
00134 
00135     string manufacturer = read_line( sys_usb_path + "/manufacturer" );
00136 
00137     string product = read_line( sys_usb_path + "/product" );
00138 
00139     string serial = read_line( sys_usb_path + "/serial" );
00140 
00141     if( manufacturer.empty() && product.empty() && serial.empty() )
00142         return "";
00143 
00144     return format("%s %s %s", manufacturer.c_str(), product.c_str(), serial.c_str() );
00145 }
00146 
00147 vector<string>
00148 get_sysfs_info(const string& device_path)
00149 {
00150     string device_name = basename( device_path );
00151 
00152     string friendly_name;
00153 
00154     string hardware_id;
00155 
00156     string sys_device_path = format( "/sys/class/tty/%s/device", device_name.c_str() );
00157 
00158     if( device_name.compare(0,6,"ttyUSB") == 0 )
00159     {
00160         sys_device_path = dirname( dirname( realpath( sys_device_path ) ) );
00161 
00162         if( path_exists( sys_device_path ) )
00163         {
00164             friendly_name = usb_sysfs_friendly_name( sys_device_path );
00165 
00166             hardware_id = usb_sysfs_hw_string( sys_device_path );
00167         }
00168     }
00169     else if( device_name.compare(0,6,"ttyACM") == 0 )
00170     {
00171         sys_device_path = dirname( realpath( sys_device_path ) );
00172 
00173         if( path_exists( sys_device_path ) )
00174         {
00175             friendly_name = usb_sysfs_friendly_name( sys_device_path );
00176 
00177             hardware_id = usb_sysfs_hw_string( sys_device_path );
00178         }
00179     }
00180     else
00181     {
00182         // Try to read ID string of PCI device
00183 
00184         string sys_id_path = sys_device_path + "/id";
00185 
00186         if( path_exists( sys_id_path ) )
00187             hardware_id = read_line( sys_id_path );
00188     }
00189 
00190     if( friendly_name.empty() )
00191         friendly_name = device_name;
00192 
00193     if( hardware_id.empty() )
00194         hardware_id = "n/a";
00195 
00196     vector<string> result;
00197     result.push_back(friendly_name);
00198     result.push_back(hardware_id);
00199 
00200     return result;
00201 }
00202 
00203 string
00204 read_line(const string& file)
00205 {
00206     ifstream ifs(file.c_str(), ifstream::in);
00207 
00208     string line;
00209 
00210     if(ifs)
00211     {
00212         getline(ifs, line);
00213     }
00214 
00215     return line;
00216 }
00217 
00218 string
00219 format(const char* format, ...)
00220 {
00221     va_list ap;
00222 
00223     size_t buffer_size_bytes = 256;
00224 
00225     string result;
00226 
00227     char* buffer = (char*)malloc(buffer_size_bytes);
00228 
00229     if( buffer == NULL )
00230         return result;
00231 
00232     bool done = false;
00233 
00234     unsigned int loop_count = 0;
00235 
00236     while(!done)
00237     {
00238         va_start(ap, format);
00239 
00240         int return_value = vsnprintf(buffer, buffer_size_bytes, format, ap);
00241 
00242         if( return_value < 0 )
00243         {
00244             done = true;
00245         }
00246         else if( return_value >= buffer_size_bytes )
00247         {
00248             // Realloc and try again.
00249 
00250             buffer_size_bytes = return_value + 1;
00251 
00252             char* new_buffer_ptr = (char*)realloc(buffer, buffer_size_bytes);
00253 
00254             if( new_buffer_ptr == NULL )
00255             {
00256                 done = true;
00257             }
00258             else
00259             {
00260                 buffer = new_buffer_ptr;
00261             }
00262         }
00263         else
00264         {
00265             result = buffer;
00266             done = true;
00267         }
00268 
00269         va_end(ap);
00270 
00271         if( ++loop_count > 5 )
00272             done = true;
00273     }
00274 
00275     free(buffer);
00276 
00277     return result;
00278 }
00279 
00280 string
00281 usb_sysfs_hw_string(const string& sysfs_path)
00282 {
00283     string serial_number = read_line( sysfs_path + "/serial" );
00284 
00285     if( serial_number.length() > 0 )
00286     {
00287         serial_number = format( "SNR=%s", serial_number.c_str() );
00288     }
00289 
00290     string vid = read_line( sysfs_path + "/idVendor" );
00291 
00292     string pid = read_line( sysfs_path + "/idProduct" );
00293 
00294     return format("USB VID:PID=%s:%s %s", vid.c_str(), pid.c_str(), serial_number.c_str() );
00295 }
00296 
00297 vector<PortInfo>
00298 serial::list_ports()
00299 {
00300     vector<PortInfo> results;
00301 
00302     vector<string> search_globs;
00303     search_globs.push_back("/dev/ttyACM*");
00304     search_globs.push_back("/dev/ttyS*");
00305     search_globs.push_back("/dev/ttyUSB*");
00306     search_globs.push_back("/dev/tty.*");
00307     search_globs.push_back("/dev/cu.*");
00308 
00309     vector<string> devices_found = glob( search_globs );
00310 
00311     vector<string>::iterator iter = devices_found.begin();
00312 
00313     while( iter != devices_found.end() )
00314     {
00315         string device = *iter++;
00316 
00317         vector<string> sysfs_info = get_sysfs_info( device );
00318 
00319         string friendly_name = sysfs_info[0];
00320 
00321         string hardware_id = sysfs_info[1];
00322 
00323         PortInfo device_entry;
00324         device_entry.port = device;
00325         device_entry.description = friendly_name;
00326         device_entry.hardware_id = hardware_id;
00327 
00328         results.push_back( device_entry );
00329 
00330     }
00331 
00332     return results;
00333 }
00334 
00335 #endif // defined(__linux__)


serial
Author(s): William Woodall , John Harrison
autogenerated on Thu Mar 28 2019 03:29:52