list_ports_osx.cc
Go to the documentation of this file.
00001 #if defined(__APPLE__)
00002 
00003 #include <sys/param.h>
00004 #include <stdint.h>
00005 
00006 #include <CoreFoundation/CoreFoundation.h>
00007 #include <IOKit/IOKitLib.h>
00008 #include <IOKit/serial/IOSerialKeys.h>
00009 #include <IOKit/IOBSD.h>
00010 
00011 #include <iostream>
00012 #include <string>
00013 #include <vector>
00014 
00015 #include "serial/serial.h"
00016 
00017 using serial::PortInfo;
00018 using std::string;
00019 using std::vector;
00020 
00021 #define HARDWARE_ID_STRING_LENGTH 128
00022 
00023 string cfstring_to_string( CFStringRef cfstring );
00024 string get_device_path( io_object_t& serial_port );
00025 string get_class_name( io_object_t& obj );
00026 io_registry_entry_t get_parent_iousb_device( io_object_t& serial_port );
00027 string get_string_property( io_object_t& device, const char* property );
00028 uint16_t get_int_property( io_object_t& device, const char* property );
00029 string rtrim(const string& str);
00030 
00031 string
00032 cfstring_to_string( CFStringRef cfstring )
00033 {
00034     char cstring[MAXPATHLEN];
00035     string result;
00036 
00037     if( cfstring )
00038     {
00039         Boolean success = CFStringGetCString( cfstring,
00040             cstring,
00041             sizeof(cstring),
00042             kCFStringEncodingASCII );
00043 
00044         if( success )
00045             result = cstring;
00046     }
00047 
00048     return result;
00049 }
00050 
00051 string
00052 get_device_path( io_object_t& serial_port )
00053 {
00054     CFTypeRef callout_path;
00055     string device_path;
00056 
00057     callout_path = IORegistryEntryCreateCFProperty( serial_port,
00058         CFSTR(kIOCalloutDeviceKey),
00059         kCFAllocatorDefault,
00060         0 );
00061 
00062     if (callout_path)
00063     {
00064         if( CFGetTypeID(callout_path) == CFStringGetTypeID() )
00065             device_path = cfstring_to_string( static_cast<CFStringRef>(callout_path) );
00066 
00067         CFRelease(callout_path);
00068     }
00069 
00070     return device_path;
00071 }
00072 
00073 string
00074 get_class_name( io_object_t& obj )
00075 {
00076     string result;
00077     io_name_t class_name;
00078     kern_return_t kern_result;
00079 
00080     kern_result = IOObjectGetClass( obj, class_name );
00081 
00082     if( kern_result == KERN_SUCCESS )
00083         result = class_name;
00084 
00085     return result;
00086 }
00087 
00088 io_registry_entry_t
00089 get_parent_iousb_device( io_object_t& serial_port )
00090 {
00091     io_object_t device = serial_port;
00092     io_registry_entry_t parent = 0;
00093     io_registry_entry_t result = 0;
00094     kern_return_t kern_result = KERN_FAILURE;
00095     string name = get_class_name(device);
00096 
00097     // Walk the IO Registry tree looking for this devices parent IOUSBDevice.
00098     while( name != "IOUSBDevice" )
00099     {
00100         kern_result = IORegistryEntryGetParentEntry( device,
00101         kIOServicePlane,
00102         &parent );
00103 
00104         if(kern_result != KERN_SUCCESS)
00105         {
00106             result = 0;
00107             break;
00108         }
00109 
00110         device = parent;
00111 
00112         name = get_class_name(device);
00113     }
00114 
00115     if(kern_result == KERN_SUCCESS)
00116         result = device;
00117 
00118     return result;
00119 }
00120 
00121 string
00122 get_string_property( io_object_t& device, const char* property )
00123 {
00124     string property_name;
00125 
00126     if( device )
00127     {
00128         CFStringRef property_as_cfstring = CFStringCreateWithCString (
00129             kCFAllocatorDefault,
00130             property,
00131             kCFStringEncodingASCII );
00132 
00133         CFTypeRef name_as_cfstring = IORegistryEntryCreateCFProperty(
00134             device,
00135             property_as_cfstring,
00136             kCFAllocatorDefault,
00137             0 );
00138 
00139         if( name_as_cfstring )
00140         {
00141             if( CFGetTypeID(name_as_cfstring) == CFStringGetTypeID() )
00142                 property_name = cfstring_to_string( static_cast<CFStringRef>(name_as_cfstring) );
00143 
00144             CFRelease(name_as_cfstring);
00145         }
00146 
00147         if(property_as_cfstring)
00148             CFRelease(property_as_cfstring);
00149     }
00150 
00151     return property_name;
00152 }
00153 
00154 uint16_t
00155 get_int_property( io_object_t& device, const char* property )
00156 {
00157     uint16_t result = 0;
00158 
00159     if( device )
00160     {
00161         CFStringRef property_as_cfstring = CFStringCreateWithCString (
00162             kCFAllocatorDefault,
00163             property,
00164             kCFStringEncodingASCII );
00165 
00166         CFTypeRef number = IORegistryEntryCreateCFProperty( device,
00167             property_as_cfstring,
00168             kCFAllocatorDefault,
00169             0 );
00170 
00171         if(property_as_cfstring)
00172             CFRelease(property_as_cfstring);
00173 
00174         if( number )
00175         {
00176             if( CFGetTypeID(number) == CFNumberGetTypeID() )
00177             {
00178                 bool success = CFNumberGetValue( static_cast<CFNumberRef>(number),
00179                     kCFNumberSInt16Type,
00180                     &result );
00181 
00182                 if( !success )
00183                     result = 0;
00184             }
00185 
00186             CFRelease(number);
00187         }
00188 
00189     }
00190 
00191     return result;
00192 }
00193 
00194 string rtrim(const string& str)
00195 {
00196     string result = str;
00197 
00198     string whitespace = " \t\f\v\n\r";
00199 
00200     std::size_t found = result.find_last_not_of(whitespace);
00201 
00202     if (found != std::string::npos)
00203         result.erase(found+1);
00204     else
00205         result.clear();
00206 
00207     return result;
00208 }
00209 
00210 vector<PortInfo>
00211 serial::list_ports(void)
00212 {
00213     vector<PortInfo> devices_found;
00214     CFMutableDictionaryRef classes_to_match;
00215     io_iterator_t serial_port_iterator;
00216     io_object_t serial_port;
00217     mach_port_t master_port;
00218     kern_return_t kern_result;
00219 
00220     kern_result = IOMasterPort(MACH_PORT_NULL, &master_port);
00221 
00222     if(kern_result != KERN_SUCCESS)
00223         return devices_found;
00224 
00225     classes_to_match = IOServiceMatching(kIOSerialBSDServiceValue);
00226 
00227     if (classes_to_match == NULL)
00228         return devices_found;
00229 
00230     CFDictionarySetValue( classes_to_match,
00231         CFSTR(kIOSerialBSDTypeKey),
00232         CFSTR(kIOSerialBSDAllTypes) );
00233 
00234     kern_result = IOServiceGetMatchingServices(master_port, classes_to_match, &serial_port_iterator);
00235 
00236     if (KERN_SUCCESS != kern_result)
00237         return devices_found;
00238 
00239     while ( (serial_port = IOIteratorNext(serial_port_iterator)) )
00240     {
00241         string device_path = get_device_path( serial_port );
00242         io_registry_entry_t parent = get_parent_iousb_device( serial_port );
00243         IOObjectRelease(serial_port);
00244 
00245         if( device_path.empty() )
00246             continue;
00247 
00248         PortInfo port_info;
00249         port_info.port = device_path;
00250         port_info.description = "n/a";
00251         port_info.hardware_id = "n/a";
00252 
00253         string device_name = rtrim( get_string_property( parent, "USB Product Name" ) );
00254         string vendor_name = rtrim( get_string_property( parent, "USB Vendor Name") );
00255         string description = rtrim( vendor_name + " " + device_name );
00256         if( !description.empty() )
00257             port_info.description = description;
00258 
00259         string serial_number = rtrim(get_string_property( parent, "USB Serial Number" ) );
00260         uint16_t vendor_id = get_int_property( parent, "idVendor" );
00261         uint16_t product_id = get_int_property( parent, "idProduct" );
00262 
00263         if( vendor_id && product_id )
00264         {
00265             char cstring[HARDWARE_ID_STRING_LENGTH];
00266 
00267             if(serial_number.empty())
00268                 serial_number = "None";
00269 
00270             int ret = snprintf( cstring, HARDWARE_ID_STRING_LENGTH, "USB VID:PID=%04x:%04x SNR=%s",
00271                 vendor_id,
00272                 product_id,
00273                 serial_number.c_str() );
00274 
00275             if( (ret >= 0) && (ret < HARDWARE_ID_STRING_LENGTH) )
00276                 port_info.hardware_id = cstring;
00277         }
00278 
00279         devices_found.push_back(port_info);
00280     }
00281 
00282     IOObjectRelease(serial_port_iterator);
00283     return devices_found;
00284 }
00285 
00286 #endif // defined(__APPLE__)


serial
Author(s): William Woodall , John Harrison
autogenerated on Sat Jan 21 2017 03:55:47