Protokół HID urządzenia śledzącego głowy

Protokół HID, dostępny w przypadku urządzeń z Androidem 13 lub nowszym, umożliwia połączenie urządzenia śledzącego ruch z urządzenia z Androidem przez USB lub Bluetooth i udostępnianie jego aplikacji za pomocą platformy czujników. Ten protokół służy do sterowania efektem wirtualizacji dźwięku (dźwięk 3D). Terminy urządzenie i host są używane na tej stronie w znaczeniu Bluetooth, gdzie urządzenie oznacza urządzenie śledzące ruch głowy, a host oznacza host Androida.

Producenci urządzeń muszą skonfigurować swoje urządzenia z Androidem, aby umożliwić obsługę protokołu HID lokalizatora głowy. Więcej informacji o konfiguracji znajdziesz w pliku README: czujniki dynamiczne.

Ta strona zakłada, że znasz te zasoby:

Struktura najwyższego poziomu

Platforma Androida identyfikuje urządzenie śledzące na głowie jako urządzenie HID.

Pełny przykład prawidłowego deskryptora HID znajdziesz w Dodatku 1: przykład deskryptora HID.

Na najwyższym poziomie urządzenie śledzące na głowę to kolekcja aplikacji ze stroną Sensors (0x20) i informacjami o wykorzystaniu Other: Custom (0xE1). Wewnątrz tej kolekcji jest kilka pól danych (dane wejściowe) i właściwości (funkcje).

Właściwości i pola danych

W tej sekcji opisano właściwości i pola danych w kolekcji aplikacji trackera.

Właściwość: Opis czujnika (0x0308)

Właściwość SensorDescription (0x0308) to właściwość ciągu znaków ASCII (tylko do odczytu) (8-bitowego), która musi zawierać następujące wartości:

Śledzik w wersji 1.0:

#AndroidHeadTracker#1.0

śledzenie ruchów głowy w wersji 2.0 (dostępne w Androidzie 15 lub nowszym), które obejmuje obsługę dźwięku LE:

#AndroidHeadTracker#2.0#x

Wartość x jest liczbą całkowitą (1, 2, 3) wskazującą sposób kontaktu z zespołem pomocy:

  • 1: Lista kontroli dostępu (ACL)
  • 2: ISO
  • 3: ACL + ISO

Nie należy stosować wartości null-terminator, co oznacza, że łączny rozmiar tej właściwości w wersji 1.0 to 23 8-bitowe znaki.

Ta właściwość służy jako dyskryminator, który zapobiega kolizjom z innymi czujnikami niestandardowymi.

Właściwość: trwały identyfikator unikalny (0x0302)

Właściwość trwały identyfikator unikalny (0x0302) to tablica tylko do odczytu zawierająca 16 elementów, z których każdy ma 8 bitów (razem 128 bitów). Nie jest wymagany terminator null. Ta właściwość jest opcjonalna.

Ta właściwość umożliwia urządzeniu śledzącym ruchy głowy zintegrowanym z urządzeniami audio wskazywanie urządzenia audio, do którego są podłączone. Obsługiwane są te schematy:

Samodzielny tracker na głowę

Jeśli właściwość Persistent Unique ID (0x0302) nie istnieje lub jest ustawiona na wszystkie zera, oznacza to, że lokalizator nie jest na stałe podłączony do urządzenia audio i można go używać oddzielnie, np. umożliwiając użytkownikowi ręczne powiązanie lokalizatora z osobnym urządzeniem audio.

Odniesienie z użyciem adresu MAC Bluetootha

Octet 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Wartość 0 0 0 0 0 0 0 0 B T Adres MAC Bluetooth

W tym schemacie pierwsze 8 oktetów musi być 0, oktety 8 i 9 muszą zawierać odpowiednio wartości ASCII BT, a kolejne 6 oktetów jest interpretowane jako adres MAC Bluetooth, przy założeniu, że urządzenie śledzące ruchy głowy dotyczy dowolnego urządzenia audio mającego ten adres MAC. Adres ten musi być adresem tożsamości, nawet jeśli urządzenie używa losowego adresu MAC do nawiązywania połączeń. Urządzenia w trybie podwójnym, które łączą się przez klasyczny Bluetooth (w formacie HID w wersji 1.0) i Bluetooth LE (w formacie HID w wersji 2.0), muszą udostępniać 2 deskryptory HID z tym samym adresem tożsamości. Urządzenia dwufunkcyjne z oddzielnymi urządzeniami lewym i prawym muszą udostępniać interfejs Bluetooth LE HID za pomocą głównego urządzenia dwufunkcyjnego zamiast urządzenia dodatkowego obsługującego tylko LE.

Odwoływanie się za pomocą UUID

Gdy najbardziej znaczący bit (MSB) oktetu 8 jest ustawiony (≥0x80), pole jest interpretowane jako identyfikator UUID zgodnie z specyfikacją RFC-4122. Odpowiadające urządzenie audio udostępnia ten sam identyfikator UUID, który jest zarejestrowany w ramach Androida za pomocą nieokreślonego mechanizmu odpowiedniego do typu używanego transportu.

Właściwość: stan raportowania (0x0316)

Właściwość raportowania (0x0316) to właściwość do odczytu i zapisu o standardowej semantyce zdefiniowaną w specyfikacji HID. Host używa tej właściwości, aby wskazać urządzeniu, które zdarzenia mają być zgłaszane. Używane są tylko wartości Brak zdarzeń (0x0840) i Wszystkie zdarzenia (0x0841).

Wartość początkowa tego pola musi wynosić Brak zdarzeń i nie może być modyfikowana przez urządzenie, tylko przez hosta.

Usługa: stan zasilania (0x0319)

Właściwość Power State (0x0319) to właściwość do odczytu i zapisu o standardowej semantyce zdefiniowanej w specyfikacji HID. Host używa tej właściwości, aby wskazać urządzeniu, w jakim stanie zasilania Używane są tylko wartości Pełna moc (0x0851) i Wyłącz zasilanie (0x0855).

Początkowa wartość tego pola jest określana przez urządzenie i nigdy nie może być modyfikowana przez urządzenie, tylko przez hosta.

Właściwość: Interwał raportowania (0x030E)

Właściwość Interwał między raportami (0x030E) to właściwość do odczytu i zapisu o standardowej semantyce zdefiniowanej w specyfikacji HID. Host używa tej właściwości, aby wskazać urządzeniu, jak często mają raportować odczyty danych. Jednostki są wyrażone w sekundach. Prawidłowy zakres tej wartości jest określany przez urządzenie i opisany za pomocą mechanizmu Min/maks. Musi być obsługiwana częstotliwość raportowania co najmniej 50 Hz, a zalecana maksymalna częstotliwość raportowania to 100 Hz. Dlatego minimalny interwał raportowania musi być krótszy lub równy 20 ms, a zalecany interwał musi być dłuższy lub równy 10 ms.

Usługa: zarezerwowane przez dostawcę LE Transport (0xF410)

Właściwość LE Transport zarezerwowana przez dostawcę (0xF410) to właściwość do odczytu i zapisu, która ma standardową semantykę zdefiniowaną w specyfikacji HID. Host używa tej właściwości do wskazywania wybranego sposobu transportu (ACL lub ISO). Używane są tylko wartości ACL (0xF800) i ISO (0xF801) – obie muszą być uwzględnione w zbiorze logicznym.

Ta właściwość jest konfigurowana przed stanem zasilania lub raportowania.

Pole danych: Wartość niestandardowa 1 (0x0544)

Pole Wartość niestandardowa 1 (0x0544) to pole danych służące do raportowania rzeczywistych informacji o śledzeniu ruchem głowy. Jest to 3-elementowa tablica interpretowana zgodnie ze standardowymi regułami HID dla wartości fizycznych, zgodnie z opisem w sekcji 6.2.2.7 specyfikacji HID. Prawidłowy zakres dla każdego elementu to [-π, π] rad. Jednostki to radiany.

Elementy są interpretowane w taki sposób: [rx, ry, rz], gdzie [rx, ry, rz] jest wektorem obrotu, reprezentującym przekształcenie z klatki referencyjnej w ramkę nagłówka. Wielkość musi mieścić się w zakresie [0..π].

Ramka referencyjna może być dowolna, ale zwykle jest stała i musi być przeznaczona dla prawej ręki. Dopuszczalne jest niewielkie odchylenie. Osie głowy:

  • X od lewego ucha do prawego
  • Y od tyłu głowy do nosa (z tyłu do przodu)
  • Z od szyi do góry głowy

Pole danych: Wartość niestandardowa 2 (0x0545)

Pole Wartość niestandardowa 2 (0x0545) to pole do wprowadzania danych służące do raportowania rzeczywistych informacji o śledzeniu głowy. Jest to 3-elementowa tablica o stałym punkcie, interpretowana zgodnie z normalnymi regułami HID dla wartości fizycznych. Jednostkami są zawsze radiany na sekundę.

Elementy są interpretowane w taki sposób: [vx, vy, vz], gdzie [vx, vy, vz] jest wektorem obrotu, reprezentującym prędkość kątową ramy głowy (w stosunku do niej).

Pole danych: wartość niestandardowa 3 (0x0546)

Pole Wartość niestandardowa 3 (0x0546) to pole do wprowadzania danych służące do śledzenia nieciągłości w ramce referencyjnej. Jest to skalarna liczba całkowita o rozmiarze 8-bitowym. Musi być zwiększany (z przewijaniem) przez urządzenie za każdym razem, gdy zmienia się układ odniesienia, na przykład gdy stan algorytmu filtra orientacji używanego do określania orientacji został zresetowany. Wartość ta jest interpretowana zgodnie z normalnymi regułami HID dla wartości fizycznych. Nie mają jednak znaczenia fizycznego ani jednostki. Jedyną istotną informacją o hoście jest zmieniona wartość. Aby uniknąć problemów liczbowych związanych z utratą precyzji podczas konwersji z jednostek logicznych na fizyczne, zalecamy ustawienie w tym polu wartości minimalnej, fizycznej i maksymalnej wartości fizycznej oraz wykładnika jednostki.

Struktura raportu

Grupowanie usług w raporty (przez przypisywanie identyfikatorów raportów) jest elastyczne. Ze względu na wydajność zalecamy oddzielenie właściwości tylko do odczytu od właściwości tylko do odczytu/zapisu.

W przypadku pól danych pola Wartość niestandardowa 1, 2 i 3 muszą znajdować się w tym samym raporcie i znajdować się tylko w jednym raporcie dotyczącym danego urządzenia (kolekcja aplikacji).

Wysyłaj raporty wejściowe

Urządzenie musi okresowo i asymetrycznie (za pomocą komunikatów HID INPUT) przesyłać raporty o wprowadzaniu danych, gdy są spełnione wszystkie te warunki:

  • Właściwość Stan zasilania ma wartość Pełna moc.
  • Właściwość Stan raportowania ma wartość Wszystkie zdarzenia.
  • Właściwość IntervalReporting jest różna od 0.

Właściwość Interwał raportowania określa, jak często mają być wysyłane raporty. Jeśli którykolwiek z powyższych warunków nie zostanie spełniony, urządzenie nie może wysyłać żadnych raportów.

Zgodność do przodu i do tyłu

Protokół HID śledzącego ruch głowy używa schematu wersji, który umożliwia aktualizacje, a także interoperacyjność między hostem a urządzeniem, które używają różnych wersji protokołu. Wersje protokołu są identyfikowane za pomocą 2 liczb (głównych i podrzędnych), które mają różną semantykę, zgodnie z opisem w kolejnych sekcjach.

Wersje obsługiwane przez urządzenie można określić, analizując jego właściwość Opis czujnika (0x0308).

Zgodność z wersją podrzędną

Zmiany w wersji podrzędnej są zgodne z wcześniejszymi wersjami podrzędnymi, które są oparte na tej samej wersji nadrzędnej. W wersji podrzędnej host ignoruje dodatkowe pola danych i właściwości. Na przykład urządzenie korzystające z wersji 1.6 protokołu jest zgodne z hostem obsługującym wersję 1.x protokołu, w tym wersję 1.5.

Zgodność wersji głównej

W przypadku zmian w głównych wersjach dozwolone są zmiany niezgodne ze starszymi wersjami. Aby zapewnić interoperacyjność wielu wersji głównych ze starymi i nowymi hostami, urządzenia mogą określać wiele kolekcji aplikacji w deskryptorach raportów. Na przykład:

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,
};

W takim przypadku host może wyliczyć wszystkie kolekcje aplikacji reklamowane przez urządzenie, analizując ich właściwość SensorDescription, aby określić zaimplementowane przez siebie wersje protokołu, a następnie wybrać najnowszą wersję protokołu obsługiwaną przez hosta. Host będzie wtedy działać z pojedynczym protokołem wybranym przez cały okres istnienia połączenia urządzenia.

Dodatek: przykład deskryptora HID

Przykład poniżej pokazuje typowy prawidłowy deskryptor HID. Używa ona powszechnie stosowanych makr C, które są opisane w Zastosowaniach czujników HID (sekcja 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,
};

Załącznik 2. Przykład opisu HID w wersji 2.0

Przykład poniżej pokazuje deskryptor HID w wersji 2.0 dla urządzenia obsługującego tylko transport Bluetooth LE ACL.

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,
};