Giao thức thiết bị có giao diện dành cho người dùng (HID) của thiết bị theo dõi đầu (dành cho các thiết bị chạy Android 13 trở lên) cho phép kết nối thiết bị theo dõi đầu với thiết bị Android qua USB hoặc Bluetooth, đồng thời được cung cấp cho khung Android và các ứng dụng thông qua khung cảm biến. Giao thức này được dùng để kiểm soát hiệu ứng ảo hoá âm thanh (âm thanh 3D). Trang này sử dụng các thuật ngữ thiết bị và máy chủ theo nghĩa Bluetooth, trong đó thiết bị có nghĩa là thiết bị theo dõi đầu và máy chủ có nghĩa là máy chủ Android.
Nhà sản xuất thiết bị phải định cấu hình thiết bị Android để hỗ trợ giao thức HID của thiết bị theo dõi đầu. Để biết thêm thông tin chi tiết về cấu hình, hãy xem Dynamic Sensors README (Tệp README của 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 đầu là một thiết bị HID.
Để xem ví dụ đầy đủ về một bộ mô tả HID hợp lệ, hãy xem Phụ lục 1: Ví dụ về bộ mô tả HID.
Ở cấp cao nhất, thiết bị theo dõi đầu là một tập hợp ứng dụng có trang Sensors
(0x20
) và mức sử dụng Other: Custom
(0xE1
). Bên trong tập hợp này có một số trường dữ liệu (đầu vào) và thuộc tính (tính năng).
Thuộc tính 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 bộ sưu tập ứng dụng của thiết bị theo dõi đầu.
Thuộc tính: Nội dung mô tả cảm biến (0x0308
)
Thuộc tính Nội dung mô tả cảm biến (0x0308
) là một thuộc tính chuỗi ASCII (8 bit) chỉ đọc và phải chứa các giá trị sau:
Head tracker phiên bản 1.0:
#AndroidHeadTracker#1.0
Trình theo dõi đầu phiên bản 2.0 (có trong Android 15 trở lên), có 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 phương thức vận chuyển được hỗ trợ:
- 1: ACL
- 2: ISO
- 3: ACL + ISO
Không có dấu kết thúc rỗng, tức 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à một giá trị phân biệt để tránh xung đột với các cảm biến tuỳ chỉnh khác.
Tài sản: Giá trị nhận dạng duy nhất ổn định (0x0302
)
Thuộc tính Mã nhận dạng duy nhất liên tục (0x0302
) là một mảng chỉ đọc gồm 16 phần tử, mỗi phần tử 8 bit (tổng cộng 128 bit). Không có dấu kết thúc rỗng. Thuộc tính này là không bắt buộc.
Thuộc tính này cho phép các thiết bị theo dõi đầu được tích hợp trong thiết bị âm thanh tham chiếu đến thiết bị âm thanh mà chúng được gắn vào. Các lược đồ sau đây được hỗ trợ.
Thiết bị theo dõi đầu độc lập
Nếu thuộc tính Giá trị nhận dạng duy nhất liên tục (0x0302
) không tồn tại hoặc được đặt thành tất cả các số 0, tức là thiết bị theo dõi đầu không được gắn vĩnh viễn vào một thiết bị âm thanh và có thể được sử dụng riêng biệt, 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 đầu với một thiết bị âm thanh riêng biệt theo cách thủ công.
Tham chiếu bằng địa chỉ MAC Bluetooth
Octet | 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 | Địa chỉ MAC Bluetooth |
Trong sơ đồ này, 8 octet đầu tiên phải là 0
, octet thứ 8 và thứ 9 phải lần lượt chứa các giá trị ASCII B
và T
, còn 6 octet tiếp theo được diễn giải là địa chỉ MAC Bluetooth, giả sử thiết bị theo dõi đầ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 các kết nối. Các thiết bị ở chế độ kép kết nối qua Bluetooth phiên bản cũ (định dạng HID v1.0) và Bluetooth LE (định dạng HID v2.0) phải hiển thị 2 bộ mô tả HID có cùng địa chỉ nhận dạng. Các thiết bị ở chế độ kép có thiết bị bên trái và bên phải riêng biệt phải hiển thị HID Bluetooth LE bằng thiết bị chính ở chế độ kép thay vì thiết bị thứ cấp chỉ có LE.
Tham chiếu bằng UUID
Bất cứ khi nào bit có nghĩa nhất (MSB) của octet 8 được đặt (≥0x80
), trường này sẽ được diễn giải là một UUID, như được chỉ định trong RFC-4122. 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 thức truyền tải được dùng.
Thuộc tính: Trạng thái báo cáo (0x0316
)
Thuộc tính Trạng thái báo cáo (0x0316
) là một thuộc tính đọc/ghi có ngữ nghĩa tiêu chuẩn như được xác định trong quy cách HID. Máy chủ lưu trữ sử dụng thuộc tính này để cho thiết bị biết những sự kiện cần báo cáo. Chỉ sử dụng các giá trị Không có sự kiện (0x0840
) và Tất cả sự kiện (0x0841
).
Giá trị ban đầu của trường này phải là No Events (Không có sự kiện) và thiết bị không được phép sửa đổi giá trị này, chỉ có máy chủ mới được phép.
Thuộc tính: Trạng thái nguồn (0x0319
)
Thuộc tính Trạng thái nguồn (0x0319
) là một thuộc tính đọc/ghi có ngữ nghĩa tiêu chuẩn như được xác định trong quy cách HID. Máy chủ lưu trữ sử dụng thuộc tính này để cho biết trạng thái nguồn mà thiết bị phải ở. Chỉ sử dụng các giá trị Full Power (0x0851
) và Power Off (0x0855
).
Giá trị ban đầu cho trường này do thiết bị xác định và thiết bị không bao giờ được sửa đổi, chỉ có máy chủ mới được phép sửa đổi.
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à một thuộc tính chỉ đọc/ghi có ngữ nghĩa tiêu chuẩn như được xác định trong quy cách HID. Máy chủ lưu trữ sử dụng thuộc tính này để cho biết tần suất thiết bị báo cáo các chỉ số dữ liệu.
Đơn vị là giây. Phạm vi hợp lệ cho giá trị này 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ế. Bạn phải hỗ trợ tốc độ báo cáo tối thiểu là 50 Hz và tốc độ báo cáo tối đa được đề xuất là 100 Hz. Do đó, khoảng thời gian báo cáo tối thiểu phải nhỏ hơn hoặc bằng 20 mili giây và nên lớn hơn hoặc bằng 10 mili giây.
Tài sản: Vendor-reserved LE Transport (0xF410
)
Thuộc tính LE Transport (0xF410
) do nhà cung cấp dành riêng là một thuộc tính đọc/ghi có ngữ nghĩa tiêu chuẩn như được xác định trong quy cách HID. Máy chủ lưu trữ sử dụng thuộc tính này để cho biết phương thức vận chuyển đã chọn (ACL hoặc ISO). Hệ thống chỉ sử dụng các giá trị ACL (0xF800
) và ISO (0xF801
), đồng thời cả hai giá trị này đều phải có trong tập hợp logic.
Thuộc tính này được định cấu hình trước trạng thái nguồn hoặc trạng thái 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à một trường nhập dùng để báo cáo thông tin theo dõi đầu thực tế. Đây 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 cho các giá trị thực tế như được chỉ định trong phần 6.2.2.7 của quy cách HID. Phạm vi 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]
, sao cho [rx, ry, rz]
là một vectơ xoay, biểu thị phép biến đổi từ khung tham chiếu sang khung đầu.
Độ lớn 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 là khung bên phải. Bạn có thể chấp nhận một lượng nhỏ độ lệch. Các trục đầu là:
- X từ tai trái sang tai phải
- Y từ phía sau đầu đến mũi (từ sau ra trước)
- 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à một trường nhập dữ liệu dùng để báo cáo thông tin theo dõi đầu thực tế. Đây là một mảng dấu phẩy cố định gồm 3 phần tử, được diễn giải theo các quy tắc HID thông thường cho các giá trị thực.
Đơn vị luôn là radian/giây.
Các phần tử được diễn giải là: [vx, vy, vz]
, sao cho [vx, vy, vz]
là một vectơ xoay, biểu thị vận tốc góc của khung đầu (tương ứng với chính nó).
Trường dữ liệu: Giá trị tuỳ chỉnh 3 (0x0546
)
Trường Giá trị tuỳ chỉnh 3 (0x0546
) là một trường nhập dữ liệu dùng để theo dõi sự gián đoạn trong khung tham chiếu. Đây là một số nguyên vô hướng có kích thước 8 bit. Thiết bị phải tăng giá trị này (có tính năng chuyển dòng) mỗi khi khung tham chiếu thay đổi, ví dụ: nếu thuật toán bộ lọc hướng dùng để xác định hướng đã đặt lại trạng thái. Giá trị này được diễn giải theo các quy tắc HID thông thường đối với các giá trị thực. Tuy nhiên, giá trị và đơn vị thực tế không quan trọng. Thông tin duy nhất liên quan đến máy chủ lưu trữ là 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 tế, bạn nên đặt các giá trị cho giá trị thực tế tối thiểu, giá trị thực tế tối đa và số mũ đơn vị thành 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) rất linh hoạt. Để tăng hiệu quả, bạn nên tách các thuộc tính chỉ đọc khỏi 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 nằm trong cùng một báo cáo và chỉ nằm trong một báo cáo cho một thiết bị nhất định (tập hợ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 các thông báo HID INPUT) gửi báo cáo đầu vào khi đáp ứng tất cả các điều kiện sau:
- Thuộc tính Trạng thái nguồn được đặt thành Nguồn đầy đủ.
- 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. Khi không đáp ứng bất kỳ điều kiện nào ở trên, 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à tương thích ngược
Giao thức HID của thiết bị theo dõi đầu sử dụng một sơ đồ lập phiên bản cho phép cập nhật, đồng thời cho phép khả năng tương tác giữa máy chủ lưu trữ và thiết bị sử dụng các phiên bản giao thức khác nhau. Các phiên bản của giao thức được xác định bằng hai số, số chính và số phụ, có ngữ nghĩa riêng biệt như 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 Sensor Description (0x0308
) của thiết bị đó.
Khả năng tương thích với phiên bản nhỏ
Những thay đổi đối với phiên bản phụ tương thích ngược với các phiên bản phụ trước đó dựa trên cùng một phiên bản chính. Trong các bản cập nhật cho phiên bản phụ, máy chủ lưu trữ sẽ bỏ qua các trường và thuộc tính dữ liệu bổ sung. Ví dụ: một thiết bị sử dụng giao thức phiên bản 1.6 sẽ tương thích với một 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 chính
Cho phép các thay đổi không tương thích ngược đối với các thay đổi đối với phiên bản chính. Để hỗ trợ nhiều phiên bản chính nhằm tương tác với các máy chủ cũ và mới, thiết bị có thể chỉ định nhiều bộ sưu tập ứng dụng trong phần mô tả báo cáo. 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 bộ sưu tập ứng dụng khác nhau mà thiết bị quảng cáo, kiểm tra thuộc tính Sensor Description (Mô tả cảm biến) của các bộ sưu tập đó để xác định phiên bản giao thức mà mỗi bộ sưu tập triển khai, sau đó chọn phiên bản giao thức mới nhất mà máy chủ lưu trữ hỗ trợ. Khi được chọn, máy chủ sẽ hoạt động với giao thức duy nhất được chọn trong suốt thời gian kết nối thiết bị.
Phụ lục: Ví dụ về một bộ mô tả HID
Ví dụ sau đây minh hoạ một bộ mô tả HID hợp lệ điển hình. Nó sử dụng các macro C thường dùng, được cung cấp trong HID Sensor Usages (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ề một bộ mô tả HID phiên bản 2.0
Ví dụ sau đây minh hoạ một bộ mô tả HID phiên bản 2.0 cho một thiết bị chỉ hỗ trợ phương thức truyền ACL Bluetooth 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,
};