Conversation
tu_edpt_stream_open() does not clear fifo, allow for persistent stream when disconnect/reconnect
0871c7d to
3be91bd
Compare
💡 Codex Reviewtinyusb/src/class/cdc/cdc_device.c Lines 372 to 379 in 0871c7d The new ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
There was a problem hiding this comment.
Pull Request Overview
This PR migrates the CDC device class to use the unified endpoint stream API, consolidating FIFO management and endpoint transfer logic into reusable stream abstractions. The changes simplify CDC device/host implementations while maintaining backward compatibility.
Key Changes:
- Refactored CDC device to use
tu_edpt_stream_tinstead of direct FIFO management, removing ~150 lines of code - Updated MIDI and vendor device classes to use stream clear operations for consistency
- Modified
.clang-formatto align function arguments on the same line (AlignAfterOpenBracket: Align) and added penalties to discourage breaking parameters
Reviewed Changes
Copilot reviewed 8 out of 9 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| src/tusb.c | Changed ZLP check from !tu_fifo_count() to tu_fifo_empty() for clarity; fixed spacing in deinit function |
| src/common/tusb_private.h | Added tu_edpt_stream_empty() helper function; removed fifo clear from stream open |
| src/class/cdc/cdc_device.c | Major refactoring to use stream API instead of direct FIFO operations; restructured interface type with nested stream struct; simplified read/write/flush implementations |
| src/class/cdc/cdc_host.c | Added TU_ASSERT for stream init; added void casts for deinit return values; added stream clear calls; improved code organization |
| src/class/midi/midi_host.c | Removed ep_in/ep_out fields; updated endpoint count logic to use stream state; added stream clear calls |
| src/class/midi/midi_device.c | Added stream clear calls after opening endpoints |
| src/class/vendor/vendor_device.c | Improved code clarity with local stream variables; updated comments |
| examples/device/net_lwip_webserver/src/usb_descriptors.c | Removed PVS-Studio comment suppressions |
| .clang-format | Updated formatting rules for better parameter alignment and reduced line breaks |
| tu_edpt_stream_init(&p_cdc->stream.rx, false, false, false, p_cdc->stream.rx_ff_buf, CFG_TUD_CDC_RX_BUFSIZE, | ||
| p_epbuf->epout, CFG_TUD_CDC_EP_BUFSIZE); | ||
|
|
||
| // TX fifo can be configured to change to overwritable if not connected (DTR bit not set). Without DTR we do not | ||
| // know if data is actually polled by terminal. This way the most current data is prioritized. | ||
| // Default: is overwritable | ||
| tu_fifo_config(&p_cdc->tx_ff, p_cdc->tx_ff_buf, TU_ARRAY_SIZE(p_cdc->tx_ff_buf), 1, _cdcd_cfg.tx_overwritabe_if_not_connected); | ||
|
|
||
| #if OSAL_MUTEX_REQUIRED | ||
| osal_mutex_t mutex_rd = osal_mutex_create(&p_cdc->rx_ff_mutex); | ||
| osal_mutex_t mutex_wr = osal_mutex_create(&p_cdc->tx_ff_mutex); | ||
| TU_ASSERT(mutex_rd != NULL && mutex_wr != NULL, ); | ||
|
|
||
| tu_fifo_config_mutex(&p_cdc->rx_ff, NULL, mutex_rd); | ||
| tu_fifo_config_mutex(&p_cdc->tx_ff, mutex_wr, NULL); | ||
| #endif | ||
| tu_edpt_stream_init(&p_cdc->stream.tx, false, true, _cdcd_cfg.tx_overwritabe_if_not_connected, | ||
| p_cdc->stream.tx_ff_buf, CFG_TUD_CDC_TX_BUFSIZE, p_epbuf->epin, CFG_TUD_CDC_EP_BUFSIZE); |
There was a problem hiding this comment.
Missing error handling for tu_edpt_stream_init(). This function can fail (returns bool), but the return value is not checked. Consider adding error checking similar to how it's done in cdc_host.c with TU_ASSERT().
| tu_edpt_stream_deinit(&p_cdc->stream.rx); | ||
| tu_edpt_stream_deinit(&p_cdc->stream.tx); |
There was a problem hiding this comment.
Missing error handling for tu_edpt_stream_deinit(). The function returns bool but the return values are not checked. If deinitialization fails, the function should propagate the error instead of always returning true.
src/common/tusb_private.h
Outdated
| return tu_fifo_empty(&s->ff); | ||
| } | ||
|
|
||
|
|
There was a problem hiding this comment.
[nitpick] Extra blank line. Consider removing one of the empty lines to maintain consistent spacing in the file.
3be91bd to
81f70bf
Compare
81f70bf to
397a3af
Compare
|
|
||
| tu_edpt_stream_read_xfer(dev_addr, &p_midi->ep_stream.rx); // prepare for next transfer | ||
| } else if (ep_addr == p_midi->ep_stream.tx.ep_addr) { | ||
| tu_edpt_stream_read_xfer(dev_addr, ep_str_rx); // prepare for next transfer |
There was a problem hiding this comment.
The return value of tu_edpt_stream_read_xfer() is not explicitly cast to void. For consistency with cdc_host.c (line 521) and to clearly indicate the intentional ignoring of the return value, consider adding (void) cast.
| tu_edpt_stream_read_xfer(dev_addr, ep_str_rx); // prepare for next transfer | |
| (void)tu_edpt_stream_read_xfer(dev_addr, ep_str_rx); // prepare for next transfer |
| // If there is no data left, a ZLP should be sent if | ||
| // xferred_bytes is multiple of EP size and not zero | ||
| tu_edpt_stream_write_zlp_if_needed(dev_addr, &p_midi->ep_stream.tx, xferred_bytes); | ||
| tu_edpt_stream_write_zlp_if_needed(dev_addr, ep_str_tx, xferred_bytes); |
There was a problem hiding this comment.
The return value of tu_edpt_stream_write_zlp_if_needed() is not explicitly cast to void. For consistency with cdc_host.c (line 698) and to clearly indicate the intentional ignoring of the return value, consider adding (void) cast.
| tu_edpt_stream_write_zlp_if_needed(dev_addr, ep_str_tx, xferred_bytes); | |
| (void)tu_edpt_stream_write_zlp_if_needed(dev_addr, ep_str_tx, xferred_bytes); |
|
|
||
| tu_edpt_stream_open(stream_tx, desc_ep); | ||
| if (_cdcd_cfg.tx_persistent) { | ||
| tu_edpt_stream_write_xfer(rhport, stream_tx); // flush pending data |
There was a problem hiding this comment.
The return value of tu_edpt_stream_write_xfer() is not explicitly cast to void. For consistency with similar calls in vendor_device.c (line 242) and to clearly indicate the intentional ignoring of the return value, consider adding (void) cast.
| tu_edpt_stream_write_xfer(rhport, stream_tx); // flush pending data | |
| (void)tu_edpt_stream_write_xfer(rhport, stream_tx); // flush pending data |
| tu_edpt_stream_init(&p_cdc->stream.rx, false, false, false, p_cdc->stream.rx_ff_buf, CFG_TUD_CDC_RX_BUFSIZE, | ||
| p_epbuf->epout, CFG_TUD_CDC_EP_BUFSIZE); |
There was a problem hiding this comment.
The return value of tu_edpt_stream_init() is not checked. If initialization fails, the interface will be in an inconsistent state. Consider adding TU_ASSERT() to validate the initialization succeeded, similar to how cdch_init() in cdc_host.c checks these return values.
|
|
||
| // prepare for OUT transaction | ||
| _prep_out_transaction(itf); | ||
| tu_edpt_stream_read_xfer(rhport, stream_rx); // prepare for more data |
There was a problem hiding this comment.
The return value of tu_edpt_stream_read_xfer() is not explicitly cast to void. For consistency with cdch_xfer_cb() in cdc_host.c (line 718) and to clearly indicate the intentional ignoring of the return value, consider adding (void) cast.
| tu_edpt_stream_read_xfer(rhport, stream_rx); // prepare for more data | |
| (void)tu_edpt_stream_read_xfer(rhport, stream_rx); // prepare for more data |
| (void)tu_edpt_stream_deinit(&p_cdc->stream.tx); | ||
| (void)tu_edpt_stream_deinit(&p_cdc->stream.rx); |
There was a problem hiding this comment.
While the return values of tu_edpt_stream_deinit() are explicitly cast to void, consider checking the return values and returning false if any deinit operation fails, to properly propagate errors to callers.
| (void)tu_edpt_stream_deinit(&p_cdc->stream.tx); | |
| (void)tu_edpt_stream_deinit(&p_cdc->stream.rx); | |
| if (!tu_edpt_stream_deinit(&p_cdc->stream.tx)) { | |
| return false; | |
| } | |
| if (!tu_edpt_stream_deinit(&p_cdc->stream.rx)) { | |
| return false; | |
| } |
| } | ||
| if (0 == tu_edpt_stream_write_xfer(rhport, stream_tx)) { | ||
| // If there is no data left, a ZLP should be sent if needed | ||
| tu_edpt_stream_write_zlp_if_needed(rhport, stream_tx, xferred_bytes); |
There was a problem hiding this comment.
The return value of tu_edpt_stream_write_zlp_if_needed() is not explicitly cast to void. For consistency with cdch_xfer_cb() in cdc_host.c (line 698) and to clearly indicate the intentional ignoring of the return value, consider adding (void) cast.
| tu_edpt_stream_write_zlp_if_needed(rhport, stream_tx, xferred_bytes); | |
| (void)tu_edpt_stream_write_zlp_if_needed(rhport, stream_tx, xferred_bytes); |
| TU_VERIFY(itf < CFG_TUD_CDC, ); | ||
| cdcd_interface_t *p_cdc = &_cdcd_itf[itf]; | ||
| tu_edpt_stream_clear(&p_cdc->stream.rx); | ||
| tu_edpt_stream_read_xfer(p_cdc->rhport, &p_cdc->stream.rx); |
There was a problem hiding this comment.
The return value of tu_edpt_stream_read_xfer() is not explicitly cast to void. For consistency with tuh_cdc_read_clear() in cdc_host.c (line 521) and to clearly indicate the intentional ignoring of the return value, consider adding (void) cast.
| tu_edpt_stream_read_xfer(p_cdc->rhport, &p_cdc->stream.rx); | |
| (void)tu_edpt_stream_read_xfer(p_cdc->rhport, &p_cdc->stream.rx); |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
53485b4 to
4e47871
Compare
4e47871 to
c9a9e94
Compare
|



Uh oh!
There was an error while loading. Please reload this page.