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 5f48d9a

Browse files
committedApr 8, 2024
feat: backports HWCDC
1 parent c2a8e25 commit 5f48d9a

File tree

5 files changed

+329
-68
lines changed

5 files changed

+329
-68
lines changed
 

‎cores/esp32/HWCDC.cpp

Lines changed: 225 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
1+
// Copyright 2015-2024 Espressif Systems (Shanghai) PTE LTD
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.
@@ -30,12 +30,14 @@ static RingbufHandle_t tx_ring_buf = NULL;
3030
static xQueueHandle rx_queue = NULL;
3131
static uint8_t rx_data_buf[64] = {0};
3232
static intr_handle_t intr_handle = NULL;
33-
static volatile bool initial_empty = false;
33+
static volatile bool connected = false;
3434
static xSemaphoreHandle tx_lock = NULL;
3535

36-
// workaround for when USB CDC is not connected
37-
static uint32_t tx_timeout_ms = 0;
38-
static bool tx_timeout_change_request = false;
36+
static volatile unsigned long lastSOF_ms;
37+
static volatile uint8_t SOF_TIMEOUT;
38+
39+
// timeout has no effect when USB CDC is unplugged
40+
static uint32_t tx_timeout_ms = 100;
3941

4042
static esp_event_loop_handle_t arduino_hw_cdc_event_loop_handle = NULL;
4143

@@ -73,21 +75,17 @@ static void hw_cdc_isr_handler(void *arg) {
7375

7476
if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY) {
7577
// Interrupt tells us the host picked up the data we sent.
76-
if (usb_serial_jtag_ll_txfifo_writable() == 1) {
78+
if(!HWCDC::isPlugged()) {
79+
connected = false;
80+
usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
81+
// USB is unplugged, nothing to be done here
82+
return;
83+
} else {
84+
connected = true;
85+
}
86+
if (tx_ring_buf != NULL && usb_serial_jtag_ll_txfifo_writable() == 1) {
7787
// We disable the interrupt here so that the interrupt won't be triggered if there is no data to send.
7888
usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
79-
if(!initial_empty){
80-
initial_empty = true;
81-
// First time USB is plugged and the application has not explicitly set TX Timeout, set it to default 100ms.
82-
// Otherwise, USB is still unplugged and the timeout will be kept as Zero in order to avoid any delay in the
83-
// application whenever it uses write() and the TX Queue gets full.
84-
if (!tx_timeout_change_request) {
85-
tx_timeout_ms = 100;
86-
}
87-
//send event?
88-
//ets_printf("CONNECTED\n");
89-
arduino_hw_cdc_event_post(ARDUINO_HW_CDC_EVENTS, ARDUINO_HW_CDC_CONNECTED_EVENT, &event, sizeof(arduino_hw_cdc_event_data_t), &xTaskWoken);
90-
}
9189
size_t queued_size;
9290
uint8_t *queued_buff = (uint8_t *)xRingbufferReceiveUpToFromISR(tx_ring_buf, &queued_size, 64);
9391
// If the hardware fifo is avaliable, write in it. Otherwise, do nothing.
@@ -97,7 +95,7 @@ static void hw_cdc_isr_handler(void *arg) {
9795
usb_serial_jtag_ll_write_txfifo(queued_buff, queued_size);
9896
usb_serial_jtag_ll_txfifo_flush();
9997
vRingbufferReturnItemFromISR(tx_ring_buf, queued_buff, &xTaskWoken);
100-
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
98+
if(connected) usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
10199
//send event?
102100
//ets_printf("TX:%u\n", queued_size);
103101
event.tx.len = queued_size;
@@ -119,45 +117,138 @@ static void hw_cdc_isr_handler(void *arg) {
119117
break;
120118
}
121119
}
122-
//send event?
123-
//ets_printf("RX:%u/%u\n", i, rx_fifo_len);
124120
event.rx.len = i;
125121
arduino_hw_cdc_event_post(ARDUINO_HW_CDC_EVENTS, ARDUINO_HW_CDC_RX_EVENT, &event, sizeof(arduino_hw_cdc_event_data_t), &xTaskWoken);
122+
connected = true;
126123
}
127124

128125
if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_BUS_RESET) {
129126
usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_BUS_RESET);
130-
initial_empty = false;
131-
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
132-
//ets_printf("BUS_RESET\n");
133127
arduino_hw_cdc_event_post(ARDUINO_HW_CDC_EVENTS, ARDUINO_HW_CDC_BUS_RESET_EVENT, &event, sizeof(arduino_hw_cdc_event_data_t), &xTaskWoken);
128+
connected = false;
129+
}
130+
131+
if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_SOF) {
132+
usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SOF);
133+
lastSOF_ms = millis();
134134
}
135135

136136
if (xTaskWoken == pdTRUE) {
137137
portYIELD_FROM_ISR();
138138
}
139139
}
140140

141+
inline bool HWCDC::isPlugged(void)
142+
{
143+
return (lastSOF_ms + SOF_TIMEOUT) >= millis();
144+
}
145+
146+
bool HWCDC::isCDC_Connected()
147+
{
148+
static bool running = false;
149+
150+
// USB may be unplugged
151+
if (!isPlugged()) {
152+
connected = false;
153+
running = false;
154+
SOF_TIMEOUT = 5; // SOF timeout when unplugged
155+
return false;
156+
} else {
157+
SOF_TIMEOUT = 50; // SOF timeout when plugged
158+
}
159+
160+
if (connected) {
161+
running = false;
162+
return true;
163+
}
164+
165+
if (running == false && !connected) { // enables it only once!
166+
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
167+
}
168+
// this will feed CDC TX FIFO to trigger IN_EMPTY
169+
//uint8_t c = '\0';
170+
//usb_serial_jtag_ll_write_txfifo(&c, sizeof(c));
171+
usb_serial_jtag_ll_txfifo_flush();
172+
running = true;
173+
return false;
174+
}
175+
176+
static void flushTXBuffer(const uint8_t *buffer, size_t size)
177+
{
178+
if (!tx_ring_buf) return;
179+
UBaseType_t uxItemsWaiting= 0;
180+
vRingbufferGetInfo(tx_ring_buf, NULL, NULL, NULL, NULL, &uxItemsWaiting);
181+
size_t freeSpace = xRingbufferGetCurFreeSize(tx_ring_buf);
182+
size_t ringbufferLength = freeSpace + uxItemsWaiting;
183+
184+
if(buffer == NULL) {
185+
// just flush the whole ring buffer and exit - used by HWCDC::flush()
186+
size_t queued_size = 0;
187+
uint8_t *queued_buff = (uint8_t *)xRingbufferReceiveUpTo(tx_ring_buf, &queued_size, 0, ringbufferLength);
188+
if (queued_size && queued_buff != NULL) {
189+
vRingbufferReturnItem(tx_ring_buf, (void *)queued_buff);
190+
}
191+
return;
192+
}
193+
if(size == 0) return; // nothing to do
194+
if(freeSpace >= size){
195+
// just add the data to the ring buffer and exit
196+
if(xRingbufferSend(tx_ring_buf, (void*)buffer, size, 0) != pdTRUE){
197+
return;
198+
}
199+
} else {
200+
// how many byte should be flushed to make space for the new data
201+
size_t to_flush = size - freeSpace;
202+
if(to_flush > ringbufferLength) to_flush = ringbufferLength;
203+
size_t queued_size = 0;
204+
uint8_t *queued_buff = (uint8_t *)xRingbufferReceiveUpTo(tx_ring_buf, &queued_size, 0, to_flush);
205+
if (queued_size && queued_buff != NULL) {
206+
vRingbufferReturnItem(tx_ring_buf, (void *)queued_buff);
207+
}
208+
// now add the new data that fits to the ring buffer
209+
uint8_t *bptr = (uint8_t *)buffer;
210+
if (size >= ringbufferLength) {
211+
size = ringbufferLength;
212+
bptr = (uint8_t *)buffer + (size - ringbufferLength);
213+
}
214+
if(xRingbufferSend(tx_ring_buf, (void *)bptr, size, 0) != pdTRUE){
215+
return;
216+
}
217+
}
218+
// flushes CDC FIFO
219+
usb_serial_jtag_ll_txfifo_flush();
220+
}
221+
141222
static void ARDUINO_ISR_ATTR cdc0_write_char(char c) {
223+
if(tx_ring_buf == NULL) {
224+
return;
225+
}
226+
if(!HWCDC::isConnected()) {
227+
// just pop/push RingBuffer and apply FIFO policy
228+
flushTXBuffer((const uint8_t*)&c, 1);
229+
return;
230+
}
142231
if(xPortInIsrContext()){
143232
xRingbufferSendFromISR(tx_ring_buf, (void*) (&c), 1, NULL);
144233
} else {
145234
xRingbufferSend(tx_ring_buf, (void*) (&c), 1, tx_timeout_ms / portTICK_PERIOD_MS);
146235
}
147-
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
236+
usb_serial_jtag_ll_txfifo_flush();
148237
}
149238

150239
HWCDC::HWCDC() {
151-
240+
lastSOF_ms = 0;
241+
SOF_TIMEOUT = 5;
152242
}
153243

154244
HWCDC::~HWCDC(){
155245
end();
156246
}
157247

248+
// It should return <true> just when USB is plugged and CDC is connected.
158249
HWCDC::operator bool() const
159250
{
160-
return initial_empty;
251+
return HWCDC::isCDC_Connected();
161252
}
162253

163254
void HWCDC::onEvent(esp_event_handler_t callback){
@@ -168,6 +259,16 @@ void HWCDC::onEvent(arduino_hw_cdc_event_t event, esp_event_handler_t callback){
168259
arduino_hw_cdc_event_handler_register_with(ARDUINO_HW_CDC_EVENTS, event, callback, this);
169260
}
170261

262+
void HWCDC::deinit()
263+
{
264+
// Setting USB D+ D- pins
265+
// Force the host to re-enumerate (BUS_RESET)
266+
pinMode(USB_DM_GPIO_NUM, OUTPUT_OPEN_DRAIN);
267+
pinMode(USB_DP_GPIO_NUM, OUTPUT_OPEN_DRAIN);
268+
digitalWrite(USB_DM_GPIO_NUM, LOW);
269+
digitalWrite(USB_DP_GPIO_NUM, LOW);
270+
}
271+
171272
void HWCDC::begin(unsigned long baud)
172273
{
173274
if(tx_lock == NULL) {
@@ -185,20 +286,35 @@ void HWCDC::begin(unsigned long baud)
185286
log_e("HW CDC TX Buffer error");
186287
}
187288
}
289+
290+
// the HW Serial pins needs to be first deinited in order to allow `if(Serial)` to work :-(
291+
deinit();
292+
delay(10); // USB Host has to enumerate it again
293+
294+
// Configure PHY
295+
// USB_Serial_JTAG use internal PHY
296+
USB_SERIAL_JTAG.conf0.phy_sel = 0;
297+
// Disable software control USB D+ D- pullup pulldown (Device FS: dp_pullup = 1)
298+
USB_SERIAL_JTAG.conf0.pad_pull_override = 0;
299+
// Enable USB D+ pullup
300+
USB_SERIAL_JTAG.conf0.dp_pullup = 1;
301+
// Enable USB pad function
302+
USB_SERIAL_JTAG.conf0.usb_pad_enable = 1;
188303
usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_LL_INTR_MASK);
189-
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY | USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT | USB_SERIAL_JTAG_INTR_BUS_RESET);
304+
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY | USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT
305+
| USB_SERIAL_JTAG_INTR_BUS_RESET | USB_SERIAL_JTAG_INTR_SOF);
190306
if(!intr_handle && esp_intr_alloc(ETS_USB_SERIAL_JTAG_INTR_SOURCE, 0, hw_cdc_isr_handler, NULL, &intr_handle) != ESP_OK){
191307
isr_log_e("HW USB CDC failed to init interrupts");
192308
end();
193309
return;
194310
}
195-
usb_serial_jtag_ll_txfifo_flush();
196311
}
197312

198313
void HWCDC::end()
199314
{
200-
//Disable tx/rx interrupt.
315+
//Disable/clear/free tx/rx interrupt.
201316
usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_LL_INTR_MASK);
317+
usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_LL_INTR_MASK);
202318
esp_intr_free(intr_handle);
203319
intr_handle = NULL;
204320
if(tx_lock != NULL) {
@@ -211,13 +327,13 @@ void HWCDC::end()
211327
esp_event_loop_delete(arduino_hw_cdc_event_loop_handle);
212328
arduino_hw_cdc_event_loop_handle = NULL;
213329
}
330+
deinit();
331+
setDebugOutput(false);
332+
connected = false;
214333
}
215334

216335
void HWCDC::setTxTimeoutMs(uint32_t timeout){
217336
tx_timeout_ms = timeout;
218-
// it registers that the user has explicitly requested to use a value as TX timeout
219-
// used for the workaround with unplugged USB and TX Queue Full that causes a delay on every write()
220-
tx_timeout_change_request = true;
221337
}
222338

223339
/*
@@ -260,35 +376,63 @@ size_t HWCDC::write(const uint8_t *buffer, size_t size)
260376
if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){
261377
return 0;
262378
}
263-
size_t max_size = xRingbufferGetMaxItemSize(tx_ring_buf);
264-
size_t space = xRingbufferGetCurFreeSize(tx_ring_buf);
265-
size_t to_send = size, so_far = 0;
266-
267-
if(space > size){
268-
space = size;
269-
}
270-
// Non-Blocking method, Sending data to ringbuffer, and handle the data in ISR.
271-
if(xRingbufferSend(tx_ring_buf, (void*) (buffer), space, 0) != pdTRUE){
272-
size = 0;
379+
if(!isCDC_Connected()) {
380+
// just pop/push RingBuffer and apply FIFO policy
381+
flushTXBuffer(buffer, size);
273382
} else {
274-
to_send -= space;
275-
so_far += space;
276-
// Now trigger the ISR to read data from the ring buffer.
277-
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
383+
size_t space = xRingbufferGetCurFreeSize(tx_ring_buf);
384+
size_t to_send = size, so_far = 0;
278385

279-
while(to_send){
280-
if(max_size > to_send){
281-
max_size = to_send;
282-
}
283-
// Blocking method, Sending data to ringbuffer, and handle the data in ISR.
284-
if(xRingbufferSend(tx_ring_buf, (void*) (buffer+so_far), max_size, tx_timeout_ms / portTICK_PERIOD_MS) != pdTRUE){
285-
size = so_far;
286-
break;
287-
}
288-
so_far += max_size;
289-
to_send -= max_size;
386+
if(space > size){
387+
space = size;
388+
}
389+
// Non-Blocking method, Sending data to ringbuffer, and handle the data in ISR.
390+
if(space > 0 && xRingbufferSend(tx_ring_buf, (void*) (buffer), space, 0) != pdTRUE){
391+
size = 0;
392+
} else {
393+
to_send -= space;
394+
so_far += space;
290395
// Now trigger the ISR to read data from the ring buffer.
291-
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
396+
usb_serial_jtag_ll_txfifo_flush();
397+
if(connected) usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
398+
// tracks CDC trasmission progress to avoid hanging if CDC is unplugged while still sending data
399+
size_t last_toSend = to_send;
400+
uint32_t tries = tx_timeout_ms; // waits 1ms per sending data attempt, in case CDC is unplugged
401+
while(connected && to_send){
402+
space = xRingbufferGetCurFreeSize(tx_ring_buf);
403+
if(space > to_send){
404+
space = to_send;
405+
}
406+
// Blocking method, Sending data to ringbuffer, and handle the data in ISR.
407+
if(xRingbufferSend(tx_ring_buf, (void*) (buffer+so_far), space, tx_timeout_ms / portTICK_PERIOD_MS) != pdTRUE){
408+
size = so_far;
409+
log_w("write failed due to ring buffer full - timeout");
410+
break;
411+
}
412+
so_far += space;
413+
to_send -= space;
414+
// Now trigger the ISR to read data from the ring buffer.
415+
usb_serial_jtag_ll_txfifo_flush();
416+
if(connected) usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
417+
if(last_toSend == to_send) {
418+
// no progress in sending data... USB CDC is probably unplugged
419+
tries--;
420+
delay(1);
421+
} else {
422+
last_toSend = to_send;
423+
tries = tx_timeout_ms; // reset the timeout
424+
}
425+
if (tries == 0) { // CDC isn't connected anymore...
426+
size = so_far;
427+
log_w("write failed due to waiting USB Host - timeout");
428+
connected = false;
429+
}
430+
}
431+
}
432+
// CDC was diconnected while sending data ==> flush the TX buffer keeping the last data
433+
if(to_send && !usb_serial_jtag_ll_txfifo_writable()) {
434+
connected = false;
435+
flushTXBuffer(buffer + so_far, to_send);
292436
}
293437
}
294438
xSemaphoreGive(tx_lock);
@@ -308,15 +452,28 @@ void HWCDC::flush(void)
308452
if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){
309453
return;
310454
}
311-
UBaseType_t uxItemsWaiting = 0;
312-
vRingbufferGetInfo(tx_ring_buf, NULL, NULL, NULL, NULL, &uxItemsWaiting);
313-
if(uxItemsWaiting){
314-
// Now trigger the ISR to read data from the ring buffer.
315-
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
316-
}
317-
while(uxItemsWaiting){
318-
delay(5);
455+
if(!isCDC_Connected()) {
456+
flushTXBuffer(NULL, 0);
457+
} else {
458+
UBaseType_t uxItemsWaiting = 0;
319459
vRingbufferGetInfo(tx_ring_buf, NULL, NULL, NULL, NULL, &uxItemsWaiting);
460+
if(uxItemsWaiting){
461+
// Now trigger the ISR to read data from the ring buffer.
462+
usb_serial_jtag_ll_txfifo_flush();
463+
if(connected) usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
464+
}
465+
uint32_t tries = tx_timeout_ms; // waits 1ms per ISR sending data attempt, in case CDC is unplugged
466+
while(connected && tries && uxItemsWaiting){
467+
delay(1);
468+
UBaseType_t lastUxItemsWaiting = uxItemsWaiting;
469+
vRingbufferGetInfo(tx_ring_buf, NULL, NULL, NULL, NULL, &uxItemsWaiting);
470+
if (lastUxItemsWaiting == uxItemsWaiting) tries--;
471+
if(connected) usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
472+
}
473+
if (tries == 0) { // CDC isn't connected anymore...
474+
connected = false;
475+
flushTXBuffer(NULL, 0); // flushes all TX Buffer
476+
}
320477
}
321478
xSemaphoreGive(tx_lock);
322479
}
@@ -407,4 +564,4 @@ HWCDC USBSerial;
407564
#endif
408565
#endif
409566

410-
#endif /* CONFIG_TINYUSB_CDC_ENABLED */
567+
#endif /* CONFIG_IDF_TARGET_ESP32C3 */

‎cores/esp32/HWCDC.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ typedef union {
4242

4343
class HWCDC: public Stream
4444
{
45+
private:
46+
static void deinit();
47+
static bool isCDC_Connected();
48+
4549
public:
4650
HWCDC();
4751
~HWCDC();
@@ -64,6 +68,11 @@ class HWCDC: public Stream
6468
size_t write(const uint8_t *buffer, size_t size);
6569
void flush(void);
6670

71+
static bool isPlugged(void);
72+
inline static bool isConnected(void)
73+
{
74+
return isCDC_Connected();
75+
}
6776
inline size_t read(char * buffer, size_t size)
6877
{
6978
return read((uint8_t*) buffer, size);

‎libraries/ESP32/examples/HWSerial_Events/.skip.esp32

Whitespace-only changes.

‎libraries/ESP32/examples/HWSerial_Events/.skip.esp32s2

Whitespace-only changes.
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* This Example demonstrates how to receive Hardware Serial Events
3+
* This USB interface is available for the ESP32-S3 and ESP32-C3
4+
*
5+
* It will log all events and USB status (plugged/unplugged) into UART0
6+
* Any data read from UART0 will be sent to the USB CDC
7+
* Any data read from USB CDC will be sent to the UART0
8+
*
9+
* A suggestion is to use Arduino Serial Monitor for the UART0 port
10+
* and some other serial monitor application for the USB CDC port
11+
* in order to see the exchanged data and the Hardware Serial Events
12+
*
13+
*/
14+
15+
#ifndef ARDUINO_USB_MODE
16+
#error This ESP32 SoC has no Native USB interface
17+
#elif ARDUINO_USB_MODE == 0
18+
#warning This sketch should be used when USB is in Hardware CDC and JTAG mode
19+
void setup(){}
20+
void loop(){}
21+
#else
22+
23+
// Makes it work always using Serial0 as UART0 and USBSerial as the HW Serial USB CDC port
24+
#if ARDUINO_USB_CDC_ON_BOOT
25+
// HardwareSerial::Serial0 is declared but HWCDC::USBSerial not
26+
// Serial is the HWCDC USB CDC port
27+
#define USBSerial Serial
28+
#else
29+
// HWCDC::USBSerial is declared but HardwareSerial::Serial0 not
30+
// Serial is HardwareSerial UART0
31+
#define Serial0 Serial // redefine the symbol Serial0 to the default Arduino
32+
#endif
33+
34+
// USB Event Callback Function that will log CDC events into UART0
35+
static void usbEventCallback(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {
36+
if (event_base == ARDUINO_HW_CDC_EVENTS) {
37+
switch (event_id) {
38+
case ARDUINO_HW_CDC_CONNECTED_EVENT:
39+
Serial0.println("CDC EVENT:: ARDUINO_HW_CDC_CONNECTED_EVENT");
40+
break;
41+
case ARDUINO_HW_CDC_BUS_RESET_EVENT:
42+
Serial0.println("CDC EVENT:: ARDUINO_HW_CDC_BUS_RESET_EVENT");
43+
break;
44+
case ARDUINO_HW_CDC_RX_EVENT:
45+
Serial0.println("\nCDC EVENT:: ARDUINO_HW_CDC_RX_EVENT");
46+
// sends all bytes read from USB Hardware Serial to UART0
47+
while (USBSerial.available()) Serial0.write(USBSerial.read());
48+
break;
49+
case ARDUINO_HW_CDC_TX_EVENT:
50+
Serial0.println("CDC EVENT:: ARDUINO_HW_CDC_TX_EVENT");
51+
break;
52+
53+
default:
54+
break;
55+
}
56+
}
57+
}
58+
59+
const char* _hwcdc_status[] = {
60+
" USB Plugged but CDC is NOT connected\r\n",
61+
" USB Plugged and CDC is connected\r\n",
62+
" USB Unplugged and CDC is NOT connected\r\n",
63+
" USB Unplugged BUT CDC is connected :: PROBLEM\r\n",
64+
};
65+
66+
const char* HWCDC_Status() {
67+
int i = USBSerial.isPlugged() ? 0 : 2;
68+
if(USBSerial.isConnected()) i += 1;
69+
return _hwcdc_status[i];
70+
}
71+
72+
void setup() {
73+
USBSerial.begin();
74+
USBSerial.onEvent(usbEventCallback);
75+
76+
Serial0.begin(115200);
77+
Serial0.setDebugOutput(true);
78+
Serial0.println("Starting...");
79+
}
80+
81+
void loop() {
82+
static uint32_t counter = 0;
83+
84+
Serial0.print(counter);
85+
Serial0.print(HWCDC_Status());
86+
87+
if (USBSerial) {
88+
USBSerial.printf(" [%ld] connected\n\r", counter);
89+
}
90+
// sends all bytes read from UART0 to USB Hardware Serial
91+
while (Serial0.available()) USBSerial.write(Serial0.read());
92+
delay(1000);
93+
counter++;
94+
}
95+
#endif

0 commit comments

Comments
 (0)
Please sign in to comment.