Go to the documentation of this file.00001 #if defined(__linux__)
00002
00003
00004
00005
00006
00007
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
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
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__)