3. USB HID自定义报告描述符

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=0x03) 输入报告 (8字节): 报告ID 0x03 命令码 1字节 传感器值 低字节 传感器值 高字节 状态[0] 标志 状态[1] 标志 状态[2] 标志 状态[3] 标志 偏移0 偏移1 偏移2 偏移3 偏移4-7 输出报告 (8字节): 报告ID 0x03 命令码 1字节 参数区 (6字节) 偏移2-7 描述符总长度: 52字节 | 输入报告: 1个 | 输出报告: 1个 | 端点类型: 中断

判定标准

验证通过需满足:①描述符能被HID工具正确解析且无格式错误;②报告ID、各字段长度与上述定义完全一致;③使用hidapi库编写测试程序发送0x03报告ID的8字节数据,设备能正确接收并解析出命令码与参数。若在STM32等MCU上实现,需将描述符数组注册到USB HID配置描述符中,并确保端点大小≥8字节。