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
4836namespace osvr {
4937namespace 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