Browse Source

♻️ Simplify SERIAL_ECHO (#25928)

Since this increases AVR code size, try to optimize further.
Scott Lahteine 1 year ago
parent
commit
2ef71c6eba

+ 3 - 9
Marlin/src/HAL/LPC1768/eeprom_sdcard.cpp

@@ -91,15 +91,9 @@ bool PersistentStore::access_finish() {
 static void debug_rw(const bool write, int &pos, const uint8_t *value, const size_t size, const FRESULT s, const size_t total=0) {
   #if ENABLED(DEBUG_SD_EEPROM_EMULATION)
     FSTR_P const rw_str = write ? F("write") : F("read");
-    SERIAL_CHAR(' ');
-    SERIAL_ECHOF(rw_str);
-    SERIAL_ECHOLNPGM("_data(", pos, ",", *value, ",", size, ", ...)");
-    if (total) {
-      SERIAL_ECHOPGM(" f_");
-      SERIAL_ECHOF(rw_str);
-      SERIAL_ECHOPGM("()=", s, "\n size=", size, "\n bytes_");
-      SERIAL_ECHOLNF(write ? F("written=") : F("read="), total);
-    }
+    SERIAL_ECHOLN(AS_CHAR(' '), rw_str, F("_data("), pos, AS_CHAR(','), *value, AS_CHAR(','), size, F(", ...)"));
+    if (total)
+      SERIAL_ECHOLN(F(" f_"), rw_str, F("()="), s, F("\n size="), size, F("\n bytes_"), write ? F("written=") : F("read="), total);
     else
       SERIAL_ECHOLNPGM(" f_lseek()=", s);
   #endif

+ 1 - 7
Marlin/src/HAL/shared/Delay.cpp

@@ -109,13 +109,7 @@
   #if ENABLED(MARLIN_DEV_MODE)
     void dump_delay_accuracy_check() {
       auto report_call_time = [](FSTR_P const name, FSTR_P const unit, const uint32_t cycles, const uint32_t total, const bool do_flush=true) {
-        SERIAL_ECHOPGM("Calling ");
-        SERIAL_ECHOF(name);
-        SERIAL_ECHOLNPGM(" for ", cycles);
-        SERIAL_ECHOF(unit);
-        SERIAL_ECHOLNPGM(" took: ", total);
-        SERIAL_CHAR(' ');
-        SERIAL_ECHOF(unit);
+        SERIAL_ECHOLN(F("Calling "), name, F(" for "), cycles, AS_CHAR(' '), unit, F(" took: "), total, AS_CHAR(' '), unit);
         if (do_flush) SERIAL_FLUSHTX();
       };
 

+ 1 - 1
Marlin/src/MarlinCore.cpp

@@ -882,7 +882,7 @@ void kill(FSTR_P const lcd_error/*=nullptr*/, FSTR_P const lcd_component/*=nullp
   TERN_(HAS_CUTTER, cutter.kill()); // Full cutter shutdown including ISR control
 
   // Echo the LCD message to serial for extra context
-  if (lcd_error) { SERIAL_ECHO_START(); SERIAL_ECHOLNF(lcd_error); }
+  if (lcd_error) { SERIAL_ECHO_START(); SERIAL_ECHOLN(lcd_error); }
 
   #if HAS_DISPLAY
     ui.kill_screen(lcd_error ?: GET_TEXT_F(MSG_KILLED), lcd_component ?: FPSTR(NUL_STR));

+ 0 - 24
Marlin/src/core/debug_out.h

@@ -31,19 +31,11 @@
 #undef DEBUG_ERROR_START
 #undef DEBUG_CHAR
 #undef DEBUG_ECHO
-#undef DEBUG_DECIMAL
-#undef DEBUG_ECHO_F
 #undef DEBUG_ECHOLN
 #undef DEBUG_ECHOPGM
 #undef DEBUG_ECHOLNPGM
-#undef DEBUG_ECHOF
-#undef DEBUG_ECHOLNF
 #undef DEBUG_ECHOPGM_P
 #undef DEBUG_ECHOLNPGM_P
-#undef DEBUG_ECHOPAIR_F
-#undef DEBUG_ECHOPAIR_F_P
-#undef DEBUG_ECHOLNPAIR_F
-#undef DEBUG_ECHOLNPAIR_F_P
 #undef DEBUG_ECHO_MSG
 #undef DEBUG_ERROR_MSG
 #undef DEBUG_EOL
@@ -62,21 +54,13 @@
   #define DEBUG_ERROR_START       SERIAL_ERROR_START
   #define DEBUG_CHAR              SERIAL_CHAR
   #define DEBUG_ECHO              SERIAL_ECHO
-  #define DEBUG_DECIMAL           SERIAL_DECIMAL
-  #define DEBUG_ECHO_F            SERIAL_ECHO_F
   #define DEBUG_ECHOLN            SERIAL_ECHOLN
   #define DEBUG_ECHOPGM           SERIAL_ECHOPGM
   #define DEBUG_ECHOLNPGM         SERIAL_ECHOLNPGM
-  #define DEBUG_ECHOF             SERIAL_ECHOF
-  #define DEBUG_ECHOLNF           SERIAL_ECHOLNF
   #define DEBUG_ECHOPGM           SERIAL_ECHOPGM
   #define DEBUG_ECHOPGM_P         SERIAL_ECHOPGM_P
-  #define DEBUG_ECHOPAIR_F        SERIAL_ECHOPAIR_F
-  #define DEBUG_ECHOPAIR_F_P      SERIAL_ECHOPAIR_F_P
   #define DEBUG_ECHOLNPGM         SERIAL_ECHOLNPGM
   #define DEBUG_ECHOLNPGM_P       SERIAL_ECHOLNPGM_P
-  #define DEBUG_ECHOLNPAIR_F      SERIAL_ECHOLNPAIR_F
-  #define DEBUG_ECHOLNPAIR_F_P    SERIAL_ECHOLNPAIR_F_P
   #define DEBUG_ECHO_MSG          SERIAL_ECHO_MSG
   #define DEBUG_ERROR_MSG         SERIAL_ERROR_MSG
   #define DEBUG_EOL               SERIAL_EOL
@@ -93,19 +77,11 @@
   #define DEBUG_ERROR_START()       NOOP
   #define DEBUG_CHAR(...)           NOOP
   #define DEBUG_ECHO(...)           NOOP
-  #define DEBUG_DECIMAL(...)        NOOP
-  #define DEBUG_ECHO_F(...)         NOOP
   #define DEBUG_ECHOLN(...)         NOOP
   #define DEBUG_ECHOPGM(...)        NOOP
   #define DEBUG_ECHOLNPGM(...)      NOOP
-  #define DEBUG_ECHOF(...)          NOOP
-  #define DEBUG_ECHOLNF(...)        NOOP
   #define DEBUG_ECHOPGM_P(...)      NOOP
   #define DEBUG_ECHOLNPGM_P(...)    NOOP
-  #define DEBUG_ECHOPAIR_F(...)     NOOP
-  #define DEBUG_ECHOPAIR_F_P(...)   NOOP
-  #define DEBUG_ECHOLNPAIR_F(...)   NOOP
-  #define DEBUG_ECHOLNPAIR_F_P(...) NOOP
   #define DEBUG_ECHO_MSG(...)       NOOP
   #define DEBUG_ERROR_MSG(...)      NOOP
   #define DEBUG_EOL()               NOOP

+ 2 - 5
Marlin/src/core/debug_section.h

@@ -38,11 +38,8 @@ private:
   bool debug;
 
   void echo_msg(FSTR_P const fpre) {
-    SERIAL_ECHOF(fpre);
-    if (the_msg) {
-      SERIAL_CHAR(' ');
-      SERIAL_ECHOF(the_msg);
-    }
+    SERIAL_ECHO(fpre);
+    if (the_msg) SERIAL_ECHO(AS_CHAR(' '), the_msg);
     SERIAL_CHAR(' ');
     print_pos(current_position);
   }

+ 35 - 10
Marlin/src/core/serial.cpp

@@ -68,26 +68,51 @@ MAP(_N_LBL, LOGICAL_AXIS_NAMES); MAP(_SP_N_LBL, LOGICAL_AXIS_NAMES);
 
 #endif
 
-void serial_print_P(PGM_P str) {
-  while (const char c = pgm_read_byte(str++)) SERIAL_CHAR(c);
+// Specializations for float, p_float_t, w_float_t
+template <> void SERIAL_ECHO(const float f)      { SERIAL_IMPL.print(f); }
+template <> void SERIAL_ECHO(const p_float_t pf) { SERIAL_IMPL.print(pf.value, pf.prec); }
+template <> void SERIAL_ECHO(const w_float_t wf) { char f1[20]; SERIAL_IMPL.print(dtostrf(wf.value, wf.width, wf.prec, f1)); }
+
+// Specializations for F-string
+template <> void SERIAL_ECHO(const FSTR_P fstr)   { SERIAL_ECHO_P(FTOP(fstr)); }
+template <> void SERIAL_ECHOLN(const FSTR_P fstr) { SERIAL_ECHOLN_P(FTOP(fstr)); }
+
+void SERIAL_CHAR(char a) { SERIAL_IMPL.write(a); }
+void SERIAL_EOL() { SERIAL_CHAR('\n'); }
+
+void SERIAL_ECHO(serial_char_t x) { SERIAL_IMPL.write(x.c); }
+
+void SERIAL_FLUSH()    { SERIAL_IMPL.flush(); }
+void SERIAL_FLUSHTX()  { SERIAL_IMPL.flushTX(); }
+
+void SERIAL_ECHO_P(PGM_P pstr) {
+  while (const char c = pgm_read_byte(pstr++)) SERIAL_CHAR(c);
 }
+void SERIAL_ECHOLN_P(PGM_P pstr) { SERIAL_ECHO_P(pstr); SERIAL_EOL(); }
 
-void serial_echo_start()  { serial_print(F("echo:")); }
-void serial_error_start() { serial_print(F("Error:")); }
+void SERIAL_ECHO_START()  { SERIAL_ECHO(F("echo:")); }
+void SERIAL_ERROR_START() { SERIAL_ECHO(F("Error:")); }
 
-void serial_spaces(uint8_t count) { count *= (PROPORTIONAL_FONT_RATIO); while (count--) SERIAL_CHAR(' '); }
+void SERIAL_ECHO_SP(uint8_t count) { count *= (PROPORTIONAL_FONT_RATIO); while (count--) SERIAL_CHAR(' '); }
 
 void serial_offset(const_float_t v, const uint8_t sp/*=0*/) {
   if (v == 0 && sp == 1)
     SERIAL_CHAR(' ');
   else if (v > 0 || (v == 0 && sp == 2))
     SERIAL_CHAR('+');
-  SERIAL_DECIMAL(v);
+  SERIAL_ECHO(v);
+}
+
+void serial_ternary(FSTR_P const pre, const bool onoff, FSTR_P const on, FSTR_P const off, FSTR_P const post/*=nullptr*/) {
+  if (pre)           SERIAL_ECHO(pre);
+  if (onoff && on)   SERIAL_ECHO(on);
+  if (!onoff && off) SERIAL_ECHO(off);
+  if (post)          SERIAL_ECHO(post);
 }
 
-void serialprint_onoff(const bool onoff) { serial_print(onoff ? F(STR_ON) : F(STR_OFF)); }
+void serialprint_onoff(const bool onoff) { SERIAL_ECHO(onoff ? F(STR_ON) : F(STR_OFF)); }
 void serialprintln_onoff(const bool onoff) { serialprint_onoff(onoff); SERIAL_EOL(); }
-void serialprint_truefalse(const bool tf) { serial_print(tf ? F("true") : F("false")); }
+void serialprint_truefalse(const bool tf) { SERIAL_ECHO(tf ? F("true") : F("false")); }
 
 void print_bin(uint16_t val) {
   for (uint8_t i = 16; i--;) {
@@ -97,11 +122,11 @@ void print_bin(uint16_t val) {
 }
 
 void print_pos(NUM_AXIS_ARGS_(const_float_t) FSTR_P const prefix/*=nullptr*/, FSTR_P const suffix/*=nullptr*/) {
-  if (prefix) serial_print(prefix);
+  if (prefix) SERIAL_ECHO(prefix);
   #if NUM_AXES
     SERIAL_ECHOPGM_P(
       LIST_N(DOUBLE(NUM_AXES), SP_X_STR, x, SP_Y_STR, y, SP_Z_STR, z, SP_I_STR, i, SP_J_STR, j, SP_K_STR, k, SP_U_STR, u, SP_V_STR, v, SP_W_STR, w)
     );
   #endif
-  if (suffix) serial_print(suffix); else SERIAL_EOL();
+  if (suffix) SERIAL_ECHO(suffix); else SERIAL_EOL();
 }

+ 47 - 145
Marlin/src/core/serial.h

@@ -125,8 +125,6 @@ extern uint8_t marlin_debug_flags;
   #define SERIAL_IMPL         SERIAL_LEAF_1
 #endif
 
-#define SERIAL_OUT(WHAT, V...)  (void)SERIAL_IMPL.WHAT(V)
-
 #define PORT_REDIRECT(p)   _PORT_REDIRECT(1,p)
 #define PORT_RESTORE()     _PORT_RESTORE(1)
 #define SERIAL_PORTMASK(P) SerialMask::from(P)
@@ -134,65 +132,69 @@ extern uint8_t marlin_debug_flags;
 //
 // SERIAL_CHAR - Print one or more individual chars
 //
-inline void SERIAL_CHAR(char a) { SERIAL_IMPL.write(a); }
+void SERIAL_CHAR(char a);
 template <typename ... Args>
 void SERIAL_CHAR(char a, Args ... args) { SERIAL_IMPL.write(a); SERIAL_CHAR(args ...); }
 
 /**
- * SERIAL_ECHO - Print a single string or value.
+ * SERIAL_ECHO / SERIAL_ECHOLN - Print a single string or value.
  *   Any numeric parameter (including char) is printed as a base-10 number.
  *   A string pointer or literal will be output as a string.
  *
  * NOTE: Use SERIAL_CHAR to print char as a single character.
  */
-template <typename T>
-void SERIAL_ECHO(T x) { SERIAL_IMPL.print(x); }
+template <typename T> void SERIAL_ECHO(T x)   { SERIAL_IMPL.print(x); }
+template <typename T> void SERIAL_ECHOLN(T x) { SERIAL_IMPL.println(x); }
 
 // Wrapper for ECHO commands to interpret a char
-typedef struct SerialChar { char c; SerialChar(char n) : c(n) { } } serial_char_t;
-inline void SERIAL_ECHO(serial_char_t x) { SERIAL_IMPL.write(x.c); }
-#define AS_CHAR(C) serial_char_t(C)
+void SERIAL_ECHO(serial_char_t x);
 #define AS_DIGIT(C) AS_CHAR('0' + (C))
 
-template <typename T>
-void SERIAL_ECHOLN(T x) { SERIAL_IMPL.println(x); }
-
-// SERIAL_PRINT works like SERIAL_ECHO but also takes the numeric base
-template <typename T, typename U>
-void SERIAL_PRINT(T x, U y) { SERIAL_IMPL.print(x, y); }
-
-template <typename T>
-void SERIAL_PRINTLN(T x, PrintBase y) { SERIAL_IMPL.println(x, y); }
+// Print an integer with a numeric base such as PrintBase::Hex
+template <typename T> void SERIAL_PRINT(T x, PrintBase y)   { SERIAL_IMPL.print(x, y); }
+template <typename T> void SERIAL_PRINTLN(T x, PrintBase y) { SERIAL_IMPL.println(x, y); }
 
 // Flush the serial port
-inline void SERIAL_FLUSH()    { SERIAL_IMPL.flush(); }
-inline void SERIAL_FLUSHTX()  { SERIAL_IMPL.flushTX(); }
+void SERIAL_FLUSH();
+void SERIAL_FLUSHTX();
 
-// Serial echo and error prefixes
-#define SERIAL_ECHO_START()           serial_echo_start()
-#define SERIAL_ERROR_START()          serial_error_start()
+// Start an echo: or error: output
+void SERIAL_ECHO_START();
+void SERIAL_ERROR_START();
 
 // Serial end-of-line
-#define SERIAL_EOL()                  SERIAL_CHAR('\n')
+void SERIAL_EOL();
 
 // Print a single PROGMEM, PGM_P, or PSTR() string.
-void serial_print_P(PGM_P str);
-inline void serial_println_P(PGM_P str) { serial_print_P(str); SERIAL_EOL(); }
+void SERIAL_ECHO_P(PGM_P pstr);
+void SERIAL_ECHOLN_P(PGM_P pstr);
+
+// Specializations for float, p_float_t, and w_float_t
+template<> void SERIAL_ECHO(const float f);
+template<> void SERIAL_ECHO(const p_float_t pf);
+template<> void SERIAL_ECHO(const w_float_t wf);
+
+// Specializations for F-string
+template<> void SERIAL_ECHO(const FSTR_P fstr);
+template<> void SERIAL_ECHOLN(const FSTR_P fstr);
 
-// Print a single FSTR_P, F(), or FPSTR() string.
-inline void serial_print(FSTR_P const fstr) { serial_print_P(FTOP(fstr)); }
-inline void serial_println(FSTR_P const fstr) { serial_println_P(FTOP(fstr)); }
+// Print any number of items with arbitrary types (except loose PROGMEM strings)
+template <typename T, typename ... Args>
+void SERIAL_ECHO(T arg1, Args ... args) { SERIAL_ECHO(arg1); SERIAL_ECHO(args ...); }
+template <typename T, typename ... Args>
+void SERIAL_ECHOLN(T arg1, Args ... args) { SERIAL_ECHO(arg1); SERIAL_ECHO(args ...); SERIAL_EOL(); }
 
 //
-// SERIAL_ECHOPGM... macros are used to output string-value pairs.
+// SERIAL_ECHOPGM... macros are used to output string-value pairs, wrapping
+//                   all the odd loose string elements as PROGMEM strings.
 //
 
 // Print up to 20 pairs of values. Odd elements must be literal strings.
 #define __SEP_N(N,V...)           _SEP_##N(V)
 #define _SEP_N(N,V...)            __SEP_N(N,V)
 #define _SEP_N_REF()              _SEP_N
-#define _SEP_1(s)                 serial_print(F(s));
-#define _SEP_2(s,v)               serial_echopair(F(s),v);
+#define _SEP_1(s)                 SERIAL_ECHO(F(s));
+#define _SEP_2(s,v)               SERIAL_ECHO(F(s),v);
 #define _SEP_3(s,v,V...)          _SEP_2(s,v); DEFER2(_SEP_N_REF)()(TWO_ARGS(V),V);
 #define SERIAL_ECHOPGM(V...)      do{ EVAL(_SEP_N(TWO_ARGS(V),V)); }while(0)
 
@@ -200,8 +202,8 @@ inline void serial_println(FSTR_P const fstr) { serial_println_P(FTOP(fstr)); }
 #define __SELP_N(N,V...)          _SELP_##N(V)
 #define _SELP_N(N,V...)           __SELP_N(N,V)
 #define _SELP_N_REF()             _SELP_N
-#define _SELP_1(s)                serial_print(F(s "\n"));
-#define _SELP_2(s,v)              serial_echolnpair(F(s),v);
+#define _SELP_1(s)                SERIAL_ECHO(F(s "\n"));
+#define _SELP_2(s,v)              SERIAL_ECHOLN(F(s),v);
 #define _SELP_3(s,v,V...)         _SEP_2(s,v); DEFER2(_SELP_N_REF)()(TWO_ARGS(V),V);
 #define SERIAL_ECHOLNPGM(V...)    do{ EVAL(_SELP_N(TWO_ARGS(V),V)); }while(0)
 
@@ -209,8 +211,8 @@ inline void serial_println(FSTR_P const fstr) { serial_println_P(FTOP(fstr)); }
 #define __SEP_N_P(N,V...)         _SEP_##N##_P(V)
 #define _SEP_N_P(N,V...)          __SEP_N_P(N,V)
 #define _SEP_N_P_REF()            _SEP_N_P
-#define _SEP_1_P(p)               serial_print_P(p);
-#define _SEP_2_P(p,v)             serial_echopair_P(p,v);
+#define _SEP_1_P(p)               SERIAL_ECHO(FPSTR(p));
+#define _SEP_2_P(p,v)             SERIAL_ECHO(FPSTR(p),v);
 #define _SEP_3_P(p,v,V...)        _SEP_2_P(p,v); DEFER2(_SEP_N_P_REF)()(TWO_ARGS(V),V);
 #define SERIAL_ECHOPGM_P(V...)    do{ EVAL(_SEP_N_P(TWO_ARGS(V),V)); }while(0)
 
@@ -218,125 +220,25 @@ inline void serial_println(FSTR_P const fstr) { serial_println_P(FTOP(fstr)); }
 #define __SELP_N_P(N,V...)        _SELP_##N##_P(V)
 #define _SELP_N_P(N,V...)         __SELP_N_P(N,V)
 #define _SELP_N_P_REF()           _SELP_N_P
-#define _SELP_1_P(p)              serial_println_P(p)
-#define _SELP_2_P(p,v)            serial_echolnpair_P(p,v)
+#define _SELP_1_P(p)              SERIAL_ECHOLN(FPSTR(p));
+#define _SELP_2_P(p,v)            SERIAL_ECHOLN(FPSTR(p),v);
 #define _SELP_3_P(p,v,V...)       { _SEP_2_P(p,v); DEFER2(_SELP_N_P_REF)()(TWO_ARGS(V),V); }
 #define SERIAL_ECHOLNPGM_P(V...)  do{ EVAL(_SELP_N_P(TWO_ARGS(V),V)); }while(0)
 
-// Print up to 20 pairs of values. Odd elements must be FSTR_P, F(), or FPSTR().
-#define __SEP_N_F(N,V...)         _SEP_##N##_F(V)
-#define _SEP_N_F(N,V...)          __SEP_N_F(N,V)
-#define _SEP_N_F_REF()            _SEP_N_F
-#define _SEP_1_F(p)               serial_print(p);
-#define _SEP_2_F(p,v)             serial_echopair(p,v);
-#define _SEP_3_F(p,v,V...)        _SEP_2_F(p,v); DEFER2(_SEP_N_F_REF)()(TWO_ARGS(V),V);
-#define SERIAL_ECHOF(V...)        do{ EVAL(_SEP_N_F(TWO_ARGS(V),V)); }while(0)
-
-// Print up to 20 pairs of values followed by newline. Odd elements must be FSTR_P, F(), or FPSTR().
-#define __SELP_N_F(N,V...)        _SELP_##N##_F(V)
-#define _SELP_N_F(N,V...)         __SELP_N_F(N,V)
-#define _SELP_N_F_REF()           _SELP_N_F
-#define _SELP_1_F(p)              serial_println(p)
-#define _SELP_2_F(p,v)            serial_echolnpair(p,v)
-#define _SELP_3_F(p,v,V...)       { _SEP_2_F(p,v); DEFER2(_SELP_N_F_REF)()(TWO_ARGS(V),V); }
-#define SERIAL_ECHOLNF(V...)      do{ EVAL(_SELP_N_F(TWO_ARGS(V),V)); }while(0)
-
-#ifdef AllowDifferentTypeInList
-
-  inline void SERIAL_ECHOLIST_IMPL() {}
-  template <typename T>
-  void SERIAL_ECHOLIST_IMPL(T && t) { SERIAL_IMPL.print(t); }
-
-  template <typename T, typename ... Args>
-  void SERIAL_ECHOLIST_IMPL(T && t, Args && ... args) {
-    SERIAL_IMPL.print(t);
-    serial_print(F(", "));
-    SERIAL_ECHOLIST_IMPL(args...);
-  }
-
-  template <typename ... Args>
-  void SERIAL_ECHOLIST(FSTR_P const str, Args && ... args) {
-    SERIAL_IMPL.print(FTOP(str));
-    SERIAL_ECHOLIST_IMPL(args...);
-  }
-
-#else // Optimization if the listed type are all the same (seems to be the case in the codebase so use that instead)
-
-  template <typename ... Args>
-  void SERIAL_ECHOLIST(FSTR_P const fstr, Args && ... args) {
-    serial_print(fstr);
-    typename Private::first_type_of<Args...>::type values[] = { args... };
-    constexpr size_t argsSize = sizeof...(args);
-    for (size_t i = 0; i < argsSize; i++) {
-      if (i) serial_print(F(", "));
-      SERIAL_IMPL.print(values[i]);
-    }
-  }
-
-#endif
-
-// SERIAL_ECHO_F prints a floating point value with optional precision
-inline void SERIAL_ECHO_F(EnsureDouble x, int digit=2) { SERIAL_IMPL.print(x, digit); }
-
-#define SERIAL_ECHOPAIR_F_P(P,V...)   do{ serial_print_P(P); SERIAL_ECHO_F(V); }while(0)
-#define SERIAL_ECHOLNPAIR_F_P(P,V...) do{ SERIAL_ECHOPAIR_F_P(P,V); SERIAL_EOL(); }while(0)
-
-#define SERIAL_ECHOPAIR_F_F(S,V...)   do{ serial_print(S); SERIAL_ECHO_F(V); }while(0)
-#define SERIAL_ECHOLNPAIR_F_F(S,V...) do{ SERIAL_ECHOPAIR_F_F(S,V); SERIAL_EOL(); }while(0)
-
-#define SERIAL_ECHOPAIR_F(S,V...)     SERIAL_ECHOPAIR_F_F(F(S),V)
-#define SERIAL_ECHOLNPAIR_F(V...)     do{ SERIAL_ECHOPAIR_F(V); SERIAL_EOL(); }while(0)
-
-#define SERIAL_ECHO_MSG(V...)         do{ SERIAL_ECHO_START();  SERIAL_ECHOLNPGM(V); }while(0)
-#define SERIAL_ERROR_MSG(V...)        do{ SERIAL_ERROR_START(); SERIAL_ECHOLNPGM(V); }while(0)
-
-#define SERIAL_ECHO_SP(C)             serial_spaces(C)
+#define SERIAL_ECHO_MSG(V...)  do{ SERIAL_ECHO_START();  SERIAL_ECHOLNPGM(V); }while(0)
+#define SERIAL_ERROR_MSG(V...) do{ SERIAL_ERROR_START(); SERIAL_ECHOLNPGM(V); }while(0)
 
+// Print a prefix, conditional string, and suffix
+void serial_ternary(FSTR_P const pre, const bool onoff, FSTR_P const on, FSTR_P const off, FSTR_P const post=nullptr);
+// Shorthand to put loose strings in PROGMEM
 #define SERIAL_ECHO_TERNARY(TF, PRE, ON, OFF, POST) serial_ternary(F(PRE), TF, F(ON), F(OFF), F(POST))
 
-#if SERIAL_FLOAT_PRECISION
-  #define SERIAL_DECIMAL(V) SERIAL_PRINT(V, SERIAL_FLOAT_PRECISION)
-#else
-  #define SERIAL_DECIMAL(V) SERIAL_ECHO(V)
-#endif
+// Print up to 255 spaces
+void SERIAL_ECHO_SP(uint8_t count);
 
-//
-// Functions for serial printing from PROGMEM. (Saves loads of SRAM.)
-//
-inline void serial_echopair_P(PGM_P const pstr, serial_char_t v) { serial_print_P(pstr); SERIAL_CHAR(v.c); }
-inline void serial_echopair_P(PGM_P const pstr, float v)         { serial_print_P(pstr); SERIAL_DECIMAL(v); }
-inline void serial_echopair_P(PGM_P const pstr, double v)        { serial_print_P(pstr); SERIAL_DECIMAL(v); }
-//inline void serial_echopair_P(PGM_P const pstr, const char *v)   { serial_print_P(pstr); SERIAL_ECHO(v); }
-inline void serial_echopair_P(PGM_P const pstr, FSTR_P v)        { serial_print_P(pstr); SERIAL_ECHOF(v); }
-
-// Default implementation for types without a specialization. Handles integers.
-template <typename T>
-inline void serial_echopair_P(PGM_P const pstr, T v) { serial_print_P(pstr); SERIAL_ECHO(v); }
-
-// Add a newline.
-template <typename T>
-inline void serial_echolnpair_P(PGM_P const pstr, T v) { serial_echopair_P(pstr, v); SERIAL_EOL(); }
-
-// Catch-all for __FlashStringHelper *
-template <typename T>
-inline void serial_echopair(FSTR_P const fstr, T v) { serial_echopair_P(FTOP(fstr), v); }
-
-// Add a newline to the serial output
-template <typename T>
-inline void serial_echolnpair(FSTR_P const fstr, T v) { serial_echolnpair_P(FTOP(fstr), v); }
-
-void serial_echo_start();
-void serial_error_start();
-inline void serial_ternary(FSTR_P const pre, const bool onoff, FSTR_P const on, FSTR_P const off, FSTR_P const post=nullptr) {
-  if (pre) serial_print(pre);
-  if (onoff && on) serial_print(on);
-  if (!onoff && off) serial_print(off);
-  if (post) serial_print(post);
-}
 void serialprint_onoff(const bool onoff);
 void serialprintln_onoff(const bool onoff);
 void serialprint_truefalse(const bool tf);
-void serial_spaces(uint8_t count);
 void serial_offset(const_float_t v, const uint8_t sp=0); // For v==0 draw space (sp==1) or plus (sp==2)
 
 void print_bin(const uint16_t val);

+ 2 - 3
Marlin/src/core/serial_base.h

@@ -79,7 +79,7 @@ struct EnsureDouble {
   operator double() { return a; }
   // If the compiler breaks on ambiguity here, it's likely because print(X, base) is called with X not a double/float, and
   // a base that's not a PrintBase value. This code is made to detect the error. You MUST set a base explicitly like this:
-  // SERIAL_PRINT(v, PrintBase::Hex)
+  //SERIAL_PRINT(v, PrintBase::Hex)
   EnsureDouble(double a) : a(a) {}
   EnsureDouble(float a) : a(a) {}
 };
@@ -169,7 +169,6 @@ struct SerialBase {
   FORCE_INLINE void print(unsigned int c, PrintBase base)       { printNumber_unsigned(c, base); }
   FORCE_INLINE void print(unsigned long c, PrintBase base)      { printNumber_unsigned(c, base); }
 
-
   void print(EnsureDouble c, int digits)           { printFloat(c, digits); }
 
   // Forward the call to the former's method
@@ -180,7 +179,7 @@ struct SerialBase {
   void print(T c)    { print(c, PrintBase::Dec); }
 
   void print(float c)    { print(c, 2); }
-  void print(double c)    { print(c, 2); }
+  void print(double c)   { print(c, 2); }
 
   void println(char *s)               { print(s); println(); }
   void println(const char *s)         { print(s); println(); }

+ 30 - 0
Marlin/src/core/types.h

@@ -283,6 +283,36 @@ typedef IF<TERN0(ABL_USES_GRID, (GRID_MAX_POINTS > 255)), uint16_t, uint8_t>::ty
 #define MMM_TO_MMS(MM_M) feedRate_t(static_cast<float>(MM_M) / 60.0f)
 #define MMS_TO_MMM(MM_S) (static_cast<float>(MM_S) * 60.0f)
 
+// Packaged character for AS_CHAR macro and other usage
+typedef struct SerialChar { char c; SerialChar(char n) : c(n) { } } serial_char_t;
+#define AS_CHAR(C) serial_char_t(C)
+
+// Packaged types: float with precision and/or width; a repeated space/character
+typedef struct WFloat { float value; char width; char prec;
+                        WFloat(float v, char w, char p) : value(v), width(w), prec(p) {}
+                      } w_float_t;
+typedef struct PFloat { float value; char prec;
+                        PFloat(float v, char p) : value(v), prec(p) {}
+                      } p_float_t;
+typedef struct RepChr { char asc; uint8_t count;
+                        RepChr(char a, uint8_t c) : asc(a), count(c) {}
+                      } repchr_t;
+typedef struct Spaces { uint8_t count;
+                        Spaces(uint8_t c) : count(c) {}
+                      } spaces_t;
+
+#ifdef __AVR__
+  typedef w_float_t w_double_t;
+  typedef p_float_t p_double_t;
+#else
+  typedef struct WDouble { double value; char width; char prec;
+                          WDouble(double v, char w, char p) : value(v), width(w), prec(p) {}
+                        } w_double_t;
+  typedef struct PDouble { double value; char prec;
+                          PDouble(double v, char p) : value(v), prec(p) {}
+                        } p_double_t;
+#endif
+
 //
 // Coordinates structures for XY, XYZ, XYZE...
 //

+ 7 - 3
Marlin/src/core/utility.cpp

@@ -25,6 +25,10 @@
 #include "../MarlinCore.h"
 #include "../module/temperature.h"
 
+#if ENABLED(MARLIN_DEV_MODE)
+  MarlinError marlin_error_number;    // Error Number - Marlin can beep X times periodically, display, and emit...
+#endif
+
 void safe_delay(millis_t ms) {
   while (ms > 50) {
     ms -= 50;
@@ -95,9 +99,9 @@ void safe_delay(millis_t ms) {
           SERIAL_ECHOPGM(" (Aligned With");
 
         if (probe.offset_xy.y > 0)
-          SERIAL_ECHOF(F(TERN(IS_SCARA, "-Distal", "-Back")));
+          SERIAL_ECHO(F(TERN(IS_SCARA, "-Distal", "-Back")));
         else if (probe.offset_xy.y < 0)
-          SERIAL_ECHOF(F(TERN(IS_SCARA, "-Proximal", "-Front")));
+          SERIAL_ECHO(F(TERN(IS_SCARA, "-Proximal", "-Front")));
         else if (probe.offset_xy.x != 0)
           SERIAL_ECHOPGM("-Center");
 
@@ -105,7 +109,7 @@ void safe_delay(millis_t ms) {
 
       #endif
 
-      SERIAL_ECHOF(probe.offset.z < 0 ? F("Below") : probe.offset.z > 0 ? F("Above") : F("Same Z as"));
+      SERIAL_ECHO(probe.offset.z < 0 ? F("Below") : probe.offset.z > 0 ? F("Above") : F("Same Z as"));
       SERIAL_ECHOLNPGM(" Nozzle)");
 
     #endif

Some files were not shown because too many files changed in this diff