Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 28293c9

Browse files
committedFeb 12, 2025·
feat(cdc): Add support for two CDC ports at once
1 parent 5ba4c21 commit 28293c9

File tree

3 files changed

+71
-28
lines changed

3 files changed

+71
-28
lines changed
 

‎cores/esp32/USBCDC.cpp

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ ESP_EVENT_DEFINE_BASE(ARDUINO_USB_CDC_EVENTS);
2525
esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait);
2626
esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg);
2727

28-
#define MAX_USB_CDC_DEVICES 2
29-
USBCDC *devices[MAX_USB_CDC_DEVICES] = {NULL, NULL};
28+
USBCDC *devices[CFG_TUD_CDC];
3029

3130
static uint16_t load_cdc_descriptor(uint8_t *dst, uint8_t *itf) {
3231
uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB CDC");
@@ -38,23 +37,42 @@ static uint16_t load_cdc_descriptor(uint8_t *dst, uint8_t *itf) {
3837
return TUD_CDC_DESC_LEN;
3938
}
4039

40+
static uint16_t load_cdc_descriptor2(uint8_t *dst, uint8_t *itf) {
41+
uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB CDC2");
42+
uint8_t ep_ntfy = tinyusb_get_free_in_endpoint();
43+
TU_VERIFY(ep_ntfy != 0);
44+
uint8_t ep_in = tinyusb_get_free_in_endpoint();
45+
TU_VERIFY(ep_in != 0);
46+
uint8_t ep_out = tinyusb_get_free_out_endpoint();
47+
TU_VERIFY(ep_out != 0);
48+
uint8_t descriptor[TUD_CDC_DESC_LEN] = {// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
49+
TUD_CDC_DESCRIPTOR(*itf, str_index, (uint8_t)(0x80 | ep_ntfy), CFG_TUD_ENDOINT_SIZE, ep_out, (uint8_t)(0x80 | ep_in), CFG_TUD_ENDOINT_SIZE)
50+
};
51+
*itf += 2;
52+
memcpy(dst, descriptor, TUD_CDC_DESC_LEN);
53+
return TUD_CDC_DESC_LEN;
54+
}
55+
4156
// Invoked when line state DTR & RTS are changed via SET_CONTROL_LINE_STATE
4257
void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) {
43-
if (itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL) {
58+
//log_v("ITF: %u, DTR: %u, RTS: %u", itf, dtr, rts);
59+
if (itf < CFG_TUD_CDC && devices[itf] != NULL) {
4460
devices[itf]->_onLineState(dtr, rts);
4561
}
4662
}
4763

4864
// Invoked when line coding is change via SET_LINE_CODING
4965
void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const *p_line_coding) {
50-
if (itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL) {
66+
//log_v("ITF: %u, BITRATE: %lu, STOP_BITS: %u, PARITY: %u, DATA_BITS: %u", itf, p_line_coding->bit_rate, p_line_coding->stop_bits, p_line_coding->parity, p_line_coding->data_bits);
67+
if (itf < CFG_TUD_CDC && devices[itf] != NULL) {
5168
devices[itf]->_onLineCoding(p_line_coding->bit_rate, p_line_coding->stop_bits, p_line_coding->parity, p_line_coding->data_bits);
5269
}
5370
}
5471

5572
// Invoked when received new data
5673
void tud_cdc_rx_cb(uint8_t itf) {
57-
if (itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL) {
74+
//log_v("ITF: %u", itf);
75+
if (itf < CFG_TUD_CDC && devices[itf] != NULL) {
5876
devices[itf]->_onRX();
5977
}
6078
}
@@ -66,13 +84,13 @@ void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms) {
6684

6785
// Invoked when space becomes available in TX buffer
6886
void tud_cdc_tx_complete_cb(uint8_t itf) {
69-
if (itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL) {
87+
if (itf < CFG_TUD_CDC && devices[itf] != NULL) {
7088
devices[itf]->_onTX();
7189
}
7290
}
7391

7492
static void ARDUINO_ISR_ATTR cdc0_write_char(char c) {
75-
if (devices[0] != NULL) {
93+
if (CFG_TUD_CDC && devices[0] != NULL) {
7694
tud_cdc_n_write_char(0, c);
7795
}
7896
}
@@ -84,9 +102,15 @@ static void usb_unplugged_cb(void *arg, esp_event_base_t event_base, int32_t eve
84102
USBCDC::USBCDC(uint8_t itfn)
85103
: itf(itfn), bit_rate(0), stop_bits(0), parity(0), data_bits(0), dtr(false), rts(false), connected(false), reboot_enable(true), rx_queue(NULL), tx_lock(NULL),
86104
tx_timeout_ms(250) {
87-
tinyusb_enable_interface(USB_INTERFACE_CDC, TUD_CDC_DESC_LEN, load_cdc_descriptor);
88-
if (itf < MAX_USB_CDC_DEVICES) {
105+
if (itf < CFG_TUD_CDC) {
106+
if (itf == 0) {
107+
tinyusb_enable_interface(USB_INTERFACE_CDC, TUD_CDC_DESC_LEN, load_cdc_descriptor);
108+
} else {
109+
tinyusb_enable_interface(USB_INTERFACE_CDC2, TUD_CDC_DESC_LEN, load_cdc_descriptor2);
110+
}
89111
arduino_usb_event_handler_register_with(ARDUINO_USB_EVENTS, ARDUINO_USB_STOPPED_EVENT, usb_unplugged_cb, this);
112+
} else {
113+
log_e("Maximum of %u CDC devices are supported", CFG_TUD_CDC);
90114
}
91115
}
92116

@@ -142,6 +166,9 @@ size_t USBCDC::setRxBufferSize(size_t rx_queue_len) {
142166
}
143167

144168
void USBCDC::begin(unsigned long baud) {
169+
if (itf >= CFG_TUD_CDC) {
170+
return;
171+
}
145172
if (tx_lock == NULL) {
146173
tx_lock = xSemaphoreCreateMutex();
147174
}
@@ -153,6 +180,9 @@ void USBCDC::begin(unsigned long baud) {
153180
}
154181

155182
void USBCDC::end() {
183+
if (itf >= CFG_TUD_CDC) {
184+
return;
185+
}
156186
connected = false;
157187
devices[itf] = NULL;
158188
setRxBufferSize(0);
@@ -298,14 +328,14 @@ bool USBCDC::rebootEnabled(void) {
298328
}
299329

300330
int USBCDC::available(void) {
301-
if (itf >= MAX_USB_CDC_DEVICES || rx_queue == NULL) {
331+
if (itf >= CFG_TUD_CDC || rx_queue == NULL) {
302332
return -1;
303333
}
304334
return uxQueueMessagesWaiting(rx_queue);
305335
}
306336

307337
int USBCDC::peek(void) {
308-
if (itf >= MAX_USB_CDC_DEVICES || rx_queue == NULL) {
338+
if (itf >= CFG_TUD_CDC || rx_queue == NULL) {
309339
return -1;
310340
}
311341
uint8_t c;
@@ -316,7 +346,7 @@ int USBCDC::peek(void) {
316346
}
317347

318348
int USBCDC::read(void) {
319-
if (itf >= MAX_USB_CDC_DEVICES || rx_queue == NULL) {
349+
if (itf >= CFG_TUD_CDC || rx_queue == NULL) {
320350
return -1;
321351
}
322352
uint8_t c = 0;
@@ -327,7 +357,7 @@ int USBCDC::read(void) {
327357
}
328358

329359
size_t USBCDC::read(uint8_t *buffer, size_t size) {
330-
if (itf >= MAX_USB_CDC_DEVICES || rx_queue == NULL) {
360+
if (itf >= CFG_TUD_CDC || rx_queue == NULL) {
331361
return -1;
332362
}
333363
uint8_t c = 0;
@@ -339,7 +369,7 @@ size_t USBCDC::read(uint8_t *buffer, size_t size) {
339369
}
340370

341371
void USBCDC::flush(void) {
342-
if (itf >= MAX_USB_CDC_DEVICES || tx_lock == NULL || !tud_cdc_n_connected(itf)) {
372+
if (itf >= CFG_TUD_CDC || tx_lock == NULL || !tud_cdc_n_connected(itf)) {
343373
return;
344374
}
345375
if (xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS) {
@@ -350,7 +380,7 @@ void USBCDC::flush(void) {
350380
}
351381

352382
int USBCDC::availableForWrite(void) {
353-
if (itf >= MAX_USB_CDC_DEVICES || tx_lock == NULL || !tud_cdc_n_connected(itf)) {
383+
if (itf >= CFG_TUD_CDC || tx_lock == NULL || !tud_cdc_n_connected(itf)) {
354384
return 0;
355385
}
356386
if (xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS) {
@@ -362,7 +392,7 @@ int USBCDC::availableForWrite(void) {
362392
}
363393

364394
size_t USBCDC::write(const uint8_t *buffer, size_t size) {
365-
if (itf >= MAX_USB_CDC_DEVICES || tx_lock == NULL || buffer == NULL || size == 0 || !tud_cdc_n_connected(itf)) {
395+
if (itf >= CFG_TUD_CDC || tx_lock == NULL || buffer == NULL || size == 0 || !tud_cdc_n_connected(itf)) {
366396
return 0;
367397
}
368398
if (xPortInIsrContext()) {
@@ -415,6 +445,9 @@ uint32_t USBCDC::baudRate() {
415445
}
416446

417447
void USBCDC::setDebugOutput(bool en) {
448+
if (itf) {
449+
return;
450+
}
418451
if (en) {
419452
uartSetDebug(NULL);
420453
ets_install_putc2((void (*)(char)) & cdc0_write_char);
@@ -424,7 +457,7 @@ void USBCDC::setDebugOutput(bool en) {
424457
}
425458

426459
USBCDC::operator bool() const {
427-
if (itf >= MAX_USB_CDC_DEVICES) {
460+
if (itf >= CFG_TUD_CDC) {
428461
return false;
429462
}
430463
return connected;

‎cores/esp32/esp32-hal-tinyusb.c

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -616,27 +616,29 @@ void usb_persist_restart(restart_type_t mode) {
616616
}
617617

618618
static bool tinyusb_reserve_in_endpoint(uint8_t endpoint) {
619-
if (endpoint > 6 || (tinyusb_endpoints.in & BIT(endpoint)) != 0) {
619+
if (endpoint > CFG_TUD_NUM_EPS || (tinyusb_endpoints.in & BIT(endpoint)) != 0) {
620620
return false;
621621
}
622622
tinyusb_endpoints.in |= BIT(endpoint);
623623
return true;
624624
}
625625

626626
static bool tinyusb_reserve_out_endpoint(uint8_t endpoint) {
627-
if (endpoint > 6 || (tinyusb_endpoints.out & BIT(endpoint)) != 0) {
627+
if (endpoint > CFG_TUD_NUM_EPS || (tinyusb_endpoints.out & BIT(endpoint)) != 0) {
628628
return false;
629629
}
630630
tinyusb_endpoints.out |= BIT(endpoint);
631631
return true;
632632
}
633633

634634
static bool tinyusb_has_available_fifos(void) {
635-
uint8_t max_endpoints = 4, active_endpoints = 0;
635+
uint8_t max_endpoints = CFG_TUD_NUM_IN_EPS-1, active_endpoints = 0;
636+
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
636637
if (tinyusb_loaded_interfaces_mask & BIT(USB_INTERFACE_CDC)) {
637-
max_endpoints = 5; //CDC endpoint 0x85 is actually not linked to FIFO and not used
638+
max_endpoints = CFG_TUD_NUM_IN_EPS; //CDC endpoint 0x85 is actually not linked to FIFO and not used
638639
}
639-
for (uint8_t i = 1; i < 7; i++) {
640+
#endif
641+
for (uint8_t i = 1; i <= CFG_TUD_NUM_EPS; i++) {
640642
if ((tinyusb_endpoints.in & BIT(i)) != 0) {
641643
active_endpoints++;
642644
}
@@ -771,7 +773,7 @@ static void usb_device_task(void *param) {
771773
* PUBLIC API
772774
* */
773775
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
774-
const char *tinyusb_interface_names[USB_INTERFACE_MAX] = {"MSC", "DFU", "HID", "VENDOR", "CDC", "MIDI", "CUSTOM"};
776+
const char *tinyusb_interface_names[USB_INTERFACE_MAX] = {"MSC", "DFU", "HID", "VENDOR", "CDC", "CDC2", "MIDI", "CUSTOM"};
775777
#endif
776778
static bool tinyusb_is_initialized = false;
777779

@@ -862,7 +864,7 @@ uint8_t tinyusb_get_free_duplex_endpoint(void) {
862864
log_e("No available IN endpoints");
863865
return 0;
864866
}
865-
for (uint8_t i = 1; i < 7; i++) {
867+
for (uint8_t i = 1; i <= CFG_TUD_NUM_IN_EPS; i++) {
866868
if ((tinyusb_endpoints.in & BIT(i)) == 0 && (tinyusb_endpoints.out & BIT(i)) == 0) {
867869
tinyusb_endpoints.in |= BIT(i);
868870
tinyusb_endpoints.out |= BIT(i);
@@ -878,13 +880,13 @@ uint8_t tinyusb_get_free_in_endpoint(void) {
878880
log_e("No available IN endpoints");
879881
return 0;
880882
}
881-
for (uint8_t i = 1; i < 7; i++) {
883+
for (uint8_t i = 1; i <= CFG_TUD_NUM_IN_EPS; i++) {
882884
if ((tinyusb_endpoints.in & BIT(i)) == 0 && (tinyusb_endpoints.out & BIT(i)) != 0) {
883885
tinyusb_endpoints.in |= BIT(i);
884886
return i;
885887
}
886888
}
887-
for (uint8_t i = 1; i < 7; i++) {
889+
for (uint8_t i = 1; i <= CFG_TUD_NUM_IN_EPS; i++) {
888890
if ((tinyusb_endpoints.in & BIT(i)) == 0) {
889891
tinyusb_endpoints.in |= BIT(i);
890892
return i;
@@ -894,13 +896,13 @@ uint8_t tinyusb_get_free_in_endpoint(void) {
894896
}
895897

896898
uint8_t tinyusb_get_free_out_endpoint(void) {
897-
for (uint8_t i = 1; i < 7; i++) {
899+
for (uint8_t i = 1; i <= CFG_TUD_NUM_EPS; i++) {
898900
if ((tinyusb_endpoints.out & BIT(i)) == 0 && (tinyusb_endpoints.in & BIT(i)) != 0) {
899901
tinyusb_endpoints.out |= BIT(i);
900902
return i;
901903
}
902904
}
903-
for (uint8_t i = 1; i < 7; i++) {
905+
for (uint8_t i = 1; i <= CFG_TUD_NUM_EPS; i++) {
904906
if ((tinyusb_endpoints.out & BIT(i)) == 0) {
905907
tinyusb_endpoints.out |= BIT(i);
906908
return i;

‎cores/esp32/esp32-hal-tinyusb.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,13 @@ extern "C" {
3838
#define CFG_TUD_ENDOINT_SIZE 64
3939
#endif
4040
#endif
41+
#if CONFIG_IDF_TARGET_ESP32P4
42+
#define CFG_TUD_NUM_EPS 15
43+
#define CFG_TUD_NUM_IN_EPS 8
44+
#else
45+
#define CFG_TUD_NUM_EPS 6
46+
#define CFG_TUD_NUM_IN_EPS 5
47+
#endif
4148

4249
typedef struct {
4350
uint16_t vid;
@@ -88,6 +95,7 @@ typedef enum {
8895
USB_INTERFACE_HID,
8996
USB_INTERFACE_VENDOR,
9097
USB_INTERFACE_CDC,
98+
USB_INTERFACE_CDC2,
9199
USB_INTERFACE_MIDI,
92100
USB_INTERFACE_CUSTOM,
93101
USB_INTERFACE_MAX

0 commit comments

Comments
 (0)
Please sign in to comment.