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()


xarm_api
Author(s):
autogenerated on Sat May 8 2021 02:51:23