پروتکل HID ردیاب سر

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

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

این صفحه به فرض آشنایی با منابع زیر است:

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

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

برای مثال کامل یک توصیفگر HID معتبر، به پیوست 1 مراجعه کنید: نمونه ای از توصیفگر HID .

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

خواص و فیلدهای داده

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

ویژگی: توضیحات سنسور ( 0x0308 )

ویژگی Sensor Description ( 0x0308 ) یک ویژگی رشته ASCII (8 بیتی) فقط خواندنی است که باید حاوی مقادیر زیر باشد:

ردیاب سر نسخه 1.0:

#AndroidHeadTracker#1.0

Head Tracker نسخه 2.0 (موجود در Android 15 یا بالاتر)، که شامل پشتیبانی از صدای LE است:

#AndroidHeadTracker#2.0#x

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

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

هیچ پایان دهنده تهی انتظار نمی رود، به این معنی که اندازه کل این ویژگی 23 کاراکتر 8 بیتی برای نسخه 1.0 است.

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

ویژگی: شناسه منحصر به فرد پایدار ( 0x0302 )

ویژگی Persistent Unique ID ( 0x0302 ) یک آرایه فقط خواندنی از 16 عنصر است که هر کدام 8 بیت (مجموع 128 بیت) است. هیچ پایان دهنده تهی انتظار نمی رود. این ویژگی اختیاری است.

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

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

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

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

اکتت 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
ارزش 0 0 0 0 0 0 0 0 ب تی مک بلوتوث

در این طرح، 8 اکتت اول باید 0 باشند، 8 و 9 باید به ترتیب حاوی مقادیر ASCII B و T باشند، و 6 اکتت زیر به عنوان یک آدرس مک بلوتوث تفسیر می شوند، با فرض اینکه دستگاه ردیاب هد برای هر دستگاه صوتی دارای اعمال می شود. این آدرس مک این آدرس باید آدرس هویت باشد، حتی اگر دستگاه از یک آدرس MAC تصادفی برای برقراری اتصال استفاده کند. دستگاه‌های دو حالته که از طریق بلوتوث کلاسیک (فرمت v1.0 HID) و بلوتوث LE (فرمت v2.0 HID) متصل می‌شوند باید دو توصیفگر HID با آدرس هویت یکسان را نشان دهند. دستگاه‌های دو حالته با دستگاه‌های چپ و راست مجزا باید بلوتوث LE HID را با استفاده از دستگاه حالت دوگانه اولیه به جای دستگاه ثانویه فقط LE در معرض دید قرار دهند.

ارجاع با استفاده از UUID

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

ویژگی: وضعیت گزارش ( 0x0316 )

ویژگی State Reporting ( 0x0316 ) یک ویژگی خواندن/نوشتن است که دارای معنای استانداردی است که در مشخصات HID تعریف شده است. میزبان از این ویژگی برای نشان دادن رویدادهایی که باید به دستگاه گزارش دهد استفاده می کند. فقط از مقادیر No Events ( 0x0840 ) و All Events ( 0x0841 ) استفاده می شود.

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

ویژگی: Power State ( 0x0319 )

ویژگی Power State ( 0x0319 ) یک ویژگی خواندن/نوشتن است که دارای معنای استانداردی است که در مشخصات HID تعریف شده است. میزبان از این ویژگی استفاده می کند تا به دستگاه نشان دهد که در کدام حالت برق باید باشد. فقط از مقادیر Full Power ( 0x0851 ) و Power Off ( 0x0855 ) استفاده می شود.

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

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

ویژگی Report Interval ( 0x030E ) یک ویژگی خواندن/نوشتن است که دارای معنای استانداردی است که در مشخصات HID تعریف شده است. میزبان از این ویژگی برای نشان دادن تعداد دفعات گزارش خواندن داده های خود به دستگاه استفاده می کند. واحدها ثانیه هستند. محدوده معتبر برای این مقدار توسط دستگاه تعیین می شود و با استفاده از مکانیسم حداقل/حداکثر فیزیکی توصیف می شود. حداقل نرخ گزارش 50 هرتز باید پشتیبانی شود و حداکثر نرخ گزارش توصیه شده 100 هرتز است. بنابراین، حداقل فاصله گزارش باید کمتر یا مساوی 20 میلی ثانیه باشد و توصیه می شود بیشتر یا مساوی 10 میلی ثانیه باشد.

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

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

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

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

فیلد Custom Value 1 ( 0x0544 ) یک فیلد ورودی است که برای گزارش اطلاعات واقعی ردیابی سر استفاده می شود. این یک آرایه 3 عنصری است که بر اساس قوانین HID معمولی برای مقادیر فیزیکی همانطور که در بخش 6.2.2.7 از مشخصات HID مشخص شده است، تفسیر شده است. محدوده معتبر برای هر عنصر [-π, π] راد است. واحدها همیشه رادیان هستند.

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

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

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

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

فیلد Custom Value 2 ( 0x0545 ) یک فیلد ورودی است که برای گزارش اطلاعات واقعی ردیابی سر استفاده می شود. این یک آرایه 3 عنصری با نقطه ثابت است که بر اساس قوانین HID معمولی برای مقادیر فیزیکی تفسیر شده است. واحدها همیشه رادیان/ثانیه هستند.

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

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

فیلد Custom Value 3 ( 0x0546 ) یک فیلد ورودی است که برای ردیابی ناپیوستگی ها در قاب مرجع استفاده می شود. این یک عدد صحیح اسکالر با اندازه 8 بیت است. برای مثال، اگر یک الگوریتم فیلتر جهت که برای تعیین جهت استفاده می‌شود، حالت خود را بازنشانی کرده باشد، هر بار که چارچوب مرجع تغییر می‌کند، باید توسط دستگاه افزایش یابد (با پوشش). این مقدار بر اساس قوانین HID معمولی برای مقادیر فیزیکی تفسیر می شود. با این حال، ارزش فیزیکی و واحدها مهم نیست. تنها اطلاعات مربوط به میزبان یک مقدار تغییر یافته است. برای جلوگیری از مسائل عددی مربوط به از دست دادن دقت هنگام تبدیل از واحدهای منطقی به فیزیکی، توصیه می‌شود مقادیر حداقل فیزیکی، حداکثر فیزیکی و توان واحد را برای این فیلد روی صفر قرار دهید.

ساختار گزارش

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

برای فیلدهای داده، فیلدهای مقدار سفارشی 1، 2، و 3 باید در همان گزارش باشند و فقط در یک گزارش برای دستگاه معین (مجموعه برنامه) باشند.

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

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

  • ویژگی Power State روی Full Power تنظیم شده است.
  • ویژگی دولت گزارشگر روی همه رویدادها تنظیم شده است.
  • ویژگی Reporting Interval غیر صفر است.

ویژگی Reporting Interval تعیین می کند که هر چند وقت یکبار گزارش ها ارسال شود. هنگامی که هر یک از شرایط بالا برآورده نمی شود، دستگاه نباید هیچ گزارشی ارسال کند.

سازگاری رو به جلو و عقب

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

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

سازگاری نسخه جزئی

تغییرات نسخه جزئی با نسخه‌های کوچک قبلی که بر اساس همان نسخه اصلی هستند سازگار هستند. در به‌روزرسانی‌های نسخه کوچک، میزبان فیلدها و ویژگی‌های داده اضافی را نادیده می‌گیرد. به عنوان مثال، دستگاهی که از پروتکل نسخه 1.6 استفاده می کند، با میزبانی سازگار است که از نسخه 1.x، از جمله نسخه 1.5، از پروتکل پشتیبانی می کند.

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

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

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

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

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

مثال زیر یک توصیفگر معتبر HID معمولی را نشان می دهد. از ماکروهای رایج C استفاده می‌کند که در موارد استفاده از حسگر HID (بخش 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,
};

پیوست 2: نمونه ای از توصیفگر HID v2.0

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

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

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

این صفحه به فرض آشنایی با منابع زیر است:

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

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

برای مثال کامل یک توصیفگر HID معتبر، به پیوست 1 مراجعه کنید: نمونه ای از توصیفگر HID .

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

خواص و فیلدهای داده

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

ویژگی: توضیحات سنسور ( 0x0308 )

ویژگی Sensor Description ( 0x0308 ) یک ویژگی رشته ASCII (8 بیتی) فقط خواندنی است که باید حاوی مقادیر زیر باشد:

ردیاب سر نسخه 1.0:

#AndroidHeadTracker#1.0

Head Tracker نسخه 2.0 (موجود در Android 15 یا بالاتر)، که شامل پشتیبانی از صدای LE است:

#AndroidHeadTracker#2.0#x

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

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

هیچ پایان دهنده تهی انتظار نمی رود، به این معنی که اندازه کل این ویژگی 23 کاراکتر 8 بیتی برای نسخه 1.0 است.

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

ویژگی: شناسه منحصر به فرد پایدار ( 0x0302 )

ویژگی Persistent Unique ID ( 0x0302 ) یک آرایه فقط خواندنی از 16 عنصر است که هر کدام 8 بیت (مجموع 128 بیت) است. هیچ پایان دهنده تهی انتظار نمی رود. این ویژگی اختیاری است.

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

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

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

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

اکتت 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
ارزش 0 0 0 0 0 0 0 0 ب تی بلوتوث مک

در این طرح، 8 اکتت اول باید 0 باشند، 8 و 9 باید به ترتیب حاوی مقادیر ASCII B و T باشند، و 6 اکتت زیر به عنوان یک آدرس مک بلوتوث تفسیر می شوند، با فرض اینکه دستگاه ردیاب هد برای هر دستگاه صوتی دارای اعمال می شود. این آدرس مک این آدرس باید آدرس هویت باشد، حتی اگر دستگاه از یک آدرس MAC تصادفی برای برقراری اتصال استفاده کند. دستگاه‌های دو حالته که از طریق بلوتوث کلاسیک (فرمت v1.0 HID) و بلوتوث LE (فرمت v2.0 HID) متصل می‌شوند باید دو توصیفگر HID با آدرس هویت یکسان را نشان دهند. دستگاه‌های دو حالته با دستگاه‌های چپ و راست مجزا باید بلوتوث LE HID را با استفاده از دستگاه حالت دوگانه اولیه به جای دستگاه ثانویه فقط LE در معرض دید قرار دهند.

ارجاع با استفاده از UUID

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

ویژگی: وضعیت گزارش ( 0x0316 )

ویژگی State Reporting ( 0x0316 ) یک ویژگی خواندن/نوشتن است که دارای معنای استانداردی است که در مشخصات HID تعریف شده است. میزبان از این ویژگی برای نشان دادن رویدادهایی که باید به دستگاه گزارش دهد استفاده می کند. فقط از مقادیر No Events ( 0x0840 ) و All Events ( 0x0841 ) استفاده می شود.

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

ویژگی: Power State ( 0x0319 )

ویژگی Power State ( 0x0319 ) یک ویژگی خواندن/نوشتن است که دارای معنای استانداردی است که در مشخصات HID تعریف شده است. میزبان از این ویژگی استفاده می کند تا به دستگاه نشان دهد که در کدام حالت برق باید باشد. فقط از مقادیر Full Power ( 0x0851 ) و Power Off ( 0x0855 ) استفاده می شود.

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

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

ویژگی Report Interval ( 0x030E ) یک ویژگی خواندن/نوشتن است که دارای معنای استانداردی است که در مشخصات HID تعریف شده است. میزبان از این ویژگی برای نشان دادن تعداد دفعات گزارش خواندن داده های خود به دستگاه استفاده می کند. واحدها ثانیه هستند. محدوده معتبر برای این مقدار توسط دستگاه تعیین می شود و با استفاده از مکانیسم حداقل/حداکثر فیزیکی توصیف می شود. حداقل نرخ گزارش 50 هرتز باید پشتیبانی شود و حداکثر نرخ گزارش توصیه شده 100 هرتز است. بنابراین، حداقل فاصله گزارش باید کمتر یا مساوی 20 میلی ثانیه باشد و توصیه می شود بیشتر یا مساوی 10 میلی ثانیه باشد.

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

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

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

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

فیلد Custom Value 1 ( 0x0544 ) یک فیلد ورودی است که برای گزارش اطلاعات واقعی ردیابی سر استفاده می شود. این یک آرایه 3 عنصری است که بر اساس قوانین HID معمولی برای مقادیر فیزیکی همانطور که در بخش 6.2.2.7 از مشخصات HID مشخص شده است، تفسیر شده است. محدوده معتبر برای هر عنصر [-π, π] راد است. واحدها همیشه رادیان هستند.

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

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

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

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

فیلد Custom Value 2 ( 0x0545 ) یک فیلد ورودی است که برای گزارش اطلاعات واقعی ردیابی سر استفاده می شود. این یک آرایه 3 عنصری با نقطه ثابت است که بر اساس قوانین HID معمولی برای مقادیر فیزیکی تفسیر شده است. واحدها همیشه رادیان/ثانیه هستند.

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

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

فیلد Custom Value 3 ( 0x0546 ) یک فیلد ورودی است که برای ردیابی ناپیوستگی ها در قاب مرجع استفاده می شود. این یک عدد صحیح اسکالر با اندازه 8 بیت است. برای مثال، اگر یک الگوریتم فیلتر جهت که برای تعیین جهت استفاده می‌شود، حالت خود را بازنشانی کرده باشد، هر بار که چارچوب مرجع تغییر می‌کند، باید توسط دستگاه افزایش یابد (با پوشش). این مقدار بر اساس قوانین HID معمولی برای مقادیر فیزیکی تفسیر می شود. با این حال، ارزش فیزیکی و واحدها مهم نیست. تنها اطلاعات مربوط به میزبان یک مقدار تغییر یافته است. برای جلوگیری از مسائل عددی مربوط به از دست دادن دقت هنگام تبدیل از واحدهای منطقی به فیزیکی، توصیه می‌شود مقادیر حداقل فیزیکی، حداکثر فیزیکی و توان واحد را برای این فیلد روی صفر قرار دهید.

ساختار گزارش

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

برای فیلدهای داده، فیلدهای مقدار سفارشی 1، 2، و 3 باید در همان گزارش باشند و فقط در یک گزارش برای دستگاه معین (مجموعه برنامه) باشند.

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

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

  • ویژگی Power State روی Full Power تنظیم شده است.
  • ویژگی دولت گزارشگر روی همه رویدادها تنظیم شده است.
  • ویژگی Reporting Interval غیر صفر است.

ویژگی Reporting Interval تعیین می کند که هر چند وقت یکبار گزارش ها ارسال شود. هنگامی که هر یک از شرایط بالا برآورده نمی شود، دستگاه نباید هیچ گزارشی ارسال کند.

سازگاری رو به جلو و عقب

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

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

سازگاری نسخه جزئی

تغییرات نسخه جزئی با نسخه‌های کوچک قبلی که بر اساس همان نسخه اصلی هستند سازگار هستند. در به‌روزرسانی‌های نسخه کوچک، میزبان فیلدها و ویژگی‌های داده اضافی را نادیده می‌گیرد. به عنوان مثال، دستگاهی که از پروتکل نسخه 1.6 استفاده می کند، با میزبانی سازگار است که از نسخه 1.x، از جمله نسخه 1.5، از پروتکل پشتیبانی می کند.

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

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

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

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

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

مثال زیر یک توصیفگر معتبر HID معمولی را نشان می دهد. از ماکروهای رایج C استفاده می‌کند که در موارد استفاده از حسگر HID (بخش 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,
};

پیوست 2: نمونه ای از توصیفگر HID v2.0

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