2013-12-15 6 views
5

Sto cercando di afferrare IOKit e mi sento vicino, ma non ancora. Quindi scusa la mia confusione.Ottenere la richiamata usando IOKit usando un punto di interruzione dell'ingresso

Sono riuscito a scrivere codice che rileva il mio dispositivo USB (un semplice pulsante all'estremità di un cavo USB che ha un driver Windows, ma nessun driver Mac).

Sto cercando di ottenere una sorta di richiamata quando si preme il pulsante.

Sono in grado di ottenere una richiamata quando il dispositivo è collegato a USB o rimosso. Ora, sto cercando di scoprire come essere informato quando si preme il pulsante, ma non riesco a capirlo. La documentazione mi confonde molto, poiché IOKit sembra essere disponibile sia in C++ che in c, a seconda di come lo si accede (estensione del kernel o driver dello spazio utente o qualcosa di simile.)

Ho provato ad aggiungere un paio di metodi per ottenere una richiamata quando un valore di Interrupt cambia come vedrai nel codice. Ma non succede nulla

Ecco il mio file AppDelegate.m corrente e le informazioni della sonda USB sul . dispositivo

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 

Il file App Delegate.m:

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

// dovrebbe verificare per gli errori qui ...

IOHIDDeviceRegisterInputValueCallback(inIOHIDDeviceRef, Handle_IOHIDDeviceInputValueCallback, NULL); 

// Deve anche registrare per runloop di nuovo qui ... mancava anche IOHIDDeviceScheduleWithRunLoop (inIOHIDDeviceRef, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);

} 

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 

Non sono nemmeno sicuro che il dispositivo sta inviando niente ... prova ad accedere Utilizzando Logger USB, a livello 7, ma solo premendo il tasto non sembra visualizza nulla ... come posso assicurati che funzioni effettivamente?

AGGIORNAMENTO: è stato possibile rilevare le pressioni dei pulsanti utilizzando this Ruby Open Source project per il BigRedButton che sto usando per apprendere questo. Quindi so che funziona davvero. Ho anche rielaborato il mio codice per registrare le modifiche del valore solo quando il dispositivo viene effettivamente rilevato e rimuovendolo quando il dispositivo viene rimosso. Ancora niente a questo punto.

AGGIORNAMENTO 2: ha funzionato! Due problemi ... Non stavo aprendo il dispositivo per la lettura, e anche non registrando il dispositivo stesso su Current RunLoop che è anche richiesto. Un grande video WWDC sull'accesso ai dispositivi Userland da WWDC 2011 ha aiutato molto. Devo anche dire che il BigRedBUtton che stavo usando forse non è un dispositivo abbastanza standard e che non ha mai funzionato come piallato, ma il dispositivo reale con cui volevo lavorare funziona come un incantesimo e mi sta dando dei suggerimenti! Quindi va tutto bene ora, grazie ai video del WWDC!

+0

Sto effettivamente utilizzando lo stesso pezzo di codice che hai qui dal tutorial di Michael Dolinars. Potresti pubblicare o forse mandarmi il pezzo di codice in cui apri il dispositivo (non solo il gestore HID) e aggiungerlo al ciclo di esecuzione? Questo è il posto in cui sono attualmente bloccato al momento. –

+0

In realtà non riesco a capire che cosa è successo, i blocchi di codice sono stati suddivisi e alcune parti di esso sembravano solo testo. –

risposta

4

Alla fine, il codice sopra funziona ora che ho aperto il dispositivo e pianificato il dispositivo sul runloop corrente. Inoltre, cambiare dispositivo mi ha permesso di lavorare con un altro dispositivo che sembra offrire un'esperienza più prevedibile cambiando i suoi valori. Suggerisco a tutti coloro che lo guardano di guardare il video Userland Device Access dal WWDC 2011 per capire come funziona (circa 30 minuti nel video)

AGGIORNAMENTO: Il motivo per cui i dispositivi reagiscono in modo diverso è un po 'complesso. Innanzitutto, ogni dispositivo HID USB può avere più "Configurazioni" e uno di default potrebbe non essere abilitato. Devi farlo esplicitamente.Quindi, la seconda parte riguarda la comprensione dei valori inviati dal dispositivo. Ciò avviene attraverso la comprensione dei "Descrittori dei report dei dispositivi HID" che descrivono in dettaglio ogni tipo di valore restituito (chiamato report) e come sono disposti i bit e i byte.

Su OS X un'ottima lettura per questo è la nota tecnica New HID Manager APIs for Mac OS X version 10.5. Anche se risale a 10.5, è l'ultima versione di questo e contiene tutte le chiamate appropriate e offre una migliore comprensione di come funziona tutto questo.

Inoltre, per informazioni sui descrittori, this tutorial è stato utile.

Problemi correlati