diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e0ce08141..fa32abbb9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -133,6 +133,7 @@ jobs: uses: dawidd6/action-download-artifact@v11 with: workflow: build.yml + workflow_conclusion: '' branch: ${{ github.base_ref }} name: metrics-tinyusb path: base-metrics diff --git a/.github/workflows/build_util.yml b/.github/workflows/build_util.yml index d03c9af81..c9b0d36d9 100644 --- a/.github/workflows/build_util.yml +++ b/.github/workflows/build_util.yml @@ -79,6 +79,7 @@ jobs: - name: Membrowse Upload if: inputs.toolchain != 'esp-idf' && inputs.upload-membrowse == true + continue-on-error: true env: MEMBROWSE_API_KEY: ${{ secrets.MEMBROWSE_API_KEY }} run: | diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml index d7f1fc066..9b3756a72 100644 --- a/.github/workflows/cifuzz.yml +++ b/.github/workflows/cifuzz.yml @@ -29,7 +29,7 @@ jobs: fuzz-seconds: 400 - name: Upload Crash - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 if: failure() && steps.build.outcome == 'success' with: name: artifacts diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml index 5d7efc115..43144bb5e 100644 --- a/.github/workflows/claude-code-review.yml +++ b/.github/workflows/claude-code-review.yml @@ -16,7 +16,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 1 diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 9471a0591..50f449949 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -26,7 +26,7 @@ jobs: actions: read # Required for Claude to read CI results on PRs steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 1 diff --git a/.github/workflows/membrowse-onboard.yml b/.github/workflows/membrowse-onboard.yml index aa7204ffa..4b9e54cff 100644 --- a/.github/workflows/membrowse-onboard.yml +++ b/.github/workflows/membrowse-onboard.yml @@ -17,7 +17,7 @@ jobs: toolchains: ${{ steps.load.outputs.toolchains }} steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Load target matrix id: load @@ -35,7 +35,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 0 submodules: recursive @@ -45,7 +45,7 @@ jobs: ${{ fromJson(needs.load-targets.outputs.toolchains)[matrix.toolchain].setup_cmd }} && python3 tools/get_deps.py ${{ matrix.get_deps || matrix.port }} - name: Setup ccache - uses: hendrikmuhs/ccache-action@v1.2 + uses: hendrikmuhs/ccache-action@v1 with: key: ${{ matrix.port }}-${{ matrix.board }} diff --git a/.github/workflows/metrics_comment.yml b/.github/workflows/metrics_comment.yml index 7443f7367..5d250211f 100644 --- a/.github/workflows/metrics_comment.yml +++ b/.github/workflows/metrics_comment.yml @@ -17,7 +17,7 @@ jobs: pull-requests: write steps: - name: Download Artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: run-id: ${{ github.event.workflow_run.id }} github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/AGENTS.md b/AGENTS.md index bbbd7c36d..4e510b01e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -211,6 +211,51 @@ take 2-5 minutes. NEVER CANCEL. Set timeout to 20+ minutes. - Install requirements: `pip install -r docs/requirements.txt` - Build docs: `cd docs && sphinx-build -b html . _build` -- takes 2-3 seconds. NEVER CANCEL. Set timeout to 10+ minutes. +## Code Size Metrics + +Generate and compare code size metrics to evaluate the impact of changes. This is the most common workflow +when making code changes — use it to verify size impact before committing. + +**Quick single-board metrics (preferred for iterative development):** + +```bash +rm -rf cmake-build +python3 tools/build.py -b raspberry_pi_pico --target all --target tinyusb_metrics +python3 tools/metrics.py combine -j -m -f tinyusb/src cmake-build/cmake-build-*/metrics.json +``` + +This builds all examples for one board and produces `metrics.json` + `metrics.md`. Takes ~30 seconds. +NEVER CANCEL. Set timeout to 10+ minutes. + +**Comparing with master (before/after workflow):** + +1. On master: build and save baseline + ```bash + rm -rf cmake-build + python3 tools/build.py -b raspberry_pi_pico --target all --target tinyusb_metrics + python3 tools/metrics.py combine -j -m -f tinyusb/src cmake-build/cmake-build-*/metrics.json + mv metrics.json metrics_master.json + ``` +2. Switch to your branch: rebuild + ```bash + rm -rf cmake-build + python3 tools/build.py -b raspberry_pi_pico --target all --target tinyusb_metrics + python3 tools/metrics.py combine -j -m -f tinyusb/src cmake-build/cmake-build-*/metrics.json + ``` +3. Compare: `python3 tools/metrics.py compare -m -f tinyusb/src metrics_master.json metrics.json` + Produces `metrics_compare.md` showing size differences. + +**Full CI metrics (all arm-gcc families, for thorough validation):** + +```bash +rm -rf cmake-build +FAMILIES=$(python3 .github/workflows/ci_set_matrix.py | python3 -c "import sys,json; d=json.load(sys.stdin); print(' '.join(d.get('arm-gcc',[])))") +python3 tools/build.py --one-first --target all --target tinyusb_metrics $FAMILIES +python3 tools/metrics.py combine -j -m -f tinyusb/src cmake-build/cmake-build-*/metrics.json +``` + +Builds the first board of each family. Takes 2-4 minutes. NEVER CANCEL. Set timeout to 10+ minutes. + ## Code Quality and Validation - Format code: `clang-format -i path/to/file.c` (uses `.clang-format` config) diff --git a/examples/dual/host_info_to_device_cdc/src/main.c b/examples/dual/host_info_to_device_cdc/src/main.c index fe2199a69..cf3430464 100644 --- a/examples/dual/host_info_to_device_cdc/src/main.c +++ b/examples/dual/host_info_to_device_cdc/src/main.c @@ -106,10 +106,6 @@ static void usb_device_init(void) { .speed = TUSB_SPEED_AUTO }; tusb_init(BOARD_TUD_RHPORT, &dev_init); - tud_cdc_configure_t cdc_cfg = CFG_TUD_CDC_CONFIGURE_DEFAULT(); - cdc_cfg.tx_persistent = true; - cdc_cfg.tx_overwritabe_if_not_connected = false; - tud_cdc_configure(&cdc_cfg); board_init_after_tusb(); } diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index c7547c92b..c499756b9 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -116,7 +116,6 @@ TU_ATTR_WEAK void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms) { // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC]; -static tud_cdc_configure_t _cdcd_cfg = CFG_TUD_CDC_CONFIGURE_DEFAULT(); TU_ATTR_ALWAYS_INLINE static inline uint8_t find_cdc_itf(uint8_t ep_addr) { for (uint8_t idx = 0; idx < CFG_TUD_CDC; idx++) { @@ -132,12 +131,6 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t find_cdc_itf(uint8_t ep_addr) { //--------------------------------------------------------------------+ // APPLICATION API //--------------------------------------------------------------------+ -bool tud_cdc_configure(const tud_cdc_configure_t* driver_cfg) { - TU_VERIFY(driver_cfg != NULL); - _cdcd_cfg = *driver_cfg; - return true; -} - bool tud_cdc_n_ready(uint8_t itf) { TU_VERIFY(itf < CFG_TUD_CDC); TU_VERIFY(tud_ready()); @@ -272,7 +265,7 @@ void cdcd_init(void) { // 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_edpt_stream_init(&p_cdc->tx_stream, false, true, _cdcd_cfg.tx_overwritabe_if_not_connected, p_cdc->tx_ff_buf, + tu_edpt_stream_init(&p_cdc->tx_stream, false, true, CFG_TUD_CDC_TX_OVERWRITABLE_IF_NOT_CONNECTED, p_cdc->tx_ff_buf, CFG_TUD_CDC_TX_BUFSIZE, epin_buf); } } @@ -293,7 +286,7 @@ void cdcd_reset(uint8_t rhport) { cdcd_interface_t* p_cdc = &_cdcd_itf[i]; tu_memclr(p_cdc, ITF_MEM_RESET_SIZE); - tu_fifo_set_overwritable(&p_cdc->tx_stream.ff, _cdcd_cfg.tx_overwritabe_if_not_connected); // back to default + tu_fifo_set_overwritable(&p_cdc->tx_stream.ff, CFG_TUD_CDC_TX_OVERWRITABLE_IF_NOT_CONNECTED); // back to default tu_edpt_stream_close(&p_cdc->rx_stream); tu_edpt_stream_close(&p_cdc->tx_stream); } @@ -348,18 +341,26 @@ uint16_t cdcd_open(uint8_t rhport, const tusb_desc_interface_t* itf_desc, uint16 if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) { tu_edpt_stream_t *stream_tx = &p_cdc->tx_stream; tu_edpt_stream_open(stream_tx, rhport, desc_ep, CFG_TUD_CDC_TX_EPSIZE); - if (_cdcd_cfg.tx_persistent) { - tu_edpt_stream_write_xfer(stream_tx); // flush pending data - } else { - tu_edpt_stream_clear(stream_tx); - } + + #if CFG_TUD_CDC_TX_PERSISTENT + tu_edpt_stream_write_xfer(stream_tx); // flush pending data + #else + tu_edpt_stream_clear(stream_tx); + #endif } else { tu_edpt_stream_t *stream_rx = &p_cdc->rx_stream; - tu_edpt_stream_open(stream_rx, rhport, desc_ep, - CFG_TUD_CDC_RX_NEED_ZLP ? CFG_TUD_CDC_RX_EPSIZE : tu_edpt_packet_size(desc_ep)); - if (!_cdcd_cfg.rx_persistent) { - tu_edpt_stream_clear(stream_rx); - } + #if CFG_TUD_CDC_RX_NEED_ZLP + const uint16_t xfer_len = CFG_TUD_CDC_RX_EPSIZE; + #else + const uint16_t xfer_len = tu_edpt_packet_size(desc_ep); + #endif + + tu_edpt_stream_open(stream_rx, rhport, desc_ep, xfer_len); + + #if !CFG_TUD_CDC_RX_PERSISTENT + tu_edpt_stream_clear(stream_rx); + #endif + TU_ASSERT(tu_edpt_stream_read_xfer(stream_rx) > 0, 0); // prepare for incoming data } } @@ -424,12 +425,13 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control_requ p_cdc->line_state = (uint8_t) request->wValue; // If enabled: fifo overwriting is disabled if DTR bit is set and vice versa - if (_cdcd_cfg.tx_overwritabe_if_not_connected) { - tu_fifo_set_overwritable(&p_cdc->tx_stream.ff, !dtr); - } else { - tu_fifo_set_overwritable(&p_cdc->tx_stream.ff, false); - } + #if CFG_TUD_CDC_TX_OVERWRITABLE_IF_NOT_CONNECTED + const bool is_overwritable = !dtr; + #else + const bool is_overwritable = false; + #endif + tu_fifo_set_overwritable(&p_cdc->tx_stream.ff, is_overwritable); TU_LOG_DRV(" Set Control Line State: DTR = %d, RTS = %d\r\n", dtr, rts); tud_cdc_line_state_cb(itf, dtr, rts); // invoke callback } else { diff --git a/src/class/cdc/cdc_device.h b/src/class/cdc/cdc_device.h index 0348bd2ec..9ac6bc58a 100644 --- a/src/class/cdc/cdc_device.h +++ b/src/class/cdc/cdc_device.h @@ -70,30 +70,32 @@ #define CFG_TUD_CDC_RX_NEED_ZLP 0 #endif -#ifndef CFG_TUD_CDC_CONFIGURE_DEFAULT - #define CFG_TUD_CDC_CONFIGURE_DEFAULT() \ - { \ - .rx_persistent = false, \ - .tx_persistent = false, \ - .tx_overwritabe_if_not_connected = true, \ - } +// Keep rx fifo data even with bus reset or disconnect +#ifndef CFG_TUD_CDC_RX_PERSISTENT + #define CFG_TUD_CDC_RX_PERSISTENT 0 #endif -//--------------------------------------------------------------------+ -// Driver Configuration -//--------------------------------------------------------------------+ +// Keep tx fifo data even with bus reset or disconnect +#ifndef CFG_TUD_CDC_TX_PERSISTENT + #define CFG_TUD_CDC_TX_PERSISTENT 0 +#endif + +// If not connected, tx fifo can be overwritten +#ifndef CFG_TUD_CDC_TX_OVERWRITABLE_IF_NOT_CONNECTED + #define CFG_TUD_CDC_TX_OVERWRITABLE_IF_NOT_CONNECTED 1 +#endif + +// Backward compatible: tud_cdc_configure_t and tud_cdc_configure() are no longer used. +// Configuration is now done via compile-time macros above. typedef struct { - bool rx_persistent; // keep rx fifo data even with bus reset or disconnect - bool tx_persistent; // keep tx fifo data even with reset or disconnect - bool tx_overwritabe_if_not_connected; // if not connected, tx fifo can be overwritten + bool rx_persistent; + bool tx_persistent; + bool tx_overwritabe_if_not_connected; } tud_cdc_configure_t; -// Configure CDC driver behavior -bool tud_cdc_configure(const tud_cdc_configure_t* driver_cfg); - -// Backward compatible -#define tud_cdc_configure_fifo_t tud_cdc_configure_t -#define tud_cdc_configure_fifo tud_cdc_configure +#define tud_cdc_configure(_cfg) ((void)(_cfg)) +#define tud_cdc_configure_fifo_t tud_cdc_configure_t +#define tud_cdc_configure_fifo(_cfg) ((void)(_cfg)) //--------------------------------------------------------------------+ // Application API (Multiple Ports) i.e. CFG_TUD_CDC > 1 diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index 029e5ffcd..e1ba5da57 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -67,7 +67,8 @@ }, "tests": { "device": true, "host": false, "dual": true, - "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2002130"}] + "dev_attached": [{"vid_pid": "067b_2303", "serial": "0"}], + "comment": "pl23x" }, "flasher": { "name": "jlink", @@ -80,7 +81,8 @@ "uid": "BAE96FB95AFA6DBB8F00005002001200", "tests": { "device": true, "host": true, "dual": true, - "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2023299"}] + "dev_attached": [{"vid_pid": "10c4_ea60", "serial": "0001"}], + "comment": "cp2102" }, "flasher": { "name": "jlink", @@ -122,7 +124,8 @@ }, "tests": { "device": true, "host": true, "dual": true, - "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2002470"}] + "dev_attached": [{"vid_pid": "1a86_7523", "serial": "0"}], + "comment": "ch34x" }, "flasher": { "name": "openocd",