it-swarm.com.de

HID-Berichtsdeskriptor für benutzerdefinierte HID-Geräte

Ich habe ein Problem mit dem Generieren des HID-Deskriptors. Ich möchte einfache Berichte mit ID1 für die Eingabe und ID2 für die Ausgabe mit 64 Byte Daten verwenden.

Mir wurde klar, dass ich trotz RTFming und Googeln immer noch keine Ahnung von einigen Feldern im HID-Deskriptor habe.

Kann mir jemand einen Hinweis oder ein Handbuch geben, in dem ich die Bedeutung aller Deskriptorfelder finden kann? Ich konnte nur Beispiele für HID-Maus/Joistick/Tastatur finden.

Zum Beispiel - REPORT_SIZE - ist die Größe in Bytes oder in Bits? Und warum gibt es auch REPORT_COUNT? Wenn ich 64 Bytes im Bericht habe, muss LOGICAL_MAXIMUM 255 oder 255 * 64 sein?

Soll ich für jeden Bericht LOGICAL_MAX und MIN schreiben oder nicht?

Oder vielleicht reicht diese (eher durch Vermutung erzeugte) aus?

char ReportDescriptor[39] = {
    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
    0x09, 0x00,                    // USAGE (Undefined)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x85, 0x01,                    //   REPORT_ID (1)
    0x09, 0x00,                    //   USAGE (Undefined)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x26, 0xff, 0x00,              //   LOGICAL_MAXIMUM (255)
    0x75, 0x40,                    //   REPORT_SIZE (64)
    0x96, 0x00, 0x02,              //   REPORT_COUNT (512)
    0x81, 0x82,                    //   INPUT (Data,Var,Abs,Vol)
    0x85, 0x02,                    //   REPORT_ID (2)
    0x09, 0x00,                    //   USAGE (Undefined)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x26, 0xff, 0x00,              //   LOGICAL_MAXIMUM (255)
    0x75, 0x40,                    //   REPORT_SIZE (64)
    0x96, 0x00, 0x02,              //   REPORT_COUNT (512)
    0x91, 0x82,                    //   OUTPUT (Data,Var,Abs,Vol)
    0xc0                           // END_COLLECTION
};
11
Amomum
  1. Die gesamte offizielle Dokumentation ist auf usb.org verfügbar. Um die HID-Berichtsbeschreibungen zu verstehen, müssen Sie einige der Dokumente auf der Seite HID Information lesen. Insbesondere sollten Sie versuchen zu verstehen:

    • Das Dokument "Geräteklassendefinition für HID 1.11" - beschreibt das Berichtsformat des Human Interface Device
    • Das Dokument "HID-Verwendungstabellen 1.12" - beschreibt die Werte vieler Verwendungsseiten und -verwendungen innerhalb der Seiten, die in einem Berichtsdeskriptor enthalten sein können

    Allerdings ist die Dokumentation bekanntermaßen stumpf und erfordert erhebliche Verdauungsarbeit.

  2. REPORT_SIZE ist die Größe eines Berichts in Bits und nicht in Bytes. Stellen Sie sich REPORT_SIZE als Breite eines Feldes (in Bits) und REPORT_COUNT als Anzahl der Felder (dieser Breite) vor. Dies wird im Dokument "Geräteklassendefinition für HID 1.11", Abschnitt 6.2.2.7 "Globale Elemente" wie folgt klargestellt:

    Global Item Tag     One-byte Prefix    Description
    Report Size         0111 01 nn         Unsigned integer specifying the size of the report
                                           fields in bits. This allows the parser to build an
                                           item map for the report handler to use. For more
                                           information, see Section 8: Report Protocol.
    
  3. Als Leitfaden dient ein vernünftiger (dh ich habe ihn nicht getestet) Berichtsdeskriptor, der einen 64-Byte-Eingabepuffer (für den Host mit einer REPORT_ID von 0x01) und einen 64-Byte-Ausgabepuffer (vom Host mit einer REPORT_ID von) beschreibt 0x02) könnte wie folgt sein:

      0x06, 0x00, 0xFF,            // (GLOBAL) USAGE_PAGE         0xFF00 Vendor-defined 
      0xA1, 0x01,                  // (MAIN)   COLLECTION         0x01 Application (Usage=0x0: Page=, Usage=, Type=) <-- Warning: USAGE type should be CA (Application)
      0x15, 0x00,                  //   (GLOBAL) LOGICAL_MINIMUM    0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0
      0x26, 0xFF, 0x00,            //   (GLOBAL) LOGICAL_MAXIMUM    0x00FF (255) 
      0x75, 0x08,                  //   (GLOBAL) REPORT_SIZE        0x08 (8) Number of bits per field 
      0x85, 0x01,                  //   (GLOBAL) REPORT_ID          0x01 (1) 
      0x95, 0x40,                  //   (GLOBAL) REPORT_COUNT       0x40 (64) Number of fields 
      0x09, 0x01,                  //   (LOCAL)  USAGE              0xFF000001  
      0x81, 0x02,                  //   (MAIN)   INPUT              0x00000002 (64 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 
      0x85, 0x02,                  //   (GLOBAL) REPORT_ID          0x02 (2) 
      0x09, 0x01,                  //   (LOCAL)  USAGE              0xFF000001  
      0x91, 0x02,                  //   (MAIN)   OUTPUT             0x00000002 (64 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 
      0xC0,                        // (MAIN)   END_COLLECTION     Application
    

    Welche den folgenden C-sprachigen Strukturdefinitionen entspricht:

    //--------------------------------------------------------------------------------
    // Vendor-defined inputReport 01 (Device --> Host)
    //--------------------------------------------------------------------------------
    
    typedef struct
    {
      uint8_t  reportId;                                 // Report ID = 0x01 (1)
      uint8_t  VEN_VendorDefined0001[64];                // FF00 0001  Value = 0 to 255
    } inputReport01_t;
    
    //--------------------------------------------------------------------------------
    // Vendor-defined outputReport 02 (Device <-- Host)
    //--------------------------------------------------------------------------------
    
    typedef struct
    {
      uint8_t  reportId;                                 // Report ID = 0x02 (2)
      uint8_t  VEN_VendorDefined0001[64];                // FF00 0001  Value = 0 to 255
    } outputReport02_t;
    
  4. Sollten Sie für jeden Bericht LOGICAL_MINIMUM und LOGICAL_MAXIMUM angeben? Nein. 

    Einige Elemente sind GLOBAL (dh, da der Berichtsdeskriptor sequentiell analysiert wird, bleiben ihre Werte, bis sie explizit von einem anderen GLOBAL-Element geändert werden) und andere sind LOCAL (was bedeutet, dass ihre Werte bei einem MAIN-Element auf die Standardwerte zurückgesetzt werden ). Sowohl LOGICAL_MINIMUM als auch LOGICAL_MAXIMUM sind GLOBAL-Elemente. Sie müssen also nur ihre Werte neu angeben, wenn der Wert geändert werden soll. Meiner Meinung nach wäre die Spezifikation klarer gewesen, wenn den offiziellen Namen für Elemente GLOBAL_, LOCAL_ und MAIN_ vorangestellt würden, aber leider müssen wir alle mit der Spezifikation in der vorliegenden Form leben.

  5. Das obige Beispiel wurde mit einem kostenlosen Tool in SourceForge namens hidrdd decodiert.

16
aja

Wie @aja bereits erwähnt hat, ist die offizielle USB-Dokumentation eher stumpf. Ich habe diese Vorlage (meistens mit Hilfe dieser Seite) als einfachen Ausgangspunkt für die Kommunikation mit einem benutzerdefinierten Board erstellt. Der HID-Code soll das Virtual COM Port-Protokoll ersetzen. Der große Vorteil von HID ist, dass kein Treiber benötigt wird.

uint8_t CUSTOM_HID_ReportDesc[REPORT_DESC_SIZE] =
{
   0x06, 0x00, 0xFF,    // Global  Usage page = 0xFF00 (Vendor-defined pages are in the range 0xFF00 through 0xFFFF)
   0x09, 0x01,          // Local   Usage (vendor usage 1)
   0xA1, 0x01,          // Main    Collection (application) begin
   0x15, 0x00,          // Global  Logical minimum (0) applies to each byte
   0x26, 0xFF, 0x00,    // Global  Logical maximum (255)
   0x75, 0x08,          // Global  Report Size (8 bits)

   // 14 bytes | Output message 1 (sent from Host to device)
   0x85,  1,            // Global  Report ID (cannot be 0)
   0x98, 64,            // Global  Report Count (number of Report Size fields, in this case 64 bytes)
   0x19, 0x01,          // Local   Usage Minimum (each Report Count must be associated with a Usage)
   0x19, 0x40,          // Local   Usage Maximum
   0x91, 0x02,          // Main    Output (data, array, absolute)

   // 24 bytes | Input message 1 (sent from device to Host)
   0x85,  1,            // Global  Report ID (cannot be 0)
   0x98, 64,            // Global  Report Count (number of Report Size fields)
   0x19, 0x01,          // Local   Usage Minimum (each Report Count must be associated with a Usage)
   0x19, 0x40,          // Local   Usage Maximum
   0x81, 0x02,          // Main    Input (data, array, absolute)

   // 34 bytes | Output message 2 (sent from Host to device)
   0x85,  2,            // Global  Report ID (cannot be 0)
   0x98, 12,            // Global  Report Count (number of Report Size fields)
   0x19, 0x01,          // Local   Usage Minimum (each Report Count must be associated with a Usage)
   0x19, 0x40,          // Local   Usage Maximum
   0x91, 0x02,          // Main    Output (data, array, absolute)

   // 44 bytes | Input message 2 (sent from device to Host)
   0x85,  2,            // Global  Report ID (cannot be 0)
   0x98, 57,            // Global  Report Count (number of Report Size fields)
   0x19, 0x01,          // Local   Usage Minimum (each Report Count must be associated with a Usage)
   0x19, 0x40,          // Local   Usage Maximum
   0x81, 0x02,          // Main    Input (data, array, absolute)

   // 54 bytes | End (add one byte)
   0xC0                 // Main    Collection (application) end
}

Ein paar Dinge zu beachten:

  • Weitere Eingabe-/Ausgabepaare können problemlos hinzugefügt werden: Geben Sie ihnen einfach eine andere Berichts-ID. Jede Nachrichtendefinition besteht aus 10 Bytes, so dass es einfach ist, sie zu addieren.
  • Wir verfolgen die Anzahl der Bytes im Deskriptor, damit die Größe des Arrays berechnet werden kann (#define REPORT_DESC_SIZE (55)).

Auf der Windows-Seite verwende ich Mike O'Briens HIDLibrary . HID-Berichten werden normalerweise die Berichts-ID vorangestellt. Verwenden Sie in HIDLibrary das Feld HidReport.ReportID, um den Wert festzulegen/abzurufen. Denken Sie auf der Platinen-Seite daran, dass das erste Byte des Berichts die Berichts-ID ist.

6
D. Shinobi

Ich habe mein benutzerdefiniertes verstecktes Gerät von Win7 erkannt (erstellt durch Vermutung und Stehlen von Beispielen):

{
    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
    0x09, 0x00,                    // USAGE (Undefined)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x26, 0xff, 0x00,              //   LOGICAL_MAXIMUM (255)
    0x85, 0x01,                    //   REPORT_ID (1)
    0x75, 0x08,                    //   REPORT_SIZE (8)
    0x95, 0x40,                    //   REPORT_COUNT (64)
    0x09, 0x00,                    //   USAGE (Undefined)
    0x81, 0x82,                    //   INPUT (Data,Var,Abs,Vol) - to the Host
    0x85, 0x02,                    //   REPORT_ID (2)
    0x75, 0x08,                    //   REPORT_SIZE (8)
    0x95, 0x40,                    //   REPORT_COUNT (64)
    0x09, 0x00,                    //   USAGE (Undefined)
    0x91, 0x82,                    //   OUTPUT (Data,Var,Abs,Vol) - from the Host
    0xc0                           // END_COLLECTION
}; /* CustomHID_ReportDescriptor */

Ich bin mir nicht sicher, ob es richtig funktioniert. Werden sehen.

2
Amomum

Hier ist ein Link zum Spec Sheet (oder "Handbuch") für Ihre Lesezwecke.

Um einige Ihrer Fragen zu beantworten, wird REPORT_SIZE in Bits angegeben, und mit REPORT_COUNT kann angegeben werden, wie viele "Usages" mit den angegebenen Eigenschaften gemeldet werden. Sie können beispielsweise die Eigenschaften für die Verwendungen X und Y festlegen und den REPORT_COUNT als 2 angeben (einen für X und einen für Y) und dann die INPUT angeben, um diese Verwendungen dem Bericht hinzuzufügen. Beschreiben Sie dann weitere Verwendungen.

Vergessen Sie auch nicht, dass die Bytes für die Verwendung ausgerichtet sind. Da REPORT_COUNT in Bits angegeben wird, ist es leicht zu vergessen, dass die Bytes für die Verwendung ausgerichtet sind. Wenn eine Verwendung nur 1 Bit ist, müssen Sie also angeben, dass in diesem Byte 7 Bits nicht verwendet werden, bevor Sie zur nächsten Verwendung wechseln, wenn mehr als 7 Bits erforderlich sind.

0
Chef Pharaoh