Question

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
Était-ce utile?

La solution

I've worked out what was wrong - I didn't do anything with the iterator in the C Callback. A stupid mistake!

Autres conseils

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).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top