Skip to content

a single hid class didn't work #3

@bitbegin

Description

@bitbegin

hid.rs:

use core::cmp::min;
use usb_device::Result;
use usb_device::bus::{InterfaceNumber, StringIndex, UsbBus, UsbBusAllocator};
use usb_device::class::{ControlIn, ControlOut, UsbClass};
use usb_device::control;
use usb_device::control::{Recipient, RequestType};
use usb_device::descriptor::DescriptorWriter;
use usb_device::endpoint::{EndpointAddress, EndpointIn, EndpointOut};
use usb_device::UsbError;
//use cortex_m_semihosting::hprintln;

pub const USB_CLASS_HID: u8 = 0x03;

const REPORT_DESCRIPTOR: &[u8] = &[
    0x06, 0xD0, 0xF1,  // Usage Page (Reserved 0xF1D0)
    0x09, 0x01,        // Usage (0x01)
    0xA1, 0x01,        // Collection (Application)
    0x09, 0x20,        //   Usage (0x20)
    0x15, 0x00,        //   Logical Minimum (0)
    0x26, 0xFF, 0x00,  //   Logical Maximum (255)
    0x75, 0x08,        //   Report Size (8)
    0x95, 0x40,        //   Report Count (64)
    0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x09, 0x21,        //   Usage (0x21)
    0x15, 0x00,        //   Logical Minimum (0)
    0x26, 0xFF, 0x00,  //   Logical Maximum (255)
    0x75, 0x08,        //   Report Size (8)
    0x95, 0x40,        //   Report Count (64)
    0x91, 0x02,        //   Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
    0xC0,              // End Collection
];

pub struct HidClass<'a, B: UsbBus> {
    intf: InterfaceNumber,
    read_ep: EndpointOut<'a, B>,
    write_ep: EndpointIn<'a, B>,
    buf: [u8; 65],
    len: usize,
}


impl<B: UsbBus> HidClass<'_, B> {
    pub fn new(alloc: &UsbBusAllocator<B>) -> HidClass<'_, B> {
        HidClass {
            intf: alloc.interface(),
            read_ep: alloc.interrupt(8, 10),
            write_ep: alloc.interrupt(8, 10),
            buf: [0; 65],
            len: 0,
        }
    }

    pub fn write(&mut self, data: &[u8]) -> Result<usize> {
        match self.write_ep.write(data) {
            Ok(count) => Ok(count),
            Err(UsbError::WouldBlock) => Ok(0),
            e => e,
        }
    }

    pub fn read(&mut self, data: &mut [u8]) -> Result<usize> {
        // Terrible buffering implementation for brevity's sake

        if self.len == 0 {
            self.len = match self.read_ep.read(&mut self.buf) {
                Ok(0) | Err(UsbError::WouldBlock) => return Ok(0),
                Ok(count) => count,
                e => return e,
            };
        }

        let count = min(data.len(), self.len);

        &data[..count].copy_from_slice(&self.buf[0..count]);

        self.buf.rotate_left(count);
        self.len -= count;

        Ok(count)
    }
}

impl<B: UsbBus> UsbClass<B> for HidClass<'_, B> {
    fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<()> {
        writer.interface(
            self.intf,
            3, //USB_CLASS_HID,
            0,
            0)?;

        let descriptor_len = REPORT_DESCRIPTOR.len();
        //hprintln!("report len: {}", descriptor_len).unwrap();
        let descriptor_len = (descriptor_len as u16).to_le_bytes();
        writer.write(
            0x21,
            &[0x10, 0x01, 0x21, 0x01, 0x22, descriptor_len[0], descriptor_len[1]]
        )?;

        writer.endpoint(&self.write_ep)?;
        writer.endpoint(&self.read_ep)?;
        //hprintln!("get_configuration_descriptors!").unwrap();
        Ok(())
    }

    fn endpoint_in_complete(&mut self, _addr: EndpointAddress) {
        //hprintln!("endpoint_in_complete!").unwrap();
    }

    fn control_in(&mut self, xfer: ControlIn<B>) {
        let req = xfer.request();
        match (req.request_type, req.recipient) {
            (RequestType::Standard, Recipient::Interface) => {
                //hprintln!("control_in!").unwrap();
                if req.request == control::Request::GET_DESCRIPTOR {
                    let (dtype, index) = req.descriptor_type_index();
                    if dtype == 0x22 && index == 0 {
                        let descriptor = REPORT_DESCRIPTOR;
                        xfer.accept_with(descriptor).ok();
                    }
                }
            }
            _ => {}
        }
    }
}

main.rs:

#![no_std]
#![no_main]

extern crate panic_semihosting; // logs messages to the host stderr; requires a debugger

use cortex_m::asm::delay;
use cortex_m_rt::entry;
use stm32f1xx_hal::{prelude::*, stm32};

use usb_device::prelude::*;
use stm32_usbd::UsbBus;
//use cortex_m_semihosting::hprintln;

mod hid;
mod vendor;
const VID: u16 = 0x1122;
const PID: u16 = 0x3344;

#[entry]
fn main() -> ! {
    let dp = stm32::Peripherals::take().unwrap();

    let mut flash = dp.FLASH.constrain();
    let mut rcc = dp.RCC.constrain();

    let clocks = rcc
        .cfgr
        .use_hse(8.mhz())
        .sysclk(48.mhz())
        .pclk1(24.mhz())
        .freeze(&mut flash.acr);

    assert!(clocks.usbclk_valid());

    let mut gpioa = dp.GPIOA.split(&mut rcc.apb2);

    // BluePill board has a pull-up resistor on the D+ line.
    // Pull the D+ pin down to send a RESET condition to the USB bus.
    let mut usb_dp = gpioa.pa12.into_push_pull_output(&mut gpioa.crh);
    usb_dp.set_low();
    delay(clocks.sysclk().0 / 100);

    let usb_dm = gpioa.pa11;
    let usb_dp = usb_dp.into_floating_input(&mut gpioa.crh);

    let usb_bus = UsbBus::new(dp.USB, (usb_dm, usb_dp));

    let mut hid = hid::HidClass::new(&usb_bus);
    //let mut vendor = vendor::HidClass::new(&usb_bus);

    // vid/pid: http://pid.codes/1209/CC1D/
    let mut usb_dev = UsbDeviceBuilder::new(
            &usb_bus,
            UsbVidPid(VID, PID),
        )
        .manufacturer("bitbegin")
        .product("hid")
        .serial_number("12345678")
        //.device_class(3)
        .build();
    //hprintln!("reset!").unwrap();
    //usb_dev.force_reset().expect("reset failed");

    let mut buf = [0u8; 65];
    loop {
        if !usb_dev.poll(&mut [&mut hid, &mut vendor]) {
            continue;
        }

        match hid.read(&mut buf) {
            Ok(count) if count > 0 => {
                // Echo back in upper case

                hid.write(&buf[0..count]).ok();
            },
            _ => { },
        }
    }
}

this will result in c0000011 - "xact error".

if add device_class(0xff) to UsbDeviceBuilder, it will be detected by Windows. but i want to use hidapi, so how to configure hid-class?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions