I have been trying to get notified when a specific USB device is added or removed. I have read 'Accessing Hardware From Applications' document and have a bare-bones demo application, mainly based on the code provided in that document.
It works the first time a device is added or removed, but after that my callbacks never get called. I cannot work out why? Can anyone spot where I am going wrong?
(xcode project if you would like to test) http://monkeyfood.com/testIOKitNOtificaiton.zip
Thanks.
//
// AppDelegate.m
// testIOKitNotification
//
// Created by Diggory Laycock on 23/07/2012.
// Copyright (c) 2012 MonkeyFood.com. All rights reserved.
//
#import "AppDelegate.h"
@implementation AppDelegate
// Arduino USB info
#define matchVendorID 0x2341
#define matchProductID 0x0043
#pragma mark -
#pragma mark C Callback functions
#pragma mark -
void usbDeviceAppeared(void *refCon, io_iterator_t iterator){
NSLog(@"Matching USB device appeared");
}
void usbDeviceDisappeared(void *refCon, io_iterator_t iterator){
NSLog(@"Matching USB device disappeared");
}
@synthesize window = _window;
#pragma mark -
#pragma mark Application Methods
#pragma mark -
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
io_iterator_t newDevicesIterator;
io_iterator_t lostDevicesIterator;
newDevicesIterator = 0;
lostDevicesIterator = 0;
NSLog(@" ");
NSMutableDictionary *matchingDict = (__bridge NSMutableDictionary *)IOServiceMatching(kIOUSBDeviceClassName);
if (matchingDict == nil){
NSLog(@"Could not create matching dictionary");
return;
}
[matchingDict setObject:[NSNumber numberWithShort:matchVendorID] forKey:(NSString *)CFSTR(kUSBVendorID)];
[matchingDict setObject:[NSNumber numberWithShort:matchProductID] forKey:(NSString *)CFSTR(kUSBProductID)];
// Add notification ports to runloop
IONotificationPortRef notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
CFRunLoopSourceRef notificationRunLoopSource = IONotificationPortGetRunLoopSource(notificationPort);
CFRunLoopAddSource([[NSRunLoop currentRunLoop] getCFRunLoop], notificationRunLoopSource, kCFRunLoopDefaultMode);
kern_return_t err;
err = IOServiceAddMatchingNotification(notificationPort,
kIOMatchedNotification,
(__bridge CFDictionaryRef)matchingDict,
usbDeviceAppeared,
(__bridge void *)self,
&newDevicesIterator);
if (err)
{
NSLog(@"error adding publish notification");
}
[self matchingDevicesAdded: newDevicesIterator];
NSMutableDictionary *matchingDictRemoved = (__bridge NSMutableDictionary *)IOServiceMatching(kIOUSBDeviceClassName);
if (matchingDictRemoved == nil){
NSLog(@"Could not create matching dictionary");
return;
}
[matchingDictRemoved setObject:[NSNumber numberWithShort:matchVendorID] forKey:(NSString *)CFSTR(kUSBVendorID)];
[matchingDictRemoved setObject:[NSNumber numberWithShort:matchProductID] forKey:(NSString *)CFSTR(kUSBProductID)];
err = IOServiceAddMatchingNotification(notificationPort,
kIOTerminatedNotification,
(__bridge CFDictionaryRef)matchingDictRemoved,
usbDeviceDisappeared,
(__bridge void *)self,
&lostDevicesIterator);
if (err)
{
NSLog(@"error adding removed notification");
}
[self matchingDevicesRemoved: lostDevicesIterator];
// CFRunLoopRun();
// [[NSRunLoop currentRunLoop] run];
}
#pragma mark -
#pragma mark ObjC Callback functions
#pragma mark -
- (void)matchingDevicesAdded:(io_iterator_t)devices
{
io_object_t thisObject;
while ( (thisObject = IOIteratorNext(devices))) {
NSLog(@"new Matching device added ");
IOObjectRelease(thisObject);
}
}
- (void)matchingDevicesRemoved:(io_iterator_t)devices
{
io_object_t thisObject;
while ( (thisObject = IOIteratorNext(devices))) {
NSLog(@"A matching device was removed ");
IOObjectRelease(thisObject);
}
}
@end
I'm a bit late as there is an accepted answer, but to fix this you need to iterate over the matching devices iterator in your callback. But doing that isn't trivial, so here's the code to make that happen, since the callback is a C function and you want to bridge that to your Objective C methods.
void usbDeviceAppeared(void *refCon, io_iterator_t iterator){
NSLog(@"Matching USB device appeared");
SerialMonitor *monitor = (__bridge SerialMonitor *)refCon;
[monitor matchingDevicesAdded:iterator];
[monitor reload];
}
void usbDeviceDisappeared(void *refCon, io_iterator_t iterator){
NSLog(@"Matching USB device disappeared");
SerialMonitor *monitor = (__bridge SerialMonitor *)refCon;
[monitor matchingDevicesRemoved:iterator];
[monitor reload];
}
SerialMonitor
is my USB device manager class, and reload
is a method that does the appropriate USB device initialization (getting feature reports and exchanging data).
I've worked out what was wrong - I didn't do anything with the iterator in the C Callback. A stupid mistake!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With