Rust USB HID描述符生成库usbd-hid-descriptors的使用,轻松创建符合规范的USB人机接口设备描述符

Rust USB HID描述符生成库usbd-hid-descriptors的使用,轻松创建符合规范的USB人机接口设备描述符

安装

在项目目录中运行以下Cargo命令:

cargo add usbd-hid-descriptors

或者在Cargo.toml中添加以下行:

usbd-hid-descriptors = "0.8.2"

基本使用

usbd-hid-descriptors库可以帮助你轻松生成符合规范的USB HID描述符。以下是一个完整的示例demo:

use usbd_hid_descriptors::*;

// 定义HID报告描述符
#[gen_hid_descriptor(
    (collection = APPLICATION, usage_page = GENERIC_DESKTOP, usage = KEYBOARD) = {
        // 键盘修饰键 (Ctrl, Shift, Alt等)
        (usage_page = KEYBOARD, usage_min = 0xE0, usage_max = 0xE7) = {
            #[packed_bits 8] #[item_settings data,variable,absolute] modifier=input;
        };
        // 保留字节
        (usage_page = KEYBOARD, usage_min = 0x00, usage_max = 0x00) = {
            #[item_settings constant,variable,absolute] reserved=input;
        };
        // 键盘按键码
        (usage_page = KEYBOARD, usage_min = 0x00, usage_max = 0xFF) = {
            #[item_settings data,array,absolute] keycodes=input;
        };
        // LED输出报告 (Num Lock, Caps Lock等)
        (usage_page = LEDS, usage_min = 0x01, usage_max = 0x05) = {
            #[packed_bits 5] #[item_settings data,variable,absolute] leds=output;
            #[item_settings constant,variable,absolute] padding=output;
        };
    }
)]
#[allow(dead_code)]
pub struct KeyboardReport {
    pub modifier: u8,
    pub reserved: u8,
    pub keycodes: [u8; 6],
    pub leds: u8,
}

fn main() {
    // 获取生成的HID报告描述符
    let descriptor = KeyboardReport::desc();
    
    // 使用描述符初始化USB HID设备
    // (实际使用中需要结合具体的USB设备库)
    println!("HID描述符: {:?}", descriptor);
}

功能说明

  1. 使用#[gen_hid_descriptor]宏可以方便地定义HID报告描述符
  2. 支持定义输入(input)和输出(output)报告
  3. 可以指定使用情况页(usage_page)和使用情况(usage)
  4. 支持位打包(packed_bits)和数组类型的数据
  5. 自动生成符合HID规范的描述符字节

完整示例

下面是一个更完整的示例,展示如何定义鼠标HID报告:

use usbd_hid_descriptors::*;

// 定义鼠标HID报告描述符
#[gen_hid_descriptor(
    (collection = APPLICATION, usage_page = GENERIC_DESKTOP, usage = MOUSE) = {
        (usage_page = BUTTON, usage_min = 0x01, usage_max = 0x08) = {
            #[packed_bits 8] #[item_settings data,variable,absolute] buttons=input;
        };
        (usage_page = GENERIC_DESKTOP,) = {
            (usage = X,) = {
                #[item_settings data,variable,relative] x=input;
            };
            (usage = Y,) = {
                #[item_settings data,variable,relative] y=input;
            };
            (usage = WHEEL,) = {
                #[item_settings data,variable,relative] wheel=input;
            };
        };
    }
)]
#[allow(dead_code)]
pub struct MouseReport {
    pub buttons: u8,
    pub x: i8,
    pub y: i8,
    pub wheel: i8,
}

fn main() {
    // 获取生成的鼠标HID报告描述符
    let descriptor = MouseReport::desc();
    println!("鼠标HID描述符: {:?}", descriptor);
    
    // 创建鼠标报告实例
    let report = MouseReport {
        buttons: 0,
        x: 10,
        y: -5,
        wheel: 0,
    };
    
    // 在实际应用中,这里会将报告发送给USB主机
    println!("发送鼠标报告: 按钮={}, X={}, Y={}, 滚轮={}", 
        report.buttons, report.x, report.y, report.wheel);
}

这个库特别适合嵌入式开发,可以与usb-device等Rust USB设备栈配合使用,轻松创建符合规范的USB HID设备。


1 回复

Rust USB HID描述符生成库usbd-hid-descriptors使用指南

简介

usbd-hid-descriptors是一个Rust库,用于简化符合规范的USB人机接口设备(HID)描述符的创建过程。它提供了一种类型安全的方式来定义HID报告描述符,避免了手动编写二进制描述符的繁琐和容易出错的问题。

主要特性

  • 类型安全的HID描述符构建
  • 支持多种HID设备类型(键盘、鼠标、游戏控制器等)
  • 自动计算描述符大小和报告长度
  • usb-device生态系统良好集成

完整示例代码

下面是一个完整的USB HID键盘设备实现示例:

use usb_device::prelude::*;
use usbd_hid::hid_class::HIDClass;
use usbd_hid_descriptors::KeyboardReport;

// 定义键盘报告结构
#[repr(C)]
#[derive(Clone, Copy)]
struct KeyboardReport {
    modifier: u8,    // 修饰键状态 (Ctrl, Alt, Shift等)
    reserved: u8,    // 保留字节
    keycodes: [u8; 6], // 当前按下的键码
}

impl KeyboardReport {
    pub fn new() -> Self {
        KeyboardReport {
            modifier: 0,
            reserved: 0,
            keycodes: [0; 6],
        }
    }
}

impl Default for KeyboardReport {
    fn default() -> Self {
        Self::new()
    }
}

// 实现HidReport trait
impl usbd_hid_descriptors::HidReport for KeyboardReport {
    const ID: u8 = 1;
    const DESCRIPTOR: &'static [u8] = usbd_hid_descriptors::gen_hid_descriptor!(
        usage_page = GENERIC_DESKTOP,
        usage = KEYBOARD,
        collection = APPLICATION {
            // 修饰键 (Ctrl, Alt, Shift等)
            usage_page = KEYBOARD,
            usage_min = 0xE0,
            usage_max = 0xE7,
            logical_min = 0,
            logical_max = 1,
            report_size = 1,
            report_count = 8,
            input = DATA_VAR_ABS,
            
            // 保留位
            report_size = 8,
            report_count = 1,
            input = CONSTANT,
            
            // 普通按键
            usage_page = KEYBOARD,
            usage_min = 0,
            usage_max = 101,
            logical_min = 0,
            logical_max = 101,
            report_size = 8,
            report_count = 6,
            input = DATA_ARRAY,
        }
    );
}

fn main() -> Result<(), usb_device::UsbError> {
    // 初始化USB总线 (具体实现取决于硬件平台)
    let usb_bus = UsbBus::new(/* 硬件特定初始化 */);
    
    // 创建HID类实例
    let hid = HIDClass::new(&usb_bus, KeyboardReport::desc(), 10);
    
    // 构建USB设备
    let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x1234, 0x5678))
        .manufacturer("Rust HID Demo")
        .product("HID Keyboard")
        .serial_number("1.0")
        .device_class(0)
        .build();
    
    // 主循环
    loop {
        // 处理USB事件
        usb_dev.poll(&mut [&mut hid]);
        
        // 模拟按下字母'a'键 (键码0x04)
        let report = KeyboardReport {
            modifier: 0,
            reserved: 0,
            keycodes: [0x04, 0, 0, 0, 0, 0],
        };
        
        // 发送键盘报告
        hid.push_input(&report)?;
        
        // 短暂延迟
        cortex_m::asm::delay(1_000_000);
        
        // 发送释放所有键的报告
        let release_report = KeyboardReport::new();
        hid.push_input(&release_report)?;
        
        cortex_m::asm::delay(1_000_000);
    }
}

代码说明

  1. 键盘报告结构:

    • modifier字段表示修饰键状态
    • reserved是必须的保留字节
    • keycodes数组存储当前按下的键码
  2. HID描述符:

    • 使用gen_hid_descriptor!宏定义键盘的报告描述符
    • 描述符定义了修饰键、保留位和普通按键的布局
    • 自动生成符合USB HID规范的二进制描述符
  3. USB设备初始化:

    • 创建USB总线实例(具体实现取决于硬件)
    • 初始化HID类并指定键盘报告描述符
    • 配置USB设备的基本信息(Vendor ID, Product ID等)
  4. 主循环:

    • 定期调用poll()处理USB事件
    • 构造键盘报告并发送
    • 示例中模拟了按下和释放字母’a’键的操作

注意事项

  1. 实际使用时需要根据具体硬件平台实现USB总线初始化
  2. 键码定义参考USB HID使用表
  3. 在嵌入式系统中使用时需考虑内存限制
  4. 复杂的HID设备可能需要定义多个报告描述符
回到顶部