Skip to content

Commit a3f0f6a

Browse files
committed
Merge pull request #235 from d235j/mac-find-serial
Implement getSerialDeviceList for Mac OS X
2 parents 4c48e60 + 286ab7d commit a3f0f6a

File tree

2 files changed

+86
-32
lines changed

2 files changed

+86
-32
lines changed

Diff for: src/osvr/USBSerial/CMakeLists.txt

+9
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,12 @@ if(WIN32)
4242
wbemuuid
4343
com_smart_pointer)
4444
endif()
45+
if(APPLE)
46+
# find_library must be used for OS X frameworks
47+
find_library(COREFOUNDATION_LIBRARY CoreFoundation)
48+
find_library(IOKIT_LIBRARY IOKit)
49+
target_link_libraries(${LIBNAME_FULL}
50+
PRIVATE
51+
${COREFOUNDATION_LIBRARY}
52+
${IOKIT_LIBRARY})
53+
endif()

Diff for: src/osvr/USBSerial/USBSerialDevInfo_MacOSX.h

+77-32
Original file line numberDiff line numberDiff line change
@@ -26,44 +26,42 @@
2626
// Internal Includes
2727
#include "USBSerialDevInfo.h"
2828

29-
// Library/third-party includes
30-
#include <boost/filesystem.hpp>
31-
#include <boost/range/iterator_range.hpp>
32-
#include <boost/algorithm/string.hpp>
33-
34-
// Standard includes
35-
#include <iostream>
36-
#include <vector>
37-
#include <string>
38-
#include <fstream>
39-
40-
#include <fcntl.h> // for O_NONBLOCK
41-
#include <sys/ioctl.h> // for ioctl
42-
#include <unistd.h> // for open, close
43-
44-
// IOKit includes
29+
30+
// System includes
31+
#include <CoreFoundation/CoreFoundation.h>
4532
#include <IOKit/IOKitLib.h>
46-
#include <IOKit/usb/IOUSBLib.h>
33+
#include <IOKit/IOKitKeys.h>
34+
#include <IOKit/serial/IOSerialKeys.h>
4735

4836
namespace osvr {
4937
namespace usbserial {
5038

5139
namespace {
5240

5341
/**
54-
* Given the name of a device, this function will create a
55-
*USBSerialDevice
56-
* object. If the device can be created successfully it will return
57-
* @c boost::none.
58-
*
59-
* @param device The name of the device to create (e.g., "ttyACM0")
60-
*
61-
* @return an optional USBSerialDevice
42+
* Helper function that returns an IOKit iterator for all serial ports
43+
* on the system.
44+
* @param matchingServices pointer which will be set to the value of the
45+
* iterator
46+
* @return 0 on success, -1 on failure
6247
*/
63-
boost::optional<USBSerialDevice>
64-
make_USBSerialDevice(const std::string &device) {
65-
//FIXME: STUB
66-
return boost::none;
48+
int findSerialPorts(io_iterator_t *matchingServices) {
49+
// Query IOKit for services matching kIOSerialBSDServiceValue
50+
CFMutableDictionaryRef classesToMatch =
51+
IOServiceMatching(kIOSerialBSDServiceValue);
52+
if (classesToMatch == NULL) {
53+
return false;
54+
}
55+
// Query only for serial ports
56+
CFDictionarySetValue(classesToMatch, CFSTR(kIOSerialBSDTypeKey),
57+
CFSTR(kIOSerialBSDAllTypes));
58+
// Run the query
59+
kern_return_t kernResult = IOServiceGetMatchingServices(
60+
kIOMasterPortDefault, classesToMatch, matchingServices);
61+
if (KERN_SUCCESS != kernResult) {
62+
return false;
63+
}
64+
return true;
6765
}
6866

6967
/**
@@ -87,15 +85,62 @@ namespace usbserial {
8785

8886
return (vendor_matches && product_matches);
8987
}
90-
91-
} // end namespace
88+
}
9289

9390
std::vector<USBSerialDevice>
9491
getSerialDeviceList(boost::optional<uint16_t> vendorID,
9592
boost::optional<uint16_t> productID) {
9693

97-
//FIXME: STUB
9894
std::vector<USBSerialDevice> devices;
95+
96+
io_iterator_t serialPortIterator;
97+
io_object_t serialPortService;
98+
// find all serial ports
99+
if (findSerialPorts(&serialPortIterator) == true) {
100+
// iterate over serial ports, getting vid and pid
101+
while ((serialPortService = IOIteratorNext(serialPortIterator)) !=
102+
0) {
103+
const CFNumberRef vidObj =
104+
static_cast<CFNumberRef>(IORegistryEntrySearchCFProperty(
105+
serialPortService, kIOServicePlane, CFSTR("idVendor"),
106+
NULL, kIORegistryIterateRecursively |
107+
kIORegistryIterateParents));
108+
const CFNumberRef pidObj =
109+
static_cast<CFNumberRef>(IORegistryEntrySearchCFProperty(
110+
serialPortService, kIOServicePlane, CFSTR("idProduct"),
111+
NULL, kIORegistryIterateRecursively |
112+
kIORegistryIterateParents));
113+
const CFStringRef bsdPathObj =
114+
static_cast<CFStringRef>(IORegistryEntryCreateCFProperty(
115+
serialPortService, CFSTR(kIOCalloutDeviceKey),
116+
kCFAllocatorDefault, 0));
117+
118+
if (!vidObj || !pidObj || !bsdPathObj) {
119+
continue;
120+
}
121+
// handle device
122+
uint16_t vid, pid;
123+
CFNumberGetValue(vidObj, kCFNumberSInt16Type, &vid);
124+
CFNumberGetValue(pidObj, kCFNumberSInt16Type, &pid);
125+
126+
// convert the string object into a C-string
127+
CFIndex bufferSize = CFStringGetMaximumSizeForEncoding(
128+
CFStringGetLength(bsdPathObj),
129+
kCFStringEncodingMacRoman) +
130+
sizeof('\0');
131+
std::vector<char> bsdPathBuf(bufferSize);
132+
CFStringGetCString(bsdPathObj, bsdPathBuf.data(), bufferSize,
133+
kCFStringEncodingMacRoman);
134+
// create the device
135+
USBSerialDevice usb_serial_device(vid, pid, bsdPathBuf.data(),
136+
bsdPathBuf.data());
137+
// check if IDs match and add
138+
if (matches_ids(usb_serial_device, vendorID, productID)) {
139+
devices.push_back(usb_serial_device);
140+
}
141+
}
142+
}
143+
99144
return devices;
100145
}
101146

0 commit comments

Comments
 (0)