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

shared/tinyusb: Buffer startup stdout (banner) to send once usb cdc is connected. #14485

Open
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

andrewleech
Copy link
Sponsor Contributor

@andrewleech andrewleech commented May 15, 2024

At startup, buffer stdout / microypthon banner so that it can be printed on initial connection of mpremote, just like stm port does.

Requires: hathach/tinyusb#2629 (merged) and hathach/tinyusb#2647 (merged)

Extra details: hathach/tinyusb#2595

Sitting on top of #14462

functional change

This change is most obvious when you've first plugged in a micropython device (or hit reset) when it's a board that uses USB (CDC) serial in the chip itself for the repl interface. This doesn't apply to UART going via a separate usb-serial chip.

On all ports other than stm32 currently, nothing happens when you first run a terminal like mpremote on a freshly booted board.
A user might typically first hit enter to look for a repl prompt >>> to ensure they are connected to a micropython board, then maybe hit ctrl-d to soft reboot and see the banner to check they're connected to the right board.
Code_dZZf1qJ3Un

On stm however, on a freshly started board when you connect mpremote the banner is immediately shown!.
Code_Wsv7praNrC

This PR extends this behaviour to rp2, mimxrt, samd and renesas. It's also extended to esp32s2 / s3 in the follow up PR.

Copy link

github-actions bot commented May 15, 2024

Code size report:

   bare-arm:    +0 +0.000% 
minimal x86:    +0 +0.000% 
   unix x64:    +0 +0.000% standard
      stm32:    +0 +0.000% PYBV10
     mimxrt:  +260 +0.072% TEENSY40[incl -8(bss)]
        rp2:  +820 +0.244% RPI_PICO[incl +516(bss)]
       samd:  +792 +0.298% ADAFRUIT_ITSYBITSY_M4_EXPRESS[incl +520(bss)]

@andrewleech andrewleech force-pushed the tinyusb_startup_banner_buffer branch from 7fddddc to 4d29eec Compare May 15, 2024 04:40
Copy link

codecov bot commented May 15, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 98.39%. Comparing base (025d10a) to head (9b8d07d).
Report is 36 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master   #14485   +/-   ##
=======================================
  Coverage   98.39%   98.39%           
=======================================
  Files         161      161           
  Lines       21204    21204           
=======================================
  Hits        20864    20864           
  Misses        340      340           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@andrewleech andrewleech changed the title DRAFT: shared/tinyusb: Buffer startup stdout (banner) to send once usb cdc is connected. shared/tinyusb: Buffer startup stdout (banner) to send once usb cdc is connected. May 15, 2024
@andrewleech
Copy link
Sponsor Contributor Author

andrewleech commented May 15, 2024

Initial tests working on rp2!

anl@STEP: ~ $ mpremote a1
Connected to MicroPython at /dev/ttyACM1
Use Ctrl-] or Ctrl-x to exit this shell
MicroPython v1.23.0-preview.377.g754ae8b76d.dirty on 2024-05-15; Raspberry Pi Pico with RP2040
Type "help()" for more information.
>>>

@andrewleech
Copy link
Sponsor Contributor Author

anl@STEP: ~ $ mpremote
Connected to MicroPython at /dev/ttyACM0
Use Ctrl-] or Ctrl-x to exit this shell
MicroPython v1.23.0-preview.380.g7ab4754386.dirty on 2024-05-16; Seeed Xiao with SAMD21G18A
Type "help()" for more information.
>>> 

@andrewleech
Copy link
Sponsor Contributor Author

anl@STEP: ~ $ mpremote
Connected to MicroPython at /dev/ttyACM0
Use Ctrl-] or Ctrl-x to exit this shell
MicroPython v1.23.0-preview.378.g9958203b3d.dirty on 2024-05-15; i.MX RT1010 EVK with MIMXRT1011DAE5A
Type "help()" for more information.
>>> 

@andrewleech andrewleech force-pushed the tinyusb_startup_banner_buffer branch from 3b8e785 to 526af51 Compare May 16, 2024 06:13
@andrewleech
Copy link
Sponsor Contributor Author

anl@STEP: ~ $ mpremote
Connected to MicroPython at /dev/ttyACM0
Use Ctrl-] or Ctrl-x to exit this shell
MicroPython v1.23.0-preview.381.gd3a95507b6.dirty on 2024-05-16; PCA10059 with NRF52840
Type "help()" for more information.
>>>

@andrewleech
Copy link
Sponsor Contributor Author

@mattytrentini

anl@STEP: ~ $ mpremote
Connected to MicroPython at /dev/ttyACM0
Use Ctrl-] or Ctrl-x to exit this shell
MicroPython v1.23.0-preview.378.g526af512b4.dirty on 2024-05-16; ItsyBitsy M4 Express with SAMD51G19A
Type "help()" for more information.
>>>

Copy link
Contributor

@projectgus projectgus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be a really nice addition, thanks @andrewleech 😁

}
n = MIN(n, tud_cdc_write_available());
if (n == 0) {
break;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC, if disconnected then after the tinyusb FIFO is full then further output is dropped until USB-CDC connects.

Could this lead to some misleading situations where USB host connects and receives:

banner
early program output
[unknown number of dropped bytes here]
contemporary output that was sent after USB host connected

Is that right? Does it seem like a problem?

The best solution I can see from this perspective would be to rotate bytes out of the overflowing FIFO as needed, but (a) this is quite slow if USB never connects and (b) not supported by current TinyUSB API.

However there is tud_cdc_n_write_clear() which empties the write FIFO. What do you think about doing this each time the FIFO fills up while disconnected? It means maybe some buffered bytes are lost, but the "new after old with missing middle" situation shown above can't happen.

(Note this isn't a request necessarily, I'm not fully convinced this is worth worrying about.)

Related request I do have is that it'd be good to have a short comment or so in here please, outlining the intended execution flow for this "disconnected, buffering" case as it may not be obvious to future readers why it's structured like this.

Copy link
Sponsor Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah you raise a good question. My thoughts were that keeping the banner (and maybe a little after it) is a good thing to display on connection.
But yes it could be somewhat confusing if there's a running application with more information, the disconnect in log could seem quite random. I'm not too sure how STM handles this currently, whether it's the initial data persisted or the latest data. @dpgeorge do you have a preference here?

A comment or two is definitely warranted regardless!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In stm32 it's a rolling ring buffer, so new data is always placed into the pending CDC output buffer, and if the ring buffer is full then the oldest data is lost. That means on connection to a USB host, the host sees a consistent history of the most recent data, possibly truncated at the beginning of that data.

Copy link
Sponsor Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @dpgeorge, the consistent view of "latest data" does make sense really. I'll have a closer look to see if I can make it automatically overwrite, I actually think this might be possible.

If not, the suggestion of "clear on full" might be worth doing instead.

Copy link
Sponsor Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hah, this is convenient: https://github.com/hathach/tinyusb/blob/1f259b3ab0f1b9587dee9c0bfb5574d70d021640/src/class/cdc/cdc_device.c#L250

  void cdcd_init(void) {

   ...

   // Config TX fifo as overwritable at initialization and will be changed to non-overwritable
   // if terminal supports DTR bit. Without DTR we do not know if data is actually polled by terminal.
   // In this way, the most current data is prioritized.
   tu_fifo_config(&p_cdc->tx_ff, p_cdc->tx_ff_buf, TU_ARRAY_SIZE(p_cdc->tx_ff_buf), 1, true);

So yeah if I basically remove the "space in buffer" check when not connected, it'll pretty much "just work". Though I'll need to confirm behavior when you try to write more than a buffer's worth in one go, whether it keeps the start or end of the data.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is certainly convenient!

It may actually be impossible to debug this with mpremote, given the pyserial hard-coded flush of the input buffer on open. 🤦 But it should be visible with other serial programs, I'd expect.

Copy link
Sponsor Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made the change and it seemed to work fine! Even with mpremote.... I added a main.py on the samd51 board:
print(list(range(512)))

Now when I start mpremote I see:

 $ mpremote
Connected to MicroPython at /dev/ttyACM0
Use Ctrl-] or Ctrl-x to exit this shell
 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511]
MicroPython v1.23.0-preview.379.g130e763226.dirty on 2024-05-25; ItsyBitsy M4 ExpreType "help()" for more information.
>>>

shared/tinyusb/mp_usbd_cdc.c Show resolved Hide resolved
@andrewleech
Copy link
Sponsor Contributor Author

Note this PR currently has the TinyUSB submodule pinned to my PR with required SOF updates, so it won't currently build easily.

This upstream PR will need to be merged first, it's blocked by the need to test on renesas.

@projectgus
Copy link
Contributor

Note this PR currently has the TinyUSB submodule pinned to my PR with required SOF updates, so it won't currently build easily.

FWIW I think we could emulate something similar by adding a callback in the mp_usbd_task, or maybe even soft timer. However I think better to stick with the approach you've already used, if it's going to be available soon.

@andrewleech
Copy link
Sponsor Contributor Author

Yes I'd originally thought of using a soft timer however it does have some overheads, and I'm not sure if all needed ports have it enabled.

I think the upstream change should be achievable, I've had very productive discussions on it already.

I'm just blocked by renesas port testing, I can't figure out the auto generated code being used in the board profiles there enough to enable USB on the evk board I've loaned.

@andrewleech
Copy link
Sponsor Contributor Author

I've now got a renesas board working finally and have finished the implementation there, it's all working too.

I just need to clean up some of the commented code in the nrf stuff and it's all good to go!

andrewleech and others added 8 commits May 29, 2024 11:48
Signed-off-by: Andrew Leech <andrew@alelec.net>
Signed-off-by: Andrew Leech <andrew@alelec.net>
Signed-off-by: Andrew Leech <andrew@alelec.net>
Signed-off-by: Andrew Leech <andrew@alelec.net>
Signed-off-by: Andrew Leech <andrew@alelec.net>
Signed-off-by: Andrew Leech <andrew@alelec.net>
Signed-off-by: Andrew Leech <andrew@alelec.net>
Signed-off-by: Andrew Leech <andrew@alelec.net>
@andrewleech andrewleech force-pushed the tinyusb_startup_banner_buffer branch from 54e0abf to 9b8d07d Compare May 29, 2024 01:59
@andrewleech
Copy link
Sponsor Contributor Author

This PR has tested working on rp2, mimxrt, samd and renesas.

esp32 support is in follow-up PR #15108.
nrf support is in follow-up PR #15158.

The required updates to TinyUSB have been merged upstream and the submodule here is now pinned to the matching master commit.

As such I consider this PR complete and ready for review.

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

Successfully merging this pull request may close these issues.

None yet

4 participants