2013-12-15 27 views
5

Ich versuche, IOKit zu verstehen, und ich fühle, dass ich nah dran bin, aber noch nicht da. Entschuldige meine Verwirrung.Rückruf mit IOKit über einen Interrupt-Eingabe-Endpunkt

Ich habe es geschafft, Code zu schreiben, der mein USB-Gerät erkennt (eine einfache Taste am Ende eines USB-Kabels, das einen Windows-Treiber, aber keinen Mac-Treiber hat).

Ich versuche, eine Art Rückruf zu erhalten, wenn die Taste gedrückt wird.

Ich bekomme einen Rückruf, wenn das Gerät an USB angeschlossen oder entfernt ist. Jetzt versuche ich herauszufinden, wie man informiert wird, wenn der Knopf gedrückt wird, aber ich kann es nicht herausfinden. Die Dokumentation ist sehr verwirrend für mich, da IOKit scheint sowohl eine C++ und c je nachdem, wie Sie darauf zugreifen (Kernel Extension oder User-Space-Treiber oder etwas ähnliches. Nicht sicher, ich habe die richtige Terminologie.

Ich habe versucht, ein paar Methoden hinzufügen, um einen Rückruf zu erhalten, wenn ein Interrupt-Wert ändert, wie Sie in den Code sehen. Aber nichts passiert.

Hier ist meine aktuelle AppDelegate.m-Datei sowie die USB-Sonde Informationen auf der . Vorrichtung

Low Speed device @ 5 (0x14100000): ............................................. Composite device: "DL100B Dream Cheeky Generic Controller" 
Port Information: 0x101a 
Number Of Endpoints (includes EP0): 
Device Descriptor 
Configuration Descriptor (current config) 
    Length (and contents): 34 
    Number of Interfaces: 1 
    Configuration Value: 1 
    Attributes: 0x80 (bus-powered) 
    MaxPower: 500 mA 
    Interface #0 - HID 
     Alternate Setting 0 
     Number of Endpoints 1 
     Interface Class: 3 (HID) 
     Interface Subclass; 0 
     Interface Protocol: 0 
     HID Descriptor 
     Endpoint 0x81 - Interrupt Input 
      Address: 0x81 (IN) 
      Attributes: 0x03 (Interrupt) 
      Max Packet Size: 8 
      Polling Interval: 10 ms 

Die App Delegate.m Datei:

// 
// USBHIDAppDelegate.m 
// USBHID 
// 
// Created by Michael Dolinar on 12-05-02. 
// Copyright (c) 2012 __MyCompanyName__. All rights reserved. 
// 

#import "USBHIDAppDelegate.h"  
#import "IOKit/hid/IOHIDManager.h" 
#include <IOKit/IOKitLib.h> 
#include <IOKit/IOCFPlugIn.h> 
#include <IOKit/usb/IOUSBLib.h> 
#include <IOKit/usb/USBSpec.h> 

@implementation USBHIDAppDelegate 

@synthesize window = _window; 

// New USB device specified in the matching dictionary has been added (callback function) 
static void Handle_DeviceMatchingCallback(void *inContext, 
              IOReturn inResult, 
              void *inSender, 
              IOHIDDeviceRef inIOHIDDeviceRef){ 

    // Retrieve the device name & serial number 
    NSString *devName = [NSString stringWithUTF8String: 
         CFStringGetCStringPtr(
               IOHIDDeviceGetProperty(inIOHIDDeviceRef, 
                     CFSTR("Product")), 
               kCFStringEncodingMacRoman)]; 

    UInt32 serialString = CFStringGetCStringPtr(
          IOHIDDeviceGetProperty(inIOHIDDeviceRef, 
               CFSTR("SerialNumber")), 
          kCFStringEncodingMacRoman); 
    NSString *devSerialNumber; 
    if (serialString == 0) { 
     devSerialNumber = @"No Serial Number"; 

    } else { 
     devSerialNumber = [NSString stringWithUTF8String:serialString]; 

    } 
    // Log the device reference, Name, Serial Number & device count 
    NSLog(@"\nDevice added: %p\nModel: %@\nSerial Number:%@\nDevice count: %ld", 
      inIOHIDDeviceRef, 
      devName, 
      devSerialNumber, 
      USBDeviceCount(inSender)); 

//Open the device (Was missing) 
IOReturn err = IOHIDDeviceOpen(inIOHIDDeviceRef, 0); 

// Sollte für Fehler überprüfen hier ...

IOHIDDeviceRegisterInputValueCallback(inIOHIDDeviceRef, Handle_IOHIDDeviceInputValueCallback, NULL); 

// Muss auch hier wieder für Runloop registrieren ... auch IOHIDDeviceScheduleWithRunLoop (inIOHIDDeviceRef, CFRunLoopGetCurrent(), kCFRunLoopCommonModes) fehlte;

} 

static void Handle_IOHIDDeviceInputValueCallback(void *inContext, 
               IOReturn inResult, 
                void *inSender, 
               IOHIDValueRef inIOHIDValueRef 
               ) 
{ 
    NSLog(@"Value changed"); 
} 


// USB device specified in the matching dictionary has been removed (callback function) 
static void Handle_DeviceRemovalCallback(void *inContext, 
             IOReturn inResult, 
             void *inSender, 
             IOHIDDeviceRef inIOHIDDeviceRef){ 

    // Log the device ID & device count 
    NSLog(@"\nDevice removed: %p\nDevice count: %ld", 
      (void *)inIOHIDDeviceRef, 
      USBDeviceCount(inSender)); 
    IOHIDDeviceRegisterInputValueCallback(inIOHIDDeviceRef, NULL, NULL); //Remove callback 

} 





// Counts the number of devices in the device set (incudes all USB devices that match our dictionary) 
static long USBDeviceCount(IOHIDManagerRef HIDManager){ 

    // The device set includes all USB devices that match our matching dictionary. Fetch it. 
    CFSetRef devSet = IOHIDManagerCopyDevices(HIDManager); 

    // The devSet will be NULL if there are 0 devices, so only try to count the devices if devSet exists 
    if(devSet) return CFSetGetCount(devSet); 

    // There were no matching devices (devSet was NULL), so return a count of 0 
    return 0; 
} 


- (void)applicationDidFinishLaunching:(NSNotification *)aNotification 
{ 
    // Insert code here to initialize your application 
    SInt32 idVendor = 0x1D34;//0x062A;//0x1d34; //0x1AAD; //// set vendor id 
    SInt32 idProduct = 0x000D;//0x0000;//0x000d; //0x000F; //// set product id 

    // Create an HID Manager 
    IOHIDManagerRef HIDManager = IOHIDManagerCreate(kCFAllocatorDefault, 
                kIOHIDOptionsTypeNone); 

    // Create a Matching Dictionary 
    CFMutableDictionaryRef matchDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 
                   2, 
                   &kCFTypeDictionaryKeyCallBacks, 
                   &kCFTypeDictionaryValueCallBacks); 

    // Specify a device manufacturer in the Matching Dictionary 

    CFDictionarySetValue(matchDict, 
         CFSTR(kIOHIDVendorIDKey), 
         CFNumberCreate(kCFAllocatorDefault, 
             kCFNumberSInt32Type, &idVendor)); 
    CFDictionarySetValue(matchDict, 
         CFSTR(kIOHIDProductKey), 
         CFNumberCreate(kCFAllocatorDefault, 
             kCFNumberSInt32Type, &idProduct)); 


    // Register the Matching Dictionary to the HID Manager 
    IOHIDManagerSetDeviceMatching(HIDManager, matchDict); 

    // Register a callback for USB device detection with the HID Manager 
    IOHIDManagerRegisterDeviceMatchingCallback(HIDManager, &Handle_DeviceMatchingCallback, NULL); 
    // Register a callback fro USB device removal with the HID Manager 
    IOHIDManagerRegisterDeviceRemovalCallback(HIDManager, &Handle_DeviceRemovalCallback, NULL); 

    // Register the HID Manager on our app’s run loop 
    IOHIDManagerScheduleWithRunLoop(HIDManager, CFRunLoopGetMain(), kCFRunLoopDefaultMode); 

    // Open the HID Manager 
    IOReturn IOReturn = IOHIDManagerOpen(HIDManager, kIOHIDOptionsTypeNone); 
    if(IOReturn) NSLog(@"IOHIDManagerOpen failed."); // Couldn't open the HID manager! TODO: proper error handling 
} 
@end 

Ich bin nicht einmal sicher, dass das Gerät etwas sendet ... Ich versuche Protokollierung USB Logger verwenden, in Stufe 7, aber nur die Taste drücken scheint nichts anzuzeigen ... wie kann ich stellen Sie sicher, dass es tatsächlich funktioniert?

UPDATE: Ich konnte Tasten drücken, die this Ruby Open Source project für den BigRedButton verwenden, den ich benutze, um das zu lernen. Ich weiß, dass es funktioniert. Ich habe auch meinen Code überarbeitet, um Wertänderungen nur dann zu registrieren, wenn das Gerät tatsächlich erkannt wird, und es zu entfernen, wenn das Gerät entfernt wird. Immer noch nichts an diesem Punkt.

UPDATE 2: Das funktioniert! Zwei Probleme ... Ich habe das Gerät nicht zum Lesen geöffnet und auch nicht das Gerät selbst auf dem aktuellen RunLoop registriert, das auch benötigt wird. Ein großartiges WWDC Video auf Userland Gerätezugriff von WWDC 2011 hat sehr geholfen. Ich muss auch sagen, dass die BigRedBUtton, die ich benutzt habe, vielleicht kein Standardgerät ist und das nie wie geplant funktioniert hat, aber das eigentliche Gerät, mit dem ich arbeiten wollte, funktioniert wie ein Zauber und gibt mir Input! Es ist also alles gut, dank der WWDC-Videos!

+0

Ich benutze tatsächlich den gleichen Stück Code, den Sie hier von Michael Dolinars Tutorial haben. Könnten Sie mir den Code-Teil, in dem Sie das Gerät öffnen (nicht nur den HID-Manager), senden oder mir vielleicht schicken und ihn dann zur Run-Schleife hinzufügen? Dies ist, wo ich derzeit gerade bin. –

+0

Eigentlich scratchen, dass ich sehe, was passiert ist, Ihre Codeblöcke wurden aufgebrochen und einige Teile sahen einfach wie Text aus. –

Antwort

4

Am Ende funktioniert der obige Code jetzt, dass ich das Gerät geöffnet und das Gerät auf dem aktuellen Runloop eingeplant habe. Außerdem ermöglichte das Wechseln von Geräten, mit einem anderen Gerät zu arbeiten, das eine berechenbare Erfahrung zu bieten scheint, die seine Werte verändert. Ich schlage jedem, der sich das anschaut, das Userland Device Access-Video von der WWDC 2011 zu betrachten, um zu verstehen, wie das funktioniert (ca. 30 Minuten in das Video)

UPDATE: Der Grund, warum Geräte anders reagieren, ist ein bisschen komplex. Erstens kann jedes USB-HID-Gerät mehrere "Konfigurationen" haben und eine Standard-HID-Einheit ist möglicherweise nicht aktiviert. Sie müssen dies explizit tun.Im zweiten Teil geht es dann darum, die Werte zu verstehen, die vom Gerät gesendet werden. Dies geschieht durch das Verständnis von "HID-Geräteberichtdeskriptoren", die im Detail jede Art von Wert beschreiben, der zurückgegeben wird (Berichte genannt) und wie seine Bits und Bytes angeordnet sind.

Auf OS X ist ein gutes Beispiel dafür die New HID Manager APIs for Mac OS X version 10.5 TechNote. Obwohl es auf 10.5 datiert, ist es die neueste Version davon und enthält alle entsprechenden Aufrufe und gibt ein besseres Verständnis davon, wie das alles funktioniert.

Auch um über Deskriptoren zu lernen, war this tutorial hilfreich.