From ad934f5d07dca0110593b86a7fe8e35d58e927de Mon Sep 17 00:00:00 2001 From: etagle Date: Tue, 2 Oct 2018 03:15:57 -0300 Subject: [PATCH 1/7] AVR templatized MarlinSerial class, allowing multiple instances --- Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp | 495 +++++++++++++----------- Marlin/src/HAL/HAL_AVR/MarlinSerial.h | 272 +++++++++---- 2 files changed, 471 insertions(+), 296 deletions(-) diff --git a/Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp b/Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp index ece249776636..cdb0531fecdd 100644 --- a/Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp +++ b/Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp @@ -42,62 +42,41 @@ #include "MarlinSerial.h" #include "../../Marlin.h" - struct ring_buffer_r { - unsigned char buffer[RX_BUFFER_SIZE]; - volatile ring_buffer_pos_t head, tail; - }; - - #if TX_BUFFER_SIZE > 0 - struct ring_buffer_t { - unsigned char buffer[TX_BUFFER_SIZE]; - volatile uint8_t head, tail; - }; - #endif - - #if UART_PRESENT(SERIAL_PORT) - ring_buffer_r rx_buffer = { { 0 }, 0, 0 }; - #if TX_BUFFER_SIZE > 0 - ring_buffer_t tx_buffer = { { 0 }, 0, 0 }; - #endif - static bool _written; - #endif + template + typename MarlinSerial::ring_buffer_r MarlinSerial::rx_buffer = { { 0 }, 0, 0 }; + + template + typename MarlinSerial::ring_buffer_t MarlinSerial::tx_buffer = { { 0 }, 0, 0 }; + + template + bool MarlinSerial::_written = false; - #if ENABLED(SERIAL_XON_XOFF) - constexpr uint8_t XON_XOFF_CHAR_SENT = 0x80, // XON / XOFF Character was sent - XON_XOFF_CHAR_MASK = 0x1F; // XON / XOFF character to send - // XON / XOFF character definitions - constexpr uint8_t XON_CHAR = 17, XOFF_CHAR = 19; - uint8_t xon_xoff_state = XON_XOFF_CHAR_SENT | XON_CHAR; - #endif + template + uint8_t MarlinSerial::xon_xoff_state = MarlinSerial::XON_XOFF_CHAR_SENT | MarlinSerial::XON_CHAR; - #if ENABLED(SERIAL_STATS_DROPPED_RX) - uint8_t rx_dropped_bytes = 0; - #endif + template + uint8_t MarlinSerial::rx_dropped_bytes = 0; - #if ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS) - uint8_t rx_buffer_overruns = 0; - #endif + template + uint8_t MarlinSerial::rx_buffer_overruns = 0; - #if ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS) - uint8_t rx_framing_errors = 0; - #endif + template + uint8_t MarlinSerial::rx_framing_errors = 0; - #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) - ring_buffer_pos_t rx_max_enqueued = 0; - #endif + 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"); - #if ENABLED(EMERGENCY_PARSER) - #include "../../feature/emergency_parser.h" - #endif + #include "../../feature/emergency_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! - FORCE_INLINE ring_buffer_pos_t atomic_read_rx_head() { - #if RX_BUFFER_SIZE > 256 + template + FORCE_INLINE typename MarlinSerial::ring_buffer_pos_t MarlinSerial::atomic_read_rx_head() { + if (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 @@ -111,23 +90,24 @@ sw_barrier(); } while (vold != vnew); return vnew; - #else + } else { // With an 8bit index, reads are always atomic. No need for special handling return rx_buffer.head; - #endif + } } - #if RX_BUFFER_SIZE > 256 - static volatile bool rx_tail_value_not_stable = false; - static volatile uint16_t rx_tail_value_backup = 0; - #endif + 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 - - FORCE_INLINE void atomic_set_rx_tail(ring_buffer_pos_t value) { - #if RX_BUFFER_SIZE > 256 + template + FORCE_INLINE void MarlinSerial::atomic_set_rx_tail(typename MarlinSerial::ring_buffer_pos_t value) { + if (RX_SIZE > 256) { // Store the new value in the backup rx_tail_value_backup = value; sw_barrier(); @@ -140,29 +120,29 @@ // Signal the new value is completely stored into the value rx_tail_value_not_stable = false; sw_barrier(); - #else + } else { rx_buffer.tail = value; - #endif + } } // 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 - - FORCE_INLINE ring_buffer_pos_t atomic_read_rx_tail() { - #if RX_BUFFER_SIZE > 256 + template + FORCE_INLINE typename MarlinSerial::ring_buffer_pos_t MarlinSerial::atomic_read_rx_tail() { + if (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; - #endif + } // The true index is stable, return it return rx_buffer.tail; } // (called with RX interrupts disabled) - FORCE_INLINE void store_rxd_char() { + template + FORCE_INLINE void MarlinSerial::store_rxd_char() { - #if ENABLED(EMERGENCY_PARSER) - static EmergencyParser::State emergency_state; // = EP_RESET - #endif + static EmergencyParser::State emergency_state; // = EP_RESET // 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. @@ -173,27 +153,27 @@ 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)(RX_BUFFER_SIZE - 1); + ring_buffer_pos_t i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(RX_SIZE - 1); - // This must read the M_UCSRxA register before reading the received byte to detect error causes - #if ENABLED(SERIAL_STATS_DROPPED_RX) - if (TEST(M_UCSRxA, M_DORx) && !++rx_dropped_bytes) --rx_dropped_bytes; - #endif + // This must read the R_UCSRA register before reading the received byte to detect error causes + if (STATS_DROPPED_RX) { + if (B_DOR && !++rx_dropped_bytes) --rx_dropped_bytes; + } - #if ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS) - if (TEST(M_UCSRxA, M_DORx) && !++rx_buffer_overruns) --rx_buffer_overruns; - #endif + if (STATS_RX_OVERRUNS) { + if (B_DOR && !++rx_buffer_overruns) --rx_buffer_overruns; + } - #if ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS) - if (TEST(M_UCSRxA, M_FEx) && !++rx_framing_errors) --rx_framing_errors; - #endif + if (STATS_RX_FRAMING_ERRORS) { + if (B_FE && !++rx_framing_errors) --rx_framing_errors; + } // Read the character from the USART - uint8_t c = M_UDRx; + uint8_t c = R_UDR; - #if ENABLED(EMERGENCY_PARSER) + if (USE_EMERGENCYPARSER) { emergency_parser.update(emergency_state, c); - #endif + } // 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 @@ -201,30 +181,30 @@ if (i != t) { rx_buffer.buffer[h] = c; h = i; + } else { + if (STATS_DROPPED_RX) + if (!++rx_dropped_bytes) --rx_dropped_bytes; } - #if ENABLED(SERIAL_STATS_DROPPED_RX) - else if (!++rx_dropped_bytes) --rx_dropped_bytes; - #endif - #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) + if (STATS_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)(RX_BUFFER_SIZE - 1); + const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(RX_SIZE - 1); // Keep track of the maximum count of enqueued bytes NOLESS(rx_max_enqueued, rx_count); - #endif + } - #if ENABLED(SERIAL_XON_XOFF) + if (USE_XONOFF) { // If the last char that was sent was an XON if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XON_CHAR) { // Bytes stored into the RX buffer - const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1); + const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(RX_SIZE - 1); // 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 >= (RX_BUFFER_SIZE) / 8) { + if (rx_count >= (RX_SIZE) / 8) { // 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 @@ -238,19 +218,18 @@ // 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 (!TEST(M_UCSRxA, M_UDREx)) { + while (!B_UDRE) { - if (TEST(M_UCSRxA,M_RXCx)) { + 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)(RX_BUFFER_SIZE - 1); + i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(RX_SIZE - 1); // Read the character from the USART - c = M_UDRx; + c = R_UDR; - #if ENABLED(EMERGENCY_PARSER) + if (USE_EMERGENCYPARSER) emergency_parser.update(emergency_state, c); - #endif // 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 @@ -258,20 +237,20 @@ if (i != t) { rx_buffer.buffer[h] = c; h = i; + } else { + if (STATS_DROPPED_RX) + if (!++rx_dropped_bytes) --rx_dropped_bytes; } - #if ENABLED(SERIAL_STATS_DROPPED_RX) - else if (!++rx_dropped_bytes) --rx_dropped_bytes; - #endif } sw_barrier(); } - M_UDRx = XOFF_CHAR; + 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 - SBI(M_UCSRxA, M_TXCx); + 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 @@ -280,19 +259,18 @@ // 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 (!TEST(M_UCSRxA, M_UDREx)) { + while (!B_UDRE) { - if (TEST(M_UCSRxA,M_RXCx)) { + 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)(RX_BUFFER_SIZE - 1); + i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(RX_SIZE - 1); // Read the character from the USART - c = M_UDRx; + c = R_UDR; - #if ENABLED(EMERGENCY_PARSER) + if (USE_EMERGENCYPARSER) emergency_parser.update(emergency_state, c); - #endif // 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 @@ -300,10 +278,10 @@ if (i != t) { rx_buffer.buffer[h] = c; h = i; + } else { + if (STATS_DROPPED_RX) + if (!++rx_dropped_bytes) --rx_dropped_bytes; } - #if ENABLED(SERIAL_STATS_DROPPED_RX) - else if (!++rx_dropped_bytes) --rx_dropped_bytes; - #endif } sw_barrier(); } @@ -312,78 +290,68 @@ // have any issues writing to the UART TX register if it needs to! } } - #endif // SERIAL_XON_XOFF + } // Store the new head value - The main loop will retry until the value is stable rx_buffer.head = h; } - #if TX_BUFFER_SIZE > 0 - - // (called with TX irqs disabled) - FORCE_INLINE void _tx_udr_empty_irq(void) { - + // (called with TX irqs disabled) + template + FORCE_INLINE void MarlinSerial::_tx_udr_empty_irq(void) { + if (TX_SIZE > 0) { // Read positions uint8_t t = tx_buffer.tail; const uint8_t h = tx_buffer.head; - #if ENABLED(SERIAL_XON_XOFF) + if (USE_XONOFF) { // If an XON char is pending to be sent, do it now if (xon_xoff_state == XON_CHAR) { // Send the character - M_UDRx = XON_CHAR; + R_UDR = 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 - SBI(M_UCSRxA, M_TXCx); + B_TXC = 1; // Remember we sent it. xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT; // If nothing else to transmit, just disable TX interrupts. - if (h == t) CBI(M_UCSRxB, M_UDRIEx); // (Non-atomic, could be reenabled by the main program, but eventually this will succeed) + if (h == t) B_UDRIE = 0; // (Non-atomic, could be reenabled by the main program, but eventually this will succeed) return; } - #endif + } // 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) { - CBI(M_UCSRxB, M_UDRIEx); // (Non-atomic, could be reenabled by the main program, but eventually this will succeed) + 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) & (TX_BUFFER_SIZE - 1); - M_UDRx = c; + t = (t + 1) & (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/ - SBI(M_UCSRxA, M_TXCx); + B_TXC = 1; // Disable interrupts if there is nothing to transmit following this byte - if (h == t) CBI(M_UCSRxB, M_UDRIEx); // (Non-atomic, could be reenabled by the main program, but eventually this will succeed) + if (h == t) B_UDRIE = 0; // (Non-atomic, could be reenabled by the main program, but eventually this will succeed) } - - #ifdef M_USARTx_UDRE_vect - ISR(M_USARTx_UDRE_vect) { _tx_udr_empty_irq(); } - #endif - - #endif // TX_BUFFER_SIZE - - #ifdef M_USARTx_RX_vect - ISR(M_USARTx_RX_vect) { store_rxd_char(); } - #endif + } // Public Methods - - void MarlinSerial::begin(const long baud) { + template + void MarlinSerial::begin(const long baud) { uint16_t baud_setting; bool useU2X = true; @@ -394,41 +362,43 @@ if (baud == 57600) useU2X = false; #endif + R_UCSRA = 0; if (useU2X) { - M_UCSRxA = _BV(M_U2Xx); + B_U2X = 1; baud_setting = (F_CPU / 4 / baud - 1) / 2; } else { - M_UCSRxA = 0; baud_setting = (F_CPU / 8 / baud - 1) / 2; } // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register) - M_UBRRxH = baud_setting >> 8; - M_UBRRxL = baud_setting; - - SBI(M_UCSRxB, M_RXENx); - SBI(M_UCSRxB, M_TXENx); - SBI(M_UCSRxB, M_RXCIEx); - #if TX_BUFFER_SIZE > 0 - CBI(M_UCSRxB, M_UDRIEx); - #endif + R_UBRRH = baud_setting >> 8; + R_UBRRL = baud_setting; + + B_RXEN = 1; + B_TXEN = 1; + B_RXCIE = 1; + if (TX_SIZE > 0) + B_UDRIE = 0; _written = false; } - void MarlinSerial::end() { - CBI(M_UCSRxB, M_RXENx); - CBI(M_UCSRxB, M_TXENx); - CBI(M_UCSRxB, M_RXCIEx); - CBI(M_UCSRxB, M_UDRIEx); + template + void MarlinSerial::end() { + B_RXEN = 0; + B_TXEN = 0; + B_RXCIE = 0; + B_UDRIE = 0; } - int MarlinSerial::peek(void) { + template + int MarlinSerial::peek(void) { const ring_buffer_pos_t h = atomic_read_rx_head(), t = rx_buffer.tail; return h == t ? -1 : rx_buffer.buffer[t]; } - int MarlinSerial::read(void) { + template + int MarlinSerial::read(void) { 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 @@ -439,42 +409,44 @@ // Get the next char const int v = rx_buffer.buffer[t]; - t = (ring_buffer_pos_t)(t + 1) & (RX_BUFFER_SIZE - 1); + t = (ring_buffer_pos_t)(t + 1) & (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 ENABLED(SERIAL_XON_XOFF) + if (USE_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)(RX_BUFFER_SIZE - 1); - if (rx_count < (RX_BUFFER_SIZE) / 10) { - #if TX_BUFFER_SIZE > 0 + const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(RX_SIZE - 1); + if (rx_count < (RX_SIZE) / 10) { + if (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 - SBI(M_UCSRxB, M_UDRIEx); - #else + 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 (!TEST(M_UCSRxA, M_UDREx)) sw_barrier(); - M_UDRx = XON_CHAR; - #endif + while (!B_UDRE) sw_barrier(); + R_UDR = XON_CHAR; + } } } - #endif + } return v; } - ring_buffer_pos_t MarlinSerial::available(void) { + template + typename MarlinSerial::ring_buffer_pos_t MarlinSerial::available(void) { const ring_buffer_pos_t h = atomic_read_rx_head(), t = rx_buffer.tail; - return (ring_buffer_pos_t)(RX_BUFFER_SIZE + h - t) & (RX_BUFFER_SIZE - 1); + return (ring_buffer_pos_t)(RX_SIZE + h - t) & (RX_SIZE - 1); } - void MarlinSerial::flush(void) { + template + void MarlinSerial::flush(void) { // Set the tail to the head: // - Read the RX head index in a safe way. (See atomic_read_rx_head.) @@ -482,26 +454,34 @@ // if it interrupts the writing of the value of that variable in the middle. atomic_set_rx_tail(atomic_read_rx_head()); - #if ENABLED(SERIAL_XON_XOFF) + if (USE_XONOFF) { // If the XOFF char was sent, or about to be sent... if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) { - #if TX_BUFFER_SIZE > 0 + if (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. - SBI(M_UCSRxB, M_UDRIEx); - #else + 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 (!TEST(M_UCSRxA, M_UDREx)) sw_barrier(); - M_UDRx = XON_CHAR; - #endif + while (!B_UDRE) sw_barrier(); + R_UDR = XON_CHAR; + } } - #endif + } } - #if TX_BUFFER_SIZE > 0 - void MarlinSerial::write(const uint8_t c) { + template + void MarlinSerial::write(const uint8_t c) { + if (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 @@ -511,17 +491,17 @@ // 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 (!TEST(M_UCSRxB, M_UDRIEx) && TEST(M_UCSRxA, M_UDREx)) { - M_UDRx = c; + 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 - SBI(M_UCSRxA, M_TXCx); + B_TXC = 1; return; } - const uint8_t i = (tx_buffer.head + 1) & (TX_BUFFER_SIZE - 1); + const uint8_t i = (tx_buffer.head + 1) & (TX_SIZE - 1); // If global interrupts are disabled (as the result of being called from an ISR)... if (!ISRS_ENABLED()) { @@ -530,7 +510,7 @@ while (i == tx_buffer.tail) { // If we can transmit another byte, do it. - if (TEST(M_UCSRxA, M_UDREx)) _tx_udr_empty_irq(); + if (B_UDRE) _tx_udr_empty_irq(); // Make sure compiler rereads tx_buffer.tail sw_barrier(); @@ -546,10 +526,26 @@ tx_buffer.head = i; // Enable TX ISR - Non atomic, but it will eventually enable TX ISR - SBI(M_UCSRxB, M_UDRIEx); + B_UDRIE = 1; } + } + + template + void MarlinSerial::flushTX(void) { + + if (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 { - void MarlinSerial::flushTX(void) { // 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; @@ -558,10 +554,10 @@ if (!ISRS_ENABLED()) { // Wait until everything was transmitted - We must do polling, as interrupts are disabled - while (tx_buffer.head != tx_buffer.tail || !TEST(M_UCSRxA, M_TXCx)) { + while (tx_buffer.head != tx_buffer.tail || !B_TXC) { // If there is more space, send an extra character - if (TEST(M_UCSRxA, M_UDREx)) + if (B_UDRE) _tx_udr_empty_irq(); sw_barrier(); @@ -570,55 +566,40 @@ } else { // Wait until everything was transmitted - while (tx_buffer.head != tx_buffer.tail || !TEST(M_UCSRxA, M_TXCx)) sw_barrier(); + 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). } - - #else // TX_BUFFER_SIZE == 0 - - void MarlinSerial::write(const uint8_t c) { - _written = true; - while (!TEST(M_UCSRxA, M_UDREx)) sw_barrier(); - M_UDRx = c; - } - - void MarlinSerial::flushTX(void) { - // 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 (!TEST(M_UCSRxA, M_TXCx)) sw_barrier(); - - // At this point nothing is queued anymore (DRIE is disabled) and - // the hardware finished transmission (TXC is set). - } - #endif // TX_BUFFER_SIZE == 0 + } /** * Imports from print.h */ - void MarlinSerial::print(char c, int base) { + template + void MarlinSerial::print(char c, int base) { print((long)c, base); } - void MarlinSerial::print(unsigned char b, int base) { + template + void MarlinSerial::print(unsigned char b, int base) { print((unsigned long)b, base); } - void MarlinSerial::print(int n, int base) { + template + void MarlinSerial::print(int n, int base) { print((long)n, base); } - void MarlinSerial::print(unsigned int n, int base) { + template + void MarlinSerial::print(unsigned int n, int base) { print((unsigned long)n, base); } - void MarlinSerial::print(long n, int base) { + template + void MarlinSerial::print(long n, int base) { if (base == 0) write(n); else if (base == 10) { if (n < 0) { print('-'); n = -n; } @@ -628,68 +609,81 @@ printNumber(n, base); } - void MarlinSerial::print(unsigned long n, int base) { + template + void MarlinSerial::print(unsigned long n, int base) { if (base == 0) write(n); else printNumber(n, base); } - void MarlinSerial::print(double n, int digits) { + template + void MarlinSerial::print(double n, int digits) { printFloat(n, digits); } - void MarlinSerial::println(void) { + template + void MarlinSerial::println(void) { print('\r'); print('\n'); } - void MarlinSerial::println(const String& s) { + template + void MarlinSerial::println(const String& s) { print(s); println(); } - void MarlinSerial::println(const char c[]) { + template + void MarlinSerial::println(const char c[]) { print(c); println(); } - void MarlinSerial::println(char c, int base) { + template + void MarlinSerial::println(char c, int base) { print(c, base); println(); } - void MarlinSerial::println(unsigned char b, int base) { + template + void MarlinSerial::println(unsigned char b, int base) { print(b, base); println(); } - void MarlinSerial::println(int n, int base) { + template + void MarlinSerial::println(int n, int base) { print(n, base); println(); } - void MarlinSerial::println(unsigned int n, int base) { + template + void MarlinSerial::println(unsigned int n, int base) { print(n, base); println(); } - void MarlinSerial::println(long n, int base) { + template + void MarlinSerial::println(long n, int base) { print(n, base); println(); } - void MarlinSerial::println(unsigned long n, int base) { + template + void MarlinSerial::println(unsigned long n, int base) { print(n, base); println(); } - void MarlinSerial::println(double n, int digits) { + template + void MarlinSerial::println(double n, int digits) { print(n, digits); println(); } // Private Methods - void MarlinSerial::printNumber(unsigned long n, uint8_t base) { + 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; @@ -704,7 +698,8 @@ print('0'); } - void MarlinSerial::printFloat(double number, uint8_t digits) { + template + void MarlinSerial::printFloat(double number, uint8_t digits) { // Handle negative numbers if (number < 0.0) { print('-'); @@ -736,8 +731,60 @@ } } + // Hookup ISR handlers + ISR(SERIAL_REGNAME(USART,SERIAL_PORT,_RX_vect)) { + MarlinSerial< + SERIAL_PORT, + RX_BUFFER_SIZE, + TX_BUFFER_SIZE, + ENABLED(SERIAL_XON_XOFF), + ENABLED(EMERGENCY_PARSER), + ENABLED(SERIAL_STATS_DROPPED_RX), + ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS), + ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS), + ENABLED(SERIAL_STATS_MAX_RX_QUEUED) + >::store_rxd_char(); + } + + ISR(SERIAL_REGNAME(USART,SERIAL_PORT,_UDRE_vect)) { + MarlinSerial< + SERIAL_PORT, + RX_BUFFER_SIZE, + TX_BUFFER_SIZE, + ENABLED(SERIAL_XON_XOFF), + ENABLED(EMERGENCY_PARSER), + ENABLED(SERIAL_STATS_DROPPED_RX), + ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS), + ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS), + ENABLED(SERIAL_STATS_MAX_RX_QUEUED) + >::_tx_udr_empty_irq(); + } + // Preinstantiate - MarlinSerial customizedSerial; + template class MarlinSerial< + SERIAL_PORT, + RX_BUFFER_SIZE, + TX_BUFFER_SIZE, + ENABLED(SERIAL_XON_XOFF), + ENABLED(EMERGENCY_PARSER), + ENABLED(SERIAL_STATS_DROPPED_RX), + ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS), + ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS), + ENABLED(SERIAL_STATS_MAX_RX_QUEUED) + >; + + // Instantiate + MarlinSerial< + SERIAL_PORT, + RX_BUFFER_SIZE, + TX_BUFFER_SIZE, + ENABLED(SERIAL_XON_XOFF), + ENABLED(EMERGENCY_PARSER), + ENABLED(SERIAL_STATS_DROPPED_RX), + ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS), + ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS), + ENABLED(SERIAL_STATS_MAX_RX_QUEUED) + > customizedSerial; #endif // !USBCON && (UBRRH || UBRR0H || UBRR1H || UBRR2H || UBRR3H) diff --git a/Marlin/src/HAL/HAL_AVR/MarlinSerial.h b/Marlin/src/HAL/HAL_AVR/MarlinSerial.h index 8c2b3f3186e5..4453ab4b4599 100644 --- a/Marlin/src/HAL/HAL_AVR/MarlinSerial.h +++ b/Marlin/src/HAL/HAL_AVR/MarlinSerial.h @@ -27,6 +27,7 @@ * Modified 28 September 2010 by Mark Sproul * Modified 14 February 2016 by Andreas Hardtung (added tx buffer) * Modified 01 October 2017 by Eduardo José Tagle (added XON/XOFF) + * Templatized 01 October 2018 by Eduardo José Tagle to allow multiple instances */ #ifndef _MARLINSERIAL_H_ @@ -40,73 +41,184 @@ #define SERIAL_PORT 0 #endif -// The presence of the UBRRH register is used to detect a UART. -#define UART_PRESENT(port) ((port == 0 && (defined(UBRRH) || defined(UBRR0H))) || \ - (port == 1 && defined(UBRR1H)) || (port == 2 && defined(UBRR2H)) || \ - (port == 3 && defined(UBRR3H))) - -// These are macros to build serial port register names for the selected SERIAL_PORT (C preprocessor -// requires two levels of indirection to expand macro values properly) -#define SERIAL_REGNAME(registerbase,number,suffix) SERIAL_REGNAME_INTERNAL(registerbase,number,suffix) -#if SERIAL_PORT == 0 && (!defined(UBRR0H) || !defined(UDR0)) // use un-numbered registers if necessary - #define SERIAL_REGNAME_INTERNAL(registerbase,number,suffix) registerbase##suffix -#else - #define SERIAL_REGNAME_INTERNAL(registerbase,number,suffix) registerbase##number##suffix -#endif +#ifndef USBCON -// Registers used by MarlinSerial class (expanded depending on selected serial port) -#define M_UCSRxA SERIAL_REGNAME(UCSR,SERIAL_PORT,A) // defines M_UCSRxA to be UCSRnA where n is the serial port number -#define M_UCSRxB SERIAL_REGNAME(UCSR,SERIAL_PORT,B) -#define M_RXENx SERIAL_REGNAME(RXEN,SERIAL_PORT,) -#define M_TXENx SERIAL_REGNAME(TXEN,SERIAL_PORT,) -#define M_TXCx SERIAL_REGNAME(TXC,SERIAL_PORT,) -#define M_RXCIEx SERIAL_REGNAME(RXCIE,SERIAL_PORT,) -#define M_UDREx SERIAL_REGNAME(UDRE,SERIAL_PORT,) -#define M_FEx SERIAL_REGNAME(FE,SERIAL_PORT,) -#define M_DORx SERIAL_REGNAME(DOR,SERIAL_PORT,) -#define M_UPEx SERIAL_REGNAME(UPE,SERIAL_PORT,) -#define M_UDRIEx SERIAL_REGNAME(UDRIE,SERIAL_PORT,) -#define M_UDRx SERIAL_REGNAME(UDR,SERIAL_PORT,) -#define M_UBRRxH SERIAL_REGNAME(UBRR,SERIAL_PORT,H) -#define M_UBRRxL SERIAL_REGNAME(UBRR,SERIAL_PORT,L) -#define M_RXCx SERIAL_REGNAME(RXC,SERIAL_PORT,) -#define M_USARTx_RX_vect SERIAL_REGNAME(USART,SERIAL_PORT,_RX_vect) -#define M_U2Xx SERIAL_REGNAME(U2X,SERIAL_PORT,) -#define M_USARTx_UDRE_vect SERIAL_REGNAME(USART,SERIAL_PORT,_UDRE_vect) - -#define DEC 10 -#define HEX 16 -#define OCT 8 -#define BIN 2 -#define BYTE 0 + // The presence of the UBRRH register is used to detect a UART. + #define UART_PRESENT(port) ((port == 0 && (defined(UBRRH) || defined(UBRR0H))) || \ + (port == 1 && defined(UBRR1H)) || (port == 2 && defined(UBRR2H)) || \ + (port == 3 && defined(UBRR3H))) -#ifndef USBCON - // We're using a ring buffer (I think), in which rx_buffer_head is the index of the - // location to which to write the next incoming character and rx_buffer_tail is the - // index of the location from which to read. - #if RX_BUFFER_SIZE > 256 - typedef uint16_t ring_buffer_pos_t; + // These are macros to build serial port register names for the selected SERIAL_PORT (C preprocessor + // requires two levels of indirection to expand macro values properly) + #define SERIAL_REGNAME(registerbase,number,suffix) SERIAL_REGNAME_INTERNAL(registerbase,number,suffix) + #if SERIAL_PORT == 0 && (!defined(UBRR0H) || !defined(UDR0)) // use un-numbered registers if necessary + #define SERIAL_REGNAME_INTERNAL(registerbase,number,suffix) registerbase##suffix #else - typedef uint8_t ring_buffer_pos_t; + #define SERIAL_REGNAME_INTERNAL(registerbase,number,suffix) registerbase##number##suffix #endif - #if ENABLED(SERIAL_STATS_DROPPED_RX) - extern uint8_t rx_dropped_bytes; - #endif + // Registers used by MarlinSerial class (expanded depending on selected serial port) - #if ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS) - extern uint8_t rx_buffer_overruns; - #endif + // Templated 8bit register (generic) + #define UART_REGISTER_DECL_BASE(registerbase, suffix) \ + template struct R_##registerbase##x##suffix {} - #if ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS) - extern uint8_t rx_framing_errors; - #endif + // Templated 8bit register (specialization for each port) + #define UART_REGISTER_DECL(port, registerbase, suffix) \ + template<> struct R_##registerbase##x##suffix { \ + constexpr R_##registerbase##x##suffix(int) {} \ + FORCE_INLINE void operator=(uint8_t newVal) const { SERIAL_REGNAME(registerbase,port,suffix) = newVal; } \ + FORCE_INLINE operator uint8_t() const { return SERIAL_REGNAME(registerbase,port,suffix); } \ + } + + // Templated 1bit register (generic) + #define UART_BIT_DECL_BASE(registerbase, suffix, bit) \ + templatestruct B_##bit##x {} + + // Templated 1bit register (specialization for each port) + #define UART_BIT_DECL(port, registerbase, suffix, bit) \ + template<> struct B_##bit##x { \ + constexpr B_##bit##x(int) {} \ + FORCE_INLINE void operator=(int newVal) const { \ + if (newVal) { \ + SBI(SERIAL_REGNAME(registerbase,port,suffix),SERIAL_REGNAME(bit,port,)); \ + } else { \ + CBI(SERIAL_REGNAME(registerbase,port,suffix),SERIAL_REGNAME(bit,port,)); \ + } \ + } \ + FORCE_INLINE operator bool() const { return TEST(SERIAL_REGNAME(registerbase,port,suffix),SERIAL_REGNAME(bit,port,)); } \ + } + + #define UART_DECL_BASE() \ + UART_REGISTER_DECL_BASE(UCSR,A);\ + UART_REGISTER_DECL_BASE(UDR,);\ + UART_REGISTER_DECL_BASE(UBRR,H);\ + UART_REGISTER_DECL_BASE(UBRR,L);\ + UART_BIT_DECL_BASE(UCSR,B,RXEN);\ + UART_BIT_DECL_BASE(UCSR,B,TXEN);\ + UART_BIT_DECL_BASE(UCSR,A,TXC);\ + UART_BIT_DECL_BASE(UCSR,B,RXCIE);\ + UART_BIT_DECL_BASE(UCSR,A,UDRE);\ + UART_BIT_DECL_BASE(UCSR,A,FE);\ + UART_BIT_DECL_BASE(UCSR,A,DOR);\ + UART_BIT_DECL_BASE(UCSR,B,UDRIE);\ + UART_BIT_DECL_BASE(UCSR,A,RXC);\ + UART_BIT_DECL_BASE(UCSR,A,U2X) + + #define UART_DECL(port) \ + UART_REGISTER_DECL(port,UCSR,A);\ + UART_REGISTER_DECL(port,UDR,);\ + UART_REGISTER_DECL(port,UBRR,H);\ + UART_REGISTER_DECL(port,UBRR,L);\ + UART_BIT_DECL(port,UCSR,B,RXEN);\ + UART_BIT_DECL(port,UCSR,B,TXEN);\ + UART_BIT_DECL(port,UCSR,A,TXC);\ + UART_BIT_DECL(port,UCSR,B,RXCIE);\ + UART_BIT_DECL(port,UCSR,A,UDRE);\ + UART_BIT_DECL(port,UCSR,A,FE);\ + UART_BIT_DECL(port,UCSR,A,DOR);\ + UART_BIT_DECL(port,UCSR,B,UDRIE);\ + UART_BIT_DECL(port,UCSR,A,RXC);\ + UART_BIT_DECL(port,UCSR,A,U2X) - #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) - extern ring_buffer_pos_t rx_max_enqueued; + // Declare empty templates + UART_DECL_BASE(); + + // And all the specializations for each possible serial port + #if UART_PRESENT(0) + UART_DECL(0); + #endif + #if UART_PRESENT(1) + UART_DECL(1); + #endif + #if UART_PRESENT(2) + UART_DECL(2); #endif + #if UART_PRESENT(3) + UART_DECL(3); + #endif + + #define DEC 10 + #define HEX 16 + #define OCT 8 + #define BIN 2 + #define BYTE 0 + // Templated type selector + template struct TypeSelector { typedef T type;} ; + template struct TypeSelector { typedef F type; }; + + template class MarlinSerial { + protected: + // Registers + static constexpr R_UCSRxA R_UCSRA = 0; + static constexpr R_UDRx R_UDR = 0; + static constexpr R_UBRRxH R_UBRRH = 0; + static constexpr R_UBRRxL R_UBRRL = 0; + + // Bits + static constexpr B_RXENx B_RXEN = 0; + static constexpr B_TXENx B_TXEN = 0; + static constexpr B_TXCx B_TXC = 0; + static constexpr B_RXCIEx B_RXCIE = 0; + static constexpr B_UDREx B_UDRE = 0; + static constexpr B_FEx B_FE = 0; + static constexpr B_DORx B_DOR = 0; + static constexpr B_UDRIEx B_UDRIE = 0; + static constexpr B_RXCx B_RXC = 0; + static constexpr B_U2Xx B_U2X = 0; + + // Base size of type on buffer size + typedef typename TypeSelector<(RX_SIZE>256), uint16_t, uint8_t>::type ring_buffer_pos_t; + + struct ring_buffer_r { + unsigned char buffer[RX_SIZE]; + volatile ring_buffer_pos_t head, tail; + }; + + struct ring_buffer_t { + unsigned char buffer[TX_SIZE]; + volatile uint8_t head, tail; + }; + + static ring_buffer_r rx_buffer; + static ring_buffer_t tx_buffer; + static bool _written; + + static constexpr uint8_t XON_XOFF_CHAR_SENT = 0x80, // XON / XOFF Character was sent + XON_XOFF_CHAR_MASK = 0x1F; // XON / XOFF character to send + + // XON / XOFF character definitions + static constexpr uint8_t XON_CHAR = 17, XOFF_CHAR = 19; + static uint8_t xon_xoff_state; + + static uint8_t rx_dropped_bytes; + static uint8_t rx_buffer_overruns; + static uint8_t rx_framing_errors; + static ring_buffer_pos_t rx_max_enqueued; + + static FORCE_INLINE ring_buffer_pos_t atomic_read_rx_head(); + + static volatile bool rx_tail_value_not_stable; + static volatile uint16_t rx_tail_value_backup; + + static FORCE_INLINE void atomic_set_rx_tail(ring_buffer_pos_t value); + static FORCE_INLINE ring_buffer_pos_t atomic_read_rx_tail(); + + public: + + FORCE_INLINE static void store_rxd_char(); + FORCE_INLINE static void _tx_udr_empty_irq(void); public: MarlinSerial() {}; @@ -119,21 +231,10 @@ static void write(const uint8_t c); static void flushTX(void); - #if ENABLED(SERIAL_STATS_DROPPED_RX) - FORCE_INLINE static uint32_t dropped() { return rx_dropped_bytes; } - #endif - - #if ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS) - FORCE_INLINE static uint32_t buffer_overruns() { return rx_buffer_overruns; } - #endif - - #if ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS) - FORCE_INLINE static uint32_t framing_errors() { return rx_framing_errors; } - #endif - - #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) - FORCE_INLINE static ring_buffer_pos_t rxMaxEnqueued() { return rx_max_enqueued; } - #endif + FORCE_INLINE static uint8_t dropped() { return STATS_DROPPED_RX ? rx_dropped_bytes : 0; } + FORCE_INLINE static uint8_t buffer_overruns() { return STATS_RX_OVERRUNS ? rx_buffer_overruns : 0; } + FORCE_INLINE static uint8_t framing_errors() { return STATS_RX_FRAMING_ERRORS ? rx_framing_errors : 0; } + FORCE_INLINE static ring_buffer_pos_t rxMaxEnqueued() { return STATS_MAX_RX_QUEUED ? rx_max_enqueued : 0; } FORCE_INLINE static void write(const char* str) { while (*str) write(*str++); } FORCE_INLINE static void write(const uint8_t* buffer, size_t size) { while (size--) write(*buffer++); } @@ -165,7 +266,34 @@ static void printFloat(double, uint8_t); }; - extern MarlinSerial customizedSerial; + // Make sure ENABLED() evaluates to 0 if feature disabled + #ifndef SERIAL_XON_XOFF + #define SERIAL_XON_XOFF 0 + #endif + #ifndef EMERGENCY_PARSER + #define EMERGENCY_PARSER 0 + #endif + #ifndef SERIAL_STATS_DROPPED_RX + #define SERIAL_STATS_DROPPED_RX 0 + #endif + #ifndef SERIAL_STATS_RX_BUFFER_OVERRUNS + #define SERIAL_STATS_RX_BUFFER_OVERRUNS 0 + #endif + #ifndef SERIAL_STATS_MAX_RX_QUEUED + #define SERIAL_STATS_MAX_RX_QUEUED 0 + #endif + + extern MarlinSerial< + SERIAL_PORT, + RX_BUFFER_SIZE, + TX_BUFFER_SIZE, + ENABLED(SERIAL_XON_XOFF), + ENABLED(EMERGENCY_PARSER), + ENABLED(SERIAL_STATS_DROPPED_RX), + ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS), + ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS), + ENABLED(SERIAL_STATS_MAX_RX_QUEUED) + > customizedSerial; #endif // !USBCON From 96627bf68568cc27adffe23ce8e03ed5e9cc4ac8 Mon Sep 17 00:00:00 2001 From: etagle Date: Tue, 2 Oct 2018 03:16:15 -0300 Subject: [PATCH 2/7] DUE templatized MarlinSerial class, allowing multiple instances --- Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp | 410 ++++++++++---------- Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h | 151 +++++-- 2 files changed, 314 insertions(+), 247 deletions(-) diff --git a/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp b/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp index 0ff98e62ffca..3bd59606e4e0 100644 --- a/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp +++ b/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp @@ -36,93 +36,40 @@ // If not using the USB port as serial port #if SERIAL_PORT >= 0 - // Based on selected port, use the proper configuration - #if SERIAL_PORT == 0 - #define HWUART UART - #define HWUART_IRQ UART_IRQn - #define HWUART_IRQ_ID ID_UART - #elif SERIAL_PORT == 1 - #define HWUART ((Uart*)USART0) - #define HWUART_IRQ USART0_IRQn - #define HWUART_IRQ_ID ID_USART0 - #elif SERIAL_PORT == 2 - #define HWUART ((Uart*)USART1) - #define HWUART_IRQ USART1_IRQn - #define HWUART_IRQ_ID ID_USART1 - #elif SERIAL_PORT == 3 - #define HWUART ((Uart*)USART2) - #define HWUART_IRQ USART2_IRQn - #define HWUART_IRQ_ID ID_USART2 - #elif SERIAL_PORT == 4 - #define HWUART ((Uart*)USART3) - #define HWUART_IRQ USART3_IRQn - #define HWUART_IRQ_ID ID_USART3 - #endif - - struct ring_buffer_r { - unsigned char buffer[RX_BUFFER_SIZE]; - volatile ring_buffer_pos_t head, tail; - }; - - #if TX_BUFFER_SIZE > 0 - struct ring_buffer_t { - unsigned char buffer[TX_BUFFER_SIZE]; - volatile uint8_t head, tail; - }; - #endif - - ring_buffer_r rx_buffer = { { 0 }, 0, 0 }; - #if TX_BUFFER_SIZE > 0 - ring_buffer_t tx_buffer = { { 0 }, 0, 0 }; - #endif - static bool _written; - - #if ENABLED(SERIAL_XON_XOFF) - constexpr uint8_t XON_XOFF_CHAR_SENT = 0x80, // XON / XOFF Character was sent - XON_XOFF_CHAR_MASK = 0x1F; // XON / XOFF character to send - // XON / XOFF character definitions - constexpr uint8_t XON_CHAR = 17, XOFF_CHAR = 19; - uint8_t xon_xoff_state = XON_XOFF_CHAR_SENT | XON_CHAR; - - // Validate that RX buffer size is at least 4096 bytes- According to several experiments, on - // the original Arduino Due that uses a ATmega16U2 as USB to serial bridge, due to the introduced - // latencies, at least 2959 bytes of RX buffering (when transmitting at 250kbits/s) are required - // to avoid overflows. - - #if RX_BUFFER_SIZE < 4096 - #error Arduino DUE requires at least 4096 bytes of RX buffer to avoid buffer overflows when using XON/XOFF handshake - #endif - #endif - - #if ENABLED(SERIAL_STATS_DROPPED_RX) - uint8_t rx_dropped_bytes = 0; - #endif - - #if ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS) - uint8_t rx_buffer_overruns = 0; - #endif - - #if ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS) - uint8_t rx_framing_errors = 0; - #endif - - #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) - ring_buffer_pos_t rx_max_enqueued = 0; - #endif + template + typename MarlinSerial::ring_buffer_r MarlinSerial::rx_buffer = { { 0 }, 0, 0 }; + + template + typename MarlinSerial::ring_buffer_t MarlinSerial::tx_buffer = { { 0 }, 0, 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"); - #if ENABLED(EMERGENCY_PARSER) - #include "../../feature/emergency_parser.h" - #endif + #include "../../feature/emergency_parser.h" // (called with RX interrupts disabled) - FORCE_INLINE void store_rxd_char() { + template + FORCE_INLINE void MarlinSerial::store_rxd_char() { - #if ENABLED(EMERGENCY_PARSER) - static EmergencyParser::State emergency_state; // = EP_RESET - #endif + static EmergencyParser::State emergency_state; // = EP_RESET // Get the tail - Nothing can alter its value while we are at this ISR const ring_buffer_pos_t t = rx_buffer.tail; @@ -131,14 +78,13 @@ 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)(RX_BUFFER_SIZE - 1); + ring_buffer_pos_t i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(RX_SIZE - 1); // Read the character from the USART uint8_t c = HWUART->UART_RHR; - #if ENABLED(EMERGENCY_PARSER) + if (USE_EMERGENCYPARSER) emergency_parser.update(emergency_state, c); - #endif // 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 @@ -147,29 +93,29 @@ rx_buffer.buffer[h] = c; h = i; } - #if ENABLED(SERIAL_STATS_DROPPED_RX) - else if (!++rx_dropped_bytes) --rx_dropped_bytes; - #endif + else { + if (STATS_DROPPED_RX) + if (!++rx_dropped_bytes) --rx_dropped_bytes; + } - #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) - const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1); - // 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)(RX_SIZE - 1); + // Calculate count of bytes stored into the RX buffer - // Keep track of the maximum count of enqueued bytes + // Keep track of the maximum count of enqueued bytes + if (STATS_MAX_RX_QUEUED) NOLESS(rx_max_enqueued, rx_count); - #endif - #if ENABLED(SERIAL_XON_XOFF) + if (USE_XONOFF) { // If the last char that was sent was an XON if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XON_CHAR) { // Bytes stored into the RX buffer - const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1); + const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(RX_SIZE - 1); // 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 >= (RX_BUFFER_SIZE) / 8) { + if (rx_count >= (RX_SIZE) / 8) { // 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 @@ -189,14 +135,13 @@ if (status & UART_SR_RXRDY) { // We received a char while waiting for the TX buffer to be empty - Receive and process it! - i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1); + i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(RX_SIZE - 1); // Read the character from the USART c = HWUART->UART_RHR; - #if ENABLED(EMERGENCY_PARSER) + if (USE_EMERGENCYPARSER) emergency_parser.update(emergency_state, c); - #endif // 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 @@ -205,9 +150,10 @@ rx_buffer.buffer[h] = c; h = i; } - #if ENABLED(SERIAL_STATS_DROPPED_RX) - else if (!++rx_dropped_bytes) --rx_dropped_bytes; - #endif + else { + if (STATS_DROPPED_RX) + if (!++rx_dropped_bytes) --rx_dropped_bytes; + } } sw_barrier(); } @@ -226,14 +172,13 @@ if (status & UART_SR_RXRDY) { // 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)(RX_BUFFER_SIZE - 1); + i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(RX_SIZE - 1); // Read the character from the USART c = HWUART->UART_RHR; - #if ENABLED(EMERGENCY_PARSER) + if (USE_EMERGENCYPARSER) emergency_parser.update(emergency_state, c); - #endif // 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 @@ -242,9 +187,10 @@ rx_buffer.buffer[h] = c; h = i; } - #if ENABLED(SERIAL_STATS_DROPPED_RX) - else if (!++rx_dropped_bytes) --rx_dropped_bytes; - #endif + else { + if (STATS_DROPPED_RX) + if (!++rx_dropped_bytes) --rx_dropped_bytes; + } } sw_barrier(); } @@ -253,35 +199,35 @@ // have any issues writing to the UART TX register if it needs to! } } - #endif // SERIAL_XON_XOFF + } // Store the new head value rx_buffer.head = h; } - #if TX_BUFFER_SIZE > 0 - - FORCE_INLINE void _tx_thr_empty_irq(void) { + template + FORCE_INLINE void MarlinSerial::_tx_thr_empty_irq(void) { + if (TX_SIZE > 0) { // Read positions uint8_t t = tx_buffer.tail; const uint8_t h = tx_buffer.head; - - #if ENABLED(SERIAL_XON_XOFF) + + if (USE_XONOFF) { // If an XON char is pending to be sent, do it now if (xon_xoff_state == XON_CHAR) { - + // Send the character HWUART->UART_THR = XON_CHAR; - + // Remember we sent it. xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT; - + // If nothing else to transmit, just disable TX interrupts. if (h == t) HWUART->UART_IDR = UART_IDR_TXRDY; - + return; } - #endif + } // If nothing to transmit, just disable TX interrupts. This could // happen as the result of the non atomicity of the disabling of RX @@ -293,41 +239,35 @@ // There is something to TX, Send the next byte const uint8_t c = tx_buffer.buffer[t]; - t = (t + 1) & (TX_BUFFER_SIZE - 1); + t = (t + 1) & (TX_SIZE - 1); HWUART->UART_THR = c; tx_buffer.tail = t; // Disable interrupts if there is nothing to transmit following this byte if (h == t) HWUART->UART_IDR = UART_IDR_TXRDY; } + } - #endif // TX_BUFFER_SIZE > 0 - - static void UART_ISR(void) { + template + void MarlinSerial::UART_ISR(void) { const uint32_t status = HWUART->UART_SR; // Data received? if (status & UART_SR_RXRDY) store_rxd_char(); - #if TX_BUFFER_SIZE > 0 + if (TX_SIZE > 0) { // Something to send, and TX interrupts are enabled (meaning something to send)? if ((status & UART_SR_TXRDY) && (HWUART->UART_IMR & UART_IMR_TXRDY)) _tx_thr_empty_irq(); - #endif + } // Acknowledge errors if ((status & UART_SR_OVRE) || (status & UART_SR_FRAME)) { - - #if ENABLED(SERIAL_STATS_DROPPED_RX) + if (STATS_DROPPED_RX) if (status & UART_SR_OVRE && !++rx_dropped_bytes) --rx_dropped_bytes; - #endif - - #if ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS) + if (STATS_RX_OVERRUNS) if (status & UART_SR_OVRE && !++rx_buffer_overruns) --rx_buffer_overruns; - #endif - - #if ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS) + if (STATS_RX_FRAMING_ERRORS) if (status & UART_SR_FRAME && !++rx_framing_errors) --rx_framing_errors; - #endif // TODO: error reporting outside ISR HWUART->UART_CR = UART_CR_RSTSTA; @@ -335,8 +275,8 @@ } // Public Methods - - void MarlinSerial::begin(const long baud_setting) { + template + void MarlinSerial::begin(const long baud_setting) { // Disable UART interrupt in NVIC NVIC_DisableIRQ( HWUART_IRQ ); @@ -382,12 +322,12 @@ // Enable receiver and transmitter HWUART->UART_CR = UART_CR_RXEN | UART_CR_TXEN; - #if TX_BUFFER_SIZE > 0 + if (TX_SIZE > 0) _written = false; - #endif } - void MarlinSerial::end() { + template + void MarlinSerial::end() { // Disable UART interrupt in NVIC NVIC_DisableIRQ( HWUART_IRQ ); @@ -399,12 +339,14 @@ pmc_disable_periph_clk( HWUART_IRQ_ID ); } - int MarlinSerial::peek(void) { + template + int MarlinSerial::peek(void) { const int v = rx_buffer.head == rx_buffer.tail ? -1 : rx_buffer.buffer[rx_buffer.tail]; return v; } - int MarlinSerial::read(void) { + template + int MarlinSerial::read(void) { const ring_buffer_pos_t h = rx_buffer.head; ring_buffer_pos_t t = rx_buffer.tail; @@ -412,65 +354,72 @@ if (h == t) return -1; int v = rx_buffer.buffer[t]; - t = (ring_buffer_pos_t)(t + 1) & (RX_BUFFER_SIZE - 1); + t = (ring_buffer_pos_t)(t + 1) & (RX_SIZE - 1); // Advance tail rx_buffer.tail = t; - #if ENABLED(SERIAL_XON_XOFF) + if (USE_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)(RX_BUFFER_SIZE - 1); + const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(RX_SIZE - 1); // When below 10% of RX buffer capacity, send XON before running out of RX buffer bytes - if (rx_count < (RX_BUFFER_SIZE) / 10) { - #if TX_BUFFER_SIZE > 0 + if (rx_count < (RX_SIZE) / 10) { + if (TX_SIZE > 0) { // Signal we want an XON character to be sent. xon_xoff_state = XON_CHAR; // Enable TX isr. HWUART->UART_IER = UART_IER_TXRDY; - #else + } else { // If not using TX interrupts, we must send the XON char now xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT; while (!(HWUART->UART_SR & UART_SR_TXRDY)) sw_barrier(); HWUART->UART_THR = XON_CHAR; - #endif + } } } - #endif + } return v; } - ring_buffer_pos_t MarlinSerial::available(void) { + template + typename MarlinSerial::ring_buffer_pos_t MarlinSerial::available(void) { const ring_buffer_pos_t h = rx_buffer.head, t = rx_buffer.tail; - return (ring_buffer_pos_t)(RX_BUFFER_SIZE + h - t) & (RX_BUFFER_SIZE - 1); + return (ring_buffer_pos_t)(RX_SIZE + h - t) & (RX_SIZE - 1); } - void MarlinSerial::flush(void) { + template + void MarlinSerial::flush(void) { rx_buffer.tail = rx_buffer.head; - #if ENABLED(SERIAL_XON_XOFF) + if (USE_XONOFF) { if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) { - #if TX_BUFFER_SIZE > 0 + if (TX_SIZE > 0) { // Signal we want an XON character to be sent. xon_xoff_state = XON_CHAR; // Enable TX isr. HWUART->UART_IER = UART_IER_TXRDY; - #else + } else { // If not using TX interrupts, we must send the XON char now xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT; while (!(HWUART->UART_SR & UART_SR_TXRDY)) sw_barrier(); HWUART->UART_THR = XON_CHAR; - #endif + } } - #endif + } } - #if TX_BUFFER_SIZE > 0 - void MarlinSerial::write(const uint8_t c) { - _written = true; + template + void MarlinSerial::write(const uint8_t c) { + _written = true; + if (TX_SIZE == 0) { + while (!(HWUART->UART_SR & UART_SR_TXRDY)) sw_barrier(); + HWUART->UART_THR = c; + } else { + // 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 @@ -482,12 +431,12 @@ HWUART->UART_THR = c; return; } - - const uint8_t i = (tx_buffer.head + 1) & (TX_BUFFER_SIZE - 1); - + + const uint8_t i = (tx_buffer.head + 1) & (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. @@ -500,87 +449,85 @@ // 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 HWUART->UART_IER = UART_IER_TXRDY; } + } + + template + void MarlinSerial::flushTX(void) { + // TX + + if (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 (!(HWUART->UART_SR & UART_SR_TXEMPTY)) sw_barrier(); - void MarlinSerial::flushTX(void) { - // TX + // At this point nothing is queued anymore (DRIE is disabled) and + // the hardware finished transmission (TXC is set). + } else { // If we have never written a byte, no need to flush. This special // case is needed since there is 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 || !(HWUART->UART_SR & UART_SR_TXEMPTY)) { // If there is more space, send an extra character if (HWUART->UART_SR & UART_SR_TXRDY) _tx_thr_empty_irq(); sw_barrier(); } - + } else { // Wait until everything was transmitted while (tx_buffer.head != tx_buffer.tail || !(HWUART->UART_SR & UART_SR_TXEMPTY)) sw_barrier(); } - + // At this point nothing is queued anymore (DRIE is disabled) and // the hardware finished transmission (TXC is set). } + } - #else // TX_BUFFER_SIZE == 0 - - void MarlinSerial::write(const uint8_t c) { - _written = true; - while (!(HWUART->UART_SR & UART_SR_TXRDY)) sw_barrier(); - HWUART->UART_THR = c; - } - - void MarlinSerial::flushTX(void) { - // TX - - // 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 (!(HWUART->UART_SR & UART_SR_TXEMPTY)) sw_barrier(); - - // At this point nothing is queued anymore (DRIE is disabled) and - // the hardware finished transmission (TXC is set). - } - #endif // TX_BUFFER_SIZE == 0 - + /** * Imports from print.h */ - void MarlinSerial::print(char c, int base) { + template + void MarlinSerial::print(char c, int base) { print((long)c, base); } - void MarlinSerial::print(unsigned char b, int base) { + template + void MarlinSerial::print(unsigned char b, int base) { print((unsigned long)b, base); } - void MarlinSerial::print(int n, int base) { + template + void MarlinSerial::print(int n, int base) { print((long)n, base); } - void MarlinSerial::print(unsigned int n, int base) { + template + void MarlinSerial::print(unsigned int n, int base) { print((unsigned long)n, base); } - void MarlinSerial::print(long n, int base) { + template + void MarlinSerial::print(long n, int base) { if (base == 0) write(n); else if (base == 10) { if (n < 0) { print('-'); n = -n; } @@ -590,68 +537,80 @@ printNumber(n, base); } - void MarlinSerial::print(unsigned long n, int base) { + template + void MarlinSerial::print(unsigned long n, int base) { if (base == 0) write(n); else printNumber(n, base); } - void MarlinSerial::print(double n, int digits) { + template + void MarlinSerial::print(double n, int digits) { printFloat(n, digits); } - void MarlinSerial::println(void) { + template + void MarlinSerial::println(void) { print('\r'); print('\n'); } - void MarlinSerial::println(const String& s) { + template + void MarlinSerial::println(const String& s) { print(s); println(); } - void MarlinSerial::println(const char c[]) { + template + void MarlinSerial::println(const char c[]) { print(c); println(); } - void MarlinSerial::println(char c, int base) { + template + void MarlinSerial::println(char c, int base) { print(c, base); println(); } - void MarlinSerial::println(unsigned char b, int base) { + template + void MarlinSerial::println(unsigned char b, int base) { print(b, base); println(); } - void MarlinSerial::println(int n, int base) { + template + void MarlinSerial::println(int n, int base) { print(n, base); println(); } - void MarlinSerial::println(unsigned int n, int base) { + template + void MarlinSerial::println(unsigned int n, int base) { print(n, base); println(); } - void MarlinSerial::println(long n, int base) { + template + void MarlinSerial::println(long n, int base) { print(n, base); println(); } - void MarlinSerial::println(unsigned long n, int base) { + template + void MarlinSerial::println(unsigned long n, int base) { print(n, base); println(); } - void MarlinSerial::println(double n, int digits) { + template + void MarlinSerial::println(double n, int digits) { print(n, digits); println(); } // Private Methods - - void MarlinSerial::printNumber(unsigned long n, uint8_t base) { + 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; @@ -666,7 +625,8 @@ print('0'); } - void MarlinSerial::printFloat(double number, uint8_t digits) { + template + void MarlinSerial::printFloat(double number, uint8_t digits) { // Handle negative numbers if (number < 0.0) { print('-'); @@ -696,8 +656,30 @@ } } + template class MarlinSerial< + SERIAL_PORT, + RX_BUFFER_SIZE, + TX_BUFFER_SIZE, + ENABLED(SERIAL_XON_XOFF), + ENABLED(EMERGENCY_PARSER), + ENABLED(SERIAL_STATS_DROPPED_RX), + ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS), + ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS), + ENABLED(SERIAL_STATS_MAX_RX_QUEUED) + >; + // Preinstantiate - MarlinSerial customizedSerial; + MarlinSerial< + SERIAL_PORT, + RX_BUFFER_SIZE, + TX_BUFFER_SIZE, + ENABLED(SERIAL_XON_XOFF), + ENABLED(EMERGENCY_PARSER), + ENABLED(SERIAL_STATS_DROPPED_RX), + ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS), + ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS), + ENABLED(SERIAL_STATS_MAX_RX_QUEUED) + > customizedSerial; #endif #endif // ARDUINO_ARCH_SAM diff --git a/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h b/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h index 2f5a07f515e4..5b6008e55d6b 100644 --- a/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h +++ b/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h @@ -60,29 +60,98 @@ // #error "TX_BUFFER_SIZE must be 0, a power of 2 greater than 1, and no greater than 256." //#endif -#if RX_BUFFER_SIZE > 256 - typedef uint16_t ring_buffer_pos_t; -#else - typedef uint8_t ring_buffer_pos_t; -#endif +// Templated type selector +template struct TypeSelector { typedef T type;} ; +template struct TypeSelector { typedef F type; }; + +// Templated structure wrapper +template struct StructWrapper { + constexpr StructWrapper(int) {} + S* operator->() const { return (S*)addr; } +}; -#if ENABLED(SERIAL_STATS_DROPPED_RX) - extern uint8_t rx_dropped_bytes; -#endif +// Hardware serial port information (by template specialization) +template struct MarlinSerialPortInfo {}; +template<> struct MarlinSerialPortInfo<0> { + static constexpr unsigned int BASE = 0x400E0800U; // UART + static constexpr IRQn_Type IRQ = UART_IRQn; + static constexpr int IRQ_ID = ID_UART; +}; -#if ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS) - extern uint8_t rx_buffer_overruns; -#endif +template<> struct MarlinSerialPortInfo<1> { + static constexpr unsigned int BASE = 0x40098000U; // USART0 + static constexpr IRQn_Type IRQ = USART0_IRQn; + static constexpr int IRQ_ID = ID_USART0; +}; -#if ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS) - extern uint8_t rx_framing_errors; -#endif +template<> struct MarlinSerialPortInfo<2> { + static constexpr unsigned int BASE = 0x4009C000U; // USART1 + static constexpr IRQn_Type IRQ = USART1_IRQn; + static constexpr int IRQ_ID = ID_USART1; +}; + +template<> struct MarlinSerialPortInfo<3> { + static constexpr unsigned int BASE = 0x400A0000U; // USART2 + static constexpr IRQn_Type IRQ = USART2_IRQn; + static constexpr int IRQ_ID = ID_USART2; +}; + +template<> struct MarlinSerialPortInfo<4> { + static constexpr unsigned int BASE = 0x400A4000U; // USART3 + static constexpr IRQn_Type IRQ = USART3_IRQn; + static constexpr int IRQ_ID = ID_USART3; +}; -#if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) - extern ring_buffer_pos_t rx_max_enqueued; -#endif +template class MarlinSerial { +protected: + // Alias for shorter code + static constexpr StructWrapper::BASE> HWUART = 0; + static constexpr IRQn_Type HWUART_IRQ = MarlinSerialPortInfo::IRQ; + static constexpr int HWUART_IRQ_ID = MarlinSerialPortInfo::IRQ_ID; + + // Base size of type on buffer size + typedef typename TypeSelector<(RX_SIZE>256), uint16_t, uint8_t>::type ring_buffer_pos_t; + + struct ring_buffer_r { + unsigned char buffer[RX_SIZE]; + volatile ring_buffer_pos_t head, tail; + }; + + struct ring_buffer_t { + unsigned char buffer[TX_SIZE]; + volatile uint8_t head, tail; + }; + + static ring_buffer_r rx_buffer; + static ring_buffer_t tx_buffer; + static bool _written; + + static constexpr uint8_t XON_XOFF_CHAR_SENT = 0x80, // XON / XOFF Character was sent + XON_XOFF_CHAR_MASK = 0x1F; // XON / XOFF character to send + + // XON / XOFF character definitions + static constexpr uint8_t XON_CHAR = 17, XOFF_CHAR = 19; + static uint8_t xon_xoff_state; + + static uint8_t rx_dropped_bytes; + static uint8_t rx_buffer_overruns; + static uint8_t rx_framing_errors; + static ring_buffer_pos_t rx_max_enqueued; + + FORCE_INLINE static void store_rxd_char(); + FORCE_INLINE static void _tx_thr_empty_irq(void); + static void UART_ISR(void); public: MarlinSerial() {}; @@ -95,21 +164,10 @@ class MarlinSerial { static void write(const uint8_t c); static void flushTX(void); - #if ENABLED(SERIAL_STATS_DROPPED_RX) - FORCE_INLINE static uint32_t dropped() { return rx_dropped_bytes; } - #endif - - #if ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS) - FORCE_INLINE static uint32_t buffer_overruns() { return rx_buffer_overruns; } - #endif - - #if ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS) - FORCE_INLINE static uint32_t framing_errors() { return rx_framing_errors; } - #endif - - #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) - FORCE_INLINE static ring_buffer_pos_t rxMaxEnqueued() { return rx_max_enqueued; } - #endif + FORCE_INLINE static uint8_t dropped() { return STATS_DROPPED_RX ? rx_dropped_bytes : 0; } + FORCE_INLINE static uint8_t buffer_overruns() { return STATS_RX_OVERRUNS ? rx_buffer_overruns : 0; } + FORCE_INLINE static uint8_t framing_errors() { return STATS_RX_FRAMING_ERRORS ? rx_framing_errors : 0; } + FORCE_INLINE static ring_buffer_pos_t rxMaxEnqueued() { return STATS_MAX_RX_QUEUED ? rx_max_enqueued : 0; } FORCE_INLINE static void write(const char* str) { while (*str) write(*str++); } FORCE_INLINE static void write(const uint8_t* buffer, size_t size) { while (size--) write(*buffer++); } @@ -141,7 +199,34 @@ class MarlinSerial { static void printFloat(double, uint8_t); }; -extern MarlinSerial customizedSerial; +// Make sure ENABLED() evaluates to 0 if feature disabled +#ifndef SERIAL_XON_XOFF + #define SERIAL_XON_XOFF 0 +#endif +#ifndef EMERGENCY_PARSER + #define EMERGENCY_PARSER 0 +#endif +#ifndef SERIAL_STATS_DROPPED_RX + #define SERIAL_STATS_DROPPED_RX 0 +#endif +#ifndef SERIAL_STATS_RX_BUFFER_OVERRUNS + #define SERIAL_STATS_RX_BUFFER_OVERRUNS 0 +#endif +#ifndef SERIAL_STATS_MAX_RX_QUEUED + #define SERIAL_STATS_MAX_RX_QUEUED 0 +#endif + +extern MarlinSerial< + SERIAL_PORT, + RX_BUFFER_SIZE, + TX_BUFFER_SIZE, + ENABLED(SERIAL_XON_XOFF), + ENABLED(EMERGENCY_PARSER), + ENABLED(SERIAL_STATS_DROPPED_RX), + ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS), + ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS), + ENABLED(SERIAL_STATS_MAX_RX_QUEUED) +> customizedSerial; #endif // SERIAL_PORT >= 0 From d7ebe7e175af6894748d9cbd5b46ea3b5e8b9191 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 2 Oct 2018 05:39:49 -0500 Subject: [PATCH 3/7] Fix MarlinSerial instantiation, etc. --- Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp | 54 ++++---- Marlin/src/HAL/HAL_AVR/MarlinSerial.h | 43 ++----- Marlin/src/HAL/HAL_DUE/MarlinSerialUSB_Due.h | 4 +- Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp | 126 +++++++++---------- Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h | 67 ++++------ Marlin/src/HAL/shared/MarlinSerial.h | 60 +++++++++ 6 files changed, 190 insertions(+), 164 deletions(-) create mode 100644 Marlin/src/HAL/shared/MarlinSerial.h diff --git a/Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp b/Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp index cdb0531fecdd..5454815a00d4 100644 --- a/Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp +++ b/Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp @@ -74,7 +74,7 @@ // "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 + template FORCE_INLINE typename MarlinSerial::ring_buffer_pos_t MarlinSerial::atomic_read_rx_head() { if (RX_SIZE > 256) { // Keep reading until 2 consecutive reads return the same value, @@ -96,9 +96,9 @@ } } - template + template volatile bool MarlinSerial::rx_tail_value_not_stable = false; - template + template volatile uint16_t MarlinSerial::rx_tail_value_backup = 0; // Set RX tail index, taking into account the RX ISR could interrupt @@ -737,12 +737,12 @@ SERIAL_PORT, RX_BUFFER_SIZE, TX_BUFFER_SIZE, - ENABLED(SERIAL_XON_XOFF), - ENABLED(EMERGENCY_PARSER), - ENABLED(SERIAL_STATS_DROPPED_RX), - ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS), - ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS), - ENABLED(SERIAL_STATS_MAX_RX_QUEUED) + bSERIAL_XON_XOFF, + bEMERGENCY_PARSER, + bSERIAL_STATS_DROPPED_RX, + bSERIAL_STATS_RX_BUFFER_OVERRUNS, + bSERIAL_STATS_RX_FRAMING_ERRORS, + bSERIAL_STATS_MAX_RX_QUEUED >::store_rxd_char(); } @@ -751,12 +751,12 @@ SERIAL_PORT, RX_BUFFER_SIZE, TX_BUFFER_SIZE, - ENABLED(SERIAL_XON_XOFF), - ENABLED(EMERGENCY_PARSER), - ENABLED(SERIAL_STATS_DROPPED_RX), - ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS), - ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS), - ENABLED(SERIAL_STATS_MAX_RX_QUEUED) + bSERIAL_XON_XOFF, + bEMERGENCY_PARSER, + bSERIAL_STATS_DROPPED_RX, + bSERIAL_STATS_RX_BUFFER_OVERRUNS, + bSERIAL_STATS_RX_FRAMING_ERRORS, + bSERIAL_STATS_MAX_RX_QUEUED >::_tx_udr_empty_irq(); } @@ -765,12 +765,12 @@ SERIAL_PORT, RX_BUFFER_SIZE, TX_BUFFER_SIZE, - ENABLED(SERIAL_XON_XOFF), - ENABLED(EMERGENCY_PARSER), - ENABLED(SERIAL_STATS_DROPPED_RX), - ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS), - ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS), - ENABLED(SERIAL_STATS_MAX_RX_QUEUED) + bSERIAL_XON_XOFF, + bEMERGENCY_PARSER, + bSERIAL_STATS_DROPPED_RX, + bSERIAL_STATS_RX_BUFFER_OVERRUNS, + bSERIAL_STATS_RX_FRAMING_ERRORS, + bSERIAL_STATS_MAX_RX_QUEUED >; // Instantiate @@ -778,12 +778,12 @@ SERIAL_PORT, RX_BUFFER_SIZE, TX_BUFFER_SIZE, - ENABLED(SERIAL_XON_XOFF), - ENABLED(EMERGENCY_PARSER), - ENABLED(SERIAL_STATS_DROPPED_RX), - ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS), - ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS), - ENABLED(SERIAL_STATS_MAX_RX_QUEUED) + bSERIAL_XON_XOFF, + bEMERGENCY_PARSER, + bSERIAL_STATS_DROPPED_RX, + bSERIAL_STATS_RX_BUFFER_OVERRUNS, + bSERIAL_STATS_RX_FRAMING_ERRORS, + bSERIAL_STATS_MAX_RX_QUEUED > customizedSerial; #endif // !USBCON && (UBRRH || UBRR0H || UBRR1H || UBRR2H || UBRR3H) diff --git a/Marlin/src/HAL/HAL_AVR/MarlinSerial.h b/Marlin/src/HAL/HAL_AVR/MarlinSerial.h index 4453ab4b4599..878979702368 100644 --- a/Marlin/src/HAL/HAL_AVR/MarlinSerial.h +++ b/Marlin/src/HAL/HAL_AVR/MarlinSerial.h @@ -33,7 +33,7 @@ #ifndef _MARLINSERIAL_H_ #define _MARLINSERIAL_H_ -#include "../../inc/MarlinConfigPre.h" +#include "../shared/MarlinSerial.h" #include @@ -148,7 +148,8 @@ template struct TypeSelector { typedef T type;} ; template struct TypeSelector { typedef F type; }; - template customizedSerial; #endif // !USBCON diff --git a/Marlin/src/HAL/HAL_DUE/MarlinSerialUSB_Due.h b/Marlin/src/HAL/HAL_DUE/MarlinSerialUSB_Due.h index bfa2ccedc040..925c322cfdc2 100644 --- a/Marlin/src/HAL/HAL_DUE/MarlinSerialUSB_Due.h +++ b/Marlin/src/HAL/HAL_DUE/MarlinSerialUSB_Due.h @@ -52,11 +52,11 @@ class MarlinSerialUSB { static void write(const uint8_t c); #if ENABLED(SERIAL_STATS_DROPPED_RX) - FORCE_INLINE static uint32_t dropped() { return 0; } + FORCE_INLINE static uint32_t dropped() { return 0; } #endif #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) - FORCE_INLINE static int rxMaxEnqueued() { return 0; } + FORCE_INLINE static int rxMaxEnqueued() { return 0; } #endif FORCE_INLINE static void write(const char* str) { while (*str) write(*str++); } diff --git a/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp b/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp index 3bd59606e4e0..13b7b76a83f5 100644 --- a/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp +++ b/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp @@ -66,7 +66,7 @@ #include "../../feature/emergency_parser.h" // (called with RX interrupts disabled) - template + template FORCE_INLINE void MarlinSerial::store_rxd_char() { static EmergencyParser::State emergency_state; // = EP_RESET @@ -205,26 +205,26 @@ rx_buffer.head = h; } - template + template FORCE_INLINE void MarlinSerial::_tx_thr_empty_irq(void) { if (TX_SIZE > 0) { // Read positions uint8_t t = tx_buffer.tail; const uint8_t h = tx_buffer.head; - + if (USE_XONOFF) { // If an XON char is pending to be sent, do it now if (xon_xoff_state == XON_CHAR) { - + // Send the character HWUART->UART_THR = XON_CHAR; - + // Remember we sent it. xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT; - + // If nothing else to transmit, just disable TX interrupts. if (h == t) HWUART->UART_IDR = UART_IDR_TXRDY; - + return; } } @@ -248,7 +248,7 @@ } } - template + template void MarlinSerial::UART_ISR(void) { const uint32_t status = HWUART->UART_SR; @@ -275,7 +275,7 @@ } // Public Methods - template + template void MarlinSerial::begin(const long baud_setting) { // Disable UART interrupt in NVIC @@ -326,7 +326,7 @@ _written = false; } - template + template void MarlinSerial::end() { // Disable UART interrupt in NVIC NVIC_DisableIRQ( HWUART_IRQ ); @@ -339,13 +339,13 @@ pmc_disable_periph_clk( HWUART_IRQ_ID ); } - template + template int MarlinSerial::peek(void) { const int v = rx_buffer.head == rx_buffer.tail ? -1 : rx_buffer.buffer[rx_buffer.tail]; return v; } - template + template int MarlinSerial::read(void) { const ring_buffer_pos_t h = rx_buffer.head; @@ -384,13 +384,13 @@ return v; } - template + template typename MarlinSerial::ring_buffer_pos_t MarlinSerial::available(void) { const ring_buffer_pos_t h = rx_buffer.head, t = rx_buffer.tail; return (ring_buffer_pos_t)(RX_SIZE + h - t) & (RX_SIZE - 1); } - template + template void MarlinSerial::flush(void) { rx_buffer.tail = rx_buffer.head; @@ -411,7 +411,7 @@ } } - template + template void MarlinSerial::write(const uint8_t c) { _written = true; @@ -419,7 +419,7 @@ while (!(HWUART->UART_SR & UART_SR_TXRDY)) sw_barrier(); HWUART->UART_THR = c; } else { - + // 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 @@ -431,12 +431,12 @@ HWUART->UART_THR = c; return; } - + const uint8_t i = (tx_buffer.head + 1) & (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. @@ -449,17 +449,17 @@ // 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 HWUART->UART_IER = UART_IER_TXRDY; } } - template + template void MarlinSerial::flushTX(void) { // TX @@ -479,54 +479,54 @@ // case is needed since there is 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 || !(HWUART->UART_SR & UART_SR_TXEMPTY)) { // If there is more space, send an extra character if (HWUART->UART_SR & UART_SR_TXRDY) _tx_thr_empty_irq(); sw_barrier(); } - + } else { // Wait until everything was transmitted while (tx_buffer.head != tx_buffer.tail || !(HWUART->UART_SR & UART_SR_TXEMPTY)) 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 + template void MarlinSerial::print(char c, int base) { print((long)c, base); } - template + template void MarlinSerial::print(unsigned char b, int base) { print((unsigned long)b, base); } - template + template void MarlinSerial::print(int n, int base) { print((long)n, base); } - template + template void MarlinSerial::print(unsigned int n, int base) { print((unsigned long)n, base); } - template + template void MarlinSerial::print(long n, int base) { if (base == 0) write(n); else if (base == 10) { @@ -537,79 +537,79 @@ printNumber(n, base); } - template + template void MarlinSerial::print(unsigned long n, int base) { if (base == 0) write(n); else printNumber(n, base); } - template + template void MarlinSerial::print(double n, int digits) { printFloat(n, digits); } - template + template void MarlinSerial::println(void) { print('\r'); print('\n'); } - template + template void MarlinSerial::println(const String& s) { print(s); println(); } - template + template void MarlinSerial::println(const char c[]) { print(c); println(); } - template + template void MarlinSerial::println(char c, int base) { print(c, base); println(); } - template + template void MarlinSerial::println(unsigned char b, int base) { print(b, base); println(); } - template + template void MarlinSerial::println(int n, int base) { print(n, base); println(); } - template + template void MarlinSerial::println(unsigned int n, int base) { print(n, base); println(); } - template + template void MarlinSerial::println(long n, int base) { print(n, base); println(); } - template + template void MarlinSerial::println(unsigned long n, int base) { print(n, base); println(); } - template + template void MarlinSerial::println(double n, int digits) { print(n, digits); println(); } // Private Methods - template + template void MarlinSerial::printNumber(unsigned long n, uint8_t base) { if (n) { unsigned char buf[8 * sizeof(long)]; // Enough space for base 2 @@ -625,7 +625,7 @@ print('0'); } - template + template void MarlinSerial::printFloat(double number, uint8_t digits) { // Handle negative numbers if (number < 0.0) { @@ -658,27 +658,27 @@ template class MarlinSerial< SERIAL_PORT, - RX_BUFFER_SIZE, - TX_BUFFER_SIZE, - ENABLED(SERIAL_XON_XOFF), - ENABLED(EMERGENCY_PARSER), - ENABLED(SERIAL_STATS_DROPPED_RX), - ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS), - ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS), - ENABLED(SERIAL_STATS_MAX_RX_QUEUED) + RX_BUFFER_SIZE, + TX_BUFFER_SIZE, + bSERIAL_XON_XOFF, + bEMERGENCY_PARSER, + bSERIAL_STATS_DROPPED_RX, + bSERIAL_STATS_RX_BUFFER_OVERRUNS, + bSERIAL_STATS_RX_FRAMING_ERRORS, + bSERIAL_STATS_MAX_RX_QUEUED >; - + // Preinstantiate MarlinSerial< SERIAL_PORT, - RX_BUFFER_SIZE, - TX_BUFFER_SIZE, - ENABLED(SERIAL_XON_XOFF), - ENABLED(EMERGENCY_PARSER), - ENABLED(SERIAL_STATS_DROPPED_RX), - ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS), - ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS), - ENABLED(SERIAL_STATS_MAX_RX_QUEUED) + RX_BUFFER_SIZE, + TX_BUFFER_SIZE, + bSERIAL_XON_XOFF, + bEMERGENCY_PARSER, + bSERIAL_STATS_DROPPED_RX, + bSERIAL_STATS_RX_BUFFER_OVERRUNS, + bSERIAL_STATS_RX_FRAMING_ERRORS, + bSERIAL_STATS_MAX_RX_QUEUED > customizedSerial; #endif diff --git a/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h b/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h index 5b6008e55d6b..45ed31130e6b 100644 --- a/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h +++ b/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h @@ -29,7 +29,7 @@ #ifndef MARLINSERIAL_DUE_H #define MARLINSERIAL_DUE_H -#include "../../inc/MarlinConfig.h" +#include "../shared/MarlinSerial.h" #if SERIAL_PORT >= 0 @@ -67,46 +67,47 @@ template struct TypeSelector { typedef F ty // Templated structure wrapper template struct StructWrapper { constexpr StructWrapper(int) {} - S* operator->() const { return (S*)addr; } + S* operator->() const { return (S*)addr; } }; // Hardware serial port information (by template specialization) template struct MarlinSerialPortInfo {}; -template<> struct MarlinSerialPortInfo<0> { +template<> struct MarlinSerialPortInfo<0> { static constexpr unsigned int BASE = 0x400E0800U; // UART static constexpr IRQn_Type IRQ = UART_IRQn; static constexpr int IRQ_ID = ID_UART; }; -template<> struct MarlinSerialPortInfo<1> { +template<> struct MarlinSerialPortInfo<1> { static constexpr unsigned int BASE = 0x40098000U; // USART0 static constexpr IRQn_Type IRQ = USART0_IRQn; static constexpr int IRQ_ID = ID_USART0; }; -template<> struct MarlinSerialPortInfo<2> { +template<> struct MarlinSerialPortInfo<2> { static constexpr unsigned int BASE = 0x4009C000U; // USART1 static constexpr IRQn_Type IRQ = USART1_IRQn; static constexpr int IRQ_ID = ID_USART1; }; -template<> struct MarlinSerialPortInfo<3> { +template<> struct MarlinSerialPortInfo<3> { static constexpr unsigned int BASE = 0x400A0000U; // USART2 static constexpr IRQn_Type IRQ = USART2_IRQn; static constexpr int IRQ_ID = ID_USART2; }; -template<> struct MarlinSerialPortInfo<4> { +template<> struct MarlinSerialPortInfo<4> { static constexpr unsigned int BASE = 0x400A4000U; // USART3 static constexpr IRQn_Type IRQ = USART3_IRQn; static constexpr int IRQ_ID = ID_USART3; }; -template customizedSerial; #endif // SERIAL_PORT >= 0 diff --git a/Marlin/src/HAL/shared/MarlinSerial.h b/Marlin/src/HAL/shared/MarlinSerial.h new file mode 100644 index 000000000000..10d55e92db41 --- /dev/null +++ b/Marlin/src/HAL/shared/MarlinSerial.h @@ -0,0 +1,60 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +/** + * HAL/shared/MarlinSerial.h + */ + +#include "../../inc/MarlinConfigPre.h" + +constexpr bool + bSERIAL_XON_XOFF = (false + #if ENABLED(SERIAL_XON_XOFF) + || true + #endif + ), + bEMERGENCY_PARSER = (false + #if ENABLED(EMERGENCY_PARSER) + || true + #endif + ), + bSERIAL_STATS_DROPPED_RX = (false + #if ENABLED(SERIAL_STATS_DROPPED_RX) + || true + #endif + ), + bSERIAL_STATS_RX_BUFFER_OVERRUNS = (false + #if ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS) + || true + #endif + ), + bSERIAL_STATS_RX_FRAMING_ERRORS = (false + #if ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS) + || true + #endif + ), + bSERIAL_STATS_MAX_RX_QUEUED = (false + #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) + || true + #endif + ); From bb36e9f1355a66d134c9c896e25186e915ebfec0 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 2 Oct 2018 06:08:57 -0500 Subject: [PATCH 4/7] "too many initializers" workaround --- Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp | 19 +++++++++++-------- Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp | 4 ++-- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp b/Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp index 5454815a00d4..ff337d8c5f29 100644 --- a/Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp +++ b/Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp @@ -43,28 +43,31 @@ #include "../../Marlin.h" template - typename MarlinSerial::ring_buffer_r MarlinSerial::rx_buffer = { { 0 }, 0, 0 }; + typename MarlinSerial::ring_buffer_r + MarlinSerial::rx_buffer; // = { { 0 }, 0, 0 }; template - typename MarlinSerial::ring_buffer_t MarlinSerial::tx_buffer = { { 0 }, 0, 0 }; + typename MarlinSerial::ring_buffer_t + MarlinSerial::tx_buffer; // = { { 0 }, 0, 0 }; template - bool MarlinSerial::_written = false; + bool MarlinSerial::_written = false; template - uint8_t MarlinSerial::xon_xoff_state = MarlinSerial::XON_XOFF_CHAR_SENT | MarlinSerial::XON_CHAR; + uint8_t MarlinSerial::xon_xoff_state = MarlinSerial::XON_XOFF_CHAR_SENT | MarlinSerial::XON_CHAR; template - uint8_t MarlinSerial::rx_dropped_bytes = 0; + uint8_t MarlinSerial::rx_dropped_bytes = 0; template - uint8_t MarlinSerial::rx_buffer_overruns = 0; + uint8_t MarlinSerial::rx_buffer_overruns = 0; template - uint8_t MarlinSerial::rx_framing_errors = 0; + uint8_t MarlinSerial::rx_framing_errors = 0; template - typename MarlinSerial::ring_buffer_pos_t MarlinSerial::rx_max_enqueued = 0; + 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"); diff --git a/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp b/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp index 13b7b76a83f5..9087bebf2ed7 100644 --- a/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp +++ b/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp @@ -37,10 +37,10 @@ #if SERIAL_PORT >= 0 template - typename MarlinSerial::ring_buffer_r MarlinSerial::rx_buffer = { { 0 }, 0, 0 }; + typename MarlinSerial::ring_buffer_r MarlinSerial::rx_buffer; // = { { 0 }, 0, 0 }; template - typename MarlinSerial::ring_buffer_t MarlinSerial::tx_buffer = { { 0 }, 0, 0 }; + typename MarlinSerial::ring_buffer_t MarlinSerial::tx_buffer; // = { { 0 }, 0, 0 }; template bool MarlinSerial::_written = false; From dcf461bbb90a2c2ffb071fef95fa340553a081c2 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 2 Oct 2018 06:35:08 -0500 Subject: [PATCH 5/7] Make template code more readable --- Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp | 170 +++++++++----------- Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp | 157 ++++++++---------- Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h | 1 - Marlin/src/HAL/shared/MarlinSerial.h | 5 + 4 files changed, 152 insertions(+), 181 deletions(-) diff --git a/Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp b/Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp index ff337d8c5f29..2c58f5021abf 100644 --- a/Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp +++ b/Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp @@ -42,32 +42,14 @@ #include "MarlinSerial.h" #include "../../Marlin.h" - template - typename MarlinSerial::ring_buffer_r - MarlinSerial::rx_buffer; // = { { 0 }, 0, 0 }; - - template - typename MarlinSerial::ring_buffer_t - MarlinSerial::tx_buffer; // = { { 0 }, 0, 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; + template typename MarlinSerial::ring_buffer_r MarlinSerial::rx_buffer; // = { { 0 }, 0, 0 }; + template typename MarlinSerial::ring_buffer_t MarlinSerial::tx_buffer; // = { { 0 }, 0, 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"); @@ -77,8 +59,8 @@ // "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() { + template + FORCE_INLINE typename MarlinSerial::ring_buffer_pos_t MarlinSerial::atomic_read_rx_head() { if (RX_SIZE > 256) { // Keep reading until 2 consecutive reads return the same value, // meaning there was no update in-between caused by an interrupt. @@ -99,17 +81,17 @@ } } - template - volatile bool MarlinSerial::rx_tail_value_not_stable = false; - template - volatile uint16_t MarlinSerial::rx_tail_value_backup = 0; + 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) { + template + FORCE_INLINE void MarlinSerial::atomic_set_rx_tail(typename MarlinSerial::ring_buffer_pos_t value) { if (RX_SIZE > 256) { // Store the new value in the backup rx_tail_value_backup = value; @@ -131,8 +113,8 @@ // 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() { + template + FORCE_INLINE typename MarlinSerial::ring_buffer_pos_t MarlinSerial::atomic_read_rx_tail() { if (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; @@ -142,8 +124,8 @@ } // (called with RX interrupts disabled) - template - FORCE_INLINE void MarlinSerial::store_rxd_char() { + template + FORCE_INLINE void MarlinSerial::store_rxd_char() { static EmergencyParser::State emergency_state; // = EP_RESET @@ -300,8 +282,8 @@ } // (called with TX irqs disabled) - template - FORCE_INLINE void MarlinSerial::_tx_udr_empty_irq(void) { + template + FORCE_INLINE void MarlinSerial::_tx_udr_empty_irq(void) { if (TX_SIZE > 0) { // Read positions uint8_t t = tx_buffer.tail; @@ -353,8 +335,8 @@ } // Public Methods - template - void MarlinSerial::begin(const long baud) { + template + void MarlinSerial::begin(const long baud) { uint16_t baud_setting; bool useU2X = true; @@ -386,22 +368,22 @@ _written = false; } - template - void MarlinSerial::end() { + template + void MarlinSerial::end() { B_RXEN = 0; B_TXEN = 0; B_RXCIE = 0; B_UDRIE = 0; } - template - int MarlinSerial::peek(void) { + template + int MarlinSerial::peek(void) { 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(void) { + template + int MarlinSerial::read(void) { 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 @@ -442,14 +424,14 @@ return v; } - template - typename MarlinSerial::ring_buffer_pos_t MarlinSerial::available(void) { + template + typename MarlinSerial::ring_buffer_pos_t MarlinSerial::available(void) { const ring_buffer_pos_t h = atomic_read_rx_head(), t = rx_buffer.tail; return (ring_buffer_pos_t)(RX_SIZE + h - t) & (RX_SIZE - 1); } - template - void MarlinSerial::flush(void) { + template + void MarlinSerial::flush(void) { // Set the tail to the head: // - Read the RX head index in a safe way. (See atomic_read_rx_head.) @@ -475,8 +457,8 @@ } } - template - void MarlinSerial::write(const uint8_t c) { + template + void MarlinSerial::write(const uint8_t c) { if (TX_SIZE == 0) { _written = true; @@ -533,8 +515,8 @@ } } - template - void MarlinSerial::flushTX(void) { + template + void MarlinSerial::flushTX(void) { if (TX_SIZE == 0) { // No bytes written, no need to flush. This special case is needed since there's @@ -581,28 +563,28 @@ * Imports from print.h */ - template - void MarlinSerial::print(char c, int base) { + template + void MarlinSerial::print(char c, int base) { print((long)c, base); } - template - void MarlinSerial::print(unsigned char b, int base) { + template + void MarlinSerial::print(unsigned char b, int base) { print((unsigned long)b, base); } - template - void MarlinSerial::print(int n, int base) { + template + void MarlinSerial::print(int n, int base) { print((long)n, base); } - template - void MarlinSerial::print(unsigned int n, int base) { + template + void MarlinSerial::print(unsigned int n, int base) { print((unsigned long)n, base); } - template - void MarlinSerial::print(long n, int base) { + template + void MarlinSerial::print(long n, int base) { if (base == 0) write(n); else if (base == 10) { if (n < 0) { print('-'); n = -n; } @@ -612,81 +594,81 @@ printNumber(n, base); } - template - void MarlinSerial::print(unsigned long n, int 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) { + template + void MarlinSerial::print(double n, int digits) { printFloat(n, digits); } - template - void MarlinSerial::println(void) { + template + void MarlinSerial::println(void) { print('\r'); print('\n'); } - template - void MarlinSerial::println(const String& s) { + template + void MarlinSerial::println(const String& s) { print(s); println(); } - template - void MarlinSerial::println(const char c[]) { + template + void MarlinSerial::println(const char c[]) { print(c); println(); } - template - void MarlinSerial::println(char c, int base) { + template + void MarlinSerial::println(char c, int base) { print(c, base); println(); } - template - void MarlinSerial::println(unsigned char b, int base) { + template + void MarlinSerial::println(unsigned char b, int base) { print(b, base); println(); } - template - void MarlinSerial::println(int n, int base) { + template + void MarlinSerial::println(int n, int base) { print(n, base); println(); } - template - void MarlinSerial::println(unsigned int n, int base) { + template + void MarlinSerial::println(unsigned int n, int base) { print(n, base); println(); } - template - void MarlinSerial::println(long n, int base) { + template + void MarlinSerial::println(long n, int base) { print(n, base); println(); } - template - void MarlinSerial::println(unsigned long n, int base) { + template + void MarlinSerial::println(unsigned long n, int base) { print(n, base); println(); } - template - void MarlinSerial::println(double n, int digits) { + template + void MarlinSerial::println(double n, int digits) { print(n, digits); println(); } // Private Methods - template - void MarlinSerial::printNumber(unsigned long n, uint8_t base) { + 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; @@ -701,8 +683,8 @@ print('0'); } - template - void MarlinSerial::printFloat(double number, uint8_t digits) { + template + void MarlinSerial::printFloat(double number, uint8_t digits) { // Handle negative numbers if (number < 0.0) { print('-'); diff --git a/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp b/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp index 9087bebf2ed7..2e5e3502ab10 100644 --- a/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp +++ b/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp @@ -29,36 +29,21 @@ #include "../../inc/MarlinConfig.h" -#include "MarlinSerial_Due.h" -#include "InterruptVectors_Due.h" -#include "../../Marlin.h" - // If not using the USB port as serial port #if SERIAL_PORT >= 0 - template - typename MarlinSerial::ring_buffer_r MarlinSerial::rx_buffer; // = { { 0 }, 0, 0 }; - - template - typename MarlinSerial::ring_buffer_t MarlinSerial::tx_buffer; // = { { 0 }, 0, 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; + #include "MarlinSerial_Due.h" + #include "InterruptVectors_Due.h" + #include "../../Marlin.h" - template - typename MarlinSerial::ring_buffer_pos_t MarlinSerial::rx_max_enqueued = 0; + template typename MarlinSerial::ring_buffer_r MarlinSerial::rx_buffer; // = { { 0 }, 0, 0 }; + template typename MarlinSerial::ring_buffer_t MarlinSerial::tx_buffer; // = { { 0 }, 0, 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"); @@ -66,8 +51,8 @@ #include "../../feature/emergency_parser.h" // (called with RX interrupts disabled) - template - FORCE_INLINE void MarlinSerial::store_rxd_char() { + template + FORCE_INLINE void MarlinSerial::store_rxd_char() { static EmergencyParser::State emergency_state; // = EP_RESET @@ -205,8 +190,8 @@ rx_buffer.head = h; } - template - FORCE_INLINE void MarlinSerial::_tx_thr_empty_irq(void) { + template + FORCE_INLINE void MarlinSerial::_tx_thr_empty_irq(void) { if (TX_SIZE > 0) { // Read positions uint8_t t = tx_buffer.tail; @@ -248,8 +233,8 @@ } } - template - void MarlinSerial::UART_ISR(void) { + template + void MarlinSerial::UART_ISR(void) { const uint32_t status = HWUART->UART_SR; // Data received? @@ -275,8 +260,8 @@ } // Public Methods - template - void MarlinSerial::begin(const long baud_setting) { + template + void MarlinSerial::begin(const long baud_setting) { // Disable UART interrupt in NVIC NVIC_DisableIRQ( HWUART_IRQ ); @@ -326,8 +311,8 @@ _written = false; } - template - void MarlinSerial::end() { + template + void MarlinSerial::end() { // Disable UART interrupt in NVIC NVIC_DisableIRQ( HWUART_IRQ ); @@ -339,14 +324,14 @@ pmc_disable_periph_clk( HWUART_IRQ_ID ); } - template - int MarlinSerial::peek(void) { + template + int MarlinSerial::peek(void) { const int v = rx_buffer.head == rx_buffer.tail ? -1 : rx_buffer.buffer[rx_buffer.tail]; return v; } - template - int MarlinSerial::read(void) { + template + int MarlinSerial::read(void) { const ring_buffer_pos_t h = rx_buffer.head; ring_buffer_pos_t t = rx_buffer.tail; @@ -384,14 +369,14 @@ return v; } - template - typename MarlinSerial::ring_buffer_pos_t MarlinSerial::available(void) { + template + typename MarlinSerial::ring_buffer_pos_t MarlinSerial::available(void) { const ring_buffer_pos_t h = rx_buffer.head, t = rx_buffer.tail; return (ring_buffer_pos_t)(RX_SIZE + h - t) & (RX_SIZE - 1); } - template - void MarlinSerial::flush(void) { + template + void MarlinSerial::flush(void) { rx_buffer.tail = rx_buffer.head; if (USE_XONOFF) { @@ -411,8 +396,8 @@ } } - template - void MarlinSerial::write(const uint8_t c) { + template + void MarlinSerial::write(const uint8_t c) { _written = true; if (TX_SIZE == 0) { @@ -459,8 +444,8 @@ } } - template - void MarlinSerial::flushTX(void) { + template + void MarlinSerial::flushTX(void) { // TX if (TX_SIZE == 0) { @@ -506,28 +491,28 @@ * Imports from print.h */ - template - void MarlinSerial::print(char c, int base) { + template + void MarlinSerial::print(char c, int base) { print((long)c, base); } - template - void MarlinSerial::print(unsigned char b, int base) { + template + void MarlinSerial::print(unsigned char b, int base) { print((unsigned long)b, base); } - template - void MarlinSerial::print(int n, int base) { + template + void MarlinSerial::print(int n, int base) { print((long)n, base); } - template - void MarlinSerial::print(unsigned int n, int base) { + template + void MarlinSerial::print(unsigned int n, int base) { print((unsigned long)n, base); } - template - void MarlinSerial::print(long n, int base) { + template + void MarlinSerial::print(long n, int base) { if (base == 0) write(n); else if (base == 10) { if (n < 0) { print('-'); n = -n; } @@ -537,80 +522,80 @@ printNumber(n, base); } - template - void MarlinSerial::print(unsigned long n, int 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) { + template + void MarlinSerial::print(double n, int digits) { printFloat(n, digits); } - template - void MarlinSerial::println(void) { + template + void MarlinSerial::println(void) { print('\r'); print('\n'); } - template - void MarlinSerial::println(const String& s) { + template + void MarlinSerial::println(const String& s) { print(s); println(); } - template - void MarlinSerial::println(const char c[]) { + template + void MarlinSerial::println(const char c[]) { print(c); println(); } - template - void MarlinSerial::println(char c, int base) { + template + void MarlinSerial::println(char c, int base) { print(c, base); println(); } - template - void MarlinSerial::println(unsigned char b, int base) { + template + void MarlinSerial::println(unsigned char b, int base) { print(b, base); println(); } - template - void MarlinSerial::println(int n, int base) { + template + void MarlinSerial::println(int n, int base) { print(n, base); println(); } - template - void MarlinSerial::println(unsigned int n, int base) { + template + void MarlinSerial::println(unsigned int n, int base) { print(n, base); println(); } - template - void MarlinSerial::println(long n, int base) { + template + void MarlinSerial::println(long n, int base) { print(n, base); println(); } - template - void MarlinSerial::println(unsigned long n, int base) { + template + void MarlinSerial::println(unsigned long n, int base) { print(n, base); println(); } - template - void MarlinSerial::println(double n, int digits) { + template + void MarlinSerial::println(double n, int digits) { print(n, digits); println(); } // Private Methods - template - void MarlinSerial::printNumber(unsigned long n, uint8_t base) { + 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; @@ -625,8 +610,8 @@ print('0'); } - template - void MarlinSerial::printFloat(double number, uint8_t digits) { + template + void MarlinSerial::printFloat(double number, uint8_t digits) { // Handle negative numbers if (number < 0.0) { print('-'); diff --git a/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h b/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h index 45ed31130e6b..9a1793483586 100644 --- a/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h +++ b/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h @@ -102,7 +102,6 @@ template<> struct MarlinSerialPortInfo<4> { static constexpr int IRQ_ID = ID_USART3; }; - template< int portNr, int RX_SIZE = 128, diff --git a/Marlin/src/HAL/shared/MarlinSerial.h b/Marlin/src/HAL/shared/MarlinSerial.h index 10d55e92db41..7b4d7be0d1e7 100644 --- a/Marlin/src/HAL/shared/MarlinSerial.h +++ b/Marlin/src/HAL/shared/MarlinSerial.h @@ -58,3 +58,8 @@ constexpr bool || true #endif ); + +#if SERIAL_PORT >= 0 + #define TEMPLATE_SIG int portNr, int RX_SIZE, int TX_SIZE, bool USE_XONOFF, bool USE_EMERGENCYPARSER, bool STATS_DROPPED_RX, bool STATS_RX_OVERRUNS, bool STATS_RX_FRAMING_ERRORS, bool STATS_MAX_RX_QUEUED + #define TEMPLATE_ARG portNr, RX_SIZE, TX_SIZE, USE_XONOFF, USE_EMERGENCYPARSER, STATS_DROPPED_RX, STATS_RX_OVERRUNS, STATS_RX_FRAMING_ERRORS, STATS_MAX_RX_QUEUED +#endif From 0e1199bf476ad4306e8946b8e5e65cc1a808152b Mon Sep 17 00:00:00 2001 From: etagle Date: Tue, 2 Oct 2018 15:56:47 -0300 Subject: [PATCH 6/7] Converted to use a struct as configurator for template --- Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp | 271 +++++++++----------- Marlin/src/HAL/HAL_AVR/MarlinSerial.h | 79 +++--- Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp | 230 ++++++++--------- Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h | 96 +++---- Marlin/src/HAL/shared/MarlinSerial.h | 4 - 5 files changed, 289 insertions(+), 391 deletions(-) diff --git a/Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp b/Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp index 2c58f5021abf..0523d462e00d 100644 --- a/Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp +++ b/Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp @@ -29,6 +29,7 @@ * Modified 14 February 2016 by Andreas Hardtung (added tx buffer) * Modified 01 October 2017 by Eduardo José Tagle (added XON/XOFF) * Modified 10 June 2018 by Eduardo José Tagle (See #10991) + * Templatized 01 October 2018 by Eduardo José Tagle to allow multiple instances */ #ifdef __AVR__ @@ -42,14 +43,14 @@ #include "MarlinSerial.h" #include "../../Marlin.h" - template typename MarlinSerial::ring_buffer_r MarlinSerial::rx_buffer; // = { { 0 }, 0, 0 }; - template typename MarlinSerial::ring_buffer_t MarlinSerial::tx_buffer; // = { { 0 }, 0, 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; + template typename MarlinSerial::ring_buffer_r MarlinSerial::rx_buffer = { 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"); @@ -59,9 +60,9 @@ // "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 (RX_SIZE > 256) { + 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 @@ -81,18 +82,18 @@ } } - template - volatile bool MarlinSerial::rx_tail_value_not_stable = false; - template - volatile uint16_t MarlinSerial::rx_tail_value_backup = 0; + 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 (RX_SIZE > 256) { + 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(); @@ -113,9 +114,9 @@ // 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 (RX_SIZE > 256) { + 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; } @@ -124,8 +125,8 @@ } // (called with RX interrupts disabled) - template - FORCE_INLINE void MarlinSerial::store_rxd_char() { + template + FORCE_INLINE void MarlinSerial::store_rxd_char() { static EmergencyParser::State emergency_state; // = EP_RESET @@ -138,25 +139,25 @@ 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)(RX_SIZE - 1); + ring_buffer_pos_t i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1); // This must read the R_UCSRA register before reading the received byte to detect error causes - if (STATS_DROPPED_RX) { + if (Cfg::DROPPED_RX) { if (B_DOR && !++rx_dropped_bytes) --rx_dropped_bytes; } - if (STATS_RX_OVERRUNS) { + if (Cfg::RX_OVERRUNS) { if (B_DOR && !++rx_buffer_overruns) --rx_buffer_overruns; } - if (STATS_RX_FRAMING_ERRORS) { + if (Cfg::RX_FRAMING_ERRORS) { if (B_FE && !++rx_framing_errors) --rx_framing_errors; } // Read the character from the USART uint8_t c = R_UDR; - if (USE_EMERGENCYPARSER) { + if (Cfg::EMERGENCYPARSER) { emergency_parser.update(emergency_state, c); } @@ -167,29 +168,29 @@ rx_buffer.buffer[h] = c; h = i; } else { - if (STATS_DROPPED_RX) + if (Cfg::DROPPED_RX) if (!++rx_dropped_bytes) --rx_dropped_bytes; } - if (STATS_MAX_RX_QUEUED) { + 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)(RX_SIZE - 1); + 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 (USE_XONOFF) { + if (Cfg::XONOFF) { // If the last char that was sent was an XON if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XON_CHAR) { // Bytes stored into the RX buffer - const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(RX_SIZE - 1); + const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1); // 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 >= (RX_SIZE) / 8) { + if (rx_count >= (Cfg::RX_SIZE) / 8) { // 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 @@ -208,12 +209,12 @@ 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)(RX_SIZE - 1); + 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 (USE_EMERGENCYPARSER) + if (Cfg::EMERGENCYPARSER) emergency_parser.update(emergency_state, c); // If the character is to be stored at the index just before the tail @@ -223,7 +224,7 @@ rx_buffer.buffer[h] = c; h = i; } else { - if (STATS_DROPPED_RX) + if (Cfg::DROPPED_RX) if (!++rx_dropped_bytes) --rx_dropped_bytes; } } @@ -249,12 +250,12 @@ 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)(RX_SIZE - 1); + 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 (USE_EMERGENCYPARSER) + if (Cfg::EMERGENCYPARSER) emergency_parser.update(emergency_state, c); // If the character is to be stored at the index just before the tail @@ -264,7 +265,7 @@ rx_buffer.buffer[h] = c; h = i; } else { - if (STATS_DROPPED_RX) + if (Cfg::DROPPED_RX) if (!++rx_dropped_bytes) --rx_dropped_bytes; } } @@ -282,14 +283,14 @@ } // (called with TX irqs disabled) - template - FORCE_INLINE void MarlinSerial::_tx_udr_empty_irq(void) { - if (TX_SIZE > 0) { + template + FORCE_INLINE void MarlinSerial::_tx_udr_empty_irq(void) { + if (Cfg::TX_SIZE > 0) { // Read positions uint8_t t = tx_buffer.tail; const uint8_t h = tx_buffer.head; - if (USE_XONOFF) { + if (Cfg::XONOFF) { // If an XON char is pending to be sent, do it now if (xon_xoff_state == XON_CHAR) { @@ -321,7 +322,7 @@ // There is something to TX, Send the next byte const uint8_t c = tx_buffer.buffer[t]; - t = (t + 1) & (TX_SIZE - 1); + t = (t + 1) & (Cfg::TX_SIZE - 1); R_UDR = c; tx_buffer.tail = t; @@ -335,8 +336,8 @@ } // Public Methods - template - void MarlinSerial::begin(const long baud) { + template + void MarlinSerial::begin(const long baud) { uint16_t baud_setting; bool useU2X = true; @@ -363,27 +364,27 @@ B_RXEN = 1; B_TXEN = 1; B_RXCIE = 1; - if (TX_SIZE > 0) + if (Cfg::TX_SIZE > 0) B_UDRIE = 0; _written = false; } - template - void MarlinSerial::end() { + template + void MarlinSerial::end() { B_RXEN = 0; B_TXEN = 0; B_RXCIE = 0; B_UDRIE = 0; } - template - int MarlinSerial::peek(void) { + template + int MarlinSerial::peek(void) { 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(void) { + template + int MarlinSerial::read(void) { 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 @@ -394,19 +395,19 @@ // Get the next char const int v = rx_buffer.buffer[t]; - t = (ring_buffer_pos_t)(t + 1) & (RX_SIZE - 1); + 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 (USE_XONOFF) { + 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)(RX_SIZE - 1); - if (rx_count < (RX_SIZE) / 10) { - if (TX_SIZE > 0) { + 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 @@ -424,14 +425,14 @@ return v; } - template - typename MarlinSerial::ring_buffer_pos_t MarlinSerial::available(void) { + template + typename MarlinSerial::ring_buffer_pos_t MarlinSerial::available(void) { const ring_buffer_pos_t h = atomic_read_rx_head(), t = rx_buffer.tail; - return (ring_buffer_pos_t)(RX_SIZE + h - t) & (RX_SIZE - 1); + return (ring_buffer_pos_t)(Cfg::RX_SIZE + h - t) & (Cfg::RX_SIZE - 1); } - template - void MarlinSerial::flush(void) { + template + void MarlinSerial::flush(void) { // Set the tail to the head: // - Read the RX head index in a safe way. (See atomic_read_rx_head.) @@ -439,10 +440,10 @@ // if it interrupts the writing of the value of that variable in the middle. atomic_set_rx_tail(atomic_read_rx_head()); - if (USE_XONOFF) { + 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 (TX_SIZE > 0) { + 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. @@ -457,9 +458,9 @@ } } - template - void MarlinSerial::write(const uint8_t c) { - if (TX_SIZE == 0) { + template + void MarlinSerial::write(const uint8_t c) { + if (Cfg::TX_SIZE == 0) { _written = true; while (!B_UDRE) sw_barrier(); @@ -486,7 +487,7 @@ return; } - const uint8_t i = (tx_buffer.head + 1) & (TX_SIZE - 1); + 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()) { @@ -515,10 +516,10 @@ } } - template - void MarlinSerial::flushTX(void) { + template + void MarlinSerial::flushTX(void) { - if (TX_SIZE == 0) { + 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; @@ -563,28 +564,28 @@ * Imports from print.h */ - template - void MarlinSerial::print(char c, int base) { + template + void MarlinSerial::print(char c, int base) { print((long)c, base); } - template - void MarlinSerial::print(unsigned char b, int base) { + template + void MarlinSerial::print(unsigned char b, int base) { print((unsigned long)b, base); } - template - void MarlinSerial::print(int n, int base) { + template + void MarlinSerial::print(int n, int base) { print((long)n, base); } - template - void MarlinSerial::print(unsigned int n, int base) { + template + void MarlinSerial::print(unsigned int n, int base) { print((unsigned long)n, base); } - template - void MarlinSerial::print(long n, int base) { + template + void MarlinSerial::print(long n, int base) { if (base == 0) write(n); else if (base == 10) { if (n < 0) { print('-'); n = -n; } @@ -594,81 +595,81 @@ printNumber(n, base); } - template - void MarlinSerial::print(unsigned long n, int 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) { + template + void MarlinSerial::print(double n, int digits) { printFloat(n, digits); } - template - void MarlinSerial::println(void) { + template + void MarlinSerial::println(void) { print('\r'); print('\n'); } - template - void MarlinSerial::println(const String& s) { + template + void MarlinSerial::println(const String& s) { print(s); println(); } - template - void MarlinSerial::println(const char c[]) { + template + void MarlinSerial::println(const char c[]) { print(c); println(); } - template - void MarlinSerial::println(char c, int base) { + template + void MarlinSerial::println(char c, int base) { print(c, base); println(); } - template - void MarlinSerial::println(unsigned char b, int base) { + template + void MarlinSerial::println(unsigned char b, int base) { print(b, base); println(); } - template - void MarlinSerial::println(int n, int base) { + template + void MarlinSerial::println(int n, int base) { print(n, base); println(); } - template - void MarlinSerial::println(unsigned int n, int base) { + template + void MarlinSerial::println(unsigned int n, int base) { print(n, base); println(); } - template - void MarlinSerial::println(long n, int base) { + template + void MarlinSerial::println(long n, int base) { print(n, base); println(); } - template - void MarlinSerial::println(unsigned long n, int base) { + template + void MarlinSerial::println(unsigned long n, int base) { print(n, base); println(); } - template - void MarlinSerial::println(double n, int digits) { + template + void MarlinSerial::println(double n, int digits) { print(n, digits); println(); } // Private Methods - template - void MarlinSerial::printNumber(unsigned long n, uint8_t base) { + 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; @@ -683,8 +684,8 @@ print('0'); } - template - void MarlinSerial::printFloat(double number, uint8_t digits) { + template + void MarlinSerial::printFloat(double number, uint8_t digits) { // Handle negative numbers if (number < 0.0) { print('-'); @@ -718,58 +719,18 @@ // Hookup ISR handlers ISR(SERIAL_REGNAME(USART,SERIAL_PORT,_RX_vect)) { - MarlinSerial< - SERIAL_PORT, - RX_BUFFER_SIZE, - TX_BUFFER_SIZE, - bSERIAL_XON_XOFF, - bEMERGENCY_PARSER, - bSERIAL_STATS_DROPPED_RX, - bSERIAL_STATS_RX_BUFFER_OVERRUNS, - bSERIAL_STATS_RX_FRAMING_ERRORS, - bSERIAL_STATS_MAX_RX_QUEUED - >::store_rxd_char(); + MarlinSerial::store_rxd_char(); } ISR(SERIAL_REGNAME(USART,SERIAL_PORT,_UDRE_vect)) { - MarlinSerial< - SERIAL_PORT, - RX_BUFFER_SIZE, - TX_BUFFER_SIZE, - bSERIAL_XON_XOFF, - bEMERGENCY_PARSER, - bSERIAL_STATS_DROPPED_RX, - bSERIAL_STATS_RX_BUFFER_OVERRUNS, - bSERIAL_STATS_RX_FRAMING_ERRORS, - bSERIAL_STATS_MAX_RX_QUEUED - >::_tx_udr_empty_irq(); + MarlinSerial::_tx_udr_empty_irq(); } // Preinstantiate - template class MarlinSerial< - SERIAL_PORT, - RX_BUFFER_SIZE, - TX_BUFFER_SIZE, - bSERIAL_XON_XOFF, - bEMERGENCY_PARSER, - bSERIAL_STATS_DROPPED_RX, - bSERIAL_STATS_RX_BUFFER_OVERRUNS, - bSERIAL_STATS_RX_FRAMING_ERRORS, - bSERIAL_STATS_MAX_RX_QUEUED - >; + template class MarlinSerial; // Instantiate - MarlinSerial< - SERIAL_PORT, - RX_BUFFER_SIZE, - TX_BUFFER_SIZE, - bSERIAL_XON_XOFF, - bEMERGENCY_PARSER, - bSERIAL_STATS_DROPPED_RX, - bSERIAL_STATS_RX_BUFFER_OVERRUNS, - bSERIAL_STATS_RX_FRAMING_ERRORS, - bSERIAL_STATS_MAX_RX_QUEUED - > customizedSerial; + MarlinSerial customizedSerial; #endif // !USBCON && (UBRRH || UBRR0H || UBRR1H || UBRR2H || UBRR3H) diff --git a/Marlin/src/HAL/HAL_AVR/MarlinSerial.h b/Marlin/src/HAL/HAL_AVR/MarlinSerial.h index 878979702368..b57d38a3c9c3 100644 --- a/Marlin/src/HAL/HAL_AVR/MarlinSerial.h +++ b/Marlin/src/HAL/HAL_AVR/MarlinSerial.h @@ -148,48 +148,38 @@ template struct TypeSelector { typedef T type;} ; template struct TypeSelector { typedef F type; }; - template< - int portNr, - int RX_SIZE = 128, - int TX_SIZE = 32, - bool USE_XONOFF = false, - bool ENABLE_EMERGENCYPARSER = false, - bool STATS_DROPPED_RX = false, - bool STATS_RX_OVERRUNS = false, - bool STATS_RX_FRAMING_ERRORS = false, - bool STATS_MAX_RX_QUEUED = false - > + template class MarlinSerial { protected: // Registers - static constexpr R_UCSRxA R_UCSRA = 0; - static constexpr R_UDRx R_UDR = 0; - static constexpr R_UBRRxH R_UBRRH = 0; - static constexpr R_UBRRxL R_UBRRL = 0; + static constexpr R_UCSRxA R_UCSRA = 0; + static constexpr R_UDRx R_UDR = 0; + static constexpr R_UBRRxH R_UBRRH = 0; + static constexpr R_UBRRxL R_UBRRL = 0; // Bits - static constexpr B_RXENx B_RXEN = 0; - static constexpr B_TXENx B_TXEN = 0; - static constexpr B_TXCx B_TXC = 0; - static constexpr B_RXCIEx B_RXCIE = 0; - static constexpr B_UDREx B_UDRE = 0; - static constexpr B_FEx B_FE = 0; - static constexpr B_DORx B_DOR = 0; - static constexpr B_UDRIEx B_UDRIE = 0; - static constexpr B_RXCx B_RXC = 0; - static constexpr B_U2Xx B_U2X = 0; + static constexpr B_RXENx B_RXEN = 0; + static constexpr B_TXENx B_TXEN = 0; + static constexpr B_TXCx B_TXC = 0; + static constexpr B_RXCIEx B_RXCIE = 0; + static constexpr B_UDREx B_UDRE = 0; + static constexpr B_FEx B_FE = 0; + static constexpr B_DORx B_DOR = 0; + static constexpr B_UDRIEx B_UDRIE = 0; + static constexpr B_RXCx B_RXC = 0; + static constexpr B_U2Xx B_U2X = 0; // Base size of type on buffer size - typedef typename TypeSelector<(RX_SIZE>256), uint16_t, uint8_t>::type ring_buffer_pos_t; + typedef typename TypeSelector<(Cfg::RX_SIZE>256), uint16_t, uint8_t>::type ring_buffer_pos_t; struct ring_buffer_r { - unsigned char buffer[RX_SIZE]; volatile ring_buffer_pos_t head, tail; + unsigned char buffer[Cfg::RX_SIZE]; }; struct ring_buffer_t { - unsigned char buffer[TX_SIZE]; volatile uint8_t head, tail; + unsigned char buffer[Cfg::TX_SIZE]; }; static ring_buffer_r rx_buffer; @@ -231,10 +221,10 @@ static void write(const uint8_t c); static void flushTX(void); - FORCE_INLINE static uint8_t dropped() { return STATS_DROPPED_RX ? rx_dropped_bytes : 0; } - FORCE_INLINE static uint8_t buffer_overruns() { return STATS_RX_OVERRUNS ? rx_buffer_overruns : 0; } - FORCE_INLINE static uint8_t framing_errors() { return STATS_RX_FRAMING_ERRORS ? rx_framing_errors : 0; } - FORCE_INLINE static ring_buffer_pos_t rxMaxEnqueued() { return STATS_MAX_RX_QUEUED ? rx_max_enqueued : 0; } + 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; } + FORCE_INLINE static ring_buffer_pos_t rxMaxEnqueued() { return Cfg::MAX_RX_QUEUED ? rx_max_enqueued : 0; } FORCE_INLINE static void write(const char* str) { while (*str) write(*str++); } FORCE_INLINE static void write(const uint8_t* buffer, size_t size) { while (size--) write(*buffer++); } @@ -266,17 +256,20 @@ static void printFloat(double, uint8_t); }; - extern MarlinSerial< - SERIAL_PORT, - RX_BUFFER_SIZE, - TX_BUFFER_SIZE, - bSERIAL_XON_XOFF, - bEMERGENCY_PARSER, - bSERIAL_STATS_DROPPED_RX, - bSERIAL_STATS_RX_BUFFER_OVERRUNS, - bSERIAL_STATS_RX_FRAMING_ERRORS, - bSERIAL_STATS_MAX_RX_QUEUED - > customizedSerial; + // Serial port configuration + struct MarlinSerialCfg { + static constexpr int PORT = SERIAL_PORT; + static constexpr int RX_SIZE = RX_BUFFER_SIZE; + static constexpr int TX_SIZE = TX_BUFFER_SIZE; + static constexpr bool XONOFF = bSERIAL_XON_XOFF; + static constexpr bool EMERGENCYPARSER = bEMERGENCY_PARSER; + static constexpr bool DROPPED_RX = bSERIAL_STATS_DROPPED_RX; + static constexpr bool RX_OVERRUNS = bSERIAL_STATS_RX_BUFFER_OVERRUNS; + static constexpr bool RX_FRAMING_ERRORS = bSERIAL_STATS_RX_FRAMING_ERRORS; + static constexpr bool MAX_RX_QUEUED = bSERIAL_STATS_MAX_RX_QUEUED; + }; + + extern MarlinSerial customizedSerial; #endif // !USBCON diff --git a/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp b/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp index 2e5e3502ab10..e9848d1c5382 100644 --- a/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp +++ b/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp @@ -36,14 +36,14 @@ #include "InterruptVectors_Due.h" #include "../../Marlin.h" - template typename MarlinSerial::ring_buffer_r MarlinSerial::rx_buffer; // = { { 0 }, 0, 0 }; - template typename MarlinSerial::ring_buffer_t MarlinSerial::tx_buffer; // = { { 0 }, 0, 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; + template typename MarlinSerial::ring_buffer_r MarlinSerial::rx_buffer = { 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"); @@ -51,8 +51,8 @@ #include "../../feature/emergency_parser.h" // (called with RX interrupts disabled) - template - FORCE_INLINE void MarlinSerial::store_rxd_char() { + template + FORCE_INLINE void MarlinSerial::store_rxd_char() { static EmergencyParser::State emergency_state; // = EP_RESET @@ -63,12 +63,12 @@ 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)(RX_SIZE - 1); + ring_buffer_pos_t i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1); // Read the character from the USART uint8_t c = HWUART->UART_RHR; - if (USE_EMERGENCYPARSER) + if (Cfg::EMERGENCYPARSER) emergency_parser.update(emergency_state, c); // If the character is to be stored at the index just before the tail @@ -79,28 +79,28 @@ h = i; } else { - if (STATS_DROPPED_RX) + if (Cfg::DROPPED_RX) if (!++rx_dropped_bytes) --rx_dropped_bytes; } - const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(RX_SIZE - 1); + const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1); // Calculate count of bytes stored into the RX buffer // Keep track of the maximum count of enqueued bytes - if (STATS_MAX_RX_QUEUED) + if (Cfg::MAX_RX_QUEUED) NOLESS(rx_max_enqueued, rx_count); - if (USE_XONOFF) { + if (Cfg::XONOFF) { // If the last char that was sent was an XON if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XON_CHAR) { // Bytes stored into the RX buffer - const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(RX_SIZE - 1); + const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1); // 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 >= (RX_SIZE) / 8) { + if (rx_count >= (Cfg::RX_SIZE) / 8) { // 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 @@ -120,12 +120,12 @@ if (status & UART_SR_RXRDY) { // We received a char while waiting for the TX buffer to be empty - Receive and process it! - i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(RX_SIZE - 1); + i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1); // Read the character from the USART c = HWUART->UART_RHR; - if (USE_EMERGENCYPARSER) + if (Cfg::EMERGENCYPARSER) emergency_parser.update(emergency_state, c); // If the character is to be stored at the index just before the tail @@ -136,7 +136,7 @@ h = i; } else { - if (STATS_DROPPED_RX) + if (Cfg::DROPPED_RX) if (!++rx_dropped_bytes) --rx_dropped_bytes; } } @@ -157,12 +157,12 @@ if (status & UART_SR_RXRDY) { // 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)(RX_SIZE - 1); + i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1); // Read the character from the USART c = HWUART->UART_RHR; - if (USE_EMERGENCYPARSER) + if (Cfg::EMERGENCYPARSER) emergency_parser.update(emergency_state, c); // If the character is to be stored at the index just before the tail @@ -173,7 +173,7 @@ h = i; } else { - if (STATS_DROPPED_RX) + if (Cfg::DROPPED_RX) if (!++rx_dropped_bytes) --rx_dropped_bytes; } } @@ -190,14 +190,14 @@ rx_buffer.head = h; } - template - FORCE_INLINE void MarlinSerial::_tx_thr_empty_irq(void) { - if (TX_SIZE > 0) { + template + FORCE_INLINE void MarlinSerial::_tx_thr_empty_irq(void) { + if (Cfg::TX_SIZE > 0) { // Read positions uint8_t t = tx_buffer.tail; const uint8_t h = tx_buffer.head; - if (USE_XONOFF) { + if (Cfg::XONOFF) { // If an XON char is pending to be sent, do it now if (xon_xoff_state == XON_CHAR) { @@ -224,7 +224,7 @@ // There is something to TX, Send the next byte const uint8_t c = tx_buffer.buffer[t]; - t = (t + 1) & (TX_SIZE - 1); + t = (t + 1) & (Cfg::TX_SIZE - 1); HWUART->UART_THR = c; tx_buffer.tail = t; @@ -233,25 +233,25 @@ } } - template - void MarlinSerial::UART_ISR(void) { + template + void MarlinSerial::UART_ISR(void) { const uint32_t status = HWUART->UART_SR; // Data received? if (status & UART_SR_RXRDY) store_rxd_char(); - if (TX_SIZE > 0) { + if (Cfg::TX_SIZE > 0) { // Something to send, and TX interrupts are enabled (meaning something to send)? if ((status & UART_SR_TXRDY) && (HWUART->UART_IMR & UART_IMR_TXRDY)) _tx_thr_empty_irq(); } // Acknowledge errors if ((status & UART_SR_OVRE) || (status & UART_SR_FRAME)) { - if (STATS_DROPPED_RX) + if (Cfg::DROPPED_RX) if (status & UART_SR_OVRE && !++rx_dropped_bytes) --rx_dropped_bytes; - if (STATS_RX_OVERRUNS) + if (Cfg::RX_OVERRUNS) if (status & UART_SR_OVRE && !++rx_buffer_overruns) --rx_buffer_overruns; - if (STATS_RX_FRAMING_ERRORS) + if (Cfg::RX_FRAMING_ERRORS) if (status & UART_SR_FRAME && !++rx_framing_errors) --rx_framing_errors; // TODO: error reporting outside ISR @@ -260,8 +260,8 @@ } // Public Methods - template - void MarlinSerial::begin(const long baud_setting) { + template + void MarlinSerial::begin(const long baud_setting) { // Disable UART interrupt in NVIC NVIC_DisableIRQ( HWUART_IRQ ); @@ -307,12 +307,12 @@ // Enable receiver and transmitter HWUART->UART_CR = UART_CR_RXEN | UART_CR_TXEN; - if (TX_SIZE > 0) + if (Cfg::TX_SIZE > 0) _written = false; } - template - void MarlinSerial::end() { + template + void MarlinSerial::end() { // Disable UART interrupt in NVIC NVIC_DisableIRQ( HWUART_IRQ ); @@ -324,14 +324,14 @@ pmc_disable_periph_clk( HWUART_IRQ_ID ); } - template - int MarlinSerial::peek(void) { + template + int MarlinSerial::peek(void) { const int v = rx_buffer.head == rx_buffer.tail ? -1 : rx_buffer.buffer[rx_buffer.tail]; return v; } - template - int MarlinSerial::read(void) { + template + int MarlinSerial::read(void) { const ring_buffer_pos_t h = rx_buffer.head; ring_buffer_pos_t t = rx_buffer.tail; @@ -339,19 +339,19 @@ if (h == t) return -1; int v = rx_buffer.buffer[t]; - t = (ring_buffer_pos_t)(t + 1) & (RX_SIZE - 1); + t = (ring_buffer_pos_t)(t + 1) & (Cfg::RX_SIZE - 1); // Advance tail rx_buffer.tail = t; - if (USE_XONOFF) { + 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)(RX_SIZE - 1); + const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1); // When below 10% of RX buffer capacity, send XON before running out of RX buffer bytes - if (rx_count < (RX_SIZE) / 10) { - if (TX_SIZE > 0) { + 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. @@ -369,19 +369,19 @@ return v; } - template - typename MarlinSerial::ring_buffer_pos_t MarlinSerial::available(void) { + template + typename MarlinSerial::ring_buffer_pos_t MarlinSerial::available(void) { const ring_buffer_pos_t h = rx_buffer.head, t = rx_buffer.tail; - return (ring_buffer_pos_t)(RX_SIZE + h - t) & (RX_SIZE - 1); + return (ring_buffer_pos_t)(Cfg::RX_SIZE + h - t) & (Cfg::RX_SIZE - 1); } - template - void MarlinSerial::flush(void) { + template + void MarlinSerial::flush(void) { rx_buffer.tail = rx_buffer.head; - if (USE_XONOFF) { + if (Cfg::XONOFF) { if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) { - if (TX_SIZE > 0) { + if (Cfg::TX_SIZE > 0) { // Signal we want an XON character to be sent. xon_xoff_state = XON_CHAR; // Enable TX isr. @@ -396,11 +396,11 @@ } } - template - void MarlinSerial::write(const uint8_t c) { + template + void MarlinSerial::write(const uint8_t c) { _written = true; - if (TX_SIZE == 0) { + if (Cfg::TX_SIZE == 0) { while (!(HWUART->UART_SR & UART_SR_TXRDY)) sw_barrier(); HWUART->UART_THR = c; } else { @@ -417,7 +417,7 @@ return; } - const uint8_t i = (tx_buffer.head + 1) & (TX_SIZE - 1); + 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()) { @@ -444,11 +444,11 @@ } } - template - void MarlinSerial::flushTX(void) { + template + void MarlinSerial::flushTX(void) { // TX - if (TX_SIZE == 0) { + 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; @@ -491,28 +491,28 @@ * Imports from print.h */ - template - void MarlinSerial::print(char c, int base) { + template + void MarlinSerial::print(char c, int base) { print((long)c, base); } - template - void MarlinSerial::print(unsigned char b, int base) { + template + void MarlinSerial::print(unsigned char b, int base) { print((unsigned long)b, base); } - template - void MarlinSerial::print(int n, int base) { + template + void MarlinSerial::print(int n, int base) { print((long)n, base); } - template - void MarlinSerial::print(unsigned int n, int base) { + template + void MarlinSerial::print(unsigned int n, int base) { print((unsigned long)n, base); } - template - void MarlinSerial::print(long n, int base) { + template + void MarlinSerial::print(long n, int base) { if (base == 0) write(n); else if (base == 10) { if (n < 0) { print('-'); n = -n; } @@ -522,80 +522,80 @@ printNumber(n, base); } - template - void MarlinSerial::print(unsigned long n, int 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) { + template + void MarlinSerial::print(double n, int digits) { printFloat(n, digits); } - template - void MarlinSerial::println(void) { + template + void MarlinSerial::println(void) { print('\r'); print('\n'); } - template - void MarlinSerial::println(const String& s) { + template + void MarlinSerial::println(const String& s) { print(s); println(); } - template - void MarlinSerial::println(const char c[]) { + template + void MarlinSerial::println(const char c[]) { print(c); println(); } - template - void MarlinSerial::println(char c, int base) { + template + void MarlinSerial::println(char c, int base) { print(c, base); println(); } - template - void MarlinSerial::println(unsigned char b, int base) { + template + void MarlinSerial::println(unsigned char b, int base) { print(b, base); println(); } - template - void MarlinSerial::println(int n, int base) { + template + void MarlinSerial::println(int n, int base) { print(n, base); println(); } - template - void MarlinSerial::println(unsigned int n, int base) { + template + void MarlinSerial::println(unsigned int n, int base) { print(n, base); println(); } - template - void MarlinSerial::println(long n, int base) { + template + void MarlinSerial::println(long n, int base) { print(n, base); println(); } - template - void MarlinSerial::println(unsigned long n, int base) { + template + void MarlinSerial::println(unsigned long n, int base) { print(n, base); println(); } - template - void MarlinSerial::println(double n, int digits) { + template + void MarlinSerial::println(double n, int digits) { print(n, digits); println(); } // Private Methods - template - void MarlinSerial::printNumber(unsigned long n, uint8_t base) { + 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; @@ -610,8 +610,8 @@ print('0'); } - template - void MarlinSerial::printFloat(double number, uint8_t digits) { + template + void MarlinSerial::printFloat(double number, uint8_t digits) { // Handle negative numbers if (number < 0.0) { print('-'); @@ -641,30 +641,12 @@ } } - template class MarlinSerial< - SERIAL_PORT, - RX_BUFFER_SIZE, - TX_BUFFER_SIZE, - bSERIAL_XON_XOFF, - bEMERGENCY_PARSER, - bSERIAL_STATS_DROPPED_RX, - bSERIAL_STATS_RX_BUFFER_OVERRUNS, - bSERIAL_STATS_RX_FRAMING_ERRORS, - bSERIAL_STATS_MAX_RX_QUEUED - >; - // Preinstantiate - MarlinSerial< - SERIAL_PORT, - RX_BUFFER_SIZE, - TX_BUFFER_SIZE, - bSERIAL_XON_XOFF, - bEMERGENCY_PARSER, - bSERIAL_STATS_DROPPED_RX, - bSERIAL_STATS_RX_BUFFER_OVERRUNS, - bSERIAL_STATS_RX_FRAMING_ERRORS, - bSERIAL_STATS_MAX_RX_QUEUED - > customizedSerial; + template class MarlinSerial; + + // Instantiate + MarlinSerial customizedSerial; + #endif #endif // ARDUINO_ARCH_SAM diff --git a/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h b/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h index 9a1793483586..c5d611ead51a 100644 --- a/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h +++ b/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h @@ -67,70 +67,33 @@ template struct TypeSelector { typedef F ty // Templated structure wrapper template struct StructWrapper { constexpr StructWrapper(int) {} - S* operator->() const { return (S*)addr; } + FORCE_INLINE S* operator->() const { return (S*)addr; } }; -// Hardware serial port information (by template specialization) -template struct MarlinSerialPortInfo {}; -template<> struct MarlinSerialPortInfo<0> { - static constexpr unsigned int BASE = 0x400E0800U; // UART - static constexpr IRQn_Type IRQ = UART_IRQn; - static constexpr int IRQ_ID = ID_UART; -}; - -template<> struct MarlinSerialPortInfo<1> { - static constexpr unsigned int BASE = 0x40098000U; // USART0 - static constexpr IRQn_Type IRQ = USART0_IRQn; - static constexpr int IRQ_ID = ID_USART0; -}; - -template<> struct MarlinSerialPortInfo<2> { - static constexpr unsigned int BASE = 0x4009C000U; // USART1 - static constexpr IRQn_Type IRQ = USART1_IRQn; - static constexpr int IRQ_ID = ID_USART1; -}; - -template<> struct MarlinSerialPortInfo<3> { - static constexpr unsigned int BASE = 0x400A0000U; // USART2 - static constexpr IRQn_Type IRQ = USART2_IRQn; - static constexpr int IRQ_ID = ID_USART2; -}; - -template<> struct MarlinSerialPortInfo<4> { - static constexpr unsigned int BASE = 0x400A4000U; // USART3 - static constexpr IRQn_Type IRQ = USART3_IRQn; - static constexpr int IRQ_ID = ID_USART3; -}; - -template< - int portNr, - int RX_SIZE = 128, - int TX_SIZE = 32, - bool USE_XONOFF = false, - bool ENABLE_EMERGENCYPARSER = false, - bool STATS_DROPPED_RX = false, - bool STATS_RX_OVERRUNS = false, - bool STATS_RX_FRAMING_ERRORS = false, - bool STATS_MAX_RX_QUEUED = false -> +template class MarlinSerial { protected: + // Information for all supported UARTs + static constexpr uint32_t BASES[] = {0x400E0800U, 0x40098000U, 0x4009C000U, 0x400A0000U, 0x400A4000U}; + static constexpr IRQn_Type IRQS[] = { UART_IRQn, USART0_IRQn, USART1_IRQn, USART2_IRQn, USART3_IRQn}; + static constexpr int IRQ_IDS[] = { ID_UART, ID_USART0, ID_USART1, ID_USART2, ID_USART3}; + // Alias for shorter code - static constexpr StructWrapper::BASE> HWUART = 0; - static constexpr IRQn_Type HWUART_IRQ = MarlinSerialPortInfo::IRQ; - static constexpr int HWUART_IRQ_ID = MarlinSerialPortInfo::IRQ_ID; + static constexpr StructWrapper HWUART = 0; + static constexpr IRQn_Type HWUART_IRQ = IRQS[Cfg::PORT]; + static constexpr int HWUART_IRQ_ID = IRQ_IDS[Cfg::PORT]; // Base size of type on buffer size - typedef typename TypeSelector<(RX_SIZE>256), uint16_t, uint8_t>::type ring_buffer_pos_t; + typedef typename TypeSelector<(Cfg::RX_SIZE>256), uint16_t, uint8_t>::type ring_buffer_pos_t; struct ring_buffer_r { - unsigned char buffer[RX_SIZE]; volatile ring_buffer_pos_t head, tail; + unsigned char buffer[Cfg::RX_SIZE]; }; struct ring_buffer_t { - unsigned char buffer[TX_SIZE]; volatile uint8_t head, tail; + unsigned char buffer[Cfg::TX_SIZE]; }; static ring_buffer_r rx_buffer; @@ -163,10 +126,10 @@ class MarlinSerial { static void write(const uint8_t c); static void flushTX(void); - FORCE_INLINE static uint8_t dropped() { return STATS_DROPPED_RX ? rx_dropped_bytes : 0; } - FORCE_INLINE static uint8_t buffer_overruns() { return STATS_RX_OVERRUNS ? rx_buffer_overruns : 0; } - FORCE_INLINE static uint8_t framing_errors() { return STATS_RX_FRAMING_ERRORS ? rx_framing_errors : 0; } - FORCE_INLINE static ring_buffer_pos_t rxMaxEnqueued() { return STATS_MAX_RX_QUEUED ? rx_max_enqueued : 0; } + 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; } + FORCE_INLINE static ring_buffer_pos_t rxMaxEnqueued() { return Cfg::MAX_RX_QUEUED ? rx_max_enqueued : 0; } FORCE_INLINE static void write(const char* str) { while (*str) write(*str++); } FORCE_INLINE static void write(const uint8_t* buffer, size_t size) { while (size--) write(*buffer++); } @@ -198,17 +161,20 @@ class MarlinSerial { static void printFloat(double, uint8_t); }; -extern MarlinSerial< - SERIAL_PORT, - RX_BUFFER_SIZE, - TX_BUFFER_SIZE, - bSERIAL_XON_XOFF, - bEMERGENCY_PARSER, - bSERIAL_STATS_DROPPED_RX, - bSERIAL_STATS_RX_BUFFER_OVERRUNS, - bSERIAL_STATS_RX_FRAMING_ERRORS, - bSERIAL_STATS_MAX_RX_QUEUED -> customizedSerial; +// Serial port configuration +struct MarlinSerialCfg { + static constexpr int PORT = SERIAL_PORT; + static constexpr int RX_SIZE = RX_BUFFER_SIZE; + static constexpr int TX_SIZE = TX_BUFFER_SIZE; + static constexpr bool XONOFF = bSERIAL_XON_XOFF; + static constexpr bool EMERGENCYPARSER = bEMERGENCY_PARSER; + static constexpr bool DROPPED_RX = bSERIAL_STATS_DROPPED_RX; + static constexpr bool RX_OVERRUNS = bSERIAL_STATS_RX_BUFFER_OVERRUNS; + static constexpr bool RX_FRAMING_ERRORS = bSERIAL_STATS_RX_FRAMING_ERRORS; + static constexpr bool MAX_RX_QUEUED = bSERIAL_STATS_MAX_RX_QUEUED; +}; + +extern MarlinSerial customizedSerial; #endif // SERIAL_PORT >= 0 diff --git a/Marlin/src/HAL/shared/MarlinSerial.h b/Marlin/src/HAL/shared/MarlinSerial.h index 7b4d7be0d1e7..3efd87702384 100644 --- a/Marlin/src/HAL/shared/MarlinSerial.h +++ b/Marlin/src/HAL/shared/MarlinSerial.h @@ -59,7 +59,3 @@ constexpr bool #endif ); -#if SERIAL_PORT >= 0 - #define TEMPLATE_SIG int portNr, int RX_SIZE, int TX_SIZE, bool USE_XONOFF, bool USE_EMERGENCYPARSER, bool STATS_DROPPED_RX, bool STATS_RX_OVERRUNS, bool STATS_RX_FRAMING_ERRORS, bool STATS_MAX_RX_QUEUED - #define TEMPLATE_ARG portNr, RX_SIZE, TX_SIZE, USE_XONOFF, USE_EMERGENCYPARSER, STATS_DROPPED_RX, STATS_RX_OVERRUNS, STATS_RX_FRAMING_ERRORS, STATS_MAX_RX_QUEUED -#endif From 4b28a2246439784cd78a50fea8b5a2c1d70a5539 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 2 Oct 2018 18:37:29 -0500 Subject: [PATCH 7/7] Tweaky spacing changes --- Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp | 70 +++++++++------------ Marlin/src/HAL/HAL_AVR/MarlinSerial.h | 21 +++---- Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp | 55 +++++++--------- Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h | 16 ++--- 4 files changed, 68 insertions(+), 94 deletions(-) diff --git a/Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp b/Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp index 0523d462e00d..32a6cc340bb3 100644 --- a/Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp +++ b/Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp @@ -76,7 +76,8 @@ sw_barrier(); } while (vold != vnew); return vnew; - } else { + } + else { // With an 8bit index, reads are always atomic. No need for special handling return rx_buffer.head; } @@ -106,9 +107,9 @@ // Signal the new value is completely stored into the value rx_tail_value_not_stable = false; sw_barrier(); - } else { - rx_buffer.tail = value; } + else + rx_buffer.tail = value; } // Get the RX tail index, taking into account the read could be @@ -142,24 +143,14 @@ ring_buffer_pos_t i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1); // This must read the R_UCSRA register before reading the received byte to detect error causes - if (Cfg::DROPPED_RX) { - if (B_DOR && !++rx_dropped_bytes) --rx_dropped_bytes; - } - - if (Cfg::RX_OVERRUNS) { - if (B_DOR && !++rx_buffer_overruns) --rx_buffer_overruns; - } - - if (Cfg::RX_FRAMING_ERRORS) { - if (B_FE && !++rx_framing_errors) --rx_framing_errors; - } + 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 (Cfg::EMERGENCYPARSER) { - emergency_parser.update(emergency_state, c); - } + 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 @@ -167,10 +158,9 @@ if (i != t) { rx_buffer.buffer[h] = c; h = i; - } else { - if (Cfg::DROPPED_RX) - if (!++rx_dropped_bytes) --rx_dropped_bytes; } + 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 @@ -214,8 +204,7 @@ // Read the character from the USART c = R_UDR; - if (Cfg::EMERGENCYPARSER) - emergency_parser.update(emergency_state, c); + 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 @@ -223,10 +212,9 @@ if (i != t) { rx_buffer.buffer[h] = c; h = i; - } else { - if (Cfg::DROPPED_RX) - if (!++rx_dropped_bytes) --rx_dropped_bytes; } + else if (Cfg::DROPPED_RX && !++rx_dropped_bytes) + --rx_dropped_bytes; } sw_barrier(); } @@ -264,10 +252,9 @@ if (i != t) { rx_buffer.buffer[h] = c; h = i; - } else { - if (Cfg::DROPPED_RX) - if (!++rx_dropped_bytes) --rx_dropped_bytes; } + else if (Cfg::DROPPED_RX && !++rx_dropped_bytes) + --rx_dropped_bytes; } sw_barrier(); } @@ -353,9 +340,8 @@ B_U2X = 1; baud_setting = (F_CPU / 4 / baud - 1) / 2; } - else { + 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; @@ -364,8 +350,7 @@ B_RXEN = 1; B_TXEN = 1; B_RXCIE = 1; - if (Cfg::TX_SIZE > 0) - B_UDRIE = 0; + if (Cfg::TX_SIZE > 0) B_UDRIE = 0; _written = false; } @@ -412,7 +397,8 @@ xon_xoff_state = XON_CHAR; // Enable TX ISR. Non atomic, but it will eventually enable them B_UDRIE = 1; - } else { + } + 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(); @@ -448,7 +434,8 @@ xon_xoff_state = XON_CHAR; // Enable TX ISR. Non atomic, but it will eventually enable it. B_UDRIE = 1; - } else { + } + 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(); @@ -466,7 +453,8 @@ while (!B_UDRE) sw_barrier(); R_UDR = c; - } else { + } + else { _written = true; @@ -504,7 +492,7 @@ } else { // Interrupts are enabled, just wait until there is space - while (i == tx_buffer.tail) { sw_barrier(); } + while (i == tx_buffer.tail) sw_barrier(); } // Store new char. head is always safe to move @@ -530,7 +518,8 @@ // At this point nothing is queued anymore (DRIE is disabled) and // the hardware finished transmission (TXC is set). - } else { + } + 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. @@ -543,8 +532,7 @@ 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(); + if (B_UDRE) _tx_udr_empty_irq(); sw_barrier(); } @@ -694,9 +682,7 @@ // Round correctly so that print(1.999, 2) prints as "2.00" double rounding = 0.5; - for (uint8_t i = 0; i < digits; ++i) - rounding *= 0.1; - + for (uint8_t i = 0; i < digits; ++i) rounding *= 0.1; number += rounding; // Extract the integer part of the number and print it diff --git a/Marlin/src/HAL/HAL_AVR/MarlinSerial.h b/Marlin/src/HAL/HAL_AVR/MarlinSerial.h index b57d38a3c9c3..b378567b6e3c 100644 --- a/Marlin/src/HAL/HAL_AVR/MarlinSerial.h +++ b/Marlin/src/HAL/HAL_AVR/MarlinSerial.h @@ -80,11 +80,10 @@ template<> struct B_##bit##x { \ constexpr B_##bit##x(int) {} \ FORCE_INLINE void operator=(int newVal) const { \ - if (newVal) { \ + if (newVal) \ SBI(SERIAL_REGNAME(registerbase,port,suffix),SERIAL_REGNAME(bit,port,)); \ - } else { \ + else \ CBI(SERIAL_REGNAME(registerbase,port,suffix),SERIAL_REGNAME(bit,port,)); \ - } \ } \ FORCE_INLINE operator bool() const { return TEST(SERIAL_REGNAME(registerbase,port,suffix),SERIAL_REGNAME(bit,port,)); } \ } @@ -258,15 +257,15 @@ // Serial port configuration struct MarlinSerialCfg { - static constexpr int PORT = SERIAL_PORT; - static constexpr int RX_SIZE = RX_BUFFER_SIZE; - static constexpr int TX_SIZE = TX_BUFFER_SIZE; - static constexpr bool XONOFF = bSERIAL_XON_XOFF; - static constexpr bool EMERGENCYPARSER = bEMERGENCY_PARSER; - static constexpr bool DROPPED_RX = bSERIAL_STATS_DROPPED_RX; - static constexpr bool RX_OVERRUNS = bSERIAL_STATS_RX_BUFFER_OVERRUNS; + static constexpr int PORT = SERIAL_PORT; + static constexpr unsigned int RX_SIZE = RX_BUFFER_SIZE; + static constexpr unsigned int TX_SIZE = TX_BUFFER_SIZE; + static constexpr bool XONOFF = bSERIAL_XON_XOFF; + static constexpr bool EMERGENCYPARSER = bEMERGENCY_PARSER; + static constexpr bool DROPPED_RX = bSERIAL_STATS_DROPPED_RX; + static constexpr bool RX_OVERRUNS = bSERIAL_STATS_RX_BUFFER_OVERRUNS; static constexpr bool RX_FRAMING_ERRORS = bSERIAL_STATS_RX_FRAMING_ERRORS; - static constexpr bool MAX_RX_QUEUED = bSERIAL_STATS_MAX_RX_QUEUED; + static constexpr bool MAX_RX_QUEUED = bSERIAL_STATS_MAX_RX_QUEUED; }; extern MarlinSerial customizedSerial; diff --git a/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp b/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp index e9848d1c5382..7efa85e0500e 100644 --- a/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp +++ b/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp @@ -68,8 +68,7 @@ // Read the character from the USART uint8_t c = HWUART->UART_RHR; - if (Cfg::EMERGENCYPARSER) - emergency_parser.update(emergency_state, c); + 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 @@ -78,17 +77,14 @@ rx_buffer.buffer[h] = c; h = i; } - else { - if (Cfg::DROPPED_RX) - if (!++rx_dropped_bytes) --rx_dropped_bytes; - } + else if (Cfg::DROPPED_RX && !++rx_dropped_bytes) + --rx_dropped_bytes; const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1); // Calculate count of bytes stored into the RX buffer // Keep track of the maximum count of enqueued bytes - if (Cfg::MAX_RX_QUEUED) - NOLESS(rx_max_enqueued, rx_count); + if (Cfg::MAX_RX_QUEUED) NOLESS(rx_max_enqueued, rx_count); if (Cfg::XONOFF) { // If the last char that was sent was an XON @@ -125,8 +121,7 @@ // Read the character from the USART c = HWUART->UART_RHR; - if (Cfg::EMERGENCYPARSER) - emergency_parser.update(emergency_state, c); + 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 @@ -135,10 +130,8 @@ rx_buffer.buffer[h] = c; h = i; } - else { - if (Cfg::DROPPED_RX) - if (!++rx_dropped_bytes) --rx_dropped_bytes; - } + else if (Cfg::DROPPED_RX && !++rx_dropped_bytes) + --rx_dropped_bytes; } sw_barrier(); } @@ -162,8 +155,7 @@ // Read the character from the USART c = HWUART->UART_RHR; - if (Cfg::EMERGENCYPARSER) - emergency_parser.update(emergency_state, c); + 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 @@ -172,10 +164,8 @@ rx_buffer.buffer[h] = c; h = i; } - else { - if (Cfg::DROPPED_RX) - if (!++rx_dropped_bytes) --rx_dropped_bytes; - } + else if (Cfg::DROPPED_RX && !++rx_dropped_bytes) + --rx_dropped_bytes; } sw_barrier(); } @@ -247,12 +237,9 @@ // Acknowledge errors if ((status & UART_SR_OVRE) || (status & UART_SR_FRAME)) { - if (Cfg::DROPPED_RX) - if (status & UART_SR_OVRE && !++rx_dropped_bytes) --rx_dropped_bytes; - if (Cfg::RX_OVERRUNS) - if (status & UART_SR_OVRE && !++rx_buffer_overruns) --rx_buffer_overruns; - if (Cfg::RX_FRAMING_ERRORS) - if (status & UART_SR_FRAME && !++rx_framing_errors) --rx_framing_errors; + if (Cfg::DROPPED_RX && (status & UART_SR_OVRE) && !++rx_dropped_bytes) --rx_dropped_bytes; + if (Cfg::RX_OVERRUNS && (status & UART_SR_OVRE) && !++rx_buffer_overruns) --rx_buffer_overruns; + if (Cfg::RX_FRAMING_ERRORS && (status & UART_SR_FRAME) && !++rx_framing_errors) --rx_framing_errors; // TODO: error reporting outside ISR HWUART->UART_CR = UART_CR_RSTSTA; @@ -307,8 +294,7 @@ // Enable receiver and transmitter HWUART->UART_CR = UART_CR_RXEN | UART_CR_TXEN; - if (Cfg::TX_SIZE > 0) - _written = false; + if (Cfg::TX_SIZE > 0) _written = false; } template @@ -356,7 +342,8 @@ xon_xoff_state = XON_CHAR; // Enable TX isr. HWUART->UART_IER = UART_IER_TXRDY; - } else { + } + else { // If not using TX interrupts, we must send the XON char now xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT; while (!(HWUART->UART_SR & UART_SR_TXRDY)) sw_barrier(); @@ -386,7 +373,8 @@ xon_xoff_state = XON_CHAR; // Enable TX isr. HWUART->UART_IER = UART_IER_TXRDY; - } else { + } + else { // If not using TX interrupts, we must send the XON char now xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT; while (!(HWUART->UART_SR & UART_SR_TXRDY)) sw_barrier(); @@ -403,7 +391,8 @@ if (Cfg::TX_SIZE == 0) { while (!(HWUART->UART_SR & UART_SR_TXRDY)) sw_barrier(); HWUART->UART_THR = c; - } else { + } + else { // If the TX interrupts are disabled and the data register // is empty, just write the byte to the data register and @@ -459,7 +448,8 @@ // At this point nothing is queued anymore (DRIE is disabled) and // the hardware finished transmission (TXC is set). - } else { + } + else { // If we have never written a byte, no need to flush. This special // case is needed since there is no way to force the TXC (transmit // complete) bit to 1 during initialization @@ -486,7 +476,6 @@ } } - /** * Imports from print.h */ diff --git a/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h b/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h index c5d611ead51a..7e20596b4c2f 100644 --- a/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h +++ b/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.h @@ -163,15 +163,15 @@ class MarlinSerial { // Serial port configuration struct MarlinSerialCfg { - static constexpr int PORT = SERIAL_PORT; - static constexpr int RX_SIZE = RX_BUFFER_SIZE; - static constexpr int TX_SIZE = TX_BUFFER_SIZE; - static constexpr bool XONOFF = bSERIAL_XON_XOFF; - static constexpr bool EMERGENCYPARSER = bEMERGENCY_PARSER; - static constexpr bool DROPPED_RX = bSERIAL_STATS_DROPPED_RX; - static constexpr bool RX_OVERRUNS = bSERIAL_STATS_RX_BUFFER_OVERRUNS; + static constexpr int PORT = SERIAL_PORT; + static constexpr unsigned int RX_SIZE = RX_BUFFER_SIZE; + static constexpr unsigned int TX_SIZE = TX_BUFFER_SIZE; + static constexpr bool XONOFF = bSERIAL_XON_XOFF; + static constexpr bool EMERGENCYPARSER = bEMERGENCY_PARSER; + static constexpr bool DROPPED_RX = bSERIAL_STATS_DROPPED_RX; + static constexpr bool RX_OVERRUNS = bSERIAL_STATS_RX_BUFFER_OVERRUNS; static constexpr bool RX_FRAMING_ERRORS = bSERIAL_STATS_RX_FRAMING_ERRORS; - static constexpr bool MAX_RX_QUEUED = bSERIAL_STATS_MAX_RX_QUEUED; + static constexpr bool MAX_RX_QUEUED = bSERIAL_STATS_MAX_RX_QUEUED; }; extern MarlinSerial customizedSerial;