diff --git a/cores/esp32/HWCDC.cpp b/cores/esp32/HWCDC.cpp index e593d7ff371..7410e257827 100644 --- a/cores/esp32/HWCDC.cpp +++ b/cores/esp32/HWCDC.cpp @@ -37,7 +37,7 @@ static QueueHandle_t rx_queue = NULL; static uint8_t rx_data_buf[64] = {0}; static intr_handle_t intr_handle = NULL; static SemaphoreHandle_t tx_lock = NULL; -static volatile bool isConnected = false; +static volatile bool connected = false; // timeout has no effect when USB CDC is unplugged static uint32_t requested_tx_timeout_ms = 100; @@ -79,12 +79,12 @@ static void hw_cdc_isr_handler(void *arg) { if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY) { // Interrupt tells us the host picked up the data we sent. if(!usb_serial_jtag_is_connected()) { - isConnected = false; + connected = false; usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); // USB is unplugged, nothing to be done here return; } else { - isConnected = true; + connected = true; } if (usb_serial_jtag_ll_txfifo_writable() == 1) { // 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) { usb_serial_jtag_ll_write_txfifo(queued_buff, queued_size); usb_serial_jtag_ll_txfifo_flush(); vRingbufferReturnItemFromISR(tx_ring_buf, queued_buff, &xTaskWoken); - if(isConnected) usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); + if(connected) usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); //send event? //ets_printf("TX:%u\n", queued_size); event.tx.len = queued_size; @@ -122,13 +122,13 @@ static void hw_cdc_isr_handler(void *arg) { } event.rx.len = i; arduino_hw_cdc_event_post(ARDUINO_HW_CDC_EVENTS, ARDUINO_HW_CDC_RX_EVENT, &event, sizeof(arduino_hw_cdc_event_data_t), &xTaskWoken); - isConnected = true; + connected = true; } if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_BUS_RESET) { usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_BUS_RESET); arduino_hw_cdc_event_post(ARDUINO_HW_CDC_EVENTS, ARDUINO_HW_CDC_BUS_RESET_EVENT, &event, sizeof(arduino_hw_cdc_event_data_t), &xTaskWoken); - isConnected = false; + connected = false; } if (xTaskWoken == pdTRUE) { @@ -136,9 +136,36 @@ static void hw_cdc_isr_handler(void *arg) { } } +bool HWCDC::isCDC_Connected() +{ + static bool running = false; + + // USB may be unplugged + if (usb_serial_jtag_is_connected() == false) { + connected = false; + running = false; + return false; + } + + if (connected) { + running = false; + return true; + } + + if (running == false && !connected) { // enables it only once! + usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); + } + // this will feed CDC TX FIFO to trigger IN_EMPTY + uint8_t c = '\0'; + usb_serial_jtag_ll_write_txfifo(&c, sizeof(c)); + usb_serial_jtag_ll_txfifo_flush(); + running = true; + return false; +} + static void ARDUINO_ISR_ATTR cdc0_write_char(char c) { uint32_t tx_timeout_ms = 0; - if(usb_serial_jtag_is_connected()) { + if(HWCDC::isConnected()) { tx_timeout_ms = requested_tx_timeout_ms; } if(xPortInIsrContext()){ @@ -157,33 +184,10 @@ HWCDC::~HWCDC(){ end(); } - // It should return just when USB is plugged and CDC is connected. HWCDC::operator bool() const { - static bool running = false; - - // USB may be unplugged - if (usb_serial_jtag_is_connected() == false) { - isConnected = false; - running = false; - return false; - } - - if (isConnected) { - running = false; - return true; - } - - if (running == false && !isConnected) { // enables it only once! - usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); - } - // this will feed CDC TX FIFO to trigger IN_EMPTY - uint8_t c = '\0'; - usb_serial_jtag_ll_write_txfifo(&c, sizeof(c)); - usb_serial_jtag_ll_txfifo_flush(); - running = true; - return false; + return HWCDC::isCDC_Connected(); } void HWCDC::onEvent(esp_event_handler_t callback){ @@ -267,7 +271,7 @@ void HWCDC::end() arduino_hw_cdc_event_loop_handle = NULL; } HWCDC::deinit(this); - isConnected = false; + connected = false; } void HWCDC::setTxTimeoutMs(uint32_t timeout){ @@ -299,7 +303,7 @@ int HWCDC::availableForWrite(void) if(tx_ring_buf == NULL || tx_lock == NULL){ return 0; } - if(usb_serial_jtag_is_connected()) { + if(HWCDC::isCDC_Connected()) { tx_timeout_ms = requested_tx_timeout_ms; } 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) if(buffer == NULL || size == 0 || tx_ring_buf == NULL || tx_lock == NULL){ return 0; } - if(usb_serial_jtag_is_connected()) { + if(HWCDC::isCDC_Connected()) { tx_timeout_ms = requested_tx_timeout_ms; } else { - isConnected = false; + connected = false; } if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){ return 0; @@ -354,7 +358,7 @@ size_t HWCDC::write(const uint8_t *buffer, size_t size) so_far += space; // Now trigger the ISR to read data from the ring buffer. usb_serial_jtag_ll_txfifo_flush(); - if(isConnected) usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); + if(connected) usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); while(to_send){ if(max_size > to_send){ @@ -369,12 +373,12 @@ size_t HWCDC::write(const uint8_t *buffer, size_t size) to_send -= max_size; // Now trigger the ISR to read data from the ring buffer. usb_serial_jtag_ll_txfifo_flush(); - if(isConnected) usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); + if(connected) usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); } } // CDC is diconnected ==> flush all data from TX buffer if(to_send && !usb_serial_jtag_ll_txfifo_writable()) { - isConnected = false; + connected = false; flushTXBuffer(); } xSemaphoreGive(tx_lock); @@ -392,10 +396,10 @@ void HWCDC::flush(void) if(tx_ring_buf == NULL || tx_lock == NULL){ return; } - if(usb_serial_jtag_is_connected()) { + if(HWCDC::isCDC_Connected()) { tx_timeout_ms = requested_tx_timeout_ms; } else { - isConnected = false; + connected = false; } if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){ return; @@ -405,7 +409,7 @@ void HWCDC::flush(void) if(uxItemsWaiting){ // Now trigger the ISR to read data from the ring buffer. usb_serial_jtag_ll_txfifo_flush(); - if(isConnected) usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); + if(connected) usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); } uint8_t tries = 3; while(tries && uxItemsWaiting){ @@ -415,7 +419,7 @@ void HWCDC::flush(void) if (lastUxItemsWaiting == uxItemsWaiting) tries--; } if (tries == 0) { // CDC isn't connected anymore... - isConnected = false; + connected = false; flushTXBuffer(); } xSemaphoreGive(tx_lock); diff --git a/cores/esp32/HWCDC.h b/cores/esp32/HWCDC.h index d09962861ec..91e99d2774d 100644 --- a/cores/esp32/HWCDC.h +++ b/cores/esp32/HWCDC.h @@ -1,4 +1,4 @@ -// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// Copyright 2015-2024 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ #include #include "esp_event.h" #include "Stream.h" +#include "driver/usb_serial_jtag.h" ESP_EVENT_DECLARE_BASE(ARDUINO_HW_CDC_EVENTS); @@ -46,6 +47,7 @@ class HWCDC: public Stream { private: static bool deinit(void * busptr); + static bool isCDC_Connected(); public: HWCDC(); @@ -68,7 +70,17 @@ class HWCDC: public Stream size_t write(uint8_t); size_t write(const uint8_t *buffer, size_t size); void flush(void); - + + inline static bool isPlugged(void) + { + return usb_serial_jtag_is_connected(); + } + + inline static bool isConnected(void) + { + return isCDC_Connected(); + } + inline size_t read(char * buffer, size_t size) { return read((uint8_t*) buffer, size); diff --git a/libraries/ESP32/examples/HWSerial_Events/HWSerial_Events.ino b/libraries/ESP32/examples/HWSerial_Events/HWSerial_Events.ino index 2838c627936..9c6de0501fa 100644 --- a/libraries/ESP32/examples/HWSerial_Events/HWSerial_Events.ino +++ b/libraries/ESP32/examples/HWSerial_Events/HWSerial_Events.ino @@ -24,8 +24,6 @@ void loop(){} HWCDC HWCDCSerial; #endif -#include "driver/usb_serial_jtag.h" - // USB Event Callback Function that will log CDC events into UART0 static void usbEventCallback(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { 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 } } -bool isPlugged() { - return usb_serial_jtag_is_connected(); -} - const char* _hwcdc_status[] = { - " USB Plugged but CDC is not connected\r\n", + " USB Plugged but CDC is NOT connected\r\n", " USB Plugged and CDC is connected\r\n", - " USB Unplugged and CDC not connected\r\n", + " USB Unplugged and CDC NOT connected\r\n", " USB Unplugged BUT CDC is connected :: PROBLEM\r\n", }; const char* HWCDC_Status() { - int i = isPlugged() ? 0 : 2; - if(HWCDCSerial) i += 1; + int i = HWCDCSerial.isPlugged() ? 0 : 2; + if(HWCDCSerial.isConnected()) i += 1; return _hwcdc_status[i]; }