Skip to content

Commit 7b651b6

Browse files
feat(cdc): Add support for two CDC ports at once (espressif#10962)
* feat(cdc): Add support for two CDC ports at once * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
1 parent 250c1ab commit 7b651b6

File tree

3 files changed

+72
-28
lines changed

3 files changed

+72
-28
lines changed

cores/esp32/USBCDC.cpp

+51-17
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,43 @@ 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] = {
49+
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
50+
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)
51+
};
52+
*itf += 2;
53+
memcpy(dst, descriptor, TUD_CDC_DESC_LEN);
54+
return TUD_CDC_DESC_LEN;
55+
}
56+
4157
// Invoked when line state DTR & RTS are changed via SET_CONTROL_LINE_STATE
4258
void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) {
43-
if (itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL) {
59+
//log_v("ITF: %u, DTR: %u, RTS: %u", itf, dtr, rts);
60+
if (itf < CFG_TUD_CDC && devices[itf] != NULL) {
4461
devices[itf]->_onLineState(dtr, rts);
4562
}
4663
}
4764

4865
// Invoked when line coding is change via SET_LINE_CODING
4966
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) {
67+
//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);
68+
if (itf < CFG_TUD_CDC && devices[itf] != NULL) {
5169
devices[itf]->_onLineCoding(p_line_coding->bit_rate, p_line_coding->stop_bits, p_line_coding->parity, p_line_coding->data_bits);
5270
}
5371
}
5472

5573
// Invoked when received new data
5674
void tud_cdc_rx_cb(uint8_t itf) {
57-
if (itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL) {
75+
//log_v("ITF: %u", itf);
76+
if (itf < CFG_TUD_CDC && devices[itf] != NULL) {
5877
devices[itf]->_onRX();
5978
}
6079
}
@@ -66,13 +85,13 @@ void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms) {
6685

6786
// Invoked when space becomes available in TX buffer
6887
void tud_cdc_tx_complete_cb(uint8_t itf) {
69-
if (itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL) {
88+
if (itf < CFG_TUD_CDC && devices[itf] != NULL) {
7089
devices[itf]->_onTX();
7190
}
7291
}
7392

7493
static void ARDUINO_ISR_ATTR cdc0_write_char(char c) {
75-
if (devices[0] != NULL) {
94+
if (CFG_TUD_CDC && devices[0] != NULL) {
7695
tud_cdc_n_write_char(0, c);
7796
}
7897
}
@@ -84,9 +103,15 @@ static void usb_unplugged_cb(void *arg, esp_event_base_t event_base, int32_t eve
84103
USBCDC::USBCDC(uint8_t itfn)
85104
: 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),
86105
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) {
106+
if (itf < CFG_TUD_CDC) {
107+
if (itf == 0) {
108+
tinyusb_enable_interface(USB_INTERFACE_CDC, TUD_CDC_DESC_LEN, load_cdc_descriptor);
109+
} else {
110+
tinyusb_enable_interface(USB_INTERFACE_CDC2, TUD_CDC_DESC_LEN, load_cdc_descriptor2);
111+
}
89112
arduino_usb_event_handler_register_with(ARDUINO_USB_EVENTS, ARDUINO_USB_STOPPED_EVENT, usb_unplugged_cb, this);
113+
} else {
114+
log_e("Maximum of %u CDC devices are supported", CFG_TUD_CDC);
90115
}
91116
}
92117

@@ -142,6 +167,9 @@ size_t USBCDC::setRxBufferSize(size_t rx_queue_len) {
142167
}
143168

144169
void USBCDC::begin(unsigned long baud) {
170+
if (itf >= CFG_TUD_CDC) {
171+
return;
172+
}
145173
if (tx_lock == NULL) {
146174
tx_lock = xSemaphoreCreateMutex();
147175
}
@@ -153,6 +181,9 @@ void USBCDC::begin(unsigned long baud) {
153181
}
154182

155183
void USBCDC::end() {
184+
if (itf >= CFG_TUD_CDC) {
185+
return;
186+
}
156187
connected = false;
157188
devices[itf] = NULL;
158189
setRxBufferSize(0);
@@ -298,14 +329,14 @@ bool USBCDC::rebootEnabled(void) {
298329
}
299330

300331
int USBCDC::available(void) {
301-
if (itf >= MAX_USB_CDC_DEVICES || rx_queue == NULL) {
332+
if (itf >= CFG_TUD_CDC || rx_queue == NULL) {
302333
return -1;
303334
}
304335
return uxQueueMessagesWaiting(rx_queue);
305336
}
306337

307338
int USBCDC::peek(void) {
308-
if (itf >= MAX_USB_CDC_DEVICES || rx_queue == NULL) {
339+
if (itf >= CFG_TUD_CDC || rx_queue == NULL) {
309340
return -1;
310341
}
311342
uint8_t c;
@@ -316,7 +347,7 @@ int USBCDC::peek(void) {
316347
}
317348

318349
int USBCDC::read(void) {
319-
if (itf >= MAX_USB_CDC_DEVICES || rx_queue == NULL) {
350+
if (itf >= CFG_TUD_CDC || rx_queue == NULL) {
320351
return -1;
321352
}
322353
uint8_t c = 0;
@@ -327,7 +358,7 @@ int USBCDC::read(void) {
327358
}
328359

329360
size_t USBCDC::read(uint8_t *buffer, size_t size) {
330-
if (itf >= MAX_USB_CDC_DEVICES || rx_queue == NULL) {
361+
if (itf >= CFG_TUD_CDC || rx_queue == NULL) {
331362
return -1;
332363
}
333364
uint8_t c = 0;
@@ -339,7 +370,7 @@ size_t USBCDC::read(uint8_t *buffer, size_t size) {
339370
}
340371

341372
void USBCDC::flush(void) {
342-
if (itf >= MAX_USB_CDC_DEVICES || tx_lock == NULL || !tud_cdc_n_connected(itf)) {
373+
if (itf >= CFG_TUD_CDC || tx_lock == NULL || !tud_cdc_n_connected(itf)) {
343374
return;
344375
}
345376
if (xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS) {
@@ -350,7 +381,7 @@ void USBCDC::flush(void) {
350381
}
351382

352383
int USBCDC::availableForWrite(void) {
353-
if (itf >= MAX_USB_CDC_DEVICES || tx_lock == NULL || !tud_cdc_n_connected(itf)) {
384+
if (itf >= CFG_TUD_CDC || tx_lock == NULL || !tud_cdc_n_connected(itf)) {
354385
return 0;
355386
}
356387
if (xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS) {
@@ -362,7 +393,7 @@ int USBCDC::availableForWrite(void) {
362393
}
363394

364395
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)) {
396+
if (itf >= CFG_TUD_CDC || tx_lock == NULL || buffer == NULL || size == 0 || !tud_cdc_n_connected(itf)) {
366397
return 0;
367398
}
368399
if (xPortInIsrContext()) {
@@ -415,6 +446,9 @@ uint32_t USBCDC::baudRate() {
415446
}
416447

417448
void USBCDC::setDebugOutput(bool en) {
449+
if (itf) {
450+
return;
451+
}
418452
if (en) {
419453
uartSetDebug(NULL);
420454
ets_install_putc2((void (*)(char)) & cdc0_write_char);
@@ -424,7 +458,7 @@ void USBCDC::setDebugOutput(bool en) {
424458
}
425459

426460
USBCDC::operator bool() const {
427-
if (itf >= MAX_USB_CDC_DEVICES) {
461+
if (itf >= CFG_TUD_CDC) {
428462
return false;
429463
}
430464
return connected;

cores/esp32/esp32-hal-tinyusb.c

+13-11
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

+8
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)