Skip to content
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

Can't implement CDC with HID #102

Closed
yallxe opened this issue Aug 7, 2022 · 15 comments
Closed

Can't implement CDC with HID #102

yallxe opened this issue Aug 7, 2022 · 15 comments

Comments

@yallxe
Copy link

yallxe commented Aug 7, 2022

I created a CDC and HID classes with one device

let mut hid = HIDClass::new_with_settings(
    &bus_allocator,
    KeyboardReport::desc(),
    10,
    HidClassSettings {  
        subclass: HidSubClass::NoSubClass,
        protocol: HidProtocol::Keyboard,
        config: ProtocolModeConfig::ForceReport,
        locale: HidCountryCode::NotSupported
    }
);
let mut serial = SerialPort::new(&bus_allocator);

let mut dev = UsbDeviceBuilder::new(&bus_allocator, vid_pid)
    .manufacturer("xkbd")
    .product("Prism80")
    .serial_number("000")
    .device_class(USB_CLASS_CDC)
    .build();

And the loop code:

loop {
    dev.poll(&mut [&mut serial, &mut hid]);
    if button_pin.is_high().unwrap() {
        hid.push_input(&report_struct).ok();
        led_pin.set_high().ok();
        serial.write(b"Pressed").ok();
    } else {
        hid.push_input(&null_report_struct).ok();
        led_pin.set_low().ok();
        serial.write(b"Released").ok();
    }

    // drop received data
    hid.pull_raw_output(&mut [0; 64]).ok();
}

However the USB device is not recognized by my PC, I tried the solution from #85 but it does not fix the issue and the device keep being unrecognized, how do I implement the HID with CDC?

@Disasm
Copy link
Member

Disasm commented Aug 7, 2022

Do you have a dmesg log of failed enumeration? Are you using a release build?

@yallxe
Copy link
Author

yallxe commented Aug 7, 2022

I don't, I'm kind of new to embedded developement and as far as I understand I need to have a debug probe to get this, maybe I understand it wrong.

P.S. I'm using Pi Pico.

@Disasm
Copy link
Member

Disasm commented Aug 7, 2022

To get dmesg logs you need Linux (MacOS probably supports these as well).
By the way, does it work for you if you add only HID or only CDC?

@yallxe
Copy link
Author

yallxe commented Aug 7, 2022

I'm on Windows currently, I can try WSL or use my laptop on linux and yes it does work with CDC or HID only.

@yallxe
Copy link
Author

yallxe commented Aug 7, 2022

Just tested on my ubuntu, and... HID works, but I can't connect to serial port. I tried to connect using screen /dev/ttyACM1 115200 but I'm getting a [screen is terminating] error. However on Windows, things seems to be even worser, I don't really know how to check for errors and the device keep being unrecognized.

Also checked dmesg and usb device seems to be created with no errors.

@yallxe
Copy link
Author

yallxe commented Aug 7, 2022

Forgot to answer, yes I'm using release build.

@Disasm
Copy link
Member

Disasm commented Aug 7, 2022

Hmm, could you check if it works in Windows without .device_class(USB_CLASS_CDC)? Also it would be interesting to see USB capture (for example, gathered with Wireshark) which contains packets transferred when you connect to the device with screen.

@ianrrees
Copy link
Contributor

ianrrees commented Aug 7, 2022

I think one issue may be that you're calling serial.write() every time through the loop {}. In practice, doing one serial write will need >1 pass through the loop to finish, so I think eventually you'll have a problem with that approach. Maybe only send the message when the button level changes - something like this:

let mut last_state = button_pin.is_high().unwrap();
loop {
    // Poll stuff as above.  I'm not sure how HID works so maybe keep it as-is, maybe adapt as below

    let current_state = button_pin.is_high().unwrap();
    if last_state != current_state {
        last_state = current_state;
        if current_state {
            serial.write(b"Pressed").ok();
        } else {
            serial.write(b"Released").ok();
        }
}

@ianrrees
Copy link
Contributor

ianrrees commented Aug 7, 2022

I'd also leave out the line .device_class(USB_CLASS_CDC) - device class should probably be 0 (the default) which tells the host OS to figure out the class of each interface from its descriptors.

@yallxe
Copy link
Author

yallxe commented Aug 8, 2022

I know about calling serial.write() every loop, fixed that already but didn't mention here, also removed .device_class(USB_CLASS_CDC) but it doesn't fix the problem.

@yallxe
Copy link
Author

yallxe commented Aug 8, 2022

Okay, I managed to open serial monitor with screen, I was getting [screen is terminating] because I forgot to run as root. So basically, everything works fine on Linux, but not on Windows.

@ryan-summers
Copy link
Member

ryan-summers commented Aug 8, 2022

What version of usb-device are you using? There was an enumeration bug on Windows that was fixed in the 2.9 release: https://github.com/rust-embedded-community/usb-device/blob/master/CHANGELOG.md

If you don't have that fix implemented, it's highly unlikely that your device will enumerate on Windows.

@mvirkkunen
Copy link
Collaborator

mvirkkunen commented Aug 8, 2022

Have you tried adding interface association descriptors (IADs)? Windows is usually more picky about them than other OSs.

You can add them by removing device_class / device_subclass / device_protocol and just calling composite_with_iads() instead of them. Make sure your usbd_serial is also the newest version.

@yallxe
Copy link
Author

yallxe commented Aug 8, 2022

Just updated usb-device to 0.2.9 and added composite_with_iads(), but still no results. Also made sure I'm using newest usbd-serial 0.1.1 and usbd-hid 0.6. Maybe something is wrong in my general code, so I'm also uploading it here.

P.S. The program is probably not crashing, because I can see the led light up when I'm pressing the button, the only thing that is not working is usb on Windows.

@yallxe
Copy link
Author

yallxe commented Aug 12, 2022

Changing max_packet_size_0 to 16 instead of default 8 seems to fix the problem. Would be glad if somebody could explain me why was this occurring only on Windows, but as a problem is resolved, I'm closing the issue. Thanks everybody for the help.

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

5 participants