From 404fc94705ed7f395a9a7ba8328d2cead44437ad Mon Sep 17 00:00:00 2001 From: etagle Date: Thu, 15 Mar 2018 00:56:28 -0300 Subject: [PATCH] DUE USB CDC: Do not send any character if no program on the PC is listening to them. This avoids Marlin waiting until the user actually opens a program that is able to consume the output of Marlin --- .../src/HAL/HAL_DUE/MarlinSerialUSB_Due.cpp | 21 ++++++++++++++++++- Marlin/src/HAL/HAL_DUE/usb/udi_cdc.c | 4 ++-- Marlin/src/HAL/HAL_DUE/usb/usb_task.c | 12 +++++++++-- Marlin/src/HAL/HAL_DUE/usb/usb_task.h | 13 ++++++++++++ 4 files changed, 45 insertions(+), 5 deletions(-) diff --git a/Marlin/src/HAL/HAL_DUE/MarlinSerialUSB_Due.cpp b/Marlin/src/HAL/HAL_DUE/MarlinSerialUSB_Due.cpp index c773877375..dc8edf9a3a 100644 --- a/Marlin/src/HAL/HAL_DUE/MarlinSerialUSB_Due.cpp +++ b/Marlin/src/HAL/HAL_DUE/MarlinSerialUSB_Due.cpp @@ -36,6 +36,7 @@ // Imports from Atmel USB Stack/CDC implementation extern "C" { bool usb_task_cdc_isenabled(void); + bool usb_task_cdc_dtr_active(void); bool udi_cdc_is_rx_ready(void); int udi_cdc_getc(void); bool udi_cdc_is_tx_ready(void); @@ -56,9 +57,11 @@ int MarlinSerialUSB::peek(void) { if (pending_char >= 0) return pending_char; + // If USB CDC not enumerated or not configured on the PC side if (!usb_task_cdc_isenabled()) return -1; + // If no bytes sent from the PC if (!udi_cdc_is_rx_ready()) return -1; @@ -73,9 +76,11 @@ int MarlinSerialUSB::read(void) { return ret; } + // If USB CDC not enumerated or not configured on the PC side if (!usb_task_cdc_isenabled()) return -1; + // If no bytes sent from the PC if (!udi_cdc_is_rx_ready()) return -1; @@ -83,7 +88,10 @@ int MarlinSerialUSB::read(void) { } bool MarlinSerialUSB::available(void) { + /* If Pending chars */ return pending_char >= 0 || + /* or USB CDC enumerated and configured on the PC side and some + bytes where sent to us */ (usb_task_cdc_isenabled() && udi_cdc_is_rx_ready()); } @@ -92,11 +100,22 @@ void MarlinSerialUSB::flush(void) { void MarlinSerialUSB::write(const uint8_t c) { + /* Do not even bother sending anything if USB CDC is not enumerated + or not configured on the PC side or there is no program on the PC + listening to our messages */ + if (!usb_task_cdc_isenabled() || !usb_task_cdc_dtr_active()) + return; + + /* Wait until the PC has read the pending to be sent data */ while (usb_task_cdc_isenabled() && + usb_task_cdc_dtr_active() && !udi_cdc_is_tx_ready()) { }; - if (!usb_task_cdc_isenabled()) + /* Do not even bother sending anything if USB CDC is not enumerated + or not configured on the PC side or there is no program on the PC + listening to our messages at this point */ + if (!usb_task_cdc_isenabled() || !usb_task_cdc_dtr_active()) return; // Fifo full diff --git a/Marlin/src/HAL/HAL_DUE/usb/udi_cdc.c b/Marlin/src/HAL/HAL_DUE/usb/udi_cdc.c index f8ae82cf8b..c8ab19b4b3 100644 --- a/Marlin/src/HAL/HAL_DUE/usb/udi_cdc.c +++ b/Marlin/src/HAL/HAL_DUE/usb/udi_cdc.c @@ -1012,7 +1012,7 @@ iram_size_t udi_cdc_read_buf(void* buf, iram_size_t size) return udi_cdc_multi_read_buf(0, buf, size); } -iram_size_t udi_cdc_multi_get_free_tx_buffer(uint8_t port) +iram_size_t __attribute__((optimize("O0"))) udi_cdc_multi_get_free_tx_buffer(uint8_t port) { irqflags_t flags; iram_size_t buf_sel_nb, retval; @@ -1097,7 +1097,7 @@ int udi_cdc_putc(int value) return udi_cdc_multi_putc(0, value); } -iram_size_t udi_cdc_multi_write_buf(uint8_t port, const void* buf, iram_size_t size) +iram_size_t __attribute__((optimize("O0"))) udi_cdc_multi_write_buf(uint8_t port, const void* buf, iram_size_t size) { irqflags_t flags; uint8_t buf_sel; diff --git a/Marlin/src/HAL/HAL_DUE/usb/usb_task.c b/Marlin/src/HAL/HAL_DUE/usb/usb_task.c index bd004c9ca4..711cbf9640 100644 --- a/Marlin/src/HAL/HAL_DUE/usb/usb_task.c +++ b/Marlin/src/HAL/HAL_DUE/usb/usb_task.c @@ -52,6 +52,7 @@ static volatile bool main_b_msc_enable = false; static volatile bool main_b_cdc_enable = false; +static volatile bool main_b_dtr_active = false; void HAL_idletask(void) { // Attend SD card access from the USB MSD -- Prioritize access to improve speed @@ -69,7 +70,7 @@ void usb_task_msc_disable(void) { main_b_msc_enable = false; } bool usb_task_msc_isenabled(void) { return main_b_msc_enable; } bool usb_task_cdc_enable(const uint8_t port) { return ((main_b_cdc_enable = true)); } -void usb_task_cdc_disable(const uint8_t port) { main_b_cdc_enable = false; } +void usb_task_cdc_disable(const uint8_t port) { main_b_cdc_enable = false; main_b_dtr_active = false; } bool usb_task_cdc_isenabled(void) { return main_b_cdc_enable; } /*! \brief Called by CDC interface @@ -87,12 +88,17 @@ void usb_task_cdc_config(const uint8_t port, usb_cdc_line_coding_t *cfg) { dwDTERate = cfg->dwDTERate; } + void usb_task_cdc_set_dtr(const uint8_t port, const bool b_enable) { + + // Keep DTR status + main_b_dtr_active = b_enable; + // Implement Arduino-Compatible kludge to enter programming mode from // the native port: // "Auto-reset into the bootloader is triggered when the port, already // open at 1200 bps, is closed." - + if (1200 == dwDTERate) { // We check DTR state to determine if host port is open (bit 0 of lineState). if (!b_enable) @@ -102,6 +108,8 @@ void usb_task_cdc_set_dtr(const uint8_t port, const bool b_enable) { } } +bool usb_task_cdc_dtr_active(void) { return main_b_dtr_active; } + /// Microsoft WCID descriptor typedef struct USB_MicrosoftCompatibleDescriptor_Interface { uint8_t bFirstInterfaceNumber; diff --git a/Marlin/src/HAL/HAL_DUE/usb/usb_task.h b/Marlin/src/HAL/HAL_DUE/usb/usb_task.h index f535c9df7a..22328e6de4 100644 --- a/Marlin/src/HAL/HAL_DUE/usb/usb_task.h +++ b/Marlin/src/HAL/HAL_DUE/usb/usb_task.h @@ -78,6 +78,19 @@ void usb_task_cdc_disable(const uint8_t port); */ void usb_task_cdc_set_dtr(const uint8_t port, const bool b_enable); +/*! \brief Check if MSC is enumerated and configured on the PC side + */ +bool usb_task_msc_isenabled(void); + +/*! \brief Check if CDC is enumerated and configured on the PC side + */ +bool usb_task_cdc_isenabled(void); + +/*! \brief Check if CDC is actually OPEN by an application on the PC side + * assuming DTR signal means a program is listening to messages + */ +bool usb_task_cdc_dtr_active(void); + /*! \brief Called by UDC when USB Host request a extra string different * of this specified in USB device descriptor */