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

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

ผู้ผลิตอุปกรณ์ต้องกำหนดค่าอุปกรณ์ Android เพื่อเปิดใช้การรองรับ โปรโตคอล HID ของการติดตามศีรษะ ดูข้อมูลโดยละเอียดเกี่ยวกับการกำหนดค่าได้ที่ 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

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

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

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

พร็อพเพอร์ตี้รหัสที่ไม่ซ้ำแบบถาวร (0x0302) เป็นอาร์เรย์แบบอ่านอย่างเดียวที่มีองค์ประกอบ 16 รายการ แต่ละรายการมี 8 บิต (รวม 128 บิต) ไม่คาดว่าจะมีการสิ้นสุดด้วยค่าว่าง พร็อพเพอร์ตี้นี้ ไม่บังคับ

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

อุปกรณ์ติดตามศีรษะแบบสแตนด์อโลน

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

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

Octet 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)

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

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

พร็อพเพอร์ตี้: สถานะพลังงาน (0x0319)

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

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

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

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

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

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

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

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

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

องค์ประกอบต่างๆ จะตีความได้ดังนี้ [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 สำหรับอุปกรณ์ที่รองรับเฉพาะการรับส่ง ACL ของบลูทูธ LE

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