Skip to content

Commit 5d21781

Browse files
Merge pull request #341 from espressif/feat/cdc_tx
feat(cdc): Added support for large TX transfers
2 parents 4c06f93 + 5ca02b0 commit 5d21781

File tree

6 files changed

+186
-168
lines changed

6 files changed

+186
-168
lines changed

host/class/cdc/esp_modem_usb_dte/esp_modem_usb.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -162,11 +162,6 @@ class UsbTerminal : public Terminal, private CdcAcmDevice {
162162
auto *this_terminal = static_cast<UsbTerminal *>(user_ctx);
163163

164164
switch (event->type) {
165-
// Notifications like Ring, Rx Carrier indication or Network connection indication are not relevant for USB terminal
166-
case CDC_ACM_HOST_NETWORK_CONNECTION:
167-
case CDC_ACM_HOST_SERIAL_STATE:
168-
ESP_LOGD(TAG, "Ignored USB event %d", event->type);
169-
break;
170165
case CDC_ACM_HOST_DEVICE_DISCONNECTED:
171166
ESP_LOGW(TAG, "USB terminal disconnected");
172167
if (this_terminal->on_error) {
@@ -180,8 +175,13 @@ class UsbTerminal : public Terminal, private CdcAcmDevice {
180175
this_terminal->on_error(terminal_error::UNEXPECTED_CONTROL_FLOW);
181176
}
182177
break;
178+
// Notifications like Ring, Rx Carrier indication or Network connection indication are not relevant for USB terminal
179+
// Suspend/resume events also ignored
180+
case CDC_ACM_HOST_NETWORK_CONNECTION:
181+
case CDC_ACM_HOST_SERIAL_STATE:
183182
default:
184-
abort();
183+
ESP_LOGD(TAG, "Ignored USB event %d", event->type);
184+
break;
185185
}
186186
}
187187
size_t buffer_size;

host/class/cdc/usb_host_cdc_acm/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
88

99
### Added
1010
- Added global suspend/resume support
11+
- Added support for transmitting data larger than the configured output buffer size
1112

1213
## [2.1.1] - 2025-09-24
1314

host/class/cdc/usb_host_cdc_acm/cdc_acm_host.c

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -961,39 +961,61 @@ static void usb_event_cb(const usb_host_client_event_msg_t *event_msg, void *arg
961961

962962
esp_err_t cdc_acm_host_data_tx_blocking(cdc_acm_dev_hdl_t cdc_hdl, const uint8_t *data, size_t data_len, uint32_t timeout_ms)
963963
{
964-
esp_err_t ret;
964+
esp_err_t ret = ESP_OK;
965965
CDC_ACM_CHECK(cdc_hdl, ESP_ERR_INVALID_ARG);
966966
cdc_dev_t *cdc_dev = (cdc_dev_t *)cdc_hdl;
967967
CDC_ACM_CHECK(data && (data_len > 0), ESP_ERR_INVALID_ARG);
968968
CDC_ACM_CHECK(cdc_dev->data.out_xfer, ESP_ERR_NOT_SUPPORTED); // Device was opened as read-only.
969-
CDC_ACM_CHECK(data_len <= cdc_dev->data.out_xfer->data_buffer_size, ESP_ERR_INVALID_SIZE);
970969

971-
// Take OUT mutex and fill the OUT transfer
972-
BaseType_t taken = xSemaphoreTake(cdc_dev->data.out_mux, pdMS_TO_TICKS(timeout_ms));
970+
const size_t buffer_size = cdc_dev->data.out_xfer->data_buffer_size;
971+
const uint8_t *data_ptr = data;
972+
size_t remaining = data_len;
973+
974+
// Record start time for timeout tracking
975+
TickType_t start_ticks = xTaskGetTickCount();
976+
TickType_t timeout_ticks = pdMS_TO_TICKS(timeout_ms);
977+
TickType_t elapsed_ticks = 0;
978+
int remaining_timeout_ticks = timeout_ticks;
979+
980+
// Take OUT mutex for the entire transfer operation
981+
BaseType_t taken = xSemaphoreTake(cdc_dev->data.out_mux, remaining_timeout_ticks);
973982
if (taken != pdTRUE) {
974983
return ESP_ERR_TIMEOUT;
975984
}
976985

977-
ESP_LOGD(TAG, "Submitting BULK OUT transfer");
978986
SemaphoreHandle_t transfer_finished_semaphore = (SemaphoreHandle_t)cdc_dev->data.out_xfer->context;
979-
xSemaphoreTake(transfer_finished_semaphore, 0); // Make sure the semaphore is taken before we submit new transfer
980987

981-
memcpy(cdc_dev->data.out_xfer->data_buffer, data, data_len);
982-
cdc_dev->data.out_xfer->num_bytes = data_len;
983-
cdc_dev->data.out_xfer->timeout_ms = timeout_ms;
984-
ESP_GOTO_ON_ERROR(usb_host_transfer_submit(cdc_dev->data.out_xfer), unblock, TAG,);
988+
// Process data in chunks if it's larger than the buffer size
989+
while (remaining > 0) {
990+
size_t chunk_size = (remaining > buffer_size) ? buffer_size : remaining;
991+
992+
ESP_LOGV(TAG, "Submitting BULK OUT transfer chunk: %zu bytes (remaining: %zu)", chunk_size, remaining);
993+
xSemaphoreTake(transfer_finished_semaphore, 0); // Make sure the semaphore is taken before we submit new transfer
994+
995+
memcpy(cdc_dev->data.out_xfer->data_buffer, data_ptr, chunk_size);
996+
cdc_dev->data.out_xfer->num_bytes = chunk_size;
997+
// Use remaining timeout for this chunk's transfer timeout
998+
cdc_dev->data.out_xfer->timeout_ms = pdTICKS_TO_MS(remaining_timeout_ticks);
999+
ESP_GOTO_ON_ERROR(usb_host_transfer_submit(cdc_dev->data.out_xfer), unblock, TAG,);
1000+
1001+
// Wait for OUT transfer completion with remaining timeout
1002+
taken = xSemaphoreTake(transfer_finished_semaphore, remaining_timeout_ticks);
1003+
elapsed_ticks = xTaskGetTickCount() - start_ticks;
1004+
remaining_timeout_ticks = timeout_ticks - elapsed_ticks;
1005+
if (!taken || remaining_timeout_ticks < 0) {
1006+
cdc_acm_reset_transfer_endpoint(cdc_dev->dev_hdl, cdc_dev->data.out_xfer); // Resetting the endpoint will cause all in-progress transfers to complete
1007+
ESP_LOGW(TAG, "TX transfer timeout");
1008+
ret = ESP_ERR_TIMEOUT;
1009+
goto unblock;
1010+
}
9851011

986-
// Wait for OUT transfer completion
987-
taken = xSemaphoreTake(transfer_finished_semaphore, pdMS_TO_TICKS(timeout_ms));
988-
if (!taken) {
989-
cdc_acm_reset_transfer_endpoint(cdc_dev->dev_hdl, cdc_dev->data.out_xfer); // Resetting the endpoint will cause all in-progress transfers to complete
990-
ESP_LOGW(TAG, "TX transfer timeout");
991-
ret = ESP_ERR_TIMEOUT;
992-
goto unblock;
1012+
ESP_GOTO_ON_FALSE(cdc_dev->data.out_xfer->status == USB_TRANSFER_STATUS_COMPLETED, ESP_ERR_INVALID_RESPONSE, unblock, TAG, "Bulk OUT transfer error");
1013+
ESP_GOTO_ON_FALSE(cdc_dev->data.out_xfer->actual_num_bytes == chunk_size, ESP_ERR_INVALID_RESPONSE, unblock, TAG, "Incorrect number of bytes transferred");
1014+
1015+
remaining -= chunk_size;
1016+
data_ptr += chunk_size;
9931017
}
9941018

995-
ESP_GOTO_ON_FALSE(cdc_dev->data.out_xfer->status == USB_TRANSFER_STATUS_COMPLETED, ESP_ERR_INVALID_RESPONSE, unblock, TAG, "Bulk OUT transfer error");
996-
ESP_GOTO_ON_FALSE(cdc_dev->data.out_xfer->actual_num_bytes == data_len, ESP_ERR_INVALID_RESPONSE, unblock, TAG, "Incorrect number of bytes transferred");
9971019
ret = ESP_OK;
9981020

9991021
unblock:

host/class/cdc/usb_host_cdc_acm/test_app/main/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ idf_component_register(SRC_DIRS .
55

66
# So we have access to private_include:
77
target_include_directories(${COMPONENT_LIB} PRIVATE "../../")
8+
target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-missing-field-initializers)

host/class/cdc/usb_host_cdc_acm/test_app/main/test_app_main.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
/*
2-
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
66

77
#include <stdio.h>
88
#include <string.h>
9+
#include "esp_newlib.h"
910
#include "unity.h"
1011
#include "unity_test_runner.h"
1112
#include "unity_test_utils_memory.h"
@@ -17,6 +18,7 @@ void setUp(void)
1718

1819
void tearDown(void)
1920
{
21+
esp_reent_cleanup(); //clean up some of the newlib's lazy allocations
2022
unity_utils_evaluate_leaks();
2123
}
2224

@@ -36,6 +38,6 @@ void app_main(void)
3638
printf(" \\/ \\/ \\/ \\/ \r\n");
3739

3840
unity_utils_setup_heap_record(80);
39-
unity_utils_set_leak_level(530);
41+
unity_utils_set_leak_level(30);
4042
unity_run_menu();
4143
}

0 commit comments

Comments
 (0)