Giao thức HID của thiết bị theo dõi đầu

Giao thức thiết bị giao diện người dùng (HID) của thiết bị theo dõi chuyển động của đầu, có sẵn cho các thiết bị chạy Android 13 trở lên, cho phép thiết bị theo dõi chuyển động của đầu được kết nối với một thiết bị Android thông qua USB hoặc Bluetooth cũng như tiếp xúc với khung và ứng dụng Android thông qua cảm biến. Giao thức này được dùng cho đang điều khiển hiệu ứng ảo hoá âm thanh (âm thanh 3D). Trang này sử dụng các thuật ngữ devicehost theo nghĩa Bluetooth, trong đó device có nghĩa là thiết bị theo dõi chuyển động của đầu và host là máy chủ Android.

Nhà sản xuất thiết bị phải định cấu hình thiết bị Android của họ để cho phép hỗ trợ cho giao thức HID của thiết bị theo dõi đầu. Để biết thêm thông tin chi tiết về , hãy xem README Cảm biến động.

Trang này giả định rằng bạn đã quen thuộc với các tài nguyên sau:

Cấu trúc cấp cao nhất

Khung Android xác định thiết bị theo dõi chuyển động của đầu là thiết bị HID.

Để biết ví dụ đầy đủ về bộ mô tả HID hợp lệ, hãy xem Phụ lục 1: Ví dụ về mã mô tả HID.

Ở cấp cao nhất, thiết bị theo dõi chuyển động của đầu là một tập hợp ứng dụng có Sensors trang (0x20) và mức sử dụng Other: Custom (0xE1). Bên trong bao gồm một số trường dữ liệu (thông tin đầu vào) và thuộc tính (tính năng).

Tài sản và trường dữ liệu

Phần này mô tả các thuộc tính và trường dữ liệu trong một ứng dụng một bộ sưu tập thiết bị theo dõi chuyển động của đầu.

Thuộc tính: Mô tả cảm biến (0x0308)

Thuộc tính Nội dung mô tả cảm biến (0x0308) là một chuỗi ASCII (8 bit) chỉ đọc thuộc tính phải chứa các giá trị sau:

Công cụ theo dõi chuyển động của đầu phiên bản 1.0:

#AndroidHeadTracker#1.0

Thiết bị theo dõi giao diện người dùng phiên bản 2.0 (có trong Android 15 hoặc cao hơn), bao gồm cả tính năng hỗ trợ Âm thanh năng lượng thấp:

#AndroidHeadTracker#2.0#x

x là một số nguyên (1, 2, 3) cho biết truyền tải hỗ trợ:

  • 1: Danh sách kiểm soát quyền truy cập (ACL)
  • 2: ISO
  • 3: ACL + ISO

Dự kiến không có dấu kết thúc rỗng, nghĩa là tổng kích thước của thuộc tính này là 23 ký tự 8 bit cho phiên bản 1.0.

Thuộc tính này đóng vai trò là yếu tố phân biệt để tránh xung đột với các thuộc tính khác các cảm biến tùy chỉnh.

Tài sản: Mã nhận dạng duy nhất cố định (0x0302)

Thuộc tính Mã nhận dạng duy nhất cố định (0x0302) là một mảng chỉ có thể đọc gồm 16 các phần tử, mỗi phần tử 8 bit (tổng cộng 128 bit). Không có ký tự kết thúc rỗng. Chiến dịch này là không bắt buộc.

Tài sản này cho phép sử dụng các thiết bị theo dõi chuyển động của đầu được tích hợp vào tính năng âm thanh để tham chiếu đến thiết bị âm thanh được gắn với thiết bị đó. Các giao thức sau được hỗ trợ.

Công cụ theo dõi đầu độc lập

Nếu thuộc tính Mã nhận dạng duy nhất cố định (0x0302) không tồn tại hoặc được đặt thành tất cả 0, nghĩa là thiết bị theo dõi chuyển động đầu không được gắn vĩnh viễn với thiết bị âm thanh và có thể được sử dụng riêng, chẳng hạn như bằng cách cho phép người dùng liên kết thiết bị theo dõi chuyển động của đầu với một thiết bị âm thanh riêng theo cách thủ công.

Tham chiếu sử dụng địa chỉ MAC Bluetooth

Bộ tám 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Giá trị 0 0 0 0 0 0 0 0 B T5 Bluetooth MAC

Trong lược đồ này, 8 octet đầu tiên phải là 0, octet 8 và 9 phải chứa các giá trị ASCII tương ứng là BT và 6 octet sau đây là được hiểu là địa chỉ MAC Bluetooth, giả sử thiết bị theo dõi chuyển động của đầu áp dụng cho mọi thiết bị âm thanh có địa chỉ MAC này. Địa chỉ này phải là địa chỉ nhận dạng, ngay cả khi thiết bị sử dụng địa chỉ MAC ngẫu nhiên để thiết lập kết nối. Các thiết bị chế độ kép kết nối qua Bluetooth cổ điển (định dạng HID phiên bản 1.0) và Bluetooth LE (định dạng HID phiên bản 2.0) phải hiển thị hai HID mã mô tả có cùng địa chỉ nhận dạng. Các thiết bị ở chế độ hai chế độ riêng biệt các thiết bị bên trái và bên phải phải bật Bluetooth LE HID bằng chế độ kép chính thiết bị chế độ thay vì thiết bị phụ chỉ dành cho LE.

Tham chiếu bằng mã nhận dạng duy nhất (UUID)

Bất cứ khi nào bit quan trọng nhất (MSB) của octet 8 được đặt (≥0x80), trường được diễn giải là UUID, như được chỉ định trong RFC-4122. Chiến lược phát hành đĩa đơn thiết bị âm thanh tương ứng cung cấp cùng một UUID, được đăng ký trên khung Android, thông qua một cơ chế không xác định dành riêng cho loại phương tiện giao thông được sử dụng.

Tài sản: Trạng thái báo cáo (0x0316)

Thuộc tính Trạng thái báo cáo (0x0316) là thuộc tính đọc/ghi có ngữ nghĩa chuẩn như được xác định trong thông số kỹ thuật HID. Người tổ chức sử dụng để cho thiết bị biết cần báo cáo sự kiện nào. Chỉ những giá trị Không Sự kiện (0x0840) và Tất cả sự kiện (0x0841) sẽ được dùng.

Giá trị ban đầu cho trường này phải là Không có sự kiện và không được là sửa đổi bởi thiết bị, chỉ do người tổ chức.

Tài sản: Trạng thái nguồn (0x0319)

Thuộc tính Trạng thái nguồn (0x0319) là thuộc tính đọc/ghi có các ngữ nghĩa chuẩn như được xác định trong thông số kỹ thuật HID. Người tổ chức sử dụng để cho thiết bị biết trạng thái nguồn của thiết bị. Chỉ các giá trị Tắt nguồn (0x0851) và Tắt nguồn (0x0855) đều được sử dụng.

Giá trị ban đầu cho trường này là do thiết bị xác định và không được là sửa đổi bởi thiết bị, chỉ do người tổ chức.

Thuộc tính: Khoảng thời gian báo cáo (0x030E)

Thuộc tính Khoảng thời gian báo cáo (0x030E) là thuộc tính đọc/ghi có ngữ nghĩa chuẩn như được xác định trong thông số kỹ thuật HID. Người tổ chức sử dụng để cho thiết bị biết tần suất báo cáo các lần đọc dữ liệu. Đơn vị là giây. Phạm vi hợp lệ cho giá trị này là do thiết bị xác định và được mô tả bằng cơ chế Tối thiểu/Tối đa thực tế. Tối thiểu 50 Hz tỷ lệ báo cáo phải được hỗ trợ và tốc độ báo cáo tối đa được đề xuất là 100 Hz. Do đó, khoảng thời gian tối thiểu trong báo cáo phải nhỏ hơn hoặc bằng thành 20 mili giây và nên lớn hơn hoặc bằng 10 mili giây.

Tài sản: Dịch vụ vận chuyển LE dành riêng cho nhà cung cấp (0xF410)

Thuộc tính LE Transport (0xF410) do nhà cung cấp đặt trước là một thuộc tính đọc/ghi có ngữ nghĩa chuẩn như được xác định trong thông số kỹ thuật HID. Máy chủ lưu trữ sử dụng thuộc tính này để biểu thị truyền tải đã chọn (ACL hoặc ISO). Chỉ giá trị ACL (0xF800) và ISO (0xF801) được sử dụng và phải bao gồm cả hai trong tập hợp logic.

Thuộc tính này được định cấu hình trước trạng thái bật/tắt nguồn hoặc báo cáo.

Trường dữ liệu: Giá trị tuỳ chỉnh 1 (0x0544)

Trường Giá trị tuỳ chỉnh 1 (0x0544) là trường nhập dữ liệu dùng để báo cáo thông tin theo dõi chuyển động thực tế của người dùng. Đó là một mảng gồm 3 phần tử, được diễn giải theo các quy tắc HID thông thường đối với các giá trị vật lý nêu trong mục 6.2.2.7 của thông số kỹ thuật HID. Khoảng hợp lệ cho mỗi phần tử là [-π, π] Rad. Đơn vị luôn là radian.

Các phần tử được diễn giải là: [rx, ry, rz], do đó [rx, ry, rz] là một vectơ xoay, biểu thị sự biến đổi từ hệ quy chiếu đến khung đầu. Cường độ phải nằm trong phạm vi [0..π].

Khung tham chiếu là tuỳ ý nhưng thường được cố định và phải được cho tay phải. Có thể chấp nhận độ trôi một chút. Các trục của đầu là:

  • X từ tai trái sang phải
  • Y từ sau đầu đến mũi (từ trước ra sau)
  • Z từ cổ đến đỉnh đầu

Trường dữ liệu: Giá trị tuỳ chỉnh 2 (0x0545)

Trường Giá trị tuỳ chỉnh 2 (0x0545) là trường nhập dữ liệu dùng để báo cáo thông tin theo dõi chuyển động thực tế của người dùng. Đó là một mảng điểm cố định gồm 3 phần tử được diễn giải theo quy tắc HID thông thường đối với các giá trị vật lý. Đơn vị luôn là radian/giây.

Các phần tử được diễn giải là: [vx, vy, vz], do đó [vx, vy, vz] là một vectơ xoay, biểu thị vận tốc góc của khung đầu (so với chính nó).

Trường dữ liệu: Giá trị tuỳ chỉnh 3 (0x0546)

Trường Giá trị tùy chỉnh 3 (0x0546) là trường nhập được sử dụng để theo dõi điểm gián đoạn trong khung tham chiếu. Đó là một số nguyên vô hướng 8 bit trong kích thước. Giá trị này phải được tăng lên (có bao quanh) theo thiết bị mỗi khi hệ quy chiếu thay đổi, ví dụ: nếu thuật toán bộ lọc hướng dùng để xác định hướng đã được đặt lại trạng thái. Giá trị này là được diễn giải theo quy tắc HID thông thường đối với các giá trị vật lý. Tuy nhiên, giá trị vật lý và đơn vị không quan trọng. Thông tin duy nhất liên quan đến lưu trữ là một giá trị đã thay đổi. Để tránh các vấn đề về số liên quan đến việc mất độ chính xác trong khi chuyển đổi từ đơn vị logic sang đơn vị thực, bạn nên đặt các giá trị cho tối thiểu vật lý, tối đa vật lý và số mũ đơn vị đến 0 cho trường này.

Cấu trúc báo cáo

Việc nhóm các tài sản vào báo cáo (bằng cách chỉ định mã báo cáo) là linh hoạt. Để tăng tính hiệu quả, bạn nên tách riêng các thuộc tính chỉ có thể đọc qua các thuộc tính đọc/ghi.

Đối với các trường dữ liệu, các trường Giá trị tuỳ chỉnh 1, 2 và 3 phải giống nhau và chỉ có trong một báo cáo cho một thiết bị cụ thể (bộ sưu tập ứng dụng).

Gửi báo cáo đầu vào

Thiết bị phải định kỳ và không đồng bộ (thông qua thông báo HID INPUT) gửi báo cáo đầu vào khi tất cả các điều kiện sau được đáp ứng:

  • Thuộc tính Trạng thái nguồn được đặt thành Mức công suất tối đa.
  • Thuộc tính Trạng thái báo cáo được đặt thành Tất cả sự kiện.
  • Thuộc tính Khoảng thời gian báo cáo khác 0.

Thuộc tính Khoảng thời gian báo cáo xác định tần suất gửi báo cáo. Thời gian không đáp ứng được bất kỳ điều kiện nào ở trên, thì thiết bị không được gửi bất kỳ báo cáo nào.

Khả năng tương thích chuyển tiếp và ngược

Giao thức HID của thiết bị theo dõi chuyển động sử dụng một lược đồ tạo phiên bản cho phép bản cập nhật, đồng thời cho phép khả năng tương tác giữa một máy chủ lưu trữ và một thiết bị sử dụng các phiên bản khác nhau của giao thức. Đã xác định các phiên bản của giao thức này theo hai số, số lớn và số nhỏ, có ngữ nghĩa riêng biệt là được mô tả trong các phần sau.

Bạn có thể xác định các phiên bản mà một thiết bị hỗ trợ bằng cách kiểm tra thuộc tính Mô tả cảm biến (0x0308).

Khả năng tương thích với phiên bản nhỏ

Các thay đổi đối với phiên bản nhỏ có khả năng tương thích ngược với trẻ vị thành niên trước đó các phiên bản dựa trên cùng một phiên bản chính. Trong các bản cập nhật dành cho trẻ vị thành niên phiên bản, máy chủ lưu trữ sẽ bỏ qua các trường và thuộc tính dữ liệu khác. Ví dụ: thiết bị sử dụng giao thức phiên bản 1.6 tương thích với máy chủ hỗ trợ giao thức phiên bản 1.x, bao gồm cả phiên bản 1.5.

Khả năng tương thích với phiên bản lớn

Bạn được phép thực hiện các thay đổi không tương thích ngược đối với những thay đổi đối với phiên bản lớn. Người nhận hỗ trợ nhiều phiên bản chính để tương tác với máy chủ cũ và máy chủ mới, thiết bị có thể chỉ định nhiều bộ sưu tập ứng dụng trong báo cáo của họ mã mô tả. Ví dụ:

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

Trong trường hợp này, máy chủ lưu trữ có thể liệt kê tất cả các tập hợp ứng dụng khác nhau mà thiết bị quảng cáo, kiểm tra thuộc tính Sensor Description của họ để xác định các phiên bản giao thức mà mỗi công ty triển khai, sau đó chọn phiên bản giao thức mới nhất mà máy chủ hỗ trợ. Khi được chọn, máy chủ lưu trữ sẽ hoạt động bằng một giao thức duy nhất được chọn trong suốt vòng đời của thiết bị kết nối.

Phụ lục: Ví dụ về bộ mô tả HID

Ví dụ sau đây minh hoạ một bộ mô tả HID hợp lệ thông thường. Chiến dịch này sử dụng macro C thường được sử dụng, được cung cấp trong Việc sử dụng cảm biến HID (mục 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,
};

Phụ lục 2: Ví dụ về bộ mô tả HID v2.0

Ví dụ sau minh hoạ bộ mô tả HID phiên bản 2.0 cho một thiết bị hỗ trợ chỉ có Bluetooth LE ACL truyền tải.

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