From 9d02cedfed0c68a4872cbfdb74d098b29a4cc547 Mon Sep 17 00:00:00 2001 From: Jason Smith Date: Thu, 24 Sep 2020 18:28:48 -0700 Subject: [PATCH] Fix and improve STM32F1 serial (#19464) --- Marlin/Configuration.h | 5 +- Marlin/Configuration_adv.h | 10 +- Marlin/src/HAL/AVR/HAL.h | 17 +- Marlin/src/HAL/AVR/MarlinSerial.cpp | 1340 ++++++++--------- Marlin/src/HAL/AVR/MarlinSerial.h | 71 +- Marlin/src/HAL/DUE/HAL.h | 12 +- Marlin/src/HAL/DUE/MarlinSerial.h | 2 + Marlin/src/HAL/LINUX/include/serial.h | 1 + Marlin/src/HAL/LPC1768/HAL.h | 12 +- Marlin/src/HAL/LPC1768/MarlinSerial.cpp | 8 +- Marlin/src/HAL/LPC1768/MarlinSerial.h | 1 + Marlin/src/HAL/LPC1768/inc/SanityCheck.h | 8 +- Marlin/src/HAL/LPC1768/usb_serial.cpp | 2 + Marlin/src/HAL/SAMD51/HAL.h | 12 +- Marlin/src/HAL/STM32/HAL.h | 16 +- Marlin/src/HAL/STM32/MarlinSerial.cpp | 4 +- Marlin/src/HAL/STM32/MarlinSerial.h | 4 + Marlin/src/HAL/STM32F1/HAL.h | 82 +- Marlin/src/HAL/STM32F1/MarlinSerial.cpp | 133 +- Marlin/src/HAL/STM32F1/MarlinSerial.h | 21 +- Marlin/src/HAL/STM32F1/msc_sd.h | 1 + Marlin/src/HAL/STM32_F4_F7/HAL.h | 16 +- Marlin/src/inc/Conditionals_adv.h | 34 + Marlin/src/inc/SanityCheck.h | 33 +- Marlin/src/lcd/extui/anycubic_chiron_lcd.cpp | 25 +- .../anycubic_i3mega/anycubic_i3mega_lcd.cpp | 18 +- Marlin/src/lcd/extui/lib/dgus/DGUSDisplay.cpp | 62 +- buildroot/tests/mks_robin_pro-tests | 1 + 28 files changed, 1009 insertions(+), 942 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 2635bc750e..93e2a0229a 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -2165,6 +2165,9 @@ // Touch-screen LCD for Malyan M200/M300 printers // //#define MALYAN_LCD +#if ENABLED(MALYAN_LCD) + #define LCD_SERIAL_PORT 1 // Default is 1 for Malyan M200 +#endif // // Touch UI for FTDI EVE (FT800/FT810) displays @@ -2178,7 +2181,7 @@ //#define ANYCUBIC_LCD_I3MEGA //#define ANYCUBIC_LCD_CHIRON #if EITHER(ANYCUBIC_LCD_I3MEGA, ANYCUBIC_LCD_CHIRON) - #define ANYCUBIC_LCD_SERIAL_PORT 3 + #define LCD_SERIAL_PORT 3 // Default is 3 for Anycubic //#define ANYCUBIC_LCD_DEBUG #endif diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 65cbd21a94..a8c9205538 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -1404,8 +1404,8 @@ // Additional options for DGUS / DWIN displays // #if HAS_DGUS_LCD - #define DGUS_SERIAL_PORT 3 - #define DGUS_BAUDRATE 115200 + #define LCD_SERIAL_PORT 3 + #define LCD_BAUDRATE 115200 #define DGUS_RX_BUFFER_SIZE 128 #define DGUS_TX_BUFFER_SIZE 48 @@ -3419,10 +3419,10 @@ #if ENABLED(PRUSA_MMU2) // Serial port used for communication with MMU2. - // For AVR enable the UART port used for the MMU. (e.g., internalSerial) + // For AVR enable the UART port used for the MMU. (e.g., mmuSerial) // For 32-bit boards check your HAL for available serial ports. (e.g., Serial2) - #define INTERNAL_SERIAL_PORT 2 - #define MMU2_SERIAL internalSerial + #define MMU2_SERIAL_PORT 2 + #define MMU2_SERIAL mmuSerial // Use hardware reset for MMU if a pin is defined for it //#define MMU2_RST_PIN 23 diff --git a/Marlin/src/HAL/AVR/HAL.h b/Marlin/src/HAL/AVR/HAL.h index af7e142679..41f1acd32f 100644 --- a/Marlin/src/HAL/AVR/HAL.h +++ b/Marlin/src/HAL/AVR/HAL.h @@ -96,19 +96,14 @@ typedef int8_t pin_t; #endif #endif -#ifdef DGUS_SERIAL_PORT - #if !WITHIN(DGUS_SERIAL_PORT, -1, 3) - #error "DGUS_SERIAL_PORT must be from -1 to 3. Please update your configuration." +#ifdef LCD_SERIAL_PORT + #if !WITHIN(LCD_SERIAL_PORT, -1, 3) + #error "LCD_SERIAL_PORT must be from -1 to 3. Please update your configuration." #endif - #define DGUS_SERIAL internalDgusSerial - #define DGUS_SERIAL_GET_TX_BUFFER_FREE DGUS_SERIAL.get_tx_buffer_free -#endif - -#ifdef ANYCUBIC_LCD_SERIAL_PORT - #if !WITHIN(ANYCUBIC_LCD_SERIAL_PORT, -1, 3) - #error "ANYCUBIC_LCD_SERIAL_PORT must be from -1 to 3. Please update your configuration." + #define LCD_SERIAL lcdSerial + #if HAS_DGUS_LCD + #define SERIAL_GET_TX_BUFFER_FREE() LCD_SERIAL.get_tx_buffer_free() #endif - #define ANYCUBIC_LCD_SERIAL anycubicLcdSerial #endif // ------------------------ diff --git a/Marlin/src/HAL/AVR/MarlinSerial.cpp b/Marlin/src/HAL/AVR/MarlinSerial.cpp index 838627001d..63599efd41 100644 --- a/Marlin/src/HAL/AVR/MarlinSerial.cpp +++ b/Marlin/src/HAL/AVR/MarlinSerial.cpp @@ -40,407 +40,370 @@ #if !defined(USBCON) && (defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(UBRR2H) || defined(UBRR3H)) - #include "MarlinSerial.h" - #include "../../MarlinCore.h" +#include "MarlinSerial.h" +#include "../../MarlinCore.h" + +#if ENABLED(DIRECT_STEPPING) + #include "../../feature/direct_stepping.h" +#endif + +template typename MarlinSerial::ring_buffer_r MarlinSerial::rx_buffer = { 0, 0, { 0 } }; +template typename MarlinSerial::ring_buffer_t MarlinSerial::tx_buffer = { 0 }; +template bool MarlinSerial::_written = false; +template uint8_t MarlinSerial::xon_xoff_state = MarlinSerial::XON_XOFF_CHAR_SENT | MarlinSerial::XON_CHAR; +template uint8_t MarlinSerial::rx_dropped_bytes = 0; +template uint8_t MarlinSerial::rx_buffer_overruns = 0; +template uint8_t MarlinSerial::rx_framing_errors = 0; +template typename MarlinSerial::ring_buffer_pos_t MarlinSerial::rx_max_enqueued = 0; + +// A SW memory barrier, to ensure GCC does not overoptimize loops +#define sw_barrier() asm volatile("": : :"memory"); + +#include "../../feature/e_parser.h" + +// "Atomically" read the RX head index value without disabling interrupts: +// This MUST be called with RX interrupts enabled, and CAN'T be called +// from the RX ISR itself! +template +FORCE_INLINE typename MarlinSerial::ring_buffer_pos_t MarlinSerial::atomic_read_rx_head() { + if (Cfg::RX_SIZE > 256) { + // Keep reading until 2 consecutive reads return the same value, + // meaning there was no update in-between caused by an interrupt. + // This works because serial RX interrupts happen at a slower rate + // than successive reads of a variable, so 2 consecutive reads with + // the same value means no interrupt updated it. + ring_buffer_pos_t vold, vnew = rx_buffer.head; + sw_barrier(); + do { + vold = vnew; + vnew = rx_buffer.head; + sw_barrier(); + } while (vold != vnew); + return vnew; + } + else { + // With an 8bit index, reads are always atomic. No need for special handling + return rx_buffer.head; + } +} + +template +volatile bool MarlinSerial::rx_tail_value_not_stable = false; +template +volatile uint16_t MarlinSerial::rx_tail_value_backup = 0; + +// Set RX tail index, taking into account the RX ISR could interrupt +// the write to this variable in the middle - So a backup strategy +// is used to ensure reads of the correct values. +// -Must NOT be called from the RX ISR - +template +FORCE_INLINE void MarlinSerial::atomic_set_rx_tail(typename MarlinSerial::ring_buffer_pos_t value) { + if (Cfg::RX_SIZE > 256) { + // Store the new value in the backup + rx_tail_value_backup = value; + sw_barrier(); + // Flag we are about to change the true value + rx_tail_value_not_stable = true; + sw_barrier(); + // Store the new value + rx_buffer.tail = value; + sw_barrier(); + // Signal the new value is completely stored into the value + rx_tail_value_not_stable = false; + sw_barrier(); + } + else + rx_buffer.tail = value; +} + +// Get the RX tail index, taking into account the read could be +// interrupting in the middle of the update of that index value +// -Called from the RX ISR - +template +FORCE_INLINE typename MarlinSerial::ring_buffer_pos_t MarlinSerial::atomic_read_rx_tail() { + if (Cfg::RX_SIZE > 256) { + // If the true index is being modified, return the backup value + if (rx_tail_value_not_stable) return rx_tail_value_backup; + } + // The true index is stable, return it + return rx_buffer.tail; +} + +// (called with RX interrupts disabled) +template +FORCE_INLINE void MarlinSerial::store_rxd_char() { + + static EmergencyParser::State emergency_state; // = EP_RESET + + // This must read the R_UCSRA register before reading the received byte to detect error causes + if (Cfg::DROPPED_RX && B_DOR && !++rx_dropped_bytes) --rx_dropped_bytes; + if (Cfg::RX_OVERRUNS && B_DOR && !++rx_buffer_overruns) --rx_buffer_overruns; + if (Cfg::RX_FRAMING_ERRORS && B_FE && !++rx_framing_errors) --rx_framing_errors; + + // Read the character from the USART + uint8_t c = R_UDR; #if ENABLED(DIRECT_STEPPING) - #include "../../feature/direct_stepping.h" + if (page_manager.maybe_store_rxd_char(c)) return; #endif - template typename MarlinSerial::ring_buffer_r MarlinSerial::rx_buffer = { 0, 0, { 0 } }; - template typename MarlinSerial::ring_buffer_t MarlinSerial::tx_buffer = { 0 }; - template bool MarlinSerial::_written = false; - template uint8_t MarlinSerial::xon_xoff_state = MarlinSerial::XON_XOFF_CHAR_SENT | MarlinSerial::XON_CHAR; - template uint8_t MarlinSerial::rx_dropped_bytes = 0; - template uint8_t MarlinSerial::rx_buffer_overruns = 0; - template uint8_t MarlinSerial::rx_framing_errors = 0; - template typename MarlinSerial::ring_buffer_pos_t MarlinSerial::rx_max_enqueued = 0; + // Get the tail - Nothing can alter its value while this ISR is executing, but there's + // a chance that this ISR interrupted the main process while it was updating the index. + // The backup mechanism ensures the correct value is always returned. + const ring_buffer_pos_t t = atomic_read_rx_tail(); - // A SW memory barrier, to ensure GCC does not overoptimize loops - #define sw_barrier() asm volatile("": : :"memory"); + // Get the head pointer - This ISR is the only one that modifies its value, so it's safe to read here + ring_buffer_pos_t h = rx_buffer.head; - #include "../../feature/e_parser.h" + // Get the next element + ring_buffer_pos_t i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1); - // "Atomically" read the RX head index value without disabling interrupts: - // This MUST be called with RX interrupts enabled, and CAN'T be called - // from the RX ISR itself! - template - FORCE_INLINE typename MarlinSerial::ring_buffer_pos_t MarlinSerial::atomic_read_rx_head() { - if (Cfg::RX_SIZE > 256) { - // Keep reading until 2 consecutive reads return the same value, - // meaning there was no update in-between caused by an interrupt. - // This works because serial RX interrupts happen at a slower rate - // than successive reads of a variable, so 2 consecutive reads with - // the same value means no interrupt updated it. - ring_buffer_pos_t vold, vnew = rx_buffer.head; - sw_barrier(); - do { - vold = vnew; - vnew = rx_buffer.head; - sw_barrier(); - } while (vold != vnew); - return vnew; - } - else { - // With an 8bit index, reads are always atomic. No need for special handling - return rx_buffer.head; - } + if (Cfg::EMERGENCYPARSER) emergency_parser.update(emergency_state, c); + + // If the character is to be stored at the index just before the tail + // (such that the head would advance to the current tail), the RX FIFO is + // full, so don't write the character or advance the head. + if (i != t) { + rx_buffer.buffer[h] = c; + h = i; + } + else if (Cfg::DROPPED_RX && !++rx_dropped_bytes) + --rx_dropped_bytes; + + if (Cfg::MAX_RX_QUEUED) { + // Calculate count of bytes stored into the RX buffer + const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1); + + // Keep track of the maximum count of enqueued bytes + NOLESS(rx_max_enqueued, rx_count); } - template - volatile bool MarlinSerial::rx_tail_value_not_stable = false; - template - volatile uint16_t MarlinSerial::rx_tail_value_backup = 0; + if (Cfg::XONOFF) { + // If the last char that was sent was an XON + if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XON_CHAR) { - // Set RX tail index, taking into account the RX ISR could interrupt - // the write to this variable in the middle - So a backup strategy - // is used to ensure reads of the correct values. - // -Must NOT be called from the RX ISR - - template - FORCE_INLINE void MarlinSerial::atomic_set_rx_tail(typename MarlinSerial::ring_buffer_pos_t value) { - if (Cfg::RX_SIZE > 256) { - // Store the new value in the backup - rx_tail_value_backup = value; - sw_barrier(); - // Flag we are about to change the true value - rx_tail_value_not_stable = true; - sw_barrier(); - // Store the new value - rx_buffer.tail = value; - sw_barrier(); - // Signal the new value is completely stored into the value - rx_tail_value_not_stable = false; - sw_barrier(); - } - else - rx_buffer.tail = value; - } - - // Get the RX tail index, taking into account the read could be - // interrupting in the middle of the update of that index value - // -Called from the RX ISR - - template - FORCE_INLINE typename MarlinSerial::ring_buffer_pos_t MarlinSerial::atomic_read_rx_tail() { - if (Cfg::RX_SIZE > 256) { - // If the true index is being modified, return the backup value - if (rx_tail_value_not_stable) return rx_tail_value_backup; - } - // The true index is stable, return it - return rx_buffer.tail; - } - - // (called with RX interrupts disabled) - template - FORCE_INLINE void MarlinSerial::store_rxd_char() { - - static EmergencyParser::State emergency_state; // = EP_RESET - - // This must read the R_UCSRA register before reading the received byte to detect error causes - if (Cfg::DROPPED_RX && B_DOR && !++rx_dropped_bytes) --rx_dropped_bytes; - if (Cfg::RX_OVERRUNS && B_DOR && !++rx_buffer_overruns) --rx_buffer_overruns; - if (Cfg::RX_FRAMING_ERRORS && B_FE && !++rx_framing_errors) --rx_framing_errors; - - // Read the character from the USART - uint8_t c = R_UDR; - - #if ENABLED(DIRECT_STEPPING) - if (page_manager.maybe_store_rxd_char(c)) return; - #endif - - // Get the tail - Nothing can alter its value while this ISR is executing, but there's - // a chance that this ISR interrupted the main process while it was updating the index. - // The backup mechanism ensures the correct value is always returned. - const ring_buffer_pos_t t = atomic_read_rx_tail(); - - // Get the head pointer - This ISR is the only one that modifies its value, so it's safe to read here - ring_buffer_pos_t h = rx_buffer.head; - - // Get the next element - ring_buffer_pos_t i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1); - - if (Cfg::EMERGENCYPARSER) emergency_parser.update(emergency_state, c); - - // If the character is to be stored at the index just before the tail - // (such that the head would advance to the current tail), the RX FIFO is - // full, so don't write the character or advance the head. - if (i != t) { - rx_buffer.buffer[h] = c; - h = i; - } - else if (Cfg::DROPPED_RX && !++rx_dropped_bytes) - --rx_dropped_bytes; - - if (Cfg::MAX_RX_QUEUED) { - // Calculate count of bytes stored into the RX buffer + // Bytes stored into the RX buffer const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1); - // Keep track of the maximum count of enqueued bytes - NOLESS(rx_max_enqueued, rx_count); - } + // If over 12.5% of RX buffer capacity, send XOFF before running out of + // RX buffer space .. 325 bytes @ 250kbits/s needed to let the host react + // and stop sending bytes. This translates to 13mS propagation time. + if (rx_count >= (Cfg::RX_SIZE) / 8) { - if (Cfg::XONOFF) { - // If the last char that was sent was an XON - if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XON_CHAR) { + // At this point, definitely no TX interrupt was executing, since the TX ISR can't be preempted. + // Don't enable the TX interrupt here as a means to trigger the XOFF char, because if it happens + // to be in the middle of trying to disable the RX interrupt in the main program, eventually the + // enabling of the TX interrupt could be undone. The ONLY reliable thing this can do to ensure + // the sending of the XOFF char is to send it HERE AND NOW. - // Bytes stored into the RX buffer - const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1); + // About to send the XOFF char + xon_xoff_state = XOFF_CHAR | XON_XOFF_CHAR_SENT; - // If over 12.5% of RX buffer capacity, send XOFF before running out of - // RX buffer space .. 325 bytes @ 250kbits/s needed to let the host react - // and stop sending bytes. This translates to 13mS propagation time. - if (rx_count >= (Cfg::RX_SIZE) / 8) { + // Wait until the TX register becomes empty and send it - Here there could be a problem + // - While waiting for the TX register to empty, the RX register could receive a new + // character. This must also handle that situation! + while (!B_UDRE) { - // At this point, definitely no TX interrupt was executing, since the TX ISR can't be preempted. - // Don't enable the TX interrupt here as a means to trigger the XOFF char, because if it happens - // to be in the middle of trying to disable the RX interrupt in the main program, eventually the - // enabling of the TX interrupt could be undone. The ONLY reliable thing this can do to ensure - // the sending of the XOFF char is to send it HERE AND NOW. + if (B_RXC) { + // A char arrived while waiting for the TX buffer to be empty - Receive and process it! - // About to send the XOFF char - xon_xoff_state = XOFF_CHAR | XON_XOFF_CHAR_SENT; + i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1); - // Wait until the TX register becomes empty and send it - Here there could be a problem - // - While waiting for the TX register to empty, the RX register could receive a new - // character. This must also handle that situation! - while (!B_UDRE) { + // Read the character from the USART + c = R_UDR; - if (B_RXC) { - // A char arrived while waiting for the TX buffer to be empty - Receive and process it! + if (Cfg::EMERGENCYPARSER) emergency_parser.update(emergency_state, c); - i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1); - - // Read the character from the USART - c = R_UDR; - - if (Cfg::EMERGENCYPARSER) emergency_parser.update(emergency_state, c); - - // If the character is to be stored at the index just before the tail - // (such that the head would advance to the current tail), the FIFO is - // full, so don't write the character or advance the head. - if (i != t) { - rx_buffer.buffer[h] = c; - h = i; - } - else if (Cfg::DROPPED_RX && !++rx_dropped_bytes) - --rx_dropped_bytes; + // If the character is to be stored at the index just before the tail + // (such that the head would advance to the current tail), the FIFO is + // full, so don't write the character or advance the head. + if (i != t) { + rx_buffer.buffer[h] = c; + h = i; } - sw_barrier(); + else if (Cfg::DROPPED_RX && !++rx_dropped_bytes) + --rx_dropped_bytes; } - - R_UDR = XOFF_CHAR; - - // Clear the TXC bit -- "can be cleared by writing a one to its bit - // location". This makes sure flush() won't return until the bytes - // actually got written - B_TXC = 1; - - // At this point there could be a race condition between the write() function - // and this sending of the XOFF char. This interrupt could happen between the - // wait to be empty TX buffer loop and the actual write of the character. Since - // the TX buffer is full because it's sending the XOFF char, the only way to be - // sure the write() function will succeed is to wait for the XOFF char to be - // completely sent. Since an extra character could be received during the wait - // it must also be handled! - while (!B_UDRE) { - - if (B_RXC) { - // A char arrived while waiting for the TX buffer to be empty - Receive and process it! - - i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1); - - // Read the character from the USART - c = R_UDR; - - if (Cfg::EMERGENCYPARSER) - emergency_parser.update(emergency_state, c); - - // If the character is to be stored at the index just before the tail - // (such that the head would advance to the current tail), the FIFO is - // full, so don't write the character or advance the head. - if (i != t) { - rx_buffer.buffer[h] = c; - h = i; - } - else if (Cfg::DROPPED_RX && !++rx_dropped_bytes) - --rx_dropped_bytes; - } - sw_barrier(); - } - - // At this point everything is ready. The write() function won't - // have any issues writing to the UART TX register if it needs to! + sw_barrier(); } + + R_UDR = XOFF_CHAR; + + // Clear the TXC bit -- "can be cleared by writing a one to its bit + // location". This makes sure flush() won't return until the bytes + // actually got written + B_TXC = 1; + + // At this point there could be a race condition between the write() function + // and this sending of the XOFF char. This interrupt could happen between the + // wait to be empty TX buffer loop and the actual write of the character. Since + // the TX buffer is full because it's sending the XOFF char, the only way to be + // sure the write() function will succeed is to wait for the XOFF char to be + // completely sent. Since an extra character could be received during the wait + // it must also be handled! + while (!B_UDRE) { + + if (B_RXC) { + // A char arrived while waiting for the TX buffer to be empty - Receive and process it! + + i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1); + + // Read the character from the USART + c = R_UDR; + + if (Cfg::EMERGENCYPARSER) + emergency_parser.update(emergency_state, c); + + // If the character is to be stored at the index just before the tail + // (such that the head would advance to the current tail), the FIFO is + // full, so don't write the character or advance the head. + if (i != t) { + rx_buffer.buffer[h] = c; + h = i; + } + else if (Cfg::DROPPED_RX && !++rx_dropped_bytes) + --rx_dropped_bytes; + } + sw_barrier(); + } + + // At this point everything is ready. The write() function won't + // have any issues writing to the UART TX register if it needs to! } } - - // Store the new head value - The main loop will retry until the value is stable - rx_buffer.head = h; } - // (called with TX irqs disabled) - template - FORCE_INLINE void MarlinSerial::_tx_udr_empty_irq() { - if (Cfg::TX_SIZE > 0) { - // Read positions - uint8_t t = tx_buffer.tail; - const uint8_t h = tx_buffer.head; + // Store the new head value - The main loop will retry until the value is stable + rx_buffer.head = h; +} - if (Cfg::XONOFF) { - // If an XON char is pending to be sent, do it now - if (xon_xoff_state == XON_CHAR) { +// (called with TX irqs disabled) +template +FORCE_INLINE void MarlinSerial::_tx_udr_empty_irq() { + if (Cfg::TX_SIZE > 0) { + // Read positions + uint8_t t = tx_buffer.tail; + const uint8_t h = tx_buffer.head; - // Send the character - R_UDR = XON_CHAR; + if (Cfg::XONOFF) { + // If an XON char is pending to be sent, do it now + if (xon_xoff_state == XON_CHAR) { - // clear the TXC bit -- "can be cleared by writing a one to its bit - // location". This makes sure flush() won't return until the bytes - // actually got written - B_TXC = 1; + // Send the character + R_UDR = XON_CHAR; - // Remember we sent it. - xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT; + // clear the TXC bit -- "can be cleared by writing a one to its bit + // location". This makes sure flush() won't return until the bytes + // actually got written + B_TXC = 1; - // If nothing else to transmit, just disable TX interrupts. - if (h == t) B_UDRIE = 0; // (Non-atomic, could be reenabled by the main program, but eventually this will succeed) + // Remember we sent it. + xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT; - return; - } - } + // If nothing else to transmit, just disable TX interrupts. + if (h == t) B_UDRIE = 0; // (Non-atomic, could be reenabled by the main program, but eventually this will succeed) - // If nothing to transmit, just disable TX interrupts. This could - // happen as the result of the non atomicity of the disabling of RX - // interrupts that could end reenabling TX interrupts as a side effect. - if (h == t) { - B_UDRIE = 0; // (Non-atomic, could be reenabled by the main program, but eventually this will succeed) return; } - - // There is something to TX, Send the next byte - const uint8_t c = tx_buffer.buffer[t]; - t = (t + 1) & (Cfg::TX_SIZE - 1); - R_UDR = c; - tx_buffer.tail = t; - - // Clear the TXC bit (by writing a one to its bit location). - // Ensures flush() won't return until the bytes are actually written/ - B_TXC = 1; - - // Disable interrupts if there is nothing to transmit following this byte - if (h == t) B_UDRIE = 0; // (Non-atomic, could be reenabled by the main program, but eventually this will succeed) - } - } - - // Public Methods - template - void MarlinSerial::begin(const long baud) { - uint16_t baud_setting; - bool useU2X = true; - - #if F_CPU == 16000000UL && SERIAL_PORT == 0 - // Hard-coded exception for compatibility with the bootloader shipped - // with the Duemilanove and previous boards, and the firmware on the - // 8U2 on the Uno and Mega 2560. - if (baud == 57600) useU2X = false; - #endif - - R_UCSRA = 0; - if (useU2X) { - B_U2X = 1; - baud_setting = (F_CPU / 4 / baud - 1) / 2; - } - else - baud_setting = (F_CPU / 8 / baud - 1) / 2; - - // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register) - R_UBRRH = baud_setting >> 8; - R_UBRRL = baud_setting; - - B_RXEN = 1; - B_TXEN = 1; - B_RXCIE = 1; - if (Cfg::TX_SIZE > 0) B_UDRIE = 0; - _written = false; - } - - template - void MarlinSerial::end() { - B_RXEN = 0; - B_TXEN = 0; - B_RXCIE = 0; - B_UDRIE = 0; - } - - template - int MarlinSerial::peek() { - const ring_buffer_pos_t h = atomic_read_rx_head(), t = rx_buffer.tail; - return h == t ? -1 : rx_buffer.buffer[t]; - } - - template - int MarlinSerial::read() { - const ring_buffer_pos_t h = atomic_read_rx_head(); - - // Read the tail. Main thread owns it, so it is safe to directly read it - ring_buffer_pos_t t = rx_buffer.tail; - - // If nothing to read, return now - if (h == t) return -1; - - // Get the next char - const int v = rx_buffer.buffer[t]; - t = (ring_buffer_pos_t)(t + 1) & (Cfg::RX_SIZE - 1); - - // Advance tail - Making sure the RX ISR will always get an stable value, even - // if it interrupts the writing of the value of that variable in the middle. - atomic_set_rx_tail(t); - - if (Cfg::XONOFF) { - // If the XOFF char was sent, or about to be sent... - if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) { - // Get count of bytes in the RX buffer - const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1); - if (rx_count < (Cfg::RX_SIZE) / 10) { - if (Cfg::TX_SIZE > 0) { - // Signal we want an XON character to be sent. - xon_xoff_state = XON_CHAR; - // Enable TX ISR. Non atomic, but it will eventually enable them - B_UDRIE = 1; - } - else { - // If not using TX interrupts, we must send the XON char now - xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT; - while (!B_UDRE) sw_barrier(); - R_UDR = XON_CHAR; - } - } - } } - return v; + // If nothing to transmit, just disable TX interrupts. This could + // happen as the result of the non atomicity of the disabling of RX + // interrupts that could end reenabling TX interrupts as a side effect. + if (h == t) { + B_UDRIE = 0; // (Non-atomic, could be reenabled by the main program, but eventually this will succeed) + return; + } + + // There is something to TX, Send the next byte + const uint8_t c = tx_buffer.buffer[t]; + t = (t + 1) & (Cfg::TX_SIZE - 1); + R_UDR = c; + tx_buffer.tail = t; + + // Clear the TXC bit (by writing a one to its bit location). + // Ensures flush() won't return until the bytes are actually written/ + B_TXC = 1; + + // Disable interrupts if there is nothing to transmit following this byte + if (h == t) B_UDRIE = 0; // (Non-atomic, could be reenabled by the main program, but eventually this will succeed) } +} - template - typename MarlinSerial::ring_buffer_pos_t MarlinSerial::available() { - const ring_buffer_pos_t h = atomic_read_rx_head(), t = rx_buffer.tail; - return (ring_buffer_pos_t)(Cfg::RX_SIZE + h - t) & (Cfg::RX_SIZE - 1); +// Public Methods +template +void MarlinSerial::begin(const long baud) { + uint16_t baud_setting; + bool useU2X = true; + + #if F_CPU == 16000000UL && SERIAL_PORT == 0 + // Hard-coded exception for compatibility with the bootloader shipped + // with the Duemilanove and previous boards, and the firmware on the + // 8U2 on the Uno and Mega 2560. + if (baud == 57600) useU2X = false; + #endif + + R_UCSRA = 0; + if (useU2X) { + B_U2X = 1; + baud_setting = (F_CPU / 4 / baud - 1) / 2; } + else + baud_setting = (F_CPU / 8 / baud - 1) / 2; - template - void MarlinSerial::flush() { + // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register) + R_UBRRH = baud_setting >> 8; + R_UBRRL = baud_setting; - // Set the tail to the head: - // - Read the RX head index in a safe way. (See atomic_read_rx_head.) - // - Set the tail, making sure the RX ISR will always get a stable value, even - // if it interrupts the writing of the value of that variable in the middle. - atomic_set_rx_tail(atomic_read_rx_head()); + B_RXEN = 1; + B_TXEN = 1; + B_RXCIE = 1; + if (Cfg::TX_SIZE > 0) B_UDRIE = 0; + _written = false; +} - if (Cfg::XONOFF) { - // If the XOFF char was sent, or about to be sent... - if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) { +template +void MarlinSerial::end() { + B_RXEN = 0; + B_TXEN = 0; + B_RXCIE = 0; + B_UDRIE = 0; +} + +template +int MarlinSerial::peek() { + const ring_buffer_pos_t h = atomic_read_rx_head(), t = rx_buffer.tail; + return h == t ? -1 : rx_buffer.buffer[t]; +} + +template +int MarlinSerial::read() { + const ring_buffer_pos_t h = atomic_read_rx_head(); + + // Read the tail. Main thread owns it, so it is safe to directly read it + ring_buffer_pos_t t = rx_buffer.tail; + + // If nothing to read, return now + if (h == t) return -1; + + // Get the next char + const int v = rx_buffer.buffer[t]; + t = (ring_buffer_pos_t)(t + 1) & (Cfg::RX_SIZE - 1); + + // Advance tail - Making sure the RX ISR will always get an stable value, even + // if it interrupts the writing of the value of that variable in the middle. + atomic_set_rx_tail(t); + + if (Cfg::XONOFF) { + // If the XOFF char was sent, or about to be sent... + if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) { + // Get count of bytes in the RX buffer + const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1); + if (rx_count < (Cfg::RX_SIZE) / 10) { if (Cfg::TX_SIZE > 0) { // Signal we want an XON character to be sent. xon_xoff_state = XON_CHAR; - // Enable TX ISR. Non atomic, but it will eventually enable it. + // Enable TX ISR. Non atomic, but it will eventually enable them B_UDRIE = 1; } else { @@ -453,363 +416,384 @@ } } - template - void MarlinSerial::write(const uint8_t c) { - if (Cfg::TX_SIZE == 0) { + return v; +} - _written = true; - while (!B_UDRE) sw_barrier(); +template +typename MarlinSerial::ring_buffer_pos_t MarlinSerial::available() { + const ring_buffer_pos_t h = atomic_read_rx_head(), t = rx_buffer.tail; + return (ring_buffer_pos_t)(Cfg::RX_SIZE + h - t) & (Cfg::RX_SIZE - 1); +} + +template +void MarlinSerial::flush() { + + // Set the tail to the head: + // - Read the RX head index in a safe way. (See atomic_read_rx_head.) + // - Set the tail, making sure the RX ISR will always get a stable value, even + // if it interrupts the writing of the value of that variable in the middle. + atomic_set_rx_tail(atomic_read_rx_head()); + + if (Cfg::XONOFF) { + // If the XOFF char was sent, or about to be sent... + if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) { + if (Cfg::TX_SIZE > 0) { + // Signal we want an XON character to be sent. + xon_xoff_state = XON_CHAR; + // Enable TX ISR. Non atomic, but it will eventually enable it. + B_UDRIE = 1; + } + else { + // If not using TX interrupts, we must send the XON char now + xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT; + while (!B_UDRE) sw_barrier(); + R_UDR = XON_CHAR; + } + } + } +} + +template +void MarlinSerial::write(const uint8_t c) { + if (Cfg::TX_SIZE == 0) { + + _written = true; + while (!B_UDRE) sw_barrier(); + R_UDR = c; + + } + else { + + _written = true; + + // If the TX interrupts are disabled and the data register + // is empty, just write the byte to the data register and + // be done. This shortcut helps significantly improve the + // effective datarate at high (>500kbit/s) bitrates, where + // interrupt overhead becomes a slowdown. + // Yes, there is a race condition between the sending of the + // XOFF char at the RX ISR, but it is properly handled there + if (!B_UDRIE && B_UDRE) { R_UDR = c; + // clear the TXC bit -- "can be cleared by writing a one to its bit + // location". This makes sure flush() won't return until the bytes + // actually got written + B_TXC = 1; + return; + } + + const uint8_t i = (tx_buffer.head + 1) & (Cfg::TX_SIZE - 1); + + // If global interrupts are disabled (as the result of being called from an ISR)... + if (!ISRS_ENABLED()) { + + // Make room by polling if it is possible to transmit, and do so! + while (i == tx_buffer.tail) { + + // If we can transmit another byte, do it. + if (B_UDRE) _tx_udr_empty_irq(); + + // Make sure compiler rereads tx_buffer.tail + sw_barrier(); + } } else { - - _written = true; - - // If the TX interrupts are disabled and the data register - // is empty, just write the byte to the data register and - // be done. This shortcut helps significantly improve the - // effective datarate at high (>500kbit/s) bitrates, where - // interrupt overhead becomes a slowdown. - // Yes, there is a race condition between the sending of the - // XOFF char at the RX ISR, but it is properly handled there - if (!B_UDRIE && B_UDRE) { - R_UDR = c; - - // clear the TXC bit -- "can be cleared by writing a one to its bit - // location". This makes sure flush() won't return until the bytes - // actually got written - B_TXC = 1; - return; - } - - const uint8_t i = (tx_buffer.head + 1) & (Cfg::TX_SIZE - 1); - - // If global interrupts are disabled (as the result of being called from an ISR)... - if (!ISRS_ENABLED()) { - - // Make room by polling if it is possible to transmit, and do so! - while (i == tx_buffer.tail) { - - // If we can transmit another byte, do it. - if (B_UDRE) _tx_udr_empty_irq(); - - // Make sure compiler rereads tx_buffer.tail - sw_barrier(); - } - } - else { - // Interrupts are enabled, just wait until there is space - while (i == tx_buffer.tail) sw_barrier(); - } - - // Store new char. head is always safe to move - tx_buffer.buffer[tx_buffer.head] = c; - tx_buffer.head = i; - - // Enable TX ISR - Non atomic, but it will eventually enable TX ISR - B_UDRIE = 1; + // Interrupts are enabled, just wait until there is space + while (i == tx_buffer.tail) sw_barrier(); } + + // Store new char. head is always safe to move + tx_buffer.buffer[tx_buffer.head] = c; + tx_buffer.head = i; + + // Enable TX ISR - Non atomic, but it will eventually enable TX ISR + B_UDRIE = 1; } +} - template - void MarlinSerial::flushTX() { +template +void MarlinSerial::flushTX() { - if (Cfg::TX_SIZE == 0) { - // No bytes written, no need to flush. This special case is needed since there's - // no way to force the TXC (transmit complete) bit to 1 during initialization. - if (!_written) return; + if (Cfg::TX_SIZE == 0) { + // No bytes written, no need to flush. This special case is needed since there's + // no way to force the TXC (transmit complete) bit to 1 during initialization. + if (!_written) return; + // Wait until everything was transmitted + while (!B_TXC) sw_barrier(); + + // At this point nothing is queued anymore (DRIE is disabled) and + // the hardware finished transmission (TXC is set). + + } + else { + + // No bytes written, no need to flush. This special case is needed since there's + // no way to force the TXC (transmit complete) bit to 1 during initialization. + if (!_written) return; + + // If global interrupts are disabled (as the result of being called from an ISR)... + if (!ISRS_ENABLED()) { + + // Wait until everything was transmitted - We must do polling, as interrupts are disabled + while (tx_buffer.head != tx_buffer.tail || !B_TXC) { + + // If there is more space, send an extra character + if (B_UDRE) _tx_udr_empty_irq(); + + sw_barrier(); + } + + } + else { // Wait until everything was transmitted - while (!B_TXC) sw_barrier(); - - // At this point nothing is queued anymore (DRIE is disabled) and - // the hardware finished transmission (TXC is set). - - } - else { - - // No bytes written, no need to flush. This special case is needed since there's - // no way to force the TXC (transmit complete) bit to 1 during initialization. - if (!_written) return; - - // If global interrupts are disabled (as the result of being called from an ISR)... - if (!ISRS_ENABLED()) { - - // Wait until everything was transmitted - We must do polling, as interrupts are disabled - while (tx_buffer.head != tx_buffer.tail || !B_TXC) { - - // If there is more space, send an extra character - if (B_UDRE) _tx_udr_empty_irq(); - - sw_barrier(); - } - - } - else { - // Wait until everything was transmitted - while (tx_buffer.head != tx_buffer.tail || !B_TXC) sw_barrier(); - } - - // At this point nothing is queued anymore (DRIE is disabled) and - // the hardware finished transmission (TXC is set). - } - } - - /** - * Imports from print.h - */ - - template - void MarlinSerial::print(char c, int base) { - print((long)c, base); - } - - template - void MarlinSerial::print(unsigned char b, int base) { - print((unsigned long)b, base); - } - - template - void MarlinSerial::print(int n, int base) { - print((long)n, base); - } - - template - void MarlinSerial::print(unsigned int n, int base) { - print((unsigned long)n, base); - } - - template - void MarlinSerial::print(long n, int base) { - if (base == 0) write(n); - else if (base == 10) { - if (n < 0) { print('-'); n = -n; } - printNumber(n, 10); - } - else - printNumber(n, base); - } - - template - void MarlinSerial::print(unsigned long n, int base) { - if (base == 0) write(n); - else printNumber(n, base); - } - - template - void MarlinSerial::print(double n, int digits) { - printFloat(n, digits); - } - - template - void MarlinSerial::println() { - print('\r'); - print('\n'); - } - - template - void MarlinSerial::println(const String& s) { - print(s); - println(); - } - - template - void MarlinSerial::println(const char c[]) { - print(c); - println(); - } - - template - void MarlinSerial::println(char c, int base) { - print(c, base); - println(); - } - - template - void MarlinSerial::println(unsigned char b, int base) { - print(b, base); - println(); - } - - template - void MarlinSerial::println(int n, int base) { - print(n, base); - println(); - } - - template - void MarlinSerial::println(unsigned int n, int base) { - print(n, base); - println(); - } - - template - void MarlinSerial::println(long n, int base) { - print(n, base); - println(); - } - - template - void MarlinSerial::println(unsigned long n, int base) { - print(n, base); - println(); - } - - template - void MarlinSerial::println(double n, int digits) { - print(n, digits); - println(); - } - - // Private Methods - - template - void MarlinSerial::printNumber(unsigned long n, uint8_t base) { - if (n) { - unsigned char buf[8 * sizeof(long)]; // Enough space for base 2 - int8_t i = 0; - while (n) { - buf[i++] = n % base; - n /= base; - } - while (i--) - print((char)(buf[i] + (buf[i] < 10 ? '0' : 'A' - 10))); - } - else - print('0'); - } - - template - void MarlinSerial::printFloat(double number, uint8_t digits) { - // Handle negative numbers - if (number < 0.0) { - print('-'); - number = -number; + while (tx_buffer.head != tx_buffer.tail || !B_TXC) sw_barrier(); } - // Round correctly so that print(1.999, 2) prints as "2.00" - double rounding = 0.5; - LOOP_L_N(i, digits) rounding *= 0.1; - number += rounding; + // At this point nothing is queued anymore (DRIE is disabled) and + // the hardware finished transmission (TXC is set). + } +} - // Extract the integer part of the number and print it - unsigned long int_part = (unsigned long)number; - double remainder = number - (double)int_part; - print(int_part); +/** + * Imports from print.h + */ - // Print the decimal point, but only if there are digits beyond - if (digits) { - print('.'); - // Extract digits from the remainder one at a time - while (digits--) { - remainder *= 10.0; - int toPrint = int(remainder); - print(toPrint); - remainder -= toPrint; - } +template +void MarlinSerial::print(char c, int base) { + print((long)c, base); +} + +template +void MarlinSerial::print(unsigned char b, int base) { + print((unsigned long)b, base); +} + +template +void MarlinSerial::print(int n, int base) { + print((long)n, base); +} + +template +void MarlinSerial::print(unsigned int n, int base) { + print((unsigned long)n, base); +} + +template +void MarlinSerial::print(long n, int base) { + if (base == 0) write(n); + else if (base == 10) { + if (n < 0) { print('-'); n = -n; } + printNumber(n, 10); + } + else + printNumber(n, base); +} + +template +void MarlinSerial::print(unsigned long n, int base) { + if (base == 0) write(n); + else printNumber(n, base); +} + +template +void MarlinSerial::print(double n, int digits) { + printFloat(n, digits); +} + +template +void MarlinSerial::println() { + print('\r'); + print('\n'); +} + +template +void MarlinSerial::println(const String& s) { + print(s); + println(); +} + +template +void MarlinSerial::println(const char c[]) { + print(c); + println(); +} + +template +void MarlinSerial::println(char c, int base) { + print(c, base); + println(); +} + +template +void MarlinSerial::println(unsigned char b, int base) { + print(b, base); + println(); +} + +template +void MarlinSerial::println(int n, int base) { + print(n, base); + println(); +} + +template +void MarlinSerial::println(unsigned int n, int base) { + print(n, base); + println(); +} + +template +void MarlinSerial::println(long n, int base) { + print(n, base); + println(); +} + +template +void MarlinSerial::println(unsigned long n, int base) { + print(n, base); + println(); +} + +template +void MarlinSerial::println(double n, int digits) { + print(n, digits); + println(); +} + +// Private Methods + +template +void MarlinSerial::printNumber(unsigned long n, uint8_t base) { + if (n) { + unsigned char buf[8 * sizeof(long)]; // Enough space for base 2 + int8_t i = 0; + while (n) { + buf[i++] = n % base; + n /= base; + } + while (i--) + print((char)(buf[i] + (buf[i] < 10 ? '0' : 'A' - 10))); + } + else + print('0'); +} + +template +void MarlinSerial::printFloat(double number, uint8_t digits) { + // Handle negative numbers + if (number < 0.0) { + print('-'); + number = -number; + } + + // Round correctly so that print(1.999, 2) prints as "2.00" + double rounding = 0.5; + LOOP_L_N(i, digits) rounding *= 0.1; + number += rounding; + + // Extract the integer part of the number and print it + unsigned long int_part = (unsigned long)number; + double remainder = number - (double)int_part; + print(int_part); + + // Print the decimal point, but only if there are digits beyond + if (digits) { + print('.'); + // Extract digits from the remainder one at a time + while (digits--) { + remainder *= 10.0; + int toPrint = int(remainder); + print(toPrint); + remainder -= toPrint; } } +} + +// Hookup ISR handlers +ISR(SERIAL_REGNAME(USART, SERIAL_PORT, _RX_vect)) { + MarlinSerial>::store_rxd_char(); +} + +ISR(SERIAL_REGNAME(USART, SERIAL_PORT, _UDRE_vect)) { + MarlinSerial>::_tx_udr_empty_irq(); +} + +// Preinstantiate +template class MarlinSerial>; + +// Instantiate +MarlinSerial> customizedSerial1; + +#ifdef SERIAL_PORT_2 // Hookup ISR handlers - ISR(SERIAL_REGNAME(USART, SERIAL_PORT, _RX_vect)) { - MarlinSerial>::store_rxd_char(); + ISR(SERIAL_REGNAME(USART, SERIAL_PORT_2, _RX_vect)) { + MarlinSerial>::store_rxd_char(); } - ISR(SERIAL_REGNAME(USART, SERIAL_PORT, _UDRE_vect)) { - MarlinSerial>::_tx_udr_empty_irq(); + ISR(SERIAL_REGNAME(USART, SERIAL_PORT_2, _UDRE_vect)) { + MarlinSerial>::_tx_udr_empty_irq(); } // Preinstantiate - template class MarlinSerial>; + template class MarlinSerial>; // Instantiate - MarlinSerial> customizedSerial1; + MarlinSerial> customizedSerial2; - #ifdef SERIAL_PORT_2 +#endif - // Hookup ISR handlers - ISR(SERIAL_REGNAME(USART, SERIAL_PORT_2, _RX_vect)) { - MarlinSerial>::store_rxd_char(); +#ifdef MMU2_SERIAL_PORT + + ISR(SERIAL_REGNAME(USART, MMU2_SERIAL_PORT, _RX_vect)) { + MarlinSerial>::store_rxd_char(); + } + + ISR(SERIAL_REGNAME(USART, MMU2_SERIAL_PORT, _UDRE_vect)) { + MarlinSerial>::_tx_udr_empty_irq(); + } + + // Preinstantiate + template class MarlinSerial>; + + // Instantiate + MarlinSerial> mmuSerial; + +#endif + +#ifdef LCD_SERIAL_PORT + + ISR(SERIAL_REGNAME(USART, LCD_SERIAL_PORT, _RX_vect)) { + MarlinSerial>::store_rxd_char(); + } + + ISR(SERIAL_REGNAME(USART, LCD_SERIAL_PORT, _UDRE_vect)) { + MarlinSerial>::_tx_udr_empty_irq(); + } + + // Preinstantiate + template class MarlinSerial>; + + // Instantiate + MarlinSerial> lcdSerial; + + #if HAS_DGUS_LCD + template + typename MarlinSerial::ring_buffer_pos_t MarlinSerial::get_tx_buffer_free() { + const ring_buffer_pos_t t = tx_buffer.tail, // next byte to send. + h = tx_buffer.head; // next pos for queue. + int ret = t - h - 1; + if (ret < 0) ret += Cfg::TX_SIZE + 1; + return ret; } - - ISR(SERIAL_REGNAME(USART, SERIAL_PORT_2, _UDRE_vect)) { - MarlinSerial>::_tx_udr_empty_irq(); - } - - // Preinstantiate - template class MarlinSerial>; - - // Instantiate - MarlinSerial> customizedSerial2; - #endif +#endif + #endif // !USBCON && (UBRRH || UBRR0H || UBRR1H || UBRR2H || UBRR3H) -#ifdef INTERNAL_SERIAL_PORT - - ISR(SERIAL_REGNAME(USART, INTERNAL_SERIAL_PORT, _RX_vect)) { - MarlinSerial>::store_rxd_char(); - } - - ISR(SERIAL_REGNAME(USART, INTERNAL_SERIAL_PORT, _UDRE_vect)) { - MarlinSerial>::_tx_udr_empty_irq(); - } - - // Preinstantiate - template class MarlinSerial>; - - // Instantiate - MarlinSerial> internalSerial; - -#endif - -#ifdef DGUS_SERIAL_PORT - - template - typename MarlinSerial::ring_buffer_pos_t MarlinSerial::get_tx_buffer_free() { - const ring_buffer_pos_t t = tx_buffer.tail, // next byte to send. - h = tx_buffer.head; // next pos for queue. - int ret = t - h - 1; - if (ret < 0) ret += Cfg::TX_SIZE + 1; - return ret; - } - - ISR(SERIAL_REGNAME(USART, DGUS_SERIAL_PORT, _RX_vect)) { - MarlinSerial>::store_rxd_char(); - } - - ISR(SERIAL_REGNAME(USART, DGUS_SERIAL_PORT, _UDRE_vect)) { - MarlinSerial>::_tx_udr_empty_irq(); - } - - // Preinstantiate - template class MarlinSerial>; - - // Instantiate - MarlinSerial> internalDgusSerial; - -#endif - -#ifdef ANYCUBIC_LCD_SERIAL_PORT - - ISR(SERIAL_REGNAME(USART, ANYCUBIC_LCD_SERIAL_PORT, _RX_vect)) { - MarlinSerial>::store_rxd_char(); - } - - ISR(SERIAL_REGNAME(USART, ANYCUBIC_LCD_SERIAL_PORT, _UDRE_vect)) { - MarlinSerial>::_tx_udr_empty_irq(); - } - - // Preinstantiate - template class MarlinSerial>; - - // Instantiate - MarlinSerial> anycubicLcdSerial; - -#endif - // For AT90USB targets use the UART for BT interfacing #if defined(USBCON) && ENABLED(BLUETOOTH) HardwareSerial bluetoothSerial; diff --git a/Marlin/src/HAL/AVR/MarlinSerial.h b/Marlin/src/HAL/AVR/MarlinSerial.h index 8dbed4d85b..cb906e2b65 100644 --- a/Marlin/src/HAL/AVR/MarlinSerial.h +++ b/Marlin/src/HAL/AVR/MarlinSerial.h @@ -217,10 +217,12 @@ static ring_buffer_pos_t available(); static void write(const uint8_t c); static void flushTX(); - #ifdef DGUS_SERIAL_PORT + #if HAS_DGUS_LCD static ring_buffer_pos_t get_tx_buffer_free(); #endif + static inline bool emergency_parser_enabled() { return Cfg::EMERGENCYPARSER; } + FORCE_INLINE static uint8_t dropped() { return Cfg::DROPPED_RX ? rx_dropped_bytes : 0; } FORCE_INLINE static uint8_t buffer_overruns() { return Cfg::RX_OVERRUNS ? rx_buffer_overruns : 0; } FORCE_INLINE static uint8_t framing_errors() { return Cfg::RX_FRAMING_ERRORS ? rx_framing_errors : 0; } @@ -278,55 +280,50 @@ #endif // !USBCON -#ifdef INTERNAL_SERIAL_PORT +#ifdef MMU2_SERIAL_PORT template - struct MarlinInternalSerialCfg { + struct MMU2SerialCfg { static constexpr int PORT = serial; + static constexpr bool XONOFF = false; + static constexpr bool EMERGENCYPARSER = false; + static constexpr bool DROPPED_RX = false; + static constexpr bool RX_FRAMING_ERRORS = false; + static constexpr bool MAX_RX_QUEUED = false; static constexpr unsigned int RX_SIZE = 32; static constexpr unsigned int TX_SIZE = 32; - static constexpr bool XONOFF = false; - static constexpr bool EMERGENCYPARSER = false; - static constexpr bool DROPPED_RX = false; static constexpr bool RX_OVERRUNS = false; - static constexpr bool RX_FRAMING_ERRORS = false; - static constexpr bool MAX_RX_QUEUED = false; }; - extern MarlinSerial> internalSerial; + extern MarlinSerial> mmuSerial; #endif -#ifdef DGUS_SERIAL_PORT +#ifdef LCD_SERIAL_PORT + template - struct MarlinInternalSerialCfg { - static constexpr int PORT = serial; - static constexpr unsigned int RX_SIZE = DGUS_RX_BUFFER_SIZE; - static constexpr unsigned int TX_SIZE = DGUS_TX_BUFFER_SIZE; - static constexpr bool XONOFF = false; - static constexpr bool EMERGENCYPARSER = false; - static constexpr bool DROPPED_RX = false; - static constexpr bool RX_OVERRUNS = BOTH(HAS_DGUS_LCD, DGUS_SERIAL_STATS_RX_BUFFER_OVERRUNS); - static constexpr bool RX_FRAMING_ERRORS = false; - static constexpr bool MAX_RX_QUEUED = false; + struct LCDSerialCfg { + static constexpr int PORT = serial; + static constexpr bool XONOFF = false; + static constexpr bool EMERGENCYPARSER = ENABLED(EMERGENCY_PARSER); + static constexpr bool DROPPED_RX = false; + static constexpr bool RX_FRAMING_ERRORS = false; + static constexpr bool MAX_RX_QUEUED = false; + #if HAS_DGUS_LCD + static constexpr unsigned int RX_SIZE = DGUS_RX_BUFFER_SIZE; + static constexpr unsigned int TX_SIZE = DGUS_TX_BUFFER_SIZE; + static constexpr bool RX_OVERRUNS = ENABLED(DGUS_SERIAL_STATS_RX_BUFFER_OVERRUNS); + #elif EITHER(ANYCUBIC_LCD_I3MEGA, ANYCUBIC_LCD_CHIRON) + static constexpr unsigned int RX_SIZE = 64; + static constexpr unsigned int TX_SIZE = 128; + static constexpr bool RX_OVERRUNS = false; + #else + static constexpr unsigned int RX_SIZE = 64; + static constexpr unsigned int TX_SIZE = 128; + static constexpr bool RX_OVERRUNS = false + #endif }; - extern MarlinSerial> internalDgusSerial; -#endif + extern MarlinSerial> lcdSerial; -#ifdef ANYCUBIC_LCD_SERIAL_PORT - template - struct AnycubicLcdSerialCfg { - static constexpr int PORT = serial; - static constexpr unsigned int RX_SIZE = 64; - static constexpr unsigned int TX_SIZE = 128; - static constexpr bool XONOFF = false; - static constexpr bool EMERGENCYPARSER = false; - static constexpr bool DROPPED_RX = false; - static constexpr bool RX_OVERRUNS = false; - static constexpr bool RX_FRAMING_ERRORS = false; - static constexpr bool MAX_RX_QUEUED = false; - }; - - extern MarlinSerial> anycubicLcdSerial; #endif // Use the UART for Bluetooth in AT90USB configurations diff --git a/Marlin/src/HAL/DUE/HAL.h b/Marlin/src/HAL/DUE/HAL.h index 974f1ccc16..7a057fdae4 100644 --- a/Marlin/src/HAL/DUE/HAL.h +++ b/Marlin/src/HAL/DUE/HAL.h @@ -61,13 +61,13 @@ #endif #endif -#ifdef DGUS_SERIAL_PORT - #if DGUS_SERIAL_PORT == -1 - #define DGUS_SERIAL internalDgusSerial - #elif WITHIN(DGUS_SERIAL_PORT, 0, 3) - #define DGUS_SERIAL MSERIAL(DGUS_SERIAL_PORT) +#ifdef LCD_SERIAL_PORT + #if LCD_SERIAL_PORT == -1 + #define LCD_SERIAL lcdSerial + #elif WITHIN(LCD_SERIAL_PORT, 0, 3) + #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT) #else - #error "DGUS_SERIAL_PORT must be from -1 to 3. Please update your configuration." + #error "LCD_SERIAL_PORT must be from -1 to 3. Please update your configuration." #endif #endif diff --git a/Marlin/src/HAL/DUE/MarlinSerial.h b/Marlin/src/HAL/DUE/MarlinSerial.h index dfafa15141..a194eba2f3 100644 --- a/Marlin/src/HAL/DUE/MarlinSerial.h +++ b/Marlin/src/HAL/DUE/MarlinSerial.h @@ -122,6 +122,8 @@ public: static void write(const uint8_t c); static void flushTX(); + static inline bool emergency_parser_enabled() { return Cfg::EMERGENCYPARSER; } + FORCE_INLINE static uint8_t dropped() { return Cfg::DROPPED_RX ? rx_dropped_bytes : 0; } FORCE_INLINE static uint8_t buffer_overruns() { return Cfg::RX_OVERRUNS ? rx_buffer_overruns : 0; } FORCE_INLINE static uint8_t framing_errors() { return Cfg::RX_FRAMING_ERRORS ? rx_framing_errors : 0; } diff --git a/Marlin/src/HAL/LINUX/include/serial.h b/Marlin/src/HAL/LINUX/include/serial.h index 154e95aec2..94e0c758ee 100644 --- a/Marlin/src/HAL/LINUX/include/serial.h +++ b/Marlin/src/HAL/LINUX/include/serial.h @@ -79,6 +79,7 @@ public: #if ENABLED(EMERGENCY_PARSER) EmergencyParser::State emergency_state; + static inline bool emergency_parser_enabled() { return true; } #endif HalSerial() { host_connected = true; } diff --git a/Marlin/src/HAL/LPC1768/HAL.h b/Marlin/src/HAL/LPC1768/HAL.h index e9f05fcc61..3118aed1b2 100644 --- a/Marlin/src/HAL/LPC1768/HAL.h +++ b/Marlin/src/HAL/LPC1768/HAL.h @@ -85,13 +85,13 @@ extern "C" volatile uint32_t _millis; #endif #endif -#ifdef DGUS_SERIAL_PORT - #if DGUS_SERIAL_PORT == -1 - #define DGUS_SERIAL UsbSerial - #elif WITHIN(DGUS_SERIAL_PORT, 0, 3) - #define DGUS_SERIAL MSERIAL(DGUS_SERIAL_PORT) +#ifdef LCD_SERIAL_PORT + #if LCD_SERIAL_PORT == -1 + #define LCD_SERIAL UsbSerial + #elif WITHIN(LCD_SERIAL_PORT, 0, 3) + #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT) #else - #error "DGUS_SERIAL_PORT must be from -1 to 3. Please update your configuration." + #error "LCD_SERIAL_PORT must be from -1 to 3. Please update your configuration." #endif #endif diff --git a/Marlin/src/HAL/LPC1768/MarlinSerial.cpp b/Marlin/src/HAL/LPC1768/MarlinSerial.cpp index c3fb3bd0e4..5374e005d3 100644 --- a/Marlin/src/HAL/LPC1768/MarlinSerial.cpp +++ b/Marlin/src/HAL/LPC1768/MarlinSerial.cpp @@ -24,28 +24,28 @@ #include "../../inc/MarlinConfigPre.h" #include "MarlinSerial.h" -#if (defined(SERIAL_PORT) && SERIAL_PORT == 0) || (defined(SERIAL_PORT_2) && SERIAL_PORT_2 == 0) || (defined(DGUS_SERIAL_PORT) && DGUS_SERIAL_PORT == 0) +#if USING_SERIAL_0 MarlinSerial MSerial(LPC_UART0); extern "C" void UART0_IRQHandler() { MSerial.IRQHandler(); } #endif -#if SERIAL_PORT == 1 || SERIAL_PORT_2 == 1 || DGUS_SERIAL_PORT == 1 +#if USING_SERIAL_1 MarlinSerial MSerial1((LPC_UART_TypeDef *) LPC_UART1); extern "C" void UART1_IRQHandler() { MSerial1.IRQHandler(); } #endif -#if SERIAL_PORT == 2 || SERIAL_PORT_2 == 2 || DGUS_SERIAL_PORT == 2 +#if USING_SERIAL_2 MarlinSerial MSerial2(LPC_UART2); extern "C" void UART2_IRQHandler() { MSerial2.IRQHandler(); } #endif -#if SERIAL_PORT == 3 || SERIAL_PORT_2 == 3 || DGUS_SERIAL_PORT == 3 +#if USING_SERIAL_3 MarlinSerial MSerial3(LPC_UART3); extern "C" void UART3_IRQHandler() { MSerial3.IRQHandler(); diff --git a/Marlin/src/HAL/LPC1768/MarlinSerial.h b/Marlin/src/HAL/LPC1768/MarlinSerial.h index 98ce73d377..8d6b64378a 100644 --- a/Marlin/src/HAL/LPC1768/MarlinSerial.h +++ b/Marlin/src/HAL/LPC1768/MarlinSerial.h @@ -57,6 +57,7 @@ public: } EmergencyParser::State emergency_state; + static inline bool emergency_parser_enabled() { return true; } #endif }; diff --git a/Marlin/src/HAL/LPC1768/inc/SanityCheck.h b/Marlin/src/HAL/LPC1768/inc/SanityCheck.h index 2ca8a29da4..b6491368cd 100644 --- a/Marlin/src/HAL/LPC1768/inc/SanityCheck.h +++ b/Marlin/src/HAL/LPC1768/inc/SanityCheck.h @@ -92,7 +92,7 @@ static_assert(DISABLED(BAUD_RATE_GCODE), "BAUD_RATE_GCODE is not yet supported o #define ANY_TX(N,V...) DO(IS_TX##N,||,V) #define ANY_RX(N,V...) DO(IS_RX##N,||,V) -#if (defined(SERIAL_PORT) && SERIAL_PORT == 0) || (defined(SERIAL_PORT_2) && SERIAL_PORT_2 == 0) || (defined(DGUS_SERIAL_PORT) && DGUS_SERIAL_PORT == 0) +#if USING_SERIAL_0 #define IS_TX0(P) (P == P0_02) #define IS_RX0(P) (P == P0_03) #if IS_TX0(TMC_SW_MISO) || IS_RX0(TMC_SW_MOSI) @@ -106,7 +106,7 @@ static_assert(DISABLED(BAUD_RATE_GCODE), "BAUD_RATE_GCODE is not yet supported o #undef IS_RX0 #endif -#if SERIAL_PORT == 1 || SERIAL_PORT_2 == 1 || DGUS_SERIAL_PORT == 1 +#if USING_SERIAL_1 #define IS_TX1(P) (P == P0_15) #define IS_RX1(P) (P == P0_16) #define _IS_TX1_1 IS_TX1 @@ -127,7 +127,7 @@ static_assert(DISABLED(BAUD_RATE_GCODE), "BAUD_RATE_GCODE is not yet supported o #undef _IS_RX1_1 #endif -#if SERIAL_PORT == 2 || SERIAL_PORT_2 == 2 || DGUS_SERIAL_PORT == 2 +#if USING_SERIAL_2 #define IS_TX2(P) (P == P0_10) #define IS_RX2(P) (P == P0_11) #define _IS_TX2_1 IS_TX2 @@ -161,7 +161,7 @@ static_assert(DISABLED(BAUD_RATE_GCODE), "BAUD_RATE_GCODE is not yet supported o #undef _IS_RX2_1 #endif -#if SERIAL_PORT == 3 || SERIAL_PORT_2 == 3 || DGUS_SERIAL_PORT == 3 +#if USING_SERIAL_3 #define PIN_IS_TX3(P) (PIN_EXISTS(P) && P##_PIN == P0_00) #define PIN_IS_RX3(P) (P##_PIN == P0_01) #if PIN_IS_TX3(X_MIN) || PIN_IS_RX3(X_MAX) diff --git a/Marlin/src/HAL/LPC1768/usb_serial.cpp b/Marlin/src/HAL/LPC1768/usb_serial.cpp index 63a570efdf..d225ce4188 100644 --- a/Marlin/src/HAL/LPC1768/usb_serial.cpp +++ b/Marlin/src/HAL/LPC1768/usb_serial.cpp @@ -26,7 +26,9 @@ #if ENABLED(EMERGENCY_PARSER) #include "../../feature/e_parser.h" + EmergencyParser::State emergency_state; + bool CDC_RecvCallback(const char buffer) { emergency_parser.update(emergency_state, buffer); return true; diff --git a/Marlin/src/HAL/SAMD51/HAL.h b/Marlin/src/HAL/SAMD51/HAL.h index c72613e772..7fd826a1b6 100644 --- a/Marlin/src/HAL/SAMD51/HAL.h +++ b/Marlin/src/HAL/SAMD51/HAL.h @@ -56,13 +56,13 @@ #endif #endif - #ifdef DGUS_SERIAL_PORT - #if DGUS_SERIAL_PORT == -1 - #define DGUS_SERIAL Serial - #elif WITHIN(DGUS_SERIAL_PORT, 0, 3) - #define MYSERIAL0 MSERIAL(DGUS_SERIAL_PORT) + #ifdef LCD_SERIAL_PORT + #if LCD_SERIAL_PORT == -1 + #define LCD_SERIAL Serial + #elif WITHIN(LCD_SERIAL_PORT, 0, 3) + #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT) #else - #error "DGUS_SERIAL_PORT must be from -1 to 3. Please update your configuration." + #error "LCD_SERIAL_PORT must be from -1 to 3. Please update your configuration." #endif #endif diff --git a/Marlin/src/HAL/STM32/HAL.h b/Marlin/src/HAL/STM32/HAL.h index 9ec2d5c19e..60ab45374a 100644 --- a/Marlin/src/HAL/STM32/HAL.h +++ b/Marlin/src/HAL/STM32/HAL.h @@ -64,18 +64,7 @@ #endif #endif -#if HAS_DGUS_LCD - #if DGUS_SERIAL_PORT == -1 - #define DGUS_SERIAL SerialUSB - #elif WITHIN(DGUS_SERIAL_PORT, 1, 6) - #define DGUS_SERIAL MSERIAL(DGUS_SERIAL_PORT) - #else - #error "DGUS_SERIAL_PORT must be -1 or from 1 to 6. Please update your configuration." - #endif - #define DGUS_SERIAL_GET_TX_BUFFER_FREE DGUS_SERIAL.availableForWrite -#endif - -#if ENABLED(MALYAN_LCD) +#ifdef LCD_SERIAL_PORT #if LCD_SERIAL_PORT == -1 #define LCD_SERIAL SerialUSB #elif WITHIN(LCD_SERIAL_PORT, 1, 6) @@ -83,6 +72,9 @@ #else #error "LCD_SERIAL_PORT must be -1 or from 1 to 6. Please update your configuration." #endif + #if HAS_DGUS_LCD + #define SERIAL_GET_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite() + #endif #endif /** diff --git a/Marlin/src/HAL/STM32/MarlinSerial.cpp b/Marlin/src/HAL/STM32/MarlinSerial.cpp index 2d799ea54d..a146664366 100644 --- a/Marlin/src/HAL/STM32/MarlinSerial.cpp +++ b/Marlin/src/HAL/STM32/MarlinSerial.cpp @@ -49,8 +49,8 @@ DECLARE_SERIAL_PORT_EXP(SERIAL_PORT_2) #endif -#if defined(DGUS_SERIAL_PORT) && DGUS_SERIAL_PORT >= 0 - DECLARE_SERIAL_PORT_EXP(DGUS_SERIAL_PORT) +#if defined(LCD_SERIAL_PORT) && LCD_SERIAL_PORT >= 0 + DECLARE_SERIAL_PORT_EXP(LCD_SERIAL_PORT) #endif void MarlinSerial::begin(unsigned long baud, uint8_t config) { diff --git a/Marlin/src/HAL/STM32/MarlinSerial.h b/Marlin/src/HAL/STM32/MarlinSerial.h index 5ab97ff3a9..3611cc78d7 100644 --- a/Marlin/src/HAL/STM32/MarlinSerial.h +++ b/Marlin/src/HAL/STM32/MarlinSerial.h @@ -35,6 +35,10 @@ public: #endif { } + #if ENABLED(EMERGENCY_PARSER) + static inline bool emergency_parser_enabled() { return true; } + #endif + void begin(unsigned long baud, uint8_t config); inline void begin(unsigned long baud) { begin(baud, SERIAL_8N1); } diff --git a/Marlin/src/HAL/STM32F1/HAL.h b/Marlin/src/HAL/STM32F1/HAL.h index 0f3c3e1460..5c03593eb0 100644 --- a/Marlin/src/HAL/STM32F1/HAL.h +++ b/Marlin/src/HAL/STM32F1/HAL.h @@ -68,71 +68,49 @@ #endif #endif -#if SERIAL_PORT == 0 - #error "SERIAL_PORT cannot be 0. (Port 0 does not exist.) Please update your configuration." -#elif SERIAL_PORT == -1 - #define MYSERIAL0 UsbSerial -#elif SERIAL_PORT == 1 - #define MYSERIAL0 MSerial1 -#elif SERIAL_PORT == 2 - #define MYSERIAL0 MSerial2 -#elif SERIAL_PORT == 3 - #define MYSERIAL0 MSerial3 -#elif SERIAL_PORT == 4 - #define MYSERIAL0 MSerial4 -#elif SERIAL_PORT == 5 - #define MYSERIAL0 MSerial5 +#define _MSERIAL(X) MSerial##X +#define MSERIAL(X) _MSERIAL(X) + +#if EITHER(STM32_HIGH_DENSITY, STM32_XL_DENSITY) + #define NUM_UARTS 5 #else - #error "SERIAL_PORT must be from -1 to 5. Please update your configuration." + #define NUM_UARTS 3 +#endif + +#if SERIAL_PORT == -1 + #define MYSERIAL0 UsbSerial +#elif WITHIN(SERIAL_PORT, 1, NUM_UARTS) + #define MYSERIAL0 MSERIAL(SERIAL_PORT) +#elif NUM_UARTS == 5 + #error "SERIAL_PORT must be -1 or from 1 to 5. Please update your configuration." +#else + #error "SERIAL_PORT must be -1 or from 1 to 3. Please update your configuration." #endif #ifdef SERIAL_PORT_2 - #if SERIAL_PORT_2 == 0 - #error "SERIAL_PORT_2 cannot be 0. (Port 0 does not exist.) Please update your configuration." - #elif SERIAL_PORT_2 == SERIAL_PORT - #error "SERIAL_PORT_2 must be different than SERIAL_PORT. Please update your configuration." - #elif SERIAL_PORT_2 == -1 + #if SERIAL_PORT_2 == -1 #define MYSERIAL1 UsbSerial - #elif SERIAL_PORT_2 == 1 - #define MYSERIAL1 MSerial1 - #elif SERIAL_PORT_2 == 2 - #define MYSERIAL1 MSerial2 - #elif SERIAL_PORT_2 == 3 - #define MYSERIAL1 MSerial3 - #elif SERIAL_PORT_2 == 4 - #define MYSERIAL1 MSerial4 - #elif SERIAL_PORT_2 == 5 - #define MYSERIAL1 MSerial5 + #elif WITHIN(SERIAL_PORT_2, 1, NUM_UARTS) + #define MYSERIAL1 MSERIAL(SERIAL_PORT_2) + #elif NUM_UARTS == 5 + #error "SERIAL_PORT_2 must be -1 or from 1 to 5. Please update your configuration." #else - #error "SERIAL_PORT_2 must be from -1 to 5. Please update your configuration." + #error "SERIAL_PORT_2 must be -1 or from 1 to 3. Please update your configuration." #endif #endif -#ifdef DGUS_SERIAL_PORT - #if DGUS_SERIAL_PORT == 0 - #error "DGUS_SERIAL_PORT cannot be 0. (Port 0 does not exist.) Please update your configuration." - #elif DGUS_SERIAL_PORT == SERIAL_PORT - #error "DGUS_SERIAL_PORT must be different than SERIAL_PORT. Please update your configuration." - #elif defined(SERIAL_PORT_2) && DGUS_SERIAL_PORT == SERIAL_PORT_2 - #error "DGUS_SERIAL_PORT must be different than SERIAL_PORT_2. Please update your configuration." - #elif DGUS_SERIAL_PORT == -1 - #define DGUS_SERIAL UsbSerial - #elif DGUS_SERIAL_PORT == 1 - #define DGUS_SERIAL MSerial1 - #elif DGUS_SERIAL_PORT == 2 - #define DGUS_SERIAL MSerial2 - #elif DGUS_SERIAL_PORT == 3 - #define DGUS_SERIAL MSerial3 - #elif DGUS_SERIAL_PORT == 4 - #define DGUS_SERIAL MSerial4 - #elif DGUS_SERIAL_PORT == 5 - #define DGUS_SERIAL MSerial5 +#ifdef LCD_SERIAL_PORT + #if LCD_SERIAL_PORT == -1 + #define LCD_SERIAL UsbSerial + #elif WITHIN(LCD_SERIAL_PORT, 1, NUM_UARTS) + #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT) + #elif NUM_UARTS == 5 + #error "LCD_SERIAL_PORT must be -1 or from 1 to 5. Please update your configuration." #else - #error "DGUS_SERIAL_PORT must be from -1 to 5. Please update your configuration." + #error "LCD_SERIAL_PORT must be -1 or from 1 to 3. Please update your configuration." #endif #endif - // Set interrupt grouping for this MCU void HAL_init(); #define HAL_IDLETASK 1 diff --git a/Marlin/src/HAL/STM32F1/MarlinSerial.cpp b/Marlin/src/HAL/STM32F1/MarlinSerial.cpp index 9a48e901f4..ebf11cb429 100644 --- a/Marlin/src/HAL/STM32F1/MarlinSerial.cpp +++ b/Marlin/src/HAL/STM32F1/MarlinSerial.cpp @@ -22,7 +22,7 @@ #ifdef __STM32F1__ -#include "../../inc/MarlinConfigPre.h" +#include "../../inc/MarlinConfig.h" #include "MarlinSerial.h" #include @@ -53,7 +53,8 @@ static inline __always_inline void my_usart_irq(ring_buffer *rb, ring_buffer *wb rb_push_insert(rb, c); #endif #if ENABLED(EMERGENCY_PARSER) - emergency_parser.update(serial.emergency_state, c); + if (serial.emergency_parser_enabled()) + emergency_parser.update(serial.emergency_state, c); #endif } } @@ -73,40 +74,120 @@ static inline __always_inline void my_usart_irq(ring_buffer *rb, ring_buffer *wb } } -#define DEFINE_HWSERIAL_MARLIN(name, n) \ - MarlinSerial name(USART##n, \ - BOARD_USART##n##_TX_PIN, \ - BOARD_USART##n##_RX_PIN); \ - extern "C" void __irq_usart##n(void) { \ +// Not every MarlinSerial port should handle emergency parsing. +// It would not make sense to parse GCode from TMC responses, for example. +constexpr bool serial_handles_emergency(int port) { + return false + #ifdef SERIAL_PORT + || (SERIAL_PORT) == port + #endif + #ifdef SERIAL_PORT_2 + || (SERIAL_PORT_2) == port + #endif + #ifdef LCD_SERIAL_PORT + || (LCD_SERIAL_PORT) == port + #endif + ; +} + +#define DEFINE_HWSERIAL_MARLIN(name, n) \ + MarlinSerial name(USART##n, \ + BOARD_USART##n##_TX_PIN, \ + BOARD_USART##n##_RX_PIN, \ + serial_handles_emergency(n)); \ + extern "C" void __irq_usart##n(void) { \ my_usart_irq(USART##n->rb, USART##n->wb, USART##n##_BASE, MSerial##n); \ } #define DEFINE_HWSERIAL_UART_MARLIN(name, n) \ MarlinSerial name(UART##n, \ - BOARD_USART##n##_TX_PIN, \ - BOARD_USART##n##_RX_PIN); \ + BOARD_USART##n##_TX_PIN, \ + BOARD_USART##n##_RX_PIN, \ + serial_handles_emergency(n)); \ extern "C" void __irq_usart##n(void) { \ - my_usart_irq(USART##n->rb, USART##n->wb, USART##n##_BASE, MSerial##n); \ + my_usart_irq(UART##n->rb, UART##n->wb, UART##n##_BASE, MSerial##n); \ } -#if SERIAL_PORT == 1 || SERIAL_PORT_2 == 1 || DGUS_SERIAL_PORT == 1 - DEFINE_HWSERIAL_MARLIN(MSerial1, 1); -#endif - -#if SERIAL_PORT == 2 || SERIAL_PORT_2 == 2 || DGUS_SERIAL_PORT == 2 - DEFINE_HWSERIAL_MARLIN(MSerial2, 2); -#endif - -#if SERIAL_PORT == 3 || SERIAL_PORT_2 == 3 || DGUS_SERIAL_PORT == 3 - DEFINE_HWSERIAL_MARLIN(MSerial3, 3); -#endif - -#if SERIAL_PORT == 4 || SERIAL_PORT_2 == 4 || DGUS_SERIAL_PORT == 4 +// Instantiate all UARTs even if they are not needed +// This avoids a bunch of logic to figure out every serial +// port which may be in use on the system. +DEFINE_HWSERIAL_MARLIN(MSerial1, 1); +DEFINE_HWSERIAL_MARLIN(MSerial2, 2); +DEFINE_HWSERIAL_MARLIN(MSerial3, 3); +#if EITHER(STM32_HIGH_DENSITY, STM32_XL_DENSITY) DEFINE_HWSERIAL_UART_MARLIN(MSerial4, 4); -#endif - -#if SERIAL_PORT == 5 || SERIAL_PORT_2 == 5 || DGUS_SERIAL_PORT == 5 DEFINE_HWSERIAL_UART_MARLIN(MSerial5, 5); #endif +// Check the type of each serial port by passing it to a template function. +// HardwareSerial is known to sometimes hang the controller when an error occurs, +// so this case will fail the static assert. All other classes are assumed to be ok. +template +constexpr bool IsSerialClassAllowed(const T&) { return true; } +constexpr bool IsSerialClassAllowed(const HardwareSerial&) { return false; } + +#define CHECK_CFG_SERIAL(A) static_assert(IsSerialClassAllowed(A), STRINGIFY(A) " is defined incorrectly"); +#define CHECK_AXIS_SERIAL(A) static_assert(IsSerialClassAllowed(A##_HARDWARE_SERIAL), STRINGIFY(A) "_HARDWARE_SERIAL must be defined in the form MSerial1, rather than Serial1"); + +// If you encounter this error, replace SerialX with MSerialX, for example MSerial3. + +// Non-TMC ports were already validated in HAL.h, so do not require verbose error messages. +#ifdef MYSERIAL0 + CHECK_CFG_SERIAL(MYSERIAL0); +#endif +#ifdef MYSERIAL1 + CHECK_CFG_SERIAL(MYSERIAL1); +#endif +#ifdef LCD_SERIAL + CHECK_CFG_SERIAL(LCD_SERIAL); +#endif +#if AXIS_HAS_HW_SERIAL(X) + CHECK_AXIS_SERIAL(X); +#endif +#if AXIS_HAS_HW_SERIAL(X2) + CHECK_AXIS_SERIAL(X2); +#endif +#if AXIS_HAS_HW_SERIAL(Y) + CHECK_AXIS_SERIAL(Y); +#endif +#if AXIS_HAS_HW_SERIAL(Y2) + CHECK_AXIS_SERIAL(Y2); +#endif +#if AXIS_HAS_HW_SERIAL(Z) + CHECK_AXIS_SERIAL(Z); +#endif +#if AXIS_HAS_HW_SERIAL(Z2) + CHECK_AXIS_SERIAL(Z2); +#endif +#if AXIS_HAS_HW_SERIAL(Z3) + CHECK_AXIS_SERIAL(Z3); +#endif +#if AXIS_HAS_HW_SERIAL(Z4) + CHECK_AXIS_SERIAL(Z4); +#endif +#if AXIS_HAS_HW_SERIAL(E0) + CHECK_AXIS_SERIAL(E0); +#endif +#if AXIS_HAS_HW_SERIAL(E1) + CHECK_AXIS_SERIAL(E1); +#endif +#if AXIS_HAS_HW_SERIAL(E2) + CHECK_AXIS_SERIAL(E2); +#endif +#if AXIS_HAS_HW_SERIAL(E3) + CHECK_AXIS_SERIAL(E3); +#endif +#if AXIS_HAS_HW_SERIAL(E4) + CHECK_AXIS_SERIAL(E4); +#endif +#if AXIS_HAS_HW_SERIAL(E5) + CHECK_AXIS_SERIAL(E5); +#endif +#if AXIS_HAS_HW_SERIAL(E6) + CHECK_AXIS_SERIAL(E6); +#endif +#if AXIS_HAS_HW_SERIAL(E7) + CHECK_AXIS_SERIAL(E7); +#endif + #endif // __STM32F1__ diff --git a/Marlin/src/HAL/STM32F1/MarlinSerial.h b/Marlin/src/HAL/STM32F1/MarlinSerial.h index b9248e50ca..6aa94b64ff 100644 --- a/Marlin/src/HAL/STM32F1/MarlinSerial.h +++ b/Marlin/src/HAL/STM32F1/MarlinSerial.h @@ -35,15 +35,22 @@ class MarlinSerial : public HardwareSerial { public: - MarlinSerial(struct usart_dev *usart_device, uint8 tx_pin, uint8 rx_pin) : + #if ENABLED(EMERGENCY_PARSER) + const bool ep_enabled; + EmergencyParser::State emergency_state; + inline bool emergency_parser_enabled() { return ep_enabled; } + #endif + + MarlinSerial(struct usart_dev *usart_device, uint8 tx_pin, uint8 rx_pin, bool TERN_(EMERGENCY_PARSER, ep_capable)) : HardwareSerial(usart_device, tx_pin, rx_pin) #if ENABLED(EMERGENCY_PARSER) + , ep_enabled(ep_capable) , emergency_state(EmergencyParser::State::EP_RESET) #endif { } #ifdef UART_IRQ_PRIO - // shadow the parent methods to set irq priority after the begin + // Shadow the parent methods to set IRQ priority after begin() void begin(uint32 baud) { MarlinSerial::begin(baud, SERIAL_8N1); } @@ -53,14 +60,12 @@ public: nvic_irq_set_priority(c_dev()->irq_num, UART_IRQ_PRIO); } #endif - - #if ENABLED(EMERGENCY_PARSER) - EmergencyParser::State emergency_state; - #endif }; extern MarlinSerial MSerial1; extern MarlinSerial MSerial2; extern MarlinSerial MSerial3; -extern MarlinSerial MSerial4; -extern MarlinSerial MSerial5; +#if EITHER(STM32_HIGH_DENSITY, STM32_XL_DENSITY) + extern MarlinSerial MSerial4; + extern MarlinSerial MSerial5; +#endif diff --git a/Marlin/src/HAL/STM32F1/msc_sd.h b/Marlin/src/HAL/STM32F1/msc_sd.h index d9cdbe6bb3..1e4e4c44b1 100644 --- a/Marlin/src/HAL/STM32F1/msc_sd.h +++ b/Marlin/src/HAL/STM32F1/msc_sd.h @@ -32,6 +32,7 @@ public: #if ENABLED(EMERGENCY_PARSER) EmergencyParser::State emergency_state; + inline bool emergency_parser_enabled() { return true; } #endif }; diff --git a/Marlin/src/HAL/STM32_F4_F7/HAL.h b/Marlin/src/HAL/STM32_F4_F7/HAL.h index e132168205..88e48f0fa0 100644 --- a/Marlin/src/HAL/STM32_F4_F7/HAL.h +++ b/Marlin/src/HAL/STM32_F4_F7/HAL.h @@ -72,15 +72,15 @@ #endif #endif -#ifdef DGUS_SERIAL_PORT - #if defined(STM32F4) && DGUS_SERIAL_PORT == 0 - #error "DGUS_SERIAL_PORT cannot be 0. (Port 0 does not exist.) Please update your configuration." - #elif DGUS_SERIAL_PORT == -1 - #define DGUS_SERIAL SerialUSB - #elif WITHIN(DGUS_SERIAL_PORT, 0, 6) - #define DGUS_SERIAL MSERIAL(DGUS_SERIAL_PORT) +#ifdef LCD_SERIAL_PORT + #if defined(STM32F4) && LCD_SERIAL_PORT == 0 + #error "LCD_SERIAL_PORT cannot be 0. (Port 0 does not exist.) Please update your configuration." + #elif LCD_SERIAL_PORT == -1 + #define LCD_SERIAL SerialUSB + #elif WITHIN(LCD_SERIAL_PORT, 0, 6) + #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT) #else - #error "DGUS_SERIAL_PORT must be from -1 to 6. Please update your configuration." + #error "LCD_SERIAL_PORT must be from -1 to 6. Please update your configuration." #endif #endif diff --git a/Marlin/src/inc/Conditionals_adv.h b/Marlin/src/inc/Conditionals_adv.h index 73e034d05f..d3f608e0a4 100644 --- a/Marlin/src/inc/Conditionals_adv.h +++ b/Marlin/src/inc/Conditionals_adv.h @@ -422,3 +422,37 @@ #if ANY(AUTO_BED_LEVELING_UBL, AUTO_BED_LEVELING_LINEAR, Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS) #define NEED_LSF 1 #endif + +// Flag the indexed serial ports that are in use +#define ANY_SERIAL_IS(N) (defined(SERIAL_PORT) && SERIAL_PORT == (N)) || (defined(SERIAL_PORT_2) && SERIAL_PORT_2 == (N)) || (defined(LCD_SERIAL_PORT) && LCD_SERIAL_PORT == (N)) +#if ANY_SERIAL_IS(-1) + #define USING_SERIAL_DEFAULT +#endif +#if ANY_SERIAL_IS(0) + #define USING_SERIAL_0 1 +#endif +#if ANY_SERIAL_IS(1) + #define USING_SERIAL_1 1 +#endif +#if ANY_SERIAL_IS(2) + #define USING_SERIAL_2 1 +#endif +#if ANY_SERIAL_IS(3) + #define USING_SERIAL_3 1 +#endif +#if ANY_SERIAL_IS(4) + #define USING_SERIAL_4 1 +#endif +#if ANY_SERIAL_IS(5) + #define USING_SERIAL_5 1 +#endif +#if ANY_SERIAL_IS(6) + #define USING_SERIAL_6 1 +#endif +#if ANY_SERIAL_IS(7) + #define USING_SERIAL_7 1 +#endif +#if ANY_SERIAL_IS(8) + #define USING_SERIAL_8 1 +#endif +#undef ANY_SERIAL_IS diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 4c0b68e8ae..27bafe0048 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -477,6 +477,10 @@ #error "HOME_USING_SPREADCYCLE is now obsolete. Please remove it from Configuration_adv.h." #elif defined(DGUS_LCD) #error "DGUS_LCD is now DGUS_LCD_UI_(ORIGIN|FYSETC|HIPRECY). Please update your configuration." +#elif defined(DGUS_SERIAL_PORT) + #error "DGUS_SERIAL_PORT is now LCD_SERIAL_PORT. Please update your configuration." +#elif defined(DGUS_BAUDRATE) + #error "DGUS_BAUDRATE is now LCD_BAUDRATE. Please update your configuration." #elif defined(X_DUAL_ENDSTOPS_ADJUSTMENT) #error "X_DUAL_ENDSTOPS_ADJUSTMENT is now X2_ENDSTOP_ADJUSTMENT. Please update Configuration_adv.h." #elif defined(Y_DUAL_ENDSTOPS_ADJUSTMENT) @@ -2281,31 +2285,20 @@ static_assert(hbm[Z_AXIS] >= 0, "HOMING_BUMP_MM.Z must be greater than or equal /** * Serial displays require a dedicated serial port */ -#if HAS_DGUS_LCD - #ifndef DGUS_SERIAL_PORT - #error "The DGUS LCD requires DGUS_SERIAL_PORT to be defined in Configuration.h" - #elif DGUS_SERIAL_PORT == SERIAL_PORT - #error "DGUS_SERIAL_PORT cannot be the same as SERIAL_PORT. Please update your configuration." - #elif defined(SERIAL_PORT_2) && DGUS_SERIAL_PORT == SERIAL_PORT_2 - #error "DGUS_SERIAL_PORT cannot be the same as SERIAL_PORT_2. Please update your configuration." - #endif -#elif ENABLED(MALYAN_LCD) - #ifndef LCD_SERIAL_PORT - #error "MALYAN_LCD requires LCD_SERIAL_PORT to be defined in Configuration.h" - #elif LCD_SERIAL_PORT == SERIAL_PORT +#ifdef LCD_SERIAL_PORT + #if LCD_SERIAL_PORT == SERIAL_PORT #error "LCD_SERIAL_PORT cannot be the same as SERIAL_PORT. Please update your configuration." #elif defined(SERIAL_PORT_2) && LCD_SERIAL_PORT == SERIAL_PORT_2 #error "LCD_SERIAL_PORT cannot be the same as SERIAL_PORT_2. Please update your configuration." #endif -#elif EITHER(ANYCUBIC_LCD_I3MEGA, ANYCUBIC_LCD_CHIRON) - #ifndef ANYCUBIC_LCD_SERIAL_PORT - #error "The ANYCUBIC LCD requires ANYCUBIC_LCD_SERIAL_PORT to be defined in Configuration.h" - #elif ANYCUBIC_LCD_SERIAL_PORT == SERIAL_PORT - #error "ANYCUBIC_LCD_SERIAL_PORT cannot be the same as SERIAL_PORT. Please update your configuration." - #elif defined(SERIAL_PORT_2) && ANYCUBIC_LCD_SERIAL_PORT == SERIAL_PORT_2 - #error "ANYCUBIC_LCD_SERIAL_PORT cannot be the same as SERIAL_PORT_2. Please update your configuration." +#else + #if HAS_DGUS_LCD + #error "The DGUS LCD requires LCD_SERIAL_PORT to be defined in Configuration.h" + #elif EITHER(ANYCUBIC_LCD_I3MEGA, ANYCUBIC_LCD_CHIRON) + #error "The ANYCUBIC LCD requires LCD_SERIAL_PORT to be defined in Configuration.h" + #elif ENABLED(MALYAN_LCD) + #error "MALYAN_LCD requires LCD_SERIAL_PORT to be defined in Configuration.h" #endif - #define ANYCUBIC_LCD_SERIAL anycubicLcdSerial #endif /** diff --git a/Marlin/src/lcd/extui/anycubic_chiron_lcd.cpp b/Marlin/src/lcd/extui/anycubic_chiron_lcd.cpp index 889a25b859..4a8095b6e9 100644 --- a/Marlin/src/lcd/extui/anycubic_chiron_lcd.cpp +++ b/Marlin/src/lcd/extui/anycubic_chiron_lcd.cpp @@ -53,12 +53,12 @@ static bool is_printing_from_sd = false; static bool is_out_of_filament = false; static void sendNewLine(void) { - ANYCUBIC_LCD_SERIAL.write('\r'); - ANYCUBIC_LCD_SERIAL.write('\n'); + LCD_SERIAL.write('\r'); + LCD_SERIAL.write('\n'); } static void send(const char *str) { - ANYCUBIC_LCD_SERIAL.print(str); + LCD_SERIAL.print(str); } static void sendLine(const char *str) { @@ -68,7 +68,7 @@ static void sendLine(const char *str) { static void send_P(PGM_P str) { while (const char c = pgm_read_byte(str++)) - ANYCUBIC_LCD_SERIAL.write(c); + LCD_SERIAL.write(c); } static void sendLine_P(PGM_P str) { @@ -78,23 +78,23 @@ static void sendLine_P(PGM_P str) { static void sendValue_P(PGM_P prefix, int value) { send_P(prefix); - ANYCUBIC_LCD_SERIAL.print(value); + LCD_SERIAL.print(value); } static void sendValue_P(PGM_P prefix, float value) { send_P(prefix); - ANYCUBIC_LCD_SERIAL.print(value); + LCD_SERIAL.print(value); } static void sendValueLine_P(PGM_P prefix, int value) { send_P(prefix); - ANYCUBIC_LCD_SERIAL.print(value); + LCD_SERIAL.print(value); sendNewLine(); } static void sendValueLine_P(PGM_P prefix, float value) { send_P(prefix); - ANYCUBIC_LCD_SERIAL.print(value); + LCD_SERIAL.print(value); sendNewLine(); } @@ -426,8 +426,8 @@ namespace ExtUI { static char rxBuffer[RX_LEN_MAX+1]; static uint8_t rxLen = 0; - while (ANYCUBIC_LCD_SERIAL.available()) { - const char c = ANYCUBIC_LCD_SERIAL.read(); + while (LCD_SERIAL.available()) { + const char c = LCD_SERIAL.read(); switch (c) { case '\r': case '\n': if (rxLen > 0 && rxLen <= RX_LEN_MAX) { @@ -466,7 +466,10 @@ namespace ExtUI { } void onStartup() { - ANYCUBIC_LCD_SERIAL.begin(115200); + #ifndef LCD_BAUDRATE + #define LCD_BAUDRATE 115200 + #endif + LCD_SERIAL.begin(LCD_BAUDRATE); sendNewLine(); SENDLINE_PGM("J17"); // Reset delay_ms(10); diff --git a/Marlin/src/lcd/extui/lib/anycubic_i3mega/anycubic_i3mega_lcd.cpp b/Marlin/src/lcd/extui/lib/anycubic_i3mega/anycubic_i3mega_lcd.cpp index 486f262778..c69fb8351a 100644 --- a/Marlin/src/lcd/extui/lib/anycubic_i3mega/anycubic_i3mega_lcd.cpp +++ b/Marlin/src/lcd/extui/lib/anycubic_i3mega/anycubic_i3mega_lcd.cpp @@ -59,12 +59,12 @@ char *itostr2(const uint8_t &x) { } static void sendNewLine(void) { - ANYCUBIC_LCD_SERIAL.write('\r'); - ANYCUBIC_LCD_SERIAL.write('\n'); + LCD_SERIAL.write('\r'); + LCD_SERIAL.write('\n'); } static void send(const char *str) { - ANYCUBIC_LCD_SERIAL.print(str); + LCD_SERIAL.print(str); } static void sendLine(const char *str) { @@ -74,7 +74,7 @@ static void sendLine(const char *str) { static void send_P(PGM_P str) { while (const char c = pgm_read_byte(str++)) - ANYCUBIC_LCD_SERIAL.write(c); + LCD_SERIAL.write(c); } static void sendLine_P(PGM_P str) { @@ -576,8 +576,8 @@ void AnycubicTFTClass::OnPrintTimerStopped() { void AnycubicTFTClass::GetCommandFromTFT() { char *starpos = NULL; - while (ANYCUBIC_LCD_SERIAL.available() > 0 && TFTbuflen < TFTBUFSIZE) { - serial3_char = ANYCUBIC_LCD_SERIAL.read(); + while (LCD_SERIAL.available() > 0 && TFTbuflen < TFTBUFSIZE) { + serial3_char = LCD_SERIAL.read(); if (serial3_char == '\n' || serial3_char == '\r' || serial3_char == ':' || @@ -639,11 +639,11 @@ void AnycubicTFTClass::GetCommandFromTFT() { float yPostition = ExtUI::getAxisPosition_mm(ExtUI::Y); float zPostition = ExtUI::getAxisPosition_mm(ExtUI::Z); SEND_PGM("A5V X: "); - ANYCUBIC_LCD_SERIAL.print(xPostition); + LCD_SERIAL.print(xPostition); SEND_PGM(" Y: "); - ANYCUBIC_LCD_SERIAL.print(yPostition); + LCD_SERIAL.print(yPostition); SEND_PGM(" Z: "); - ANYCUBIC_LCD_SERIAL.print(zPostition); + LCD_SERIAL.print(zPostition); SENDLINE_PGM(""); } break; diff --git a/Marlin/src/lcd/extui/lib/dgus/DGUSDisplay.cpp b/Marlin/src/lcd/extui/lib/dgus/DGUSDisplay.cpp index b788587c94..5181ba7cc4 100644 --- a/Marlin/src/lcd/extui/lib/dgus/DGUSDisplay.cpp +++ b/Marlin/src/lcd/extui/lib/dgus/DGUSDisplay.cpp @@ -59,23 +59,13 @@ constexpr uint8_t DGUS_CMD_READVAR = 0x83; bool dguslcd_local_debug; // = false; #endif -#define dgusserial DGUS_SERIAL - void DGUSDisplay::InitDisplay() { - dgusserial.begin(DGUS_BAUDRATE); - - if (true - #if ENABLED(POWER_LOSS_RECOVERY) - && !recovery.valid() - #endif - ) - RequestScreen( - #if ENABLED(SHOW_BOOTSCREEN) - DGUSLCD_SCREEN_BOOT - #else - DGUSLCD_SCREEN_MAIN - #endif - ); + #ifndef LCD_BAUDRATE + #define LCD_BAUDRATE 115200 + #endif + LCD_SERIAL.begin(LCD_BAUDRATE); + if (TERN1(POWER_LOSS_RECOVERY, !recovery.valid())) + RequestScreen(TERN(SHOW_BOOTSCREEN, DGUSLCD_SCREEN_BOOT, DGUSLCD_SCREEN_MAIN)); } void DGUSDisplay::WriteVariable(uint16_t adr, const void* values, uint8_t valueslen, bool isstr) { @@ -89,7 +79,7 @@ void DGUSDisplay::WriteVariable(uint16_t adr, const void* values, uint8_t values strend = true; x = ' '; } - dgusserial.write(x); + LCD_SERIAL.write(x); } } @@ -133,41 +123,41 @@ void DGUSDisplay::WriteVariablePGM(uint16_t adr, const void* values, uint8_t val strend = true; x = ' '; } - dgusserial.write(x); + LCD_SERIAL.write(x); } } void DGUSDisplay::ProcessRx() { #if ENABLED(DGUS_SERIAL_STATS_RX_BUFFER_OVERRUNS) - if (!dgusserial.available() && dgusserial.buffer_overruns()) { + if (!LCD_SERIAL.available() && LCD_SERIAL.buffer_overruns()) { // Overrun, but reset the flag only when the buffer is empty // We want to extract as many as valid datagrams possible... DEBUG_ECHOPGM("OVFL"); rx_datagram_state = DGUS_IDLE; - //dgusserial.reset_rx_overun(); - dgusserial.flush(); + //LCD_SERIAL.reset_rx_overun(); + LCD_SERIAL.flush(); } #endif uint8_t receivedbyte; - while (dgusserial.available()) { + while (LCD_SERIAL.available()) { switch (rx_datagram_state) { case DGUS_IDLE: // Waiting for the first header byte - receivedbyte = dgusserial.read(); + receivedbyte = LCD_SERIAL.read(); //DEBUG_ECHOPAIR("< ",x); if (DGUS_HEADER1 == receivedbyte) rx_datagram_state = DGUS_HEADER1_SEEN; break; case DGUS_HEADER1_SEEN: // Waiting for the second header byte - receivedbyte = dgusserial.read(); + receivedbyte = LCD_SERIAL.read(); //DEBUG_ECHOPAIR(" ",x); rx_datagram_state = (DGUS_HEADER2 == receivedbyte) ? DGUS_HEADER2_SEEN : DGUS_IDLE; break; case DGUS_HEADER2_SEEN: // Waiting for the length byte - rx_datagram_len = dgusserial.read(); + rx_datagram_len = LCD_SERIAL.read(); DEBUG_ECHOPAIR(" (", rx_datagram_len, ") "); // Telegram min len is 3 (command and one word of payload) @@ -175,10 +165,10 @@ void DGUSDisplay::ProcessRx() { break; case DGUS_WAIT_TELEGRAM: // wait for complete datagram to arrive. - if (dgusserial.available() < rx_datagram_len) return; + if (LCD_SERIAL.available() < rx_datagram_len) return; Initialized = true; // We've talked to it, so we defined it as initialized. - uint8_t command = dgusserial.read(); + uint8_t command = LCD_SERIAL.read(); DEBUG_ECHOPAIR("# ", command); @@ -186,7 +176,7 @@ void DGUSDisplay::ProcessRx() { unsigned char tmp[rx_datagram_len - 1]; unsigned char *ptmp = tmp; while (readlen--) { - receivedbyte = dgusserial.read(); + receivedbyte = LCD_SERIAL.read(); DEBUG_ECHOPAIR(" ", receivedbyte); *ptmp++ = receivedbyte; } @@ -229,19 +219,19 @@ void DGUSDisplay::ProcessRx() { } } -size_t DGUSDisplay::GetFreeTxBuffer() { return DGUS_SERIAL_GET_TX_BUFFER_FREE(); } +size_t DGUSDisplay::GetFreeTxBuffer() { return SERIAL_GET_TX_BUFFER_FREE(); } void DGUSDisplay::WriteHeader(uint16_t adr, uint8_t cmd, uint8_t payloadlen) { - dgusserial.write(DGUS_HEADER1); - dgusserial.write(DGUS_HEADER2); - dgusserial.write(payloadlen + 3); - dgusserial.write(cmd); - dgusserial.write(adr >> 8); - dgusserial.write(adr & 0xFF); + LCD_SERIAL.write(DGUS_HEADER1); + LCD_SERIAL.write(DGUS_HEADER2); + LCD_SERIAL.write(payloadlen + 3); + LCD_SERIAL.write(cmd); + LCD_SERIAL.write(adr >> 8); + LCD_SERIAL.write(adr & 0xFF); } void DGUSDisplay::WritePGM(const char str[], uint8_t len) { - while (len--) dgusserial.write(pgm_read_byte(str++)); + while (len--) LCD_SERIAL.write(pgm_read_byte(str++)); } void DGUSDisplay::loop() { diff --git a/buildroot/tests/mks_robin_pro-tests b/buildroot/tests/mks_robin_pro-tests index cfd36832fd..7ae4670fed 100644 --- a/buildroot/tests/mks_robin_pro-tests +++ b/buildroot/tests/mks_robin_pro-tests @@ -7,6 +7,7 @@ set -e use_example_configs Mks/Robin_Pro +opt_enable EMERGENCY_PARSER opt_set SDCARD_CONNECTION LCD opt_set X_DRIVER_TYPE TMC2209 opt_set Y_DRIVER_TYPE TMC2130