Skip to content

Commit 2fdd901

Browse files
authored
fixes default 100ms delay with HWCDC write() is CDC is not connected (espressif#9307)
* feat(hwcdc): fix delay Fixes delay when CDC is disconnected. At this time is only fixes it when USB cable is unplugged. * feat(hwcdc): fix delay fixes delay when CDC is not connected. It was only considering when the USB cable was not plugged. * feat(hwcdc): add 2 methods Adds 2 new methods: - isPlugged() will return true when USB cable is plugged, false otherwise. - isConnected() will return true when USB CDC is connected to a application in the USB Host side and communication is stablished. * feat(hwcdc): adjusts APIs Fixes the example to use the new added APIs for checking if USB cable is plugged and for checking if CDC is connected. * fixes api declaration * fixes API declaration
1 parent b7af090 commit 2fdd901

File tree

3 files changed

+64
-54
lines changed

3 files changed

+64
-54
lines changed

Diff for: cores/esp32/HWCDC.cpp

+46-42
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ static QueueHandle_t rx_queue = NULL;
3737
static uint8_t rx_data_buf[64] = {0};
3838
static intr_handle_t intr_handle = NULL;
3939
static SemaphoreHandle_t tx_lock = NULL;
40-
static volatile bool isConnected = false;
40+
static volatile bool connected = false;
4141

4242
// timeout has no effect when USB CDC is unplugged
4343
static uint32_t requested_tx_timeout_ms = 100;
@@ -79,12 +79,12 @@ static void hw_cdc_isr_handler(void *arg) {
7979
if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY) {
8080
// Interrupt tells us the host picked up the data we sent.
8181
if(!usb_serial_jtag_is_connected()) {
82-
isConnected = false;
82+
connected = false;
8383
usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
8484
// USB is unplugged, nothing to be done here
8585
return;
8686
} else {
87-
isConnected = true;
87+
connected = true;
8888
}
8989
if (usb_serial_jtag_ll_txfifo_writable() == 1) {
9090
// We disable the interrupt here so that the interrupt won't be triggered if there is no data to send.
@@ -98,7 +98,7 @@ static void hw_cdc_isr_handler(void *arg) {
9898
usb_serial_jtag_ll_write_txfifo(queued_buff, queued_size);
9999
usb_serial_jtag_ll_txfifo_flush();
100100
vRingbufferReturnItemFromISR(tx_ring_buf, queued_buff, &xTaskWoken);
101-
if(isConnected) usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
101+
if(connected) usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
102102
//send event?
103103
//ets_printf("TX:%u\n", queued_size);
104104
event.tx.len = queued_size;
@@ -122,23 +122,50 @@ static void hw_cdc_isr_handler(void *arg) {
122122
}
123123
event.rx.len = i;
124124
arduino_hw_cdc_event_post(ARDUINO_HW_CDC_EVENTS, ARDUINO_HW_CDC_RX_EVENT, &event, sizeof(arduino_hw_cdc_event_data_t), &xTaskWoken);
125-
isConnected = true;
125+
connected = true;
126126
}
127127

128128
if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_BUS_RESET) {
129129
usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_BUS_RESET);
130130
arduino_hw_cdc_event_post(ARDUINO_HW_CDC_EVENTS, ARDUINO_HW_CDC_BUS_RESET_EVENT, &event, sizeof(arduino_hw_cdc_event_data_t), &xTaskWoken);
131-
isConnected = false;
131+
connected = false;
132132
}
133133

134134
if (xTaskWoken == pdTRUE) {
135135
portYIELD_FROM_ISR();
136136
}
137137
}
138138

139+
bool HWCDC::isCDC_Connected()
140+
{
141+
static bool running = false;
142+
143+
// USB may be unplugged
144+
if (usb_serial_jtag_is_connected() == false) {
145+
connected = false;
146+
running = false;
147+
return false;
148+
}
149+
150+
if (connected) {
151+
running = false;
152+
return true;
153+
}
154+
155+
if (running == false && !connected) { // enables it only once!
156+
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
157+
}
158+
// this will feed CDC TX FIFO to trigger IN_EMPTY
159+
uint8_t c = '\0';
160+
usb_serial_jtag_ll_write_txfifo(&c, sizeof(c));
161+
usb_serial_jtag_ll_txfifo_flush();
162+
running = true;
163+
return false;
164+
}
165+
139166
static void ARDUINO_ISR_ATTR cdc0_write_char(char c) {
140167
uint32_t tx_timeout_ms = 0;
141-
if(usb_serial_jtag_is_connected()) {
168+
if(HWCDC::isConnected()) {
142169
tx_timeout_ms = requested_tx_timeout_ms;
143170
}
144171
if(xPortInIsrContext()){
@@ -157,33 +184,10 @@ HWCDC::~HWCDC(){
157184
end();
158185
}
159186

160-
161187
// It should return <true> just when USB is plugged and CDC is connected.
162188
HWCDC::operator bool() const
163189
{
164-
static bool running = false;
165-
166-
// USB may be unplugged
167-
if (usb_serial_jtag_is_connected() == false) {
168-
isConnected = false;
169-
running = false;
170-
return false;
171-
}
172-
173-
if (isConnected) {
174-
running = false;
175-
return true;
176-
}
177-
178-
if (running == false && !isConnected) { // enables it only once!
179-
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
180-
}
181-
// this will feed CDC TX FIFO to trigger IN_EMPTY
182-
uint8_t c = '\0';
183-
usb_serial_jtag_ll_write_txfifo(&c, sizeof(c));
184-
usb_serial_jtag_ll_txfifo_flush();
185-
running = true;
186-
return false;
190+
return HWCDC::isCDC_Connected();
187191
}
188192

189193
void HWCDC::onEvent(esp_event_handler_t callback){
@@ -267,7 +271,7 @@ void HWCDC::end()
267271
arduino_hw_cdc_event_loop_handle = NULL;
268272
}
269273
HWCDC::deinit(this);
270-
isConnected = false;
274+
connected = false;
271275
}
272276

273277
void HWCDC::setTxTimeoutMs(uint32_t timeout){
@@ -299,7 +303,7 @@ int HWCDC::availableForWrite(void)
299303
if(tx_ring_buf == NULL || tx_lock == NULL){
300304
return 0;
301305
}
302-
if(usb_serial_jtag_is_connected()) {
306+
if(HWCDC::isCDC_Connected()) {
303307
tx_timeout_ms = requested_tx_timeout_ms;
304308
}
305309
if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){
@@ -331,10 +335,10 @@ size_t HWCDC::write(const uint8_t *buffer, size_t size)
331335
if(buffer == NULL || size == 0 || tx_ring_buf == NULL || tx_lock == NULL){
332336
return 0;
333337
}
334-
if(usb_serial_jtag_is_connected()) {
338+
if(HWCDC::isCDC_Connected()) {
335339
tx_timeout_ms = requested_tx_timeout_ms;
336340
} else {
337-
isConnected = false;
341+
connected = false;
338342
}
339343
if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){
340344
return 0;
@@ -354,7 +358,7 @@ size_t HWCDC::write(const uint8_t *buffer, size_t size)
354358
so_far += space;
355359
// Now trigger the ISR to read data from the ring buffer.
356360
usb_serial_jtag_ll_txfifo_flush();
357-
if(isConnected) usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
361+
if(connected) usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
358362

359363
while(to_send){
360364
if(max_size > to_send){
@@ -369,12 +373,12 @@ size_t HWCDC::write(const uint8_t *buffer, size_t size)
369373
to_send -= max_size;
370374
// Now trigger the ISR to read data from the ring buffer.
371375
usb_serial_jtag_ll_txfifo_flush();
372-
if(isConnected) usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
376+
if(connected) usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
373377
}
374378
}
375379
// CDC is diconnected ==> flush all data from TX buffer
376380
if(to_send && !usb_serial_jtag_ll_txfifo_writable()) {
377-
isConnected = false;
381+
connected = false;
378382
flushTXBuffer();
379383
}
380384
xSemaphoreGive(tx_lock);
@@ -392,10 +396,10 @@ void HWCDC::flush(void)
392396
if(tx_ring_buf == NULL || tx_lock == NULL){
393397
return;
394398
}
395-
if(usb_serial_jtag_is_connected()) {
399+
if(HWCDC::isCDC_Connected()) {
396400
tx_timeout_ms = requested_tx_timeout_ms;
397401
} else {
398-
isConnected = false;
402+
connected = false;
399403
}
400404
if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){
401405
return;
@@ -405,7 +409,7 @@ void HWCDC::flush(void)
405409
if(uxItemsWaiting){
406410
// Now trigger the ISR to read data from the ring buffer.
407411
usb_serial_jtag_ll_txfifo_flush();
408-
if(isConnected) usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
412+
if(connected) usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
409413
}
410414
uint8_t tries = 3;
411415
while(tries && uxItemsWaiting){
@@ -415,7 +419,7 @@ void HWCDC::flush(void)
415419
if (lastUxItemsWaiting == uxItemsWaiting) tries--;
416420
}
417421
if (tries == 0) { // CDC isn't connected anymore...
418-
isConnected = false;
422+
connected = false;
419423
flushTXBuffer();
420424
}
421425
xSemaphoreGive(tx_lock);

Diff for: cores/esp32/HWCDC.h

+14-2
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.
@@ -21,6 +21,7 @@
2121
#include <inttypes.h>
2222
#include "esp_event.h"
2323
#include "Stream.h"
24+
#include "driver/usb_serial_jtag.h"
2425

2526
ESP_EVENT_DECLARE_BASE(ARDUINO_HW_CDC_EVENTS);
2627

@@ -46,6 +47,7 @@ class HWCDC: public Stream
4647
{
4748
private:
4849
static bool deinit(void * busptr);
50+
static bool isCDC_Connected();
4951

5052
public:
5153
HWCDC();
@@ -68,7 +70,17 @@ class HWCDC: public Stream
6870
size_t write(uint8_t);
6971
size_t write(const uint8_t *buffer, size_t size);
7072
void flush(void);
71-
73+
74+
inline static bool isPlugged(void)
75+
{
76+
return usb_serial_jtag_is_connected();
77+
}
78+
79+
inline static bool isConnected(void)
80+
{
81+
return isCDC_Connected();
82+
}
83+
7284
inline size_t read(char * buffer, size_t size)
7385
{
7486
return read((uint8_t*) buffer, size);

Diff for: libraries/ESP32/examples/HWSerial_Events/HWSerial_Events.ino

+4-10
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ void loop(){}
2424
HWCDC HWCDCSerial;
2525
#endif
2626

27-
#include "driver/usb_serial_jtag.h"
28-
2927
// USB Event Callback Function that will log CDC events into UART0
3028
static void usbEventCallback(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {
3129
if (event_base == ARDUINO_HW_CDC_EVENTS) {
@@ -51,20 +49,16 @@ static void usbEventCallback(void* arg, esp_event_base_t event_base, int32_t eve
5149
}
5250
}
5351

54-
bool isPlugged() {
55-
return usb_serial_jtag_is_connected();
56-
}
57-
5852
const char* _hwcdc_status[] = {
59-
" USB Plugged but CDC is not connected\r\n",
53+
" USB Plugged but CDC is NOT connected\r\n",
6054
" USB Plugged and CDC is connected\r\n",
61-
" USB Unplugged and CDC not connected\r\n",
55+
" USB Unplugged and CDC NOT connected\r\n",
6256
" USB Unplugged BUT CDC is connected :: PROBLEM\r\n",
6357
};
6458

6559
const char* HWCDC_Status() {
66-
int i = isPlugged() ? 0 : 2;
67-
if(HWCDCSerial) i += 1;
60+
int i = HWCDCSerial.isPlugged() ? 0 : 2;
61+
if(HWCDCSerial.isConnected()) i += 1;
6862
return _hwcdc_status[i];
6963
}
7064

0 commit comments

Comments
 (0)