From 52da2305c1b4d844e9cee580865d88acebf2a450 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Wed, 28 Feb 2024 16:23:10 -0300 Subject: [PATCH 1/6] feat(hwcdc): fix delay Fixes delay when CDC is disconnected. At this time is only fixes it when USB cable is unplugged. --- cores/esp32/HWCDC.h | 1 + 1 file changed, 1 insertion(+) diff --git a/cores/esp32/HWCDC.h b/cores/esp32/HWCDC.h index d09962861ec..e54ad4da53c 100644 --- a/cores/esp32/HWCDC.h +++ b/cores/esp32/HWCDC.h @@ -46,6 +46,7 @@ class HWCDC: public Stream { private: static bool deinit(void * busptr); + static bool isCDC_Connected(); public: HWCDC(); From 32b2fa743635b18f185be1efddca8dabb54f8e03 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Wed, 28 Feb 2024 16:28:17 -0300 Subject: [PATCH 2/6] feat(hwcdc): fix delay fixes delay when CDC is not connected. It was only considering when the USB cable was not plugged. --- cores/esp32/HWCDC.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/cores/esp32/HWCDC.cpp b/cores/esp32/HWCDC.cpp index e593d7ff371..6092bd1f810 100644 --- a/cores/esp32/HWCDC.cpp +++ b/cores/esp32/HWCDC.cpp @@ -138,7 +138,7 @@ static void hw_cdc_isr_handler(void *arg) { static void ARDUINO_ISR_ATTR cdc0_write_char(char c) { uint32_t tx_timeout_ms = 0; - if(usb_serial_jtag_is_connected()) { + if(isCDC_Connected()) { tx_timeout_ms = requested_tx_timeout_ms; } if(xPortInIsrContext()){ @@ -157,9 +157,7 @@ HWCDC::~HWCDC(){ end(); } - -// It should return just when USB is plugged and CDC is connected. -HWCDC::operator bool() const +bool HWCDC::isCDC_Connected() { static bool running = false; @@ -183,7 +181,13 @@ HWCDC::operator bool() const usb_serial_jtag_ll_write_txfifo(&c, sizeof(c)); usb_serial_jtag_ll_txfifo_flush(); running = true; - return false; + return false; +} + +// It should return just when USB is plugged and CDC is connected. +HWCDC::operator bool() const +{ + return isCDC_Connected(); } void HWCDC::onEvent(esp_event_handler_t callback){ @@ -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(isCDC_Connected()) { tx_timeout_ms = requested_tx_timeout_ms; } if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){ @@ -331,7 +335,7 @@ 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(isCDC_Connected()) { tx_timeout_ms = requested_tx_timeout_ms; } else { isConnected = false; @@ -392,7 +396,7 @@ void HWCDC::flush(void) if(tx_ring_buf == NULL || tx_lock == NULL){ return; } - if(usb_serial_jtag_is_connected()) { + if(isCDC_Connected()) { tx_timeout_ms = requested_tx_timeout_ms; } else { isConnected = false; From a0eb4c0bedb55cf23da9186cad9bb81ba3c9285e Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Wed, 28 Feb 2024 16:34:02 -0300 Subject: [PATCH 3/6] 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. --- cores/esp32/HWCDC.h | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/cores/esp32/HWCDC.h b/cores/esp32/HWCDC.h index e54ad4da53c..fb02b3c7f86 100644 --- a/cores/esp32/HWCDC.h +++ b/cores/esp32/HWCDC.h @@ -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,7 +47,7 @@ class HWCDC: public Stream { private: static bool deinit(void * busptr); - static bool isCDC_Connected(); + bool isCDC_Connected(); public: HWCDC(); @@ -69,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 bool isPlugged(void) + { + return usb_serial_jtag_is_connected(); + } + + inline bool isConnected(void) + { + return isCDC_Connected(); + } + inline size_t read(char * buffer, size_t size) { return read((uint8_t*) buffer, size); From d7bca83e1f5691cb1b7f3ba897d2ff8a13ebbf52 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Wed, 28 Feb 2024 16:38:45 -0300 Subject: [PATCH 4/6] 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. --- .../examples/HWSerial_Events/HWSerial_Events.ino | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) 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]; } From 76e28e87a6711398d5d9a91fdc725996f4626e3c Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Wed, 28 Feb 2024 18:07:12 -0300 Subject: [PATCH 5/6] fixes api declaration --- cores/esp32/HWCDC.cpp | 84 +++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/cores/esp32/HWCDC.cpp b/cores/esp32/HWCDC.cpp index 6092bd1f810..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,44 +136,23 @@ static void hw_cdc_isr_handler(void *arg) { } } -static void ARDUINO_ISR_ATTR cdc0_write_char(char c) { - uint32_t tx_timeout_ms = 0; - if(isCDC_Connected()) { - tx_timeout_ms = requested_tx_timeout_ms; - } - if(xPortInIsrContext()){ - xRingbufferSendFromISR(tx_ring_buf, (void*) (&c), 1, NULL); - } else { - xRingbufferSend(tx_ring_buf, (void*) (&c), 1, tx_timeout_ms / portTICK_PERIOD_MS); - } - usb_serial_jtag_ll_txfifo_flush(); -} - -HWCDC::HWCDC() { - -} - -HWCDC::~HWCDC(){ - end(); -} - bool HWCDC::isCDC_Connected() { static bool running = false; // USB may be unplugged if (usb_serial_jtag_is_connected() == false) { - isConnected = false; + connected = false; running = false; return false; } - if (isConnected) { + if (connected) { running = false; return true; } - if (running == false && !isConnected) { // enables it only once! + 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 @@ -184,10 +163,31 @@ bool HWCDC::isCDC_Connected() return false; } +static void ARDUINO_ISR_ATTR cdc0_write_char(char c) { + uint32_t tx_timeout_ms = 0; + if(HWCDC::isConnected()) { + tx_timeout_ms = requested_tx_timeout_ms; + } + if(xPortInIsrContext()){ + xRingbufferSendFromISR(tx_ring_buf, (void*) (&c), 1, NULL); + } else { + xRingbufferSend(tx_ring_buf, (void*) (&c), 1, tx_timeout_ms / portTICK_PERIOD_MS); + } + usb_serial_jtag_ll_txfifo_flush(); +} + +HWCDC::HWCDC() { + +} + +HWCDC::~HWCDC(){ + end(); +} + // It should return just when USB is plugged and CDC is connected. HWCDC::operator bool() const { - return isCDC_Connected(); + return HWCDC::isCDC_Connected(); } void HWCDC::onEvent(esp_event_handler_t callback){ @@ -271,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){ @@ -303,7 +303,7 @@ int HWCDC::availableForWrite(void) if(tx_ring_buf == NULL || tx_lock == NULL){ return 0; } - if(isCDC_Connected()) { + if(HWCDC::isCDC_Connected()) { tx_timeout_ms = requested_tx_timeout_ms; } if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){ @@ -335,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(isCDC_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; @@ -358,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){ @@ -373,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); @@ -396,10 +396,10 @@ void HWCDC::flush(void) if(tx_ring_buf == NULL || tx_lock == NULL){ return; } - if(isCDC_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; @@ -409,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){ @@ -419,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); From e72d94565a6d1ad097f04d872c3976ce631b707a Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Wed, 28 Feb 2024 18:08:04 -0300 Subject: [PATCH 6/6] fixes API declaration --- cores/esp32/HWCDC.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cores/esp32/HWCDC.h b/cores/esp32/HWCDC.h index fb02b3c7f86..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. @@ -47,7 +47,7 @@ class HWCDC: public Stream { private: static bool deinit(void * busptr); - bool isCDC_Connected(); + static bool isCDC_Connected(); public: HWCDC(); @@ -71,12 +71,12 @@ class HWCDC: public Stream size_t write(const uint8_t *buffer, size_t size); void flush(void); - inline bool isPlugged(void) + inline static bool isPlugged(void) { return usb_serial_jtag_is_connected(); } - inline bool isConnected(void) + inline static bool isConnected(void) { return isCDC_Connected(); }