Giter Site home page Giter Site logo

usbd-serial's People

Contributors

alexismarquet avatar atykhyy avatar conorpp avatar dirbaio avatar disasm avatar eldruin avatar elfmimi avatar iostat avatar mvirkkunen avatar nickray avatar ryan-summers avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

usbd-serial's Issues

Device Terminal Ready (DTR) is not resetting

Hi, I'm using usbd-serial on the NordicSemi NRF52840 and it's working pretty well.

To detect when there is a terminal connected on the host I use the SerialPort::dtr function so the buffer is not filled with stale data. This works well but the flag is not reset when the terminal disconnects. I make sure to poll the device between checking the flag. Is this behavior expected?

If so, do you know of another way to detect the terminal disconnecting?

Cannot open serial port in cygwin environment.

Cygwin requires serial ports to be setup to so to say well known speed upon when it tries to open a port.

This crate usbd-serial is setting default value of data_rate in LineCoding to 8_000 . this is a problem for cygwin.

There is no way to modify data_rate from outside the crate. other than from usb host side.
so easy and simple solution will be to just change the default value from 8_000 to 9_600 .

Composite device support

For this to work as part of a composite device an interface association descriptor (IAD) is required which in turn requires that the device class, sub class and function are set as 0xEF, 0x02 and 0x01 respectively.

I achieved producing a composite device with two CDC ACM serial ports by:

  • Setting the device class etc as above
  • Writing the IAD directly before the interface descriptors
  • Enabling feature control-buffer-256

The IAD was initially inserted directly into get_configuration_descriptors as per the below:

writer.write(
    INTERFACE_ASSOCIATION, // 0x0B
    &[
        self.com_if.into(), // bFirstInterface
        2, // bInterfaceCount
        USB_CLASS_CDC, // bfunctionClass
        CDC_SUBCLASS_ACM, // bfunctionSubClass
        CDC_PROTOCOL_NONE, // bfunctionProtocol
        0, // iFunction
    ])?;

I have since refactored this a little extending usb-device to include an interface_association() function much like interface() and endpoint() as this is useful across multiple classes of device:

pub fn interface_association(&mut self, first_interface: InterfaceNumber,
    interface_count: u8, function_class: u8, function_sub_class: u8, function_protocol: u8)
    -> Result<()>
{
    self.write(
        descriptor_type::INTERFACE_ASSOCIATION,
        &[
            first_interface.into(), // bFirstInterface
            interface_count, // bInterfaceCount
            function_class, // bfunctionClass
            function_sub_class, // bfunctionSubClass
            function_protocol, // bfunctionProtocol
            0, // iFunction
        ])?;

    Ok(())
}

This IAD is only required for composite devices. What do you think the best approach would be to only include the IAD for usbd-serial when needed?

Doesn't work when not building in release mode

Hey not sure if it is usbd-serial or usb-device or maybe even the stm32f4xx-hal

but after much testing if found that when I build without the release flag Windows can't read the address of the device. Usbdeview shows me "Unknown USB Device (Device Descriptor Request Failed)"

Using poormans debugging with semihosting I saw that it gets stuck in the SerialPort::new call. Trying to debug using gdb it just land in asm/lib.rs (I also have no idea what I am doing never used gdb before :) )

I am totally new to embedded and rust, so this might just be a complete fail on my side. Also my instincts tell me that the compiler optimizing stuff should not be the reason for the code to work. But then it's super low level stuff I guess maybe optimizations change some register interactions. (But again shouldn't optimizations break code)

Editing the Release Profile:

just adding debug = true works
while debug = true playing with opt-level:
opt-level=0 - does not work
opt-level=1 - does not work
opt-level=2 - does work
opt-level=2 - also works
didn't test "z" and "s"

That are my findings :)
I still have the feeling it's just some stupid setting I added and totally my fault (Or I missed some note in the documentation) :)))

Config:

  • rustc 1.50.0 (cb75ad5db 2021-02-10)
  • building for thumbv7em-none-eabihf

CdcAcmClass needs more pub

I'm implementing a USB device along the lines of SerialPort, but which directly talks to a UART peripheral - tacking on a USB-UART functionality to an existing widget. The initial snag that prompted this issue is that CdcAcmClass::write_ep_address() isn't available to my new crate, but looking at CdcAcmClass more, I wonder if read_ep and write_ep shouldn't simply be public?

Happy to make a PR either way, if that's easier to deal with.

Bug: Writing data. Every 705 Byte will be omitted

When sending the following string literal, making multiple successive calls to write will cause the every 705th packet to be dropped.

        let data: &[u8] = b"
!his is the usb_data its 8192 bytes long                                     
\r                                  
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvw#.za
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdjfghijklmnopqrstuvwxyzabcdefg#.jklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopq#.tuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyza#.defghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijk#.nopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvw#.za
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg#.jklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopq#.tuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyza#.defghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijk#.nopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvw#.za
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza
\rbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx!";

let mut bytes_written = 0;
while bytes_written < 8_192 {
    match serial.write(&data[bytes_written..bytes_written + 64]) {
        Ok(_) => {
            bytes_written += 64;
        }
        Err(err) => {
            match err {
                UsbError::WouldBlock => {} //defmt::println!("write WouldBlock"),
                UsbError::BufferOverflow => defmt::println!("write BufferOverflow"),
                _ => defmt::println!("write unaccounted error"),
            }
        }
    }
}

.'s within the string are the bytes that are dropped. The #'s exists in case you want to use a logic analyzer and want to search for where the .'s characters are being dropped. !'s exist so you can find the start and end of the string when using a logic analyzer.

Reduce copying with methods to query the inner read buffer

I am writing a transport to encapsulate SerialPort to add framing and encoding (serde). When I want to read from the port, I need to allocate some space in my Transport but I don't know how many bytes to allocate until the read is actually performed. This means I need to keep an intermediate buffer for bytes to be read into, and then I can copy the number of bytes actually read from the port into my Transport.

However, SerialPort already has internal buffering with a default size of 128 bytes for the read buffer. So, I am effectively triple buffering and copying twice for no good reason.

On the host side with the serialport crate, I can query the number of bytes available in the OS buffer with SerialPort::bytes_to_read(). It is trivial for me to allocate space in my Transport with this API and copy only once.

Can't send and receive at the same time? Where to start debugging?

I can get the example to work, but if I try to do anything more complex the SerialPort code seems to stop working...

Basically I can receive fine, or send fine, but if I try to do both it stops sending and receiving seems to stop working as well. I have a debugger attached and I am not seeing any crashes so not quite sure what is going on...

Do you have any ideas on where to start debugging this?

BTW I am running the USB code in the USB ISR, this is also on a STM32F072 if that matters.

I tried moving the USB code to the loop{} in my main() but that had no effect.

Thanks for any help!

panic: attempt to subtract with overflow in available_read()

I hit a panic when using this module to serial print info from my project when I print a lot in a debug build. It seems it is possible for the write index to get behind the read index. It happened when I was viewing serial output and it looked a little garbled (I might be outputting too much too fast) and I hit enter a few times, so I suspect there was some overwriting along with reading in some data too.

panicked at 'attempt to subtract with overflow', /Users/tholmes/.cargo/registry/src/github.com-1ecc6299db9ec823/usbd-serial-0.1.0/src/buffer.rs:33:9

Program received signal SIGTRAP, Trace/breakpoint trap.
0x00019e78 in __bkpt ()
(gdb) bt
#0  0x00019e78 in __bkpt ()
#1  0x0001bdc6 in cortex_m::asm::bkpt ()
    at /Users/tholmes/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.6.2/src/asm.rs:19
#2  rust_begin_unwind (info=0x20007c90)
    at /Users/tholmes/.cargo/registry/src/github.com-1ecc6299db9ec823/panic-semihosting-0.5.3/src/lib.rs:91
#3  0x0001a724 in core::panicking::panic_fmt () at src/libcore/panicking.rs:85
#4  0x0001a6c6 in core::panicking::panic () at src/libcore/panicking.rs:52
#5  0x000060ba in usbd_serial::buffer::Buffer<S>::available_read (self=0x2000019c <oven_temp_rs::usbserial::USB_SERIAL+412>)
    at /Users/tholmes/.cargo/registry/src/github.com-1ecc6299db9ec823/usbd-serial-0.1.0/src/buffer.rs:33
#6  0x0000616a in usbd_serial::buffer::Buffer<S>::discard_already_read_data (
    self=0x2000019c <oven_temp_rs::usbserial::USB_SERIAL+412>)
    at /Users/tholmes/.cargo/registry/src/github.com-1ecc6299db9ec823/usbd-serial-0.1.0/src/buffer.rs:111
#7  0x0000649e in usbd_serial::buffer::Buffer<S>::write (self=0x2000019c <oven_temp_rs::usbserial::USB_SERIAL+412>, data=...)
    at /Users/tholmes/.cargo/registry/src/github.com-1ecc6299db9ec823/usbd-serial-0.1.0/src/buffer.rs:49
#8  0x0000bbda in usbd_serial::serial_port::SerialPort<B,RS,WS>::write (self=0x200000e4 <oven_temp_rs::usbserial::USB_SERIAL+228>,
    data=...) at /Users/tholmes/.cargo/registry/src/github.com-1ecc6299db9ec823/usbd-serial-0.1.0/src/serial_port.rs:95
#9  0x00002b0e in oven_temp_rs::usbserial::USBSerial::write_to_usb (message=...) at oven-temp-rs/src/usbserial.rs:77
#10 0x00005f08 in oven_temp_rs::__cortex_m_rt_main () at oven-temp-rs/src/main.rs:135
#11 0x00005bee in main () at oven-temp-rs/src/main.rs:57
(gdb) select-frame 5
(gdb) frame
#5  0x000060ba in usbd_serial::buffer::Buffer<S>::available_read (self=0x2000019c <oven_temp_rs::usbserial::USB_SERIAL+412>)
    at /Users/tholmes/.cargo/registry/src/github.com-1ecc6299db9ec823/usbd-serial-0.1.0/src/buffer.rs:33
33	        self.wpos - self.rpos
(gdb) p self
$1 = (*mut usbd_serial::buffer::Buffer<usbd_serial::buffer::DefaultBufferStore>) 0x2000019c <oven_temp_rs::usbserial::USB_SERIAL+412>
(gdb) p self.wpos
$2 = 114
(gdb) p self.rpos
$3 = 126

Here is the full used-serial object:

usbd_serial::serial_port::SerialPort<atsamd_hal::samd21::usb::bus::UsbBus, usbd_serial::buffer::DefaultBufferStore, usbd_serial::buffer::DefaultBufferStore> {inner: usbd_serial::cdc_acm::CdcAcmClass<atsamd_hal::samd21::usb::bus::UsbBus> {comm_if: usb_device::bus::InterfaceNumber (0), comm_ep: usb_device::endpoint::Endpoint<atsamd_hal::samd21::usb::bus::UsbBus, usb_device::endpoint::In> {bus_ptr: 0x2000040c <oven_temp_rs::usbserial::BUS_ALLOCATOR+480>, address: usb_device::endpoint::EndpointAddress (129), ep_type: usb_device::endpoint::EndpointType::Interrupt, max_packet_size: 8, interval: 255, _marker: core::marker::PhantomData<usb_device::endpoint::In>}, data_if: usb_device::bus::InterfaceNumber (1), read_ep: usb_device::endpoint::Endpoint<atsamd_hal::samd21::usb::bus::UsbBus, usb_device::endpoint::Out> {bus_ptr: 0x2000040c <oven_temp_rs::usbserial::BUS_ALLOCATOR+480>, address: usb_device::endpoint::EndpointAddress (1), ep_type: usb_device::endpoint::EndpointType::Bulk, max_packet_size: 64, interval: 0, _marker: core::marker::PhantomData<usb_device::endpoint::Out>}, write_ep: usb_device::endpoint::Endpoint<atsamd_hal::samd21::usb::bus::UsbBus, usb_device::endpoint::In> {bus_ptr: 0x2000040c <oven_temp_rs::usbserial::BUS_ALLOCATOR+480>, address: usb_device::endpoint::EndpointAddress (130), ep_type: usb_device::endpoint::EndpointType::Bulk, max_packet_size: 64, interval: 0, _marker: core::marker::PhantomData<usb_device::endpoint::In>}, line_coding: usbd_serial::cdc_acm::LineCoding {stop_bits: usbd_serial::cdc_acm::StopBits::One, data_bits: 8, parity_type: usbd_serial::cdc_acm::ParityType::None, data_rate: 115200}, dtr: true, rts: true}, read_buf: usbd_serial::buffer::Buffer<usbd_serial::buffer::DefaultBufferStore> {store: usbd_serial::buffer::DefaultBufferStore ([13, 13, 0 <repeats 27 times>, 113, 234, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 247, 237, 60, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 113, 234, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 247, 237, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 113, 234, 68,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 247, 237, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 113, 234, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 247, 237,
            60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 113, 234,
            68]), rpos: 2, wpos: 2}, write_buf: usbd_serial::buffer::Buffer<usbd_serial::buffer::DefaultBufferStore> {store: usbd_serial::buffer::DefaultBufferStore ([114, 101, 97, 100, 105, 110, 103, 58, 32, 55, 49, 53, 46, 55, 13, 10, 68, 101, 108, 97, 121, 105,
            110, 103, 32, 102, 111, 114, 32, 49, 48, 48, 48, 32, 109, 115, 13, 10, 114, 101, 97, 100, 105, 110, 103, 58, 32, 55, 49,
            54, 46, 54, 13, 10, 68, 101, 108, 97, 121, 105, 110, 103, 32, 102, 111, 114, 32, 49, 48, 48, 48, 32, 109, 115, 13, 10,
            114, 101, 97, 100, 105, 110, 103, 58, 32, 55, 49, 54, 46, 48, 13, 10, 68, 101, 108, 97, 121, 105, 110, 103, 32, 102, 111,
            114, 32, 49, 48, 48, 48, 32, 109, 115, 13, 10, 0, 32, 220, 126, 0, 32, 44, 211, 1, 0, 48, 2, 0,
            32]), rpos: 126, wpos: 114}, write_state: <error reading variable>}})

Here's my interrupt handler:

#[interrupt]
fn USB() {
    let mut read_buf: [u8; 64] = [0u8; 64];
    unsafe {
            let usbserial: &mut USBSerial = USB_SERIAL.as_mut().unwrap();
            usbserial.usb_bus.poll(&mut [&mut usbserial.usb_serial]);
            usbserial.usb_serial.read(read_buf).unwrap();
        };
}

And how I write:

    pub fn write_to_usb(message: &str) -> usize {
        let message_bytes = message.as_bytes();
        unsafe {
            match USB_SERIAL.as_mut().unwrap().usb_serial.write(message_bytes) {
                Ok(count) => count,
                Err(_) => 0,
            }
        }
    }

What is needed to make a composite device with two Serials?

I'm trying what others seem to have done before, but I can't find any examples online.
I want to have two serial CDC-ACM interfaces, so that one can stream data continuously while the other can be used for interaction with the device.
Calling the second SerialPort::new() panics at https://github.com/rust-embedded-community/usbd-serial/blob/master/src/cdc_acm.rs#L60 with alloc_ep failed: EndpointOverflow.
My microcontroller is the stm32f411. This is supported by the blackmagic probe firmware, which also offers two Serial interfaces, so I assume that the microcontroller should be able to handle it:
https://github.com/blackmagic-debug/blackmagic/blob/df0c092165a5e6784ba94a0eaa0ec08a71c3a0c7/src/platforms/common/usb_serial.c#L30-L39
Is it maybe relevant that the blackmagic uses an IN endpoint for one CDC CTRL endpoint and an OUT endpoint for the other one? Is this somehow possible with usbd-serial?

How can we handle read buffer overflow?

I have an embedded project on an STM32F405 with USB serial configured and running with FreeRTOS (rust wrapper) as follows:

// Make USB serial device globally available
pub static G_USB_SERIAL: Mutex<RefCell<Option<SerialPort<UsbBus<USB>>>>> =
    Mutex::new(RefCell::new(None));

// Make USB device globally available
pub static G_USB_DEVICE: Mutex<RefCell<Option<UsbDevice<UsbBus<USB>>>>> =
    Mutex::new(RefCell::new(None));

pub unsafe fn usb_init(usb: USB) {
    static mut EP_MEMORY: [u32; 1024] = [0; 1024];
    static mut USB_BUS: Option<UsbBusAllocator<stm32f4xx_hal::otg_fs::UsbBusType>> = None;
    USB_BUS = Some(stm32f4xx_hal::otg_fs::UsbBusType::new(usb, &mut EP_MEMORY));
    let usb_bus = USB_BUS.as_ref().unwrap();
    let serial_port = SerialPort::new(&usb_bus);
    let usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x17c0, 0x28dd))
        .manufacturer("University of Bern")
        .product("Thermometry")
        .serial_number("IceLab814")
        .device_class(usbd_serial::USB_CLASS_CDC)
        .build();
    cortex_m::interrupt::free(|cs| {
        *G_USB_SERIAL.borrow(cs).borrow_mut() = Some(serial_port);
        *G_USB_DEVICE.borrow(cs).borrow_mut() = Some(usb_dev);
    });
}

pub fn usb_read(message: &mut [u8; 1024]) -> bool {
    cortex_m::interrupt::free(|cs| {
        *message = [0; 1024];
        return match G_USB_SERIAL.borrow(cs).borrow_mut().as_mut() {
            None => false,
            Some(serial) => match serial.read(message) {
                Ok(a) => if a < 1024 {
                    true
                } else {
                    false
                },
                Err(_) => false,
            },
        };
    })
}

#[interrupt]
#[allow(non_snake_case)]
fn OTG_FS() {
    cortex_m::interrupt::free(|cs| {
        match G_USB_DEVICE.borrow(cs).borrow_mut().as_mut() {
            None => {}
            Some(usb_dev) => {
                match G_USB_SERIAL.borrow(cs).borrow_mut().as_mut() {
                    None => {}
                    Some(serial) => {
                        // do this regularly to keep connection to USB host
                        usb_dev.poll(&mut [serial]);
                    }
                }
            }
        }
    });
}

initialized in the main function like this:

let mut dp = pac::Peripherals::take().unwrap();

let rcc = dp.RCC.constrain();

let clocks = rcc
    .cfgr
    .use_hse(8.MHz())
    .sysclk(48.MHz())
    .hclk(48.MHz())
    .require_pll48clk()
    .pclk1(24.MHz())
    .pclk2(24.MHz())
    .freeze();

let gpioa = dp.GPIOA.split();

// initialize usb
let usb = USB {
    usb_global: dp.OTG_FS_GLOBAL,
    usb_device: dp.OTG_FS_DEVICE,
    usb_pwrclk: dp.OTG_FS_PWRCLK,
    pin_dm: gpioa.pa11.into_alternate(),
    pin_dp: gpioa.pa12.into_alternate(),
    hclk: clocks.hclk(),
 };
unsafe {
     usb_init(usb);
     cortex_m::peripheral::NVIC::unmask(Interrupt::OTG_FS);
}

my USB task (stack size 2048) does something like this:

loop {
    let mut message_bytes = [0; 1024];
    usb_read(&mut message_bytes);
    // do something
    // print something over usb
}

I noticed that the SerialPort::new(&usb_bus) doc says: "Creates a new USB serial port with the provided UsbBus and 128 byte read/write buffers.". Whenever I send a message longer than 63 characters, the microcontroller gets stuck and requires a reset. How can I handle this case?

Add a license

Hello!

This package doesn't currently have a license. It would be nice if it did. usb_device uses MIT.

First packet getting lost

Hello,

I'm trying to use USB serial to read and write some config options from a Raspberry Pi Pico used for a macro keypad. The Pico acts both as a HID device (using the usbd_hid crate) and a Serial device. The main thread just builds the HID reports, and the USB polling and handling of the serial communication happens inside the IRQ handler. The Pico never starts the communication, it always responds to request packets sent by the PC.

My problem is that the first packet sent by the PC is never received, but from then on it seems they are all received. Am I using the crate in a wrong way or are there some details of the USB Serial protocol that I don't understand?

The IRQ handler:

#[interrupt]
unsafe fn USBCTRL_IRQ() {
    // Handle USB request
    let usb_dev = USB_DEVICE.as_mut().unwrap();
    let usb_hid = USB_HID.as_mut().unwrap();
    let serial = USB_SERIAL.as_mut().unwrap();

    if usb_dev.poll(&mut [usb_hid, serial]) {
        let mut buf = [0u8; 67];
        let rd = serial.read(&mut buf);

        let response = match rd {
            Ok(0) => None,
            Ok(n) => config::process_command(&mut buf, n), // This function just builds a new packet to be sent back to the PC
            Err(_) => None,
        };

        if response.is_some() {
            serial.write(response.unwrap());
        }
    }
}

I also have an extra question because I'm curious and I don't want to open an additional issue. If in the IRQ handler I just set a flag (a volatile bool) if the poll returns true, and I do everything else in the main thread, including the serial reading and writing, the device doesn't seem to receive anything, read always returns WouldBlock. What could be the cause for this behavior?

Config:

  • rustc 1.63.0 (4b91a6ea7 2022-08-08)
  • target: thumbv6m-none-eabi
  • device: Raspberry Pi Pico (RP2040)
  • PC OS: Fedora 36

Should this work with the writeln! macro?

Was trying to use it with writeln! but it does not seem to implement core::fmt::Write. I'm kinda a rust n00b so maybe I am doing something wrong, so just want to confirm.

How to check if hardware buffers are flushed?

The docs of SerialPort::flush metion that:

Note that even if this method returns Ok, data may still be in hardware buffers on either side.

I don't fully understand how USB works.
Would it be enough to check if write_state == WriteState::Idle?
Also do I understand correctly that usb_device.poll(&mut [&mut serial_port]) needs to be called to make progress in flushing the hardware buffers?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.