2013-12-15 9 views
5

Próbuję uzyskać zrozumienie dla IOKit i czuję, że jestem blisko, ale jeszcze nie. Więc przepraszam za zamieszanie.Uzyskaj oddzwonienie za pomocą IOKit za pomocą punktu przerwania Input Endpoint

Udało mi się napisać kod, który wykrywa moje urządzenie USB (prosty przycisk na końcu kabla USB z sterownikiem Windows, ale bez sterownika Mac).

Próbuję uzyskać jakieś wywołanie zwrotne po naciśnięciu przycisku.

Udało mi się uzyskać wywołanie zwrotne, gdy urządzenie jest podłączone do USB lub usunięte. Teraz próbuję dowiedzieć się, jak uzyskać informacje, gdy przycisk jest wciśnięty, ale nie mogę tego rozgryźć. Dokumentacja jest dla mnie bardzo kłopotliwa, ponieważ wydaje mi się, że IOKit jest dostępny zarówno w języku C++, jak i c, w zależności od tego, w jaki sposób uzyskuje się do niego dostęp (rozszerzenie jądra lub sterownik przestrzeni użytkownika, lub coś podobnego.) Nie jestem pewien, czy mam właściwą terminologię:

Próbowałem dodać kilka metod, aby uzyskać wywołanie zwrotne, gdy jakakolwiek wartość przerwania zmieni się, jak widać w kodzie, ale nic się nie dzieje

Oto mój obecny plik AppDelegate.m, a także informacje o sondzie USB na . urządzenie

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 

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

// powinien sprawdzić błędu tutaj ...

IOHIDDeviceRegisterInputValueCallback(inIOHIDDeviceRef, Handle_IOHIDDeviceInputValueCallback, NULL); 

// Musi również rejestrować RunLoop znowu tutaj ... również brakuje 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 

Nie jestem nawet pewien, urządzenie wysyła niczego ... Staram zalogowaniu Korzystanie Logger USB, na poziomie 7, ale tylko naciśnięcie przycisku wydaje się nie wyświetla niczego ... jak mogę upewnić się, że faktycznie działa?

AKTUALIZACJA: Był w stanie wykryć naciśnięcia przycisków za pomocą this Ruby Open Source project dla BigRedButton, którego używam, aby się tego nauczyć. Więc wiem, że to działa. Przebudowałem również mój kod, aby rejestrować zmiany wartości tylko wtedy, gdy urządzenie zostanie wykryte i usunięte po usunięciu urządzenia. Wciąż nic w tym momencie.

AKTUALIZACJA 2: Gotowe! Dwa problemy ... Nie otwierałem urządzenia do czytania, a także nie rejestrowałem samego urządzenia w bieżącej RunLoop, która jest również wymagana. Świetny film WWDC na temat dostępu do urządzenia Userland z WWDC 2011 znacznie pomógł. Muszę też powiedzieć, że BigRedBUtton, którego używałem, nie jest całkiem standardowym urządzeniem i nigdy nie działało jak zaplanowane, ale rzeczywiste urządzenie, z którym chciałem pracować, działa jak urok i daje mi dane wejściowe! Teraz wszystko jest dobrze, dzięki filmom z WWDC!

+0

Używam tego samego fragmentu kodu, który masz tutaj z samouczka Michaela Dolinarsa. Czy mógłbyś opublikować lub może wysłać mi fragment kodu, w którym otwierasz urządzenie (nie tylko menedżera HID), a następnie dodać go do pętli uruchamiania? To jest miejsce, w którym ja sam obecnie utknąłem. –

+0

Właściwie to podrapałem się, że widzę, co się stało, twoje bloki kodu zostały zerwane, a niektóre jego części wyglądały po prostu jak tekst. –

Odpowiedz

4

W końcu powyższy kod działa teraz, gdy już otworzyłem urządzenie i zaplanowałem urządzenie na bieżącym uruchomieniu. Zmieniające się urządzenia pozwoliły mi również na pracę z innym urządzeniem, które wydaje się bardziej przewidywalne, zmieniając jego wartości. Sugeruję, aby każdy, kto się tym zajmie, obejrzał wideo z Userland Device Access z WWDC 2011, aby dowiedzieć się, jak to działa (około 30 minut filmu).

AKTUALIZACJA: Przyczyna, dla której urządzenia reagują inaczej, jest nieco skomplikowana. Po pierwsze, każde urządzenie USB HID może mieć wiele "Konfiguracji", a domyślne może nie być włączone. Musisz to wyraźnie zrobić.Druga część polega na zrozumieniu wartości przesyłanych z urządzenia. Odbywa się to poprzez zrozumienie "Deskryptorów raportów urządzeń HID", które szczegółowo opisują każdy rodzaj zwracanej wartości (zwanych raportami) oraz sposób rozmieszczenia jej bitów i bajtów.

Na OS X świetną lekturą jest New HID Manager APIs for Mac OS X version 10.5 TechNote. Mimo że pochodzi z wersji 10.5, jest to najnowsza wersja i zawiera wszystkie odpowiednie wywołania oraz zapewnia lepsze zrozumienie, jak to wszystko działa.

Pomocna była także informacja o deskryptorach: this tutorial.

Powiązane problemy