Protokol HID pelacak kepala

Protokol perangkat antarmuka manusia (HID) pelacak kepala, tersedia untuk perangkat yang menjalankan Android 13 dan yang lebih tinggi, memungkinkan perangkat pelacak kepala untuk terhubung ke perangkat Android melalui USB atau Bluetooth dan terekspos ke framework serta aplikasi Android melalui sensors. Protokol ini digunakan untuk mengontrol efek virtualizer audio (audio 3D). Halaman ini menggunakan istilah device dan host dalam arti Bluetooth-nya, dengan device berarti perangkat pelacakan kepala dan host berarti host Android.

Produsen perangkat harus mengonfigurasi perangkat Android mereka guna mengaktifkan dukungan untuk protokol HID pelacak kepala. Untuk informasi lebih rinci tentang konfigurasi, lihat Sensor Dinamis README.

Halaman ini mengasumsikan Anda telah memahami aset berikut:

Struktur tingkat atas

Framework Android mengidentifikasi perangkat pelacak kepala sebagai perangkat HID.

Untuk contoh lengkap deskriptor HID yang valid, lihat Lampiran 1: Contoh Deskripsi HID.

Di tingkat teratas, perangkat pelacak kepala adalah koleksi aplikasi dengan Sensors halaman (0x20) dan penggunaan Other: Custom (0xE1). Di dalam terdapat beberapa kolom data (input) dan properti (fitur).

Properti dan kolom data

Bagian ini menjelaskan properti dan kolom data dalam aplikasi koleksi perangkat pelacak kepala.

Properti: Deskripsi Sensor (0x0308)

Properti Deskripsi Sensor (0x0308) adalah string ASCII (8-bit) hanya baca yang harus berisi nilai-nilai berikut:

Pelacak kepala versi 1.0:

#AndroidHeadTracker#1.0

Pelacak kepala versi 2.0 (tersedia di Android 15 atau lebih tinggi), yang mencakup dukungan untuk LE Audio:

#AndroidHeadTracker#2.0#x

x adalah bilangan bulat (1, 2, 3) yang menunjukkan transpor dukungan:

  • 1: ACL
  • 2: ISO
  • 3: ACL + ISO

Tidak ada terminator null, yang berarti ukuran total properti ini adalah 23 karakter 8-bit untuk versi 1.0.

Properti ini berfungsi sebagai diskriminator untuk menghindari konflik dengan sensor kustom.

Properti: ID Unik Persisten (0x0302)

Properti Persistent Unique ID (0x0302) adalah array hanya baca yang berjumlah 16 karakter elemen, masing-masing 8 bit (total 128 bit). Tidak ada terminator null yang diharapkan. Ini bersifat opsional.

Properti ini memungkinkan perangkat pelacakan kepala yang terintegrasi dalam audio perangkat itu untuk mereferensikan perangkat audio yang terpasang. Skema berikut didukung.

Pelacak kepala terpisah

Jika properti Persistent Unique ID (0x0302) tidak ada atau disetel ke semua nol, itu berarti bahwa perangkat pelacak kepala tidak terpasang secara permanen ke perangkat audio Anda dan dapat digunakan secara terpisah, misalnya, dengan memungkinkan pengguna secara manual mengaitkan perangkat pelacak kepala dengan perangkat audio terpisah.

Mereferensikan menggunakan alamat MAC Bluetooth

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

Dalam skema ini, 8 oktet pertama harus 0, oktet 8 dan 9 harus berisi nilai ASCII B dan T masing-masing, dan 6 oktet berikutnya adalah ditafsirkan sebagai alamat MAC Bluetooth, dengan asumsi perangkat {i>head tracker<i} berlaku untuk setiap perangkat audio yang memiliki alamat MAC ini. Alamat ini harus merupakan alamat MAC, meskipun perangkat menggunakan alamat MAC acak untuk membuat koneksi jarak jauh. Perangkat mode ganda yang terhubung melalui Bluetooth klasik (format HID v1.0) dan Bluetooth LE (format HID v2.0) harus mengekspos dua HID deskripsi dengan alamat identitas yang sama. Perangkat mode ganda dengan perangkat kiri dan kanan harus mengekspos Bluetooth LE HID menggunakan perangkat mode alih-alih perangkat sekunder khusus LE.

Referensi menggunakan UUID

Setiap kali bit paling signifikan (MSB) dari octet 8 ditetapkan (≥0x80), kolom ditafsirkan sebagai UUID, seperti yang ditentukan dalam RFC-4122. Tujuan perangkat audio yang sesuai menyediakan UUID yang sama, yang terdaftar di kerangka kerja Android, melalui mekanisme yang tidak ditentukan yang khusus untuk jenis transportasi yang digunakan.

Properti: Status Pelaporan (0x0316)

Properti Status Pelaporan (0x0316) adalah properti baca/tulis yang memiliki semantik standar seperti yang ditentukan dalam spesifikasi HID. Host menggunakan untuk menunjukkan peristiwa mana yang akan dilaporkan ke perangkat. Hanya nilai No Peristiwa (0x0840) dan Semua Peristiwa (0x0841) digunakan.

Nilai awal untuk kolom ini harus berupa Tidak Ada Peristiwa dan tidak boleh berupa dimodifikasi oleh perangkat, hanya oleh {i>host<i}.

Properti: Status Daya (0x0319)

Properti Status Daya (0x0319) adalah properti baca/tulis yang memiliki semantik standar seperti yang ditentukan dalam spesifikasi HID. Host menggunakan untuk menunjukkan pada perangkat status daya mana yang harus dimasukkan. Hanya nilai Daya Penuh (0x0851) dan Matikan (0x0855) akan digunakan.

Nilai awal kolom ini ditentukan oleh perangkat dan tidak boleh dimodifikasi oleh perangkat, hanya oleh {i>host<i}.

Properti: Interval Laporan (0x030E)

Properti Interval Laporan (0x030E) adalah properti baca/tulis yang memiliki semantik standar seperti yang ditentukan dalam spesifikasi HID. Host menggunakan untuk menunjukkan ke perangkat seberapa sering melaporkan pembacaan datanya. Satuan dalam detik. Rentang yang valid untuk nilai ini ditentukan oleh perangkat dan dijelaskan menggunakan mekanisme Min/Maksimal Fisik. Minimal 50 Hz harus didukung, dan rasio pelaporan maksimum yang disarankan adalah 100 Hz. Oleh karena itu, interval laporan minimum harus kurang dari atau sama dengan hingga 20 milidetik, dan sebaiknya lebih dari atau sama dengan 10 milidetik.

Properti: LE Transport yang direservasi ke vendor (0xF410)

Properti LE Transport yang disediakan Vendor (0xF410) adalah properti baca/tulis yang memiliki semantik standar seperti yang didefinisikan dalam spesifikasi HID. Host menggunakan properti ini untuk menunjukkan transport yang dipilih (ACL atau ISO). Hanya nilai ACL (0xF800) dan ISO (0xF801) digunakan, dan keduanya harus disertakan ke dalam koleksi logis.

Properti ini dikonfigurasi sebelum status pelaporan atau daya.

Kolom data: Nilai Kustom 1 (0x0544)

Kolom Nilai Kustom 1 (0x0544) adalah kolom input yang digunakan untuk melaporkan informasi pelacakan gerakan kepala yang sebenarnya. Array adalah 3 elemen, yang ditafsirkan sesuai dengan aturan HID normal untuk nilai fisik sebagaimana ditentukan dalam bagian 6.2.2.7 dari spesifikasi HID. Rentang yang valid untuk setiap elemen adalah [-π, π] rad. Unit selalu radian.

Elemen ini ditafsirkan sebagai: [rx, ry, rz], sehingga [rx, ry, rz] adalah vektor rotasi, yang mewakili transformasi dari {i>frame<i} referensi ke {i>head frame<i}. Magnitudo harus berada dalam rentang [0..π].

Bingkai referensi bersifat tidak tentu, tetapi umumnya bersifat tetap dan harus bukan tangan kanan. Sedikit penyimpangan dapat diterima. Sumbu kepala adalah:

  • X dari telinga kiri ke kanan
  • Y dari belakang kepala ke hidung (belakang ke depan)
  • Z dari leher ke atas kepala

Kolom data: Nilai Kustom 2 (0x0545)

Kolom Nilai Kustom 2 (0x0545) adalah kolom input yang digunakan untuk melaporkan informasi pelacakan gerakan kepala yang sebenarnya. Array adalah susunan titik tetap yang terdiri dari 3 elemen, ditafsirkan sesuai dengan aturan HID normal untuk nilai fisik. Satuan selalu radian/detik.

Elemen ini ditafsirkan sebagai: [vx, vy, vz], sehingga [vx, vy, vz] adalah vektor rotasi, yang mewakili kecepatan sudut dari frame head (relatif terhadap dirinya sendiri).

Kolom data: Nilai Kustom 3 (0x0546)

Kolom Nilai Kustom 3 (0x0546) adalah kolom input yang digunakan untuk melacak diskontinuitas dalam frame referensi. Ini adalah bilangan bulat skalar 8 bit dalam ukuran. Nilai ini harus ditambah (dengan wraparound) oleh perangkat setiap kali bingkai referensi diubah, misalnya, jika algoritma filter orientasi yang digunakan untuk menentukan orientasi, statusnya telah direset. Nilai ini adalah ditafsirkan sesuai dengan aturan HID normal untuk nilai fisik. Namun, nilai fisik dan satuannya tidak menjadi masalah. Satu-satunya informasi yang relevan dengan {i>host<i} adalah nilai yang diubah. Untuk menghindari masalah numerik terkait hilangnya presisi saat mengonversi dari unit logis ke fisik, sebaiknya setel nilai minimum fisik, maksimum fisik, dan eksponen unit ke nol untuk kolom ini.

Struktur laporan

Pengelompokan properti ke dalam laporan (berdasarkan penetapan ID laporan) adalah fleksibel. Untuk efisiensi, sebaiknya pisahkan properti hanya baca dari properti baca/tulis.

Untuk kolom data, kolom Nilai Kustom 1, 2, dan 3 harus sama dan hanya ada di satu laporan untuk perangkat tertentu (kumpulan aplikasi).

Mengirim laporan input

Perangkat harus secara berkala dan asinkron (melalui pesan HID INPUT) mengirimkan laporan input saat semua kondisi berikut terpenuhi:

  • Properti Status Daya disetel ke Daya Penuh.
  • Properti Status Pelaporan ditetapkan ke Semua Peristiwa.
  • Properti Interval Pelaporan bukan nol.

Properti Interval Pelaporan menentukan frekuensi pengiriman laporan. Kapan salah satu kondisi di atas tidak terpenuhi, perangkat tidak boleh mengirim laporan apa pun.

Kompatibilitas maju dan mundur

Protokol HID pelacak kepala menggunakan skema pembuatan versi yang memungkinkan sekaligus memungkinkan interoperabilitas antara {i>host<i} dan perangkat yang menggunakan versi protokol yang berbeda. Versi untuk protokol diidentifikasi dengan dua angka, mayor dan minor, yang memiliki semantik yang berbeda sebagai yang dijelaskan di bagian berikut.

Versi yang didukung oleh perangkat dapat ditentukan dengan memeriksa properti Deskripsi Sensor (0x0308).

Kompatibilitas versi minor

Perubahan pada versi minor kompatibel dengan versi minor sebelumnya versi yang didasarkan pada versi utama yang sama. Dalam pembaruan untuk anak di bawah umur {i>host<i}, {i>host<i} mengabaikan kolom data dan properti tambahan. Misalnya, perangkat yang menggunakan protokol versi 1.6 kompatibel dengan {i>host<i} yang mendukung Protokol versi 1.x, termasuk versi 1.5.

Kompatibilitas versi utama

Perubahan yang tidak kompatibel dengan versi sebelumnya diizinkan untuk perubahan pada versi utama. Kepada mendukung beberapa versi utama untuk interoperabilitas dengan {i>host<i} lama dan baru, perangkat dapat menentukan beberapa kumpulan aplikasi dalam laporannya deskripsi. Contoh:

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

Dalam hal ini, host dapat menghitung semua koleksi aplikasi yang berbeda yang diiklankan oleh perangkat, memeriksa properti Deskripsi Sensornya untuk menentukan versi protokol yang mereka implementasikan masing-masing, lalu memilih versi protokol terbaru yang didukung {i>host<i}. Jika dipilih, host berfungsi dengan satu protokol yang dipilih selama penggunaan perangkat koneksi jarak jauh.

Lampiran: Contoh deskripsi HID

Contoh berikut mengilustrasikan deskriptor HID yang valid pada umumnya. Fungsi ini menggunakan makro C yang biasa digunakan, Penggunaan Sensor HID (bagian 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,
};

Lampiran 2: Contoh deskriptor HID v2.0

Contoh berikut mengilustrasikan deskriptor HID v2.0 untuk perangkat yang mendukung hanya 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,
};