OSVR Framework (Internal Development Docs)  0.6-1962-g59773924
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
USBSerialDevInfo_MacOSX.h
Go to the documentation of this file.
1 
12 // Copyright 2015 Sensics, Inc.
13 //
14 // Licensed under the Apache License, Version 2.0 (the "License");
15 // you may not use this file except in compliance with the License.
16 // You may obtain a copy of the License at
17 //
18 // http://www.apache.org/licenses/LICENSE-2.0
19 //
20 // Unless required by applicable law or agreed to in writing, software
21 // distributed under the License is distributed on an "AS IS" BASIS,
22 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23 // See the License for the specific language governing permissions and
24 // limitations under the License.
25 
26 // Internal Includes
27 #include "USBSerialDevInfo.h"
28 
29 // System includes
30 #include <CoreFoundation/CoreFoundation.h>
31 #include <IOKit/IOKitLib.h>
32 #include <IOKit/IOKitKeys.h>
33 #include <IOKit/serial/IOSerialKeys.h>
34 
35 namespace osvr {
36 namespace usbserial {
37 
38  namespace {
39 
47  int findSerialPorts(io_iterator_t *matchingServices) {
48  // Query IOKit for services matching kIOSerialBSDServiceValue
49  CFMutableDictionaryRef classesToMatch =
50  IOServiceMatching(kIOSerialBSDServiceValue);
51  if (classesToMatch == NULL) {
52  return false;
53  }
54  // Query only for serial ports
55  CFDictionarySetValue(classesToMatch, CFSTR(kIOSerialBSDTypeKey),
56  CFSTR(kIOSerialBSDAllTypes));
57  // Run the query
58  kern_return_t kernResult = IOServiceGetMatchingServices(
59  kIOMasterPortDefault, classesToMatch, matchingServices);
60  if (KERN_SUCCESS != kernResult) {
61  return false;
62  }
63  return true;
64  }
65 
77  bool matches_ids(const USBSerialDevice &device,
78  const boost::optional<uint16_t> &vendorID,
79  const boost::optional<uint16_t> &productID) {
80  const bool vendor_matches =
81  (!vendorID || *vendorID == device.getVID());
82  const bool product_matches =
83  (!productID || *productID == device.getPID());
84 
85  return (vendor_matches && product_matches);
86  }
87  }
88 
89  std::vector<USBSerialDevice>
90  getSerialDeviceList(boost::optional<uint16_t> vendorID,
91  boost::optional<uint16_t> productID) {
92 
93  std::vector<USBSerialDevice> devices;
94 
95  io_iterator_t serialPortIterator;
96  io_object_t serialPortService;
97  // find all serial ports
98  if (findSerialPorts(&serialPortIterator) == true) {
99  // iterate over serial ports, getting vid and pid
100  while ((serialPortService = IOIteratorNext(serialPortIterator)) !=
101  0) {
102  const CFNumberRef vidObj =
103  static_cast<CFNumberRef>(IORegistryEntrySearchCFProperty(
104  serialPortService, kIOServicePlane, CFSTR("idVendor"),
105  NULL, kIORegistryIterateRecursively |
106  kIORegistryIterateParents));
107  const CFNumberRef pidObj =
108  static_cast<CFNumberRef>(IORegistryEntrySearchCFProperty(
109  serialPortService, kIOServicePlane, CFSTR("idProduct"),
110  NULL, kIORegistryIterateRecursively |
111  kIORegistryIterateParents));
112  const CFStringRef bsdPathObj =
113  static_cast<CFStringRef>(IORegistryEntryCreateCFProperty(
114  serialPortService, CFSTR(kIOCalloutDeviceKey),
115  kCFAllocatorDefault, 0));
116 
117  if (!vidObj || !pidObj || !bsdPathObj) {
118  continue;
119  }
120  // handle device
121  uint16_t vid, pid;
122  CFNumberGetValue(vidObj, kCFNumberSInt16Type, &vid);
123  CFNumberGetValue(pidObj, kCFNumberSInt16Type, &pid);
124 
125  // convert the string object into a C-string
126  CFIndex bufferSize = CFStringGetMaximumSizeForEncoding(
127  CFStringGetLength(bsdPathObj),
128  kCFStringEncodingMacRoman) +
129  sizeof('\0');
130  std::vector<char> bsdPathBuf(bufferSize);
131  CFStringGetCString(bsdPathObj, bsdPathBuf.data(), bufferSize,
132  kCFStringEncodingMacRoman);
133  // create the device
134  USBSerialDevice usb_serial_device(vid, pid, bsdPathBuf.data(),
135  bsdPathBuf.data());
136  // check if IDs match and add
137  if (matches_ids(usb_serial_device, vendorID, productID)) {
138  devices.push_back(usb_serial_device);
139  }
140  }
141  }
142 
143  return devices;
144  }
145 
146 } // namespace usbserial
147 } // namespace osvr