Уведомления о добавлении / удалении устройства IOKit - только один раз?

Я пытался получать уведомления, когда определенное USB-устройство добавляется или удаляется. Я прочитал документ «Доступ к оборудованию из приложений» и имею простое демонстрационное приложение, в основном основанное на коде, представленном в этом документе.

Он работает при первом добавлении или удалении устройства, но после этого мои обратные вызовы никогда не вызываются. Я не могу понять, почему? Может ли кто-нибудь заметить, где я ошибаюсь?

(проект xcode, если вы хотите протестировать) http://monkeyfood.com/testIOKitNOtificaiton.zip

Спасибо.

//
//  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

person Diggory    schedule 24.07.2012    source источник


Ответы (2)


Я понял, что было не так - я ничего не делал с итератором в обратном вызове C. Глупая ошибка!

person Diggory    schedule 25.07.2012

Я немного опоздал, так как есть принятый ответ, но чтобы исправить это, вам нужно перебрать итератор соответствующих устройств в обратном вызове. Но сделать это не так просто, поэтому вот код, чтобы это произошло, поскольку обратный вызов является функцией C, и вы хотите связать его с вашими методами Objective C.

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 — это мой класс диспетчера USB-устройств, а reload — метод, который выполняет соответствующую инициализацию USB-устройства (получение отчетов о функциях и обмен данными).

person Samuel Clay    schedule 03.04.2014