โปรโตคอล HID ของเครื่องติดตามการเคลื่อนไหวศีรษะ

โปรโตคอลอุปกรณ์ที่โต้ตอบกับมนุษย์โดยตรง (HID) ของอุปกรณ์ติดตามการเคลื่อนไหวของศีรษะ ซึ่งพร้อมใช้งานสำหรับอุปกรณ์ที่ใช้ Android 13 ขึ้นไป จะช่วยให้อุปกรณ์ติดตามการเคลื่อนไหวของศีรษะเชื่อมต่อกับอุปกรณ์ Android ผ่าน USB หรือบลูทูธ และแสดงในเฟรมเวิร์กและแอป Android ผ่านเฟรมเวิร์กเซ็นเซอร์ โปรโตคอลนี้ใช้สำหรับการควบคุมเอฟเฟกต์การจำลองเสียง (เสียง 3 มิติ) หน้านี้จะใช้คำว่าอุปกรณ์และโฮสต์ในความหมายเกี่ยวกับบลูทูธ โดยอุปกรณ์หมายถึงอุปกรณ์ติดตามการเคลื่อนไหวศีรษะและโฮสต์หมายถึงโฮสต์ Android

ผู้ผลิตอุปกรณ์ต้องกำหนดค่าอุปกรณ์ Android เพื่อให้รองรับโปรโตคอล HID ของอุปกรณ์ติดตามศีรษะ ดูข้อมูลโดยละเอียดเกี่ยวกับการกําหนดค่าได้ที่ Dynamic Sensors README

หน้านี้ในกรณีที่คุ้นเคยกับแหล่งข้อมูลต่อไปนี้

โครงสร้างระดับบนสุด

เฟรมเวิร์ก Android ระบุว่าอุปกรณ์ติดตามศีรษะเป็นอุปกรณ์ HID

ดูตัวอย่างที่สมบูรณ์ของข้อบ่งชี้ HID ที่ถูกต้องได้ที่ภาคผนวก 1: ตัวอย่างข้อบ่งชี้ HID

ที่ระดับบนสุด อุปกรณ์ติดตามศีรษะเป็นคอลเล็กชันแอปที่มีหน้า Sensors (0x20) และการใช้งาน Other: Custom (0xE1) ภายในคอลเล็กชันนี้มีช่องข้อมูลหลายช่อง (อินพุต) และพร็อพเพอร์ตี้ (ฟีเจอร์)

พร็อพเพอร์ตี้และฟิลด์ข้อมูล

ส่วนนี้อธิบายพร็อพเพอร์ตี้และช่องข้อมูลในคอลเล็กชันแอปพลิเคชันของอุปกรณ์ติดตามการเคลื่อนไหวของศีรษะ

พร็อพเพอร์ตี้: คำอธิบายเซ็นเซอร์ (0x0308)

พร็อพเพอร์ตี้คำอธิบายเซ็นเซอร์ (0x0308) เป็นพร็อพเพอร์ตี้สตริง ASCII (8 บิต) แบบอ่านอย่างเดียว ซึ่งต้องมีค่าต่อไปนี้

อุปกรณ์ติดตามการเคลื่อนไหวของศีรษะเวอร์ชัน 1.0

#AndroidHeadTracker#1.0

อุปกรณ์ติดตามศีรษะเวอร์ชัน 2.0 (พร้อมใช้งานใน Android 15 ขึ้นไป) ซึ่งรวมถึงการรองรับ LE Audio ดังนี้

#AndroidHeadTracker#2.0#x

x คือจำนวนเต็ม (1, 2, 3) ที่ระบุการขนส่งที่รองรับ ดังนี้

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

ไม่มีการสิ้นสุดด้วยค่า Null ซึ่งหมายความว่าขนาดทั้งหมดของพร็อพเพอร์ตี้นี้คืออักขระ 8 บิต 23 ตัวสำหรับเวอร์ชัน 1.0

พร็อพเพอร์ตี้นี้ใช้เป็นตัวแยกแยะเพื่อหลีกเลี่ยงการทับซ้อนกับเซ็นเซอร์ที่กำหนดเองอื่นๆ

พร็อพเพอร์ตี้: รหัสที่ไม่ซ้ำกันแบบถาวร (0x0302)

พร็อพเพอร์ตี้ Persistent Unique ID (0x0302) คืออาร์เรย์แบบอ่านอย่างเดียวที่มี 16 เอลิเมนต์ รายการละ 8 บิต (ทั้งหมด 128 บิต) ไม่ควรมีตัวสิ้นสุด Null คุณจะระบุพร็อพเพอร์ตี้นี้หรือไม่ก็ได้

พร็อพเพอร์ตี้นี้ช่วยให้อุปกรณ์ติดตามการเคลื่อนไหวศีรษะที่ผสานรวมอยู่ในอุปกรณ์เสียงสามารถอ้างอิงอุปกรณ์เสียงที่ติดอยู่ได้ ระบบรองรับรูปแบบต่อไปนี้

อุปกรณ์ติดตามการเคลื่อนไหวของศีรษะแบบสแตนด์อโลน

หากไม่มีพร็อพเพอร์ตี้ Persistent Unique ID (0x0302) หรือตั้งค่าเป็นศูนย์ทั้งหมด แสดงว่าอุปกรณ์ติดตามศีรษะไม่ได้แนบกับอุปกรณ์เสียงอย่างถาวรและใช้แยกกันได้ เช่น ให้ผู้ใช้เชื่อมโยงอุปกรณ์ติดตามศีรษะกับอุปกรณ์เสียงแยกต่างหากด้วยตนเอง

การอ้างอิงใช้ที่อยู่ MAC ของบลูทูธ

อ็อกเท็ต 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
ค่า 0 0 0 0 0 0 0 0 B T MAC ของบลูทูธ

ในรูปแบบนี้ อ็อกเต็ต 8 ตัวแรกต้องเป็น 0 อ็อกเต็ต 8 และ 9 ต้องมีค่า ASCII เป็น B และ T ตามลำดับ และระบบจะตีความอ็อกเต็ต 6 ตัวถัดไปเป็นที่อยู่ MAC ของบลูทูธ โดยสมมติว่าอุปกรณ์ติดตามการเคลื่อนไหวของศีรษะใช้ได้กับอุปกรณ์เสียงที่มีที่อยู่ MAC นี้ ที่อยู่นี้ต้องเป็นที่อยู่ประจําตัว แม้ว่าอุปกรณ์จะใช้ที่อยู่ MAC แบบสุ่มเพื่อสร้างการเชื่อมต่อ อุปกรณ์แบบ 2 โหมดที่เชื่อมต่อผ่านบลูทูธคลาสสิก (รูปแบบ HID v1.0) และบลูทูธ LE (รูปแบบ HID v2.0) ต้องแสดงตัวบ่งชี้ HID 2 รายการที่มีที่อยู่เดียวกัน อุปกรณ์แบบ 2 โหมดที่มีอุปกรณ์ซ้ายและขวาแยกกันต้องแสดง HID ของบลูทูธ LE โดยใช้อุปกรณ์แบบ 2 โหมดหลักแทนอุปกรณ์รองที่ใช้ LE เท่านั้น

การอ้างอิงโดยใช้ UUID

เมื่อใดก็ตามที่มีการตั้งค่าบิตสําคัญที่สุด (MSB) ของโอคเต็ต 8 (≥0x80) ระบบจะตีความช่องนี้เป็น UUID ตามที่ระบุไว้ใน RFC-4122 อุปกรณ์เสียงที่เกี่ยวข้องจะมี UUID เดียวกันซึ่งลงทะเบียนในเฟรมเวิร์กของ Android ผ่านกลไกที่ไม่ได้ระบุที่เจาะจงสำหรับประเภทการรับส่งข้อมูลที่ใช้

พร็อพเพอร์ตี้: สถานะการรายงาน (0x0316)

พร็อพเพอร์ตี้สถานะการรายงาน (0x0316) เป็นพร็อพเพอร์ตี้อ่าน/เขียนที่มีความหมายมาตรฐานตามที่นิยามไว้ในข้อกำหนด HID โฮสต์ใช้พร็อพเพอร์ตี้นี้เพื่อระบุเหตุการณ์ที่จะรายงานให้อุปกรณ์ทราบ ระบบจะใช้เฉพาะค่า ไม่มีเหตุการณ์ (0x0840) และเหตุการณ์ทั้งหมด (0x0841) เท่านั้น

ค่าเริ่มต้นของช่องนี้ต้องเป็น "ไม่มีเหตุการณ์" และต้องไม่แก้ไขโดยอุปกรณ์ แต่จะแก้ไขโดยโฮสต์เท่านั้น

คุณสมบัติ: สถานะพลังงาน (0x0319)

พร็อพเพอร์ตี้ Power State (0x0319) เป็นพร็อพเพอร์ตี้อ่าน/เขียนที่มีความหมายมาตรฐานตามที่นิยามไว้ในข้อกำหนด HID โฮสต์ใช้พร็อพเพอร์ตี้นี้เพื่อบ่งบอกสถานะพลังงานที่อุปกรณ์ต้องอยู่ ใช้เฉพาะค่าโหมดพลังงานเต็ม (0x0851) และปิดเครื่อง (0x0855) เท่านั้น

ค่าเริ่มต้นของช่องนี้จะกำหนดโดยอุปกรณ์ และต้องไม่แก้ไขโดยอุปกรณ์ แต่จะแก้ไขโดยโฮสต์เท่านั้น

พร็อพเพอร์ตี้: ช่วงเวลาของรายงาน (0x030E)

พร็อพเพอร์ตี้ระยะเวลาของรายงาน (0x030E) เป็นพร็อพเพอร์ตี้การอ่าน/เขียนที่มีความหมายมาตรฐานตามที่ระบุไว้ในข้อกำหนด HID โฮสต์ใช้พร็อพเพอร์ตี้นี้เพื่อระบุให้อุปกรณ์ทราบว่าจะรายงานการอ่านข้อมูลบ่อยเพียงใด หน่วยเป็นวินาที ช่วงที่ถูกต้องสำหรับค่านี้จะกำหนดโดยอุปกรณ์และอธิบายโดยใช้กลไก Physical นาที/สูงสุด ต้องรองรับอัตราการรายงานอย่างน้อย 50 Hz และอัตราการรายงานสูงสุดที่แนะนำคือ 100 Hz ดังนั้น ช่วงเวลารายงานขั้นต่ำต้องน้อยกว่าหรือเท่ากับ 20 ms และควรมากกว่าหรือเท่ากับ 10 ms

พร็อพเพอร์ตี้: LE Transport ที่ผู้ให้บริการสงวนไว้ (0xF410)

พร็อพเพอร์ตี้ LE Transport (0xF410) ที่ผู้ให้บริการสงวนไว้เป็นพร็อพเพอร์ตี้แบบอ่าน/เขียนที่มีความหมายมาตรฐานตามที่ระบุไว้ในข้อกำหนด HID โฮสต์ใช้พร็อพเพอร์ตี้นี้เพื่อระบุการรับส่งข้อมูลที่เลือก (ACL หรือ ISO) ใช้เฉพาะค่า ACL (0xF800) และ ISO (0xF801) เท่านั้น โดยต้องรวมทั้ง 2 ค่าไว้ในคอลเล็กชันเชิงตรรกะ

พร็อพเพอร์ตี้นี้ได้รับการกำหนดค่าก่อนสถานะกำลังหรือการรายงาน

ฟิลด์ข้อมูล: ค่าที่กำหนดเอง 1 (0x0544)

ช่องค่าที่กำหนดเอง 1 (0x0544) คือช่องป้อนข้อมูลที่ใช้สำหรับการรายงานข้อมูลการติดตามการเคลื่อนไหวของศีรษะจริง อาร์เรย์ 3 องค์ประกอบที่ตีความตามกฎ HID ปกติสำหรับค่าทางกายภาพตามที่ระบุไว้ในส่วนที่ 6.2.2.7 ของข้อกำหนด HID ช่วงที่ถูกต้องสำหรับองค์ประกอบแต่ละรายการคือ [-π, π] rad หน่วยจะเป็นเรเดียนเสมอ

ระบบจะตีความองค์ประกอบเป็น [rx, ry, rz] โดยที่ [rx, ry, rz] คือเวกเตอร์การหมุน ซึ่งแสดงการเปลี่ยนรูปแบบจากเฟรมอ้างอิงไปยังเฟรมส่วนหัว ค่าแมกนิจูดต้องอยู่ในช่วง [0..π]

เฟรมอ้างอิงเป็นค่าที่กำหนดเอง แต่โดยทั่วไปจะกำหนดไว้แบบคงที่และต้องเป็นแบบมือขวา ยอมรับได้ว่ามีละอองลอยเล็กน้อย แกนศีรษะมีดังนี้

  • X จากหูฟังข้างซ้ายไปขวา
  • Y จากด้านหลังศีรษะถึงจมูก (จากด้านหลังไปด้านหน้า)
  • Z จากคอถึงด้านบนของศีรษะ

ฟิลด์ข้อมูล: ค่าที่กำหนดเอง 2 (0x0545)

ช่องค่าที่กำหนดเอง 2 (0x0545) เป็นช่องป้อนข้อมูลที่ใช้ในการรายงานข้อมูลการติดตามส่วนหัวจริง อาร์เรย์จุดคงที่ 3 องค์ประกอบ ซึ่งตีความตามกฎ HID ปกติสำหรับค่าทางกายภาพ หน่วยจะเป็นเรเดียน/วินาทีเสมอ

ระบบจะตีความองค์ประกอบว่าเป็น [vx, vy, vz] ซึ่งทำให้ [vx, vy, vz] เป็นเวกเตอร์การหมุน ซึ่งแสดงถึงความเร็วเชิงมุมของเฟรมส่วนหัว (สัมพันธ์กับตัวเอง)

ฟิลด์ข้อมูล: ค่าที่กำหนดเอง 3 (0x0546)

ช่องค่าที่กำหนดเอง 3 (0x0546) เป็นช่องป้อนข้อมูลที่ใช้สำหรับการติดตามความไม่ต่อเนื่องในเฟรมอ้างอิง เป็นจำนวนเต็มสเกลาร์ จำนวนเต็ม 8 บิต โดยอุปกรณ์จะต้องเพิ่มขึ้น (มีการล้อมรอบ) ทุกครั้งที่เฟรมของการอ้างอิงมีการเปลี่ยนแปลง เช่น หากอัลกอริทึมตัวกรองการวางแนวที่ใช้เพื่อกำหนดการวางแนวได้รีเซ็ตสถานะ ระบบจะตีความค่านี้ตามกฎ HID ปกติสำหรับค่าทางกายภาพ แต่ค่าจริงและหน่วยจะไม่มีผล ข้อมูลเดียวที่เกี่ยวข้องกับโฮสต์คือค่าที่มีการเปลี่ยนแปลง หากต้องการหลีกเลี่ยงปัญหาตัวเลขที่เกี่ยวข้องกับการสูญเสียความแม่นยำขณะแปลงจากหน่วยเชิงตรรกะเป็นหน่วยกายภาพ เราขอแนะนำให้กำหนดค่าต่ำสุดทางกายภาพ ค่าสูงสุดทางกายภาพ และเลขชี้กำลังของหน่วยเป็น 0 สำหรับฟิลด์นี้

โครงสร้างรายงาน

การจัดกลุ่มพร็อพเพอร์ตี้เป็นรายงาน (โดยการกําหนดรหัสรายงาน) มีความยืดหยุ่น เราขอแนะนำให้แยกพร็อพเพอร์ตี้ที่อ่านอย่างเดียวออกจากพร็อพเพอร์ตี้ที่อ่าน/เขียนเพื่อให้มีประสิทธิภาพ

สำหรับช่องข้อมูล ช่องค่าที่กำหนดเอง 1, 2 และ 3 จะต้องอยู่ในรายงานเดียวกันและอยู่ในรายงานเดียวสำหรับอุปกรณ์หนึ่งๆ (คอลเล็กชันแอป)

ส่งรายงานอินพุต

อุปกรณ์ต้องส่งรายงานอินพุตเป็นระยะๆ และไม่พร้อมกัน (ผ่านข้อความ HID INPUT) เมื่อเป็นไปตามเงื่อนไขทั้งหมดต่อไปนี้

  • พร็อพเพอร์ตี้สถานะพลังงานตั้งค่าเป็น "เปิดเต็มกำลัง"
  • ตั้งค่าพร็อพเพอร์ตี้สถานะการรายงานเป็นเหตุการณ์ทั้งหมด
  • พร็อพเพอร์ตี้ช่วงเวลาการรายงานไม่ใช่ 0

พร็อพเพอร์ตี้ "ช่วงเวลาการรายงาน" จะกําหนดความถี่ในการส่งรายงาน เมื่อไม่ตรงตามเงื่อนไขใดๆ ข้างต้น อุปกรณ์จะต้องไม่ส่งรายงานใดๆ

ความเข้ากันได้แบบส่งต่อและย้อนหลัง

โปรโตคอล HID ของตัวติดตามส่วนหัวใช้รูปแบบการกำหนดเวอร์ชันที่อนุญาตให้อัปเดต ขณะที่อนุญาตให้โฮสต์และอุปกรณ์ที่ใช้โปรโตคอลเวอร์ชันต่างกันสามารถทำงานร่วมกันได้ เวอร์ชันต่างๆ ของโปรโตคอลจะระบุด้วยตัวเลข 2 หลัก ได้แก่ หลักและรอง ซึ่งมีความหมายแตกต่างกันตามที่อธิบายไว้ในส่วนต่อไปนี้

คุณสามารถระบุเวอร์ชันที่อุปกรณ์รองรับได้โดยการตรวจสอบพร็อพเพอร์ตี้คำอธิบายเซ็นเซอร์ (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,
};

ในกรณีนี้ โฮสต์สามารถแจกแจงคอลเล็กชันแอปทั้งหมดที่อุปกรณ์โฆษณา ตรวจสอบพร็อพเพอร์ตี้คำอธิบายเซ็นเซอร์เพื่อระบุเวอร์ชันของโปรโตคอลที่แต่ละเวอร์ชันใช้ แล้วเลือกโปรโตคอลเวอร์ชันล่าสุดที่โฮสต์รองรับ เมื่อเลือกแล้ว โฮสต์จะทํางานกับโปรโตคอลเดียวที่เลือกไว้ตลอดอายุการใช้งานการเชื่อมต่อของอุปกรณ์

ภาคผนวก: ตัวอย่างของข้อบ่งชี้ 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 สำหรับอุปกรณ์ที่รองรับเฉพาะการรับส่ง 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,
};