-
Notifications
You must be signed in to change notification settings - Fork 1.3k
migrate cdc device to edpt stream API #3339
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
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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); |
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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); |
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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); | ||
| } | ||
|
|
||
|
|
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 9 out of 10 changed files in this pull request and generated 8 comments.
|
|
||
| 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 |
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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); |
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 |
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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); |
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 |
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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); |
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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); |
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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); |
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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); |
53485b4 to
4e47871
Compare
4e47871 to
c9a9e94
Compare
|



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