Protocole HID du coach électronique

Le protocole HID (Human Interface Device) du traceur de tête, disponible pour les appareils équipés d'Android 13 ou version ultérieure, permet de connecter un traceur de tête à un appareil Android via USB ou Bluetooth, et de l'exposer au framework et aux applications Android via le framework sensors. Ce protocole est utilisé pour contrôler un effet de virtualisation audio (audio 3D). Cette page utilise les termes appareil et hôte dans leur sens du Bluetooth, où appareil désigne l'appareil de suivi de la tête et hôte correspond à l'hôte Android.

Les fabricants d'appareils doivent configurer leurs appareils Android de façon à activer la prise en charge du protocole HID du coach électronique. Pour en savoir plus sur la configuration, consultez le fichier README des capteurs dynamiques.

Cette page suppose que vous connaissez les ressources suivantes:

Structure de premier niveau

Le framework Android identifie le dispositif de suivi de la tête comme un dispositif HID.

Pour obtenir un exemple complet de descripteur HID valide, consultez l'Annexe 1: Exemple de descripteur HID.

Au niveau supérieur, l'appareil de suivi de la tête est une collection d'applications avec la page Sensors (0x20) et l'utilisation de Other: Custom (0xE1). Cette collection contient plusieurs champs de données (entrées) et des propriétés (fonctionnalités).

Propriétés et champs de données

Cette section décrit les propriétés et les champs de données d'une collection d'applications d'un appareil de suivi de la tête.

Propriété : Description du capteur (0x0308)

La propriété de description du capteur (0x0308) est une propriété de chaîne ASCII (8 bits) en lecture seule qui doit contenir les valeurs suivantes:

Suiveur de tête version 1.0 :

#AndroidHeadTracker#1.0

Suiveur de tête version 2.0 (disponible sous Android 15 ou version ultérieure), qui est compatible avec l'audio LE :

#AndroidHeadTracker#2.0#x

x est un entier (1, 2, 3) indiquant le transport accepté:

  • 1 : LCA
  • 2: ISO
  • 3: LCA + ISO

Aucun terminal de valeur nulle n'est attendu, ce qui signifie que la taille totale de cette propriété est de 23 caractères de 8 bits pour la version 1.0.

Cette propriété sert de discriminateur pour éviter les collisions avec d'autres capteurs personnalisés.

Propriété : ID unique persistant (0x0302)

La propriété ID unique persistant (0x0302) est un tableau en lecture seule de 16 éléments, chacun de 8 bits (128 bits au total). Aucun terminaison nulle n'est attendu. Cette propriété est facultative.

Cette propriété permet aux appareils de suivi de la tête intégrés aux appareils audio de faire référence à l'appareil audio auquel ils sont connectés. Les schémas suivants sont acceptés.

Moniteur de tête autonome

Si la propriété d'identifiant unique persistant (0x0302) n'existe pas ou est définie sur tous les zéros, cela signifie que l'appareil de suivi de la tête n'est pas associé de manière permanente à un appareil audio et qu'il peut être utilisé séparément, par exemple en permettant à l'utilisateur d'associer manuellement l'appareil de suivi de la tête à un appareil audio distinct.

Référence utilisant une adresse MAC Bluetooth

Octet 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Valeur 0 0 0 0 0 0 0 0 B T Adresse MAC Bluetooth

Dans ce schéma, les huit premiers octets doivent être 0, les octets 8 et 9 doivent contenir respectivement les valeurs ASCII B et T, et les six octets suivants sont interprétés comme une adresse MAC Bluetooth, en supposant que le head tracker s'applique à tout appareil audio disposant de cette adresse MAC. Il doit s'agir de l'adresse d'identité, même si l'appareil utilise une adresse MAC aléatoire pour établir les connexions. Les appareils double mode se connectant via Bluetooth classique (format HID v1.0) et Bluetooth LE (format HID v2.0) doivent exposer deux descripteurs HID avec la même adresse d'identité. Les appareils dual-mode avec des appareils gauche et droit distincts doivent exposer le HID Bluetooth LE à l'aide de l'appareil dual-mode principal au lieu de l'appareil secondaire LE uniquement.

Référence utilisant un UUID

Chaque fois que le bit de poids fort (MSB) de l'octet 8 est défini (≥0x80), le champ est interprété comme un UUID, comme spécifié dans la RFC 4122. L'appareil audio correspondant fournit le même UUID, qui est enregistré sur le framework Android, via un mécanisme non spécifié spécifique au type de transport utilisé.

Propriété : État des rapports (0x0316)

La propriété d'état de rapport (0x0316) est une propriété en lecture/écriture qui présente la sémantique standard définie dans la spécification HID. L'hôte utilise cette propriété pour indiquer à l'appareil les événements à signaler. Seules les valeurs "Aucun événement" (0x0840) et "Tous les événements" (0x0841) sont utilisées.

La valeur initiale de ce champ doit être "Aucun événement" et ne doit jamais être modifiée par l'appareil, mais uniquement par l'hôte.

Propriété: état de l'alimentation (0x0319)

La propriété d'état de l'alimentation (0x0319) est une propriété en lecture/écriture qui possède la sémantique standard définie dans la spécification HID. L'hôte utilise cette propriété pour indiquer à l'appareil l'état d'alimentation dans lequel il doit se trouver. Seules les valeurs Pleine puissance (0x0851) et Éteindre (0x0855) sont utilisées.

La valeur initiale de ce champ est déterminée par l'appareil et ne doit jamais être modifiée par celui-ci, mais uniquement par l'hôte.

Propriété : Intervalle de rapport (0x030E)

La propriété Intervalle de rapport (0x030E) est une propriété en lecture/écriture qui possède la sémantique standard définie dans la spécification HID. L'hôte utilise cette propriété pour indiquer à l'appareil la fréquence à laquelle il doit signaler ses lectures de données. Les unités sont exprimées en secondes. La plage valide pour cette valeur est déterminée par l'appareil et décrite à l'aide du mécanisme Min/Max physique. Un taux de signalement d'au moins 50 Hz doit être pris en charge, et le taux de signalement maximal recommandé est de 100 Hz. Par conséquent, l'intervalle de signalement minimal doit être inférieur ou égal à 20 ms, et il est recommandé qu'il soit supérieur ou égal à 10 ms.

Propriété: LE Transport réservé par le fournisseur (0xF410)

La propriété LE Transport (0xF410) réservée par le fournisseur est une propriété en lecture/écriture qui présente la sémantique standard définie dans la spécification HID. L'hôte utilise cette propriété pour indiquer le transport sélectionné (ACL ou ISO). Seules les valeurs ACL (0xF800) et ISO (0xF801) sont utilisées, et les deux doivent être incluses dans la collection logique.

Cette propriété est configurée avant les états d'alimentation ou de création de rapports.

Champ de données: valeur personnalisée 1 (0x0544)

Le champ Valeur personnalisée 1 (0x0544) est un champ de saisie utilisé pour enregistrer les informations de suivi de la tête réelles. Il s'agit d'un tableau à trois éléments, interprété selon les règles HID normales applicables aux valeurs physiques, comme spécifié dans la section 6.2.2.7 de la spécification HID. La plage valide pour chaque élément est [-π, π] rad. Les unités sont toujours des radians.

Les éléments sont interprétés comme suit : [rx, ry, rz], de sorte que [rx, ry, rz] soit un vecteur de rotation, représentant la transformation du cadre de référence au cadre de tête. La magnitude doit être comprise dans la plage [0, π].

La trame de référence est arbitraire, mais elle est généralement fixe et doit être droite. Une légère dérive est acceptable. Les axes de la tête sont les suivants :

  • X de l'oreille gauche à la droite
  • Y de l'arrière de la tête jusqu'au nez (de l'arrière vers l'avant)
  • Z du cou jusqu'au haut de la tête

Champ de données: valeur personnalisée 2 (0x0545)

Le champ "Valeur personnalisée 2" (0x0545) est un champ de saisie utilisé pour générer des rapports sur les informations réelles de suivi des mouvements de la tête. Il s'agit d'un tableau à trois éléments à virgule fixe, interprété selon les règles HID normales pour les valeurs physiques. Les unités sont toujours exprimées en radians par seconde.

Les éléments sont interprétés comme suit : [vx, vy, vz], de sorte que [vx, vy, vz] soit un vecteur de rotation représentant la vitesse angulaire du cadre de la tête (par rapport à lui-même).

Champ de données: valeur personnalisée 3 (0x0546)

Le champ Valeur personnalisée 3 (0x0546) est un champ de saisie utilisé pour suivre les discontinuités dans le cadre de référence. C'est un entier scalaire de 8 bits. Il doit être incrémenté (avec retour à zéro) par l'appareil chaque fois que le frame de référence est modifié, par exemple si l'état d'un algorithme de filtre d'orientation utilisé pour déterminer l'orientation a été réinitialisé. Cette valeur est interprétée conformément aux règles HID normales pour les valeurs physiques. Toutefois, la valeur physique et les unités n'ont pas d'importance. La seule information pertinente pour l'hôte est une valeur modifiée. Pour éviter les problèmes numériques liés à la perte de précision lors de la conversion d'unités logiques en unités physiques, nous vous recommandons de définir les valeurs minimale et maximale physique ainsi que l'exposant unitaire sur zéro pour ce champ.

Structure du rapport

Le regroupement des propriétés dans des rapports (en attribuant des ID de rapport) est flexible. Pour plus d'efficacité, nous vous recommandons de séparer les propriétés de lecture seule des propriétés de lecture/écriture.

Pour les champs de données, les champs "Valeur personnalisée 1", "2" et "3" doivent figurer dans le même rapport et figurer dans un seul rapport pour un appareil donné (collection d'applications).

Envoyer les rapports d'entrée

L'appareil doit envoyer des rapports d'entrée régulièrement et de manière asynchrone (via des messages HID INPUT) lorsque toutes ces conditions sont remplies:

  • La propriété "État de l'alimentation" est définie sur "Full Power" (Alimentation complète).
  • La propriété "État des rapports" est définie sur "Tous les événements".
  • La propriété "Reporting Interval" (Intervalle de création de rapports) n'est pas nulle.

La propriété "Intervalle entre les rapports" détermine la fréquence d'envoi des rapports. Lorsque l'une des conditions ci-dessus n'est pas remplie, l'appareil ne doit pas envoyer de rapports.

Rétrocompatibilité et compatibilité ascendante

Le protocole HID du suivi de la tête utilise un schéma de gestion des versions qui permet les mises à jour, tout en permettant l'interopérabilité entre un hôte et un appareil qui utilisent différentes versions du protocole. Les versions du protocole sont identifiées par deux nombres, majeur et mineur, qui ont une sémantique distincte, comme décrit dans les sections suivantes.

Les versions compatibles avec un appareil peuvent être déterminées en examinant sa propriété "Description du capteur" (0x0308).

Compatibilité des versions mineures

Les modifications apportées à la version mineure sont rétrocompatibles avec les versions mineures précédentes basées sur la même version majeure. Dans les mises à jour de la version mineure, l'hôte ignore les champs de données et les propriétés supplémentaires. Par exemple, un appareil utilisant la version 1.6 du protocole est compatible avec un hôte compatible avec la version 1.x du protocole, y compris la version 1.5.

Compatibilité des versions majeures

Les modifications non rétrocompatibles sont autorisées pour les versions majeures. Pour prendre en charge plusieurs versions majeures de l'interopérabilité avec les anciens et les nouveaux hôtes, les appareils peuvent spécifier plusieurs collections d'applications dans leurs descripteurs de rapport. Exemple :

const unsigned char ReportDescriptor[] = {
    HID_USAGE_PAGE_SENSOR,
    HID_USAGE_SENSOR_TYPE_OTHER_CUSTOM,

    HID_COLLECTION(HID_APPLICATION),
        // Feature report 2 (read-only).
        HID_REPORT_ID(2),

        // Magic value: "#AndroidHeadTracker#1.5"
        HID_USAGE_SENSOR_PROPERTY_SENSOR_DESCRIPTION,
        HID_LOGICAL_MIN_8(0),
        HID_LOGICAL_MAX_8(0xFF),
        HID_REPORT_SIZE(8),
        HID_REPORT_COUNT(23),
        HID_FEATURE(HID_CONST_VAR_ABS),

      ...

    HID_END_COLLECTION,

    HID_COLLECTION(HID_APPLICATION),
        // Feature report 12 (read-only).
        HID_REPORT_ID(12),

        // Magic value: "#AndroidHeadTracker#2.4"
        HID_USAGE_SENSOR_PROPERTY_SENSOR_DESCRIPTION,
        HID_LOGICAL_MIN_8(0),
        HID_LOGICAL_MAX_8(0xFF),
        HID_REPORT_SIZE(8),
        HID_REPORT_COUNT(23),
        HID_FEATURE(HID_CONST_VAR_ABS),

      ...

    HID_END_COLLECTION,
};

Dans ce cas, l'hôte peut énumérer toutes les différentes collections d'applications annoncées par l'appareil, en examinant leur propriété "Sensor Description" pour déterminer les versions de protocole qu'elles implémentent chacune, puis en sélectionnant la dernière version de protocole compatible avec l'hôte. Lorsqu'il est sélectionné, l'hôte fonctionne avec le protocole unique choisi pour toute la durée de vie de la connexion de l'appareil.

Annexe: Exemple de descripteur HID

L'exemple suivant illustre un descripteur HID valide type. Il reprend les macros C couramment utilisées, fournies dans la section Utilisations du capteur HID (section 4.1).

const unsigned char ReportDescriptor[] = {
    HID_USAGE_PAGE_SENSOR,
    HID_USAGE_SENSOR_TYPE_OTHER_CUSTOM,
    HID_COLLECTION(HID_APPLICATION),
        // Feature report 2 (read-only).
        HID_REPORT_ID(2),

        // Magic value: "#AndroidHeadTracker#1.0"
        HID_USAGE_SENSOR_PROPERTY_SENSOR_DESCRIPTION,
        HID_LOGICAL_MIN_8(0),
        HID_LOGICAL_MAX_8(0xFF),
        HID_REPORT_SIZE(8),
        HID_REPORT_COUNT(23),
        HID_FEATURE(HID_CONST_VAR_ABS),

        // UUID.
        HID_USAGE_SENSOR_PROPERTY_PERSISTENT_UNIQUE_ID,
        HID_LOGICAL_MIN_8(0),
        HID_LOGICAL_MAX_8(0xFF),
        HID_REPORT_SIZE(8),
        HID_REPORT_COUNT(16),
        HID_FEATURE(HID_CONST_VAR_ABS),

        // Feature report 1 (read/write).
        HID_REPORT_ID(1),

        // 1-bit on/off reporting state.
        HID_USAGE_SENSOR_PROPERTY_REPORTING_STATE,
        HID_LOGICAL_MIN_8(0),
        HID_LOGICAL_MAX_8(1),
        HID_REPORT_SIZE(1),
        HID_REPORT_COUNT(1),
        HID_COLLECTION(HID_LOGICAL),
            HID_USAGE_SENSOR_PROPERTY_REPORTING_STATE_NO_EVENTS,
            HID_USAGE_SENSOR_PROPERTY_REPORTING_STATE_ALL_EVENTS,
            HID_FEATURE(HID_DATA_ARR_ABS),
        HID_END_COLLECTION,

        // 1-bit on/off power state.
        HID_USAGE_SENSOR_PROPERTY_POWER_STATE,
        HID_LOGICAL_MIN_8(0),
        HID_LOGICAL_MAX_8(1),
        HID_REPORT_SIZE(1),
        HID_REPORT_COUNT(1),
        HID_COLLECTION(HID_LOGICAL),
            HID_USAGE_SENSOR_PROPERTY_POWER_STATE_D4_POWER_OFF,
            HID_USAGE_SENSOR_PROPERTY_POWER_STATE_D0_FULL_POWER,
            HID_FEATURE(HID_DATA_ARR_ABS),
        HID_END_COLLECTION,

        // 6-bit reporting interval, with values [0x00..0x3F] corresponding to [10ms..100ms].
        HID_USAGE_SENSOR_PROPERTY_REPORT_INTERVAL,
        HID_LOGICAL_MIN_8(0x00),
        HID_LOGICAL_MAX_8(0x3F),
        HID_PHYSICAL_MIN_8(10),
        HID_PHYSICAL_MAX_8(100),
        HID_REPORT_SIZE(6),
        HID_REPORT_COUNT(1),
        HID_USAGE_SENSOR_UNITS_SECOND,
        HID_UNIT_EXPONENT(0xD),  // 10^-3
        HID_FEATURE(HID_DATA_VAR_ABS),

        // Input report 1

        // Orientation as rotation vector (scaled to [-pi..pi] rad).
        HID_USAGE_SENSOR_DATA_CUSTOM_VALUE_1,
        HID_LOGICAL_MIN_16(0x01, 0x80), // LOGICAL_MINIMUM (-32767)
        HID_LOGICAL_MAX_16(0xFF, 0x7F), // LOGICAL_MAXIMUM (32767)
        HID_PHYSICAL_MIN_32(0x60, 0x4F, 0x46, 0xED),  // -314159265
        HID_PHYSICAL_MAX_32(0xA1, 0xB0, 0xB9, 0x12),  // 314159265
        HID_UNIT_EXPONENT(0x08),  // 10^-8
        HID_REPORT_SIZE(16),
        HID_REPORT_COUNT(3),
        HID_INPUT(HID_DATA_VAR_ABS),

        // Angular velocity as rotation vector (scaled to [-32..32] rad/sec).
        HID_USAGE_SENSOR_DATA_CUSTOM_VALUE_2,
        HID_LOGICAL_MIN_16(0x01, 0x80), // LOGICAL_MINIMUM (-32767)
        HID_LOGICAL_MAX_16(0xFF, 0x7F), // LOGICAL_MAXIMUM (32767)
        HID_PHYSICAL_MIN_8(0xE0),
        HID_PHYSICAL_MAX_8(0x20),
        HID_UNIT_EXPONENT(0x00),  // 10^0
        HID_REPORT_SIZE(16),
        HID_REPORT_COUNT(3),
        HID_INPUT(HID_DATA_VAR_ABS),

        // Reference frame reset counter.
        HID_USAGE_SENSOR_DATA_CUSTOM_VALUE_3,
        HID_LOGICAL_MIN_16(0x00, 0x00), // LOGICAL_MINIMUM (0)
        HID_LOGICAL_MAX_16(0xFF, 0x00), // LOGICAL_MAXIMUM (255)
        HID_PHYSICAL_MIN_8(0x00),
        HID_PHYSICAL_MAX_8(0x00),
        HID_UNIT_EXPONENT(0x00),  // 10^0
        HID_REPORT_SIZE(8),
        HID_REPORT_COUNT(1),
        HID_INPUT(HID_DATA_VAR_ABS),

    HID_END_COLLECTION,
};

Annexe 2 : Exemple de descripteur HID v2.0

L'exemple suivant illustre un descripteur HID v2.0 pour un appareil n'acceptant que le transport des LCA Bluetooth LE.

const unsigned char ReportDescriptor[] = {
    HID_USAGE_PAGE_SENSOR,
    HID_USAGE_SENSOR_TYPE_OTHER_CUSTOM,
    HID_COLLECTION(HID_APPLICATION),
        // Feature report 2 (read-only).
        HID_REPORT_ID(2),

        // Magic value: "#AndroidHeadTracker#2.0#1"
        HID_USAGE_SENSOR_PROPERTY_SENSOR_DESCRIPTION,
        HID_LOGICAL_MIN_8(0),
        HID_LOGICAL_MAX_8(0xFF),
        HID_REPORT_SIZE(8),
        HID_REPORT_COUNT(25),
        HID_FEATURE(HID_CONST_VAR_ABS),

        // UUID.
        HID_USAGE_SENSOR_PROPERTY_PERSISTENT_UNIQUE_ID,
        HID_LOGICAL_MIN_8(0),
        HID_LOGICAL_MAX_8(0xFF),
        HID_REPORT_SIZE(8),
        HID_REPORT_COUNT(16),
        HID_FEATURE(HID_CONST_VAR_ABS),

        // Feature report 1 (read/write).
        HID_REPORT_ID(1),

        // 1-bit on/off reporting state.
        HID_USAGE_SENSOR_PROPERTY_REPORTING_STATE,
        HID_LOGICAL_MIN_8(0),
        HID_LOGICAL_MAX_8(1),
        HID_REPORT_SIZE(1),
        HID_REPORT_COUNT(1),
        HID_COLLECTION(HID_LOGICAL),
            HID_USAGE_SENSOR_PROPERTY_REPORTING_STATE_NO_EVENTS,
            HID_USAGE_SENSOR_PROPERTY_REPORTING_STATE_ALL_EVENTS,
            HID_FEATURE(HID_DATA_ARR_ABS),
        HID_END_COLLECTION,

        // 1-bit on/off power state.
        HID_USAGE_SENSOR_PROPERTY_POWER_STATE,
        HID_LOGICAL_MIN_8(0),
        HID_LOGICAL_MAX_8(1),
        HID_REPORT_SIZE(1),
        HID_REPORT_COUNT(1),
        HID_COLLECTION(HID_LOGICAL),
            HID_USAGE_SENSOR_PROPERTY_POWER_STATE_D4_POWER_OFF,
            HID_USAGE_SENSOR_PROPERTY_POWER_STATE_D0_FULL_POWER,
            HID_FEATURE(HID_DATA_ARR_ABS),
        HID_END_COLLECTION,

        // 6-bit reporting interval, with values [0x00..0x3F] corresponding to [10ms..100ms].
        HID_USAGE_SENSOR_PROPERTY_REPORT_INTERVAL,
        HID_LOGICAL_MIN_8(0x00),
        HID_LOGICAL_MAX_8(0x3F),
        HID_PHYSICAL_MIN_8(10),
        HID_PHYSICAL_MAX_8(100),
        HID_REPORT_SIZE(6),
        HID_REPORT_COUNT(1),
        HID_USAGE_SENSOR_UNITS_SECOND,
        HID_UNIT_EXPONENT(0xD),  // 10^-3
        HID_FEATURE(HID_DATA_VAR_ABS),

        // 1-bit transport selection
        HID_USAGE_SENSOR_PROPERTY_VENDOR_LE_TRANSPORT,
        HID_LOGICAL_MIN_8(0),
        HID_LOGICAL_MAX_8(1),
        HID_REPORT_SIZE(1),
        HID_REPORT_COUNT(1),
        HID_COLLECTION(HID_LOGICAL),
            HID_USAGE_SENSOR_PROPERTY_VENDOR_LE_TRANSPORT_ACL,
            HID_USAGE_SENSOR_PROPERTY_VENDOR_LE_TRANSPORT_ISO,
            HID_FEATURE(HID_DATA_ARR_ABS),
        HID_END_COLLECTION,

        // Input report 1

        // Orientation as rotation vector (scaled to [-pi..pi] rad).
        HID_USAGE_SENSOR_DATA_CUSTOM_VALUE_1,
        HID_LOGICAL_MIN_16(0x01, 0x80), // LOGICAL_MINIMUM (-32767)
        HID_LOGICAL_MAX_16(0xFF, 0x7F), // LOGICAL_MAXIMUM (32767)
        HID_PHYSICAL_MIN_32(0x60, 0x4F, 0x46, 0xED),  // -314159265
        HID_PHYSICAL_MAX_32(0xA1, 0xB0, 0xB9, 0x12),  // 314159265
        HID_UNIT_EXPONENT(0x08),  // 10^-8
        HID_REPORT_SIZE(16),
        HID_REPORT_COUNT(3),
        HID_INPUT(HID_DATA_VAR_ABS),

        // Angular velocity as rotation vector (scaled to [-32..32] rad/sec).
        HID_USAGE_SENSOR_DATA_CUSTOM_VALUE_2,
        HID_LOGICAL_MIN_16(0x01, 0x80), // LOGICAL_MINIMUM (-32767)
        HID_LOGICAL_MAX_16(0xFF, 0x7F), // LOGICAL_MAXIMUM (32767)
        HID_PHYSICAL_MIN_8(0xE0),
        HID_PHYSICAL_MAX_8(0x20),
        HID_UNIT_EXPONENT(0x00),  // 10^0
        HID_REPORT_SIZE(16),
        HID_REPORT_COUNT(3),
        HID_INPUT(HID_DATA_VAR_ABS),

        // Reference frame reset counter.
        HID_USAGE_SENSOR_DATA_CUSTOM_VALUE_3,
        HID_LOGICAL_MIN_16(0x00, 0x00), // LOGICAL_MINIMUM (0)
        HID_LOGICAL_MAX_16(0xFF, 0x00), // LOGICAL_MAXIMUM (255)
        HID_PHYSICAL_MIN_8(0x00),
        HID_PHYSICAL_MAX_8(0x00),
        HID_UNIT_EXPONENT(0x00),  // 10^0
        HID_REPORT_SIZE(8),
        HID_REPORT_COUNT(1),
        HID_INPUT(HID_DATA_VAR_ABS),

    HID_END_COLLECTION,
};