Vuo 2.4.2
Loading...
Searching...
No Matches
VuoSerialDevices.cc
Go to the documentation of this file.
1
10#include "VuoSerial.h"
11#include "VuoTriggerSet.hh"
12
13
14#include <IOKit/IOKitLib.h>
15#include <IOKit/serial/IOSerialKeys.h>
16#include <IOKit/usb/USBSpec.h>
17
18extern "C"
19{
20
21#ifdef VUO_COMPILER
23 "title" : "VuoSerialDevices",
24 "dependencies" : [
25 "CoreFoundation.framework",
26 "IOKit.framework",
27 "VuoSerialDevice",
28 "VuoSerialDevices",
29 "VuoSerialIO",
30 "VuoList_VuoSerialDevice",
31 "VuoList_VuoInteger"
32 ]
33 });
34#endif
35}
36
38
42static VuoText VuoSerial_getPropertyFromObjectOrAncestry(io_object_t o, CFStringRef property)
43{
44 CFStringRef valueCF = (CFStringRef)IORegistryEntryCreateCFProperty(o, property, NULL, 0);
45 if (valueCF)
46 {
47 VuoText value = VuoText_makeFromCFString(valueCF);
48 CFRelease(valueCF);
49 return value;
50 }
51
52 io_iterator_t it;
53 kern_return_t ret = IORegistryEntryGetParentIterator(o, kIOServicePlane, &it);
54 if (ret != KERN_SUCCESS)
55 {
56 VUserLog("Error: Couldn't get parent iterator: %d", ret);
57 return NULL;
58 }
59
60 io_object_t po;
61 while ( (po = IOIteratorNext(it)) )
62 {
64 IOObjectRelease(po);
65 if (value)
66 {
67 IOObjectRelease(it);
68 return value;
69 }
70 }
71 IOObjectRelease(it);
72
73 return NULL;
74}
75
76
81{
82 CFMutableDictionaryRef match = IOServiceMatching(kIOSerialBSDServiceValue);
83 if (!match)
84 {
85 VUserLog("Error: Couldn't create serial matching dictionary.");
86 return NULL;
87 }
88 CFDictionarySetValue(match, CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDAllTypes));
89
90 io_iterator_t it;
91 kern_return_t ret = IOServiceGetMatchingServices(kIOMasterPortDefault, match, &it);
92 if (ret != KERN_SUCCESS)
93 {
94 VUserLog("Error: Couldn't get serial device list: %d", ret);
95 return NULL;
96 }
97
99 io_object_t o;
100 while ( (o = IOIteratorNext(it)) )
101 {
102 VuoSerialDevice device;
103 device.matchType = VuoSerialDevice_MatchPath;
104
105 device.path = VuoSerial_getPropertyFromObjectOrAncestry(o, CFSTR(kIOCalloutDeviceKey));
106 if (!device.path)
107 {
108 VUserLog("Error: Device %d has no path.", o);
109 continue;
110 }
111
112 // Omit devices we can't open.
113 if (strstr(device.path, "-Wireless") // iPhone?
114 || strstr(device.path, "Bluetooth-"))
115 {
116 VuoRetain(device.path);
117 VuoRelease(device.path);
118 continue;
119 }
120
121 VuoText vendorName = VuoSerial_getPropertyFromObjectOrAncestry(o, CFSTR(kUSBVendorString));
122 VuoText productName = VuoSerial_getPropertyFromObjectOrAncestry(o, CFSTR(kUSBProductString));
123 VuoText serialNumber = VuoSerial_getPropertyFromObjectOrAncestry(o, CFSTR(kUSBSerialNumberString));
124
125 VuoRetain(vendorName);
126 VuoRetain(productName);
127 VuoRetain(serialNumber);
128
129 if (vendorName && productName && serialNumber)
130 device.name = VuoText_makeWithoutCopying(VuoText_format("%s %s (%s)", vendorName, productName, serialNumber));
131 else if (vendorName && productName)
132 device.name = VuoText_makeWithoutCopying(VuoText_format("%s %s", vendorName, productName));
133 else if (vendorName && serialNumber)
134 device.name = VuoText_makeWithoutCopying(VuoText_format("%s (%s)", vendorName, serialNumber));
135 else if (productName && serialNumber)
136 device.name = VuoText_makeWithoutCopying(VuoText_format("%s (%s)", productName, serialNumber));
137 else if (vendorName)
138 device.name = VuoText_make(vendorName);
139 else if (productName)
140 device.name = VuoText_make(productName);
141 else
142 {
143 VuoText ttyDevice = VuoSerial_getPropertyFromObjectOrAncestry(o, CFSTR(kIOTTYDeviceKey));
144 if (ttyDevice)
145 device.name = ttyDevice;
146 else
147 device.name = VuoText_make(device.path);
148 }
149
150
151 VuoRelease(vendorName);
152 VuoRelease(productName);
153 VuoRelease(serialNumber);
154 IOObjectRelease(o);
155
156 VuoListAppendValue_VuoSerialDevice(devices, device);
157 }
158
159 return devices;
160}
161
162unsigned int VuoSerial_useCount = 0;
163IONotificationPortRef VuoSerial_notificationPort;
164
168static void VuoSerial_servicesChanged(void *refcon, io_iterator_t it)
169{
170 // The notification won't fire again until we've looked at all of the existing items once.
171 while (IOIteratorNext(it));
172
174
176}
177
184{
185 if (__sync_add_and_fetch(&VuoSerial_useCount, 1) == 1)
186 {
187 VuoSerial_notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
189 {
190 VUserLog("Error: Couldn't create serial notification port.");
191 return;
192 }
193
194 CFRunLoopSourceRef notificationSource = IONotificationPortGetRunLoopSource(VuoSerial_notificationPort);
195 if (!notificationSource)
196 {
197 VUserLog("Error: Couldn't get serial notification source.");
198 return;
199 }
200
201 CFRunLoopAddSource(CFRunLoopGetMain(), notificationSource, kCFRunLoopCommonModes);
202
203
204 CFMutableDictionaryRef match = IOServiceMatching(kIOSerialBSDServiceValue);
205 if (!match)
206 {
207 VUserLog("Error: Couldn't create serial matching dictionary.");
208 return;
209 }
210 CFDictionarySetValue(match, CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDAllTypes));
211
212 // Since each IOServiceAddMatchingNotification() call releases the matching dictionary, retain it in order to make it through both calls.
213 CFRetain(match);
214
215
216 io_iterator_t it;
217 kern_return_t ret = IOServiceAddMatchingNotification(VuoSerial_notificationPort, kIOMatchedNotification, match, VuoSerial_servicesChanged, NULL, &it);
218 if (ret != KERN_SUCCESS)
219 {
220 VUserLog("Error: Couldn't create serial-add notification: %d", ret);
221 return;
222 }
223 // The notification doesn't start firing until we've looked at all of the existing items once.
224 while (IOIteratorNext(it));
225
226
227 ret = IOServiceAddMatchingNotification(VuoSerial_notificationPort, kIOTerminatedNotification, match, VuoSerial_servicesChanged, NULL, &it);
228 if (ret != KERN_SUCCESS)
229 {
230 VUserLog("Error: Couldn't create serial-remove notification: %d", ret);
231 return;
232 }
233 // The notification doesn't start firing until we've looked at all of the existing items once.
234 while (IOIteratorNext(it));
235 }
236}
237
244{
245 if (VuoSerial_useCount <= 0)
246 {
247 VUserLog("Error: Unbalanced VuoSerial_use() / _disuse() calls.");
248 return;
249 }
250
251 if (__sync_sub_and_fetch(&VuoSerial_useCount, 1) == 0)
252 IONotificationPortDestroy(VuoSerial_notificationPort);
253}
254
263{
264 VuoSerial_deviceCallbacks.addTrigger(devices);
265 devices(VuoSerial_getDeviceList());
266}
267
274{
275 VuoSerial_deviceCallbacks.removeTrigger(devices);
276}