J'ai un problème avec la génération du descripteur HID . Je souhaite utiliser des rapports simples avec ID1 pour entrée et ID2 pour sortie avec 64 octets de données.
J'ai réalisé que malgré rtfming et googling, je n'ai toujours aucune idée de certains champs dans le descripteur HID.
Quelqu'un peut-il me donner s'il vous plaît un indice ou un manuel où je peux trouver la signification de tous les champs de descripteur? Tout ce que j'ai pu trouver, ce sont des exemples pour HID-mouse/joistick/keyboard.
Par exemple - REPORT_SIZE - sa taille est-elle exprimée en octets ou en bits? Et pourquoi il y a aussi REPORT_COUNT? Si le rapport contient 64 octets, LOGICAL_MAXIMUM doit être 255 ou 255 * 64?
Devrais-je écrire LOGICAL_MAX et MIN pour chaque rapport ou pas?
Ou peut-être que celui-ci (généré plutôt en devinant) suffira?
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
};
Toute la documentation officielle est disponible sur usb.org. Pour comprendre les descripteurs de rapport HID, vous devez lire certains des documents situés sur la page Informations HID . En particulier, vous devriez essayer de comprendre:
Cela dit, la documentation est notoirement obtuse et nécessitera des efforts considérables pour être digérée.
REPORT_SIZE est la taille d'un rapport en bits et non en octets. Reportez-vous à REPORT_SIZE en tant que largeur d'un champ (en bits) et à REPORT_COUNT en tant que nombre de champs (de cette largeur). Cela apparaît clairement dans le document "Définition de la classe d'unités pour HID 1.11", au paragraphe 6.2.2.7 "Éléments globaux", comme suit:
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.
À titre indicatif, un descripteur de rapport raisonnable (c’est-à-dire que je ne l’ai pas testé) décrit un tampon d’entrée de 64 octets (pour l’hôte avec un REPORT_ID égal à 0x01) et un tampon de sortie de 64 octets (de l’hôte avec un REPORT_ID de 0x02) pourrait être comme suit:
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
Ce qui correspond aux définitions de structure de langage C suivantes:
//--------------------------------------------------------------------------------
// 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;
Devez-vous spécifier LOGICAL_MINIMUM et LOGICAL_MAXIMUM pour chaque rapport? Non.
Certains éléments sont GLOBAL (ce qui signifie que, le descripteur de rapport étant analysé séquentiellement, leurs valeurs demeurent jusqu'à ce qu'ils soient explicitement modifiés par un autre élément GLOBAL) et d'autres sont LOCAL (ce qui signifie que leurs valeurs sont réinitialisées à leurs valeurs par défaut lorsqu'un élément PRINCIPAL est rencontré. ) LOGICAL_MINIMUM et LOGICAL_MAXIMUM sont des éléments GLOBAUX. Vous devez donc spécifier à nouveau leurs valeurs si vous souhaitez que la valeur change. À mon avis, la spécification aurait été plus claire si les noms officiels des éléments avaient été préfixés par GLOBAL_, LOCAL_ et MAIN_, mais malheureusement, nous devons tous vivre avec la spécification telle quelle.
L'exemple ci-dessus a été décodé à l'aide d'un outil gratuit sur SourceForge appelé hidrdd
Comme @aja l'a indiqué ci-dessus, la documentation USB officielle est plutôt obtuse. J'ai créé ce modèle (principalement avec l'aide de cette page) comme simple point de départ pour communiquer avec un forum personnalisé. Le code HID est destiné à remplacer le protocole du port COM virtuel. Le gros avantage de HID est qu'aucun pilote n'est requis.
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
}
Quelques points à noter:
#define REPORT_DESC_SIZE (55)
).Du côté de Windows, j'utilise Mike O'Brien's HIDLibrary . Les rapports HID sont généralement précédés de l'ID du rapport - dans HIDLibrary, utilisez le champ HidReport.ReportID
pour définir/obtenir la valeur. Du côté du tableau, rappelez-vous que le premier octet du rapport sera l'identifiant du rapport.
J'ai mon appareil caché personnalisé détecté par Win7 avec ceci (construit par deviner et voler des exemples):
{
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 */
Je ne sais pas si cela fonctionnera correctement. Va voir.
Voici un lien vers la Spec Sheet (ou "manuel") à des fins de lecture.
Pour répondre à certaines de vos questions, REPORT_SIZE
est spécifié en bits et REPORT_COUNT
peut être utilisé pour spécifier le nombre d '"Usages" signalés avec les propriétés indiquées. Par exemple, vous pouvez définir les propriétés pour les utilisations X
et Y
et définir le REPORT_COUNT
en tant que 2 (un pour X et un pour Y), puis spécifier la INPUT
pour ajouter ces utilisations au rapport. Continuez ensuite à décrire d'autres usages.
De plus, n'oubliez pas que les utilisations sont alignées. Puisque REPORT_COUNT
est spécifié en bits, il est facile d’oublier d’aligner les utilisations sur des octets. Ainsi, si une utilisation ne fait que 1 bit, vous devez spécifier que cet octet ne contiendra pas 7 bits avant de passer à la prochaine utilisation si elle nécessite plus de 7 bits.