3. USB HID自定义报告描述符
任务定义
本案例要求设计一个自定义HID报告描述符,实现特定用途的数据传输。我们将实现一个8字节自定义报告:第0字节为报告ID(固定值0x03),第1字节为命令码,第2~3字节为16位传感器数值(小端序),第4~7字节为4字节状态标志位。该描述符将用于后续固件中与主机进行双向通信。
自定义HID报告描述符实现
// 自定义HID报告描述符
// 报告ID: 0x03
// 结构: [报告ID(1)] [命令码(1)] [传感器值(2)] [状态标志(4)]
// 总长度: 8字节
const uint8_t CustomHID_ReportDescriptor[] = {
0x06, 0x00, 0xFF, // USAGE_PAGE (Vendor Defined Page 0xFF00)
0x09, 0x01, // USAGE (Vendor Usage 1)
0xA1, 0x01, // COLLECTION (Application)
// 报告ID: 0x03
0x85, 0x03, // REPORT_ID (3)
// 命令码 - 1字节
0x09, 0x02, // USAGE (Vendor Usage 2)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0xFF, // LOGICAL_MAXIMUM (255)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
// 传感器值 - 2字节 (16位小端)
0x09, 0x03, // USAGE (Vendor Usage 3)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xFF, 0xFF, // LOGICAL_MAXIMUM (65535)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x02, // REPORT_COUNT (2)
0x81, 0x02, // INPUT (Data,Var,Abs)
// 状态标志 - 4字节
0x09, 0x04, // USAGE (Vendor Usage 4)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0xFF, // LOGICAL_MAXIMUM (255)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x04, // REPORT_COUNT (4)
0x81, 0x02, // INPUT (Data,Var,Abs)
// 输出报告 - 用于主机下发命令
0x09, 0x05, // USAGE (Vendor Usage 5)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0xFF, // LOGICAL_MAXIMUM (255)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x08, // REPORT_COUNT (8)
0x91, 0x02, // OUTPUT (Data,Var,Abs)
0xC0 // END_COLLECTION
};
// 描述符长度计算
#define CUSTOM_HID_REPORT_DESC_SIZE sizeof(CustomHID_ReportDescriptor)
报告数据解析与封装
// 输入报告数据结构 (8字节)
typedef struct {
uint8_t report_id; // 固定为0x03
uint8_t command; // 命令码
uint16_t sensor_value; // 传感器值 (小端)
uint8_t status[4]; // 状态标志
} CustomHID_InputReport_t;
// 输出报告数据结构 (8字节)
typedef struct {
uint8_t report_id; // 固定为0x03
uint8_t command; // 命令码
uint8_t params[6]; // 参数区
} CustomHID_OutputReport_t;
// 封装输入报告
void CustomHID_PackInputReport(uint8_t *buffer, uint8_t cmd,
uint16_t sensor_val, uint8_t *status) {
buffer[0] = 0x03; // 报告ID
buffer[1] = cmd; // 命令码
buffer[2] = sensor_val & 0xFF; // 低字节
buffer[3] = (sensor_val >> 8) & 0xFF; // 高字节
for (int i = 0; i < 4; i++) {
buffer[4 + i] = status[i]; // 状态标志
}
}
// 解析输出报告
void CustomHID_ParseOutputReport(uint8_t *buffer, CustomHID_OutputReport_t *out) {
out->report_id = buffer[0];
out->command = buffer[1];
for (int i = 0; i < 6; i++) {
out->params[i] = buffer[2 + i];
}
}
验证方法
使用HID Descriptor Tool(USB-IF官方工具)加载上述描述符,检查格式合法性。在Linux系统中,可通过lsusb -v查看设备枚举后的HID描述符是否正确解析。预期输出:描述符总长度为52字节,包含1个输入报告(8字节)和1个输出报告(8字节),报告ID均为0x03。
判定标准
验证通过需满足:①描述符能被HID工具正确解析且无格式错误;②报告ID、各字段长度与上述定义完全一致;③使用hidapi库编写测试程序发送0x03报告ID的8字节数据,设备能正确接收并解析出命令码与参数。若在STM32等MCU上实现,需将描述符数组注册到USB HID配置描述符中,并确保端点大小≥8字节。