Skip to content

a single hid class didn't work #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
bitbegin opened this issue Jun 10, 2019 · 2 comments
Open

a single hid class didn't work #3

bitbegin opened this issue Jun 10, 2019 · 2 comments

Comments

@bitbegin
Copy link

bitbegin commented Jun 10, 2019

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?

@Disasm
Copy link
Member

Disasm commented Jun 10, 2019

I'm not sure I can help you with this. Try reproducing real device's descriptors and endpoint structure in your device.

@Disasm
Copy link
Member

Disasm commented Oct 1, 2020

@bitbegin Did you manage to solve the problem?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants