diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 3f3a83648..d4075fedc 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -107,7 +107,7 @@ * * 250000 works in most cases, but you might try a lower speed if * you commonly experience drop-outs during host printing. - * You may try up to 1000000 to speed up file transfer to the SD card + * You may try up to 1000000 to speed up SD file transfer. * * :[2400, 9600, 19200, 38400, 57600, 115200, 250000, 500000, 1000000] */ diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 1a627a0dd..33a9ca48f 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -740,24 +740,27 @@ // :[0, 2, 4, 8, 16, 32, 64, 128, 256] #define TX_BUFFER_SIZE 0 -// Reception from Host Buffer Size -// This is the size of the Reception buffer. If XON/XOFF software flow control -// is not enabled, then 32 bytes should be enough. But if you plan to use XON/XOFF -// you need 1024 bytes at least. +// Host Receive Buffer Size +// Without XON/XOFF flow control (see SERIAL_XON_XOFF below) 32 bytes should be enough. +// To use flow control, set this buffer size to at least 1024 bytes. // :[0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048] -#define RX_BUFFER_SIZE 1024 +//#define RX_BUFFER_SIZE 1024 -// This setting determines if the printer will send the XON/XOFF -// control characters to the host to signal RX buffer is becoming full -#define SERIAL_XON_XOFF 1 +#if RX_BUFFER_SIZE >= 1024 + // Enable to have the controller send XON/XOFF control characters to + // the host to signal the RX buffer is becoming full. + //#define SERIAL_XON_XOFF +#endif -// This setting determines if you want to display and collect -// maximum RX queue usage after transferring a file to the SD -//#define SERIAL_STATS_MAX_RX_QUEUED 1 +#if ENABLED(SDSUPPORT) + // Enable this option to collect and display the maximum + // RX queue usage after transferring a file to SD. + //#define SERIAL_STATS_MAX_RX_QUEUED -// This setting determines if you want to display and collect -// the number of dropped bytes after a file transfer to the SD -#define SERIAL_STATS_DROPPED_RX 1 + // Enable this option to collect and display the number + // of dropped bytes after a file transfer to SD. + //#define SERIAL_STATS_DROPPED_RX +#endif // Enable an emergency-command parser to intercept certain commands as they // enter the serial receive buffer, so they cannot be blocked. diff --git a/Marlin/MarlinSerial.cpp b/Marlin/MarlinSerial.cpp index 8a881db22..778125818 100644 --- a/Marlin/MarlinSerial.cpp +++ b/Marlin/MarlinSerial.cpp @@ -27,15 +27,30 @@ * Modified 23 November 2006 by David A. Mellis * 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) */ -#include "MarlinSerial.h" -#include "Marlin.h" - // Disable HardwareSerial.cpp to support chips without a UART (Attiny, etc.) +#include "MarlinConfig.h" + #if !defined(USBCON) && (defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(UBRR2H) || defined(UBRR3H)) + #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 @@ -45,15 +60,21 @@ #endif #if ENABLED(SERIAL_XON_XOFF) - uint8_t xon_xoff_state = XON_XOFF_CHAR_SENT | XON_CHAR; + uint8_t xon_xoff_state = XON_XOFF_CHAR_SENT | XON_CHAR; + constexpr uint8_t XON_XOFF_CHAR_SENT = 0x80; // XON / XOFF Character was sent + constexpr uint8_t XON_XOFF_CHAR_MASK = 0x1F; // XON / XOFF character to send + // XON / XOFF character definitions + constexpr uint8_t XON_CHAR = 17; + constexpr uint8_t XOFF_CHAR = 19; #endif - + #if ENABLED(SERIAL_STATS_DROPPED_RX) - uint8_t rx_dropped_bytes = 0; + uint8_t rx_dropped_bytes = 0; #endif + #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) - ring_buffer_pos_t rx_max_enqueued = 0; - #endif + ring_buffer_pos_t rx_max_enqueued = 0; + #endif #if ENABLED(EMERGENCY_PARSER) @@ -149,92 +170,76 @@ FORCE_INLINE void store_rxd_char() { const ring_buffer_pos_t h = rx_buffer.head, - 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_BUFFER_SIZE - 1); - // if we should be storing the received character into the location - // just before the tail (meaning that the head would advance to the - // current location of the tail), we're about to overflow the buffer - // and so we don't write the character or advance the head. - if (i != rx_buffer.tail) { + // 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 buffer is + // critical, so don't write the character or advance the head. + if (i != rx_buffer.tail) { rx_buffer.buffer[h] = M_UDRx; - rx_buffer.head = i; + rx_buffer.head = i; + } + else { + (void)M_UDRx; + #if ENABLED(SERIAL_STATS_DROPPED_RX) + if (!++rx_dropped_bytes) ++rx_dropped_bytes; + #endif + } + + #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) + // calculate count of bytes stored into the RX buffer + ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(rx_buffer.head - rx_buffer.tail) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1); + // Keep track of the maximum count of enqueued bytes + NOLESS(rx_max_enqueued, rx_count); + #endif + + #if ENABLED(SERIAL_XON_XOFF) + + // for high speed transfers, we can use XON/XOFF protocol to do + // software handshake and avoid overruns. + if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XON_CHAR) { + + // calculate count of bytes stored into the RX buffer + ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(rx_buffer.head - rx_buffer.tail) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1); + + // if we are above 12.5% of RX buffer capacity, send XOFF before + // we run out of RX buffer space .. We need 325 bytes @ 250kbits/s to + // let the host react and stop sending bytes. This translates to 13mS + // propagation time. + if (rx_count >= (RX_BUFFER_SIZE) / 8) { + // If TX interrupts are disabled and data register is empty, + // just write the byte to the data register and be done. This + // shortcut helps significantly improve the effective datarate + // at high (>500kbit/s) bitrates, where interrupt overhead + // becomes a slowdown. + if (!TEST(M_UCSRxB, M_UDRIEx) && TEST(M_UCSRxA, M_UDREx)) { + // Send an XOFF character + M_UDRx = 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); + // And remember it was sent + xon_xoff_state = XOFF_CHAR | XON_XOFF_CHAR_SENT; + } + else { + // TX interrupts disabled, but buffer still not empty ... or + // TX interrupts enabled. Reenable TX ints and schedule XOFF + // character to be sent + #if TX_BUFFER_SIZE > 0 + SBI(M_UCSRxB, M_UDRIEx); + xon_xoff_state = XOFF_CHAR; + #else + // We are not using TX interrupts, we will have to send this manually + while (!TEST(M_UCSRxA, M_UDREx)) {/* nada */} + M_UDRx = XOFF_CHAR; + // And remember we already sent it + xon_xoff_state = XOFF_CHAR | XON_XOFF_CHAR_SENT; + #endif + } + } } - else { - (void)M_UDRx; - #if ENABLED(SERIAL_STATS_DROPPED_RX) - if (!++rx_dropped_bytes) - ++rx_dropped_bytes; - #endif - } - #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) - { - // calculate count of bytes stored into the RX buffer - ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(rx_buffer.head - rx_buffer.tail) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1); - - // Keep track of the maximum count of enqueued bytes - if (rx_max_enqueued < rx_count) - rx_max_enqueued = rx_count; - } - #endif - - #if ENABLED(SERIAL_XON_XOFF) - - // for high speed transfers, we can use XON/XOFF protocol to do - // software handshake and avoid overruns. - if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XON_CHAR) { - - // calculate count of bytes stored into the RX buffer - ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(rx_buffer.head - rx_buffer.tail) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1); - - // if we are above 12.5% of RX buffer capacity, send XOFF before - // we run out of RX buffer space .. We need 325 bytes @ 250kbits/s to - // let the host react and stop sending bytes. This translates to 13mS - // propagation time. - if (rx_count >= (RX_BUFFER_SIZE/8)) { - - // If TX interrupts are disabled and data register is empty, - // just write the byte to the data register and be done. This - // shortcut helps significantly improve the effective datarate - // at high (>500kbit/s) bitrates, where interrupt overhead - // becomes a slowdown. - if (!TEST(M_UCSRxB, M_UDRIEx) && TEST(M_UCSRxA, M_UDREx)) { - - // Send an XOFF character - M_UDRx = 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); - - // And remember we already sent it - xon_xoff_state = XOFF_CHAR | XON_XOFF_CHAR_SENT; - - } else { - - // TX interrupts disabled, but buffer still not empty ... or - // TX interrupts enabled. Reenable TX ints and schedule XOFF - // character to be sent - #if TX_BUFFER_SIZE > 0 - - SBI(M_UCSRxB, M_UDRIEx); - xon_xoff_state = XOFF_CHAR; - - #else - // We are not using TX interrupts, we will have to send this manually - while (!TEST(M_UCSRxA, M_UDREx)) - ; - M_UDRx = XOFF_CHAR; - - // And remember we already sent it - xon_xoff_state = XOFF_CHAR | XON_XOFF_CHAR_SENT; - - #endif - } - - } - } - #endif + #endif // SERIAL_XON_XOFF #if ENABLED(EMERGENCY_PARSER) emergency_parser(c); @@ -247,52 +252,39 @@ // If interrupts are enabled, there must be more data in the output // buffer. - #if ENABLED(SERIAL_XON_XOFF) - - // If we must do a priority insertion of an XON/XOFF char, - // do it now - uint8_t state = xon_xoff_state; - if (!(state & XON_XOFF_CHAR_SENT)) { - M_UDRx = state & XON_XOFF_CHAR_MASK; - xon_xoff_state = state | XON_XOFF_CHAR_SENT; - - } else { - #endif - - // Send the next byte - const uint8_t t = tx_buffer.tail, - c = tx_buffer.buffer[t]; - tx_buffer.tail = (t + 1) & (TX_BUFFER_SIZE - 1); - - M_UDRx = c; + #if ENABLED(SERIAL_XON_XOFF) + // Do a priority insertion of an XON/XOFF char, if needed. + const uint8_t state = xon_xoff_state; + if (!(state & XON_XOFF_CHAR_SENT)) { + M_UDRx = state & XON_XOFF_CHAR_MASK; + xon_xoff_state = state | XON_XOFF_CHAR_SENT; + } + else + #endif + { // Send the next byte + const uint8_t t = tx_buffer.tail, c = tx_buffer.buffer[t]; + tx_buffer.tail = (t + 1) & (TX_BUFFER_SIZE - 1); + M_UDRx = c; + } - #if ENABLED(SERIAL_XON_XOFF) - } - #endif - // 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); - if (tx_buffer.head == tx_buffer.tail) { - // Buffer empty, so disable interrupts + // Disable interrupts if the buffer is empty + if (tx_buffer.head == tx_buffer.tail) CBI(M_UCSRxB, M_UDRIEx); - } } #ifdef M_USARTx_UDRE_vect - ISR(M_USARTx_UDRE_vect) { - _tx_udr_empty_irq(); - } + 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(); - } + ISR(M_USARTx_RX_vect) { store_rxd_char(); } #endif // Public Methods @@ -302,9 +294,9 @@ bool useU2X = true; #if F_CPU == 16000000UL && SERIAL_PORT == 0 - // hard-coded exception for compatibility with the bootloader shipped - // with the Duemilanove and previous boards and the firmware on the 8U2 - // on the Uno and Mega 2560. + // Hard-coded exception for compatibility with the bootloader shipped + // with the Duemilanove and previous boards, and the firmware on the + // 8U2 on the Uno and Mega 2560. if (baud == 57600) useU2X = false; #endif @@ -339,9 +331,9 @@ void MarlinSerial::checkRx(void) { if (TEST(M_UCSRxA, M_RXCx)) { - CRITICAL_SECTION_START; + CRITICAL_SECTION_START; store_rxd_char(); - CRITICAL_SECTION_END; + CRITICAL_SECTION_END; } } @@ -361,35 +353,21 @@ else { v = rx_buffer.buffer[t]; rx_buffer.tail = (ring_buffer_pos_t)(t + 1) & (RX_BUFFER_SIZE - 1); - - #if ENABLED(SERIAL_XON_XOFF) - - // for high speed transfers, we can use XON/XOFF protocol to do - // software handshake and avoid overruns. - if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) { - - // calculate count of bytes stored into the RX buffer - ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(rx_buffer.head - rx_buffer.tail) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1); - - // if we are below 10% of RX buffer capacity, send XON before - // we run out of RX buffer bytes - if (rx_count < (RX_BUFFER_SIZE/10)) { - - // Send an XON character - xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT; - - // End critical section - CRITICAL_SECTION_END; - - // Transmit the XON character - writeNoHandshake(XON_CHAR); - - // Done - return v; - } - } - #endif - + + #if ENABLED(SERIAL_XON_XOFF) + if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) { + // Get count of bytes in the RX buffer + ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(rx_buffer.head - rx_buffer.tail) & (ring_buffer_pos_t)(RX_BUFFER_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) { + xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT; + CRITICAL_SECTION_END; // End critical section before returning! + writeNoHandshake(XON_CHAR); + return v; + } + } + #endif } CRITICAL_SECTION_END; return v; @@ -397,68 +375,53 @@ ring_buffer_pos_t MarlinSerial::available(void) { CRITICAL_SECTION_START; - const ring_buffer_pos_t h = rx_buffer.head, - t = rx_buffer.tail; + const ring_buffer_pos_t h = rx_buffer.head, t = rx_buffer.tail; CRITICAL_SECTION_END; return (ring_buffer_pos_t)(RX_BUFFER_SIZE + h - t) & (RX_BUFFER_SIZE - 1); } void MarlinSerial::flush(void) { - // RX - // don't reverse this or there may be problems if the RX interrupt - // occurs after reading the value of rx_buffer_head but before writing - // the value to rx_buffer_tail; the previous value of rx_buffer_head - // may be written to rx_buffer_tail, making it appear as if the buffer - // were full, not empty. + // Don't change this order of operations. If the RX interrupt occurs between + // reading rx_buffer_head and updating rx_buffer_tail, the previous rx_buffer_head + // may be written to rx_buffer_tail, making the buffer appear full rather than empty. CRITICAL_SECTION_START; rx_buffer.head = rx_buffer.tail; CRITICAL_SECTION_END; - - #if ENABLED(SERIAL_XON_XOFF) - - // for high speed transfers, we can use XON/XOFF protocol to do - // software handshake and avoid overruns. - if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) { - - // Send an XON character - xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT; - - // Transmit the XON character - writeNoHandshake(XON_CHAR); - } - #endif + + #if ENABLED(SERIAL_XON_XOFF) + if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) { + xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT; + writeNoHandshake(XON_CHAR); + } + #endif } #if TX_BUFFER_SIZE > 0 uint8_t MarlinSerial::availableForWrite(void) { CRITICAL_SECTION_START; - const uint8_t h = tx_buffer.head, - t = tx_buffer.tail; + const uint8_t h = tx_buffer.head, t = tx_buffer.tail; CRITICAL_SECTION_END; return (uint8_t)(TX_BUFFER_SIZE + h - t) & (TX_BUFFER_SIZE - 1); } void MarlinSerial::write(const uint8_t c) { - - #if ENABLED(SERIAL_XON_XOFF) - uint8_t state = xon_xoff_state; - if (!(state & XON_XOFF_CHAR_SENT)) { - // 2 characters to send: The XON/XOFF character and the user - // specified char. - writeNoHandshake(state & XON_XOFF_CHAR_MASK); - xon_xoff_state = state | XON_XOFF_CHAR_SENT; - } - #endif - writeNoHandshake(c); + #if ENABLED(SERIAL_XON_XOFF) + const uint8_t state = xon_xoff_state; + if (!(state & XON_XOFF_CHAR_SENT)) { + // Send 2 chars: XON/XOFF, then a user-specified char + writeNoHandshake(state & XON_XOFF_CHAR_MASK); + xon_xoff_state = state | XON_XOFF_CHAR_SENT; + } + #endif + writeNoHandshake(c); } - - void MarlinSerial::writeNoHandshake(uint8_t c) { - + + void MarlinSerial::writeNoHandshake(const uint8_t c) { _written = true; CRITICAL_SECTION_START; bool emty = (tx_buffer.head == tx_buffer.tail); CRITICAL_SECTION_END; - + // If the buffer and the data register is empty, just write the byte // to the data register and be done. This shortcut helps // significantly improve the effective datarate at high (> @@ -497,7 +460,6 @@ return; } - void MarlinSerial::flushTX(void) { // TX // If we have never written a byte, no need to flush. This special @@ -516,35 +478,32 @@ } // If we get here, nothing is queued anymore (DRIE is disabled) and // the hardware finished tranmission (TXC is set). - } + } - #else - void MarlinSerial::write(uint8_t c) { - - #if ENABLED(SERIAL_XON_XOFF) - // If we must do a priority insertion of an XON/XOFF char, do it now - uint8_t state = xon_xoff_state; - if (!(state & XON_XOFF_CHAR_SENT)) { - - writeNoHandshake(state & XON_XOFF_CHAR_MASK); - xon_xoff_state = state | XON_XOFF_CHAR_SENT; - } - #endif - - writeNoHandshake(c); + #else // TX_BUFFER_SIZE == 0 + + void MarlinSerial::write(const uint8_t c) { + #if ENABLED(SERIAL_XON_XOFF) + // Do a priority insertion of an XON/XOFF char, if needed. + const uint8_t state = xon_xoff_state; + if (!(state & XON_XOFF_CHAR_SENT)) { + writeNoHandshake(state & XON_XOFF_CHAR_MASK); + xon_xoff_state = state | XON_XOFF_CHAR_SENT; + } + #endif + writeNoHandshake(c); } - + void MarlinSerial::writeNoHandshake(uint8_t c) { - while (!TEST(M_UCSRxA, M_UDREx)) - ; + while (!TEST(M_UCSRxA, M_UDREx)) {/* nada */} M_UDRx = c; } - #endif - - // end NEW - /// imports from print.h + #endif // TX_BUFFER_SIZE == 0 + /** + * Imports from print.h + */ void MarlinSerial::print(char c, int base) { print((long)c, base); diff --git a/Marlin/MarlinSerial.h b/Marlin/MarlinSerial.h index b0de0bb87..a6c4728ce 100644 --- a/Marlin/MarlinSerial.h +++ b/Marlin/MarlinSerial.h @@ -84,61 +84,32 @@ #ifndef RX_BUFFER_SIZE #define RX_BUFFER_SIZE 128 #endif - #if ENABLED(SERIAL_XON_XOFF) && RX_BUFFER_SIZE < 1024 - #error "XON/XOFF requires a 1024 or greater RX_BUFFER_SIZE for allowing reliable transfers without drops" - #endif #ifndef TX_BUFFER_SIZE #define TX_BUFFER_SIZE 32 #endif - #if !IS_POWEROF2(RX_BUFFER_SIZE) || (RX_BUFFER_SIZE < 2) - #error "RX_BUFFER_SIZE has to be a power of 2 and >= 2" - #endif - #if TX_BUFFER_SIZE != 0 && (TX_BUFFER_SIZE < 2 || TX_BUFFER_SIZE > 256 || !IS_POWEROF2(TX_BUFFER_SIZE)) - #error "TX_BUFFER_SIZE has to be a power of 2 or 0" - #endif - #if RX_BUFFER_SIZE > 256 - typedef uint16_t ring_buffer_pos_t; - #else - typedef uint8_t ring_buffer_pos_t; - #endif - - struct ring_buffer_r { - unsigned char buffer[RX_BUFFER_SIZE]; - volatile ring_buffer_pos_t head; - volatile ring_buffer_pos_t tail; - }; - #if TX_BUFFER_SIZE > 0 - struct ring_buffer_t { - unsigned char buffer[TX_BUFFER_SIZE]; - volatile uint8_t head; - volatile uint8_t tail; - }; + #if ENABLED(SERIAL_XON_XOFF) && RX_BUFFER_SIZE < 1024 + #error "XON/XOFF requires RX_BUFFER_SIZE >= 1024 for reliable transfers without drops." #endif - - #if UART_PRESENT(SERIAL_PORT) - extern ring_buffer_r rx_buffer; - #if TX_BUFFER_SIZE > 0 - extern ring_buffer_t tx_buffer; - #endif + #if !IS_POWER_OF_2(RX_BUFFER_SIZE) || RX_BUFFER_SIZE < 2 + #error "RX_BUFFER_SIZE must be a power of 2 greater than 1." + #endif + #if TX_BUFFER_SIZE && (TX_BUFFER_SIZE < 2 || TX_BUFFER_SIZE > 256 || !IS_POWER_OF_2(TX_BUFFER_SIZE)) + #error "TX_BUFFER_SIZE must be 0 or a power of 2 greater than 1." #endif - #if ENABLED(SERIAL_XON_XOFF) - #define XON_XOFF_CHAR_SENT (uint8_t)0x80 /* XON / XOFF Character was sent */ - #define XON_XOFF_CHAR_MASK (uint8_t)0x1F /* XON / XOFF character to send */ - - extern uint8_t xon_xoff_state; - - // XON / XOFF character definitions - #define XON_CHAR (uint8_t)17 - #define XOFF_CHAR (uint8_t)19 + #if RX_BUFFER_SIZE > 256 + typedef uint16_t ring_buffer_pos_t; + #else + typedef uint8_t ring_buffer_pos_t; #endif #if ENABLED(SERIAL_STATS_DROPPED_RX) - extern uint8_t rx_dropped_bytes; + extern uint8_t rx_dropped_bytes; #endif + #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) - extern ring_buffer_pos_t rx_max_enqueued; + extern ring_buffer_pos_t rx_max_enqueued; #endif class MarlinSerial { //: public Stream @@ -157,14 +128,15 @@ static uint8_t availableForWrite(void); static void flushTX(void); #endif - static void writeNoHandshake(uint8_t c); + static void writeNoHandshake(const uint8_t c); - #if ENABLED(SERIAL_STATS_DROPPED_RX) - static uint32_t dropped() { return rx_dropped_bytes; } - #endif - #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) - static ring_buffer_pos_t rxMaxEnqueued() { return rx_max_enqueued; } - #endif + #if ENABLED(SERIAL_STATS_DROPPED_RX) + FORCE_INLINE static uint32_t dropped() { return rx_dropped_bytes; } + #endif + + #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) + FORCE_INLINE static ring_buffer_pos_t rxMaxEnqueued() { return rx_max_enqueued; } + #endif private: static void printNumber(unsigned long, const uint8_t); diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 9d5963054..043480aa7 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -1097,7 +1097,7 @@ inline void get_serial_commands() { int c; while (commands_in_queue < BUFSIZE && (c = MYSERIAL.read()) >= 0) { - char serial_char = c; + char serial_char = c; /** * If the character ends the line @@ -13330,12 +13330,15 @@ void loop() { // M29 closes the file card.closefile(); SERIAL_PROTOCOLLNPGM(MSG_FILE_SAVED); - #if ENABLED(SERIAL_STATS_DROPPED_RX) - SERIAL_ECHOLNPAIR("Dropped bytes: ", MarlinSerial::dropped()); - #endif - #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) - SERIAL_ECHOLNPAIR("Max RX Queue Size: ", MarlinSerial::rxMaxEnqueued()); - #endif + + #if ENABLED(SERIAL_STATS_DROPPED_RX) + SERIAL_ECHOLNPAIR("Dropped bytes: ", customizedSerial.dropped()); + #endif + + #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED) + SERIAL_ECHOLNPAIR("Max RX Queue Size: ", customizedSerial.rxMaxEnqueued()); + #endif + ok_to_send(); } else { diff --git a/Marlin/macros.h b/Marlin/macros.h index 9c45ba38e..05433597f 100644 --- a/Marlin/macros.h +++ b/Marlin/macros.h @@ -100,7 +100,7 @@ #define SET_BIT(n,b,value) (n) ^= ((-value)^(n)) & (_BV(b)) // Macro to check that a number if a power if 2 -#define IS_POWEROF2(x) ((x) && !((x) & ((x) - 1))) +#define IS_POWER_OF_2(x) ((x) && !((x) & ((x) - 1))) // Macros for maths shortcuts #ifndef M_PI