پروتکل دستگاه میانای انسانی ردیاب سر

پروتکل دستگاه میانای انسانی (HID) ردیاب سر که برای دستگاه‌های دارای Android 13 و بالاتر دردسترس است، امکان می‌دهد دستگاه ردیاب سر ازطریق USB یا بلوتوث به دستگاه Android متصل شود و ازطریق چارچوب حسگرها در چارچوب Android و برنامه‌ها نمایش داده شود. این پروتکل برای کنترل جلوه مجازی‌ساز صوتی (صدای سه‌بعدی) استفاده می‌شود. این صفحه از اصطلاحات دستگاه و میزبان در مفهوم بلوتوثی آن‌ها استفاده می‌کند، که در آن دستگاه به‌معنای دستگاه ردیابی سر و میزبان به‌معنای میزبان Android است.

سازندگان دستگاه باید دستگاه‌های Android خود را پیکربندی کنند تا از پروتکل HID ردیاب سر پشتیبانی کنند. برای اطلاعات دقیق‌تر درباره پیکربندی، «فایل خودخوان حسگرهای پویا» را ببینید.

این صفحه فرض می‌کند که با منابع زیر آشنایی دارید:

ساختار سطح بالا

چارچوب Android دستگاه ردیاب سر را به‌عنوان دستگاه HID شناسایی می‌کند.

برای مشاهده نمونه کاملی از توصیف‌گر HID معتبر، پیوست ۱: نمونه‌ای از توصیف‌گر HID را ببینید.

در بالاترین سطح، دستگاه ردیاب سر مجموعه‌ای از برنامه‌ها با صفحه Sensors (0x20) و کاربرد Other: Custom (0xE1) است. در این مجموعه، چندین فیلد داده (ورودی) و ویژگی (قابلیت) وجود دارد.

مشخصه‌ها و فیلدهای داده

این بخش خواص و فیلدهای داده در مجموعه برنامه دستگاه ردیاب سر را توصیف می‌کند.

دارایی: شرح حسگر (0x0308)

دارایی «شرح حسگر» (0x0308) رشته ASCII (۸ بیتی) فقط‌خواندنی است دارایی که باید حاوی مقادیر زیر باشد:

نسخه ردیاب سر ۱.۰:

#AndroidHeadTracker#1.0

نسخه ۲.۰ ردیاب سر (در Android 15 یا نسخه‌های بالاتر دردسترس است)، که شامل پشتیبانی از صدای کم‌مصرف می‌شود:

#AndroidHeadTracker#2.0#x

‫x یک عدد صحیح (1،‏ 2،‏ 3) است که نشان‌دهنده حمل‌ونقل پشتیبانی‌شده است:

  • ‫۱: ACL
  • ‫۲: ISO
  • ‫۳: ACL + ISO

هیچ نویسه پایانی تهی موردانتظار نیست، یعنی اندازه کل این دارایی برای نسخه ۱.۰ برابر با ۲۳ نویسه ۸ بیتی است.

این ویژگی به‌عنوان متمایزکننده عمل می‌کند تا از تداخل با دیگر حسگرهای سفارشی جلوگیری شود.

دارایی: شناسه یکتای ماندگار (0x0302)

دارایی «شناسه یکتای ماندگار» (0x0302) آرایه‌ای فقط خواندنی از ۱۶ عنصر است که هرکدام ۸ بیت (مجموعاً ۱۲۸ بیت) است. هیچ پایان‌دهنده تهی‌ای انتظار نمی‌رود. این دارایی اختیاری است.

این دارایی به دستگاه‌های ردیابی سر که در دستگاه‌های صوتی ادغام شده‌اند اجازه می‌دهد به دستگاه صوتی که به آن متصل هستند ارجاع دهند. طرح‌های زیر پشتیبانی می‌شوند.

ردیاب سر مستقل

اگر ویژگی «شناسه یکتای دائمی» (0x0302) وجود نداشته باشد یا روی همه صفرها تنظیم شده باشد، به این معنی است که دستگاه ردیاب سر به‌طور دائم به دستگاه صوتی متصل نیست و می‌تواند به‌طور جداگانه استفاده شود، برای مثال، با اجازه دادن به کاربر برای مرتبط کردن دستی دستگاه ردیاب سر با یک دستگاه صوتی جداگانه.

ارجاع بااستفاده از مک آدرس بلوتوث

هشت‌تایی 0 1 ۲ ۳ ۴ ۵ 6 7 8 9 10 11 12 13 14 15
مقدار 0 0 0 0 0 0 0 0 B T آدرس MAC بلوتوث

در این طرح، ۸ هشت‌تایی اول باید 0 باشد، هشت‌تایی‌های ۸ و ۹ باید به‌ترتیب حاوی مقادیر ASCII‏ B و T باشند، و ۶ هشت‌تایی بعدی به‌عنوان مک آدرس بلوتوث تفسیر می‌شوند، با این فرض که دستگاه ردیاب سر برای هر دستگاه صوتی دارای این مک آدرس اعمال می‌شود. این نشانی باید نشانی هویت باشد، حتی اگر دستگاه از مک آدرس تصادفی برای برقراری اتصال استفاده کند. دستگاه‌های دوحالته که ازطریق «بلوتوث کلاسیک» (قالب HID نسخه ۱.۰) و «بلوتوث کم‌مصرف» (قالب HID نسخه ۲.۰) متصل می‌شوند باید دو توصیفگر HID با نشانی هویت یکسان ارائه دهند. دستگاه‌های دومد با دستگاه‌های چپ و راست جداگانه باید ازطریق دستگاه اصلی دومد به‌جای دستگاه ثانویه فقط LE، «دستگاه واسط انسانی بلوتوث کم‌مصرف» را نمایان کنند.

ارجاع بااستفاده از شناسه منحصربه‌فرد جهانی

هرگاه مهم‌ترین بیت (MSB) از هشت‌تایی ۸ تنظیم شود (≥0x80)، فیلد به‌عنوان UUID تفسیر می‌شود، همان‌طور که در RFC-4122 مشخص شده است. دستگاه صوتی مربوطه همان UUID را که در چارچوب Android ثبت شده است ازطریق سازوکار نامشخصی که مختص نوع انتقال مورداستفاده است ارائه می‌دهد.

دارایی: وضعیت گزارش‌دهی (0x0316)

دارایی «وضعیت گزارش‌دهی» (0x0316) دارایی خواندنی/نوشتنی است که معناشناسی استاندارد آن در مشخصات HID تعریف شده است. میزبان از این ویژگی برای نشان دادن رویدادهایی که باید گزارش شوند به دستگاه استفاده می‌کند. فقط از مقادیر «هیچ رویدادی» (0x0840) و «همه رویدادها» (0x0841) استفاده می‌شود.

مقدار اولیه این فیلد باید «بدون رویداد» باشد و هرگز نباید توسط دستگاه تغییر کند، فقط توسط میزبان.

ویژگی: وضعیت روشن بودن (0x0319)

دارایی «وضعیت توان» (0x0319) دارایی خواندنی/نوشتنی است که معناشناسی استاندارد آن در مشخصات HID تعریف شده است. میزبان از این ویژگی برای نشان دادن وضعیت برقی که دستگاه باید در آن باشد استفاده می‌کند. فقط از مقادیر «توان کامل» (0x0851) و «خاموش» (0x0855) استفاده می‌شود.

مقدار اولیه این فیلد توسط دستگاه تعیین می‌شود و هرگز نباید توسط دستگاه تغییر کند، فقط توسط میزبان قابل تغییر است.

دارایی: فاصله گزارش (0x030E)

دارایی «فاصله گزارش» (0x030E) دارایی خواندنی/نوشتنی است که معناشناسی استاندارد آن در مشخصات HID تعریف شده است. میزبان از این ویژگی برای نشان دادن تعداد دفعات گزارش خوانش‌های داده به دستگاه استفاده می‌کند. واحدها ثانیه هستند. محدوده معتبر برای این مقدار توسط دستگاه تعیین می‌شود و بااستفاده از سازوکار «حداقل/حداکثر فیزیکی» شرح داده می‌شود. باید از نرخ گزارش حداقل ۵۰ هرتز پشتیبانی شود و حداکثر نرخ گزارش توصیه‌شده ۱۰۰ هرتز است. بنابراین، حداقل فاصله گزارش باید کمتر یا مساوی ۲۰ میلی‌ثانیه باشد و توصیه می‌شود بیشتر یا مساوی ۱۰ میلی‌ثانیه باشد.

ویژگی: LE Transport رزروشده توسط فروشنده (0xF410)

ویژگی «انتقال LE رزروشده توسط فروشنده» (0xF410) ویژگی خواندن/نوشتن است که معناشناسی استاندارد تعریف‌شده در مشخصات HID را دارد. میزبان از این دارایی برای نشان دادن انتقال انتخاب‌شده (ACL یا ISO) استفاده می‌کند. فقط مقادیر ACL (0xF800) و ISO (0xF801) استفاده می‌شوند و هر دو باید در مجموعه منطقی گنجانده شوند.

این دارایی قبل‌از وضعیت‌های قدرت یا گزارش پیکربندی شده است.

فیلد داده: مقدار سفارشی ۱ (0x0544)

فیلد «مقدار سفارشی ۱» (0x0544) یک فیلد ورودی است که برای گزارش کردن اطلاعات واقعی ردیابی سر استفاده می‌شود. این آرایه ۳ عنصری مطابق با قوانین عادی HID برای مقادیر فیزیکی که در بخش ۶.۲.۲.۷ مشخصات HID ذکر شده است تفسیر می‌شود. محدوده معتبر برای هر عنصر [-π, π] رادیان است. واحدها همیشه رادیان هستند.

عناصر به‌صورت [rx, ry, rz] تفسیر می‌شوند، به‌طوری‌که [rx, ry, rz] یک بردار چرخش است که تبدیل از قاب مرجع به قاب سر را نشان می‌دهد. اندازه باید در محدوده [۰..π] باشد.

قاب مرجع اختیاری است، اما معمولاً ثابت است و باید دست راست باشد. مقدار کمی انحراف قابل‌قبول است. محورهای سر عبارت‌اند از:

  • ‫X از گوش چپ به راست
  • Y از پشت سر تا بینی (پشت به جلو)
  • Z از گردن تا بالای سر

فیلد داده: مقدار سفارشی ۲ (0x0545)

فیلد «مقدار سفارشی ۲» (0x0545) یک فیلد ورودی است که برای گزارش کردن اطلاعات واقعی ردیابی سر استفاده می‌شود. این یک آرایه نقطه ثابت ۳ عنصری است که طبق قوانین عادی HID برای مقادیر فیزیکی تفسیر می‌شود. واحدها همیشه رادیان/ثانیه هستند.

عناصر به‌صورت زیر تفسیر می‌شوند: [vx, vy, vz]، به‌طوری‌که [vx, vy, vz] یک بردار چرخش است، که سرعت زاویه‌ای قاب سر را (نسبت‌به خودش) نشان می‌دهد.

فیلد داده: مقدار سفارشی ۳ (0x0546)

فیلد «مقدار سفارشی ۳» (0x0546) یک فیلد ورودی است که برای پیگیری ناپیوستگی‌ها در چارچوب مرجع استفاده می‌شود. این یک عدد صحیح اسکالر ۸ بیتی در اندازه است. هر بار که چارچوب مرجع تغییر می‌کند، برای مثال، اگر الگوریتم فیلتر گرایشی که برای تعیین گرایش استفاده می‌شود وضعیتش بازنشانی شود، باید این مقدار در دستگاه افزایش یابد (با چرخش). این مقدار براساس قوانین عادی HID برای مقادیر فیزیکی تفسیر می‌شود. بااین‌حال، مقدار فیزیکی و واحدها مهم نیستند. تنها اطلاعات مربوط به میزبان مقدار تغییریافته است. برای جلوگیری از مشکلات عددی مربوط به ازدست رفتن دقت هنگام تبدیل از واحدهای منطقی به فیزیکی، توصیه می‌شود مقادیر حداقل فیزیکی، حداکثر فیزیکی، و توان واحد را برای این فیلد روی صفر تنظیم کنید.

ساختار گزارش

گروه‌بندی دارایی‌ها در گزارش‌ها (براساس تخصیص شناسه‌های گزارش) انعطاف‌پذیر است. برای کارآمدی، توصیه می‌کنیم دارایی‌های فقط خواندنی را از دارایی‌های خواندنی/نوشتنی جدا کنید.

برای فیلدهای داده، فیلدهای «مقدار سفارشی ۱»، «۲»، و «۳» باید در همان گزارش باشند و برای دستگاهی معین (مجموعه برنامه) فقط در یک گزارش باشند.

ارسال گزارش‌های ورودی

دستگاه باید به‌طور دوره‌ای و ناهمگام (ازطریق پیام‌های HID INPUT) گزارش‌های ورودی را وقتی همه این شرایط برآورده می‌شود ارسال کند:

  • دارایی «وضعیت برق» روی «برق کامل» تنظیم شده است.
  • دارایی «وضعیت گزارش‌دهی» روی «همه رویدادها» تنظیم شده است.
  • دارایی «فاصله گزارش‌دهی» غیرصفر است.

دارایی «فاصله گزارش‌دهی» تعیین می‌کند که گزارش‌ها هر چند وقت یک‌بار ارسال شوند. وقتی هریک از شرایط بالا برآورده نشود، دستگاه نباید هیچ گزارشی ارسال کند.

سازگاری با نسخه قدیمی و جدید

پروتکل HID ردیاب سر از طرح نسخه‌بندی استفاده می‌کند که امکان به‌روزرسانی را فراهم می‌کند، درحالی‌که امکان همکاری بین میزبان و دستگاهی را که از نسخه‌های مختلف پروتکل استفاده می‌کنند فراهم می‌کند. نسخه‌های پروتکل با دو عدد، اصلی و فرعی، شناسایی می‌شوند که معنای متمایزی دارند، همان‌طور که در بخش‌های زیر توضیح داده شده است.

نسخه‌های پشتیبانی‌شده توسط دستگاه را می‌توان با بررسی ویژگی «شرح حسگر» (0x0308) آن تعیین کرد.

سازگاری نسخه فرعی

تغییرات نسخه جزئی با نسخه‌های جزئی قبلی که براساس همان نسخه عمده هستند سازگار با نسخه قدیمی است. در به‌روزرسانی‌های نسخه فرعی، میزبان فیلدها و دارایی‌های داده اضافی را نادیده می‌گیرد. برای مثال، دستگاهی که از نسخه ۱.۶ پروتکل استفاده می‌کند با میزبانی که از نسخه ۱.x پروتکل پشتیبانی می‌کند، ازجمله نسخه ۱.۵، سازگار است.

سازگاری نسخه اصلی

تغییرات غیرسازگار با نسخه‌های قبلی برای تغییرات در نسخه‌های اصلی مجاز است. برای پشتیبانی از چندین نسخه اصلی برای قابلیت همکاری با میزبان‌های قدیمی و جدید، دستگاه‌ها می‌توانند چندین مجموعه برنامه را در توصیف‌کننده‌های گزارش خود مشخص کنند. برای مثال:

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

در این مورد، میزبان می‌تواند همه مجموعه‌های برنامه مختلف را که دستگاه تبلیغ می‌کند فهرست کند، با بررسی کردن دارایی «شرح حسگر» آن‌ها نسخه‌های پروتکل را که هرکدام پیاده‌سازی می‌کنند تعیین کند، سپس جدیدترین نسخه پروتکل را که میزبان پشتیبانی می‌کند انتخاب کند. وقتی انتخاب شود، میزبان با پروتکل واحدی که برای طول عمر اتصال دستگاه انتخاب شده است کار می‌کند.

پیوست: نمونه‌ای از توصیفگر HID

مثال زیر یک توصیف‌گر HID معتبر معمولی را نشان می‌دهد. این فایل از ماکروهای C پرکاربرد که در HID Sensor Usages (بخش ۴.۱) ارائه شده است استفاده می‌کند.

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

پیوست ۲: نمونه‌ای از توصیف‌گر HID نسخه ۲.۰

مثال زیر توصیف‌گر HID نسخه ۲.۰ را برای دستگاهی نشان می‌دهد که فقط از انتقال 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,
};