hathach / tinyusb

An open source cross-platform USB stack for embedded system
https://www.tinyusb.org
MIT License
4.98k stars 1.05k forks source link

tud_cdc_send_break_cb not called when Serial break from MacOS #2003

Closed ulften closed 7 months ago

ulften commented 1 year ago

Operating System

MacOS

Board

Raspberry Pi Pico

Firmware

issue.zip

What happened ?

I was trying to follow along rumbledethumps picocomputer project using MacOS as host and ran into a problem with sending serial break from Mac host to the Raspberry Py pico running an image containing tinyUSB and picoprobe. I have confirmed that break works fine from a Linux host (and I have been told it also works on Windows). Using a USB to Serial adapter (bypassing tinyUSB and going directly from MacOS to the pico UART also works fine. Hence, I suspect an issue in TinyUSB.

To try and simplify, I modified one of the standard examples that comes with the pico software (hello_usb.c) and built an image that demonstrates the problem. The tud_cdc_send_break_cb() never gets called when connected to a MacOS USB port and using minicom to send the Break (ctrl-A F). Using the python scripts from rumbledethumps exhibits the same issue. But switching to a minicom hosted on Linux works as expected. I have created a mostly empty directory tree with the modified hello_usb.c in ./pico-examples/hello_world/usb and the executables in ./pico-examples/build/hello_world/usb/, hoping that this will enable you to test what I have built, and/or replace the standard hello_usb.c with my modified c file and build your own test.

Thanks, Ulf

How to reproduce ?

  1. flash the included hello_usb.uf2 on a pico, but connecting the USB cable while holding down the BOOTSEL button on the pico
  2. Open a minicom serial terminal on a Linux host towards the /dev/ttyACM0 with speed 115200
  3. type a few characters into minicom and press . Characters should be printed back on the screen
  4. press ctrl-A F to send a break
  5. Again, type a few characters and press enter
  6. After the characters have been printed back, the message "main: 2 BREAK(s) received!" indicating that the call back has been called. It works on Linux
  7. Repeat the same steps on a minicom from a MacOS. The tty port will probably be called something else on the mac (/dev/tty.usbxxxxx). The character echoing works the same, but the break callback function is never called.

Debug Log as txt file

No response

Screenshots

No response

I have checked existing issues, dicussion and documentation

hathach commented 1 year ago
ulften commented 1 year ago

Thanks for quick response!

hathach commented 1 year ago

Yes, by way of a USB to Serial adapter board connected to the UART pins on the pico. This board passes the break from both MacOS and Linux minicom.

Which Serial Adapter, FTDI/CP2104 using different driver than ACM, you need to double check to see if BREAK is indeed sent over ttyACM (not ttyUSB with other device).

I have now modified hello.c, adding a callback and printing a BREAK message when detecting a break. Running the cdc_msc example produces the same result as my previous test. Issuing a break from minicom and then typing a character will print my BREAK message in minicom on Linux, but not on MacOS.

LOG is required, check out getting started guide to enable it. I can't run and test every scenario, please try to troubleshoot at your end as far as you could first.

ulften commented 1 year ago

OK, I am back. I have now built the modified cdc-msc example in the tinyusb example tree:

make BOARD=raspberry_pi_pico DEBUG=1 LOG=2 all

with my modified main.c, as attached earlier.

But, alas, not much new to report. The break is detected when connected to /dev/ttyACM0, but not when using MacOS, where there is no /dev/ttyACMx, but the pico usb is seen as /dev/tty.usbserial-0001. Logging over the pico UART does not display anything, so I have nothing more to attach, I'm afraid. I will just move on over to Linux, which is a less desirable host in my case. Thx, Ulf

Kriechi commented 1 year ago

I can report the same issue using macOS 13.3.1: the BREAK is not received:

minicom -D /dev/tty.usbmodem14401
# press Meta+F, which shows a visual indication that claims a BREAK has been sent.

Also tried with a self-written tool that holds the BREAK signal for 1sec -- same issue.

It works just fine on Linux kernel 5.15.

HiFiPhile commented 1 year ago

@Kriechi Could you please upload log with CFG_TUSB_DEBUG=3 I'm highly doubt BREAK is not sent for ttyACM class under MacOS

Kriechi commented 1 year ago

@HiFiPhile I'm actually "only" running this test via CircuitPython 8.0.5 on an RP2040, though I would be even more surprised if there is some host-platform dependency in this code path: https://github.com/adafruit/circuitpython/pull/7227/files

HiFiPhile commented 1 year ago

though I would be even more surprised if there is some host-platform dependency in this code path

CDC driver of TinyUSB is compliant to ACM specification, and BREAK works on Windows and Linux. So it sounds like MacOS does something funky.

Kriechi commented 1 year ago

Also broken on macOS 12.6.4. I tried with both the tty and the cu device types under macOS - same issue in both.

rumbledethumps commented 1 year ago

The attached image is from Linux and Windows. MacOS didn't display any CFG_TUSB_DEBUG=3 message when sending a break as such:

import serial
s=serial.Serial('/dev/ttyACM1')
s.sendBreak(100)

good

hathach commented 1 year ago

I have the same experience with Bluetooth SPP (rfcomm) on macos, basically it ignores some of cotnrol signals. That is why I suspect that macos does not send BREAK signal to acm device at all. Previously, I monitor it with macos console/log (forgot) for kernel/IO log, you may also want to try it out. Though the easiest way is hooking the usb analyzer to see if the control is actually sent via USB bus. When I have time, I will fire up my old macbook and try to capture its USB bus.

hathach commented 7 months ago

I guess we can conclude that macos driver does not send BREAK request.

trejan commented 5 months ago

This is likely due to the tinyusb ACM device cap not advertising support for serial break. Linux used to ignore it and always send a break but a recent patch has made it check. Patching usbd.h to add the missing cap bit restores the break functionality.

HiFiPhile commented 5 months ago

tinyusb ACM device cap not advertising support for line break.

Good finding ! You can make a PR if you want.