diff --git a/Marlin/G26_Mesh_Validation_Tool.cpp b/Marlin/G26_Mesh_Validation_Tool.cpp
index b67b080ce..d00369d57 100644
--- a/Marlin/G26_Mesh_Validation_Tool.cpp
+++ b/Marlin/G26_Mesh_Validation_Tool.cpp
@@ -128,7 +128,7 @@
extern bool code_value_bool();
extern bool code_has_value();
extern void lcd_init();
- extern void lcd_setstatuspgm(const char* const message, uint8_t level);
+ extern void lcd_setstatuspgm(const char* const message, const uint8_t level);
#define PLANNER_XY_FEEDRATE() (min(planner.max_feedrate_mm_s[X_AXIS], planner.max_feedrate_mm_s[Y_AXIS])) //bob
bool prepare_move_to_destination_cartesian();
void line_to_destination();
@@ -156,7 +156,7 @@
// won't leave us in a bad state.
float valid_trig_angle(float);
- mesh_index_pair find_closest_circle_to_print(float, float);
+ mesh_index_pair find_closest_circle_to_print(const float&, const float&);
static float extrusion_multiplier = EXTRUSION_MULTIPLIER,
retraction_multiplier = RETRACTION_MULTIPLIER,
@@ -183,8 +183,8 @@
int i, xi, yi;
mesh_index_pair location;
- // Don't allow Mesh Validation without homing first
- // If the paramter parsing did not go OK, we abort the command
+ // Don't allow Mesh Validation without homing first,
+ // or if the parameter parsing did not go OK, abort
if (axis_unhomed_error(true, true, true) || parse_G26_parameters()) return;
if (current_position[Z_AXIS] < Z_CLEARANCE_BETWEEN_PROBES) {
@@ -391,8 +391,8 @@
return d;
}
- mesh_index_pair find_closest_circle_to_print( float X, float Y) {
- float f, mx, my, dx, dy, closest = 99999.99;
+ mesh_index_pair find_closest_circle_to_print(const float &X, const float &Y) {
+ float closest = 99999.99;
mesh_index_pair return_val;
return_val.x_index = return_val.y_index = -1;
@@ -400,28 +400,27 @@
for (uint8_t i = 0; i < UBL_MESH_NUM_X_POINTS; i++) {
for (uint8_t j = 0; j < UBL_MESH_NUM_Y_POINTS; j++) {
if (!is_bit_set(circle_flags, i, j)) {
- mx = ubl.mesh_index_to_xpos[i]; // We found a circle that needs to be printed
- my = ubl.mesh_index_to_ypos[j];
+ const float mx = ubl.mesh_index_to_xpos[i], // We found a circle that needs to be printed
+ my = ubl.mesh_index_to_ypos[j];
- dx = X - mx; // Get the distance to this intersection
- dy = Y - my;
- f = HYPOT(dx, dy);
+ // Get the distance to this intersection
+ float f = HYPOT(X - mx, Y - my);
- dx = x_pos - mx; // It is possible that we are being called with the values
- dy = y_pos - my; // to let us find the closest circle to the start position.
- f += HYPOT(dx, dy) / 15.0; // But if this is not the case,
- // we are going to add in a small
- // weighting to the distance calculation to help it choose
- // a better place to continue.
+ // It is possible that we are being called with the values
+ // to let us find the closest circle to the start position.
+ // But if this is not the case, add a small weighting to the
+ // distance calculation to help it choose a better place to continue.
+ f += HYPOT(x_pos - mx, y_pos - my) / 15.0;
+ // Add in the specified amount of Random Noise to our search
if (random_deviation > 1.0)
- f += random(0.0, random_deviation); // Add in the specified amount of Random Noise to our search
+ f += random(0.0, random_deviation);
if (f < closest) {
closest = f; // We found a closer location that is still
return_val.x_index = i; // un-printed --- save the data for it
return_val.y_index = j;
- return_val.distance= closest;
+ return_val.distance = closest;
}
}
}
diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h
index 218291b4c..86d4bb033 100644
--- a/Marlin/Marlin.h
+++ b/Marlin/Marlin.h
@@ -39,19 +39,7 @@
#include "types.h"
#include "fastio.h"
#include "utility.h"
-
-#ifdef USBCON
- #include "HardwareSerial.h"
- #if ENABLED(BLUETOOTH)
- #define MYSERIAL bluetoothSerial
- #else
- #define MYSERIAL Serial
- #endif // BLUETOOTH
-#else
- #include "MarlinSerial.h"
- #define MYSERIAL customizedSerial
-#endif
-
+#include "serial.h"
#include "WString.h"
#if ENABLED(PRINTCOUNTER)
@@ -60,54 +48,6 @@
#include "stopwatch.h"
#endif
-extern const char echomagic[] PROGMEM;
-extern const char errormagic[] PROGMEM;
-
-#define SERIAL_CHAR(x) (MYSERIAL.write(x))
-#define SERIAL_EOL SERIAL_CHAR('\n')
-
-#define SERIAL_PROTOCOLCHAR(x) SERIAL_CHAR(x)
-#define SERIAL_PROTOCOL(x) (MYSERIAL.print(x))
-#define SERIAL_PROTOCOL_F(x,y) (MYSERIAL.print(x,y))
-#define SERIAL_PROTOCOLPGM(x) (serialprintPGM(PSTR(x)))
-#define SERIAL_PROTOCOLLN(x) do{ MYSERIAL.print(x); SERIAL_EOL; }while(0)
-#define SERIAL_PROTOCOLLNPGM(x) (serialprintPGM(PSTR(x "\n")))
-#define SERIAL_PROTOCOLPAIR(name, value) (serial_echopair_P(PSTR(name),(value)))
-#define SERIAL_PROTOCOLLNPAIR(name, value) do{ SERIAL_PROTOCOLPAIR(name, value); SERIAL_EOL; }while(0)
-
-#define SERIAL_ECHO_START (serialprintPGM(echomagic))
-#define SERIAL_ECHO(x) SERIAL_PROTOCOL(x)
-#define SERIAL_ECHOPGM(x) SERIAL_PROTOCOLPGM(x)
-#define SERIAL_ECHOLN(x) SERIAL_PROTOCOLLN(x)
-#define SERIAL_ECHOLNPGM(x) SERIAL_PROTOCOLLNPGM(x)
-#define SERIAL_ECHOPAIR(name,value) SERIAL_PROTOCOLPAIR(name, value)
-#define SERIAL_ECHOLNPAIR(name, value) SERIAL_PROTOCOLLNPAIR(name, value)
-#define SERIAL_ECHO_F(x,y) SERIAL_PROTOCOL_F(x,y)
-
-#define SERIAL_ERROR_START (serialprintPGM(errormagic))
-#define SERIAL_ERROR(x) SERIAL_PROTOCOL(x)
-#define SERIAL_ERRORPGM(x) SERIAL_PROTOCOLPGM(x)
-#define SERIAL_ERRORLN(x) SERIAL_PROTOCOLLN(x)
-#define SERIAL_ERRORLNPGM(x) SERIAL_PROTOCOLLNPGM(x)
-
-void serial_echopair_P(const char* s_P, const char *v);
-void serial_echopair_P(const char* s_P, char v);
-void serial_echopair_P(const char* s_P, int v);
-void serial_echopair_P(const char* s_P, long v);
-void serial_echopair_P(const char* s_P, float v);
-void serial_echopair_P(const char* s_P, double v);
-void serial_echopair_P(const char* s_P, unsigned int v);
-void serial_echopair_P(const char* s_P, unsigned long v);
-FORCE_INLINE void serial_echopair_P(const char* s_P, uint8_t v) { serial_echopair_P(s_P, (int)v); }
-FORCE_INLINE void serial_echopair_P(const char* s_P, uint16_t v) { serial_echopair_P(s_P, (int)v); }
-FORCE_INLINE void serial_echopair_P(const char* s_P, bool v) { serial_echopair_P(s_P, (int)v); }
-FORCE_INLINE void serial_echopair_P(const char* s_P, void *v) { serial_echopair_P(s_P, (unsigned long)v); }
-
-// Things to write to serial from Program memory. Saves 400 to 2k of RAM.
-FORCE_INLINE void serialprintPGM(const char* str) {
- while (char ch = pgm_read_byte(str++)) MYSERIAL.write(ch);
-}
-
void idle(
#if ENABLED(FILAMENT_CHANGE_FEATURE)
bool no_stepper_sleep = false // pass true to keep steppers from disabling on timeout
diff --git a/Marlin/MarlinSerial.cpp b/Marlin/MarlinSerial.cpp
index 38e1b51cf..2004d3657 100644
--- a/Marlin/MarlinSerial.cpp
+++ b/Marlin/MarlinSerial.cpp
@@ -33,495 +33,490 @@
#include "stepper.h"
#include "Marlin.h"
-#ifndef USBCON
-// this next line disables the entire HardwareSerial.cpp,
-// this is so I can support Attiny series and any other chip without a UART
-#if defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(UBRR2H) || defined(UBRR3H)
+// Disable HardwareSerial.cpp to support chips without a UART (Attiny, etc.)
-#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 };
- static bool _written;
+#if !defined(USBCON) && (defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(UBRR2H) || defined(UBRR3H))
+
+ #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 };
+ static bool _written;
+ #endif
#endif
-#endif
-
-
-FORCE_INLINE void store_char(unsigned char c) {
- CRITICAL_SECTION_START;
- uint8_t h = rx_buffer.head;
- uint8_t i = (uint8_t)(h + 1) & (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) {
- rx_buffer.buffer[h] = c;
- rx_buffer.head = i;
- }
- CRITICAL_SECTION_END;
#if ENABLED(EMERGENCY_PARSER)
- emergency_parser(c);
- #endif
-}
-#if TX_BUFFER_SIZE > 0
+ #include "language.h"
- FORCE_INLINE void _tx_udr_empty_irq(void) {
- // If interrupts are enabled, there must be more data in the output
- // buffer. Send the next byte
- uint8_t t = tx_buffer.tail;
- uint8_t c = tx_buffer.buffer[t];
- tx_buffer.tail = (t + 1) & (TX_BUFFER_SIZE - 1);
+ // Currently looking for: M108, M112, M410
+ // If you alter the parser please don't forget to update the capabilities in Conditionals_post.h
- M_UDRx = c;
+ FORCE_INLINE void emergency_parser(const unsigned char 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);
+ static e_parser_state state = state_RESET;
- if (tx_buffer.head == tx_buffer.tail) {
- // Buffer empty, so disable interrupts
- CBI(M_UCSRxB, M_UDRIEx);
- }
- }
+ switch (state) {
+ case state_RESET:
+ switch (c) {
+ case ' ': break;
+ case 'N': state = state_N; break;
+ case 'M': state = state_M; break;
+ default: state = state_IGNORE;
+ }
+ break;
- #ifdef M_USARTx_UDRE_vect
- ISR(M_USARTx_UDRE_vect) {
- _tx_udr_empty_irq();
- }
- #endif
+ case state_N:
+ switch (c) {
+ case '0': case '1': case '2':
+ case '3': case '4': case '5':
+ case '6': case '7': case '8':
+ case '9': case '-': case ' ': break;
+ case 'M': state = state_M; break;
+ default: state = state_IGNORE;
+ }
+ break;
-#endif // TX_BUFFER_SIZE
+ case state_M:
+ switch (c) {
+ case ' ': break;
+ case '1': state = state_M1; break;
+ case '4': state = state_M4; break;
+ default: state = state_IGNORE;
+ }
+ break;
-#ifdef M_USARTx_RX_vect
- ISR(M_USARTx_RX_vect) {
- unsigned char c = M_UDRx;
- store_char(c);
- }
-#endif
+ case state_M1:
+ switch (c) {
+ case '0': state = state_M10; break;
+ case '1': state = state_M11; break;
+ default: state = state_IGNORE;
+ }
+ break;
-// Constructors ////////////////////////////////////////////////////////////////
+ case state_M10:
+ state = (c == '8') ? state_M108 : state_IGNORE;
+ break;
-MarlinSerial::MarlinSerial() { }
+ case state_M11:
+ state = (c == '2') ? state_M112 : state_IGNORE;
+ break;
-// Public Methods //////////////////////////////////////////////////////////////
+ case state_M4:
+ state = (c == '1') ? state_M41 : state_IGNORE;
+ break;
-void MarlinSerial::begin(long baud) {
- uint16_t baud_setting;
- bool useU2X = true;
+ case state_M41:
+ state = (c == '0') ? state_M410 : state_IGNORE;
+ break;
- #if F_CPU == 16000000UL && SERIAL_PORT == 0
- // hard-coded exception for compatibility with the bootloader shipped
- // with the Duemilanove and previous boards and the firmware on the 8U2
- // on the Uno and Mega 2560.
- if (baud == 57600) {
- useU2X = false;
- }
- #endif
+ case state_IGNORE:
+ if (c == '\n') state = state_RESET;
+ break;
- if (useU2X) {
- M_UCSRxA = _BV(M_U2Xx);
- 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);
- _written = false;
- #endif
-}
-
-void MarlinSerial::end() {
- CBI(M_UCSRxB, M_RXENx);
- CBI(M_UCSRxB, M_TXENx);
- CBI(M_UCSRxB, M_RXCIEx);
- CBI(M_UCSRxB, M_UDRIEx);
-}
-
-void MarlinSerial::checkRx(void) {
- if (TEST(M_UCSRxA, M_RXCx)) {
- uint8_t c = M_UDRx;
- store_char(c);
- }
-}
-
-int MarlinSerial::peek(void) {
- CRITICAL_SECTION_START;
- int v = rx_buffer.head == rx_buffer.tail ? -1 : rx_buffer.buffer[rx_buffer.tail];
- CRITICAL_SECTION_END;
- return v;
-}
-
-int MarlinSerial::read(void) {
- int v;
- CRITICAL_SECTION_START;
- uint8_t t = rx_buffer.tail;
- if (rx_buffer.head == t) {
- v = -1;
- }
- else {
- v = rx_buffer.buffer[t];
- rx_buffer.tail = (uint8_t)(t + 1) & (RX_BUFFER_SIZE - 1);
- }
- CRITICAL_SECTION_END;
- return v;
-}
-
-uint8_t MarlinSerial::available(void) {
- CRITICAL_SECTION_START;
- uint8_t h = rx_buffer.head,
- t = rx_buffer.tail;
- CRITICAL_SECTION_END;
- return (uint8_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.
- CRITICAL_SECTION_START;
- rx_buffer.head = rx_buffer.tail;
- CRITICAL_SECTION_END;
-}
-
-#if TX_BUFFER_SIZE > 0
- uint8_t MarlinSerial::availableForWrite(void) {
- CRITICAL_SECTION_START;
- uint8_t h = tx_buffer.head;
- uint8_t t = tx_buffer.tail;
- CRITICAL_SECTION_END;
- return (uint8_t)(TX_BUFFER_SIZE + h - t) & (TX_BUFFER_SIZE - 1);
- }
-
- void MarlinSerial::write(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 (>
- // 500kbit/s) bitrates, where interrupt overhead becomes a slowdown.
- if (emty && TEST(M_UCSRxA, M_UDREx)) {
- CRITICAL_SECTION_START;
- M_UDRx = c;
- SBI(M_UCSRxA, M_TXCx);
- CRITICAL_SECTION_END;
- return;
- }
- uint8_t i = (tx_buffer.head + 1) & (TX_BUFFER_SIZE - 1);
-
- // If the output buffer is full, there's nothing for it other than to
- // wait for the interrupt handler to empty it a bit
- while (i == tx_buffer.tail) {
- if (!TEST(SREG, SREG_I)) {
- // Interrupts are disabled, so we'll have to poll the data
- // register empty flag ourselves. If it is set, pretend an
- // interrupt has happened and call the handler to free up
- // space for us.
- if (TEST(M_UCSRxA, M_UDREx))
- _tx_udr_empty_irq();
- } else {
- // nop, the interrupt handler will free up space for us
+ default:
+ if (c == '\n') {
+ switch (state) {
+ case state_M108:
+ wait_for_user = wait_for_heatup = false;
+ break;
+ case state_M112:
+ kill(PSTR(MSG_KILLED));
+ break;
+ case state_M410:
+ quickstop_stepper();
+ break;
+ default:
+ break;
+ }
+ state = state_RESET;
+ }
}
}
- tx_buffer.buffer[tx_buffer.head] = c;
- { CRITICAL_SECTION_START;
- tx_buffer.head = i;
- SBI(M_UCSRxB, M_UDRIEx);
+ #endif
+
+
+ FORCE_INLINE void store_char(unsigned char c) {
+ CRITICAL_SECTION_START;
+ uint8_t h = rx_buffer.head;
+ uint8_t i = (uint8_t)(h + 1) & (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) {
+ rx_buffer.buffer[h] = c;
+ rx_buffer.head = i;
+ }
+ CRITICAL_SECTION_END;
+
+ #if ENABLED(EMERGENCY_PARSER)
+ emergency_parser(c);
+ #endif
+ }
+
+ #if TX_BUFFER_SIZE > 0
+
+ FORCE_INLINE void _tx_udr_empty_irq(void) {
+ // If interrupts are enabled, there must be more data in the output
+ // buffer. Send the next byte
+ uint8_t t = tx_buffer.tail;
+ uint8_t c = tx_buffer.buffer[t];
+ tx_buffer.tail = (t + 1) & (TX_BUFFER_SIZE - 1);
+
+ M_UDRx = 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);
+
+ if (tx_buffer.head == tx_buffer.tail) {
+ // Buffer empty, so disable interrupts
+ CBI(M_UCSRxB, M_UDRIEx);
+ }
+ }
+
+ #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) {
+ unsigned char c = M_UDRx;
+ store_char(c);
+ }
+ #endif
+
+ // Public Methods
+
+ void MarlinSerial::begin(long baud) {
+ uint16_t baud_setting;
+ bool useU2X = true;
+
+ #if F_CPU == 16000000UL && SERIAL_PORT == 0
+ // hard-coded exception for compatibility with the bootloader shipped
+ // with the Duemilanove and previous boards and the firmware on the 8U2
+ // on the Uno and Mega 2560.
+ if (baud == 57600) {
+ useU2X = false;
+ }
+ #endif
+
+ if (useU2X) {
+ M_UCSRxA = _BV(M_U2Xx);
+ 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);
+ _written = false;
+ #endif
+ }
+
+ void MarlinSerial::end() {
+ CBI(M_UCSRxB, M_RXENx);
+ CBI(M_UCSRxB, M_TXENx);
+ CBI(M_UCSRxB, M_RXCIEx);
+ CBI(M_UCSRxB, M_UDRIEx);
+ }
+
+ void MarlinSerial::checkRx(void) {
+ if (TEST(M_UCSRxA, M_RXCx)) {
+ uint8_t c = M_UDRx;
+ store_char(c);
+ }
+ }
+
+ int MarlinSerial::peek(void) {
+ CRITICAL_SECTION_START;
+ int v = rx_buffer.head == rx_buffer.tail ? -1 : rx_buffer.buffer[rx_buffer.tail];
+ CRITICAL_SECTION_END;
+ return v;
+ }
+
+ int MarlinSerial::read(void) {
+ int v;
+ CRITICAL_SECTION_START;
+ uint8_t t = rx_buffer.tail;
+ if (rx_buffer.head == t) {
+ v = -1;
+ }
+ else {
+ v = rx_buffer.buffer[t];
+ rx_buffer.tail = (uint8_t)(t + 1) & (RX_BUFFER_SIZE - 1);
+ }
+ CRITICAL_SECTION_END;
+ return v;
+ }
+
+ uint8_t MarlinSerial::available(void) {
+ CRITICAL_SECTION_START;
+ uint8_t h = rx_buffer.head,
+ t = rx_buffer.tail;
+ CRITICAL_SECTION_END;
+ return (uint8_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.
+ CRITICAL_SECTION_START;
+ rx_buffer.head = rx_buffer.tail;
+ CRITICAL_SECTION_END;
+ }
+
+ #if TX_BUFFER_SIZE > 0
+ uint8_t MarlinSerial::availableForWrite(void) {
+ CRITICAL_SECTION_START;
+ uint8_t h = tx_buffer.head;
+ uint8_t t = tx_buffer.tail;
CRITICAL_SECTION_END;
+ return (uint8_t)(TX_BUFFER_SIZE + h - t) & (TX_BUFFER_SIZE - 1);
}
- return;
- }
- void MarlinSerial::flushTX(void) {
- // TX
- // 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)
+ void MarlinSerial::write(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 (>
+ // 500kbit/s) bitrates, where interrupt overhead becomes a slowdown.
+ if (emty && TEST(M_UCSRxA, M_UDREx)) {
+ CRITICAL_SECTION_START;
+ M_UDRx = c;
+ SBI(M_UCSRxA, M_TXCx);
+ CRITICAL_SECTION_END;
+ return;
+ }
+ uint8_t i = (tx_buffer.head + 1) & (TX_BUFFER_SIZE - 1);
+
+ // If the output buffer is full, there's nothing for it other than to
+ // wait for the interrupt handler to empty it a bit
+ while (i == tx_buffer.tail) {
+ if (!TEST(SREG, SREG_I)) {
+ // Interrupts are disabled, so we'll have to poll the data
+ // register empty flag ourselves. If it is set, pretend an
+ // interrupt has happened and call the handler to free up
+ // space for us.
+ if (TEST(M_UCSRxA, M_UDREx))
+ _tx_udr_empty_irq();
+ } else {
+ // nop, the interrupt handler will free up space for us
+ }
+ }
+
+ tx_buffer.buffer[tx_buffer.head] = c;
+ { CRITICAL_SECTION_START;
+ tx_buffer.head = i;
+ SBI(M_UCSRxB, M_UDRIEx);
+ CRITICAL_SECTION_END;
+ }
return;
-
- while (TEST(M_UCSRxB, M_UDRIEx) || !TEST(M_UCSRxA, M_TXCx)) {
- if (!TEST(SREG, SREG_I) && TEST(M_UCSRxB, M_UDRIEx))
- // Interrupts are globally disabled, but the DR empty
- // interrupt should be enabled, so poll the DR empty flag to
- // prevent deadlock
- if (TEST(M_UCSRxA, M_UDREx))
- _tx_udr_empty_irq();
}
- // 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) {
- while (!TEST(M_UCSRxA, M_UDREx))
- ;
- M_UDRx = c;
+ void MarlinSerial::flushTX(void) {
+ // TX
+ // 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;
+
+ while (TEST(M_UCSRxB, M_UDRIEx) || !TEST(M_UCSRxA, M_TXCx)) {
+ if (!TEST(SREG, SREG_I) && TEST(M_UCSRxB, M_UDRIEx))
+ // Interrupts are globally disabled, but the DR empty
+ // interrupt should be enabled, so poll the DR empty flag to
+ // prevent deadlock
+ if (TEST(M_UCSRxA, M_UDREx))
+ _tx_udr_empty_irq();
+ }
+ // If we get here, nothing is queued anymore (DRIE is disabled) and
+ // the hardware finished tranmission (TXC is set).
}
-#endif
-// end NEW
+ #else
+ void MarlinSerial::write(uint8_t c) {
+ while (!TEST(M_UCSRxA, M_UDREx))
+ ;
+ M_UDRx = c;
+ }
+ #endif
-/// imports from print.h
+ // end NEW
+
+ /// imports from print.h
-void MarlinSerial::print(char c, int base) {
- print((long) c, base);
-}
-
-void MarlinSerial::print(unsigned char b, int base) {
- print((unsigned long) b, base);
-}
-
-void MarlinSerial::print(int n, int base) {
- print((long) n, base);
-}
-
-void MarlinSerial::print(unsigned int n, int base) {
- print((unsigned long) n, base);
-}
-
-void MarlinSerial::print(long n, int base) {
- if (base == 0) {
- write(n);
+ void MarlinSerial::print(char c, int base) {
+ print((long) c, base);
}
- else if (base == 10) {
- if (n < 0) {
+
+ void MarlinSerial::print(unsigned char b, int base) {
+ print((unsigned long) b, base);
+ }
+
+ void MarlinSerial::print(int n, int base) {
+ print((long) n, base);
+ }
+
+ void MarlinSerial::print(unsigned int n, int base) {
+ print((unsigned long) n, base);
+ }
+
+ void MarlinSerial::print(long n, int base) {
+ if (base == 0) {
+ write(n);
+ }
+ else if (base == 10) {
+ if (n < 0) {
+ print('-');
+ n = -n;
+ }
+ printNumber(n, 10);
+ }
+ else {
+ printNumber(n, base);
+ }
+ }
+
+ void MarlinSerial::print(unsigned long n, int base) {
+ if (base == 0) write(n);
+ else printNumber(n, base);
+ }
+
+ void MarlinSerial::print(double n, int digits) {
+ printFloat(n, digits);
+ }
+
+ void MarlinSerial::println(void) {
+ print('\r');
+ print('\n');
+ }
+
+ void MarlinSerial::println(const String& s) {
+ print(s);
+ println();
+ }
+
+ void MarlinSerial::println(const char c[]) {
+ print(c);
+ println();
+ }
+
+ void MarlinSerial::println(char c, int base) {
+ print(c, base);
+ println();
+ }
+
+ void MarlinSerial::println(unsigned char b, int base) {
+ print(b, base);
+ println();
+ }
+
+ void MarlinSerial::println(int n, int base) {
+ print(n, base);
+ println();
+ }
+
+ void MarlinSerial::println(unsigned int n, int base) {
+ print(n, base);
+ println();
+ }
+
+ void MarlinSerial::println(long n, int base) {
+ print(n, base);
+ println();
+ }
+
+ void MarlinSerial::println(unsigned long n, int base) {
+ print(n, base);
+ println();
+ }
+
+ void MarlinSerial::println(double n, int digits) {
+ print(n, digits);
+ println();
+ }
+
+ // Private Methods
+
+ void MarlinSerial::printNumber(unsigned long n, uint8_t base) {
+ if (n) {
+ unsigned char buf[8 * sizeof(long)]; // Enough space for base 2
+ int8_t i = 0;
+ while (n) {
+ buf[i++] = n % base;
+ n /= base;
+ }
+ while (i--)
+ print((char)(buf[i] + (buf[i] < 10 ? '0' : 'A' - 10)));
+ }
+ else
+ print('0');
+ }
+
+ void MarlinSerial::printFloat(double number, uint8_t digits) {
+ // Handle negative numbers
+ if (number < 0.0) {
print('-');
- n = -n;
+ number = -number;
}
- printNumber(n, 10);
- }
- else {
- printNumber(n, base);
- }
-}
-void MarlinSerial::print(unsigned long n, int base) {
- if (base == 0) write(n);
- else printNumber(n, base);
-}
+ // 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;
-void MarlinSerial::print(double n, int digits) {
- printFloat(n, digits);
-}
+ number += rounding;
-void MarlinSerial::println(void) {
- print('\r');
- print('\n');
-}
+ // Extract the integer part of the number and print it
+ unsigned long int_part = (unsigned long)number;
+ double remainder = number - (double)int_part;
+ print(int_part);
-void MarlinSerial::println(const String& s) {
- print(s);
- println();
-}
-
-void MarlinSerial::println(const char c[]) {
- print(c);
- println();
-}
-
-void MarlinSerial::println(char c, int base) {
- print(c, base);
- println();
-}
-
-void MarlinSerial::println(unsigned char b, int base) {
- print(b, base);
- println();
-}
-
-void MarlinSerial::println(int n, int base) {
- print(n, base);
- println();
-}
-
-void MarlinSerial::println(unsigned int n, int base) {
- print(n, base);
- println();
-}
-
-void MarlinSerial::println(long n, int base) {
- print(n, base);
- println();
-}
-
-void MarlinSerial::println(unsigned long n, int base) {
- print(n, base);
- println();
-}
-
-void MarlinSerial::println(double n, int digits) {
- print(n, digits);
- println();
-}
-
-// Private Methods /////////////////////////////////////////////////////////////
-
-void MarlinSerial::printNumber(unsigned long n, uint8_t base) {
- if (n) {
- unsigned char buf[8 * sizeof(long)]; // Enough space for base 2
- int8_t i = 0;
- while (n) {
- buf[i++] = n % base;
- n /= base;
- }
- while (i--)
- print((char)(buf[i] + (buf[i] < 10 ? '0' : 'A' - 10)));
- }
- else
- print('0');
-}
-
-void MarlinSerial::printFloat(double number, uint8_t digits) {
- // Handle negative numbers
- if (number < 0.0) {
- print('-');
- number = -number;
- }
-
- // Round correctly so that print(1.999, 2) prints as "2.00"
- double rounding = 0.5;
- for (uint8_t i = 0; i < digits; ++i)
- rounding *= 0.1;
-
- number += rounding;
-
- // Extract the integer part of the number and print it
- unsigned long int_part = (unsigned long)number;
- double remainder = number - (double)int_part;
- print(int_part);
-
- // Print the decimal point, but only if there are digits beyond
- if (digits) {
- print('.');
- // Extract digits from the remainder one at a time
- while (digits--) {
- remainder *= 10.0;
- int toPrint = int(remainder);
- print(toPrint);
- remainder -= toPrint;
+ // Print the decimal point, but only if there are digits beyond
+ if (digits) {
+ print('.');
+ // Extract digits from the remainder one at a time
+ while (digits--) {
+ remainder *= 10.0;
+ int toPrint = int(remainder);
+ print(toPrint);
+ remainder -= toPrint;
+ }
}
}
-}
-// Preinstantiate Objects //////////////////////////////////////////////////////
+ // Preinstantiate
+ MarlinSerial customizedSerial;
-MarlinSerial customizedSerial;
-
-#endif // whole file
-#endif // !USBCON
+#endif // !USBCON && (UBRRH || UBRR0H || UBRR1H || UBRR2H || UBRR3H)
// For AT90USB targets use the UART for BT interfacing
#if defined(USBCON) && ENABLED(BLUETOOTH)
HardwareSerial bluetoothSerial;
#endif
-
-#if ENABLED(EMERGENCY_PARSER)
-
- // Currently looking for: M108, M112, M410
- // If you alter the parser please don't forget to update the capabilities in Conditionals_post.h
-
- FORCE_INLINE void emergency_parser(unsigned char c) {
-
- static e_parser_state state = state_RESET;
-
- switch (state) {
- case state_RESET:
- switch (c) {
- case ' ': break;
- case 'N': state = state_N; break;
- case 'M': state = state_M; break;
- default: state = state_IGNORE;
- }
- break;
-
- case state_N:
- switch (c) {
- case '0': case '1': case '2':
- case '3': case '4': case '5':
- case '6': case '7': case '8':
- case '9': case '-': case ' ': break;
- case 'M': state = state_M; break;
- default: state = state_IGNORE;
- }
- break;
-
- case state_M:
- switch (c) {
- case ' ': break;
- case '1': state = state_M1; break;
- case '4': state = state_M4; break;
- default: state = state_IGNORE;
- }
- break;
-
- case state_M1:
- switch (c) {
- case '0': state = state_M10; break;
- case '1': state = state_M11; break;
- default: state = state_IGNORE;
- }
- break;
-
- case state_M10:
- state = (c == '8') ? state_M108 : state_IGNORE;
- break;
-
- case state_M11:
- state = (c == '2') ? state_M112 : state_IGNORE;
- break;
-
- case state_M4:
- state = (c == '1') ? state_M41 : state_IGNORE;
- break;
-
- case state_M41:
- state = (c == '0') ? state_M410 : state_IGNORE;
- break;
-
- case state_IGNORE:
- if (c == '\n') state = state_RESET;
- break;
-
- default:
- if (c == '\n') {
- switch (state) {
- case state_M108:
- wait_for_user = wait_for_heatup = false;
- break;
- case state_M112:
- kill(PSTR(MSG_KILLED));
- break;
- case state_M410:
- quickstop_stepper();
- break;
- default:
- break;
- }
- state = state_RESET;
- }
- }
- }
-
-#endif
diff --git a/Marlin/MarlinSerial.h b/Marlin/MarlinSerial.h
index 87f4f6a92..7ec7b2c26 100644
--- a/Marlin/MarlinSerial.h
+++ b/Marlin/MarlinSerial.h
@@ -29,8 +29,8 @@
*/
-#ifndef MarlinSerial_h
-#define MarlinSerial_h
+#ifndef MARLINSERIAL_H
+#define MARLINSERIAL_H
#include "MarlinConfig.h"
@@ -52,125 +52,118 @@
#define SERIAL_REGNAME_INTERNAL(registerbase,number,suffix) registerbase##number##suffix
#endif
-// Registers used by MarlinSerial class (these are 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_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,)
+// 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_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
-
#ifndef USBCON
-// Define constants and variables for buffering incoming serial data. 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.
-// 256 is the max limit due to uint8_t head and tail. Use only powers of 2. (...,16,32,64,128,256)
-#ifndef RX_BUFFER_SIZE
- #define RX_BUFFER_SIZE 128
-#endif
-#ifndef TX_BUFFER_SIZE
- #define TX_BUFFER_SIZE 32
-#endif
-#if !((RX_BUFFER_SIZE == 256) ||(RX_BUFFER_SIZE == 128) ||(RX_BUFFER_SIZE == 64) ||(RX_BUFFER_SIZE == 32) ||(RX_BUFFER_SIZE == 16) ||(RX_BUFFER_SIZE == 8) ||(RX_BUFFER_SIZE == 4) ||(RX_BUFFER_SIZE == 2))
- #error "RX_BUFFER_SIZE has to be a power of 2 and >= 2"
-#endif
-#if !((TX_BUFFER_SIZE == 256) ||(TX_BUFFER_SIZE == 128) ||(TX_BUFFER_SIZE == 64) ||(TX_BUFFER_SIZE == 32) ||(TX_BUFFER_SIZE == 16) ||(TX_BUFFER_SIZE == 8) ||(TX_BUFFER_SIZE == 4) ||(TX_BUFFER_SIZE == 2) ||(TX_BUFFER_SIZE == 0))
- #error TX_BUFFER_SIZE has to be a power of 2 or 0
-#endif
+ // Define constants and variables for buffering incoming serial data. 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.
+ // 256 is the max limit due to uint8_t head and tail. Use only powers of 2. (...,16,32,64,128,256)
+ #ifndef RX_BUFFER_SIZE
+ #define RX_BUFFER_SIZE 128
+ #endif
+ #ifndef TX_BUFFER_SIZE
+ #define TX_BUFFER_SIZE 32
+ #endif
+ #if !((RX_BUFFER_SIZE == 256) ||(RX_BUFFER_SIZE == 128) ||(RX_BUFFER_SIZE == 64) ||(RX_BUFFER_SIZE == 32) ||(RX_BUFFER_SIZE == 16) ||(RX_BUFFER_SIZE == 8) ||(RX_BUFFER_SIZE == 4) ||(RX_BUFFER_SIZE == 2))
+ #error "RX_BUFFER_SIZE has to be a power of 2 and >= 2"
+ #endif
+ #if !((TX_BUFFER_SIZE == 256) ||(TX_BUFFER_SIZE == 128) ||(TX_BUFFER_SIZE == 64) ||(TX_BUFFER_SIZE == 32) ||(TX_BUFFER_SIZE == 16) ||(TX_BUFFER_SIZE == 8) ||(TX_BUFFER_SIZE == 4) ||(TX_BUFFER_SIZE == 2) ||(TX_BUFFER_SIZE == 0))
+ #error TX_BUFFER_SIZE has to be a power of 2 or 0
+ #endif
-struct ring_buffer_r {
- unsigned char buffer[RX_BUFFER_SIZE];
- volatile uint8_t head;
- volatile uint8_t tail;
-};
-
-#if TX_BUFFER_SIZE > 0
- struct ring_buffer_t {
- unsigned char buffer[TX_BUFFER_SIZE];
+ struct ring_buffer_r {
+ unsigned char buffer[RX_BUFFER_SIZE];
volatile uint8_t head;
volatile uint8_t tail;
};
-#endif
-#if UART_PRESENT(SERIAL_PORT)
- extern ring_buffer_r rx_buffer;
#if TX_BUFFER_SIZE > 0
- extern ring_buffer_t tx_buffer;
+ struct ring_buffer_t {
+ unsigned char buffer[TX_BUFFER_SIZE];
+ volatile uint8_t head;
+ volatile uint8_t tail;
+ };
#endif
-#endif
-#if ENABLED(EMERGENCY_PARSER)
- #include "language.h"
- void emergency_parser(unsigned char c);
-#endif
-
-class MarlinSerial { //: public Stream
-
- public:
- MarlinSerial();
- static void begin(long);
- static void end();
- static int peek(void);
- static int read(void);
- static void flush(void);
- static uint8_t available(void);
- static void checkRx(void);
- static void write(uint8_t c);
+ #if UART_PRESENT(SERIAL_PORT)
+ extern ring_buffer_r rx_buffer;
#if TX_BUFFER_SIZE > 0
- static uint8_t availableForWrite(void);
- static void flushTX(void);
+ extern ring_buffer_t tx_buffer;
#endif
+ #endif
- private:
- static void printNumber(unsigned long, uint8_t);
- static void printFloat(double, uint8_t);
+ class MarlinSerial { //: public Stream
- public:
- static FORCE_INLINE void write(const char* str) { while (*str) write(*str++); }
- static FORCE_INLINE void write(const uint8_t* buffer, size_t size) { while (size--) write(*buffer++); }
- static FORCE_INLINE void print(const String& s) { for (int i = 0; i < (int)s.length(); i++) write(s[i]); }
- static FORCE_INLINE void print(const char* str) { write(str); }
+ public:
+ MarlinSerial() {};
+ static void begin(long);
+ static void end();
+ static int peek(void);
+ static int read(void);
+ static void flush(void);
+ static uint8_t available(void);
+ static void checkRx(void);
+ static void write(uint8_t c);
+ #if TX_BUFFER_SIZE > 0
+ static uint8_t availableForWrite(void);
+ static void flushTX(void);
+ #endif
- static void print(char, int = BYTE);
- static void print(unsigned char, int = BYTE);
- static void print(int, int = DEC);
- static void print(unsigned int, int = DEC);
- static void print(long, int = DEC);
- static void print(unsigned long, int = DEC);
- static void print(double, int = 2);
+ private:
+ static void printNumber(unsigned long, uint8_t);
+ static void printFloat(double, uint8_t);
- static void println(const String& s);
- static void println(const char[]);
- static void println(char, int = BYTE);
- static void println(unsigned char, int = BYTE);
- static void println(int, int = DEC);
- static void println(unsigned int, int = DEC);
- static void println(long, int = DEC);
- static void println(unsigned long, int = DEC);
- static void println(double, int = 2);
- static void println(void);
-};
+ public:
+ static FORCE_INLINE void write(const char* str) { while (*str) write(*str++); }
+ static FORCE_INLINE void write(const uint8_t* buffer, size_t size) { while (size--) write(*buffer++); }
+ static FORCE_INLINE void print(const String& s) { for (int i = 0; i < (int)s.length(); i++) write(s[i]); }
+ static FORCE_INLINE void print(const char* str) { write(str); }
+
+ static void print(char, int = BYTE);
+ static void print(unsigned char, int = BYTE);
+ static void print(int, int = DEC);
+ static void print(unsigned int, int = DEC);
+ static void print(long, int = DEC);
+ static void print(unsigned long, int = DEC);
+ static void print(double, int = 2);
+
+ static void println(const String& s);
+ static void println(const char[]);
+ static void println(char, int = BYTE);
+ static void println(unsigned char, int = BYTE);
+ static void println(int, int = DEC);
+ static void println(unsigned int, int = DEC);
+ static void println(long, int = DEC);
+ static void println(unsigned long, int = DEC);
+ static void println(double, int = 2);
+ static void println(void);
+ };
+
+ extern MarlinSerial customizedSerial;
-extern MarlinSerial customizedSerial;
#endif // !USBCON
// Use the UART for Bluetooth in AT90USB configurations
@@ -178,4 +171,4 @@ extern MarlinSerial customizedSerial;
extern HardwareSerial bluetoothSerial;
#endif
-#endif
+#endif // MARLINSERIAL_H
diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp
index 7d4a95506..79771ae06 100755
--- a/Marlin/Marlin_main.cpp
+++ b/Marlin/Marlin_main.cpp
@@ -447,8 +447,6 @@ volatile bool wait_for_heatup = true;
volatile bool wait_for_user = false;
#endif
-const char errormagic[] PROGMEM = "Error:";
-const char echomagic[] PROGMEM = "echo:";
const char axis_codes[XYZE] = {'X', 'Y', 'Z', 'E'};
// Number of characters read in the current line of serial input
@@ -696,14 +694,6 @@ void set_current_from_steppers_for_axis(const AxisEnum axis);
void plan_cubic_move(const float offset[4]);
#endif
-void serial_echopair_P(const char* s_P, const char *v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
-void serial_echopair_P(const char* s_P, char v) { serialprintPGM(s_P); SERIAL_CHAR(v); }
-void serial_echopair_P(const char* s_P, int v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
-void serial_echopair_P(const char* s_P, long v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
-void serial_echopair_P(const char* s_P, float v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
-void serial_echopair_P(const char* s_P, double v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
-void serial_echopair_P(const char* s_P, unsigned long v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
-
void tool_change(const uint8_t tmp_extruder, const float fr_mm_s=0.0, bool no_move=false);
static void report_current_position();
@@ -1789,15 +1779,10 @@ static void clean_up_after_endstop_or_probe_move() {
SERIAL_ECHOLNPGM(" " MSG_FIRST);
#if ENABLED(ULTRA_LCD)
- char message[3 * (LCD_WIDTH) + 1] = ""; // worst case is kana.utf with up to 3*LCD_WIDTH+1
- strcat_P(message, PSTR(MSG_HOME " "));
- if (xx) strcat_P(message, PSTR(MSG_X));
- if (yy) strcat_P(message, PSTR(MSG_Y));
- if (zz) strcat_P(message, PSTR(MSG_Z));
- strcat_P(message, PSTR(" " MSG_FIRST));
- lcd_setstatus(message);
+ lcd_status_printf_P(0, PSTR(MSG_HOME " %s%s%s " MSG_FIRST), xx ? MSG_X : "", yy ? MSG_Y : "", zz ? MSG_Z : "");
#endif
return true;
+
}
return false;
}
@@ -5153,7 +5138,6 @@ inline void gcode_M31() {
char buffer[21];
duration_t elapsed = print_job_timer.duration();
elapsed.toString(buffer);
-
lcd_setstatus(buffer);
SERIAL_ECHO_START;
@@ -5700,7 +5684,7 @@ inline void gcode_M104() {
}
#endif
- if (code_value_temp_abs() > thermalManager.degHotend(target_extruder)) status_printf(0, PSTR("E%i %s"), target_extruder + 1, MSG_HEATING);
+ if (code_value_temp_abs() > thermalManager.degHotend(target_extruder)) lcd_status_printf_P(0, PSTR("E%i %s"), target_extruder + 1, MSG_HEATING);
}
#if ENABLED(AUTOTEMP)
@@ -5898,7 +5882,7 @@ inline void gcode_M109() {
else print_job_timer.start();
#endif
- if (thermalManager.isHeatingHotend(target_extruder)) status_printf(0, PSTR("E%i %s"), target_extruder + 1, MSG_HEATING);
+ if (thermalManager.isHeatingHotend(target_extruder)) lcd_status_printf_P(0, PSTR("E%i %s"), target_extruder + 1, MSG_HEATING);
}
#if ENABLED(AUTOTEMP)
@@ -8903,7 +8887,7 @@ void process_next_command() {
gcode_G28();
break;
- #if PLANNER_LEVELING && !ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(AUTO_BED_LEVELING_UBL) && ENABLED(UBL_G26_MESH_EDITING)
+ #if PLANNER_LEVELING || ENABLED(AUTO_BED_LEVELING_UBL)
case 29: // G29 Detailed Z probe, probes the bed at 3 or more points,
// or provides access to the UBL System if enabled.
gcode_G29();
@@ -10175,6 +10159,8 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) {
/**
* Prepare a linear move in a Cartesian setup.
* If Mesh Bed Leveling is enabled, perform a mesh move.
+ *
+ * Returns true if the caller didn't update current_position.
*/
inline bool prepare_move_to_destination_cartesian() {
// Do not use feedrate_percentage for E or Z only moves
@@ -10190,9 +10176,7 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) {
else
#elif ENABLED(AUTO_BED_LEVELING_UBL)
if (ubl.state.active) {
-
ubl_line_to_destination(MMS_SCALED(feedrate_mm_s), active_extruder);
-
return false;
}
else
diff --git a/Marlin/UBL.h b/Marlin/UBL.h
index ea726b457..c62e05a31 100644
--- a/Marlin/UBL.h
+++ b/Marlin/UBL.h
@@ -29,6 +29,7 @@
#if ENABLED(AUTO_BED_LEVELING_UBL)
+ #define UBL_VERSION "1.00"
#define UBL_OK false
#define UBL_ERR true
@@ -98,9 +99,6 @@
float g29_correction_fade_height = 10.0,
g29_fade_height_multiplier = 1.0 / 10.0; // It's cheaper to do a floating point multiply than divide,
// so keep this value and its reciprocal.
- #else
- const float g29_correction_fade_height = 10.0,
- g29_fade_height_multiplier = 1.0 / 10.0;
#endif
// If you change this struct, adjust TOTAL_STRUCT_SIZE
@@ -118,8 +116,7 @@
class unified_bed_leveling {
private:
- static float last_specified_z,
- fade_scaling_factor_for_current_height;
+ static float last_specified_z;
public:
@@ -307,32 +304,29 @@
}
/**
- * This routine is used to scale the Z correction depending upon the current nozzle height. It is
- * optimized for speed. It avoids floating point operations by checking if the requested scaling
- * factor is going to be the same as the last time the function calculated a value. If so, it just
- * returns it.
+ * This function sets the Z leveling fade factor based on the given Z height,
+ * only re-calculating when necessary.
*
- * It returns a scaling factor of 1.0 if UBL is inactive.
- * It returns a scaling factor of 0.0 if Z is past the specified 'Fade Height'
+ * Returns 1.0 if g29_correction_fade_height is 0.0.
+ * Returns 0.0 if Z is past the specified 'Fade Height'.
*/
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
static FORCE_INLINE float fade_scaling_factor_for_z(const float &lz) {
+ if (state.g29_correction_fade_height == 0.0) return 1.0;
+
+ static float fade_scaling_factor = 1.0;
const float rz = RAW_Z_POSITION(lz);
if (last_specified_z != rz) {
last_specified_z = rz;
- fade_scaling_factor_for_current_height =
- state.active && rz < state.g29_correction_fade_height
+ fade_scaling_factor =
+ rz < state.g29_correction_fade_height
? 1.0 - (rz * state.g29_fade_height_multiplier)
: 0.0;
}
- return fade_scaling_factor_for_current_height;
+ return fade_scaling_factor;
}
- #else
-
- static constexpr float fade_scaling_factor_for_z(const float &lz) { UNUSED(lz); return 1.0; }
-
#endif
}; // class unified_bed_leveling
diff --git a/Marlin/UBL_Bed_Leveling.cpp b/Marlin/UBL_Bed_Leveling.cpp
index e173247fe..414099b76 100644
--- a/Marlin/UBL_Bed_Leveling.cpp
+++ b/Marlin/UBL_Bed_Leveling.cpp
@@ -61,7 +61,6 @@
float unified_bed_leveling::z_values[UBL_MESH_NUM_X_POINTS][UBL_MESH_NUM_Y_POINTS],
unified_bed_leveling::last_specified_z,
- unified_bed_leveling::fade_scaling_factor_for_current_height,
unified_bed_leveling::mesh_index_to_xpos[UBL_MESH_NUM_X_POINTS + 1], // +1 safety margin for now, until determinism prevails
unified_bed_leveling::mesh_index_to_ypos[UBL_MESH_NUM_Y_POINTS + 1];
@@ -102,8 +101,9 @@
* updated, but until then, we try to ease the transition
* for our Beta testers.
*/
- if (ubl.state.g29_fade_height_multiplier != 1.0 / ubl.state.g29_correction_fade_height) {
- ubl.state.g29_fade_height_multiplier = 1.0 / ubl.state.g29_correction_fade_height;
+ const float recip = ubl.state.g29_correction_fade_height ? 1.0 / ubl.state.g29_correction_fade_height : 1.0;
+ if (ubl.state.g29_fade_height_multiplier != recip) {
+ ubl.state.g29_fade_height_multiplier = recip;
store_state();
}
#endif
@@ -160,7 +160,6 @@
ZERO(z_values);
last_specified_z = -999.9;
- fade_scaling_factor_for_current_height = 0.0;
}
void unified_bed_leveling::invalidate() {
diff --git a/Marlin/UBL_G29.cpp b/Marlin/UBL_G29.cpp
index 9b7ccadd9..3d877cc8d 100644
--- a/Marlin/UBL_G29.cpp
+++ b/Marlin/UBL_G29.cpp
@@ -307,7 +307,8 @@
static float x_pos, y_pos, measured_z, card_thickness = 0.0, ubl_constant = 0.0;
#if ENABLED(ULTRA_LCD)
- void lcd_setstatus(const char* message, bool persist);
+ extern void lcd_setstatus(const char* message, const bool persist);
+ extern void lcd_setstatuspgm(const char* message, const uint8_t level);
#endif
void gcode_G29() {
@@ -655,7 +656,7 @@
if (ELAPSED(millis(), nxt)) {
SERIAL_PROTOCOLLNPGM("\nZ-Offset Adjustment Stopped.");
do_blocking_move_to_z(Z_CLEARANCE_DEPLOY_PROBE);
- lcd_setstatus("Z-Offset Stopped", true);
+ lcd_setstatuspgm("Z-Offset Stopped");
restore_ubl_active_state_and_leave();
goto LEAVE;
}
@@ -673,7 +674,8 @@
LEAVE:
#if ENABLED(ULTRA_LCD)
- lcd_setstatus(" ", true);
+ lcd_reset_alert_level();
+ lcd_setstatuspgm("");
lcd_quick_feedback();
#endif
@@ -977,7 +979,7 @@
bool g29_parameter_parsing() {
#if ENABLED(ULTRA_LCD)
- lcd_setstatus("Doing G29 UBL !", true);
+ lcd_setstatuspgm("Doing G29 UBL!");
lcd_quick_feedback();
#endif
@@ -1088,7 +1090,7 @@
ubl_state_recursion_chk++;
if (ubl_state_recursion_chk != 1) {
SERIAL_ECHOLNPGM("save_ubl_active_state_and_disabled() called multiple times in a row.");
- lcd_setstatus("save_UBL_active() error", true);
+ lcd_setstatuspgm("save_UBL_active() error");
lcd_quick_feedback();
return;
}
@@ -1099,7 +1101,7 @@
void restore_ubl_active_state_and_leave() {
if (--ubl_state_recursion_chk) {
SERIAL_ECHOLNPGM("restore_ubl_active_state_and_leave() called too many times.");
- lcd_setstatus("restore_UBL_active() error", true);
+ lcd_setstatuspgm("restore_UBL_active() error");
lcd_quick_feedback();
return;
}
@@ -1114,7 +1116,7 @@
void g29_what_command() {
const uint16_t k = E2END - ubl.eeprom_start;
- SERIAL_PROTOCOLPGM("Unified Bed Leveling System Version 1.00 ");
+ SERIAL_PROTOCOLPGM("Unified Bed Leveling System Version " UBL_VERSION " ");
if (ubl.state.active)
SERIAL_PROTOCOLCHAR('A');
else
@@ -1132,8 +1134,7 @@
safe_delay(50);
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
- SERIAL_PROTOCOLPAIR("g29_correction_fade_height : ", ubl.state.g29_correction_fade_height);
- SERIAL_EOL;
+ SERIAL_PROTOCOLLNPAIR("g29_correction_fade_height : ", ubl.state.g29_correction_fade_height);
#endif
SERIAL_PROTOCOLPGM("z_offset: ");
@@ -1340,7 +1341,7 @@
memset(not_done, 0xFF, sizeof(not_done));
#if ENABLED(ULTRA_LCD)
- lcd_setstatus("Fine Tuning Mesh.", true);
+ lcd_setstatuspgm("Fine Tuning Mesh");
#endif
do_blocking_move_to_z(Z_CLEARANCE_DEPLOY_PROBE);
@@ -1399,7 +1400,7 @@
lcd_return_to_status();
//SERIAL_PROTOCOLLNPGM("\nFine Tuning of Mesh Stopped.");
do_blocking_move_to_z(Z_CLEARANCE_DEPLOY_PROBE);
- lcd_setstatus("Mesh Editing Stopped", true);
+ lcd_setstatuspgm("Mesh Editing Stopped");
while (ubl_lcd_clicked()) idle();
@@ -1427,9 +1428,9 @@
do_blocking_move_to_xy(lx, ly);
#if ENABLED(ULTRA_LCD)
- lcd_setstatus("Done Editing Mesh", true);
+ lcd_setstatuspgm("Done Editing Mesh");
#endif
- SERIAL_ECHOLNPGM("Done Editing Mesh.");
+ SERIAL_ECHOLNPGM("Done Editing Mesh");
}
#endif // AUTO_BED_LEVELING_UBL
\ No newline at end of file
diff --git a/Marlin/endstops.cpp b/Marlin/endstops.cpp
index 54a512787..a80a07dc1 100644
--- a/Marlin/endstops.cpp
+++ b/Marlin/endstops.cpp
@@ -170,9 +170,7 @@ void Endstops::report_state() {
SERIAL_EOL;
#if ENABLED(ULTRA_LCD)
- char msg[3 * strlen(MSG_LCD_ENDSTOPS) + 8 + 1]; // Room for a UTF 8 string
- sprintf_P(msg, PSTR(MSG_LCD_ENDSTOPS " %c %c %c %c"), chrX, chrY, chrZ, chrP);
- lcd_setstatus(msg);
+ lcd_status_printf_P(0, PSTR(MSG_LCD_ENDSTOPS " %c %c %c %c"), chrX, chrY, chrZ, chrP);
#endif
hit_on_purpose();
diff --git a/Marlin/serial.cpp b/Marlin/serial.cpp
new file mode 100644
index 000000000..9b5ae139e
--- /dev/null
+++ b/Marlin/serial.cpp
@@ -0,0 +1,34 @@
+/**
+ * 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 .
+ *
+ */
+
+#include "serial.h"
+
+const char errormagic[] PROGMEM = "Error:";
+const char echomagic[] PROGMEM = "echo:";
+
+void serial_echopair_P(const char* s_P, const char *v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
+void serial_echopair_P(const char* s_P, char v) { serialprintPGM(s_P); SERIAL_CHAR(v); }
+void serial_echopair_P(const char* s_P, int v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
+void serial_echopair_P(const char* s_P, long v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
+void serial_echopair_P(const char* s_P, float v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
+void serial_echopair_P(const char* s_P, double v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
+void serial_echopair_P(const char* s_P, unsigned long v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
diff --git a/Marlin/serial.h b/Marlin/serial.h
new file mode 100644
index 000000000..864a9d8f6
--- /dev/null
+++ b/Marlin/serial.h
@@ -0,0 +1,88 @@
+/**
+ * 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 .
+ *
+ */
+
+#ifndef __SERIAL_H__
+#define __SERIAL_H__
+
+#ifdef USBCON
+ #include "HardwareSerial.h"
+ #if ENABLED(BLUETOOTH)
+ #define MYSERIAL bluetoothSerial
+ #else
+ #define MYSERIAL Serial
+ #endif // BLUETOOTH
+#else
+ #include "MarlinSerial.h"
+ #define MYSERIAL customizedSerial
+#endif
+
+extern const char echomagic[] PROGMEM;
+extern const char errormagic[] PROGMEM;
+
+#define SERIAL_CHAR(x) (MYSERIAL.write(x))
+#define SERIAL_EOL SERIAL_CHAR('\n')
+
+#define SERIAL_PROTOCOLCHAR(x) SERIAL_CHAR(x)
+#define SERIAL_PROTOCOL(x) (MYSERIAL.print(x))
+#define SERIAL_PROTOCOL_F(x,y) (MYSERIAL.print(x,y))
+#define SERIAL_PROTOCOLPGM(x) (serialprintPGM(PSTR(x)))
+#define SERIAL_PROTOCOLLN(x) do{ MYSERIAL.print(x); SERIAL_EOL; }while(0)
+#define SERIAL_PROTOCOLLNPGM(x) (serialprintPGM(PSTR(x "\n")))
+#define SERIAL_PROTOCOLPAIR(name, value) (serial_echopair_P(PSTR(name),(value)))
+#define SERIAL_PROTOCOLLNPAIR(name, value) do{ SERIAL_PROTOCOLPAIR(name, value); SERIAL_EOL; }while(0)
+
+#define SERIAL_ECHO_START (serialprintPGM(echomagic))
+#define SERIAL_ECHO(x) SERIAL_PROTOCOL(x)
+#define SERIAL_ECHOPGM(x) SERIAL_PROTOCOLPGM(x)
+#define SERIAL_ECHOLN(x) SERIAL_PROTOCOLLN(x)
+#define SERIAL_ECHOLNPGM(x) SERIAL_PROTOCOLLNPGM(x)
+#define SERIAL_ECHOPAIR(name,value) SERIAL_PROTOCOLPAIR(name, value)
+#define SERIAL_ECHOLNPAIR(name, value) SERIAL_PROTOCOLLNPAIR(name, value)
+#define SERIAL_ECHO_F(x,y) SERIAL_PROTOCOL_F(x,y)
+
+#define SERIAL_ERROR_START (serialprintPGM(errormagic))
+#define SERIAL_ERROR(x) SERIAL_PROTOCOL(x)
+#define SERIAL_ERRORPGM(x) SERIAL_PROTOCOLPGM(x)
+#define SERIAL_ERRORLN(x) SERIAL_PROTOCOLLN(x)
+#define SERIAL_ERRORLNPGM(x) SERIAL_PROTOCOLLNPGM(x)
+
+void serial_echopair_P(const char* s_P, const char *v);
+void serial_echopair_P(const char* s_P, char v);
+void serial_echopair_P(const char* s_P, int v);
+void serial_echopair_P(const char* s_P, long v);
+void serial_echopair_P(const char* s_P, float v);
+void serial_echopair_P(const char* s_P, double v);
+void serial_echopair_P(const char* s_P, unsigned int v);
+void serial_echopair_P(const char* s_P, unsigned long v);
+FORCE_INLINE void serial_echopair_P(const char* s_P, uint8_t v) { serial_echopair_P(s_P, (int)v); }
+FORCE_INLINE void serial_echopair_P(const char* s_P, uint16_t v) { serial_echopair_P(s_P, (int)v); }
+FORCE_INLINE void serial_echopair_P(const char* s_P, bool v) { serial_echopair_P(s_P, (int)v); }
+FORCE_INLINE void serial_echopair_P(const char* s_P, void *v) { serial_echopair_P(s_P, (unsigned long)v); }
+
+//
+// Functions for serial printing from PROGMEM. (Saves loads of SRAM.)
+//
+FORCE_INLINE void serialprintPGM(const char* str) {
+ while (char ch = pgm_read_byte(str++)) MYSERIAL.write(ch);
+}
+
+#endif // __SERIAL_H__
diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp
index f40742442..5c36b5724 100755
--- a/Marlin/ultralcd.cpp
+++ b/Marlin/ultralcd.cpp
@@ -677,7 +677,7 @@ void kill_screen(const char* lcd_msg) {
thermalManager.autotempShutdown();
#endif
wait_for_heatup = false;
- lcd_setstatus(MSG_PRINT_ABORTED, true);
+ lcd_setstatuspgm(PSTR(MSG_PRINT_ABORTED), true);
}
#endif // SDSUPPORT
@@ -3552,30 +3552,30 @@ void lcd_finishstatus(bool persist=false) {
bool lcd_hasstatus() { return (lcd_status_message[0] != '\0'); }
-void lcd_setstatus(const char* const message, bool persist) {
+void lcd_setstatus(const char * const message, const bool persist) {
if (lcd_status_message_level > 0) return;
strncpy(lcd_status_message, message, 3 * (LCD_WIDTH));
lcd_finishstatus(persist);
}
-void lcd_setstatuspgm(const char* const message, uint8_t level) {
+void lcd_setstatuspgm(const char * const message, const uint8_t level) {
if (level < lcd_status_message_level) return;
lcd_status_message_level = level;
strncpy_P(lcd_status_message, message, 3 * (LCD_WIDTH));
lcd_finishstatus(level > 0);
}
-void status_printf(uint8_t level, const char *status, ...) {
+void lcd_status_printf_P(const uint8_t level, const char * const fmt, ...) {
if (level < lcd_status_message_level) return;
lcd_status_message_level = level;
va_list args;
- va_start(args, status);
- vsnprintf_P(lcd_status_message, 3 * (LCD_WIDTH), status, args);
+ va_start(args, fmt);
+ vsnprintf_P(lcd_status_message, 3 * (LCD_WIDTH), fmt, args);
va_end(args);
lcd_finishstatus(level > 0);
}
-void lcd_setalertstatuspgm(const char* const message) {
+void lcd_setalertstatuspgm(const char * const message) {
lcd_setstatuspgm(message, 1);
#if ENABLED(ULTIPANEL)
lcd_return_to_status();
diff --git a/Marlin/ultralcd.h b/Marlin/ultralcd.h
index 071323157..0b32c09b6 100644
--- a/Marlin/ultralcd.h
+++ b/Marlin/ultralcd.h
@@ -39,7 +39,7 @@
bool lcd_hasstatus();
void lcd_setstatus(const char* message, const bool persist=false);
void lcd_setstatuspgm(const char* message, const uint8_t level=0);
- void status_printf(uint8_t level, const char *Status, ...);
+ void lcd_status_printf_P(const uint8_t level, const char * const fmt, ...);
void lcd_setalertstatuspgm(const char* message);
void lcd_reset_alert_level();
void lcd_kill_screen();
@@ -154,7 +154,7 @@
inline bool lcd_hasstatus() { return false; }
inline void lcd_setstatus(const char* const message, const bool persist=false) { UNUSED(message); UNUSED(persist); }
inline void lcd_setstatuspgm(const char* const message, const uint8_t level=0) { UNUSED(message); UNUSED(level); }
- inline void status_printf(uint8_t level, const char *status, ...) { UNUSED(level); UNUSED(status); }
+ inline void lcd_status_printf_P(const uint8_t level, const char * const fmt, ...) { UNUSED(level); UNUSED(fmt); }
inline void lcd_buttons_update() {}
inline void lcd_reset_alert_level() {}
inline bool lcd_detected() { return true; }