list_ports_osx.cc
Go to the documentation of this file.
1 #if defined(__APPLE__)
2 
3 #include <sys/param.h>
4 #include <stdint.h>
5 
6 #include <CoreFoundation/CoreFoundation.h>
7 #include <IOKit/IOKitLib.h>
8 #include <IOKit/serial/IOSerialKeys.h>
9 #include <IOKit/IOBSD.h>
10 
11 #include <iostream>
12 #include <string>
13 #include <vector>
14 
15 #include "serial/serial.h"
16 
17 using serial::PortInfo;
18 using std::string;
19 using std::vector;
20 
21 #define HARDWARE_ID_STRING_LENGTH 128
22 
23 string cfstring_to_string( CFStringRef cfstring );
24 string get_device_path( io_object_t& serial_port );
25 string get_class_name( io_object_t& obj );
26 io_registry_entry_t get_parent_iousb_device( io_object_t& serial_port );
27 string get_string_property( io_object_t& device, const char* property );
28 uint16_t get_int_property( io_object_t& device, const char* property );
29 string rtrim(const string& str);
30 
31 string
32 cfstring_to_string( CFStringRef cfstring )
33 {
34  char cstring[MAXPATHLEN];
35  string result;
36 
37  if( cfstring )
38  {
39  Boolean success = CFStringGetCString( cfstring,
40  cstring,
41  sizeof(cstring),
42  kCFStringEncodingASCII );
43 
44  if( success )
45  result = cstring;
46  }
47 
48  return result;
49 }
50 
51 string
52 get_device_path( io_object_t& serial_port )
53 {
54  CFTypeRef callout_path;
55  string device_path;
56 
57  callout_path = IORegistryEntryCreateCFProperty( serial_port,
58  CFSTR(kIOCalloutDeviceKey),
59  kCFAllocatorDefault,
60  0 );
61 
62  if (callout_path)
63  {
64  if( CFGetTypeID(callout_path) == CFStringGetTypeID() )
65  device_path = cfstring_to_string( static_cast<CFStringRef>(callout_path) );
66 
67  CFRelease(callout_path);
68  }
69 
70  return device_path;
71 }
72 
73 string
74 get_class_name( io_object_t& obj )
75 {
76  string result;
77  io_name_t class_name;
78  kern_return_t kern_result;
79 
80  kern_result = IOObjectGetClass( obj, class_name );
81 
82  if( kern_result == KERN_SUCCESS )
83  result = class_name;
84 
85  return result;
86 }
87 
88 io_registry_entry_t
89 get_parent_iousb_device( io_object_t& serial_port )
90 {
91  io_object_t device = serial_port;
92  io_registry_entry_t parent = 0;
93  io_registry_entry_t result = 0;
94  kern_return_t kern_result = KERN_FAILURE;
95  string name = get_class_name(device);
96 
97  // Walk the IO Registry tree looking for this devices parent IOUSBDevice.
98  while( name != "IOUSBDevice" )
99  {
100  kern_result = IORegistryEntryGetParentEntry( device,
101  kIOServicePlane,
102  &parent );
103 
104  if(kern_result != KERN_SUCCESS)
105  {
106  result = 0;
107  break;
108  }
109 
110  device = parent;
111 
112  name = get_class_name(device);
113  }
114 
115  if(kern_result == KERN_SUCCESS)
116  result = device;
117 
118  return result;
119 }
120 
121 string
122 get_string_property( io_object_t& device, const char* property )
123 {
124  string property_name;
125 
126  if( device )
127  {
128  CFStringRef property_as_cfstring = CFStringCreateWithCString (
129  kCFAllocatorDefault,
130  property,
131  kCFStringEncodingASCII );
132 
133  CFTypeRef name_as_cfstring = IORegistryEntryCreateCFProperty(
134  device,
135  property_as_cfstring,
136  kCFAllocatorDefault,
137  0 );
138 
139  if( name_as_cfstring )
140  {
141  if( CFGetTypeID(name_as_cfstring) == CFStringGetTypeID() )
142  property_name = cfstring_to_string( static_cast<CFStringRef>(name_as_cfstring) );
143 
144  CFRelease(name_as_cfstring);
145  }
146 
147  if(property_as_cfstring)
148  CFRelease(property_as_cfstring);
149  }
150 
151  return property_name;
152 }
153 
154 uint16_t
155 get_int_property( io_object_t& device, const char* property )
156 {
157  uint16_t result = 0;
158 
159  if( device )
160  {
161  CFStringRef property_as_cfstring = CFStringCreateWithCString (
162  kCFAllocatorDefault,
163  property,
164  kCFStringEncodingASCII );
165 
166  CFTypeRef number = IORegistryEntryCreateCFProperty( device,
167  property_as_cfstring,
168  kCFAllocatorDefault,
169  0 );
170 
171  if(property_as_cfstring)
172  CFRelease(property_as_cfstring);
173 
174  if( number )
175  {
176  if( CFGetTypeID(number) == CFNumberGetTypeID() )
177  {
178  bool success = CFNumberGetValue( static_cast<CFNumberRef>(number),
179  kCFNumberSInt16Type,
180  &result );
181 
182  if( !success )
183  result = 0;
184  }
185 
186  CFRelease(number);
187  }
188 
189  }
190 
191  return result;
192 }
193 
194 string rtrim(const string& str)
195 {
196  string result = str;
197 
198  string whitespace = " \t\f\v\n\r";
199 
200  std::size_t found = result.find_last_not_of(whitespace);
201 
202  if (found != std::string::npos)
203  result.erase(found+1);
204  else
205  result.clear();
206 
207  return result;
208 }
209 
210 vector<PortInfo>
211 serial::list_ports(void)
212 {
213  vector<PortInfo> devices_found;
214  CFMutableDictionaryRef classes_to_match;
215  io_iterator_t serial_port_iterator;
216  io_object_t serial_port;
217  mach_port_t master_port;
218  kern_return_t kern_result;
219 
220  kern_result = IOMasterPort(MACH_PORT_NULL, &master_port);
221 
222  if(kern_result != KERN_SUCCESS)
223  return devices_found;
224 
225  classes_to_match = IOServiceMatching(kIOSerialBSDServiceValue);
226 
227  if (classes_to_match == NULL)
228  return devices_found;
229 
230  CFDictionarySetValue( classes_to_match,
231  CFSTR(kIOSerialBSDTypeKey),
232  CFSTR(kIOSerialBSDAllTypes) );
233 
234  kern_result = IOServiceGetMatchingServices(master_port, classes_to_match, &serial_port_iterator);
235 
236  if (KERN_SUCCESS != kern_result)
237  return devices_found;
238 
239  while ( (serial_port = IOIteratorNext(serial_port_iterator)) )
240  {
241  string device_path = get_device_path( serial_port );
242  io_registry_entry_t parent = get_parent_iousb_device( serial_port );
243  IOObjectRelease(serial_port);
244 
245  if( device_path.empty() )
246  continue;
247 
248  PortInfo port_info;
249  port_info.port = device_path;
250  port_info.description = "n/a";
251  port_info.hardware_id = "n/a";
252 
253  string device_name = rtrim( get_string_property( parent, "USB Product Name" ) );
254  string vendor_name = rtrim( get_string_property( parent, "USB Vendor Name") );
255  string description = rtrim( vendor_name + " " + device_name );
256  if( !description.empty() )
257  port_info.description = description;
258 
259  string serial_number = rtrim(get_string_property( parent, "USB Serial Number" ) );
260  uint16_t vendor_id = get_int_property( parent, "idVendor" );
261  uint16_t product_id = get_int_property( parent, "idProduct" );
262 
263  if( vendor_id && product_id )
264  {
265  char cstring[HARDWARE_ID_STRING_LENGTH];
266 
267  if(serial_number.empty())
268  serial_number = "None";
269 
270  int ret = snprintf( cstring, HARDWARE_ID_STRING_LENGTH, "USB VID:PID=%04x:%04x SNR=%s",
271  vendor_id,
272  product_id,
273  serial_number.c_str() );
274 
275  if( (ret >= 0) && (ret < HARDWARE_ID_STRING_LENGTH) )
276  port_info.hardware_id = cstring;
277  }
278 
279  devices_found.push_back(port_info);
280  }
281 
282  IOObjectRelease(serial_port_iterator);
283  return devices_found;
284 }
285 
286 #endif // defined(__APPLE__)
std::vector< PortInfo > list_ports()


serial
Author(s): William Woodall , John Harrison
autogenerated on Thu Jan 9 2020 07:18:58