Das Human Interface Device (HID)-Protokoll für den Head Tracker, das für Geräte verfügbar ist mit Android 13 und höher, ermöglicht mit einem Android-Gerät über USB oder Bluetooth und das Android-Framework und die Apps können über die sensors-Framework. Dieses Protokoll wird für steuern ein Audio-Virtualizer-Effekt (3D-Audio). Auf dieser Seite werden die Begriffe Gerät und host im Sinne von Bluetooth, wobei device für das Head-Tracker-Gerät steht und host steht für den Android-Host.
Gerätehersteller müssen ihre Android-Geräte so konfigurieren, dass sie die Unterstützung für das HID-Protokoll des Kopf-Trackers. Nähere Informationen über finden Sie in der README-Datei für dynamische Sensoren
Auf dieser Seite wird davon ausgegangen, dass Sie mit den folgenden Ressourcen vertraut sind:
Struktur der obersten Ebene
Das Android-Framework identifiziert das Kopf-Tracker-Gerät als HID-Gerät.
Ein vollständiges Beispiel für einen gültigen HID-Deskriptor finden Sie unter Anhang 1: Beispiel für einen HID-Deskriptor
Auf der obersten Ebene ist das Kopf-Tracker-Gerät eine App-Sammlung mit dem
Sensors
Seite (0x20
) und die Other: Custom
-Nutzung (0xE1
). In diesem
Sammlung besteht aus mehreren Datenfeldern (Eingaben) und Eigenschaften (Features).
Eigenschaften und Datenfelder
In diesem Abschnitt werden die Eigenschaften und Datenfelder in einer Anwendung beschrieben. Sammlung eines Kopf-Tracker-Geräts.
Eigenschaft: Sensorbeschreibung (0x0308
)
Das Attribut „Sensorbeschreibung“ (0x0308
) ist ein schreibgeschützter ASCII-String (8-Bit)
die die folgenden Werte enthalten muss:
Kopf-Tracker-Version 1.0:
#AndroidHeadTracker#1.0
Kopf-Tracker-Version 2.0 (verfügbar mit Android 15 oder ) – einschließlich Unterstützung für LE Audio:
#AndroidHeadTracker#2.0#x
x
ist eine Ganzzahl (1
, 2
, 3
), die den Supporttransport angibt:
- 1: ACL
- 2: ISO
- 3: ACL und ISO
Es wird kein Nullterminator erwartet. Das bedeutet, dass die Gesamtgröße dieser Property ist 23 8-Bit-Zeichen für Version 1.0.
Diese Eigenschaft dient als Diskriminator, um Kollisionen mit anderen Sensoren.
Property: Persistente eindeutige ID (0x0302
)
Das Attribut der persistenten eindeutigen ID (0x0302
) ist ein schreibgeschütztes Array aus 16
-Elemente mit jeweils 8 Bit (insgesamt 128 Bit). Es wird kein Nullabschlusszeichen erwartet. Dieses
ist optional.
Mit dieser Eigenschaft können in Audio integrierte Headtracking-Geräte verwendet werden. Geräte so, dass sie auf das Audiogerät verweisen, an das sie angeschlossen sind. Die folgenden Schemas werden unterstützt.
Eigenständiger Kopf-Tracker
Wenn das Attribut „Persistente eindeutige ID“ (0x0302
) nicht vorhanden oder auf „Alle“ festgelegt ist
bedeutet dies, dass der Kopf-Tracker nicht dauerhaft mit einem
Audiogerät und kann separat verwendet werden, z. B. indem der Nutzer
den Kopf-Tracker manuell mit einem separaten Audiogerät verknüpfen.
Referenz mit Bluetooth-MAC-Adresse
Oktett | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
Wert | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | B | T | Bluetooth-MAC |
Bei diesem Schema müssen die ersten acht Oktette 0
sein, die Oktette 8 und 9 müssen
die ASCII-Werte B
bzw. T
und die folgenden 6 Oktette sind
als Bluetooth-MAC-Adresse interpretiert, unter der Annahme, dass das Kopf-Tracker-Gerät
gilt für alle Audiogeräte mit dieser MAC-Adresse. Diese Adresse muss die
Identitätsadresse, auch wenn das Gerät eine zufällige MAC-Adresse verwendet, um
Verbindungen. Dual-Mode-Geräte, die sich über Bluetooth Classic verbinden
(HID-Format v1.0) und Bluetooth LE (HID-Format v2.0) müssen zwei HID verfügbar machen.
Deskriptoren mit derselben Identitätsadresse. Dual-Mode-Geräte mit getrennten
das linke und das rechte Gerät muss Bluetooth LE HID über die primäre Dual-
Gerät im Modus statt auf das sekundäre Gerät nur für LE.
Referenz mit UUID
Wenn das höchstwertige Bit (MSB) von Oktett 8 (≥0x80
) festgelegt wird, wird das Feld
als UUID interpretiert, wie in
RFC-4122. Die
dasselbe Audiogerät dieselbe UUID auf, die unter
des Android-Frameworks mithilfe eines nicht angegebenen Mechanismus für die
Art des verwendeten Transportmittels.
Property: Meldestatus (0x0316
)
Das Attribut für den Berichtsstatus (0x0316
) ist ein Lese-/Schreibattribut, das die
Standardsemantik, wie in der HID-Spezifikation definiert. Der Host verwendet diese
um dem Gerät anzugeben, welche Ereignisse gemeldet werden sollen. Nur die Werte „Nein“
Es werden die Ereignisse „0x0840
“ und „Alle Ereignisse“ (0x0841
) verwendet.
Der Anfangswert dieses Feldes darf „No Events“ (Keine Ereignisse) sein. vom Gerät, nur vom Host verändert.
Property: Leistungszustand (0x0319
)
Das Attribut „Leistungsstatus“ (0x0319
) ist ein Lese-/Schreibattribut, das die Eigenschaft
Standardsemantik, wie in der HID-Spezifikation definiert. Der Host verwendet diese
, um dem Gerät anzugeben, in welchem Zustand das Gerät sich befinden muss. Nur die
werden die Werte „Volle Power“ (0x0851
) und „Ausschalten“ (0x0855
) verwendet.
Der Anfangswert für dieses Feld wird vom Gerät bestimmt und darf auf keinen Fall vom Gerät, nur vom Host verändert.
Property: Berichtsintervall (0x030E
)
Das Attribut „Berichtsintervall“ (0x030E
) ist eine Lese-/Schreibeigenschaft mit folgendem Wert:
Standardsemantik, wie in der HID-Spezifikation definiert. Der Host verwendet diese
festgelegt, wie oft das Gerät seine Datenmesswerte melden soll.
Die Einheiten sind Sekunden. Der gültige Bereich für diesen Wert wird vom Gerät bestimmt
und unter Verwendung des Mechanismus der
physischen Min/Max beschrieben. Mindestens 50 Hz
Reporting-Rate muss unterstützt werden und die empfohlene maximale Reporting-Rate ist
100 Hz. Daher muss das minimale Berichtsintervall kleiner oder gleich sein
auf 20 ms. Der Wert sollte größer oder gleich 10 ms sein.
Property: Vom Anbieter reservierter LE Transport (0xF410
)
Das Attribut für den vom Anbieter reservierten LE-Transport (0xF410
) ist ein Lese-/Schreibattribut
die die in der HID-Spezifikation definierte Standardsemantik hat. Host
verwendet diese Eigenschaft, um den ausgewählten Transport anzugeben (ACL oder ISO). Nur die
Die Werte ACL (0xF800
) und ISO (0xF801
) werden verwendet und müssen beide angegeben werden
in der logischen Sammlung.
Diese Eigenschaft wird vor dem Ein/Aus- oder Berichterstellungsstatus konfiguriert.
Datenfeld: Benutzerdefinierter Wert 1 (0x0544
)
Das Feld Benutzerdefinierter Wert 1 (0x0544
) ist ein Eingabefeld für die
Informationen zur Erfassung von Kopfbewegungen. Es ist ein Array mit drei Elementen,
die normalen HID-Regeln für physikalische Werte, wie in Abschnitt 6.2.2.7
die HID-Spezifikation. Der gültige Bereich für jedes Element ist [-hol, pi] rad. Einheiten
sind immer Radianten.
Die Elemente werden so interpretiert: [rx, ry, rz]
, wobei [rx, ry, rz]
ein
Rotationsvektor,
die die Transformation vom Referenzframe zum Headframe darstellt.
Die Magnitude muss im Bereich [0–...] liegen.
Der Referenzrahmen ist willkürlich, er ist aber in der Regel unveränderlich und muss Rechtshänder. Eine geringe Abweichung ist akzeptabel. Die Kopfachsen sind:
- X vom linken Ohr nach rechts
- Y vom Kopf bis zur Nase (hinten nach vorne)
- Z vom Hals bis zur Spitze des Kopfes
Datenfeld: Benutzerdefinierter Wert 2 (0x0545
)
Das Feld für den benutzerdefinierten Wert 2 (0x0545
) ist ein Eingabefeld für die
Informationen zur Erfassung von Kopfbewegungen. Ein Festpunktarray mit 3 Elementen,
wird gemäß den normalen HID-Regeln für physikalische Werte interpretiert.
Die Einheiten sind immer Radianten/Sekunde.
Die Elemente werden so interpretiert: [vx, vy, vz]
, wobei [vx, vy, vz]
ein
Rotationsvektor,
die die Winkelgeschwindigkeit des Headframes (relativ zu sich selbst) darstellt.
Datenfeld: Benutzerdefinierter Wert 3 (0x0546
)
Das Feld für den benutzerdefinierten Wert 3 (0x0546
) ist ein Eingabefeld für das Tracking
Diskontinuitäten im Bezugsrahmen. Es ist eine skalare Ganzzahl 8 Bit
Größe. Sie muss jedes Mal vom Gerät erhöht werden (mit Wraparound), wenn der
Bezugsrahmen geändert wird, z. B. wenn ein Ausrichtungsfilter-Algorithmus
anhand derer ermittelt wurde, dass der Status der Ausrichtung zurückgesetzt wurde. Dieser Wert ist
wird gemäß den normalen HID-Regeln für physikalische Werte interpretiert. Sie können jedoch
der physikalische Wert
und die Einheiten spielen keine Rolle. Die einzigen Informationen, die für den
„host“ ein geänderter Wert ist. Um numerische Probleme im Zusammenhang mit einem Genauigkeitsverlust zu vermeiden
beim Umwandeln logischer in physische Einheiten
für dieses Feld die physikalischen Minimal- und Maximalwerte sowie den Einheitenexponenten auf null setzen.
Berichtsstruktur
Die Gruppierung von Properties in Berichten (durch Zuweisung von Berichts-IDs) ist flexibel sein. Aus Effizienzgründen empfehlen wir, die schreibgeschützten Eigenschaften zu trennen. aus den Lese-/Schreib-Attributen.
Die benutzerdefinierten Werte 1, 2 und 3 für die Datenfelder müssen sich in den Feldern „Benutzerdefinierter Wert 1“, „2“ und „3“ befinden. und sich für ein bestimmtes Gerät (App-Sammlung) nur in einem Bericht befinden.
Eingabeberichte senden
Das Gerät muss regelmäßig und asynchron (über HID-INPUT-Nachrichten) Eingabeberichte senden, wenn alle diese Bedingungen erfüllt sind:
- Die Eigenschaft "Leistungsstatus" ist auf "Full Power" gesetzt.
- Die Eigenschaft Berichtsstatus ist auf "Alle Ereignisse" festgelegt.
- Die Eigenschaft Reporting-Intervall ist ungleich null.
Mit der Eigenschaft "Berichtsintervall" wird festgelegt, wie oft die Berichte gesendet werden. Wann? eine der oben genannten Bedingungen nicht erfüllt ist, darf das Gerät keine Berichte senden.
Vorwärts- und Abwärtskompatibilität
Für das HID-Protokoll des Kopf-Trackers wird ein Versionierungsschema verwendet, und gleichzeitig die Interoperabilität zwischen einem Host und einem Gerät, Versionen des Protokolls. Versionen für das Protokoll sind identifiziert die zwei Zahlen, Dur und Moll, haben eine unterschiedliche Semantik die in den folgenden Abschnitten beschrieben werden.
Welche Versionen von einem Gerät unterstützt werden, kann ermittelt werden, indem
die Eigenschaft „Sensorbeschreibung“ (0x0308
).
Kompatibilität von Nebenversionen
Änderungen an der Nebenversion sind abwärtskompatibel mit früheren Nebenversionen Versionen, die auf derselben Hauptversion basieren. In Änderungen an Minderjährige Version, ignoriert der Host zusätzliche Datenfelder und Eigenschaften. Beispiel: Ein Gerät, das die Protokollversion 1.6 verwendet, ist mit einem Host kompatibel, der Protokollversion 1.x, einschließlich Version 1.5.
Kompatibilität mit Hauptversionen
Nicht abwärtskompatible Änderungen sind für Änderungen an Hauptversionen zulässig. Bis mehrere Hauptversionen für die Interoperabilität mit alten und neuen Hosts, Geräte können in ihrem Bericht mehrere App-Sammlungen angeben. Beschreibungen. Beispiel:
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,
};
In diesem Fall kann der Host alle verschiedenen App-Sammlungen aufzählen, die vom Gerät beworben werden, untersuchen der Sensorbeschreibung ermitteln die Protokollversionen, die sie jeweils implementieren, und wählen dann neueste Protokollversion, die vom Host unterstützt wird. Bei der Auswahl funktioniert der Organisator mit dem einzelnen Protokoll, das für die Lebensdauer des Geräts ausgewählt wurde
Anhang: Beispiel eines HID-Deskriptors
Das folgende Beispiel zeigt einen typischen gültigen HID-Deskriptor. Dabei werden die häufig verwendeten C-Makros, die in Verwendung des HID-Sensors (Abschnitt 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,
};
Anhang 2: Beispiel eines HID-Deskriptors in Version 2.0
Das folgende Beispiel zeigt einen v2.0-HID-Deskriptor für ein Gerät, das die nur den Bluetooth LE ACL-Transport.
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,
};