Merge pull request #6202 from thinkyhead/rc_fix_broken_ubl
Patching up UBL, vetting recent commits
This commit is contained in:
commit
34b23ff312
|
@ -128,7 +128,7 @@
|
||||||
extern bool code_value_bool();
|
extern bool code_value_bool();
|
||||||
extern bool code_has_value();
|
extern bool code_has_value();
|
||||||
extern void lcd_init();
|
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
|
#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();
|
bool prepare_move_to_destination_cartesian();
|
||||||
void line_to_destination();
|
void line_to_destination();
|
||||||
|
@ -156,7 +156,7 @@
|
||||||
// won't leave us in a bad state.
|
// won't leave us in a bad state.
|
||||||
|
|
||||||
float valid_trig_angle(float);
|
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,
|
static float extrusion_multiplier = EXTRUSION_MULTIPLIER,
|
||||||
retraction_multiplier = RETRACTION_MULTIPLIER,
|
retraction_multiplier = RETRACTION_MULTIPLIER,
|
||||||
|
@ -183,8 +183,8 @@
|
||||||
int i, xi, yi;
|
int i, xi, yi;
|
||||||
mesh_index_pair location;
|
mesh_index_pair location;
|
||||||
|
|
||||||
// Don't allow Mesh Validation without homing first
|
// Don't allow Mesh Validation without homing first,
|
||||||
// If the paramter parsing did not go OK, we abort the command
|
// or if the parameter parsing did not go OK, abort
|
||||||
if (axis_unhomed_error(true, true, true) || parse_G26_parameters()) return;
|
if (axis_unhomed_error(true, true, true) || parse_G26_parameters()) return;
|
||||||
|
|
||||||
if (current_position[Z_AXIS] < Z_CLEARANCE_BETWEEN_PROBES) {
|
if (current_position[Z_AXIS] < Z_CLEARANCE_BETWEEN_PROBES) {
|
||||||
|
@ -391,8 +391,8 @@
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
mesh_index_pair find_closest_circle_to_print( float X, float Y) {
|
mesh_index_pair find_closest_circle_to_print(const float &X, const float &Y) {
|
||||||
float f, mx, my, dx, dy, closest = 99999.99;
|
float closest = 99999.99;
|
||||||
mesh_index_pair return_val;
|
mesh_index_pair return_val;
|
||||||
|
|
||||||
return_val.x_index = return_val.y_index = -1;
|
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 i = 0; i < UBL_MESH_NUM_X_POINTS; i++) {
|
||||||
for (uint8_t j = 0; j < UBL_MESH_NUM_Y_POINTS; j++) {
|
for (uint8_t j = 0; j < UBL_MESH_NUM_Y_POINTS; j++) {
|
||||||
if (!is_bit_set(circle_flags, i, 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
|
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];
|
my = ubl.mesh_index_to_ypos[j];
|
||||||
|
|
||||||
dx = X - mx; // Get the distance to this intersection
|
// Get the distance to this intersection
|
||||||
dy = Y - my;
|
float f = HYPOT(X - mx, Y - my);
|
||||||
f = HYPOT(dx, dy);
|
|
||||||
|
|
||||||
dx = x_pos - mx; // It is possible that we are being called with the values
|
// 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.
|
// to let us find the closest circle to the start position.
|
||||||
f += HYPOT(dx, dy) / 15.0; // But if this is not the case,
|
// But if this is not the case, add a small weighting to the
|
||||||
// we are going to add in a small
|
// distance calculation to help it choose a better place to continue.
|
||||||
// weighting to the distance calculation to help it choose
|
f += HYPOT(x_pos - mx, y_pos - my) / 15.0;
|
||||||
// a better place to continue.
|
|
||||||
|
|
||||||
|
// Add in the specified amount of Random Noise to our search
|
||||||
if (random_deviation > 1.0)
|
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) {
|
if (f < closest) {
|
||||||
closest = f; // We found a closer location that is still
|
closest = f; // We found a closer location that is still
|
||||||
return_val.x_index = i; // un-printed --- save the data for it
|
return_val.x_index = i; // un-printed --- save the data for it
|
||||||
return_val.y_index = j;
|
return_val.y_index = j;
|
||||||
return_val.distance= closest;
|
return_val.distance = closest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,19 +39,7 @@
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "fastio.h"
|
#include "fastio.h"
|
||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
|
#include "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
|
|
||||||
|
|
||||||
#include "WString.h"
|
#include "WString.h"
|
||||||
|
|
||||||
#if ENABLED(PRINTCOUNTER)
|
#if ENABLED(PRINTCOUNTER)
|
||||||
|
@ -60,54 +48,6 @@
|
||||||
#include "stopwatch.h"
|
#include "stopwatch.h"
|
||||||
#endif
|
#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(
|
void idle(
|
||||||
#if ENABLED(FILAMENT_CHANGE_FEATURE)
|
#if ENABLED(FILAMENT_CHANGE_FEATURE)
|
||||||
bool no_stepper_sleep = false // pass true to keep steppers from disabling on timeout
|
bool no_stepper_sleep = false // pass true to keep steppers from disabling on timeout
|
||||||
|
|
|
@ -33,495 +33,490 @@
|
||||||
#include "stepper.h"
|
#include "stepper.h"
|
||||||
#include "Marlin.h"
|
#include "Marlin.h"
|
||||||
|
|
||||||
#ifndef USBCON
|
// Disable HardwareSerial.cpp to support chips without a UART (Attiny, etc.)
|
||||||
// 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)
|
|
||||||
|
|
||||||
#if UART_PRESENT(SERIAL_PORT)
|
#if !defined(USBCON) && (defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(UBRR2H) || defined(UBRR3H))
|
||||||
ring_buffer_r rx_buffer = { { 0 }, 0, 0 };
|
|
||||||
#if TX_BUFFER_SIZE > 0
|
#if UART_PRESENT(SERIAL_PORT)
|
||||||
ring_buffer_t tx_buffer = { { 0 }, 0, 0 };
|
ring_buffer_r rx_buffer = { { 0 }, 0, 0 };
|
||||||
static bool _written;
|
#if TX_BUFFER_SIZE > 0
|
||||||
|
ring_buffer_t tx_buffer = { { 0 }, 0, 0 };
|
||||||
|
static bool _written;
|
||||||
|
#endif
|
||||||
#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)
|
#if ENABLED(EMERGENCY_PARSER)
|
||||||
emergency_parser(c);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#if TX_BUFFER_SIZE > 0
|
#include "language.h"
|
||||||
|
|
||||||
FORCE_INLINE void _tx_udr_empty_irq(void) {
|
// Currently looking for: M108, M112, M410
|
||||||
// If interrupts are enabled, there must be more data in the output
|
// If you alter the parser please don't forget to update the capabilities in Conditionals_post.h
|
||||||
// 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;
|
FORCE_INLINE void emergency_parser(const unsigned char c) {
|
||||||
|
|
||||||
// clear the TXC bit -- "can be cleared by writing a one to its bit
|
static e_parser_state state = state_RESET;
|
||||||
// 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) {
|
switch (state) {
|
||||||
// Buffer empty, so disable interrupts
|
case state_RESET:
|
||||||
CBI(M_UCSRxB, M_UDRIEx);
|
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
|
case state_N:
|
||||||
ISR(M_USARTx_UDRE_vect) {
|
switch (c) {
|
||||||
_tx_udr_empty_irq();
|
case '0': case '1': case '2':
|
||||||
}
|
case '3': case '4': case '5':
|
||||||
#endif
|
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
|
case state_M1:
|
||||||
ISR(M_USARTx_RX_vect) {
|
switch (c) {
|
||||||
unsigned char c = M_UDRx;
|
case '0': state = state_M10; break;
|
||||||
store_char(c);
|
case '1': state = state_M11; break;
|
||||||
}
|
default: state = state_IGNORE;
|
||||||
#endif
|
}
|
||||||
|
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) {
|
case state_M41:
|
||||||
uint16_t baud_setting;
|
state = (c == '0') ? state_M410 : state_IGNORE;
|
||||||
bool useU2X = true;
|
break;
|
||||||
|
|
||||||
#if F_CPU == 16000000UL && SERIAL_PORT == 0
|
case state_IGNORE:
|
||||||
// hard-coded exception for compatibility with the bootloader shipped
|
if (c == '\n') state = state_RESET;
|
||||||
// with the Duemilanove and previous boards and the firmware on the 8U2
|
break;
|
||||||
// on the Uno and Mega 2560.
|
|
||||||
if (baud == 57600) {
|
|
||||||
useU2X = false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (useU2X) {
|
default:
|
||||||
M_UCSRxA = _BV(M_U2Xx);
|
if (c == '\n') {
|
||||||
baud_setting = (F_CPU / 4 / baud - 1) / 2;
|
switch (state) {
|
||||||
}
|
case state_M108:
|
||||||
else {
|
wait_for_user = wait_for_heatup = false;
|
||||||
M_UCSRxA = 0;
|
break;
|
||||||
baud_setting = (F_CPU / 8 / baud - 1) / 2;
|
case state_M112:
|
||||||
}
|
kill(PSTR(MSG_KILLED));
|
||||||
|
break;
|
||||||
// assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register)
|
case state_M410:
|
||||||
M_UBRRxH = baud_setting >> 8;
|
quickstop_stepper();
|
||||||
M_UBRRxL = baud_setting;
|
break;
|
||||||
|
default:
|
||||||
SBI(M_UCSRxB, M_RXENx);
|
break;
|
||||||
SBI(M_UCSRxB, M_TXENx);
|
}
|
||||||
SBI(M_UCSRxB, M_RXCIEx);
|
state = state_RESET;
|
||||||
#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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tx_buffer.buffer[tx_buffer.head] = c;
|
#endif
|
||||||
{ CRITICAL_SECTION_START;
|
|
||||||
tx_buffer.head = i;
|
|
||||||
SBI(M_UCSRxB, M_UDRIEx);
|
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;
|
CRITICAL_SECTION_END;
|
||||||
|
return (uint8_t)(TX_BUFFER_SIZE + h - t) & (TX_BUFFER_SIZE - 1);
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MarlinSerial::flushTX(void) {
|
void MarlinSerial::write(uint8_t c) {
|
||||||
// TX
|
_written = true;
|
||||||
// If we have never written a byte, no need to flush. This special
|
CRITICAL_SECTION_START;
|
||||||
// case is needed since there is no way to force the TXC (transmit
|
bool emty = (tx_buffer.head == tx_buffer.tail);
|
||||||
// complete) bit to 1 during initialization
|
CRITICAL_SECTION_END;
|
||||||
if (!_written)
|
// 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;
|
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::flushTX(void) {
|
||||||
void MarlinSerial::write(uint8_t c) {
|
// TX
|
||||||
while (!TEST(M_UCSRxA, M_UDREx))
|
// 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
|
||||||
M_UDRx = c;
|
// 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) {
|
void MarlinSerial::print(char c, int base) {
|
||||||
print((long) c, 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);
|
|
||||||
}
|
}
|
||||||
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('-');
|
print('-');
|
||||||
n = -n;
|
number = -number;
|
||||||
}
|
}
|
||||||
printNumber(n, 10);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
printNumber(n, base);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MarlinSerial::print(unsigned long n, int base) {
|
// Round correctly so that print(1.999, 2) prints as "2.00"
|
||||||
if (base == 0) write(n);
|
double rounding = 0.5;
|
||||||
else printNumber(n, base);
|
for (uint8_t i = 0; i < digits; ++i)
|
||||||
}
|
rounding *= 0.1;
|
||||||
|
|
||||||
void MarlinSerial::print(double n, int digits) {
|
number += rounding;
|
||||||
printFloat(n, digits);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MarlinSerial::println(void) {
|
// Extract the integer part of the number and print it
|
||||||
print('\r');
|
unsigned long int_part = (unsigned long)number;
|
||||||
print('\n');
|
double remainder = number - (double)int_part;
|
||||||
}
|
print(int_part);
|
||||||
|
|
||||||
void MarlinSerial::println(const String& s) {
|
// Print the decimal point, but only if there are digits beyond
|
||||||
print(s);
|
if (digits) {
|
||||||
println();
|
print('.');
|
||||||
}
|
// Extract digits from the remainder one at a time
|
||||||
|
while (digits--) {
|
||||||
void MarlinSerial::println(const char c[]) {
|
remainder *= 10.0;
|
||||||
print(c);
|
int toPrint = int(remainder);
|
||||||
println();
|
print(toPrint);
|
||||||
}
|
remainder -= toPrint;
|
||||||
|
}
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// Preinstantiate Objects //////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
// Preinstantiate
|
||||||
|
MarlinSerial customizedSerial;
|
||||||
|
|
||||||
MarlinSerial customizedSerial;
|
#endif // !USBCON && (UBRRH || UBRR0H || UBRR1H || UBRR2H || UBRR3H)
|
||||||
|
|
||||||
#endif // whole file
|
|
||||||
#endif // !USBCON
|
|
||||||
|
|
||||||
// For AT90USB targets use the UART for BT interfacing
|
// For AT90USB targets use the UART for BT interfacing
|
||||||
#if defined(USBCON) && ENABLED(BLUETOOTH)
|
#if defined(USBCON) && ENABLED(BLUETOOTH)
|
||||||
HardwareSerial bluetoothSerial;
|
HardwareSerial bluetoothSerial;
|
||||||
#endif
|
#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
|
|
||||||
|
|
|
@ -29,8 +29,8 @@
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef MarlinSerial_h
|
#ifndef MARLINSERIAL_H
|
||||||
#define MarlinSerial_h
|
#define MARLINSERIAL_H
|
||||||
|
|
||||||
#include "MarlinConfig.h"
|
#include "MarlinConfig.h"
|
||||||
|
|
||||||
|
@ -52,125 +52,118 @@
|
||||||
#define SERIAL_REGNAME_INTERNAL(registerbase,number,suffix) registerbase##number##suffix
|
#define SERIAL_REGNAME_INTERNAL(registerbase,number,suffix) registerbase##number##suffix
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Registers used by MarlinSerial class (these are expanded
|
// Registers used by MarlinSerial class (expanded depending on selected serial port)
|
||||||
// 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_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_UCSRxB SERIAL_REGNAME(UCSR,SERIAL_PORT,B)
|
#define M_RXENx SERIAL_REGNAME(RXEN,SERIAL_PORT,)
|
||||||
#define M_RXENx SERIAL_REGNAME(RXEN,SERIAL_PORT,)
|
#define M_TXENx SERIAL_REGNAME(TXEN,SERIAL_PORT,)
|
||||||
#define M_TXENx SERIAL_REGNAME(TXEN,SERIAL_PORT,)
|
#define M_TXCx SERIAL_REGNAME(TXC,SERIAL_PORT,)
|
||||||
#define M_TXCx SERIAL_REGNAME(TXC,SERIAL_PORT,)
|
#define M_RXCIEx SERIAL_REGNAME(RXCIE,SERIAL_PORT,)
|
||||||
#define M_RXCIEx SERIAL_REGNAME(RXCIE,SERIAL_PORT,)
|
#define M_UDREx SERIAL_REGNAME(UDRE,SERIAL_PORT,)
|
||||||
#define M_UDREx SERIAL_REGNAME(UDRE,SERIAL_PORT,)
|
#define M_UDRIEx SERIAL_REGNAME(UDRIE,SERIAL_PORT,)
|
||||||
#define M_UDRIEx SERIAL_REGNAME(UDRIE,SERIAL_PORT,)
|
#define M_UDRx SERIAL_REGNAME(UDR,SERIAL_PORT,)
|
||||||
#define M_UDRx SERIAL_REGNAME(UDR,SERIAL_PORT,)
|
#define M_UBRRxH SERIAL_REGNAME(UBRR,SERIAL_PORT,H)
|
||||||
#define M_UBRRxH SERIAL_REGNAME(UBRR,SERIAL_PORT,H)
|
#define M_UBRRxL SERIAL_REGNAME(UBRR,SERIAL_PORT,L)
|
||||||
#define M_UBRRxL SERIAL_REGNAME(UBRR,SERIAL_PORT,L)
|
#define M_RXCx SERIAL_REGNAME(RXC,SERIAL_PORT,)
|
||||||
#define M_RXCx SERIAL_REGNAME(RXC,SERIAL_PORT,)
|
#define M_USARTx_RX_vect SERIAL_REGNAME(USART,SERIAL_PORT,_RX_vect)
|
||||||
#define M_USARTx_RX_vect SERIAL_REGNAME(USART,SERIAL_PORT,_RX_vect)
|
#define M_U2Xx SERIAL_REGNAME(U2X,SERIAL_PORT,)
|
||||||
#define M_U2Xx SERIAL_REGNAME(U2X,SERIAL_PORT,)
|
|
||||||
#define M_USARTx_UDRE_vect SERIAL_REGNAME(USART,SERIAL_PORT,_UDRE_vect)
|
#define M_USARTx_UDRE_vect SERIAL_REGNAME(USART,SERIAL_PORT,_UDRE_vect)
|
||||||
|
|
||||||
|
|
||||||
#define DEC 10
|
#define DEC 10
|
||||||
#define HEX 16
|
#define HEX 16
|
||||||
#define OCT 8
|
#define OCT 8
|
||||||
#define BIN 2
|
#define BIN 2
|
||||||
#define BYTE 0
|
#define BYTE 0
|
||||||
|
|
||||||
|
|
||||||
#ifndef USBCON
|
#ifndef USBCON
|
||||||
// Define constants and variables for buffering incoming serial data. We're
|
// 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
|
// 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
|
// location to which to write the next incoming character and rx_buffer_tail
|
||||||
// is the index of the location from which to read.
|
// 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)
|
// 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
|
#ifndef RX_BUFFER_SIZE
|
||||||
#define RX_BUFFER_SIZE 128
|
#define RX_BUFFER_SIZE 128
|
||||||
#endif
|
#endif
|
||||||
#ifndef TX_BUFFER_SIZE
|
#ifndef TX_BUFFER_SIZE
|
||||||
#define TX_BUFFER_SIZE 32
|
#define TX_BUFFER_SIZE 32
|
||||||
#endif
|
#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))
|
#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"
|
#error "RX_BUFFER_SIZE has to be a power of 2 and >= 2"
|
||||||
#endif
|
#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))
|
#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
|
#error TX_BUFFER_SIZE has to be a power of 2 or 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct ring_buffer_r {
|
struct ring_buffer_r {
|
||||||
unsigned char buffer[RX_BUFFER_SIZE];
|
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];
|
|
||||||
volatile uint8_t head;
|
volatile uint8_t head;
|
||||||
volatile uint8_t tail;
|
volatile uint8_t tail;
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
|
|
||||||
#if UART_PRESENT(SERIAL_PORT)
|
|
||||||
extern ring_buffer_r rx_buffer;
|
|
||||||
#if TX_BUFFER_SIZE > 0
|
#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
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ENABLED(EMERGENCY_PARSER)
|
#if UART_PRESENT(SERIAL_PORT)
|
||||||
#include "language.h"
|
extern ring_buffer_r rx_buffer;
|
||||||
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 TX_BUFFER_SIZE > 0
|
#if TX_BUFFER_SIZE > 0
|
||||||
static uint8_t availableForWrite(void);
|
extern ring_buffer_t tx_buffer;
|
||||||
static void flushTX(void);
|
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
class MarlinSerial { //: public Stream
|
||||||
static void printNumber(unsigned long, uint8_t);
|
|
||||||
static void printFloat(double, uint8_t);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static FORCE_INLINE void write(const char* str) { while (*str) write(*str++); }
|
MarlinSerial() {};
|
||||||
static FORCE_INLINE void write(const uint8_t* buffer, size_t size) { while (size--) write(*buffer++); }
|
static void begin(long);
|
||||||
static FORCE_INLINE void print(const String& s) { for (int i = 0; i < (int)s.length(); i++) write(s[i]); }
|
static void end();
|
||||||
static FORCE_INLINE void print(const char* str) { write(str); }
|
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);
|
private:
|
||||||
static void print(unsigned char, int = BYTE);
|
static void printNumber(unsigned long, uint8_t);
|
||||||
static void print(int, int = DEC);
|
static void printFloat(double, uint8_t);
|
||||||
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);
|
public:
|
||||||
static void println(const char[]);
|
static FORCE_INLINE void write(const char* str) { while (*str) write(*str++); }
|
||||||
static void println(char, int = BYTE);
|
static FORCE_INLINE void write(const uint8_t* buffer, size_t size) { while (size--) write(*buffer++); }
|
||||||
static void println(unsigned char, int = BYTE);
|
static FORCE_INLINE void print(const String& s) { for (int i = 0; i < (int)s.length(); i++) write(s[i]); }
|
||||||
static void println(int, int = DEC);
|
static FORCE_INLINE void print(const char* str) { write(str); }
|
||||||
static void println(unsigned int, int = DEC);
|
|
||||||
static void println(long, int = DEC);
|
static void print(char, int = BYTE);
|
||||||
static void println(unsigned long, int = DEC);
|
static void print(unsigned char, int = BYTE);
|
||||||
static void println(double, int = 2);
|
static void print(int, int = DEC);
|
||||||
static void println(void);
|
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
|
#endif // !USBCON
|
||||||
|
|
||||||
// Use the UART for Bluetooth in AT90USB configurations
|
// Use the UART for Bluetooth in AT90USB configurations
|
||||||
|
@ -178,4 +171,4 @@ extern MarlinSerial customizedSerial;
|
||||||
extern HardwareSerial bluetoothSerial;
|
extern HardwareSerial bluetoothSerial;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif // MARLINSERIAL_H
|
||||||
|
|
|
@ -447,8 +447,6 @@ volatile bool wait_for_heatup = true;
|
||||||
volatile bool wait_for_user = false;
|
volatile bool wait_for_user = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const char errormagic[] PROGMEM = "Error:";
|
|
||||||
const char echomagic[] PROGMEM = "echo:";
|
|
||||||
const char axis_codes[XYZE] = {'X', 'Y', 'Z', 'E'};
|
const char axis_codes[XYZE] = {'X', 'Y', 'Z', 'E'};
|
||||||
|
|
||||||
// Number of characters read in the current line of serial input
|
// 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]);
|
void plan_cubic_move(const float offset[4]);
|
||||||
#endif
|
#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);
|
void tool_change(const uint8_t tmp_extruder, const float fr_mm_s=0.0, bool no_move=false);
|
||||||
static void report_current_position();
|
static void report_current_position();
|
||||||
|
|
||||||
|
@ -1789,15 +1779,10 @@ static void clean_up_after_endstop_or_probe_move() {
|
||||||
SERIAL_ECHOLNPGM(" " MSG_FIRST);
|
SERIAL_ECHOLNPGM(" " MSG_FIRST);
|
||||||
|
|
||||||
#if ENABLED(ULTRA_LCD)
|
#if ENABLED(ULTRA_LCD)
|
||||||
char message[3 * (LCD_WIDTH) + 1] = ""; // worst case is kana.utf with up to 3*LCD_WIDTH+1
|
lcd_status_printf_P(0, PSTR(MSG_HOME " %s%s%s " MSG_FIRST), xx ? MSG_X : "", yy ? MSG_Y : "", zz ? MSG_Z : "");
|
||||||
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);
|
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -5153,7 +5138,6 @@ inline void gcode_M31() {
|
||||||
char buffer[21];
|
char buffer[21];
|
||||||
duration_t elapsed = print_job_timer.duration();
|
duration_t elapsed = print_job_timer.duration();
|
||||||
elapsed.toString(buffer);
|
elapsed.toString(buffer);
|
||||||
|
|
||||||
lcd_setstatus(buffer);
|
lcd_setstatus(buffer);
|
||||||
|
|
||||||
SERIAL_ECHO_START;
|
SERIAL_ECHO_START;
|
||||||
|
@ -5700,7 +5684,7 @@ inline void gcode_M104() {
|
||||||
}
|
}
|
||||||
#endif
|
#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)
|
#if ENABLED(AUTOTEMP)
|
||||||
|
@ -5898,7 +5882,7 @@ inline void gcode_M109() {
|
||||||
else print_job_timer.start();
|
else print_job_timer.start();
|
||||||
#endif
|
#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)
|
#if ENABLED(AUTOTEMP)
|
||||||
|
@ -8903,7 +8887,7 @@ void process_next_command() {
|
||||||
gcode_G28();
|
gcode_G28();
|
||||||
break;
|
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,
|
case 29: // G29 Detailed Z probe, probes the bed at 3 or more points,
|
||||||
// or provides access to the UBL System if enabled.
|
// or provides access to the UBL System if enabled.
|
||||||
gcode_G29();
|
gcode_G29();
|
||||||
|
@ -10175,6 +10159,8 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) {
|
||||||
/**
|
/**
|
||||||
* Prepare a linear move in a Cartesian setup.
|
* Prepare a linear move in a Cartesian setup.
|
||||||
* If Mesh Bed Leveling is enabled, perform a mesh move.
|
* 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() {
|
inline bool prepare_move_to_destination_cartesian() {
|
||||||
// Do not use feedrate_percentage for E or Z only moves
|
// 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
|
else
|
||||||
#elif ENABLED(AUTO_BED_LEVELING_UBL)
|
#elif ENABLED(AUTO_BED_LEVELING_UBL)
|
||||||
if (ubl.state.active) {
|
if (ubl.state.active) {
|
||||||
|
|
||||||
ubl_line_to_destination(MMS_SCALED(feedrate_mm_s), active_extruder);
|
ubl_line_to_destination(MMS_SCALED(feedrate_mm_s), active_extruder);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
30
Marlin/UBL.h
30
Marlin/UBL.h
|
@ -29,6 +29,7 @@
|
||||||
|
|
||||||
#if ENABLED(AUTO_BED_LEVELING_UBL)
|
#if ENABLED(AUTO_BED_LEVELING_UBL)
|
||||||
|
|
||||||
|
#define UBL_VERSION "1.00"
|
||||||
#define UBL_OK false
|
#define UBL_OK false
|
||||||
#define UBL_ERR true
|
#define UBL_ERR true
|
||||||
|
|
||||||
|
@ -98,9 +99,6 @@
|
||||||
float g29_correction_fade_height = 10.0,
|
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,
|
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.
|
// 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
|
#endif
|
||||||
|
|
||||||
// If you change this struct, adjust TOTAL_STRUCT_SIZE
|
// If you change this struct, adjust TOTAL_STRUCT_SIZE
|
||||||
|
@ -118,8 +116,7 @@
|
||||||
class unified_bed_leveling {
|
class unified_bed_leveling {
|
||||||
private:
|
private:
|
||||||
|
|
||||||
static float last_specified_z,
|
static float last_specified_z;
|
||||||
fade_scaling_factor_for_current_height;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -307,32 +304,29 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This routine is used to scale the Z correction depending upon the current nozzle height. It is
|
* This function sets the Z leveling fade factor based on the given Z height,
|
||||||
* optimized for speed. It avoids floating point operations by checking if the requested scaling
|
* only re-calculating when necessary.
|
||||||
* factor is going to be the same as the last time the function calculated a value. If so, it just
|
|
||||||
* returns it.
|
|
||||||
*
|
*
|
||||||
* It returns a scaling factor of 1.0 if UBL is inactive.
|
* Returns 1.0 if g29_correction_fade_height is 0.0.
|
||||||
* It returns a scaling factor of 0.0 if Z is past the specified 'Fade Height'
|
* Returns 0.0 if Z is past the specified 'Fade Height'.
|
||||||
*/
|
*/
|
||||||
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
|
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
|
||||||
|
|
||||||
static FORCE_INLINE float fade_scaling_factor_for_z(const float &lz) {
|
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);
|
const float rz = RAW_Z_POSITION(lz);
|
||||||
if (last_specified_z != rz) {
|
if (last_specified_z != rz) {
|
||||||
last_specified_z = rz;
|
last_specified_z = rz;
|
||||||
fade_scaling_factor_for_current_height =
|
fade_scaling_factor =
|
||||||
state.active && rz < state.g29_correction_fade_height
|
rz < state.g29_correction_fade_height
|
||||||
? 1.0 - (rz * state.g29_fade_height_multiplier)
|
? 1.0 - (rz * state.g29_fade_height_multiplier)
|
||||||
: 0.0;
|
: 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
|
#endif
|
||||||
|
|
||||||
}; // class unified_bed_leveling
|
}; // class unified_bed_leveling
|
||||||
|
|
|
@ -61,7 +61,6 @@
|
||||||
|
|
||||||
float unified_bed_leveling::z_values[UBL_MESH_NUM_X_POINTS][UBL_MESH_NUM_Y_POINTS],
|
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::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_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];
|
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
|
* updated, but until then, we try to ease the transition
|
||||||
* for our Beta testers.
|
* for our Beta testers.
|
||||||
*/
|
*/
|
||||||
if (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;
|
||||||
ubl.state.g29_fade_height_multiplier = 1.0 / ubl.state.g29_correction_fade_height;
|
if (ubl.state.g29_fade_height_multiplier != recip) {
|
||||||
|
ubl.state.g29_fade_height_multiplier = recip;
|
||||||
store_state();
|
store_state();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -160,7 +160,6 @@
|
||||||
ZERO(z_values);
|
ZERO(z_values);
|
||||||
|
|
||||||
last_specified_z = -999.9;
|
last_specified_z = -999.9;
|
||||||
fade_scaling_factor_for_current_height = 0.0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void unified_bed_leveling::invalidate() {
|
void unified_bed_leveling::invalidate() {
|
||||||
|
|
|
@ -307,7 +307,8 @@
|
||||||
static float x_pos, y_pos, measured_z, card_thickness = 0.0, ubl_constant = 0.0;
|
static float x_pos, y_pos, measured_z, card_thickness = 0.0, ubl_constant = 0.0;
|
||||||
|
|
||||||
#if ENABLED(ULTRA_LCD)
|
#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
|
#endif
|
||||||
|
|
||||||
void gcode_G29() {
|
void gcode_G29() {
|
||||||
|
@ -655,7 +656,7 @@
|
||||||
if (ELAPSED(millis(), nxt)) {
|
if (ELAPSED(millis(), nxt)) {
|
||||||
SERIAL_PROTOCOLLNPGM("\nZ-Offset Adjustment Stopped.");
|
SERIAL_PROTOCOLLNPGM("\nZ-Offset Adjustment Stopped.");
|
||||||
do_blocking_move_to_z(Z_CLEARANCE_DEPLOY_PROBE);
|
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();
|
restore_ubl_active_state_and_leave();
|
||||||
goto LEAVE;
|
goto LEAVE;
|
||||||
}
|
}
|
||||||
|
@ -673,7 +674,8 @@
|
||||||
LEAVE:
|
LEAVE:
|
||||||
|
|
||||||
#if ENABLED(ULTRA_LCD)
|
#if ENABLED(ULTRA_LCD)
|
||||||
lcd_setstatus(" ", true);
|
lcd_reset_alert_level();
|
||||||
|
lcd_setstatuspgm("");
|
||||||
lcd_quick_feedback();
|
lcd_quick_feedback();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -977,7 +979,7 @@
|
||||||
|
|
||||||
bool g29_parameter_parsing() {
|
bool g29_parameter_parsing() {
|
||||||
#if ENABLED(ULTRA_LCD)
|
#if ENABLED(ULTRA_LCD)
|
||||||
lcd_setstatus("Doing G29 UBL !", true);
|
lcd_setstatuspgm("Doing G29 UBL!");
|
||||||
lcd_quick_feedback();
|
lcd_quick_feedback();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1088,7 +1090,7 @@
|
||||||
ubl_state_recursion_chk++;
|
ubl_state_recursion_chk++;
|
||||||
if (ubl_state_recursion_chk != 1) {
|
if (ubl_state_recursion_chk != 1) {
|
||||||
SERIAL_ECHOLNPGM("save_ubl_active_state_and_disabled() called multiple times in a row.");
|
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();
|
lcd_quick_feedback();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1099,7 +1101,7 @@
|
||||||
void restore_ubl_active_state_and_leave() {
|
void restore_ubl_active_state_and_leave() {
|
||||||
if (--ubl_state_recursion_chk) {
|
if (--ubl_state_recursion_chk) {
|
||||||
SERIAL_ECHOLNPGM("restore_ubl_active_state_and_leave() called too many times.");
|
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();
|
lcd_quick_feedback();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1114,7 +1116,7 @@
|
||||||
void g29_what_command() {
|
void g29_what_command() {
|
||||||
const uint16_t k = E2END - ubl.eeprom_start;
|
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)
|
if (ubl.state.active)
|
||||||
SERIAL_PROTOCOLCHAR('A');
|
SERIAL_PROTOCOLCHAR('A');
|
||||||
else
|
else
|
||||||
|
@ -1132,8 +1134,7 @@
|
||||||
safe_delay(50);
|
safe_delay(50);
|
||||||
|
|
||||||
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
|
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
|
||||||
SERIAL_PROTOCOLPAIR("g29_correction_fade_height : ", ubl.state.g29_correction_fade_height);
|
SERIAL_PROTOCOLLNPAIR("g29_correction_fade_height : ", ubl.state.g29_correction_fade_height);
|
||||||
SERIAL_EOL;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SERIAL_PROTOCOLPGM("z_offset: ");
|
SERIAL_PROTOCOLPGM("z_offset: ");
|
||||||
|
@ -1340,7 +1341,7 @@
|
||||||
memset(not_done, 0xFF, sizeof(not_done));
|
memset(not_done, 0xFF, sizeof(not_done));
|
||||||
|
|
||||||
#if ENABLED(ULTRA_LCD)
|
#if ENABLED(ULTRA_LCD)
|
||||||
lcd_setstatus("Fine Tuning Mesh.", true);
|
lcd_setstatuspgm("Fine Tuning Mesh");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
do_blocking_move_to_z(Z_CLEARANCE_DEPLOY_PROBE);
|
do_blocking_move_to_z(Z_CLEARANCE_DEPLOY_PROBE);
|
||||||
|
@ -1399,7 +1400,7 @@
|
||||||
lcd_return_to_status();
|
lcd_return_to_status();
|
||||||
//SERIAL_PROTOCOLLNPGM("\nFine Tuning of Mesh Stopped.");
|
//SERIAL_PROTOCOLLNPGM("\nFine Tuning of Mesh Stopped.");
|
||||||
do_blocking_move_to_z(Z_CLEARANCE_DEPLOY_PROBE);
|
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();
|
while (ubl_lcd_clicked()) idle();
|
||||||
|
|
||||||
|
@ -1427,9 +1428,9 @@
|
||||||
do_blocking_move_to_xy(lx, ly);
|
do_blocking_move_to_xy(lx, ly);
|
||||||
|
|
||||||
#if ENABLED(ULTRA_LCD)
|
#if ENABLED(ULTRA_LCD)
|
||||||
lcd_setstatus("Done Editing Mesh", true);
|
lcd_setstatuspgm("Done Editing Mesh");
|
||||||
#endif
|
#endif
|
||||||
SERIAL_ECHOLNPGM("Done Editing Mesh.");
|
SERIAL_ECHOLNPGM("Done Editing Mesh");
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // AUTO_BED_LEVELING_UBL
|
#endif // AUTO_BED_LEVELING_UBL
|
|
@ -170,9 +170,7 @@ void Endstops::report_state() {
|
||||||
SERIAL_EOL;
|
SERIAL_EOL;
|
||||||
|
|
||||||
#if ENABLED(ULTRA_LCD)
|
#if ENABLED(ULTRA_LCD)
|
||||||
char msg[3 * strlen(MSG_LCD_ENDSTOPS) + 8 + 1]; // Room for a UTF 8 string
|
lcd_status_printf_P(0, PSTR(MSG_LCD_ENDSTOPS " %c %c %c %c"), chrX, chrY, chrZ, chrP);
|
||||||
sprintf_P(msg, PSTR(MSG_LCD_ENDSTOPS " %c %c %c %c"), chrX, chrY, chrZ, chrP);
|
|
||||||
lcd_setstatus(msg);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
hit_on_purpose();
|
hit_on_purpose();
|
||||||
|
|
34
Marlin/serial.cpp
Normal file
34
Marlin/serial.cpp
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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); }
|
88
Marlin/serial.h
Normal file
88
Marlin/serial.h
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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__
|
|
@ -677,7 +677,7 @@ void kill_screen(const char* lcd_msg) {
|
||||||
thermalManager.autotempShutdown();
|
thermalManager.autotempShutdown();
|
||||||
#endif
|
#endif
|
||||||
wait_for_heatup = false;
|
wait_for_heatup = false;
|
||||||
lcd_setstatus(MSG_PRINT_ABORTED, true);
|
lcd_setstatuspgm(PSTR(MSG_PRINT_ABORTED), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // SDSUPPORT
|
#endif // SDSUPPORT
|
||||||
|
@ -3552,30 +3552,30 @@ void lcd_finishstatus(bool persist=false) {
|
||||||
|
|
||||||
bool lcd_hasstatus() { return (lcd_status_message[0] != '\0'); }
|
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;
|
if (lcd_status_message_level > 0) return;
|
||||||
strncpy(lcd_status_message, message, 3 * (LCD_WIDTH));
|
strncpy(lcd_status_message, message, 3 * (LCD_WIDTH));
|
||||||
lcd_finishstatus(persist);
|
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;
|
if (level < lcd_status_message_level) return;
|
||||||
lcd_status_message_level = level;
|
lcd_status_message_level = level;
|
||||||
strncpy_P(lcd_status_message, message, 3 * (LCD_WIDTH));
|
strncpy_P(lcd_status_message, message, 3 * (LCD_WIDTH));
|
||||||
lcd_finishstatus(level > 0);
|
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;
|
if (level < lcd_status_message_level) return;
|
||||||
lcd_status_message_level = level;
|
lcd_status_message_level = level;
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, status);
|
va_start(args, fmt);
|
||||||
vsnprintf_P(lcd_status_message, 3 * (LCD_WIDTH), status, args);
|
vsnprintf_P(lcd_status_message, 3 * (LCD_WIDTH), fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
lcd_finishstatus(level > 0);
|
lcd_finishstatus(level > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void lcd_setalertstatuspgm(const char* const message) {
|
void lcd_setalertstatuspgm(const char * const message) {
|
||||||
lcd_setstatuspgm(message, 1);
|
lcd_setstatuspgm(message, 1);
|
||||||
#if ENABLED(ULTIPANEL)
|
#if ENABLED(ULTIPANEL)
|
||||||
lcd_return_to_status();
|
lcd_return_to_status();
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
bool lcd_hasstatus();
|
bool lcd_hasstatus();
|
||||||
void lcd_setstatus(const char* message, const bool persist=false);
|
void lcd_setstatus(const char* message, const bool persist=false);
|
||||||
void lcd_setstatuspgm(const char* message, const uint8_t level=0);
|
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_setalertstatuspgm(const char* message);
|
||||||
void lcd_reset_alert_level();
|
void lcd_reset_alert_level();
|
||||||
void lcd_kill_screen();
|
void lcd_kill_screen();
|
||||||
|
@ -154,7 +154,7 @@
|
||||||
inline bool lcd_hasstatus() { return false; }
|
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_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 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_buttons_update() {}
|
||||||
inline void lcd_reset_alert_level() {}
|
inline void lcd_reset_alert_level() {}
|
||||||
inline bool lcd_detected() { return true; }
|
inline bool lcd_detected() { return true; }
|
||||||
|
|
Loading…
Reference in a new issue