diff --git a/.gitignore b/.gitignore
index 62f73a7c0d00..f7d49cc1ed28 100755
--- a/.gitignore
+++ b/.gitignore
@@ -19,9 +19,9 @@
# along with this program. If not, see .
#
-# Our automatic versioning scheme generates the following file
-# NEVER put it in the repository
+# Generated files
_Version.h
+bdf2u8g
#
# OS
diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h
index f0fd6abee47e..11dcd53f812c 100644
--- a/Marlin/Configuration.h
+++ b/Marlin/Configuration.h
@@ -1625,7 +1625,9 @@
// @section temperature
-// Preheat Constants
+//
+// Preheat Constants - Up to 5 are supported without changes
+//
#define PREHEAT_1_LABEL "PLA"
#define PREHEAT_1_TEMP_HOTEND 200
#define PREHEAT_1_TEMP_BED 55
diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h
index c8d702518cd1..8f0b31b05673 100644
--- a/Marlin/Configuration_adv.h
+++ b/Marlin/Configuration_adv.h
@@ -115,6 +115,12 @@
#define CHAMBER_BETA 3950 // Beta value
#endif
+#if TEMP_SENSOR_PROBE == 1000
+ #define PROBE_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
+ #define PROBE_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
+ #define PROBE_BETA 3950 // Beta value
+#endif
+
//
// Hephestos 2 24V heated bed upgrade kit.
// https://store.bq.com/en/heated-bed-kit-hephestos2
@@ -333,7 +339,7 @@
* High Temperature Thermistor Support
*
* Thermistors able to support high temperature tend to have a hard time getting
- * good readings at room and lower temperatures. This means HEATER_X_RAW_LO_TEMP
+ * good readings at room and lower temperatures. This means TEMP_SENSOR_X_RAW_LO_TEMP
* will probably be caught when the heating element first turns on during the
* preheating process, which will trigger a min_temp_error as a safety measure
* and force stop everything.
@@ -1405,6 +1411,9 @@
// Enable if SD detect is rendered useless (e.g., by using an SD extender)
//#define NO_SD_DETECT
+ // Enable if SD detect is rendered useless (e.g., by using an SD extender)
+ //#define NO_SD_DETECT
+
#endif // SDSUPPORT
/**
@@ -3359,7 +3368,8 @@
#endif
/**
- * User-defined menu items that execute custom GCode
+ * User-defined menu items to run custom G-code.
+ * Up to 25 may be defined, but the actual number is LCD-dependent.
*/
//#define CUSTOM_USER_MENUS
#if ENABLED(CUSTOM_USER_MENUS)
@@ -3369,7 +3379,7 @@
//#define USER_SCRIPT_RETURN // Return to status screen after a script
#define USER_DESC_1 "Home & UBL Info"
- #define USER_GCODE_1 "G28\nG29 W"
+ #define USER_GCODE_1 "G28\nG29W"
#define USER_DESC_2 "Preheat for " PREHEAT_1_LABEL
#define USER_GCODE_2 "M140 S" STRINGIFY(PREHEAT_1_TEMP_BED) "\nM104 S" STRINGIFY(PREHEAT_1_TEMP_HOTEND)
diff --git a/Marlin/src/HAL/AVR/HAL.cpp b/Marlin/src/HAL/AVR/HAL.cpp
index 58d57c8ee54b..4c45a5d78e65 100644
--- a/Marlin/src/HAL/AVR/HAL.cpp
+++ b/Marlin/src/HAL/AVR/HAL.cpp
@@ -24,6 +24,13 @@
#include "../../inc/MarlinConfig.h"
#include "HAL.h"
+#ifdef USBCON
+ DefaultSerial MSerial(false, Serial);
+ #ifdef BLUETOOTH
+ BTSerial btSerial(false, bluetoothSerial);
+ #endif
+#endif
+
// ------------------------
// Public Variables
// ------------------------
diff --git a/Marlin/src/HAL/AVR/HAL.h b/Marlin/src/HAL/AVR/HAL.h
index aa6a32132032..5e22ac0836e2 100644
--- a/Marlin/src/HAL/AVR/HAL.h
+++ b/Marlin/src/HAL/AVR/HAL.h
@@ -82,7 +82,15 @@ typedef int8_t pin_t;
// Serial ports
#ifdef USBCON
- #define MYSERIAL0 TERN(BLUETOOTH, bluetoothSerial, Serial)
+ #include "../../core/serial_hook.h"
+ typedef ForwardSerial0Type< decltype(Serial) > DefaultSerial;
+ extern DefaultSerial MSerial;
+ #ifdef BLUETOOTH
+ typedef ForwardSerial0Type< decltype(bluetoothSerial) > BTSerial;
+ extern BTSerial btSerial;
+ #endif
+
+ #define MYSERIAL0 TERN(BLUETOOTH, btSerial, MSerial)
#else
#if !WITHIN(SERIAL_PORT, -1, 3)
#error "SERIAL_PORT must be from -1 to 3. Please update your configuration."
@@ -97,6 +105,13 @@ typedef int8_t pin_t;
#endif
#endif
+#ifdef MMU2_SERIAL_PORT
+ #if !WITHIN(MMU2_SERIAL_PORT, -1, 3)
+ #error "MMU2_SERIAL_PORT must be from -1 to 3. Please update your configuration."
+ #endif
+ #define MMU2_SERIAL mmuSerial
+#endif
+
#ifdef LCD_SERIAL_PORT
#if !WITHIN(LCD_SERIAL_PORT, -1, 3)
#error "LCD_SERIAL_PORT must be from -1 to 3. Please update your configuration."
diff --git a/Marlin/src/HAL/AVR/MarlinSerial.cpp b/Marlin/src/HAL/AVR/MarlinSerial.cpp
index 63599efd4132..562a70ced7a9 100644
--- a/Marlin/src/HAL/AVR/MarlinSerial.cpp
+++ b/Marlin/src/HAL/AVR/MarlinSerial.cpp
@@ -454,7 +454,7 @@ void MarlinSerial::flush() {
}
template
-void MarlinSerial::write(const uint8_t c) {
+size_t MarlinSerial::write(const uint8_t c) {
if (Cfg::TX_SIZE == 0) {
_written = true;
@@ -480,7 +480,7 @@ void MarlinSerial::write(const uint8_t c) {
// location". This makes sure flush() won't return until the bytes
// actually got written
B_TXC = 1;
- return;
+ return 1;
}
const uint8_t i = (tx_buffer.head + 1) & (Cfg::TX_SIZE - 1);
@@ -510,6 +510,7 @@ void MarlinSerial::write(const uint8_t c) {
// Enable TX ISR - Non atomic, but it will eventually enable TX ISR
B_UDRIE = 1;
}
+ return 1;
}
template
@@ -556,161 +557,6 @@ void MarlinSerial::flushTX() {
}
}
-/**
- * Imports from print.h
- */
-
-template
-void MarlinSerial::print(char c, int base) {
- print((long)c, base);
-}
-
-template
-void MarlinSerial::print(unsigned char b, int base) {
- print((unsigned long)b, base);
-}
-
-template
-void MarlinSerial::print(int n, int base) {
- print((long)n, base);
-}
-
-template
-void MarlinSerial::print(unsigned int n, int base) {
- print((unsigned long)n, base);
-}
-
-template
-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);
-}
-
-template
-void MarlinSerial::print(unsigned long n, int base) {
- if (base == 0) write(n);
- else printNumber(n, base);
-}
-
-template
-void MarlinSerial::print(double n, int digits) {
- printFloat(n, digits);
-}
-
-template
-void MarlinSerial::println() {
- print('\r');
- print('\n');
-}
-
-template
-void MarlinSerial::println(const String& s) {
- print(s);
- println();
-}
-
-template
-void MarlinSerial::println(const char c[]) {
- print(c);
- println();
-}
-
-template
-void MarlinSerial::println(char c, int base) {
- print(c, base);
- println();
-}
-
-template
-void MarlinSerial::println(unsigned char b, int base) {
- print(b, base);
- println();
-}
-
-template
-void MarlinSerial::println(int n, int base) {
- print(n, base);
- println();
-}
-
-template
-void MarlinSerial::println(unsigned int n, int base) {
- print(n, base);
- println();
-}
-
-template
-void MarlinSerial::println(long n, int base) {
- print(n, base);
- println();
-}
-
-template
-void MarlinSerial::println(unsigned long n, int base) {
- print(n, base);
- println();
-}
-
-template
-void MarlinSerial::println(double n, int digits) {
- print(n, digits);
- println();
-}
-
-// Private Methods
-
-template
-void MarlinSerial::printNumber(unsigned long n, uint8_t base) {
- if (n) {
- unsigned char buf[8 * sizeof(long)]; // Enough space for base 2
- int8_t i = 0;
- while (n) {
- buf[i++] = n % base;
- n /= base;
- }
- while (i--)
- print((char)(buf[i] + (buf[i] < 10 ? '0' : 'A' - 10)));
- }
- else
- print('0');
-}
-
-template
-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;
- LOOP_L_N(i, digits) 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;
- }
- }
-}
-
// Hookup ISR handlers
ISR(SERIAL_REGNAME(USART, SERIAL_PORT, _RX_vect)) {
MarlinSerial>::store_rxd_char();
@@ -720,11 +566,9 @@ ISR(SERIAL_REGNAME(USART, SERIAL_PORT, _UDRE_vect)) {
MarlinSerial>::_tx_udr_empty_irq();
}
-// Preinstantiate
-template class MarlinSerial>;
-
-// Instantiate
-MarlinSerial> customizedSerial1;
+// Because of the template definition above, it's required to instantiate the template to have all method generated
+template class MarlinSerial< MarlinSerialCfg >;
+MSerialT customizedSerial1(MSerialT::HasEmergencyParser);
#ifdef SERIAL_PORT_2
@@ -737,12 +581,8 @@ MarlinSerial> customizedSerial1;
MarlinSerial>::_tx_udr_empty_irq();
}
- // Preinstantiate
- template class MarlinSerial>;
-
- // Instantiate
- MarlinSerial> customizedSerial2;
-
+ template class MarlinSerial< MarlinSerialCfg >;
+ MSerialT2 customizedSerial2(MSerialT2::HasEmergencyParser);
#endif
#ifdef MMU2_SERIAL_PORT
@@ -755,12 +595,8 @@ MarlinSerial> customizedSerial1;
MarlinSerial>::_tx_udr_empty_irq();
}
- // Preinstantiate
- template class MarlinSerial>;
-
- // Instantiate
- MarlinSerial> mmuSerial;
-
+ template class MarlinSerial< MMU2SerialCfg >;
+ MSerialT3 mmuSerial(MSerialT3::HasEmergencyParser);
#endif
#ifdef LCD_SERIAL_PORT
@@ -773,11 +609,8 @@ MarlinSerial> customizedSerial1;
MarlinSerial>::_tx_udr_empty_irq();
}
- // Preinstantiate
- template class MarlinSerial>;
-
- // Instantiate
- MarlinSerial> lcdSerial;
+ template class MarlinSerial< LCDSerialCfg >;
+ MSerialT4 lcdSerial(MSerialT4::HasEmergencyParser);
#if HAS_DGUS_LCD
template
@@ -796,7 +629,7 @@ MarlinSerial> customizedSerial1;
// For AT90USB targets use the UART for BT interfacing
#if defined(USBCON) && ENABLED(BLUETOOTH)
- HardwareSerial bluetoothSerial;
+ MSerialT5 bluetoothSerial(false);
#endif
#endif // __AVR__
diff --git a/Marlin/src/HAL/AVR/MarlinSerial.h b/Marlin/src/HAL/AVR/MarlinSerial.h
index 8a0423d143d8..9abc3dbed0c0 100644
--- a/Marlin/src/HAL/AVR/MarlinSerial.h
+++ b/Marlin/src/HAL/AVR/MarlinSerial.h
@@ -34,6 +34,7 @@
#include
#include "../../inc/MarlinConfigPre.h"
+#include "../../core/serial_hook.h"
#ifndef SERIAL_PORT
#define SERIAL_PORT 0
@@ -135,10 +136,6 @@
UART_DECL(3);
#endif
- #define DEC 10
- #define HEX 16
- #define OCT 8
- #define BIN 2
#define BYTE 0
// Templated type selector
@@ -202,60 +199,30 @@
static FORCE_INLINE void atomic_set_rx_tail(ring_buffer_pos_t value);
static FORCE_INLINE ring_buffer_pos_t atomic_read_rx_tail();
- public:
-
+ public:
FORCE_INLINE static void store_rxd_char();
FORCE_INLINE static void _tx_udr_empty_irq();
- public:
- MarlinSerial() {};
- static void begin(const long);
- static void end();
- static int peek();
- static int read();
- static void flush();
- static ring_buffer_pos_t available();
- static void write(const uint8_t c);
- static void flushTX();
- #if HAS_DGUS_LCD
- static ring_buffer_pos_t get_tx_buffer_free();
- #endif
-
- static inline bool emergency_parser_enabled() { return Cfg::EMERGENCYPARSER; }
-
- FORCE_INLINE static uint8_t dropped() { return Cfg::DROPPED_RX ? rx_dropped_bytes : 0; }
- FORCE_INLINE static uint8_t buffer_overruns() { return Cfg::RX_OVERRUNS ? rx_buffer_overruns : 0; }
- FORCE_INLINE static uint8_t framing_errors() { return Cfg::RX_FRAMING_ERRORS ? rx_framing_errors : 0; }
- FORCE_INLINE static ring_buffer_pos_t rxMaxEnqueued() { return Cfg::MAX_RX_QUEUED ? rx_max_enqueued : 0; }
-
- FORCE_INLINE static void write(const char* str) { while (*str) write(*str++); }
- FORCE_INLINE static void write(const uint8_t* buffer, size_t size) { while (size--) write(*buffer++); }
- FORCE_INLINE static void print(const String& s) { for (int i = 0; i < (int)s.length(); i++) write(s[i]); }
- FORCE_INLINE static void print(const char* str) { write(str); }
-
- static void print(char, int = BYTE);
- static void print(unsigned char, int = BYTE);
- static void print(int, int = DEC);
- static void print(unsigned int, int = DEC);
- static void print(long, int = DEC);
- static void print(unsigned long, int = DEC);
- static void print(double, int = 2);
-
- static void println(const String& s);
- static void println(const char[]);
- static void println(char, int = BYTE);
- static void println(unsigned char, int = BYTE);
- static void println(int, int = DEC);
- static void println(unsigned int, int = DEC);
- static void println(long, int = DEC);
- static void println(unsigned long, int = DEC);
- static void println(double, int = 2);
- static void println();
- operator bool() { return true; }
-
- private:
- static void printNumber(unsigned long, const uint8_t);
- static void printFloat(double, uint8_t);
+ public:
+ static void begin(const long);
+ static void end();
+ static int peek();
+ static int read();
+ static void flush();
+ static ring_buffer_pos_t available();
+ static size_t write(const uint8_t c);
+ static void flushTX();
+ #if HAS_DGUS_LCD
+ static ring_buffer_pos_t get_tx_buffer_free();
+ #endif
+
+ enum { HasEmergencyParser = Cfg::EMERGENCYPARSER };
+ static inline bool emergency_parser_enabled() { return Cfg::EMERGENCYPARSER; }
+
+ FORCE_INLINE static uint8_t dropped() { return Cfg::DROPPED_RX ? rx_dropped_bytes : 0; }
+ FORCE_INLINE static uint8_t buffer_overruns() { return Cfg::RX_OVERRUNS ? rx_buffer_overruns : 0; }
+ FORCE_INLINE static uint8_t framing_errors() { return Cfg::RX_FRAMING_ERRORS ? rx_framing_errors : 0; }
+ FORCE_INLINE static ring_buffer_pos_t rxMaxEnqueued() { return Cfg::MAX_RX_QUEUED ? rx_max_enqueued : 0; }
};
template
@@ -270,12 +237,13 @@
static constexpr bool RX_FRAMING_ERRORS = ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS);
static constexpr bool MAX_RX_QUEUED = ENABLED(SERIAL_STATS_MAX_RX_QUEUED);
};
- extern MarlinSerial> customizedSerial1;
-
- #ifdef SERIAL_PORT_2
- extern MarlinSerial> customizedSerial2;
+ typedef Serial0Type< MarlinSerial< MarlinSerialCfg > > MSerialT;
+ extern MSerialT customizedSerial1;
+ #ifdef SERIAL_PORT_2
+ typedef Serial0Type< MarlinSerial< MarlinSerialCfg > > MSerialT2;
+ extern MSerialT2 customizedSerial2;
#endif
#endif // !USBCON
@@ -294,7 +262,8 @@
static constexpr bool RX_OVERRUNS = false;
};
- extern MarlinSerial> mmuSerial;
+ typedef Serial0Type< MarlinSerial< MMU2SerialCfg > > MSerialT3;
+ extern MSerialT3 mmuSerial;
#endif
#ifdef LCD_SERIAL_PORT
@@ -322,11 +291,13 @@
#endif
};
- extern MarlinSerial> lcdSerial;
+ typedef Serial0Type< MarlinSerial< LCDSerialCfg > > MSerialT4;
+ extern MSerialT4 lcdSerial;
#endif
// Use the UART for Bluetooth in AT90USB configurations
#if defined(USBCON) && ENABLED(BLUETOOTH)
- extern HardwareSerial bluetoothSerial;
+ typedef Serial0Type MSerialT5;
+ extern MSerialT5 bluetoothSerial;
#endif
diff --git a/Marlin/src/HAL/AVR/pinsDebug.h b/Marlin/src/HAL/AVR/pinsDebug.h
index dac6b1b150bd..6bf9f33a0ce5 100644
--- a/Marlin/src/HAL/AVR/pinsDebug.h
+++ b/Marlin/src/HAL/AVR/pinsDebug.h
@@ -235,8 +235,8 @@ static void print_is_also_tied() { SERIAL_ECHOPGM(" is also tied to this pin");
inline void com_print(const uint8_t N, const uint8_t Z) {
const uint8_t *TCCRA = (uint8_t*)TCCR_A(N);
- SERIAL_ECHOPGM(" COM");
- SERIAL_CHAR('0' + N, Z);
+ SERIAL_ECHOPAIR(" COM", AS_CHAR('0' + N));
+ SERIAL_CHAR(Z);
SERIAL_ECHOPAIR(": ", int((*TCCRA >> (6 - Z * 2)) & 0x03));
}
@@ -247,8 +247,8 @@ void timer_prefix(uint8_t T, char L, uint8_t N) { // T - timer L - pwm N -
uint8_t WGM = (((*TCCRB & _BV(WGM_2)) >> 1) | (*TCCRA & (_BV(WGM_0) | _BV(WGM_1))));
if (N == 4) WGM |= ((*TCCRB & _BV(WGM_3)) >> 1);
- SERIAL_ECHOPGM(" TIMER");
- SERIAL_CHAR(T + '0', L);
+ SERIAL_ECHOPAIR(" TIMER", AS_CHAR(T + '0'));
+ SERIAL_CHAR(L);
SERIAL_ECHO_SP(3);
if (N == 3) {
@@ -262,19 +262,11 @@ void timer_prefix(uint8_t T, char L, uint8_t N) { // T - timer L - pwm N -
SERIAL_ECHOPAIR(" WGM: ", WGM);
com_print(T,L);
SERIAL_ECHOPAIR(" CS: ", (*TCCRB & (_BV(CS_0) | _BV(CS_1) | _BV(CS_2)) ));
-
- SERIAL_ECHOPGM(" TCCR");
- SERIAL_CHAR(T + '0');
- SERIAL_ECHOPAIR("A: ", *TCCRA);
-
- SERIAL_ECHOPGM(" TCCR");
- SERIAL_CHAR(T + '0');
- SERIAL_ECHOPAIR("B: ", *TCCRB);
+ SERIAL_ECHOPAIR(" TCCR", AS_CHAR(T + '0'), "A: ", *TCCRA);
+ SERIAL_ECHOPAIR(" TCCR", AS_CHAR(T + '0'), "B: ", *TCCRB);
const uint8_t *TMSK = (uint8_t*)TIMSK(T);
- SERIAL_ECHOPGM(" TIMSK");
- SERIAL_CHAR(T + '0');
- SERIAL_ECHOPAIR(": ", *TMSK);
+ SERIAL_ECHOPAIR(" TIMSK", AS_CHAR(T + '0'), ": ", *TMSK);
const uint8_t OCIE = L - 'A' + 1;
if (N == 3) { if (WGM == 0 || WGM == 2 || WGM == 4 || WGM == 6) err_is_counter(); }
diff --git a/Marlin/src/HAL/DUE/HAL.cpp b/Marlin/src/HAL/DUE/HAL.cpp
index 6ce85a4643bb..2ae70843f0c7 100644
--- a/Marlin/src/HAL/DUE/HAL.cpp
+++ b/Marlin/src/HAL/DUE/HAL.cpp
@@ -102,4 +102,11 @@ uint16_t HAL_adc_get_result() {
return HAL_adc_result;
}
+// Forward the default serial port
+DefaultSerial MSerial(false, Serial);
+
+DefaultSerial1 MSerial1(false, Serial1);
+DefaultSerial2 MSerial2(false, Serial2);
+DefaultSerial3 MSerial3(false, Serial3);
+
#endif // ARDUINO_ARCH_SAM
diff --git a/Marlin/src/HAL/DUE/HAL.h b/Marlin/src/HAL/DUE/HAL.h
index 395ca4ccc971..78c8a800b9d6 100644
--- a/Marlin/src/HAL/DUE/HAL.h
+++ b/Marlin/src/HAL/DUE/HAL.h
@@ -36,9 +36,20 @@
#include
-#define _MSERIAL(X) Serial##X
+#include "../../core/serial_hook.h"
+typedef ForwardSerial0Type< decltype(Serial) > DefaultSerial;
+extern DefaultSerial MSerial;
+
+typedef ForwardSerial0Type< decltype(Serial1) > DefaultSerial1;
+typedef ForwardSerial0Type< decltype(Serial2) > DefaultSerial2;
+typedef ForwardSerial0Type< decltype(Serial3) > DefaultSerial3;
+extern DefaultSerial1 MSerial1;
+extern DefaultSerial2 MSerial2;
+extern DefaultSerial3 MSerial3;
+
+#define _MSERIAL(X) MSerial##X
#define MSERIAL(X) _MSERIAL(X)
-#define Serial0 Serial
+#define MSerial0 MSerial
// Define MYSERIAL0/1 before MarlinSerial includes!
#if SERIAL_PORT == -1 || ENABLED(EMERGENCY_PARSER)
@@ -59,6 +70,14 @@
#endif
#endif
+#ifdef MMU2_SERIAL_PORT
+ #if WITHIN(MMU2_SERIAL_PORT, 0, 3)
+ #define MMU2_SERIAL MSERIAL(MMU2_SERIAL_PORT)
+ #else
+ #error "MMU2_SERIAL_PORT must be from 0 to 3. Please update your configuration."
+ #endif
+#endif
+
#ifdef LCD_SERIAL_PORT
#if LCD_SERIAL_PORT == -1
#define LCD_SERIAL lcdSerial
@@ -75,16 +94,6 @@
// On AVR this is in math.h?
#define square(x) ((x)*(x))
-#ifndef strncpy_P
- #define strncpy_P(dest, src, num) strncpy((dest), (src), (num))
-#endif
-
-// Fix bug in pgm_read_ptr
-#undef pgm_read_ptr
-#define pgm_read_ptr(addr) (*((void**)(addr)))
-#undef pgm_read_word
-#define pgm_read_word(addr) (*((uint16_t*)(addr)))
-
typedef int8_t pin_t;
#define SHARED_SERVOS HAS_SERVOS
diff --git a/Marlin/src/HAL/DUE/HAL_SPI.cpp b/Marlin/src/HAL/DUE/HAL_SPI.cpp
index 342c37373538..6cb2912c12a4 100644
--- a/Marlin/src/HAL/DUE/HAL_SPI.cpp
+++ b/Marlin/src/HAL/DUE/HAL_SPI.cpp
@@ -240,7 +240,7 @@
}
// all the others
- static uint32_t spiDelayCyclesX4 = (F_CPU) / 1000000; // 4µs => 125khz
+ static uint32_t spiDelayCyclesX4 = 4 * (F_CPU) / 1000000; // 4µs => 125khz
static uint8_t spiTransferX(uint8_t b) { // using Mode 0
int bits = 8;
@@ -249,12 +249,12 @@
b <<= 1; // little setup time
WRITE(SD_SCK_PIN, HIGH);
- __delay_4cycles(spiDelayCyclesX4);
+ DELAY_CYCLES(spiDelayCyclesX4);
b |= (READ(SD_MISO_PIN) != 0);
WRITE(SD_SCK_PIN, LOW);
- __delay_4cycles(spiDelayCyclesX4);
+ DELAY_CYCLES(spiDelayCyclesX4);
} while (--bits);
return b;
}
@@ -510,7 +510,7 @@
spiRxBlock = (pfnSpiRxBlock)spiRxBlockX;
break;
default:
- spiDelayCyclesX4 = ((F_CPU) / 1000000) >> (6 - spiRate);
+ spiDelayCyclesX4 = ((F_CPU) / 1000000) >> (6 - spiRate) << 2; // spiRate of 2 gives the maximum error with current CPU
spiTransferTx = (pfnSpiTransfer)spiTransferX;
spiTransferRx = (pfnSpiTransfer)spiTransferX;
spiTxBlock = (pfnSpiTxBlock)spiTxBlockX;
diff --git a/Marlin/src/HAL/DUE/MarlinSerial.cpp b/Marlin/src/HAL/DUE/MarlinSerial.cpp
index c9a372eeb14f..50b84c0b1d40 100644
--- a/Marlin/src/HAL/DUE/MarlinSerial.cpp
+++ b/Marlin/src/HAL/DUE/MarlinSerial.cpp
@@ -382,7 +382,7 @@ void MarlinSerial::flush() {
}
template
-void MarlinSerial::write(const uint8_t c) {
+size_t MarlinSerial::write(const uint8_t c) {
_written = true;
if (Cfg::TX_SIZE == 0) {
@@ -400,7 +400,7 @@ void MarlinSerial::write(const uint8_t c) {
// XOFF char at the RX isr, but it is properly handled there
if (!(HWUART->UART_IMR & UART_IMR_TXRDY) && (HWUART->UART_SR & UART_SR_TXRDY)) {
HWUART->UART_THR = c;
- return;
+ return 1;
}
const uint8_t i = (tx_buffer.head + 1) & (Cfg::TX_SIZE - 1);
@@ -428,6 +428,7 @@ void MarlinSerial::write(const uint8_t c) {
// Enable TX isr - Non atomic, but it will eventually enable TX isr
HWUART->UART_IER = UART_IER_TXRDY;
}
+ return 1;
}
template
@@ -473,169 +474,16 @@ void MarlinSerial::flushTX() {
}
}
-/**
- * Imports from print.h
- */
-
-template
-void MarlinSerial::print(char c, int base) {
- print((long)c, base);
-}
-
-template
-void MarlinSerial::print(unsigned char b, int base) {
- print((unsigned long)b, base);
-}
-
-template
-void MarlinSerial::print(int n, int base) {
- print((long)n, base);
-}
-
-template
-void MarlinSerial::print(unsigned int n, int base) {
- print((unsigned long)n, base);
-}
-
-template
-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);
-}
-
-template
-void MarlinSerial::print(unsigned long n, int base) {
- if (base == 0) write(n);
- else printNumber(n, base);
-}
-
-template
-void MarlinSerial::print(double n, int digits) {
- printFloat(n, digits);
-}
-
-template
-void MarlinSerial::println() {
- print('\r');
- print('\n');
-}
-
-template
-void MarlinSerial::println(const String& s) {
- print(s);
- println();
-}
-
-template
-void MarlinSerial::println(const char c[]) {
- print(c);
- println();
-}
-
-template
-void MarlinSerial::println(char c, int base) {
- print(c, base);
- println();
-}
-
-template
-void MarlinSerial::println(unsigned char b, int base) {
- print(b, base);
- println();
-}
-
-template
-void MarlinSerial::println(int n, int base) {
- print(n, base);
- println();
-}
-
-template
-void MarlinSerial::println(unsigned int n, int base) {
- print(n, base);
- println();
-}
-
-template
-void MarlinSerial::println(long n, int base) {
- print(n, base);
- println();
-}
-
-template
-void MarlinSerial::println(unsigned long n, int base) {
- print(n, base);
- println();
-}
-
-template
-void MarlinSerial::println(double n, int digits) {
- print(n, digits);
- println();
-}
-
-// Private Methods
-template
-void MarlinSerial::printNumber(unsigned long n, uint8_t base) {
- if (n) {
- unsigned char buf[8 * sizeof(long)]; // Enough space for base 2
- int8_t i = 0;
- while (n) {
- buf[i++] = n % base;
- n /= base;
- }
- while (i--)
- print((char)(buf[i] + (buf[i] < 10 ? '0' : 'A' - 10)));
- }
- else
- print('0');
-}
-
-template
-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;
- LOOP_L_N(i, digits) 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;
- }
- }
-}
// If not using the USB port as serial port
#if SERIAL_PORT >= 0
- template class MarlinSerial>; // Define
- MarlinSerial> customizedSerial1; // Instantiate
+ template class MarlinSerial< MarlinSerialCfg >;
+ MSerialT customizedSerial1(MarlinSerialCfg::EMERGENCYPARSER);
#endif
#if defined(SERIAL_PORT_2) && SERIAL_PORT_2 >= 0
- template class MarlinSerial>; // Define
- MarlinSerial> customizedSerial2; // Instantiate
+ template class MarlinSerial< MarlinSerialCfg >;
+ MSerialT2 customizedSerial2(MarlinSerialCfg::EMERGENCYPARSER);
#endif
#endif // ARDUINO_ARCH_SAM
diff --git a/Marlin/src/HAL/DUE/MarlinSerial.h b/Marlin/src/HAL/DUE/MarlinSerial.h
index a194eba2f386..7fc21264bba9 100644
--- a/Marlin/src/HAL/DUE/MarlinSerial.h
+++ b/Marlin/src/HAL/DUE/MarlinSerial.h
@@ -30,11 +30,7 @@
#include
#include "../../inc/MarlinConfigPre.h"
-
-#define DEC 10
-#define HEX 16
-#define OCT 8
-#define BIN 2
+#include "../../core/serial_hook.h"
// 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
@@ -119,7 +115,7 @@ class MarlinSerial {
static int read();
static void flush();
static ring_buffer_pos_t available();
- static void write(const uint8_t c);
+ static size_t write(const uint8_t c);
static void flushTX();
static inline bool emergency_parser_enabled() { return Cfg::EMERGENCYPARSER; }
@@ -128,35 +124,6 @@ class MarlinSerial {
FORCE_INLINE static uint8_t buffer_overruns() { return Cfg::RX_OVERRUNS ? rx_buffer_overruns : 0; }
FORCE_INLINE static uint8_t framing_errors() { return Cfg::RX_FRAMING_ERRORS ? rx_framing_errors : 0; }
FORCE_INLINE static ring_buffer_pos_t rxMaxEnqueued() { return Cfg::MAX_RX_QUEUED ? rx_max_enqueued : 0; }
-
- FORCE_INLINE static void write(const char* str) { while (*str) write(*str++); }
- FORCE_INLINE static void write(const uint8_t* buffer, size_t size) { while (size--) write(*buffer++); }
- FORCE_INLINE static void print(const String& s) { for (int i = 0; i < (int)s.length(); i++) write(s[i]); }
- FORCE_INLINE static void print(const char* str) { write(str); }
-
- static void print(char, int = 0);
- static void print(unsigned char, int = 0);
- static void print(int, int = DEC);
- static void print(unsigned int, int = DEC);
- static void print(long, int = DEC);
- static void print(unsigned long, int = DEC);
- static void print(double, int = 2);
-
- static void println(const String& s);
- static void println(const char[]);
- static void println(char, int = 0);
- static void println(unsigned char, int = 0);
- 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();
- operator bool() { return true; }
-
-private:
- static void printNumber(unsigned long, const uint8_t);
- static void printFloat(double, uint8_t);
};
// Serial port configuration
@@ -174,9 +141,11 @@ struct MarlinSerialCfg {
};
#if SERIAL_PORT >= 0
- extern MarlinSerial> customizedSerial1;
+ typedef Serial0Type< MarlinSerial< MarlinSerialCfg > > MSerialT;
+ extern MSerialT customizedSerial1;
#endif
#if defined(SERIAL_PORT_2) && SERIAL_PORT_2 >= 0
- extern MarlinSerial> customizedSerial2;
+ typedef Serial0Type< MarlinSerial< MarlinSerialCfg > > MSerialT2;
+ extern MSerialT2 customizedSerial2;
#endif
diff --git a/Marlin/src/HAL/DUE/MarlinSerialUSB.cpp b/Marlin/src/HAL/DUE/MarlinSerialUSB.cpp
index a41dbfeb7a57..a04993ca35ed 100644
--- a/Marlin/src/HAL/DUE/MarlinSerialUSB.cpp
+++ b/Marlin/src/HAL/DUE/MarlinSerialUSB.cpp
@@ -33,10 +33,6 @@
#include "MarlinSerialUSB.h"
-#if ENABLED(EMERGENCY_PARSER)
- #include "../../feature/e_parser.h"
-#endif
-
// Imports from Atmel USB Stack/CDC implementation
extern "C" {
bool usb_task_cdc_isenabled();
@@ -50,10 +46,6 @@ extern "C" {
// Pending character
static int pending_char = -1;
-#if ENABLED(EMERGENCY_PARSER)
- static EmergencyParser::State emergency_state; // = EP_RESET
-#endif
-
// Public Methods
void MarlinSerialUSB::begin(const long) {}
@@ -73,7 +65,7 @@ int MarlinSerialUSB::peek() {
pending_char = udi_cdc_getc();
- TERN_(EMERGENCY_PARSER, emergency_parser.update(emergency_state, (char)pending_char));
+ TERN_(EMERGENCY_PARSER, emergency_parser.update(static_cast(this)->emergency_state, (char)pending_char));
return pending_char;
}
@@ -95,7 +87,7 @@ int MarlinSerialUSB::read() {
int c = udi_cdc_getc();
- TERN_(EMERGENCY_PARSER, emergency_parser.update(emergency_state, (char)c));
+ TERN_(EMERGENCY_PARSER, emergency_parser.update(static_cast(this)->emergency_state, (char)c));
return c;
}
@@ -109,15 +101,14 @@ bool MarlinSerialUSB::available() {
}
void MarlinSerialUSB::flush() { }
-void MarlinSerialUSB::flushTX() { }
-void MarlinSerialUSB::write(const uint8_t c) {
+size_t MarlinSerialUSB::write(const uint8_t c) {
/* Do not even bother sending anything if USB CDC is not enumerated
or not configured on the PC side or there is no program on the PC
listening to our messages */
if (!usb_task_cdc_isenabled() || !usb_task_cdc_dtr_active())
- return;
+ return 0;
/* Wait until the PC has read the pending to be sent data */
while (usb_task_cdc_isenabled() &&
@@ -129,161 +120,20 @@ void MarlinSerialUSB::write(const uint8_t c) {
or not configured on the PC side or there is no program on the PC
listening to our messages at this point */
if (!usb_task_cdc_isenabled() || !usb_task_cdc_dtr_active())
- return;
+ return 0;
// Fifo full
// udi_cdc_signal_overrun();
udi_cdc_putc(c);
-}
-
-/**
- * Imports from print.h
- */
-
-void MarlinSerialUSB::print(char c, int base) {
- print((long)c, base);
-}
-
-void MarlinSerialUSB::print(unsigned char b, int base) {
- print((unsigned long)b, base);
-}
-
-void MarlinSerialUSB::print(int n, int base) {
- print((long)n, base);
-}
-
-void MarlinSerialUSB::print(unsigned int n, int base) {
- print((unsigned long)n, base);
-}
-
-void MarlinSerialUSB::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 MarlinSerialUSB::print(unsigned long n, int base) {
- if (base == 0) write(n);
- else printNumber(n, base);
-}
-
-void MarlinSerialUSB::print(double n, int digits) {
- printFloat(n, digits);
-}
-
-void MarlinSerialUSB::println() {
- print('\r');
- print('\n');
-}
-
-void MarlinSerialUSB::println(const String& s) {
- print(s);
- println();
-}
-
-void MarlinSerialUSB::println(const char c[]) {
- print(c);
- println();
-}
-
-void MarlinSerialUSB::println(char c, int base) {
- print(c, base);
- println();
-}
-
-void MarlinSerialUSB::println(unsigned char b, int base) {
- print(b, base);
- println();
-}
-
-void MarlinSerialUSB::println(int n, int base) {
- print(n, base);
- println();
-}
-
-void MarlinSerialUSB::println(unsigned int n, int base) {
- print(n, base);
- println();
-}
-
-void MarlinSerialUSB::println(long n, int base) {
- print(n, base);
- println();
-}
-
-void MarlinSerialUSB::println(unsigned long n, int base) {
- print(n, base);
- println();
-}
-
-void MarlinSerialUSB::println(double n, int digits) {
- print(n, digits);
- println();
-}
-
-// Private Methods
-
-void MarlinSerialUSB::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 MarlinSerialUSB::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;
- LOOP_L_N(i, digits)
- 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;
- }
- }
+ return 1;
}
// Preinstantiate
#if SERIAL_PORT == -1
- MarlinSerialUSB customizedSerial1;
+ MSerialT customizedSerial1(TERN0(EMERGENCY_PARSER, true));
#endif
#if SERIAL_PORT_2 == -1
- MarlinSerialUSB customizedSerial2;
+ MSerialT customizedSerial2(TERN0(EMERGENCY_PARSER, true));
#endif
#endif // HAS_USB_SERIAL
diff --git a/Marlin/src/HAL/DUE/MarlinSerialUSB.h b/Marlin/src/HAL/DUE/MarlinSerialUSB.h
index 2e3622e5534a..5281a006b155 100644
--- a/Marlin/src/HAL/DUE/MarlinSerialUSB.h
+++ b/Marlin/src/HAL/DUE/MarlinSerialUSB.h
@@ -27,73 +27,37 @@
*/
#include "../../inc/MarlinConfig.h"
-
#if HAS_USB_SERIAL
#include
+#include "../../core/serial_hook.h"
-#define DEC 10
-#define HEX 16
-#define OCT 8
-#define BIN 2
-
-class MarlinSerialUSB {
-public:
- MarlinSerialUSB() {};
- static void begin(const long);
- static void end();
- static int peek();
- static int read();
- static void flush();
- static void flushTX();
- static bool available();
- static void write(const uint8_t c);
+struct MarlinSerialUSB {
+ void begin(const long);
+ void end();
+ int peek();
+ int read();
+ void flush();
+ bool available();
+ size_t write(const uint8_t c);
#if ENABLED(SERIAL_STATS_DROPPED_RX)
- FORCE_INLINE static uint32_t dropped() { return 0; }
+ FORCE_INLINE uint32_t dropped() { return 0; }
#endif
#if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
- FORCE_INLINE static int rxMaxEnqueued() { return 0; }
+ FORCE_INLINE int rxMaxEnqueued() { return 0; }
#endif
-
- FORCE_INLINE static void write(const char* str) { while (*str) write(*str++); }
- FORCE_INLINE static void write(const uint8_t* buffer, size_t size) { while (size--) write(*buffer++); }
- FORCE_INLINE static void print(const String& s) { for (int i = 0; i < (int)s.length(); i++) write(s[i]); }
- FORCE_INLINE static void print(const char* str) { write(str); }
-
- static void print(char, int = 0);
- static void print(unsigned char, int = 0);
- static void print(int, int = DEC);
- static void print(unsigned int, int = DEC);
- static void print(long, int = DEC);
- static void print(unsigned long, int = DEC);
- static void print(double, int = 2);
-
- static void println(const String& s);
- static void println(const char[]);
- static void println(char, int = 0);
- static void println(unsigned char, int = 0);
- 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();
- operator bool() { return true; }
-
-private:
- static void printNumber(unsigned long, const uint8_t);
- static void printFloat(double, uint8_t);
};
+typedef Serial0Type MSerialT;
#if SERIAL_PORT == -1
- extern MarlinSerialUSB customizedSerial1;
+ extern MSerialT customizedSerial1;
#endif
#if SERIAL_PORT_2 == -1
- extern MarlinSerialUSB customizedSerial2;
+ extern MSerialT customizedSerial2;
#endif
#endif // HAS_USB_SERIAL
diff --git a/Marlin/src/HAL/DUE/dogm/u8g_com_HAL_DUE_st7920_sw_spi.cpp b/Marlin/src/HAL/DUE/dogm/u8g_com_HAL_DUE_st7920_sw_spi.cpp
index 7df180cbaa82..d01cd4dd6b27 100644
--- a/Marlin/src/HAL/DUE/dogm/u8g_com_HAL_DUE_st7920_sw_spi.cpp
+++ b/Marlin/src/HAL/DUE/dogm/u8g_com_HAL_DUE_st7920_sw_spi.cpp
@@ -59,6 +59,7 @@
#if ENABLED(U8GLIB_ST7920)
+#include "../../../inc/MarlinConfig.h"
#include "../../shared/Delay.h"
#include
diff --git a/Marlin/src/HAL/DUE/dogm/u8g_com_HAL_DUE_sw_spi_shared.cpp b/Marlin/src/HAL/DUE/dogm/u8g_com_HAL_DUE_sw_spi_shared.cpp
index 615a386c3542..4fb7a6e2c315 100644
--- a/Marlin/src/HAL/DUE/dogm/u8g_com_HAL_DUE_sw_spi_shared.cpp
+++ b/Marlin/src/HAL/DUE/dogm/u8g_com_HAL_DUE_sw_spi_shared.cpp
@@ -59,6 +59,7 @@
#if HAS_MARLINUI_U8GLIB
+#include "../../../inc/MarlinConfig.h"
#include "../../shared/Delay.h"
#include
diff --git a/Marlin/src/HAL/DUE/fastio.h b/Marlin/src/HAL/DUE/fastio.h
index 5fb8b4d01533..f375cb6b2977 100644
--- a/Marlin/src/HAL/DUE/fastio.h
+++ b/Marlin/src/HAL/DUE/fastio.h
@@ -50,7 +50,7 @@
#define PWM_PIN(P) WITHIN(P, 2, 13)
#ifndef MASK
- #define MASK(PIN) (1 << PIN)
+ #define MASK(PIN) _BV(PIN)
#endif
/**
diff --git a/Marlin/src/HAL/DUE/timers.cpp b/Marlin/src/HAL/DUE/timers.cpp
index 9b937d1a7c83..65073c510d7c 100644
--- a/Marlin/src/HAL/DUE/timers.cpp
+++ b/Marlin/src/HAL/DUE/timers.cpp
@@ -121,7 +121,7 @@ void HAL_timer_disable_interrupt(const uint8_t timer_num) {
// missing from CMSIS: Check if interrupt is enabled or not
static bool NVIC_GetEnabledIRQ(IRQn_Type IRQn) {
- return (NVIC->ISER[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F))) != 0;
+ return TEST(NVIC->ISER[uint32_t(IRQn) >> 5], uint32_t(IRQn) & 0x1F);
}
bool HAL_timer_interrupt_enabled(const uint8_t timer_num) {
diff --git a/Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.cpp b/Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.cpp
index db5e82ec5502..d92d332c1efd 100644
--- a/Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.cpp
+++ b/Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.cpp
@@ -68,7 +68,7 @@ Ctrl_status sd_mmc_spi_usb_read_10(uint32_t addr, uint16_t nb_sector) {
{
char buffer[80];
sprintf_P(buffer, PSTR("SDRD: %d @ 0x%08x\n"), nb_sector, addr);
- PORT_REDIRECT(0);
+ PORT_REDIRECT(SERIAL_PORTMASK(0));
SERIAL_ECHO(buffer);
}
#endif
@@ -108,7 +108,7 @@ Ctrl_status sd_mmc_spi_usb_write_10(uint32_t addr, uint16_t nb_sector) {
{
char buffer[80];
sprintf_P(buffer, PSTR("SDWR: %d @ 0x%08x\n"), nb_sector, addr);
- PORT_REDIRECT(0);
+ PORT_REDIRECT(SERIAL_PORTMASK(0));
SERIAL_ECHO(buffer);
}
#endif
diff --git a/Marlin/src/HAL/ESP32/FlushableHardwareSerial.cpp b/Marlin/src/HAL/ESP32/FlushableHardwareSerial.cpp
index d4b2f42c5351..cc5a4fc476c4 100644
--- a/Marlin/src/HAL/ESP32/FlushableHardwareSerial.cpp
+++ b/Marlin/src/HAL/ESP32/FlushableHardwareSerial.cpp
@@ -24,10 +24,7 @@
#ifdef ARDUINO_ARCH_ESP32
-FlushableHardwareSerial::FlushableHardwareSerial(int uart_nr)
- : HardwareSerial(uart_nr)
-{}
-FlushableHardwareSerial flushableSerial(0);
+Serial0Type flushableSerial(false, 0);
#endif // ARDUINO_ARCH_ESP32
diff --git a/Marlin/src/HAL/ESP32/FlushableHardwareSerial.h b/Marlin/src/HAL/ESP32/FlushableHardwareSerial.h
index b43caea13c1d..27df0be4b63b 100644
--- a/Marlin/src/HAL/ESP32/FlushableHardwareSerial.h
+++ b/Marlin/src/HAL/ESP32/FlushableHardwareSerial.h
@@ -24,14 +24,13 @@
#ifdef ARDUINO_ARCH_ESP32
#include
+#include "../../core/serial_hook.h"
class FlushableHardwareSerial : public HardwareSerial {
public:
- FlushableHardwareSerial(int uart_nr);
-
- inline void flushTX() { /* No need to flush the hardware serial, but defined here for compatibility. */ }
+ FlushableHardwareSerial(int uart_nr) : HardwareSerial(uart_nr) {}
};
-extern FlushableHardwareSerial flushableSerial;
+extern Serial0Type flushableSerial;
#endif // ARDUINO_ARCH_ESP32
diff --git a/Marlin/src/HAL/ESP32/HAL.cpp b/Marlin/src/HAL/ESP32/HAL.cpp
index ead448d78d7a..fb5f531b22aa 100644
--- a/Marlin/src/HAL/ESP32/HAL.cpp
+++ b/Marlin/src/HAL/ESP32/HAL.cpp
@@ -40,6 +40,10 @@
#endif
#endif
+#if ENABLED(ESP3D_WIFISUPPORT)
+ DefaultSerial MSerial(false, Serial2Socket);
+#endif
+
// ------------------------
// Externs
// ------------------------
@@ -86,8 +90,6 @@ volatile int numPWMUsed = 0,
#endif
-void HAL_init() { TERN_(I2S_STEPPER_STREAM, i2s_init()); }
-
void HAL_init_board() {
#if ENABLED(ESP3D_WIFISUPPORT)
@@ -122,6 +124,10 @@ void HAL_init_board() {
#endif
#endif
+ // Initialize the i2s peripheral only if the I2S stepper stream is enabled.
+ // The following initialization is performed after Serial1 and Serial2 are defined as
+ // their native pins might conflict with the i2s stream even when they are remapped.
+ TERN_(I2S_STEPPER_STREAM, i2s_init());
}
void HAL_idletask() {
diff --git a/Marlin/src/HAL/ESP32/HAL.h b/Marlin/src/HAL/ESP32/HAL.h
index 5ef13e0c21d4..4d1db571d04a 100644
--- a/Marlin/src/HAL/ESP32/HAL.h
+++ b/Marlin/src/HAL/ESP32/HAL.h
@@ -55,7 +55,9 @@ extern portMUX_TYPE spinlock;
#if EITHER(WIFISUPPORT, ESP3D_WIFISUPPORT)
#if ENABLED(ESP3D_WIFISUPPORT)
- #define MYSERIAL1 Serial2Socket
+ typedef ForwardSerial0Type< decltype(Serial2Socket) > DefaultSerial;
+ extern DefaultSerial MSerial;
+ #define MYSERIAL1 MSerial
#else
#define MYSERIAL1 webSocketSerial
#endif
@@ -67,10 +69,6 @@ extern portMUX_TYPE spinlock;
#define ENABLE_ISRS() if (spinlock.owner != portMUX_FREE_VAL) portEXIT_CRITICAL(&spinlock)
#define DISABLE_ISRS() portENTER_CRITICAL(&spinlock)
-// Fix bug in pgm_read_ptr
-#undef pgm_read_ptr
-#define pgm_read_ptr(addr) (*(addr))
-
// ------------------------
// Types
// ------------------------
@@ -90,6 +88,13 @@ extern uint16_t HAL_adc_result;
// Public functions
// ------------------------
+//
+// Tone
+//
+void toneInit();
+void tone(const pin_t _pin, const unsigned int frequency, const unsigned long duration=0);
+void noTone(const pin_t _pin);
+
// clear reset reason
void HAL_clear_reset_source();
@@ -134,7 +139,7 @@ void HAL_adc_start_conversion(const uint8_t adc_pin);
#define HAL_IDLETASK 1
#define BOARD_INIT() HAL_init_board();
void HAL_idletask();
-void HAL_init();
+inline void HAL_init() {}
void HAL_init_board();
//
diff --git a/Marlin/src/HAL/ESP32/Servo.h b/Marlin/src/HAL/ESP32/Servo.h
index b0d929452732..8542092d66ea 100644
--- a/Marlin/src/HAL/ESP32/Servo.h
+++ b/Marlin/src/HAL/ESP32/Servo.h
@@ -30,7 +30,7 @@ class Servo {
MAX_PULSE_WIDTH = 2400, // Longest pulse sent to a servo
TAU_MSEC = 20,
TAU_USEC = (TAU_MSEC * 1000),
- MAX_COMPARE = ((1 << 16) - 1), // 65535
+ MAX_COMPARE = _BV(16) - 1, // 65535
CHANNEL_MAX_NUM = 16;
public:
diff --git a/Marlin/src/HAL/ESP32/Tone.cpp b/Marlin/src/HAL/ESP32/Tone.cpp
new file mode 100644
index 000000000000..376c0f32e129
--- /dev/null
+++ b/Marlin/src/HAL/ESP32/Tone.cpp
@@ -0,0 +1,59 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * Copypaste of SAMD51 HAL developed by Giuliano Zaro (AKA GMagician)
+ *
+ * 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 .
+ *
+ */
+
+/**
+ * Description: Tone function for ESP32
+ * Derived from https://forum.arduino.cc/index.php?topic=136500.msg2903012#msg2903012
+ */
+
+#ifdef ARDUINO_ARCH_ESP32
+
+#include "../../inc/MarlinConfig.h"
+#include "HAL.h"
+
+static pin_t tone_pin;
+volatile static int32_t toggles;
+
+void tone(const pin_t _pin, const unsigned int frequency, const unsigned long duration) {
+ tone_pin = _pin;
+ toggles = 2 * frequency * duration / 1000;
+ HAL_timer_start(TONE_TIMER_NUM, 2 * frequency);
+}
+
+void noTone(const pin_t _pin) {
+ HAL_timer_disable_interrupt(TONE_TIMER_NUM);
+ WRITE(_pin, LOW);
+}
+
+HAL_TONE_TIMER_ISR() {
+ HAL_timer_isr_prologue(TONE_TIMER_NUM);
+
+ if (toggles) {
+ toggles--;
+ TOGGLE(tone_pin);
+ }
+ else noTone(tone_pin); // turn off interrupt
+}
+
+#endif // ARDUINO_ARCH_ESP32
diff --git a/Marlin/src/HAL/ESP32/WebSocketSerial.cpp b/Marlin/src/HAL/ESP32/WebSocketSerial.cpp
index ca7f47a1f8bd..8825742d38fa 100644
--- a/Marlin/src/HAL/ESP32/WebSocketSerial.cpp
+++ b/Marlin/src/HAL/ESP32/WebSocketSerial.cpp
@@ -29,7 +29,7 @@
#include "wifi.h"
#include
-WebSocketSerial webSocketSerial;
+MSerialT webSocketSerial(false);
AsyncWebSocket ws("/ws"); // TODO Move inside the class.
// RingBuffer impl
@@ -144,9 +144,5 @@ size_t WebSocketSerial::write(const uint8_t* buffer, size_t size) {
return written;
}
-void WebSocketSerial::flushTX() {
- // No need to do anything as there's no benefit to sending partial lines over the websocket connection.
-}
-
#endif // WIFISUPPORT
#endif // ARDUINO_ARCH_ESP32
diff --git a/Marlin/src/HAL/ESP32/WebSocketSerial.h b/Marlin/src/HAL/ESP32/WebSocketSerial.h
index 7a25c6dc5e9c..c68792c8c15d 100644
--- a/Marlin/src/HAL/ESP32/WebSocketSerial.h
+++ b/Marlin/src/HAL/ESP32/WebSocketSerial.h
@@ -22,6 +22,7 @@
#pragma once
#include "../../inc/MarlinConfig.h"
+#include "../../core/serial_hook.h"
#include
@@ -68,12 +69,9 @@ class WebSocketSerial: public Stream {
int peek();
int read();
void flush();
- void flushTX();
size_t write(const uint8_t c);
size_t write(const uint8_t* buffer, size_t size);
- operator bool() { return true; }
-
#if ENABLED(SERIAL_STATS_DROPPED_RX)
FORCE_INLINE uint32_t dropped() { return 0; }
#endif
@@ -83,4 +81,5 @@ class WebSocketSerial: public Stream {
#endif
};
-extern WebSocketSerial webSocketSerial;
+typedef Serial0Type MSerialT;
+extern MSerialT webSocketSerial;
diff --git a/Marlin/src/HAL/ESP32/timers.cpp b/Marlin/src/HAL/ESP32/timers.cpp
index 3300aea8a89c..57662a665882 100644
--- a/Marlin/src/HAL/ESP32/timers.cpp
+++ b/Marlin/src/HAL/ESP32/timers.cpp
@@ -45,7 +45,7 @@ const tTimerConfig TimerConfig [NUM_HARDWARE_TIMERS] = {
{ TIMER_GROUP_0, TIMER_0, STEPPER_TIMER_PRESCALE, stepTC_Handler }, // 0 - Stepper
{ TIMER_GROUP_0, TIMER_1, TEMP_TIMER_PRESCALE, tempTC_Handler }, // 1 - Temperature
{ TIMER_GROUP_1, TIMER_0, PWM_TIMER_PRESCALE, pwmTC_Handler }, // 2 - PWM
- { TIMER_GROUP_1, TIMER_1, 1, nullptr }, // 3
+ { TIMER_GROUP_1, TIMER_1, TONE_TIMER_PRESCALE, toneTC_Handler }, // 3 - Tone
};
// ------------------------
diff --git a/Marlin/src/HAL/ESP32/timers.h b/Marlin/src/HAL/ESP32/timers.h
index 98386e3980b9..a47697113d5d 100644
--- a/Marlin/src/HAL/ESP32/timers.h
+++ b/Marlin/src/HAL/ESP32/timers.h
@@ -44,6 +44,9 @@ typedef uint64_t hal_timer_t;
#ifndef PWM_TIMER_NUM
#define PWM_TIMER_NUM 2 // index of timer to use for PWM outputs
#endif
+#ifndef TONE_TIMER_NUM
+ #define TONE_TIMER_NUM 3 // index of timer for beeper tones
+#endif
#define HAL_TIMER_RATE APB_CLK_FREQ // frequency of timer peripherals
@@ -59,6 +62,8 @@ typedef uint64_t hal_timer_t;
#define STEP_TIMER_MIN_INTERVAL 8 // minimum time in µs between stepper interrupts
+#define TONE_TIMER_PRESCALE 1000 // Arbitrary value, no idea what i'm doing here
+
#define TEMP_TIMER_PRESCALE 1000 // prescaler for setting Temp timer, 72Khz
#define TEMP_TIMER_FREQUENCY 1000 // temperature interrupt frequency
@@ -90,11 +95,15 @@ typedef uint64_t hal_timer_t;
#ifndef HAL_PWM_TIMER_ISR
#define HAL_PWM_TIMER_ISR() extern "C" void pwmTC_Handler()
#endif
+#ifndef HAL_TONE_TIMER_ISR
+ #define HAL_TONE_TIMER_ISR() extern "C" void toneTC_Handler()
+#endif
extern "C" {
void tempTC_Handler();
void stepTC_Handler();
void pwmTC_Handler();
+ void toneTC_Handler();
}
// ------------------------
diff --git a/Marlin/src/HAL/LINUX/HAL.cpp b/Marlin/src/HAL/LINUX/HAL.cpp
index ee9e31e140e8..771f1d2a087f 100644
--- a/Marlin/src/HAL/LINUX/HAL.cpp
+++ b/Marlin/src/HAL/LINUX/HAL.cpp
@@ -24,7 +24,7 @@
#include "../../inc/MarlinConfig.h"
#include "../shared/Delay.h"
-HalSerial usb_serial;
+MSerialT usb_serial(TERN0(EMERGENCY_PARSER, true));
// U8glib required functions
extern "C" {
diff --git a/Marlin/src/HAL/LINUX/HAL.h b/Marlin/src/HAL/LINUX/HAL.h
index 729f6c856e19..e4f4dd3fc36a 100644
--- a/Marlin/src/HAL/LINUX/HAL.h
+++ b/Marlin/src/HAL/LINUX/HAL.h
@@ -60,7 +60,7 @@ uint8_t _getc();
#define SHARED_SERVOS HAS_SERVOS
-extern HalSerial usb_serial;
+extern MSerialT usb_serial;
#define MYSERIAL0 usb_serial
#define ST7920_DELAY_1 DELAY_NS(600)
@@ -113,8 +113,3 @@ inline void HAL_reboot() {} // reboot the board or restart the bootloader
FORCE_INLINE static void DELAY_CYCLES(uint64_t x) {
Clock::delayCycles(x);
}
-
-// Add strcmp_P if missing
-#ifndef strcmp_P
- #define strcmp_P(a, b) strcmp((a), (b))
-#endif
diff --git a/Marlin/src/HAL/LINUX/include/Arduino.h b/Marlin/src/HAL/LINUX/include/Arduino.h
index 6aeb0db58335..d4086e259a2f 100644
--- a/Marlin/src/HAL/LINUX/include/Arduino.h
+++ b/Marlin/src/HAL/LINUX/include/Arduino.h
@@ -73,27 +73,6 @@ extern "C" {
void GpioDisableInt(uint32_t port, uint32_t pin);
}
-// Program Memory
-#define pgm_read_ptr(addr) (*((void**)(addr)))
-#define pgm_read_byte_near(addr) (*((uint8_t*)(addr)))
-#define pgm_read_float_near(addr) (*((float*)(addr)))
-#define pgm_read_word_near(addr) (*((uint16_t*)(addr)))
-#define pgm_read_dword_near(addr) (*((uint32_t*)(addr)))
-#define pgm_read_byte(addr) pgm_read_byte_near(addr)
-#define pgm_read_float(addr) pgm_read_float_near(addr)
-#define pgm_read_word(addr) pgm_read_word_near(addr)
-#define pgm_read_dword(addr) pgm_read_dword_near(addr)
-
-using std::memcpy;
-#define memcpy_P memcpy
-#define sprintf_P sprintf
-#define strstr_P strstr
-#define strncpy_P strncpy
-#define vsnprintf_P vsnprintf
-#define strcpy_P strcpy
-#define snprintf_P snprintf
-#define strlen_P strlen
-
// Time functions
extern "C" void delay(const int milis);
void _delay_ms(const int delay);
diff --git a/Marlin/src/HAL/LINUX/include/serial.h b/Marlin/src/HAL/LINUX/include/serial.h
index e91624938978..2585be25bf01 100644
--- a/Marlin/src/HAL/LINUX/include/serial.h
+++ b/Marlin/src/HAL/LINUX/include/serial.h
@@ -25,6 +25,7 @@
#if ENABLED(EMERGENCY_PARSER)
#include "../../../feature/e_parser.h"
#endif
+#include "../../../core/serial_hook.h"
#include
#include
@@ -73,19 +74,11 @@ template class RingBuffer {
volatile uint32_t index_read;
};
-class HalSerial {
-public:
-
- #if ENABLED(EMERGENCY_PARSER)
- EmergencyParser::State emergency_state;
- static inline bool emergency_parser_enabled() { return true; }
- #endif
-
+struct HalSerial {
HalSerial() { host_connected = true; }
void begin(int32_t) {}
-
- void end() {}
+ void end() {}
int peek() {
uint8_t value;
@@ -100,7 +93,7 @@ class HalSerial {
return transmit_buffer.write(c);
}
- operator bool() { return host_connected; }
+ bool connected() { return host_connected; }
uint16_t available() {
return (uint16_t)receive_buffer.available();
@@ -117,92 +110,9 @@ class HalSerial {
while (transmit_buffer.available()) { /* nada */ }
}
- void printf(const char *format, ...) {
- static char buffer[256];
- va_list vArgs;
- va_start(vArgs, format);
- int length = vsnprintf((char *) buffer, 256, (char const *) format, vArgs);
- va_end(vArgs);
- if (length > 0 && length < 256) {
- if (host_connected) {
- for (int i = 0; i < length;) {
- if (transmit_buffer.write(buffer[i])) {
- ++i;
- }
- }
- }
- }
- }
-
- #define DEC 10
- #define HEX 16
- #define OCT 8
- #define BIN 2
-
- void print_bin(uint32_t value, uint8_t num_digits) {
- uint32_t mask = 1 << (num_digits -1);
- for (uint8_t i = 0; i < num_digits; i++) {
- if (!(i % 4) && i) write(' ');
- if (!(i % 16) && i) write(' ');
- if (value & mask) write('1');
- else write('0');
- value <<= 1;
- }
- }
-
- void print(const char value[]) { printf("%s" , value); }
- void print(char value, int nbase = 0) {
- if (nbase == BIN) print_bin(value, 8);
- else if (nbase == OCT) printf("%3o", value);
- else if (nbase == HEX) printf("%2X", value);
- else if (nbase == DEC ) printf("%d", value);
- else printf("%c" , value);
- }
- void print(unsigned char value, int nbase = 0) {
- if (nbase == BIN) print_bin(value, 8);
- else if (nbase == OCT) printf("%3o", value);
- else if (nbase == HEX) printf("%2X", value);
- else printf("%u" , value);
- }
- void print(int value, int nbase = 0) {
- if (nbase == BIN) print_bin(value, 16);
- else if (nbase == OCT) printf("%6o", value);
- else if (nbase == HEX) printf("%4X", value);
- else printf("%d", value);
- }
- void print(unsigned int value, int nbase = 0) {
- if (nbase == BIN) print_bin(value, 16);
- else if (nbase == OCT) printf("%6o", value);
- else if (nbase == HEX) printf("%4X", value);
- else printf("%u" , value);
- }
- void print(long value, int nbase = 0) {
- if (nbase == BIN) print_bin(value, 32);
- else if (nbase == OCT) printf("%11o", value);
- else if (nbase == HEX) printf("%8X", value);
- else printf("%ld" , value);
- }
- void print(unsigned long value, int nbase = 0) {
- if (nbase == BIN) print_bin(value, 32);
- else if (nbase == OCT) printf("%11o", value);
- else if (nbase == HEX) printf("%8X", value);
- else printf("%lu" , value);
- }
- void print(float value, int round = 6) { printf("%f" , value); }
- void print(double value, int round = 6) { printf("%f" , value); }
-
- void println(const char value[]) { printf("%s\n" , value); }
- void println(char value, int nbase = 0) { print(value, nbase); println(); }
- void println(unsigned char value, int nbase = 0) { print(value, nbase); println(); }
- void println(int value, int nbase = 0) { print(value, nbase); println(); }
- void println(unsigned int value, int nbase = 0) { print(value, nbase); println(); }
- void println(long value, int nbase = 0) { print(value, nbase); println(); }
- void println(unsigned long value, int nbase = 0) { print(value, nbase); println(); }
- void println(float value, int round = 6) { printf("%f\n" , value); }
- void println(double value, int round = 6) { printf("%f\n" , value); }
- void println() { print('\n'); }
-
volatile RingBuffer receive_buffer;
volatile RingBuffer transmit_buffer;
volatile bool host_connected;
};
+
+typedef Serial0Type MSerialT;
diff --git a/Marlin/src/HAL/LINUX/main.cpp b/Marlin/src/HAL/LINUX/main.cpp
index eadc409324c9..c409a83e5d55 100644
--- a/Marlin/src/HAL/LINUX/main.cpp
+++ b/Marlin/src/HAL/LINUX/main.cpp
@@ -1,6 +1,5 @@
/**
* Marlin 3D Printer Firmware
- *
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* This program is free software: you can redistribute it and/or modify
diff --git a/Marlin/src/HAL/LPC1768/HAL.cpp b/Marlin/src/HAL/LPC1768/HAL.cpp
index 3614e953851c..26a2c0e7db59 100644
--- a/Marlin/src/HAL/LPC1768/HAL.cpp
+++ b/Marlin/src/HAL/LPC1768/HAL.cpp
@@ -29,6 +29,8 @@
#include "watchdog.h"
#endif
+DefaultSerial USBSerial(false, UsbSerial);
+
uint32_t HAL_adc_reading = 0;
// U8glib required functions
@@ -61,7 +63,12 @@ int16_t PARSED_PIN_INDEX(const char code, const int16_t dval) {
return ind > -1 ? ind : dval;
}
-void flashFirmware(const int16_t) { NVIC_SystemReset(); }
+void flashFirmware(const int16_t) {
+ delay(500); // Give OS time to disconnect
+ USB_Connect(false); // USB clear connection
+ delay(1000); // Give OS time to notice
+ NVIC_SystemReset();
+}
void HAL_clear_reset_source(void) {
TERN_(USE_WATCHDOG, watchdog_clear_timeout_flag());
diff --git a/Marlin/src/HAL/LPC1768/HAL.h b/Marlin/src/HAL/LPC1768/HAL.h
index f2347bf5a7fe..1dc4fe6ff9c3 100644
--- a/Marlin/src/HAL/LPC1768/HAL.h
+++ b/Marlin/src/HAL/LPC1768/HAL.h
@@ -60,12 +60,15 @@ extern "C" volatile uint32_t _millis;
#define ST7920_DELAY_3 DELAY_NS(750)
#endif
+typedef ForwardSerial0Type< decltype(UsbSerial) > DefaultSerial;
+extern DefaultSerial USBSerial;
+
#define _MSERIAL(X) MSerial##X
#define MSERIAL(X) _MSERIAL(X)
#define MSerial0 MSerial
#if SERIAL_PORT == -1
- #define MYSERIAL0 UsbSerial
+ #define MYSERIAL0 USBSerial
#elif WITHIN(SERIAL_PORT, 0, 3)
#define MYSERIAL0 MSERIAL(SERIAL_PORT)
#else
@@ -74,7 +77,7 @@ extern "C" volatile uint32_t _millis;
#ifdef SERIAL_PORT_2
#if SERIAL_PORT_2 == -1
- #define MYSERIAL1 UsbSerial
+ #define MYSERIAL1 USBSerial
#elif WITHIN(SERIAL_PORT_2, 0, 3)
#define MYSERIAL1 MSERIAL(SERIAL_PORT_2)
#else
@@ -82,9 +85,19 @@ extern "C" volatile uint32_t _millis;
#endif
#endif
+#ifdef MMU2_SERIAL_PORT
+ #if MMU2_SERIAL_PORT == -1
+ #define MMU2_SERIAL USBSerial
+ #elif WITHIN(MMU2_SERIAL_PORT, 0, 3)
+ #define MMU2_SERIAL MSERIAL(MMU2_SERIAL_PORT)
+ #else
+ #error "MMU2_SERIAL_PORT must be from -1 to 3. Please update your configuration."
+ #endif
+#endif
+
#ifdef LCD_SERIAL_PORT
#if LCD_SERIAL_PORT == -1
- #define LCD_SERIAL UsbSerial
+ #define LCD_SERIAL USBSerial
#elif WITHIN(LCD_SERIAL_PORT, 0, 3)
#define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT)
#else
@@ -204,16 +217,3 @@ void HAL_clear_reset_source(void);
uint8_t HAL_get_reset_source(void);
inline void HAL_reboot() {} // reboot the board or restart the bootloader
-
-// Add strcmp_P if missing
-#ifndef strcmp_P
- #define strcmp_P(a, b) strcmp((a), (b))
-#endif
-
-#ifndef strcat_P
- #define strcat_P(a, b) strcat((a), (b))
-#endif
-
-#ifndef strcpy_P
- #define strcpy_P(a, b) strcpy((a), (b))
-#endif
diff --git a/Marlin/src/HAL/LPC1768/MarlinSerial.cpp b/Marlin/src/HAL/LPC1768/MarlinSerial.cpp
index baad3f8f26b7..c636a40a120c 100644
--- a/Marlin/src/HAL/LPC1768/MarlinSerial.cpp
+++ b/Marlin/src/HAL/LPC1768/MarlinSerial.cpp
@@ -24,20 +24,20 @@
#include "../../inc/MarlinConfigPre.h"
#include "MarlinSerial.h"
-#if USING_SERIAL_0
- MarlinSerial MSerial(LPC_UART0);
+#if ANY_SERIAL_IS(0)
+ MSerialT MSerial(true, LPC_UART0);
extern "C" void UART0_IRQHandler() { MSerial.IRQHandler(); }
#endif
-#if USING_SERIAL_1
- MarlinSerial MSerial1((LPC_UART_TypeDef *) LPC_UART1);
+#if ANY_SERIAL_IS(1)
+ MSerialT MSerial1(true, (LPC_UART_TypeDef *) LPC_UART1);
extern "C" void UART1_IRQHandler() { MSerial1.IRQHandler(); }
#endif
-#if USING_SERIAL_2
- MarlinSerial MSerial2(LPC_UART2);
+#if ANY_SERIAL_IS(2)
+ MSerialT MSerial2(true, LPC_UART2);
extern "C" void UART2_IRQHandler() { MSerial2.IRQHandler(); }
#endif
-#if USING_SERIAL_3
- MarlinSerial MSerial3(LPC_UART3);
+#if ANY_SERIAL_IS(3)
+ MSerialT MSerial3(true, LPC_UART3);
extern "C" void UART3_IRQHandler() { MSerial3.IRQHandler(); }
#endif
diff --git a/Marlin/src/HAL/LPC1768/MarlinSerial.h b/Marlin/src/HAL/LPC1768/MarlinSerial.h
index 8d6b64378a0a..de0f62f006d2 100644
--- a/Marlin/src/HAL/LPC1768/MarlinSerial.h
+++ b/Marlin/src/HAL/LPC1768/MarlinSerial.h
@@ -28,6 +28,7 @@
#if ENABLED(EMERGENCY_PARSER)
#include "../../feature/e_parser.h"
#endif
+#include "../../core/serial_hook.h"
#ifndef SERIAL_PORT
#define SERIAL_PORT 0
@@ -41,27 +42,20 @@
class MarlinSerial : public HardwareSerial {
public:
- MarlinSerial(LPC_UART_TypeDef *UARTx) :
- HardwareSerial(UARTx)
- #if ENABLED(EMERGENCY_PARSER)
- , emergency_state(EmergencyParser::State::EP_RESET)
- #endif
- { }
+ MarlinSerial(LPC_UART_TypeDef *UARTx) : HardwareSerial(UARTx) { }
void end() {}
#if ENABLED(EMERGENCY_PARSER)
bool recv_callback(const char c) override {
- emergency_parser.update(emergency_state, c);
+ emergency_parser.update(static_cast *>(this)->emergency_state, c);
return true; // do not discard character
}
-
- EmergencyParser::State emergency_state;
- static inline bool emergency_parser_enabled() { return true; }
#endif
};
-extern MarlinSerial MSerial;
-extern MarlinSerial MSerial1;
-extern MarlinSerial MSerial2;
-extern MarlinSerial MSerial3;
+typedef Serial0Type MSerialT;
+extern MSerialT MSerial;
+extern MSerialT MSerial1;
+extern MSerialT MSerial2;
+extern MSerialT MSerial3;
diff --git a/Marlin/src/HAL/LPC1768/eeprom_flash.cpp b/Marlin/src/HAL/LPC1768/eeprom_flash.cpp
index 3c0c3c8ec30e..38d2705d519a 100644
--- a/Marlin/src/HAL/LPC1768/eeprom_flash.cpp
+++ b/Marlin/src/HAL/LPC1768/eeprom_flash.cpp
@@ -25,7 +25,7 @@
* Emulate EEPROM storage using Flash Memory
*
* Use a single 32K flash sector to store EEPROM data. To reduce the
- * number of erase operations a simple "levelling" scheme is used that
+ * number of erase operations a simple "leveling" scheme is used that
* maintains a number of EEPROM "slots" within the larger flash sector.
* Each slot is used in turn and the entire sector is only erased when all
* slots have been used.
diff --git a/Marlin/src/HAL/LPC1768/eeprom_sdcard.cpp b/Marlin/src/HAL/LPC1768/eeprom_sdcard.cpp
index 54a64ccd72f1..b97b161dc94c 100644
--- a/Marlin/src/HAL/LPC1768/eeprom_sdcard.cpp
+++ b/Marlin/src/HAL/LPC1768/eeprom_sdcard.cpp
@@ -84,16 +84,16 @@ static void debug_rw(const bool write, int &pos, const uint8_t *value, const siz
PGM_P const rw_str = write ? PSTR("write") : PSTR("read");
SERIAL_CHAR(' ');
serialprintPGM(rw_str);
- SERIAL_ECHOLNPAIR("_data(", pos, ",", int(value), ",", int(size), ", ...)");
+ SERIAL_ECHOLNPAIR("_data(", pos, ",", value, ",", size, ", ...)");
if (total) {
SERIAL_ECHOPGM(" f_");
serialprintPGM(rw_str);
- SERIAL_ECHOPAIR("()=", int(s), "\n size=", int(size), "\n bytes_");
+ SERIAL_ECHOPAIR("()=", s, "\n size=", size, "\n bytes_");
serialprintPGM(write ? PSTR("written=") : PSTR("read="));
SERIAL_ECHOLN(total);
}
else
- SERIAL_ECHOLNPAIR(" f_lseek()=", int(s));
+ SERIAL_ECHOLNPAIR(" f_lseek()=", s);
}
// File function return codes for type FRESULT. This goes away soon, but
diff --git a/Marlin/src/HAL/LPC1768/inc/Conditionals_post.h b/Marlin/src/HAL/LPC1768/inc/Conditionals_post.h
index ce6d3fdde27f..94e4ce134170 100644
--- a/Marlin/src/HAL/LPC1768/inc/Conditionals_post.h
+++ b/Marlin/src/HAL/LPC1768/inc/Conditionals_post.h
@@ -26,3 +26,10 @@
#elif EITHER(I2C_EEPROM, SPI_EEPROM)
#define USE_SHARED_EEPROM 1
#endif
+
+// LPC1768 boards seem to lose steps when saving to EEPROM during print (issue #20785)
+// TODO: Which other boards are incompatible?
+#if defined(MCU_LPC1768) && PRINTCOUNTER_SAVE_INTERVAL > 0
+ #warning "To prevent step loss, motion will pause for PRINTCOUNTER auto-save."
+ #define PRINTCOUNTER_SYNC 1
+#endif
diff --git a/Marlin/src/HAL/LPC1768/inc/SanityCheck.h b/Marlin/src/HAL/LPC1768/inc/SanityCheck.h
index 11b8761550d7..10d673771472 100644
--- a/Marlin/src/HAL/LPC1768/inc/SanityCheck.h
+++ b/Marlin/src/HAL/LPC1768/inc/SanityCheck.h
@@ -31,7 +31,7 @@
/**
* Detect an old pins file by checking for old ADC pins values.
*/
-#define _OLD_TEMP_PIN(P) PIN_EXISTS(P) && _CAT(P,_PIN) <= 7 && _CAT(P,_PIN) != 2 && _CAT(P,_PIN) != 3
+#define _OLD_TEMP_PIN(P) PIN_EXISTS(P) && _CAT(P,_PIN) <= 7 && !WITHIN(_CAT(P,_PIN), TERN(LPC1768_IS_SKRV1_3, 0, 2), 3) // Include P0_00 and P0_01 for SKR V1.3 board
#if _OLD_TEMP_PIN(TEMP_BED)
#error "TEMP_BED_PIN must be defined using the Pn_nn or Pn_nn_An format. (See the included pins files)."
#elif _OLD_TEMP_PIN(TEMP_0)
@@ -92,7 +92,7 @@ static_assert(DISABLED(BAUD_RATE_GCODE), "BAUD_RATE_GCODE is not yet supported o
#define ANY_TX(N,V...) DO(IS_TX##N,||,V)
#define ANY_RX(N,V...) DO(IS_RX##N,||,V)
-#if USING_SERIAL_0
+#if ANY_SERIAL_IS(0)
#define IS_TX0(P) (P == P0_02)
#define IS_RX0(P) (P == P0_03)
#if IS_TX0(TMC_SW_MISO) || IS_RX0(TMC_SW_MOSI)
@@ -106,7 +106,7 @@ static_assert(DISABLED(BAUD_RATE_GCODE), "BAUD_RATE_GCODE is not yet supported o
#undef IS_RX0
#endif
-#if USING_SERIAL_1
+#if ANY_SERIAL_IS(1)
#define IS_TX1(P) (P == P0_15)
#define IS_RX1(P) (P == P0_16)
#define _IS_TX1_1 IS_TX1
@@ -116,7 +116,7 @@ static_assert(DISABLED(BAUD_RATE_GCODE), "BAUD_RATE_GCODE is not yet supported o
#elif HAS_WIRED_LCD
#if IS_TX1(BTN_EN2) || IS_RX1(BTN_EN1)
#error "Serial port pins (1) conflict with Encoder Buttons!"
- #elif ANY_TX(1, SD_SCK_PIN, LCD_PINS_D4, DOGLCD_SCK, LCD_RESET_PIN, LCD_PINS_RS, SHIFT_CLK) \
+ #elif ANY_TX(1, SD_SCK_PIN, LCD_PINS_D4, DOGLCD_SCK, LCD_RESET_PIN, LCD_PINS_RS, SHIFT_CLK_PIN) \
|| ANY_RX(1, LCD_SDSS, LCD_PINS_RS, SD_MISO_PIN, DOGLCD_A0, SD_SS_PIN, LCD_SDSS, DOGLCD_CS, LCD_RESET_PIN, LCD_BACKLIGHT_PIN)
#error "Serial port pins (1) conflict with LCD pins!"
#endif
@@ -127,7 +127,7 @@ static_assert(DISABLED(BAUD_RATE_GCODE), "BAUD_RATE_GCODE is not yet supported o
#undef _IS_RX1_1
#endif
-#if USING_SERIAL_2
+#if ANY_SERIAL_IS(2)
#define IS_TX2(P) (P == P0_10)
#define IS_RX2(P) (P == P0_11)
#define _IS_TX2_1 IS_TX2
@@ -161,7 +161,7 @@ static_assert(DISABLED(BAUD_RATE_GCODE), "BAUD_RATE_GCODE is not yet supported o
#undef _IS_RX2_1
#endif
-#if USING_SERIAL_3
+#if ANY_SERIAL_IS(3)
#define PIN_IS_TX3(P) (PIN_EXISTS(P) && P##_PIN == P0_00)
#define PIN_IS_RX3(P) (P##_PIN == P0_01)
#if PIN_IS_TX3(X_MIN) || PIN_IS_RX3(X_MAX)
diff --git a/Marlin/src/HAL/LPC1768/main.cpp b/Marlin/src/HAL/LPC1768/main.cpp
index f41a57637639..1fbeddd9ea64 100644
--- a/Marlin/src/HAL/LPC1768/main.cpp
+++ b/Marlin/src/HAL/LPC1768/main.cpp
@@ -119,9 +119,9 @@ void HAL_init() {
#endif
USB_Init(); // USB Initialization
- USB_Connect(FALSE); // USB clear connection
+ USB_Connect(false); // USB clear connection
delay(1000); // Give OS time to notice
- USB_Connect(TRUE);
+ USB_Connect(true);
#if HAS_SD_HOST_DRIVE
MSC_SD_Init(0); // Enable USB SD card access
diff --git a/Marlin/src/HAL/LPC1768/timers.h b/Marlin/src/HAL/LPC1768/timers.h
index e6744fb005bf..4b638546856f 100644
--- a/Marlin/src/HAL/LPC1768/timers.h
+++ b/Marlin/src/HAL/LPC1768/timers.h
@@ -152,7 +152,7 @@ FORCE_INLINE static void HAL_timer_disable_interrupt(const uint8_t timer_num) {
// This function is missing from CMSIS
FORCE_INLINE static bool NVIC_GetEnableIRQ(IRQn_Type IRQn) {
- return (NVIC->ISER[((uint32_t)IRQn) >> 5] & (1 << ((uint32_t)IRQn) & 0x1F)) != 0;
+ return TEST(NVIC->ISER[uint32_t(IRQn) >> 5], uint32_t(IRQn) & 0x1F);
}
FORCE_INLINE static bool HAL_timer_interrupt_enabled(const uint8_t timer_num) {
diff --git a/Marlin/src/HAL/SAMD51/HAL.cpp b/Marlin/src/HAL/SAMD51/HAL.cpp
index d985ef37871f..a413c4cd80e7 100644
--- a/Marlin/src/HAL/SAMD51/HAL.cpp
+++ b/Marlin/src/HAL/SAMD51/HAL.cpp
@@ -24,6 +24,11 @@
#include
#include
+#ifdef ADAFRUIT_GRAND_CENTRAL_M4
+ DefaultSerial MSerial(false, Serial);
+ DefaultSerial1 MSerial1(false, Serial1);
+#endif
+
// ------------------------
// Local defines
// ------------------------
diff --git a/Marlin/src/HAL/SAMD51/HAL.h b/Marlin/src/HAL/SAMD51/HAL.h
index ff9310114641..f28583c771be 100644
--- a/Marlin/src/HAL/SAMD51/HAL.h
+++ b/Marlin/src/HAL/SAMD51/HAL.h
@@ -32,15 +32,19 @@
#include "MarlinSerial_AGCM4.h"
// Serial ports
+ typedef ForwardSerial0Type< decltype(Serial) > DefaultSerial;
+ extern DefaultSerial MSerial;
+ typedef ForwardSerial0Type< decltype(Serial1) > DefaultSerial1;
+ extern DefaultSerial1 MSerial1;
// MYSERIAL0 required before MarlinSerial includes!
- #define __MSERIAL(X) Serial##X
+ #define __MSERIAL(X) MSerial##X
#define _MSERIAL(X) __MSERIAL(X)
#define MSERIAL(X) _MSERIAL(INCREMENT(X))
#if SERIAL_PORT == -1
- #define MYSERIAL0 Serial
+ #define MYSERIAL0 MSerial
#elif WITHIN(SERIAL_PORT, 0, 3)
#define MYSERIAL0 MSERIAL(SERIAL_PORT)
#else
@@ -49,7 +53,7 @@
#ifdef SERIAL_PORT_2
#if SERIAL_PORT_2 == -1
- #define MYSERIAL1 Serial
+ #define MYSERIAL1 MSerial
#elif WITHIN(SERIAL_PORT_2, 0, 3)
#define MYSERIAL1 MSERIAL(SERIAL_PORT_2)
#else
@@ -57,9 +61,19 @@
#endif
#endif
+ #ifdef MMU2_SERIAL_PORT
+ #if MMU2_SERIAL_PORT == -1
+ #define MMU2_SERIAL MSerial
+ #elif WITHIN(MMU2_SERIAL_PORT, 0, 3)
+ #define MMU2_SERIAL MSERIAL(MMU2_SERIAL_PORT)
+ #else
+ #error "MMU2_SERIAL_PORT must be from -1 to 3. Please update your configuration."
+ #endif
+ #endif
+
#ifdef LCD_SERIAL_PORT
#if LCD_SERIAL_PORT == -1
- #define LCD_SERIAL Serial
+ #define LCD_SERIAL MSerial
#elif WITHIN(LCD_SERIAL_PORT, 0, 3)
#define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT)
#else
diff --git a/Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.cpp b/Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.cpp
index abc5f3acbf77..3f43585cf242 100644
--- a/Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.cpp
+++ b/Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.cpp
@@ -21,30 +21,30 @@
#ifdef ADAFRUIT_GRAND_CENTRAL_M4
/**
- * Framework doesn't define some serial to save sercom resources
+ * Framework doesn't define some serials to save sercom resources
* hence if these are used I need to define them
*/
#include "../../inc/MarlinConfig.h"
-#if SERIAL_PORT == 1 || SERIAL_PORT_2 == 1
- Uart Serial2(&sercom4, PIN_SERIAL2_RX, PIN_SERIAL2_TX, PAD_SERIAL2_RX, PAD_SERIAL2_TX);
+#if ANY_SERIAL_IS(1)
+ UartT Serial2(false, &sercom4, PIN_SERIAL2_RX, PIN_SERIAL2_TX, PAD_SERIAL2_RX, PAD_SERIAL2_TX);
void SERCOM4_0_Handler() { Serial2.IrqHandler(); }
void SERCOM4_1_Handler() { Serial2.IrqHandler(); }
void SERCOM4_2_Handler() { Serial2.IrqHandler(); }
void SERCOM4_3_Handler() { Serial2.IrqHandler(); }
#endif
-#if SERIAL_PORT == 2 || SERIAL_PORT_2 == 2
- Uart Serial3(&sercom1, PIN_SERIAL3_RX, PIN_SERIAL3_TX, PAD_SERIAL3_RX, PAD_SERIAL3_TX);
+#if ANY_SERIAL_IS(2)
+ UartT Serial3(false, &sercom1, PIN_SERIAL3_RX, PIN_SERIAL3_TX, PAD_SERIAL3_RX, PAD_SERIAL3_TX);
void SERCOM1_0_Handler() { Serial3.IrqHandler(); }
void SERCOM1_1_Handler() { Serial3.IrqHandler(); }
void SERCOM1_2_Handler() { Serial3.IrqHandler(); }
void SERCOM1_3_Handler() { Serial3.IrqHandler(); }
#endif
-#if SERIAL_PORT == 3 || SERIAL_PORT_2 == 3
- Uart Serial4(&sercom5, PIN_SERIAL4_RX, PIN_SERIAL4_TX, PAD_SERIAL4_RX, PAD_SERIAL4_TX);
+#if ANY_SERIAL_IS(3)
+ UartT Serial4(false, &sercom5, PIN_SERIAL4_RX, PIN_SERIAL4_TX, PAD_SERIAL4_RX, PAD_SERIAL4_TX);
void SERCOM5_0_Handler() { Serial4.IrqHandler(); }
void SERCOM5_1_Handler() { Serial4.IrqHandler(); }
void SERCOM5_2_Handler() { Serial4.IrqHandler(); }
diff --git a/Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.h b/Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.h
index f3821d8d5a84..b7293415d136 100644
--- a/Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.h
+++ b/Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.h
@@ -20,6 +20,10 @@
*/
#pragma once
-extern Uart Serial2;
-extern Uart Serial3;
-extern Uart Serial4;
+#include "../../core/serial_hook.h"
+
+typedef Serial0Type UartT;
+
+extern UartT Serial2;
+extern UartT Serial3;
+extern UartT Serial4;
diff --git a/Marlin/src/HAL/SAMD51/fastio.h b/Marlin/src/HAL/SAMD51/fastio.h
index c456dfce30cb..a95b7cac0ce9 100644
--- a/Marlin/src/HAL/SAMD51/fastio.h
+++ b/Marlin/src/HAL/SAMD51/fastio.h
@@ -31,7 +31,7 @@
*/
#ifndef MASK
- #define MASK(PIN) (1 << PIN)
+ #define MASK(PIN) _BV(PIN)
#endif
/**
diff --git a/Marlin/src/HAL/SAMD51/timers.cpp b/Marlin/src/HAL/SAMD51/timers.cpp
index a68af2e074ae..5c55d324079a 100644
--- a/Marlin/src/HAL/SAMD51/timers.cpp
+++ b/Marlin/src/HAL/SAMD51/timers.cpp
@@ -157,7 +157,7 @@ void HAL_timer_disable_interrupt(const uint8_t timer_num) {
// missing from CMSIS: Check if interrupt is enabled or not
static bool NVIC_GetEnabledIRQ(IRQn_Type IRQn) {
- return (NVIC->ISER[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F))) != 0;
+ return TEST(NVIC->ISER[uint32_t(IRQn) >> 5], uint32_t(IRQn) & 0x1F);
}
bool HAL_timer_interrupt_enabled(const uint8_t timer_num) {
diff --git a/Marlin/src/HAL/STM32/HAL.cpp b/Marlin/src/HAL/STM32/HAL.cpp
index c886f9c0b988..e694a16a820d 100644
--- a/Marlin/src/HAL/STM32/HAL.cpp
+++ b/Marlin/src/HAL/STM32/HAL.cpp
@@ -28,6 +28,10 @@
#include "../../inc/MarlinConfig.h"
#include "../shared/Delay.h"
+#ifdef USBCON
+ DefaultSerial MSerial(false, SerialUSB);
+#endif
+
#if ENABLED(SRAM_EEPROM_EMULATION)
#if STM32F7xx
#include
@@ -38,6 +42,11 @@
#endif
#endif
+#if HAS_SD_HOST_DRIVE
+ #include "msc_sd.h"
+ #include "usbd_cdc_if.h"
+#endif
+
// ------------------------
// Public Variables
// ------------------------
@@ -48,17 +57,6 @@ uint16_t HAL_adc_result;
// Public functions
// ------------------------
-// Needed for DELAY_NS() / DELAY_US() on CORTEX-M7
-#if (defined(__arm__) || defined(__thumb__)) && __CORTEX_M == 7
- // HAL pre-initialization task
- // Force the preinit function to run between the premain() and main() function
- // of the STM32 arduino core
- __attribute__((constructor (102)))
- void HAL_preinit() {
- enableCycleCounter();
- }
-#endif
-
// HAL initialization task
void HAL_init() {
FastIO_init();
@@ -84,6 +82,19 @@ void HAL_init() {
#if ENABLED(EMERGENCY_PARSER) && USBD_USE_CDC
USB_Hook_init();
#endif
+
+ #if HAS_SD_HOST_DRIVE
+ MSC_SD_init(); // Enable USB SD card access
+ #endif
+}
+
+// HAL idle task
+void HAL_idletask() {
+ #if HAS_SHARED_MEDIA
+ // Stm32duino currently doesn't have a "loop/idle" method
+ CDC_resume_receive();
+ CDC_continue_transmit();
+ #endif
}
void HAL_clear_reset_source() { __HAL_RCC_CLEAR_RESET_FLAGS(); }
diff --git a/Marlin/src/HAL/STM32/HAL.h b/Marlin/src/HAL/STM32/HAL.h
index b1c27e4ec5fb..be0cc309626c 100644
--- a/Marlin/src/HAL/STM32/HAL.h
+++ b/Marlin/src/HAL/STM32/HAL.h
@@ -39,6 +39,9 @@
#ifdef USBCON
#include
+ #include "../../core/serial_hook.h"
+ typedef ForwardSerial0Type< decltype(SerialUSB) > DefaultSerial;
+ extern DefaultSerial MSerial;
#endif
// ------------------------
@@ -48,7 +51,7 @@
#define MSERIAL(X) _MSERIAL(X)
#if SERIAL_PORT == -1
- #define MYSERIAL0 SerialUSB
+ #define MYSERIAL0 MSerial
#elif WITHIN(SERIAL_PORT, 1, 6)
#define MYSERIAL0 MSERIAL(SERIAL_PORT)
#else
@@ -57,7 +60,7 @@
#ifdef SERIAL_PORT_2
#if SERIAL_PORT_2 == -1
- #define MYSERIAL1 SerialUSB
+ #define MYSERIAL1 MSerial
#elif WITHIN(SERIAL_PORT_2, 1, 6)
#define MYSERIAL1 MSERIAL(SERIAL_PORT_2)
#else
@@ -65,9 +68,19 @@
#endif
#endif
+#ifdef MMU2_SERIAL_PORT
+ #if MMU2_SERIAL_PORT == -1
+ #define MMU2_SERIAL MSerial
+ #elif WITHIN(MMU2_SERIAL_PORT, 1, 6)
+ #define MMU2_SERIAL MSERIAL(MMU2_SERIAL_PORT)
+ #else
+ #error "MMU2_SERIAL_PORT must be -1 or from 1 to 6. Please update your configuration."
+ #endif
+#endif
+
#ifdef LCD_SERIAL_PORT
#if LCD_SERIAL_PORT == -1
- #define LCD_SERIAL SerialUSB
+ #define LCD_SERIAL MSerial
#elif WITHIN(LCD_SERIAL_PORT, 1, 6)
#define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT)
#else
@@ -96,14 +109,6 @@
// On AVR this is in math.h?
#define square(x) ((x)*(x))
-#ifndef strncpy_P
- #define strncpy_P(dest, src, num) strncpy((dest), (src), (num))
-#endif
-
-// Fix bug in pgm_read_ptr
-#undef pgm_read_ptr
-#define pgm_read_ptr(addr) (*(addr))
-
// ------------------------
// Types
// ------------------------
@@ -130,6 +135,8 @@ extern uint16_t HAL_adc_result;
// Enable hooks into setup for HAL
void HAL_init();
+#define HAL_IDLETASK 1
+void HAL_idletask();
// Clear reset reason
void HAL_clear_reset_source();
@@ -187,6 +194,7 @@ void flashFirmware(const int16_t);
typedef void (*systickCallback_t)(void);
void systick_attach_callback(systickCallback_t cb);
void HAL_SYSTICK_Callback();
+
extern volatile uint32_t systick_uptime_millis;
#define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment
diff --git a/Marlin/src/HAL/STM32/HAL_SPI.cpp b/Marlin/src/HAL/STM32/HAL_SPI.cpp
index eef480777bb7..c9f23e6fa312 100644
--- a/Marlin/src/HAL/STM32/HAL_SPI.cpp
+++ b/Marlin/src/HAL/STM32/HAL_SPI.cpp
@@ -51,18 +51,28 @@ static SPISettings spiConfig;
OUT_WRITE(SD_MOSI_PIN, HIGH);
}
- static uint16_t delay_STM32_soft_spi;
+ // Use function with compile-time value so we can actually reach the desired frequency
+ // Need to adjust this a little bit: on a 72MHz clock, we have 14ns/clock
+ // and we'll use ~3 cycles to jump to the method and going back, so it'll take ~40ns from the given clock here
+ #define CALLING_COST_NS (3U * 1000000000U) / (F_CPU)
+ void (*delaySPIFunc)();
+ void delaySPI_125() { DELAY_NS(125 - CALLING_COST_NS); }
+ void delaySPI_250() { DELAY_NS(250 - CALLING_COST_NS); }
+ void delaySPI_500() { DELAY_NS(500 - CALLING_COST_NS); }
+ void delaySPI_1000() { DELAY_NS(1000 - CALLING_COST_NS); }
+ void delaySPI_2000() { DELAY_NS(2000 - CALLING_COST_NS); }
+ void delaySPI_4000() { DELAY_NS(4000 - CALLING_COST_NS); }
void spiInit(uint8_t spiRate) {
// Use datarates Marlin uses
switch (spiRate) {
- case SPI_FULL_SPEED: delay_STM32_soft_spi = 125; break; // desired: 8,000,000 actual: ~1.1M
- case SPI_HALF_SPEED: delay_STM32_soft_spi = 125; break; // desired: 4,000,000 actual: ~1.1M
- case SPI_QUARTER_SPEED:delay_STM32_soft_spi = 250; break; // desired: 2,000,000 actual: ~890K
- case SPI_EIGHTH_SPEED: delay_STM32_soft_spi = 500; break; // desired: 1,000,000 actual: ~590K
- case SPI_SPEED_5: delay_STM32_soft_spi = 1000; break; // desired: 500,000 actual: ~360K
- case SPI_SPEED_6: delay_STM32_soft_spi = 2000; break; // desired: 250,000 actual: ~210K
- default: delay_STM32_soft_spi = 4000; break; // desired: 125,000 actual: ~123K
+ case SPI_FULL_SPEED: delaySPIFunc = &delaySPI_125; break; // desired: 8,000,000 actual: ~1.1M
+ case SPI_HALF_SPEED: delaySPIFunc = &delaySPI_125; break; // desired: 4,000,000 actual: ~1.1M
+ case SPI_QUARTER_SPEED:delaySPIFunc = &delaySPI_250; break; // desired: 2,000,000 actual: ~890K
+ case SPI_EIGHTH_SPEED: delaySPIFunc = &delaySPI_500; break; // desired: 1,000,000 actual: ~590K
+ case SPI_SPEED_5: delaySPIFunc = &delaySPI_1000; break; // desired: 500,000 actual: ~360K
+ case SPI_SPEED_6: delaySPIFunc = &delaySPI_2000; break; // desired: 250,000 actual: ~210K
+ default: delaySPIFunc = &delaySPI_4000; break; // desired: 125,000 actual: ~123K
}
SPI.begin();
}
@@ -75,9 +85,9 @@ static SPISettings spiConfig;
WRITE(SD_SCK_PIN, LOW);
WRITE(SD_MOSI_PIN, b & 0x80);
- DELAY_NS(delay_STM32_soft_spi);
+ delaySPIFunc();
WRITE(SD_SCK_PIN, HIGH);
- DELAY_NS(delay_STM32_soft_spi);
+ delaySPIFunc();
b <<= 1; // little setup time
b |= (READ(SD_MISO_PIN) != 0);
diff --git a/Marlin/src/HAL/STM32/MarlinSerial.cpp b/Marlin/src/HAL/STM32/MarlinSerial.cpp
index 50765ee9958e..cfb13f5bb561 100644
--- a/Marlin/src/HAL/STM32/MarlinSerial.cpp
+++ b/Marlin/src/HAL/STM32/MarlinSerial.cpp
@@ -35,7 +35,7 @@
#define DECLARE_SERIAL_PORT(ser_num) \
void _rx_complete_irq_ ## ser_num (serial_t * obj); \
- MarlinSerial MSerial ## ser_num (USART ## ser_num, &_rx_complete_irq_ ## ser_num); \
+ MSerialT MSerial ## ser_num (true, USART ## ser_num, &_rx_complete_irq_ ## ser_num); \
void _rx_complete_irq_ ## ser_num (serial_t * obj) { MSerial ## ser_num ._rx_complete_irq(obj); }
#define DECLARE_SERIAL_PORT_EXP(ser_num) DECLARE_SERIAL_PORT(ser_num)
@@ -48,6 +48,10 @@
DECLARE_SERIAL_PORT_EXP(SERIAL_PORT_2)
#endif
+#if defined(MMU2_SERIAL_PORT) && MMU2_SERIAL_PORT >= 0
+ DECLARE_SERIAL_PORT_EXP(MMU2_SERIAL_PORT)
+#endif
+
#if defined(LCD_SERIAL_PORT) && LCD_SERIAL_PORT >= 0
DECLARE_SERIAL_PORT_EXP(LCD_SERIAL_PORT)
#endif
@@ -77,7 +81,7 @@ void MarlinSerial::_rx_complete_irq(serial_t *obj) {
}
#if ENABLED(EMERGENCY_PARSER)
- emergency_parser.update(emergency_state, c);
+ emergency_parser.update(static_cast(this)->emergency_state, c);
#endif
}
}
diff --git a/Marlin/src/HAL/STM32/MarlinSerial.h b/Marlin/src/HAL/STM32/MarlinSerial.h
index 3611cc78d7ce..8cc4f0dd4cb8 100644
--- a/Marlin/src/HAL/STM32/MarlinSerial.h
+++ b/Marlin/src/HAL/STM32/MarlinSerial.h
@@ -24,21 +24,15 @@
#include "../../feature/e_parser.h"
#endif
+#include "../../core/serial_hook.h"
+
typedef void (*usart_rx_callback_t)(serial_t * obj);
-class MarlinSerial : public HardwareSerial {
-public:
+struct MarlinSerial : public HardwareSerial {
MarlinSerial(void* peripheral, usart_rx_callback_t rx_callback) :
HardwareSerial(peripheral), _rx_callback(rx_callback)
- #if ENABLED(EMERGENCY_PARSER)
- , emergency_state(EmergencyParser::State::EP_RESET)
- #endif
{ }
- #if ENABLED(EMERGENCY_PARSER)
- static inline bool emergency_parser_enabled() { return true; }
- #endif
-
void begin(unsigned long baud, uint8_t config);
inline void begin(unsigned long baud) { begin(baud, SERIAL_8N1); }
@@ -46,19 +40,17 @@ class MarlinSerial : public HardwareSerial {
protected:
usart_rx_callback_t _rx_callback;
- #if ENABLED(EMERGENCY_PARSER)
- EmergencyParser::State emergency_state;
- #endif
};
-extern MarlinSerial MSerial1;
-extern MarlinSerial MSerial2;
-extern MarlinSerial MSerial3;
-extern MarlinSerial MSerial4;
-extern MarlinSerial MSerial5;
-extern MarlinSerial MSerial6;
-extern MarlinSerial MSerial7;
-extern MarlinSerial MSerial8;
-extern MarlinSerial MSerial9;
-extern MarlinSerial MSerial10;
-extern MarlinSerial MSerialLP1;
+typedef Serial0Type MSerialT;
+extern MSerialT MSerial1;
+extern MSerialT MSerial2;
+extern MSerialT MSerial3;
+extern MSerialT MSerial4;
+extern MSerialT MSerial5;
+extern MSerialT MSerial6;
+extern MSerialT MSerial7;
+extern MSerialT MSerial8;
+extern MSerialT MSerial9;
+extern MSerialT MSerial10;
+extern MSerialT MSerialLP1;
diff --git a/Marlin/src/HAL/STM32/Sd2Card_sdio_stm32duino.cpp b/Marlin/src/HAL/STM32/Sd2Card_sdio_stm32duino.cpp
index e00fb9b16f7a..fc9b960c1c49 100644
--- a/Marlin/src/HAL/STM32/Sd2Card_sdio_stm32duino.cpp
+++ b/Marlin/src/HAL/STM32/Sd2Card_sdio_stm32duino.cpp
@@ -163,7 +163,6 @@
GPIO_InitStruct.Pin = GPIO_PIN_2;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
-
#if DISABLED(STM32F1xx)
// TODO: use __HAL_RCC_SDIO_RELEASE_RESET() and __HAL_RCC_SDIO_CLK_ENABLE();
RCC->APB2RSTR &= ~RCC_APB2RSTR_SDIORST_Msk; // take SDIO out of reset
diff --git a/Marlin/src/HAL/STM32/eeprom_flash.cpp b/Marlin/src/HAL/STM32/eeprom_flash.cpp
index 8cd62879a5c6..633a286dc8dd 100644
--- a/Marlin/src/HAL/STM32/eeprom_flash.cpp
+++ b/Marlin/src/HAL/STM32/eeprom_flash.cpp
@@ -61,7 +61,9 @@
#define FLASH_UNIT_SIZE 0x20000 // 128kB
#endif
- #define FLASH_ADDRESS_START (FLASH_END - ((FLASH_SECTOR_TOTAL - (FLASH_SECTOR)) * (FLASH_UNIT_SIZE)) + 1)
+ #ifndef FLASH_ADDRESS_START
+ #define FLASH_ADDRESS_START (FLASH_END - ((FLASH_SECTOR_TOTAL - (FLASH_SECTOR)) * (FLASH_UNIT_SIZE)) + 1)
+ #endif
#define FLASH_ADDRESS_END (FLASH_ADDRESS_START + FLASH_UNIT_SIZE - 1)
#define EEPROM_SLOTS ((FLASH_UNIT_SIZE) / (MARLIN_EEPROM_SIZE))
diff --git a/Marlin/src/HAL/STM32/fastio.h b/Marlin/src/HAL/STM32/fastio.h
index ea28b8f3bfaa..17751c44dd8d 100644
--- a/Marlin/src/HAL/STM32/fastio.h
+++ b/Marlin/src/HAL/STM32/fastio.h
@@ -59,7 +59,7 @@ void FastIO_init(); // Must be called before using fast io macros
#endif
#define _READ(IO) bool(READ_BIT(FastIOPortMap[STM_PORT(digitalPinToPinName(IO))]->IDR, _BV32(STM_PIN(digitalPinToPinName(IO)))))
-#define _TOGGLE(IO) (FastIOPortMap[STM_PORT(digitalPinToPinName(IO))]->ODR ^= _BV32(STM_PIN(digitalPinToPinName(IO))))
+#define _TOGGLE(IO) TBI32(FastIOPortMap[STM_PORT(digitalPinToPinName(IO))]->ODR, STM_PIN(digitalPinToPinName(IO)))
#define _GET_MODE(IO)
#define _SET_MODE(IO,M) pinMode(IO, M)
diff --git a/Marlin/src/HAL/STM32/inc/Conditionals_adv.h b/Marlin/src/HAL/STM32/inc/Conditionals_adv.h
index e07c0d9cda5e..672d405d6b84 100644
--- a/Marlin/src/HAL/STM32/inc/Conditionals_adv.h
+++ b/Marlin/src/HAL/STM32/inc/Conditionals_adv.h
@@ -21,6 +21,6 @@
*/
#pragma once
-#if defined(USBD_USE_CDC_COMPOSITE) && DISABLED(NO_SD_HOST_DRIVE)
+#if defined(USBD_USE_CDC_MSC) && DISABLED(NO_SD_HOST_DRIVE)
#define HAS_SD_HOST_DRIVE 1
#endif
diff --git a/Marlin/src/HAL/STM32/msc_sd.cpp b/Marlin/src/HAL/STM32/msc_sd.cpp
new file mode 100644
index 000000000000..63ce7808f183
--- /dev/null
+++ b/Marlin/src/HAL/STM32/msc_sd.cpp
@@ -0,0 +1,112 @@
+/**
+ * Marlin 3D Printer Firmware
+ *
+ * Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ * Copyright (c) 2019 BigTreeTech [https://github.com/bigtreetech]
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+#include "../../inc/MarlinConfigPre.h"
+
+#if defined(ARDUINO_ARCH_STM32) && !defined(STM32GENERIC) && HAS_SD_HOST_DRIVE
+
+#include "msc_sd.h"
+#include "../shared/Marduino.h"
+#include "usbd_core.h"
+#include
+#include
+
+#define BLOCK_SIZE 512
+#define PRODUCT_ID 0x29
+
+#include "../../sd/cardreader.h"
+
+class Sd2CardUSBMscHandler : public USBMscHandler {
+public:
+ bool GetCapacity(uint32_t *pBlockNum, uint16_t *pBlockSize) {
+ *pBlockNum = card.getSd2Card().cardSize();
+ *pBlockSize = BLOCK_SIZE;
+ return true;
+ }
+
+ bool Write(uint8_t *pBuf, uint32_t blkAddr, uint16_t blkLen) {
+ auto sd2card = card.getSd2Card();
+ // single block
+ if (blkLen == 1) {
+ watchdog_refresh();
+ sd2card.writeBlock(blkAddr, pBuf);
+ return true;
+ }
+
+ // multi block optmization
+ sd2card.writeStart(blkAddr, blkLen);
+ while (blkLen--) {
+ watchdog_refresh();
+ sd2card.writeData(pBuf);
+ pBuf += BLOCK_SIZE;
+ }
+ sd2card.writeStop();
+ return true;
+ }
+
+ bool Read(uint8_t *pBuf, uint32_t blkAddr, uint16_t blkLen) {
+ auto sd2card = card.getSd2Card();
+ // single block
+ if (blkLen == 1) {
+ watchdog_refresh();
+ sd2card.readBlock(blkAddr, pBuf);
+ return true;
+ }
+
+ // multi block optmization
+ sd2card.readStart(blkAddr);
+ while (blkLen--) {
+ watchdog_refresh();
+ sd2card.readData(pBuf);
+ pBuf += BLOCK_SIZE;
+ }
+ sd2card.readStop();
+ return true;
+ }
+
+ bool IsReady() {
+ return card.isMounted();
+ }
+};
+
+Sd2CardUSBMscHandler usbMscHandler;
+
+/* USB Mass storage Standard Inquiry Data */
+uint8_t Marlin_STORAGE_Inquirydata[] = { /* 36 */
+ /* LUN 0 */
+ 0x00,
+ 0x80,
+ 0x02,
+ 0x02,
+ (STANDARD_INQUIRY_DATA_LEN - 5),
+ 0x00,
+ 0x00,
+ 0x00,
+ 'M', 'A', 'R', 'L', 'I', 'N', ' ', ' ', /* Manufacturer : 8 bytes */
+ 'P', 'r', 'o', 'd', 'u', 'c', 't', ' ', /* Product : 16 Bytes */
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ '0', '.', '0', '1', /* Version : 4 Bytes */
+};
+
+USBMscHandler *pSingleMscHandler = &usbMscHandler;
+
+void MSC_SD_init() {
+ USBDevice.end();
+ delay(200);
+ USBDevice.begin();
+ USBDevice.registerMscHandlers(1, &pSingleMscHandler, Marlin_STORAGE_Inquirydata);
+}
+
+#endif // __STM32F1__ && HAS_SD_HOST_DRIVE
diff --git a/Marlin/src/HAL/STM32/msc_sd.h b/Marlin/src/HAL/STM32/msc_sd.h
new file mode 100644
index 000000000000..a8e5349f7cd3
--- /dev/null
+++ b/Marlin/src/HAL/STM32/msc_sd.h
@@ -0,0 +1,18 @@
+/**
+ * Marlin 3D Printer Firmware
+ *
+ * Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ * Copyright (c) 2019 BigTreeTech [https://github.com/bigtreetech]
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+#pragma once
+
+void MSC_SD_init();
diff --git a/Marlin/src/HAL/STM32/tft/tft_fsmc.h b/Marlin/src/HAL/STM32/tft/tft_fsmc.h
index 7c40151e2bdf..2200abaa10e8 100644
--- a/Marlin/src/HAL/STM32/tft/tft_fsmc.h
+++ b/Marlin/src/HAL/STM32/tft/tft_fsmc.h
@@ -84,7 +84,6 @@ class TFT_FSMC {
}
};
-
#ifdef STM32F1xx
#define FSMC_PIN_DATA STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, AFIO_NONE)
#elif defined(STM32F4xx)
diff --git a/Marlin/src/HAL/STM32F1/HAL.cpp b/Marlin/src/HAL/STM32F1/HAL.cpp
index dfa99d83f4cf..2f29b9b0e36d 100644
--- a/Marlin/src/HAL/STM32F1/HAL.cpp
+++ b/Marlin/src/HAL/STM32F1/HAL.cpp
@@ -84,6 +84,32 @@
#if defined(SERIAL_USB) && !HAS_SD_HOST_DRIVE
USBSerial SerialUSB;
+ DefaultSerial MSerial(true, SerialUSB);
+
+ #if ENABLED(EMERGENCY_PARSER)
+ #include "../libmaple/usb/stm32f1/usb_reg_map.h"
+ #include "libmaple/usb_cdcacm.h"
+ // The original callback is not called (no way to retrieve address).
+ // That callback detects a special STM32 reset sequence: this functionality is not essential
+ // as M997 achieves the same.
+ void my_rx_callback(unsigned int, void*) {
+ // max length of 16 is enough to contain all emergency commands
+ uint8 buf[16];
+
+ //rx is usbSerialPart.endpoints[2]
+ uint16 len = usb_get_ep_rx_count(USB_CDCACM_RX_ENDP);
+ uint32 total = usb_cdcacm_data_available();
+
+ if (len == 0 || total == 0 || !WITHIN(total, len, COUNT(buf)))
+ return;
+
+ // cannot get character by character due to bug in composite_cdcacm_peek_ex
+ len = usb_cdcacm_peek(buf, total);
+
+ for (uint32 i = 0; i < len; i++)
+ emergency_parser.update(MSerial.emergency_state, buf[i + total - len]);
+ }
+ #endif
#endif
uint16_t HAL_adc_result;
@@ -253,6 +279,8 @@ void HAL_init() {
#endif
#if HAS_SD_HOST_DRIVE
MSC_SD_init();
+ #elif BOTH(SERIAL_USB, EMERGENCY_PARSER)
+ usb_cdcacm_set_hooks(USB_CDCACM_HOOK_RX, my_rx_callback);
#endif
#if PIN_EXISTS(USB_CONNECT)
OUT_WRITE(USB_CONNECT_PIN, !USB_CONNECT_INVERTING); // USB clear connection
diff --git a/Marlin/src/HAL/STM32F1/HAL.h b/Marlin/src/HAL/STM32F1/HAL.h
index 7163db43a2fd..30bf60b6e8a1 100644
--- a/Marlin/src/HAL/STM32F1/HAL.h
+++ b/Marlin/src/HAL/STM32F1/HAL.h
@@ -61,8 +61,11 @@
#endif
#ifdef SERIAL_USB
+ typedef ForwardSerial0Type< USBSerial > DefaultSerial;
+ extern DefaultSerial MSerial;
+
#if !HAS_SD_HOST_DRIVE
- #define UsbSerial Serial
+ #define UsbSerial MSerial
#else
#define UsbSerial MarlinCompositeSerial
#endif
@@ -99,6 +102,18 @@
#endif
#endif
+#ifdef MMU2_SERIAL_PORT
+ #if MMU2_SERIAL_PORT == -1
+ #define MMU2_SERIAL UsbSerial
+ #elif WITHIN(MMU2_SERIAL_PORT, 1, NUM_UARTS)
+ #define MMU2_SERIAL MSERIAL(MMU2_SERIAL_PORT)
+ #elif NUM_UARTS == 5
+ #error "MMU2_SERIAL_PORT must be -1 or from 1 to 5. Please update your configuration."
+ #else
+ #error "MMU2_SERIAL_PORT must be -1 or from 1 to 3. Please update your configuration."
+ #endif
+#endif
+
#ifdef LCD_SERIAL_PORT
#if LCD_SERIAL_PORT == -1
#define LCD_SERIAL UsbSerial
@@ -109,8 +124,9 @@
#else
#error "LCD_SERIAL_PORT must be -1 or from 1 to 3. Please update your configuration."
#endif
-
- #define SERIAL_GET_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite()
+ #if HAS_DGUS_LCD
+ #define SERIAL_GET_TX_BUFFER_FREE() LCD_SERIAL.availableForWrite()
+ #endif
#endif
// Set interrupt grouping for this MCU
@@ -139,14 +155,6 @@ void HAL_idletask();
// On AVR this is in math.h?
#define square(x) ((x)*(x))
-#ifndef strncpy_P
- #define strncpy_P(dest, src, num) strncpy((dest), (src), (num))
-#endif
-
-// Fix bug in pgm_read_ptr
-#undef pgm_read_ptr
-#define pgm_read_ptr(addr) (*(addr))
-
#define RST_POWER_ON 1
#define RST_EXTERNAL 2
#define RST_BROWN_OUT 4
diff --git a/Marlin/src/HAL/STM32F1/MarlinSerial.cpp b/Marlin/src/HAL/STM32F1/MarlinSerial.cpp
index 7c9625d64cd2..c404e81b35e8 100644
--- a/Marlin/src/HAL/STM32F1/MarlinSerial.cpp
+++ b/Marlin/src/HAL/STM32F1/MarlinSerial.cpp
@@ -28,7 +28,7 @@
// Copied from ~/.platformio/packages/framework-arduinoststm32-maple/STM32F1/system/libmaple/usart_private.h
// Changed to handle Emergency Parser
-static inline __always_inline void my_usart_irq(ring_buffer *rb, ring_buffer *wb, usart_reg_map *regs, MarlinSerial &serial) {
+static inline __always_inline void my_usart_irq(ring_buffer *rb, ring_buffer *wb, usart_reg_map *regs, MSerialT &serial) {
/* Handle RXNEIE and TXEIE interrupts.
* RXNE signifies availability of a byte in DR.
*
@@ -90,20 +90,20 @@ constexpr bool serial_handles_emergency(int port) {
;
}
-#define DEFINE_HWSERIAL_MARLIN(name, n) \
- MarlinSerial name(USART##n, \
- BOARD_USART##n##_TX_PIN, \
- BOARD_USART##n##_RX_PIN, \
- serial_handles_emergency(n)); \
- extern "C" void __irq_usart##n(void) { \
+#define DEFINE_HWSERIAL_MARLIN(name, n) \
+ MSerialT name(serial_handles_emergency(n),\
+ USART##n, \
+ BOARD_USART##n##_TX_PIN, \
+ BOARD_USART##n##_RX_PIN); \
+ extern "C" void __irq_usart##n(void) { \
my_usart_irq(USART##n->rb, USART##n->wb, USART##n##_BASE, MSerial##n); \
}
#define DEFINE_HWSERIAL_UART_MARLIN(name, n) \
- MarlinSerial name(UART##n, \
+ MSerialT name(serial_handles_emergency(n), \
+ UART##n, \
BOARD_USART##n##_TX_PIN, \
- BOARD_USART##n##_RX_PIN, \
- serial_handles_emergency(n)); \
+ BOARD_USART##n##_RX_PIN); \
extern "C" void __irq_usart##n(void) { \
my_usart_irq(UART##n->rb, UART##n->wb, UART##n##_BASE, MSerial##n); \
}
diff --git a/Marlin/src/HAL/STM32F1/MarlinSerial.h b/Marlin/src/HAL/STM32F1/MarlinSerial.h
index 6aa94b64fff7..692e97e61832 100644
--- a/Marlin/src/HAL/STM32F1/MarlinSerial.h
+++ b/Marlin/src/HAL/STM32F1/MarlinSerial.h
@@ -26,28 +26,13 @@
#include
#include "../../inc/MarlinConfigPre.h"
-#if ENABLED(EMERGENCY_PARSER)
- #include "../../feature/e_parser.h"
-#endif
+#include "../../core/serial_hook.h"
// Increase priority of serial interrupts, to reduce overflow errors
#define UART_IRQ_PRIO 1
-class MarlinSerial : public HardwareSerial {
-public:
- #if ENABLED(EMERGENCY_PARSER)
- const bool ep_enabled;
- EmergencyParser::State emergency_state;
- inline bool emergency_parser_enabled() { return ep_enabled; }
- #endif
-
- MarlinSerial(struct usart_dev *usart_device, uint8 tx_pin, uint8 rx_pin, bool TERN_(EMERGENCY_PARSER, ep_capable)) :
- HardwareSerial(usart_device, tx_pin, rx_pin)
- #if ENABLED(EMERGENCY_PARSER)
- , ep_enabled(ep_capable)
- , emergency_state(EmergencyParser::State::EP_RESET)
- #endif
- { }
+struct MarlinSerial : public HardwareSerial {
+ MarlinSerial(struct usart_dev *usart_device, uint8 tx_pin, uint8 rx_pin) : HardwareSerial(usart_device, tx_pin, rx_pin) { }
#ifdef UART_IRQ_PRIO
// Shadow the parent methods to set IRQ priority after begin()
@@ -62,10 +47,12 @@ class MarlinSerial : public HardwareSerial {
#endif
};
-extern MarlinSerial MSerial1;
-extern MarlinSerial MSerial2;
-extern MarlinSerial MSerial3;
+typedef Serial0Type MSerialT;
+
+extern MSerialT MSerial1;
+extern MSerialT MSerial2;
+extern MSerialT MSerial3;
#if EITHER(STM32_HIGH_DENSITY, STM32_XL_DENSITY)
- extern MarlinSerial MSerial4;
- extern MarlinSerial MSerial5;
+ extern MSerialT MSerial4;
+ extern MSerialT MSerial5;
#endif
diff --git a/Marlin/src/HAL/STM32F1/Servo.cpp b/Marlin/src/HAL/STM32F1/Servo.cpp
index e1ee83149374..36f7c6d51273 100644
--- a/Marlin/src/HAL/STM32F1/Servo.cpp
+++ b/Marlin/src/HAL/STM32F1/Servo.cpp
@@ -45,7 +45,7 @@ uint8_t ServoCount = 0;
*
* This uses the smallest prescaler that allows an overflow < 2^16.
*/
-#define MAX_OVERFLOW UINT16_MAX //((1 << 16) - 1)
+#define MAX_OVERFLOW UINT16_MAX // _BV(16) - 1
#define CYC_MSEC (1000 * CYCLES_PER_MICROSECOND)
#define TAU_MSEC 20
#define TAU_USEC (TAU_MSEC * 1000)
diff --git a/Marlin/src/HAL/STM32F1/eeprom_wired.cpp b/Marlin/src/HAL/STM32F1/eeprom_wired.cpp
index 6e992a22a32d..16cfc24af6f6 100644
--- a/Marlin/src/HAL/STM32F1/eeprom_wired.cpp
+++ b/Marlin/src/HAL/STM32F1/eeprom_wired.cpp
@@ -1,6 +1,5 @@
/**
* Marlin 3D Printer Firmware
- *
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* This program is free software: you can redistribute it and/or modify
diff --git a/Marlin/src/HAL/STM32F1/fastio.h b/Marlin/src/HAL/STM32F1/fastio.h
index a618fccc578e..e75254d6929e 100644
--- a/Marlin/src/HAL/STM32F1/fastio.h
+++ b/Marlin/src/HAL/STM32F1/fastio.h
@@ -29,9 +29,9 @@
#include
-#define READ(IO) (PIN_MAP[IO].gpio_device->regs->IDR & (1U << PIN_MAP[IO].gpio_bit) ? HIGH : LOW)
-#define WRITE(IO,V) (PIN_MAP[IO].gpio_device->regs->BSRR = (1U << PIN_MAP[IO].gpio_bit) << ((V) ? 0 : 16))
-#define TOGGLE(IO) (PIN_MAP[IO].gpio_device->regs->ODR = PIN_MAP[IO].gpio_device->regs->ODR ^ (1U << PIN_MAP[IO].gpio_bit))
+#define READ(IO) (PIN_MAP[IO].gpio_device->regs->IDR & _BV32(PIN_MAP[IO].gpio_bit) ? HIGH : LOW)
+#define WRITE(IO,V) (PIN_MAP[IO].gpio_device->regs->BSRR = _BV32(PIN_MAP[IO].gpio_bit) << ((V) ? 0 : 16))
+#define TOGGLE(IO) TBI32(PIN_MAP[IO].gpio_device->regs->ODR, PIN_MAP[IO].gpio_bit)
#define _GET_MODE(IO) gpio_get_mode(PIN_MAP[IO].gpio_device, PIN_MAP[IO].gpio_bit)
#define _SET_MODE(IO,M) gpio_set_mode(PIN_MAP[IO].gpio_device, PIN_MAP[IO].gpio_bit, M)
diff --git a/Marlin/src/HAL/STM32F1/msc_sd.cpp b/Marlin/src/HAL/STM32F1/msc_sd.cpp
index ba722b8aebfe..a91618499995 100644
--- a/Marlin/src/HAL/STM32F1/msc_sd.cpp
+++ b/Marlin/src/HAL/STM32F1/msc_sd.cpp
@@ -19,11 +19,12 @@
#include "msc_sd.h"
#include "SPI.h"
+#include "usb_reg_map.h"
#define PRODUCT_ID 0x29
USBMassStorage MarlinMSC;
-MarlinUSBCompositeSerial MarlinCompositeSerial;
+Serial0Type MarlinCompositeSerial(true);
#include "../../inc/MarlinConfig.h"
@@ -41,14 +42,27 @@ MarlinUSBCompositeSerial MarlinCompositeSerial;
#endif
#if ENABLED(EMERGENCY_PARSER)
- void (*real_rx_callback)(void);
- void my_rx_callback(void) {
- real_rx_callback();
- int len = MarlinCompositeSerial.available();
- while (len-- > 0) // >0 because available() may return a negative value
- emergency_parser.update(MarlinCompositeSerial.emergency_state, MarlinCompositeSerial.peek());
- }
+// The original callback is not called (no way to retrieve address).
+// That callback detects a special STM32 reset sequence: this functionality is not essential
+// as M997 achieves the same.
+void my_rx_callback(unsigned int, void*) {
+ // max length of 16 is enough to contain all emergency commands
+ uint8 buf[16];
+
+ //rx is usbSerialPart.endpoints[2]
+ uint16 len = usb_get_ep_rx_count(usbSerialPart.endpoints[2].address);
+ uint32 total = composite_cdcacm_data_available();
+
+ if (len == 0 || total == 0 || !WITHIN(total, len, COUNT(buf)))
+ return;
+
+ // cannot get character by character due to bug in composite_cdcacm_peek_ex
+ len = composite_cdcacm_peek(buf, total);
+
+ for (uint32 i = 0; i < len; i++)
+ emergency_parser.update(MarlinCompositeSerial.emergency_state, buf[i+total-len]);
+}
#endif
void MSC_SD_init() {
@@ -73,9 +87,7 @@ void MSC_SD_init() {
MarlinCompositeSerial.registerComponent();
USBComposite.begin();
#if ENABLED(EMERGENCY_PARSER)
- //rx is usbSerialPart.endpoints[2]
- real_rx_callback = usbSerialPart.endpoints[2].callback;
- usbSerialPart.endpoints[2].callback = my_rx_callback;
+ composite_cdcacm_set_hooks(USBHID_CDCACM_HOOK_RX, my_rx_callback);
#endif
}
diff --git a/Marlin/src/HAL/STM32F1/msc_sd.h b/Marlin/src/HAL/STM32F1/msc_sd.h
index 1e4e4c44b1b5..151287f7a7e2 100644
--- a/Marlin/src/HAL/STM32F1/msc_sd.h
+++ b/Marlin/src/HAL/STM32F1/msc_sd.h
@@ -18,25 +18,9 @@
#include
#include "../../inc/MarlinConfigPre.h"
-#if ENABLED(EMERGENCY_PARSER)
- #include "../../feature/e_parser.h"
-#endif
-
-class MarlinUSBCompositeSerial : public USBCompositeSerial {
-public:
- MarlinUSBCompositeSerial() : USBCompositeSerial()
- #if ENABLED(EMERGENCY_PARSER)
- , emergency_state(EmergencyParser::State::EP_RESET)
- #endif
- { }
-
- #if ENABLED(EMERGENCY_PARSER)
- EmergencyParser::State emergency_state;
- inline bool emergency_parser_enabled() { return true; }
- #endif
-};
+#include "../../core/serial_hook.h"
extern USBMassStorage MarlinMSC;
-extern MarlinUSBCompositeSerial MarlinCompositeSerial;
+extern Serial0Type MarlinCompositeSerial;
void MSC_SD_init();
diff --git a/Marlin/src/HAL/TEENSY31_32/HAL.cpp b/Marlin/src/HAL/TEENSY31_32/HAL.cpp
index 8c3dd8337740..51636d29bf14 100644
--- a/Marlin/src/HAL/TEENSY31_32/HAL.cpp
+++ b/Marlin/src/HAL/TEENSY31_32/HAL.cpp
@@ -31,6 +31,9 @@
#include
+DefaultSerial MSerial(false);
+USBSerialType USBSerial(false, SerialUSB);
+
uint16_t HAL_adc_result;
static const uint8_t pin2sc1a[] = {
diff --git a/Marlin/src/HAL/TEENSY31_32/HAL.h b/Marlin/src/HAL/TEENSY31_32/HAL.h
index 9156aadb4de0..5273b3863774 100644
--- a/Marlin/src/HAL/TEENSY31_32/HAL.h
+++ b/Marlin/src/HAL/TEENSY31_32/HAL.h
@@ -50,12 +50,18 @@
#define IS_TEENSY32 1
#endif
-#define _MSERIAL(X) Serial##X
+#include "../../core/serial_hook.h"
+typedef Serial0Type DefaultSerial;
+extern DefaultSerial MSerial;
+typedef ForwardSerial0Type USBSerialType;
+extern USBSerialType USBSerial;
+
+#define _MSERIAL(X) MSerial##X
#define MSERIAL(X) _MSERIAL(X)
-#define Serial0 Serial
+#define MSerial0 MSerial
#if SERIAL_PORT == -1
- #define MYSERIAL0 SerialUSB
+ #define MYSERIAL0 USBSerial
#elif WITHIN(SERIAL_PORT, 0, 3)
#define MYSERIAL0 MSERIAL(SERIAL_PORT)
#endif
@@ -74,17 +80,6 @@ typedef int8_t pin_t;
#define ENABLE_ISRS() __enable_irq()
#define DISABLE_ISRS() __disable_irq()
-#ifndef strncpy_P
- #define strncpy_P(dest, src, num) strncpy((dest), (src), (num))
-#endif
-
-// Fix bug in pgm_read_ptr
-#undef pgm_read_ptr
-#define pgm_read_ptr(addr) (*((void**)(addr)))
-// Add type-checking to pgm_read_word
-#undef pgm_read_word
-#define pgm_read_word(addr) (*((uint16_t*)(addr)))
-
inline void HAL_init() {}
// Clear the reset reason
diff --git a/Marlin/src/HAL/TEENSY31_32/fastio.h b/Marlin/src/HAL/TEENSY31_32/fastio.h
index 9a299de9c763..622799ec8cac 100644
--- a/Marlin/src/HAL/TEENSY31_32/fastio.h
+++ b/Marlin/src/HAL/TEENSY31_32/fastio.h
@@ -28,7 +28,7 @@
*/
#ifndef MASK
- #define MASK(PIN) (1 << PIN)
+ #define MASK(PIN) _BV(PIN)
#endif
#define GPIO_BITBAND_ADDR(reg, bit) (((uint32_t)&(reg) - 0x40000000) * 32 + (bit) * 4 + 0x42000000)
diff --git a/Marlin/src/HAL/TEENSY35_36/HAL.cpp b/Marlin/src/HAL/TEENSY35_36/HAL.cpp
index 92907353b833..547681de5f12 100644
--- a/Marlin/src/HAL/TEENSY35_36/HAL.cpp
+++ b/Marlin/src/HAL/TEENSY35_36/HAL.cpp
@@ -31,6 +31,9 @@
#include
+DefaultSerial MSerial(false);
+USBSerialType USBSerial(false, SerialUSB);
+
uint16_t HAL_adc_result, HAL_adc_select;
static const uint8_t pin2sc1a[] = {
diff --git a/Marlin/src/HAL/TEENSY35_36/HAL.h b/Marlin/src/HAL/TEENSY35_36/HAL.h
index 04151e837861..94c514bf6275 100644
--- a/Marlin/src/HAL/TEENSY35_36/HAL.h
+++ b/Marlin/src/HAL/TEENSY35_36/HAL.h
@@ -53,12 +53,18 @@
#define IS_TEENSY35 1
#endif
-#define _MSERIAL(X) Serial##X
+#include "../../core/serial_hook.h"
+typedef Serial0Type DefaultSerial;
+extern DefaultSerial MSerial;
+typedef ForwardSerial0Type USBSerialType;
+extern USBSerialType USBSerial;
+
+#define _MSERIAL(X) MSerial##X
#define MSERIAL(X) _MSERIAL(X)
-#define Serial0 Serial
+#define MSerial0 MSerial
#if SERIAL_PORT == -1
- #define MYSERIAL0 SerialUSB
+ #define MYSERIAL0 USBSerial
#elif WITHIN(SERIAL_PORT, 0, 3)
#define MYSERIAL0 MSERIAL(SERIAL_PORT)
#endif
@@ -80,17 +86,6 @@ typedef int8_t pin_t;
#undef sq
#define sq(x) ((x)*(x))
-#ifndef strncpy_P
- #define strncpy_P(dest, src, num) strncpy((dest), (src), (num))
-#endif
-
-// Fix bug in pgm_read_ptr
-#undef pgm_read_ptr
-#define pgm_read_ptr(addr) (*((void**)(addr)))
-// Add type-checking to pgm_read_word
-#undef pgm_read_word
-#define pgm_read_word(addr) (*((uint16_t*)(addr)))
-
inline void HAL_init() {}
// Clear reset reason
diff --git a/Marlin/src/HAL/TEENSY35_36/fastio.h b/Marlin/src/HAL/TEENSY35_36/fastio.h
index 9a299de9c763..622799ec8cac 100644
--- a/Marlin/src/HAL/TEENSY35_36/fastio.h
+++ b/Marlin/src/HAL/TEENSY35_36/fastio.h
@@ -28,7 +28,7 @@
*/
#ifndef MASK
- #define MASK(PIN) (1 << PIN)
+ #define MASK(PIN) _BV(PIN)
#endif
#define GPIO_BITBAND_ADDR(reg, bit) (((uint32_t)&(reg) - 0x40000000) * 32 + (bit) * 4 + 0x42000000)
diff --git a/Marlin/src/HAL/TEENSY40_41/HAL.cpp b/Marlin/src/HAL/TEENSY40_41/HAL.cpp
index 5b1b4272f5ee..26449d7eb298 100644
--- a/Marlin/src/HAL/TEENSY40_41/HAL.cpp
+++ b/Marlin/src/HAL/TEENSY40_41/HAL.cpp
@@ -32,6 +32,9 @@
#include
+DefaultSerial MSerial(false);
+USBSerialType USBSerial(false, SerialUSB);
+
uint16_t HAL_adc_result, HAL_adc_select;
static const uint8_t pin2sc1a[] = {
diff --git a/Marlin/src/HAL/TEENSY40_41/HAL.h b/Marlin/src/HAL/TEENSY40_41/HAL.h
index 28f511631eea..6aa1e521a48b 100644
--- a/Marlin/src/HAL/TEENSY40_41/HAL.h
+++ b/Marlin/src/HAL/TEENSY40_41/HAL.h
@@ -37,6 +37,10 @@
#include
#include
+#if HAS_ETHERNET
+ #include "../../feature/ethernet.h"
+#endif
+
//#define ST7920_DELAY_1 DELAY_NS(600)
//#define ST7920_DELAY_2 DELAY_NS(750)
//#define ST7920_DELAY_3 DELAY_NS(750)
@@ -51,9 +55,15 @@
#define IS_TEENSY41 1
#endif
-#define _MSERIAL(X) Serial##X
+#include "../../core/serial_hook.h"
+typedef Serial0Type DefaultSerial;
+extern DefaultSerial MSerial;
+typedef ForwardSerial0Type USBSerialType;
+extern USBSerialType USBSerial;
+
+#define _MSERIAL(X) MSerial##X
#define MSERIAL(X) _MSERIAL(X)
-#define Serial0 Serial
+#define MSerial0 MSerial
#if SERIAL_PORT == -1
#define MYSERIAL0 SerialUSB
@@ -92,21 +102,10 @@ typedef int8_t pin_t;
#undef sq
#define sq(x) ((x)*(x))
-#ifndef strncpy_P
- #define strncpy_P(dest, src, num) strncpy((dest), (src), (num))
-#endif
-
// Don't place string constants in PROGMEM
#undef PSTR
#define PSTR(str) ({static const char *data = (str); &data[0];})
-// Fix bug in pgm_read_ptr
-#undef pgm_read_ptr
-#define pgm_read_ptr(addr) (*((void**)(addr)))
-// Add type-checking to pgm_read_word
-#undef pgm_read_word
-#define pgm_read_word(addr) (*((uint16_t*)(addr)))
-
// Enable hooks into idle and setup for HAL
#define HAL_IDLETASK 1
FORCE_INLINE void HAL_idletask() {}
diff --git a/Marlin/src/HAL/shared/Delay.cpp b/Marlin/src/HAL/shared/Delay.cpp
new file mode 100644
index 000000000000..1ae1b3e381fd
--- /dev/null
+++ b/Marlin/src/HAL/shared/Delay.cpp
@@ -0,0 +1,176 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+#include "Delay.h"
+
+#include "../../inc/MarlinConfig.h"
+
+#if defined(__arm__) || defined(__thumb__)
+
+ static uint32_t ASM_CYCLES_PER_ITERATION = 4; // Initial bet which will be adjusted in calibrate_delay_loop
+
+ // Simple assembler loop counting down
+ void delay_asm(uint32_t cy) {
+ cy = _MAX(cy / ASM_CYCLES_PER_ITERATION, 1U); // Zero is forbidden here
+ __asm__ __volatile__(
+ A(".syntax unified") // is to prevent CM0,CM1 non-unified syntax
+ L("1")
+ A("subs %[cnt],#1")
+ A("bne 1b")
+ : [cnt]"+r"(cy) // output: +r means input+output
+ : // input:
+ : "cc" // clobbers:
+ );
+ }
+
+ // We can't use CMSIS since it's not available on all platform, so fallback to hardcoded register values
+ #define HW_REG(X) *(volatile uint32_t *)(X)
+ #define _DWT_CTRL 0xE0001000
+ #define _DWT_CYCCNT 0xE0001004 // CYCCNT is 32bits, takes 37s or so to wrap.
+ #define _DEM_CR 0xE000EDFC
+ #define _LAR 0xE0001FB0
+
+ // Use hardware cycle counter instead, it's much safer
+ void delay_dwt(uint32_t count) {
+ // Reuse the ASM_CYCLES_PER_ITERATION variable to avoid wasting another useless variable
+ register uint32_t start = HW_REG(_DWT_CYCCNT) - ASM_CYCLES_PER_ITERATION, elapsed;
+ do {
+ elapsed = HW_REG(_DWT_CYCCNT) - start;
+ } while (elapsed < count);
+ }
+
+ // Pointer to asm function, calling the functions has a ~20 cycles overhead
+ DelayImpl DelayCycleFnc = delay_asm;
+
+ void calibrate_delay_loop() {
+ // Check if we have a working DWT implementation in the CPU (see https://developer.arm.com/documentation/ddi0439/b/Data-Watchpoint-and-Trace-Unit/DWT-Programmers-Model)
+ if (!HW_REG(_DWT_CTRL)) {
+ // No DWT present, so fallback to plain old ASM nop counting
+ // Unfortunately, we don't exactly know how many iteration it'll take to decrement a counter in a loop
+ // It depends on the CPU architecture, the code current position (flash vs SRAM)
+ // So, instead of wild guessing and making mistake, instead
+ // compute it once for all
+ ASM_CYCLES_PER_ITERATION = 1;
+ // We need to fetch some reference clock before waiting
+ cli();
+ uint32_t start = micros();
+ delay_asm(1000); // On a typical CPU running in MHz, waiting 1000 "unknown cycles" means it'll take between 1ms to 6ms, that's perfectly acceptable
+ uint32_t end = micros();
+ sei();
+ uint32_t expectedCycles = (end - start) * ((F_CPU) / 1000000UL); // Convert microseconds to cycles
+ // Finally compute the right scale
+ ASM_CYCLES_PER_ITERATION = (uint32_t)(expectedCycles / 1000);
+
+ // No DWT present, likely a Cortex M0 so NOP counting is our best bet here
+ DelayCycleFnc = delay_asm;
+ }
+ else {
+ // Enable DWT counter
+ // From https://stackoverflow.com/a/41188674/1469714
+ HW_REG(_DEM_CR) = HW_REG(_DEM_CR) | 0x01000000; // Enable trace
+ #if __CORTEX_M == 7
+ HW_REG(_LAR) = 0xC5ACCE55; // Unlock access to DWT registers, see https://developer.arm.com/documentation/ihi0029/e/ section B2.3.10
+ #endif
+ HW_REG(_DWT_CYCCNT) = 0; // Clear DWT cycle counter
+ HW_REG(_DWT_CTRL) = HW_REG(_DWT_CTRL) | 1; // Enable DWT cycle counter
+
+ // Then calibrate the constant offset from the counter
+ ASM_CYCLES_PER_ITERATION = 0;
+ uint32_t s = HW_REG(_DWT_CYCCNT);
+ uint32_t e = HW_REG(_DWT_CYCCNT); // (e - s) contains the number of cycle required to read the cycle counter
+ delay_dwt(0);
+ uint32_t f = HW_REG(_DWT_CYCCNT); // (f - e) contains the delay to call the delay function + the time to read the cycle counter
+ ASM_CYCLES_PER_ITERATION = (f - e) - (e - s);
+
+ // Use safer DWT function
+ DelayCycleFnc = delay_dwt;
+ }
+ }
+
+ #if ENABLED(MARLIN_DEV_MODE)
+ void dump_delay_accuracy_check()
+ {
+ auto report_call_time = [](PGM_P const name, const uint32_t cycles, const uint32_t total, const bool do_flush=true) {
+ SERIAL_ECHOPGM("Calling ");
+ serialprintPGM(name);
+ SERIAL_ECHOLNPAIR(" for ", cycles, "cycles took: ", total, "cycles");
+ if (do_flush) SERIAL_FLUSH();
+ };
+
+ uint32_t s, e;
+
+ SERIAL_ECHOLNPAIR("Computed delay calibration value: ", ASM_CYCLES_PER_ITERATION);
+ SERIAL_FLUSH();
+ // Display the results of the calibration above
+ constexpr uint32_t testValues[] = { 1, 5, 10, 20, 50, 100, 150, 200, 350, 500, 750, 1000 };
+ for (auto i : testValues) {
+ s = micros(); DELAY_US(i); e = micros();
+ report_call_time(PSTR("delay"), i, e - s);
+ }
+
+ if (HW_REG(_DWT_CTRL)) {
+ for (auto i : testValues) {
+ s = HW_REG(_DWT_CYCCNT); DELAY_CYCLES(i); e = HW_REG(_DWT_CYCCNT);
+ report_call_time(PSTR("delay"), i, e - s);
+ }
+
+ // Measure the delay to call a real function compared to a function pointer
+ s = HW_REG(_DWT_CYCCNT); delay_dwt(1); e = HW_REG(_DWT_CYCCNT);
+ report_call_time(PSTR("delay_dwt"), 1, e - s);
+
+ static PGMSTR(dcd, "DELAY_CYCLES directly ");
+
+ s = HW_REG(_DWT_CYCCNT); DELAY_CYCLES( 1); e = HW_REG(_DWT_CYCCNT);
+ report_call_time(dcd, 1, e - s, false);
+
+ s = HW_REG(_DWT_CYCCNT); DELAY_CYCLES( 5); e = HW_REG(_DWT_CYCCNT);
+ report_call_time(dcd, 5, e - s, false);
+
+ s = HW_REG(_DWT_CYCCNT); DELAY_CYCLES(10); e = HW_REG(_DWT_CYCCNT);
+ report_call_time(dcd, 10, e - s, false);
+
+ s = HW_REG(_DWT_CYCCNT); DELAY_CYCLES(20); e = HW_REG(_DWT_CYCCNT);
+ report_call_time(dcd, 20, e - s, false);
+
+ s = HW_REG(_DWT_CYCCNT); DELAY_CYCLES(50); e = HW_REG(_DWT_CYCCNT);
+ report_call_time(dcd, 50, e - s, false);
+
+ s = HW_REG(_DWT_CYCCNT); DELAY_CYCLES(100); e = HW_REG(_DWT_CYCCNT);
+ report_call_time(dcd, 100, e - s, false);
+
+ s = HW_REG(_DWT_CYCCNT); DELAY_CYCLES(200); e = HW_REG(_DWT_CYCCNT);
+ report_call_time(dcd, 200, e - s, false);
+ }
+ }
+ #endif // MARLIN_DEV_MODE
+
+
+#else
+
+ void calibrate_delay_loop() {}
+ #if ENABLED(MARLIN_DEV_MODE)
+ void dump_delay_accuracy_check() {
+ static PGMSTR(none, "N/A on this platform");
+ serialprintPGM(none);
+ }
+ #endif
+
+#endif
diff --git a/Marlin/src/HAL/shared/Delay.h b/Marlin/src/HAL/shared/Delay.h
index a48f3f79cfd0..dc1f158b44ae 100644
--- a/Marlin/src/HAL/shared/Delay.h
+++ b/Marlin/src/HAL/shared/Delay.h
@@ -21,6 +21,8 @@
*/
#pragma once
+#include "../../inc/MarlinConfigPre.h"
+
/**
* Busy wait delay cycles routines:
*
@@ -31,79 +33,68 @@
#include "../../core/macros.h"
-#if defined(__arm__) || defined(__thumb__)
-
- #if __CORTEX_M == 7
+void calibrate_delay_loop();
- // Cortex-M3 through M7 can use the cycle counter of the DWT unit
- // https://www.anthonyvh.com/2017/05/18/cortex_m-cycle_counter/
+#if defined(__arm__) || defined(__thumb__)
- FORCE_INLINE static void enableCycleCounter() {
- CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
+ // We want to have delay_cycle function with the lowest possible overhead, so we adjust at the function at runtime based on the current CPU best feature
+ typedef void (*DelayImpl)(uint32_t);
+ extern DelayImpl DelayCycleFnc;
- #if __CORTEX_M == 7
- DWT->LAR = 0xC5ACCE55; // Unlock DWT on the M7
- #endif
+ // I've measured 36 cycles on my system to call the cycle waiting method, but it shouldn't change much to have a bit more margin, it only consume a bit more flash
+ #define TRIP_POINT_FOR_CALLING_FUNCTION 40
- DWT->CYCCNT = 0;
- DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
+ // A simple recursive template class that output exactly one 'nop' of code per recursion
+ template struct NopWriter {
+ FORCE_INLINE static void build() {
+ __asm__ __volatile__("nop");
+ NopWriter::build();
}
+ };
+ // End the loop
+ template <> struct NopWriter<0> { FORCE_INLINE static void build() {} };
+
+ namespace Private {
+ // Split recursing template in 2 different class so we don't reach the maximum template instantiation depth limit
+ template struct Helper {
+ FORCE_INLINE static void build() {
+ DelayCycleFnc(N - 2); // Approximative cost of calling the function (might be off by one or 2 cycles)
+ }
+ };
- FORCE_INLINE volatile uint32_t getCycleCount() { return DWT->CYCCNT; }
+ template struct Helper {
+ FORCE_INLINE static void build() {
+ NopWriter::build();
+ }
+ };
- FORCE_INLINE static void DELAY_CYCLES(const uint32_t x) {
- const uint32_t endCycles = getCycleCount() + x;
- while (PENDING(getCycleCount(), endCycles)) {}
- }
+ template <> struct Helper {
+ FORCE_INLINE static void build() {}
+ };
- #else
-
- // https://blueprints.launchpad.net/gcc-arm-embedded/+spec/delay-cycles
-
- #define nop() __asm__ __volatile__("nop;\n\t":::)
-
- FORCE_INLINE static void __delay_4cycles(uint32_t cy) { // +1 cycle
- #if ARCH_PIPELINE_RELOAD_CYCLES < 2
- #define EXTRA_NOP_CYCLES A("nop")
- #else
- #define EXTRA_NOP_CYCLES ""
- #endif
-
- __asm__ __volatile__(
- A(".syntax unified") // is to prevent CM0,CM1 non-unified syntax
- L("1")
- A("subs %[cnt],#1")
- EXTRA_NOP_CYCLES
- A("bne 1b")
- : [cnt]"+r"(cy) // output: +r means input+output
- : // input:
- : "cc" // clobbers:
- );
+ }
+ // Select a behavior based on the constexpr'ness of the parameter
+ // If called with a compile-time parameter, then write as many NOP as required to reach the asked cycle count
+ // (there is some tripping point here to start looping when it's more profitable than gruntly executing NOPs)
+ // If not called from a compile-time parameter, fallback to a runtime loop counting version instead
+ template
+ struct SmartDelay {
+ FORCE_INLINE SmartDelay(int) {
+ if (Cycles == 0) return;
+ Private::Helper::build();
}
+ };
+ // Runtime version below. There is no way this would run under less than ~TRIP_POINT_FOR_CALLING_FUNCTION cycles
+ template
+ struct SmartDelay {
+ FORCE_INLINE SmartDelay(int v) { DelayCycleFnc(v); }
+ };
- // Delay in cycles
- FORCE_INLINE static void DELAY_CYCLES(uint32_t x) {
-
- if (__builtin_constant_p(x)) {
- #define MAXNOPS 4
-
- if (x <= (MAXNOPS)) {
- switch (x) { case 4: nop(); case 3: nop(); case 2: nop(); case 1: nop(); }
- }
- else { // because of +1 cycle inside delay_4cycles
- const uint32_t rem = (x - 1) % (MAXNOPS);
- switch (rem) { case 3: nop(); case 2: nop(); case 1: nop(); }
- if ((x = (x - 1) / (MAXNOPS)))
- __delay_4cycles(x); // if need more then 4 nop loop is more optimal
- }
- #undef MAXNOPS
- }
- else if ((x >>= 2))
- __delay_4cycles(x);
- }
- #undef nop
+ #define DELAY_CYCLES(X) do { SmartDelay _smrtdly_X(X); } while(0)
- #endif
+ // For delay in microseconds, no smart delay selection is required, directly call the delay function
+ // Teensy compiler is too old and does not accept smart delay compile-time / run-time selection correctly
+ #define DELAY_US(x) DelayCycleFnc((x) * ((F_CPU) / 1000000UL))
#elif defined(__AVR__)
@@ -144,10 +135,15 @@
}
#undef nop
+ // Delay in microseconds
+ #define DELAY_US(x) DELAY_CYCLES((x) * ((F_CPU) / 1000000UL))
+
#elif defined(__PLAT_LINUX__) || defined(ESP32)
- // specified inside platform
+ // DELAY_CYCLES specified inside platform
+ // Delay in microseconds
+ #define DELAY_US(x) DELAY_CYCLES((x) * ((F_CPU) / 1000000UL))
#else
#error "Unsupported MCU architecture"
@@ -157,5 +153,5 @@
// Delay in nanoseconds
#define DELAY_NS(x) DELAY_CYCLES((x) * ((F_CPU) / 1000000UL) / 1000UL)
-// Delay in microseconds
-#define DELAY_US(x) DELAY_CYCLES((x) * ((F_CPU) / 1000000UL))
+
+
diff --git a/Marlin/src/HAL/shared/Marduino.h b/Marlin/src/HAL/shared/Marduino.h
index 3003f3cc2891..d0ee6ecc9d43 100644
--- a/Marlin/src/HAL/shared/Marduino.h
+++ b/Marlin/src/HAL/shared/Marduino.h
@@ -28,9 +28,9 @@
#undef DISABLED // Redefined by ESP32
#undef M_PI // Redefined by all
#undef _BV // Redefined by some
-#undef sq // Redefined by teensy3/wiring.h
#undef SBI // Redefined by arduino/const_functions.h
#undef CBI // Redefined by arduino/const_functions.h
+#undef sq // Redefined by teensy3/wiring.h
#undef UNUSED // Redefined by stm32f4xx_hal_def.h
#include // NOTE: If included earlier then this line is a NOOP
@@ -40,18 +40,16 @@
#undef _BV
#define _BV(b) (1UL << (b))
-
-#undef sq
-#define sq(x) ((x)*(x))
-
#ifndef SBI
- #define SBI(A,B) (A |= (1 << (B)))
+ #define SBI(A,B) (A |= _BV(B))
#endif
-
#ifndef CBI
- #define CBI(A,B) (A &= ~(1 << (B)))
+ #define CBI(A,B) (A &= ~_BV(B))
#endif
+#undef sq
+#define sq(x) ((x)*(x))
+
#ifndef __AVR__
#ifndef strchr_P // Some platforms define a macro (DUE, teensy35)
inline const char* strchr_P(const char *s, int c) { return strchr(s,c); }
@@ -83,3 +81,5 @@
#ifndef UNUSED
#define UNUSED(x) ((void)(x))
#endif
+
+#include "progmem.h"
diff --git a/Marlin/src/HAL/shared/backtrace/backtrace.cpp b/Marlin/src/HAL/shared/backtrace/backtrace.cpp
index 6cf5e055e151..4a8990c00b83 100644
--- a/Marlin/src/HAL/shared/backtrace/backtrace.cpp
+++ b/Marlin/src/HAL/shared/backtrace/backtrace.cpp
@@ -34,10 +34,10 @@ static bool UnwReportOut(void* ctx, const UnwReport* bte) {
(*p)++;
- SERIAL_CHAR('#'); SERIAL_PRINT(*p, DEC); SERIAL_ECHOPGM(" : ");
- SERIAL_ECHOPGM(bte->name ? bte->name : "unknown"); SERIAL_ECHOPGM("@0x"); SERIAL_PRINT(bte->function, HEX);
- SERIAL_CHAR('+'); SERIAL_PRINT(bte->address - bte->function,DEC);
- SERIAL_ECHOPGM(" PC:"); SERIAL_PRINT(bte->address,HEX); SERIAL_CHAR('\n');
+ SERIAL_CHAR('#'); SERIAL_ECHO(*p); SERIAL_ECHOPGM(" : ");
+ SERIAL_ECHOPGM(bte->name ? bte->name : "unknown"); SERIAL_ECHOPGM("@0x"); SERIAL_PRINT(bte->function, PrintBase::Hex);
+ SERIAL_CHAR('+'); SERIAL_ECHO(bte->address - bte->function);
+ SERIAL_ECHOPGM(" PC:"); SERIAL_PRINT(bte->address, PrintBase::Hex); SERIAL_CHAR('\n');
return true;
}
diff --git a/Marlin/src/HAL/shared/backtrace/unwarmbytab.cpp b/Marlin/src/HAL/shared/backtrace/unwarmbytab.cpp
index bfc062af2090..f1ee81ed4acb 100644
--- a/Marlin/src/HAL/shared/backtrace/unwarmbytab.cpp
+++ b/Marlin/src/HAL/shared/backtrace/unwarmbytab.cpp
@@ -128,11 +128,8 @@ static UnwResult UnwTabStateInit(const UnwindCallbacks *cb, UnwTabState *ucb, ui
* Execute unwinding instructions
*/
static UnwResult UnwTabExecuteInstructions(const UnwindCallbacks *cb, UnwTabState *ucb) {
-
int instruction;
- uint32_t mask;
- uint32_t reg;
- uint32_t vsp;
+ uint32_t mask, reg, vsp;
/* Consume all instruction byte */
while ((instruction = UnwTabGetNextInstruction(cb, ucb)) != -1) {
@@ -140,12 +137,12 @@ static UnwResult UnwTabExecuteInstructions(const UnwindCallbacks *cb, UnwTabStat
if ((instruction & 0xC0) == 0x00) { // ARM_EXIDX_CMD_DATA_POP
/* vsp = vsp + (xxxxxx << 2) + 4 */
ucb->vrs[13] += ((instruction & 0x3F) << 2) + 4;
- } else
- if ((instruction & 0xC0) == 0x40) { // ARM_EXIDX_CMD_DATA_PUSH
+ }
+ else if ((instruction & 0xC0) == 0x40) { // ARM_EXIDX_CMD_DATA_PUSH
/* vsp = vsp - (xxxxxx << 2) - 4 */
ucb->vrs[13] -= ((instruction & 0x3F) << 2) - 4;
- } else
- if ((instruction & 0xF0) == 0x80) {
+ }
+ else if ((instruction & 0xF0) == 0x80) {
/* pop under mask {r15-r12},{r11-r4} or refuse to unwind */
instruction = instruction << 8 | UnwTabGetNextInstruction(cb, ucb);
@@ -171,17 +168,17 @@ static UnwResult UnwTabExecuteInstructions(const UnwindCallbacks *cb, UnwTabStat
}
/* Patch up the vrs sp if it was in the mask */
- if ((instruction & (1 << (13 - 4))) != 0)
+ if (instruction & (1 << (13 - 4)))
ucb->vrs[13] = vsp;
-
- } else
- if ((instruction & 0xF0) == 0x90 && // ARM_EXIDX_CMD_REG_TO_SP
- instruction != 0x9D &&
- instruction != 0x9F) {
+ }
+ else if ((instruction & 0xF0) == 0x90 // ARM_EXIDX_CMD_REG_TO_SP
+ && instruction != 0x9D
+ && instruction != 0x9F
+ ) {
/* vsp = r[nnnn] */
ucb->vrs[13] = ucb->vrs[instruction & 0x0F];
- } else
- if ((instruction & 0xF0) == 0xA0) { // ARM_EXIDX_CMD_REG_POP
+ }
+ else if ((instruction & 0xF0) == 0xA0) { // ARM_EXIDX_CMD_REG_POP
/* pop r4-r[4+nnn] or pop r4-r[4+nnn], r14*/
vsp = ucb->vrs[13];
@@ -204,8 +201,8 @@ static UnwResult UnwTabExecuteInstructions(const UnwindCallbacks *cb, UnwTabStat
ucb->vrs[13] = vsp;
- } else
- if (instruction == 0xB0) { // ARM_EXIDX_CMD_FINISH
+ }
+ else if (instruction == 0xB0) { // ARM_EXIDX_CMD_FINISH
/* finished */
if (ucb->vrs[15] == 0)
ucb->vrs[15] = ucb->vrs[14];
@@ -213,8 +210,8 @@ static UnwResult UnwTabExecuteInstructions(const UnwindCallbacks *cb, UnwTabStat
/* All done unwinding */
return UNWIND_SUCCESS;
- } else
- if (instruction == 0xB1) { // ARM_EXIDX_CMD_REG_POP
+ }
+ else if (instruction == 0xB1) { // ARM_EXIDX_CMD_REG_POP
/* pop register under mask {r3,r2,r1,r0} */
vsp = ucb->vrs[13];
mask = UnwTabGetNextInstruction(cb, ucb);
@@ -234,16 +231,15 @@ static UnwResult UnwTabExecuteInstructions(const UnwindCallbacks *cb, UnwTabStat
}
ucb->vrs[13] = (uint32_t)vsp;
- } else
- if (instruction == 0xB2) { // ARM_EXIDX_CMD_DATA_POP
+ }
+ else if (instruction == 0xB2) { // ARM_EXIDX_CMD_DATA_POP
/* vps = vsp + 0x204 + (uleb128 << 2) */
ucb->vrs[13] += 0x204 + (UnwTabGetNextInstruction(cb, ucb) << 2);
-
- } else
- if (instruction == 0xB3 || // ARM_EXIDX_CMD_VFP_POP
- instruction == 0xC8 ||
- instruction == 0xC9) {
-
+ }
+ else if (instruction == 0xB3 // ARM_EXIDX_CMD_VFP_POP
+ || instruction == 0xC8
+ || instruction == 0xC9
+ ) {
/* pop VFP double-precision registers */
vsp = ucb->vrs[13];
@@ -266,27 +262,20 @@ static UnwResult UnwTabExecuteInstructions(const UnwindCallbacks *cb, UnwTabStat
}
ucb->vrs[13] = vsp;
-
- } else
- if ((instruction & 0xF8) == 0xB8 ||
- (instruction & 0xF8) == 0xD0) {
-
+ }
+ else if ((instruction & 0xF8) == 0xB8 || (instruction & 0xF8) == 0xD0) {
/* Pop VFP double precision registers D[8]-D[8+nnn] */
ucb->vrs[14] = 0x80 | (instruction & 0x07);
-
- if ((instruction & 0xF8) == 0xD0) {
+ if ((instruction & 0xF8) == 0xD0)
ucb->vrs[14] = 1 << 17;
- }
-
- } else
+ }
+ else
return UNWIND_UNSUPPORTED_DWARF_INSTR;
}
-
return UNWIND_SUCCESS;
}
static inline __attribute__((always_inline)) uint32_t read_psp() {
-
/* Read the current PSP and return its value as a pointer */
uint32_t psp;
diff --git a/Marlin/src/HAL/shared/progmem.h b/Marlin/src/HAL/shared/progmem.h
new file mode 100644
index 000000000000..539d02705e97
--- /dev/null
+++ b/Marlin/src/HAL/shared/progmem.h
@@ -0,0 +1,189 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+#pragma once
+
+#ifndef __AVR__
+#ifndef __PGMSPACE_H_
+// This define should prevent reading the system pgmspace.h if included elsewhere
+// This is not normally needed.
+#define __PGMSPACE_H_ 1
+#endif
+
+#ifndef PROGMEM
+#define PROGMEM
+#endif
+#ifndef PGM_P
+#define PGM_P const char *
+#endif
+#ifndef PSTR
+#define PSTR(str) (str)
+#endif
+#ifndef F
+#define F(str) (str)
+#endif
+#ifndef _SFR_BYTE
+#define _SFR_BYTE(n) (n)
+#endif
+#ifndef memchr_P
+#define memchr_P(str, c, len) memchr((str), (c), (len))
+#endif
+#ifndef memcmp_P
+#define memcmp_P(a, b, n) memcmp((a), (b), (n))
+#endif
+#ifndef memcpy_P
+#define memcpy_P(dest, src, num) memcpy((dest), (src), (num))
+#endif
+#ifndef memmem_P
+#define memmem_P(a, alen, b, blen) memmem((a), (alen), (b), (blen))
+#endif
+#ifndef memrchr_P
+#define memrchr_P(str, val, len) memrchr((str), (val), (len))
+#endif
+#ifndef strcat_P
+#define strcat_P(dest, src) strcat((dest), (src))
+#endif
+#ifndef strchr_P
+#define strchr_P(str, c) strchr((str), (c))
+#endif
+#ifndef strchrnul_P
+#define strchrnul_P(str, c) strchrnul((str), (c))
+#endif
+#ifndef strcmp_P
+#define strcmp_P(a, b) strcmp((a), (b))
+#endif
+#ifndef strcpy_P
+#define strcpy_P(dest, src) strcpy((dest), (src))
+#endif
+#ifndef strcasecmp_P
+#define strcasecmp_P(a, b) strcasecmp((a), (b))
+#endif
+#ifndef strcasestr_P
+#define strcasestr_P(a, b) strcasestr((a), (b))
+#endif
+#ifndef strlcat_P
+#define strlcat_P(dest, src, len) strlcat((dest), (src), (len))
+#endif
+#ifndef strlcpy_P
+#define strlcpy_P(dest, src, len) strlcpy((dest), (src), (len))
+#endif
+#ifndef strlen_P
+#define strlen_P(s) strlen((const char *)(s))
+#endif
+#ifndef strnlen_P
+#define strnlen_P(str, len) strnlen((str), (len))
+#endif
+#ifndef strncmp_P
+#define strncmp_P(a, b, n) strncmp((a), (b), (n))
+#endif
+#ifndef strncasecmp_P
+#define strncasecmp_P(a, b, n) strncasecmp((a), (b), (n))
+#endif
+#ifndef strncat_P
+#define strncat_P(a, b, n) strncat((a), (b), (n))
+#endif
+#ifndef strncpy_P
+#define strncpy_P(a, b, n) strncpy((a), (b), (n))
+#endif
+#ifndef strpbrk_P
+#define strpbrk_P(str, chrs) strpbrk((str), (chrs))
+#endif
+#ifndef strrchr_P
+#define strrchr_P(str, c) strrchr((str), (c))
+#endif
+#ifndef strsep_P
+#define strsep_P(strp, delim) strsep((strp), (delim))
+#endif
+#ifndef strspn_P
+#define strspn_P(str, chrs) strspn((str), (chrs))
+#endif
+#ifndef strstr_P
+#define strstr_P(a, b) strstr((a), (b))
+#endif
+#ifndef sprintf_P
+#define sprintf_P(s, ...) sprintf((s), __VA_ARGS__)
+#endif
+#ifndef vfprintf_P
+#define vfprintf_P(s, ...) vfprintf((s), __VA_ARGS__)
+#endif
+#ifndef printf_P
+#define printf_P(...) printf(__VA_ARGS__)
+#endif
+#ifndef snprintf_P
+#define snprintf_P(s, n, ...) snprintf((s), (n), __VA_ARGS__)
+#endif
+#ifndef vsprintf_P
+#define vsprintf_P(s, ...) vsprintf((s),__VA_ARGS__)
+#endif
+#ifndef vsnprintf_P
+#define vsnprintf_P(s, n, ...) vsnprintf((s), (n),__VA_ARGS__)
+#endif
+#ifndef fprintf_P
+#define fprintf_P(s, ...) fprintf((s), __VA_ARGS__)
+#endif
+
+#ifndef pgm_read_byte
+#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
+#endif
+#ifndef pgm_read_word
+#define pgm_read_word(addr) (*(const unsigned short *)(addr))
+#endif
+#ifndef pgm_read_dword
+#define pgm_read_dword(addr) (*(const unsigned long *)(addr))
+#endif
+#ifndef pgm_read_float
+#define pgm_read_float(addr) (*(const float *)(addr))
+#endif
+
+#ifndef pgm_read_byte_near
+#define pgm_read_byte_near(addr) pgm_read_byte(addr)
+#endif
+#ifndef pgm_read_word_near
+#define pgm_read_word_near(addr) pgm_read_word(addr)
+#endif
+#ifndef pgm_read_dword_near
+#define pgm_read_dword_near(addr) pgm_read_dword(addr)
+#endif
+#ifndef pgm_read_float_near
+#define pgm_read_float_near(addr) pgm_read_float(addr)
+#endif
+#ifndef pgm_read_byte_far
+#define pgm_read_byte_far(addr) pgm_read_byte(addr)
+#endif
+#ifndef pgm_read_word_far
+#define pgm_read_word_far(addr) pgm_read_word(addr)
+#endif
+#ifndef pgm_read_dword_far
+#define pgm_read_dword_far(addr) pgm_read_dword(addr)
+#endif
+#ifndef pgm_read_float_far
+#define pgm_read_float_far(addr) pgm_read_float(addr)
+#endif
+
+#ifndef pgm_read_pointer
+#define pgm_read_pointer
+#endif
+
+// Fix bug in pgm_read_ptr
+#undef pgm_read_ptr
+#define pgm_read_ptr(addr) (*((void**)(addr)))
+
+#endif // __AVR__
diff --git a/Marlin/src/MarlinCore.cpp b/Marlin/src/MarlinCore.cpp
index 343700e9f7ae..b085e6145a51 100644
--- a/Marlin/src/MarlinCore.cpp
+++ b/Marlin/src/MarlinCore.cpp
@@ -43,6 +43,7 @@
#include
#include "core/utility.h"
+
#include "module/motion.h"
#include "module/planner.h"
#include "module/endstops.h"
@@ -57,6 +58,7 @@
#include "gcode/parser.h"
#include "gcode/queue.h"
+#include "feature/pause.h"
#include "sd/cardreader.h"
#include "lcd/marlinui.h"
@@ -139,7 +141,6 @@
#if ENABLED(EXPERIMENTAL_I2CBUS)
#include "feature/twibus.h"
- TWIBus i2c;
#endif
#if ENABLED(I2C_POSITION_ENCODERS)
@@ -173,10 +174,6 @@
#include "feature/bedlevel/bedlevel.h"
#endif
-#if BOTH(ADVANCED_PAUSE_FEATURE, PAUSE_PARK_NO_STEPPER_TIMEOUT)
- #include "feature/pause.h"
-#endif
-
#if ENABLED(GCODE_REPEAT_MARKERS)
#include "feature/repeat.h"
#endif
@@ -233,18 +230,7 @@
#include "feature/password/password.h"
#endif
-PGMSTR(NUL_STR, "");
PGMSTR(M112_KILL_STR, "M112 Shutdown");
-PGMSTR(G28_STR, "G28");
-PGMSTR(M21_STR, "M21");
-PGMSTR(M23_STR, "M23 %s");
-PGMSTR(M24_STR, "M24");
-PGMSTR(SP_P_STR, " P"); PGMSTR(SP_T_STR, " T");
-PGMSTR(X_STR, "X"); PGMSTR(Y_STR, "Y"); PGMSTR(Z_STR, "Z"); PGMSTR(E_STR, "E");
-PGMSTR(X_LBL, "X:"); PGMSTR(Y_LBL, "Y:"); PGMSTR(Z_LBL, "Z:"); PGMSTR(E_LBL, "E:");
-PGMSTR(SP_A_STR, " A"); PGMSTR(SP_B_STR, " B"); PGMSTR(SP_C_STR, " C");
-PGMSTR(SP_X_STR, " X"); PGMSTR(SP_Y_STR, " Y"); PGMSTR(SP_Z_STR, " Z"); PGMSTR(SP_E_STR, " E");
-PGMSTR(SP_X_LBL, " X:"); PGMSTR(SP_Y_LBL, " Y:"); PGMSTR(SP_Z_LBL, " Z:"); PGMSTR(SP_E_LBL, " E:");
MarlinState marlin_state = MF_INITIALIZING;
@@ -267,40 +253,12 @@ bool wait_for_heatup = true;
#endif
-#if PIN_EXISTS(CHDK)
- extern millis_t chdk_timeout;
-#endif
-
-#if ENABLED(I2C_POSITION_ENCODERS)
- I2CPositionEncodersMgr I2CPEM;
-#endif
-
/**
* ***************************************************************************
* ******************************** FUNCTIONS ********************************
* ***************************************************************************
*/
-void setup_killpin() {
- #if HAS_KILL
- #if KILL_PIN_STATE
- SET_INPUT_PULLDOWN(KILL_PIN);
- #else
- SET_INPUT_PULLUP(KILL_PIN);
- #endif
- #endif
-}
-
-void setup_powerhold() {
- #if HAS_SUICIDE
- OUT_WRITE(SUICIDE_PIN, !SUICIDE_PIN_INVERTING);
- #endif
- #if ENABLED(PSU_CONTROL)
- powersupply_on = ENABLED(PSU_DEFAULT_OFF);
- if (ENABLED(PSU_DEFAULT_OFF)) PSU_OFF(); else PSU_ON();
- #endif
-}
-
/**
* Stepper Reset (RigidBoard, et.al.)
*/
@@ -309,18 +267,6 @@ void setup_powerhold() {
void enableStepperDrivers() { SET_INPUT(STEPPER_RESET_PIN); } // Set to input, allowing pullups to pull the pin high
#endif
-#if ENABLED(EXPERIMENTAL_I2CBUS) && I2C_SLAVE_ADDRESS > 0
-
- void i2c_on_receive(int bytes) { // just echo all bytes received to serial
- i2c.receive(bytes);
- }
-
- void i2c_on_request() { // just send dummy data for now
- i2c.reply("Hello World!\n");
- }
-
-#endif
-
/**
* Sensitive pin test for M42, M226
*/
@@ -342,17 +288,6 @@ bool pin_is_protected(const pin_t pin) {
#pragma GCC diagnostic pop
-void protected_pin_err() {
- SERIAL_ERROR_MSG(STR_ERR_PROTECTED_PIN);
-}
-
-void quickstop_stepper() {
- planner.quick_stop();
- planner.synchronize();
- set_current_from_steppers_for_axis(ALL_AXES);
- sync_plan_position();
-}
-
void enable_e_steppers() {
#define _ENA_E(N) ENABLE_AXIS_E##N();
REPEAT(E_STEPPERS, _ENA_E)
@@ -389,41 +324,6 @@ void disable_all_steppers() {
TERN_(EXTENSIBLE_UI, ExtUI::onSteppersDisabled());
}
-#if ENABLED(G29_RETRY_AND_RECOVER)
-
- void event_probe_failure() {
- #ifdef ACTION_ON_G29_FAILURE
- host_action(PSTR(ACTION_ON_G29_FAILURE));
- #endif
- #ifdef G29_FAILURE_COMMANDS
- gcode.process_subcommands_now_P(PSTR(G29_FAILURE_COMMANDS));
- #endif
- #if ENABLED(G29_HALT_ON_FAILURE)
- #ifdef ACTION_ON_CANCEL
- host_action_cancel();
- #endif
- kill(GET_TEXT(MSG_LCD_PROBING_FAILED));
- #endif
- }
-
- void event_probe_recover() {
- TERN_(HOST_PROMPT_SUPPORT, host_prompt_do(PROMPT_INFO, PSTR("G29 Retrying"), DISMISS_STR));
- #ifdef ACTION_ON_G29_RECOVER
- host_action(PSTR(ACTION_ON_G29_RECOVER));
- #endif
- #ifdef G29_RECOVER_COMMANDS
- gcode.process_subcommands_now_P(PSTR(G29_RECOVER_COMMANDS));
- #endif
- }
-
-#endif
-
-#if ENABLED(ADVANCED_PAUSE_FEATURE)
- #include "feature/pause.h"
-#else
- constexpr bool did_pause_print = false;
-#endif
-
/**
* A Print Job exists when the timer is running or SD printing
*/
@@ -462,19 +362,20 @@ void startOrResumeJob() {
inline void abortSDPrinting() {
IF_DISABLED(NO_SD_AUTOSTART, card.autofile_cancel());
card.endFilePrint(TERN_(SD_RESORT, true));
+
queue.clear();
quickstop_stepper();
- print_job_timer.stop();
- #if DISABLED(SD_ABORT_NO_COOLDOWN)
- thermalManager.disable_all_heaters();
- #endif
- #if !HAS_CUTTER
- thermalManager.zero_fan_speeds();
- #else
- cutter.kill(); // Full cutter shutdown including ISR control
- #endif
+
+ print_job_timer.abort();
+
+ IF_DISABLED(SD_ABORT_NO_COOLDOWN, thermalManager.disable_all_heaters());
+
+ TERN(HAS_CUTTER, cutter.kill(), thermalManager.zero_fan_speeds()); // Full cutter shutdown including ISR control
+
wait_for_heatup = false;
+
TERN_(POWER_LOSS_RECOVERY, recovery.purge());
+
#ifdef EVENT_GCODE_SD_ABORT
queue.inject_P(PSTR(EVENT_GCODE_SD_ABORT));
#endif
@@ -511,15 +412,14 @@ inline void manage_inactivity(const bool ignore_stepper_queue=false) {
// Prevent steppers timing-out in the middle of M600
// unless PAUSE_PARK_NO_STEPPER_TIMEOUT is disabled
- const bool parked_or_ignoring = ignore_stepper_queue ||
- (BOTH(ADVANCED_PAUSE_FEATURE, PAUSE_PARK_NO_STEPPER_TIMEOUT) && did_pause_print);
+ const bool parked_or_ignoring = ignore_stepper_queue
+ || TERN0(PAUSE_PARK_NO_STEPPER_TIMEOUT, did_pause_print);
// Reset both the M18/M84 activity timeout and the M85 max 'kill' timeout
if (parked_or_ignoring) gcode.reset_stepper_timeout(ms);
if (gcode.stepper_max_timed_out(ms)) {
- SERIAL_ERROR_START();
- SERIAL_ECHOLNPAIR(STR_KILL_INACTIVE_TIME, parser.command_ptr);
+ SERIAL_ERROR_MSG(STR_KILL_INACTIVE_TIME, parser.command_ptr);
kill();
}
@@ -550,6 +450,7 @@ inline void manage_inactivity(const bool ignore_stepper_queue=false) {
}
#if PIN_EXISTS(CHDK) // Check if pin should be set to LOW (after M240 set it HIGH)
+ extern millis_t chdk_timeout;
if (chdk_timeout && ELAPSED(ms, chdk_timeout)) {
chdk_timeout = 0;
WRITE(CHDK_PIN, LOW);
@@ -712,8 +613,8 @@ inline void manage_inactivity(const bool ignore_stepper_queue=false) {
*/
void idle(TERN_(ADVANCED_PAUSE_FEATURE, bool no_stepper_sleep/*=false*/)) {
#if ENABLED(MARLIN_DEV_MODE)
- static uint8_t idle_depth = 0;
- if (++idle_depth > 5) SERIAL_ECHOLNPAIR("idle() call depth: ", int(idle_depth));
+ static uint16_t idle_depth = 0;
+ if (++idle_depth > 5) SERIAL_ECHOLNPAIR("idle() call depth: ", idle_depth);
#endif
// Core Marlin activities
@@ -785,8 +686,8 @@ void idle(TERN_(ADVANCED_PAUSE_FEATURE, bool no_stepper_sleep/*=false*/)) {
// Auto-report Temperatures / SD Status
#if HAS_AUTO_REPORTING
if (!gcode.autoreport_paused) {
- TERN_(AUTO_REPORT_TEMPERATURES, thermalManager.auto_report_temperatures());
- TERN_(AUTO_REPORT_SD_STATUS, card.auto_report_sd_status());
+ TERN_(AUTO_REPORT_TEMPERATURES, thermalManager.auto_reporter.tick());
+ TERN_(AUTO_REPORT_SD_STATUS, card.auto_reporter.tick());
}
#endif
@@ -882,6 +783,7 @@ void minkill(const bool steppers_off/*=false*/) {
*/
void stop() {
thermalManager.disable_all_heaters(); // 'unpause' taken care of in here
+
print_job_timer.stop();
#if ENABLED(PROBING_FANS_OFF)
@@ -983,6 +885,38 @@ void setup() {
#endif
#define SETUP_RUN(C) do{ SETUP_LOG(STRINGIFY(C)); C; }while(0)
+ MYSERIAL0.begin(BAUDRATE);
+ millis_t serial_connect_timeout = millis() + 1000UL;
+ while (!MYSERIAL0.connected() && PENDING(millis(), serial_connect_timeout)) { /*nada*/ }
+
+ #if HAS_MULTI_SERIAL && !HAS_ETHERNET
+ MYSERIAL1.begin(BAUDRATE);
+ serial_connect_timeout = millis() + 1000UL;
+ while (!MYSERIAL1.connected() && PENDING(millis(), serial_connect_timeout)) { /*nada*/ }
+ #endif
+ SERIAL_ECHOLNPGM("start");
+
+ // Set up these pins early to prevent suicide
+ #if HAS_KILL
+ SETUP_LOG("KILL_PIN");
+ #if KILL_PIN_STATE
+ SET_INPUT_PULLDOWN(KILL_PIN);
+ #else
+ SET_INPUT_PULLUP(KILL_PIN);
+ #endif
+ #endif
+
+ #if HAS_SUICIDE
+ SETUP_LOG("SUICIDE_PIN");
+ OUT_WRITE(SUICIDE_PIN, !SUICIDE_PIN_INVERTING);
+ #endif
+
+ #if ENABLED(PSU_CONTROL)
+ SETUP_LOG("PSU_CONTROL");
+ powersupply_on = ENABLED(PSU_DEFAULT_OFF);
+ if (ENABLED(PSU_DEFAULT_OFF)) PSU_OFF(); else PSU_ON();
+ #endif
+
#if EITHER(DISABLE_DEBUG, DISABLE_JTAG)
// Disable any hardware debug to free up pins for IO
#if ENABLED(DISABLE_DEBUG) && defined(JTAGSWD_DISABLE)
@@ -994,16 +928,6 @@ void setup() {
#endif
#endif
- MYSERIAL0.begin(BAUDRATE);
- uint32_t serial_connect_timeout = millis() + 1000UL;
- while (!MYSERIAL0 && PENDING(millis(), serial_connect_timeout)) { /*nada*/ }
- #if HAS_MULTI_SERIAL && !HAS_ETHERNET
- MYSERIAL1.begin(BAUDRATE);
- serial_connect_timeout = millis() + 1000UL;
- while (!MYSERIAL1 && PENDING(millis(), serial_connect_timeout)) { /*nada*/ }
- #endif
- SERIAL_ECHOLNPGM("start");
-
#if BOTH(HAS_TFT_LVGL_UI, MKS_WIFI_MODULE)
mks_esp_wifi_init();
WIFISERIAL.begin(WIFI_BAUDRATE);
@@ -1013,11 +937,11 @@ void setup() {
SETUP_RUN(HAL_init());
- // Init and disable SPI thermocouples
- #if HEATER_0_USES_MAX6675
+ // Init and disable SPI thermocouples; this is still needed
+ #if TEMP_SENSOR_0_IS_MAX_TC
OUT_WRITE(MAX6675_SS_PIN, HIGH); // Disable
#endif
- #if HEATER_1_USES_MAX6675
+ #if TEMP_SENSOR_1_IS_MAX_TC
OUT_WRITE(MAX6675_SS2_PIN, HIGH); // Disable
#endif
@@ -1037,14 +961,10 @@ void setup() {
SETUP_RUN(recovery.setup());
#endif
- SETUP_RUN(setup_killpin());
-
#if HAS_TMC220x
SETUP_RUN(tmc_serial_begin());
#endif
- SETUP_RUN(setup_powerhold());
-
#if HAS_STEPPER_RESET
SETUP_RUN(disableStepperDrivers());
#endif
@@ -1083,7 +1003,10 @@ void setup() {
);
#endif
SERIAL_ECHO_MSG("Compiled: " __DATE__);
- SERIAL_ECHO_MSG(STR_FREE_MEMORY, freeMemory(), STR_PLANNER_BUFFER_BYTES, (int)sizeof(block_t) * (BLOCK_BUFFER_SIZE));
+ SERIAL_ECHO_MSG(STR_FREE_MEMORY, freeMemory(), STR_PLANNER_BUFFER_BYTES, sizeof(block_t) * (BLOCK_BUFFER_SIZE));
+
+ // Some HAL need precise delay adjustment
+ calibrate_delay_loop();
// Init buzzer pin(s)
#if USE_BEEPER
diff --git a/Marlin/src/MarlinCore.h b/Marlin/src/MarlinCore.h
index 908636e9677c..d43d46bbd8e1 100644
--- a/Marlin/src/MarlinCore.h
+++ b/Marlin/src/MarlinCore.h
@@ -37,11 +37,6 @@ void stop();
void idle(TERN_(ADVANCED_PAUSE_FEATURE, bool no_stepper_sleep=false));
inline void idle_no_sleep() { idle(TERN_(ADVANCED_PAUSE_FEATURE, true)); }
-#if ENABLED(EXPERIMENTAL_I2CBUS)
- #include "feature/twibus.h"
- extern TWIBus i2c;
-#endif
-
#if ENABLED(G38_PROBE_TARGET)
extern uint8_t G38_move; // Flag to tell the ISR that G38 is in progress, and the type
extern bool G38_did_trigger; // Flag from the ISR to indicate the endstop changed
@@ -59,8 +54,6 @@ void disable_all_steppers();
void kill(PGM_P const lcd_error=nullptr, PGM_P const lcd_component=nullptr, const bool steppers_off=false);
void minkill(const bool steppers_off=false);
-void quickstop_stepper();
-
// Global State of the firmware
enum MarlinState : uint8_t {
MF_INITIALIZING = 0,
@@ -103,7 +96,6 @@ extern bool wait_for_heatup;
#endif
bool pin_is_protected(const pin_t pin);
-void protected_pin_err();
#if HAS_SUICIDE
inline void suicide() { OUT_WRITE(SUICIDE_PIN, SUICIDE_PIN_INVERTING); }
@@ -116,12 +108,4 @@ void protected_pin_err();
inline bool kill_state() { return READ(KILL_PIN) == KILL_PIN_STATE; }
#endif
-#if ENABLED(G29_RETRY_AND_RECOVER)
- void event_probe_recover();
- void event_probe_failure();
-#endif
-
-extern const char NUL_STR[], M112_KILL_STR[], G28_STR[], M21_STR[], M23_STR[], M24_STR[],
- SP_A_STR[], SP_B_STR[], SP_C_STR[],
- SP_P_STR[], SP_T_STR[], SP_X_STR[], SP_Y_STR[], SP_Z_STR[], SP_E_STR[],
- X_LBL[], Y_LBL[], Z_LBL[], E_LBL[], SP_X_LBL[], SP_Y_LBL[], SP_Z_LBL[], SP_E_LBL[];
+extern const char M112_KILL_STR[];
diff --git a/Marlin/src/core/boards.h b/Marlin/src/core/boards.h
index 13a202daedb1..0f076b1b2aa7 100644
--- a/Marlin/src/core/boards.h
+++ b/Marlin/src/core/boards.h
@@ -338,6 +338,7 @@
#define BOARD_FLY_MINI 4045 // FLY MINI (STM32F103RCT6)
#define BOARD_FLSUN_HISPEED 4046 // FLSUN HiSpeedV1 (STM32F103VET6)
#define BOARD_BEAST 4047 // STM32F103RET6 Libmaple-based controller
+#define BOARD_MINGDA_MPX_ARM_MINI 4048 // STM32F103ZET6 Mingda MD-16
//
// ARM Cortex-M4F
@@ -373,6 +374,7 @@
#define BOARD_MKS_ROBIN_NANO_V3 4220 // MKS Robin Nano V3 (STM32F407VG)
#define BOARD_ANET_ET4 4221 // ANET ET4 V1.x (STM32F407VGT6)
#define BOARD_ANET_ET4P 4222 // ANET ET4P V1.x (STM32F407VGT6)
+#define BOARD_FYSETC_CHEETAH_V20 4223 // FYSETC Cheetah V2.0
//
// ARM Cortex M7
@@ -413,5 +415,3 @@
#define _MB_1(B) (defined(BOARD_##B) && MOTHERBOARD==BOARD_##B)
#define MB(V...) DO(MB,||,V)
-
-#define IS_MELZI MB(MELZI, MELZI_CREALITY, MELZI_MAKR3D, MELZI_MALYAN, MELZI_TRONXY, MELZI_V2)
diff --git a/Marlin/src/core/language.h b/Marlin/src/core/language.h
index d6048d293c80..923ad903cb55 100644
--- a/Marlin/src/core/language.h
+++ b/Marlin/src/core/language.h
@@ -68,6 +68,7 @@
// ro Romanian
// ru Russian
// sk Slovak
+// sv Swedish
// tr Turkish
// uk Ukrainian
// vi Vietnamese
diff --git a/Marlin/src/core/macros.h b/Marlin/src/core/macros.h
index 56e80b87dc9d..16e18ac9023d 100644
--- a/Marlin/src/core/macros.h
+++ b/Marlin/src/core/macros.h
@@ -53,6 +53,7 @@
#define _FORCE_INLINE_ __attribute__((__always_inline__)) __inline__
#define FORCE_INLINE __attribute__((always_inline)) inline
+#define NO_INLINE __attribute__((noinline))
#define _UNUSED __attribute__((unused))
#define _O0 __attribute__((optimize("O0")))
#define _Os __attribute__((optimize("Os")))
@@ -60,6 +61,8 @@
#define _O2 __attribute__((optimize("O2")))
#define _O3 __attribute__((optimize("O3")))
+#define IS_CONSTEXPR(...) __builtin_constant_p(__VA_ARGS__) // Only valid solution with C++14. Should use std::is_constant_evaluated() in C++20 instead
+
#ifndef UNUSED
#define UNUSED(x) ((void)(x))
#endif
@@ -84,17 +87,13 @@
#define _BV(n) (1<<(n))
#define TEST(n,b) (!!((n)&_BV(b)))
#define SET_BIT_TO(N,B,TF) do{ if (TF) SBI(N,B); else CBI(N,B); }while(0)
-
#ifndef SBI
- #define SBI(A,B) (A |= (1 << (B)))
+ #define SBI(A,B) (A |= _BV(B))
#endif
-
#ifndef CBI
- #define CBI(A,B) (A &= ~(1 << (B)))
+ #define CBI(A,B) (A &= ~_BV(B))
#endif
-
#define TBI(N,B) (N ^= _BV(B))
-
#define _BV32(b) (1UL << (b))
#define TEST32(n,b) !!((n)&_BV32(b))
#define SBI32(n,b) (n |= _BV32(b))
@@ -131,20 +130,20 @@
#define NOLESS(v, n) \
do{ \
- __typeof__(n) _n = (n); \
+ __typeof__(v) _n = (n); \
if (_n > v) v = _n; \
}while(0)
#define NOMORE(v, n) \
do{ \
- __typeof__(n) _n = (n); \
+ __typeof__(v) _n = (n); \
if (_n < v) v = _n; \
}while(0)
#define LIMIT(v, n1, n2) \
do{ \
- __typeof__(n1) _n1 = (n1); \
- __typeof__(n2) _n2 = (n2); \
+ __typeof__(v) _n1 = (n1); \
+ __typeof__(v) _n2 = (n2); \
if (_n1 > v) v = _n1; \
else if (_n2 < v) v = _n2; \
}while(0)
@@ -166,6 +165,7 @@
#define _DO_12(W,C,A,V...) (_##W##_1(A) C _DO_11(W,C,V))
#define _DO_13(W,C,A,V...) (_##W##_1(A) C _DO_12(W,C,V))
#define _DO_14(W,C,A,V...) (_##W##_1(A) C _DO_13(W,C,V))
+#define _DO_15(W,C,A,V...) (_##W##_1(A) C _DO_14(W,C,V))
#define __DO_N(W,C,N,V...) _DO_##N(W,C,V)
#define _DO_N(W,C,N,V...) __DO_N(W,C,N,V)
#define DO(W,C,V...) (_DO_N(W,C,NUM_ARGS(V),V))
@@ -317,6 +317,38 @@
#endif
+ // C++11 solution that is standard compliant. is not available on all platform
+ namespace Private {
+ template struct enable_if { };
+ template struct enable_if { typedef _Tp type; };
+
+ template struct is_same { enum { value = false }; };
+ template struct is_same { enum { value = true }; };
+
+ template struct first_type_of { typedef T type; };
+ template struct first_type_of { typedef T type; };
+ }
+ // C++11 solution using SFINAE to detect the existance of a member in a class at compile time.
+ // It creates a HasMember structure containing 'value' set to true if the member exists
+ #define HAS_MEMBER_IMPL(Member) \
+ namespace Private { \
+ template struct HasMember_ ## Member { \
+ template static Yes& test( decltype(&C::Member) ) ; \
+ template static No& test(...); \
+ enum { value = sizeof(test(0)) == sizeof(Yes) }; }; \
+ }
+
+ // Call the method if it exists, but do nothing if it does not. The method is detected at compile time.
+ // If the method exists, this is inlined and does not cost anything. Else, an "empty" wrapper is created, returning a default value
+ #define CALL_IF_EXISTS_IMPL(Return, Method, ...) \
+ HAS_MEMBER_IMPL(Method) \
+ namespace Private { \
+ template FORCE_INLINE typename enable_if::value, Return>::type Call_ ## Method(T * t, Args... a) { return static_cast(t->Method(a...)); } \
+ _UNUSED static Return Call_ ## Method(...) { return __VA_ARGS__; } \
+ }
+ #define CALL_IF_EXISTS(Return, That, Method, ...) \
+ static_cast(Private::Call_ ## Method(That, ##__VA_ARGS__))
+
#else
#define MIN_2(a,b) ((a)<(b)?(a):(b))
diff --git a/Marlin/src/core/multi_language.h b/Marlin/src/core/multi_language.h
index 6af4af2f8df4..5a26edf8d453 100644
--- a/Marlin/src/core/multi_language.h
+++ b/Marlin/src/core/multi_language.h
@@ -20,6 +20,8 @@
****************************************************************************/
#pragma once
+#include "../inc/MarlinConfigPre.h"
+
typedef const char Language_Str[];
#ifdef LCD_LANGUAGE_5
@@ -57,26 +59,27 @@ typedef const char Language_Str[];
#define GET_LANG(LANG) _GET_LANG(LANG)
#if NUM_LANGUAGES > 1
- extern uint8_t lang;
+ #define HAS_MULTI_LANGUAGE 1
#define GET_TEXT(MSG) ( \
- lang == 0 ? GET_LANG(LCD_LANGUAGE)::MSG : \
- lang == 1 ? GET_LANG(LCD_LANGUAGE_2)::MSG : \
- lang == 2 ? GET_LANG(LCD_LANGUAGE_3)::MSG : \
- lang == 3 ? GET_LANG(LCD_LANGUAGE_4)::MSG : \
- GET_LANG(LCD_LANGUAGE_5)::MSG \
- )
- #define MAX_LANG_CHARSIZE _MAX(GET_LANG(LCD_LANGUAGE)::CHARSIZE, \
- GET_LANG(LCD_LANGUAGE_2)::CHARSIZE, \
- GET_LANG(LCD_LANGUAGE_3)::CHARSIZE, \
- GET_LANG(LCD_LANGUAGE_4)::CHARSIZE, \
- GET_LANG(LCD_LANGUAGE_5)::CHARSIZE)
+ ui.language == 0 ? GET_LANG(LCD_LANGUAGE )::MSG : \
+ ui.language == 1 ? GET_LANG(LCD_LANGUAGE_2)::MSG : \
+ ui.language == 2 ? GET_LANG(LCD_LANGUAGE_3)::MSG : \
+ ui.language == 3 ? GET_LANG(LCD_LANGUAGE_4)::MSG : \
+ GET_LANG(LCD_LANGUAGE_5)::MSG )
+ #define MAX_LANG_CHARSIZE _MAX(GET_LANG(LCD_LANGUAGE )::CHARSIZE, \
+ GET_LANG(LCD_LANGUAGE_2)::CHARSIZE, \
+ GET_LANG(LCD_LANGUAGE_3)::CHARSIZE, \
+ GET_LANG(LCD_LANGUAGE_4)::CHARSIZE, \
+ GET_LANG(LCD_LANGUAGE_5)::CHARSIZE )
#else
#define GET_TEXT(MSG) GET_LANG(LCD_LANGUAGE)::MSG
- #define MAX_LANG_CHARSIZE GET_LANG(LCD_LANGUAGE)::CHARSIZE
+ #define MAX_LANG_CHARSIZE LANG_CHARSIZE
#endif
#define GET_TEXT_F(MSG) (const __FlashStringHelper*)GET_TEXT(MSG)
#define GET_LANGUAGE_NAME(INDEX) GET_LANG(LCD_LANGUAGE_##INDEX)::LANGUAGE
+#define LANG_CHARSIZE GET_TEXT(CHARSIZE)
+#define USE_WIDE_GLYPH (LANG_CHARSIZE > 2)
#define MSG_1_LINE(A) A "\0" "\0"
#define MSG_2_LINE(A,B) A "\0" B "\0"
diff --git a/Marlin/src/core/serial.cpp b/Marlin/src/core/serial.cpp
index 0d22f7bfc067..31f6d67e326e 100644
--- a/Marlin/src/core/serial.cpp
+++ b/Marlin/src/core/serial.cpp
@@ -23,27 +23,50 @@
#include "serial.h"
#include "../inc/MarlinConfig.h"
+#if HAS_ETHERNET
+ #include "../feature/ethernet.h"
+#endif
+
uint8_t marlin_debug_flags = MARLIN_DEBUG_NONE;
-static PGMSTR(errormagic, "Error:");
-static PGMSTR(echomagic, "echo:");
+// Commonly-used strings in serial output
+PGMSTR(NUL_STR, ""); PGMSTR(SP_P_STR, " P"); PGMSTR(SP_T_STR, " T");
+PGMSTR(X_STR, "X"); PGMSTR(Y_STR, "Y"); PGMSTR(Z_STR, "Z"); PGMSTR(E_STR, "E");
+PGMSTR(X_LBL, "X:"); PGMSTR(Y_LBL, "Y:"); PGMSTR(Z_LBL, "Z:"); PGMSTR(E_LBL, "E:");
+PGMSTR(SP_A_STR, " A"); PGMSTR(SP_B_STR, " B"); PGMSTR(SP_C_STR, " C");
+PGMSTR(SP_X_STR, " X"); PGMSTR(SP_Y_STR, " Y"); PGMSTR(SP_Z_STR, " Z"); PGMSTR(SP_E_STR, " E");
+PGMSTR(SP_X_LBL, " X:"); PGMSTR(SP_Y_LBL, " Y:"); PGMSTR(SP_Z_LBL, " Z:"); PGMSTR(SP_E_LBL, " E:");
#if HAS_MULTI_SERIAL
- int8_t serial_port_index = 0;
+ #ifdef SERIAL_CATCHALL
+ SerialOutputT multiSerial(MYSERIAL, SERIAL_CATCHALL);
+ #else
+ #if HAS_ETHERNET
+ // Runtime checking of the condition variable
+ ConditionalSerial serialOut1(ethernet.have_telnet_client, MYSERIAL1, false); // Takes reference here
+ #else
+ // Don't pay for runtime checking a true variable, instead use the output directly
+ #define serialOut1 MYSERIAL1
+ #endif
+ SerialOutputT multiSerial(MYSERIAL0, serialOut1);
+ #endif
#endif
void serialprintPGM(PGM_P str) {
while (const char c = pgm_read_byte(str++)) SERIAL_CHAR(c);
}
-void serial_echo_start() { serialprintPGM(echomagic); }
-void serial_error_start() { serialprintPGM(errormagic); }
+void serial_echo_start() { static PGMSTR(echomagic, "echo:"); serialprintPGM(echomagic); }
+void serial_error_start() { static PGMSTR(errormagic, "Error:"); serialprintPGM(errormagic); }
+
+void serial_echopair_PGM(PGM_P const s_P, serial_char_t v) { serialprintPGM(s_P); SERIAL_CHAR(v.c); }
void serial_echopair_PGM(PGM_P const s_P, const char *v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
-void serial_echopair_PGM(PGM_P const s_P, char v) { serialprintPGM(s_P); SERIAL_CHAR(v); }
+void serial_echopair_PGM(PGM_P const s_P, char v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
void serial_echopair_PGM(PGM_P const s_P, int v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
void serial_echopair_PGM(PGM_P const s_P, long v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
void serial_echopair_PGM(PGM_P const s_P, float v) { serialprintPGM(s_P); SERIAL_DECIMAL(v); }
void serial_echopair_PGM(PGM_P const s_P, double v) { serialprintPGM(s_P); SERIAL_DECIMAL(v); }
+void serial_echopair_PGM(PGM_P const s_P, unsigned char v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
void serial_echopair_PGM(PGM_P const s_P, unsigned int v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
void serial_echopair_PGM(PGM_P const s_P, unsigned long v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
@@ -65,8 +88,6 @@ void print_bin(uint16_t val) {
}
}
-extern const char SP_X_STR[], SP_Y_STR[], SP_Z_STR[];
-
void print_xyz(const float &x, const float &y, const float &z, PGM_P const prefix/*=nullptr*/, PGM_P const suffix/*=nullptr*/) {
if (prefix) serialprintPGM(prefix);
SERIAL_ECHOPAIR_P(SP_X_STR, x, SP_Y_STR, y, SP_Z_STR, z);
diff --git a/Marlin/src/core/serial.h b/Marlin/src/core/serial.h
index 4824866aebe4..c422f8e25b26 100644
--- a/Marlin/src/core/serial.h
+++ b/Marlin/src/core/serial.h
@@ -22,14 +22,19 @@
#pragma once
#include "../inc/MarlinConfig.h"
+#include "serial_hook.h"
-#if HAS_ETHERNET
- #include "../feature/ethernet.h"
-#endif
+// Commonly-used strings in serial output
+extern const char NUL_STR[], SP_P_STR[], SP_T_STR[],
+ X_STR[], Y_STR[], Z_STR[], E_STR[],
+ X_LBL[], Y_LBL[], Z_LBL[], E_LBL[],
+ SP_A_STR[], SP_B_STR[], SP_C_STR[],
+ SP_X_STR[], SP_Y_STR[], SP_Z_STR[], SP_E_STR[],
+ SP_X_LBL[], SP_Y_LBL[], SP_Z_LBL[], SP_E_LBL[];
-/**
- * Define debug bit-masks
- */
+//
+// Debugging flags for use by M111
+//
enum MarlinDebugFlags : uint8_t {
MARLIN_DEBUG_NONE = 0,
MARLIN_DEBUG_ECHO = _BV(0), ///< Echo commands in order as they are processed
@@ -50,65 +55,75 @@ enum MarlinDebugFlags : uint8_t {
extern uint8_t marlin_debug_flags;
#define DEBUGGING(F) (marlin_debug_flags & (MARLIN_DEBUG_## F))
-#define SERIAL_BOTH 0x7F
+//
+// Serial redirection
+//
+typedef int8_t serial_index_t;
+#define SERIAL_ALL 0x7F
#if HAS_MULTI_SERIAL
- extern int8_t serial_port_index;
- #define _PORT_REDIRECT(n,p) REMEMBER(n,serial_port_index,p)
- #define _PORT_RESTORE(n) RESTORE(n)
-
+ #define _PORT_REDIRECT(n,p) REMEMBER(n,multiSerial.portMask,p)
+ #define SERIAL_ASSERT(P) if(multiSerial.portMask!=(P)){ debugger(); }
#ifdef SERIAL_CATCHALL
- #define SERIAL_OUT(WHAT, V...) (void)CAT(MYSERIAL,SERIAL_CATCHALL).WHAT(V)
+ typedef MultiSerial SerialOutputT;
#else
- #define SERIAL_OUT(WHAT, V...) do{ \
- const bool port2_open = TERN1(HAS_ETHERNET, ethernet.have_telnet_client); \
- if ( serial_port_index == 0 || serial_port_index == SERIAL_BOTH) (void)MYSERIAL0.WHAT(V); \
- if ((serial_port_index == 1 || serial_port_index == SERIAL_BOTH) && port2_open) (void)MYSERIAL1.WHAT(V); \
- }while(0)
+ typedef MultiSerial, decltype(MYSERIAL1)), 0> SerialOutputT;
#endif
-
- #define SERIAL_ASSERT(P) if(serial_port_index!=(P)){ debugger(); }
+ extern SerialOutputT multiSerial;
+ #define SERIAL_IMPL multiSerial
#else
#define _PORT_REDIRECT(n,p) NOOP
- #define _PORT_RESTORE(n) NOOP
- #define SERIAL_OUT(WHAT, V...) (void)MYSERIAL0.WHAT(V)
#define SERIAL_ASSERT(P) NOOP
+ #define SERIAL_IMPL MYSERIAL0
#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_ECHO(x) SERIAL_OUT(print, x)
-#define SERIAL_ECHO_F(V...) SERIAL_OUT(print, V)
-#define SERIAL_ECHOLN(x) SERIAL_OUT(println, x)
-#define SERIAL_PRINT(x,b) SERIAL_OUT(print, x, b)
-#define SERIAL_PRINTLN(x,b) SERIAL_OUT(println, x, b)
-#define SERIAL_PRINTF(V...) SERIAL_OUT(printf, V)
-#define SERIAL_FLUSH() SERIAL_OUT(flush)
-
-#ifdef ARDUINO_ARCH_STM32
- #define SERIAL_FLUSHTX() SERIAL_OUT(flush)
-#elif TX_BUFFER_SIZE > 0
- #define SERIAL_FLUSHTX() SERIAL_OUT(flushTX)
-#else
- #define SERIAL_FLUSHTX()
-#endif
+#define SERIAL_PORTMASK(P) _BV(P)
-// Print up to 10 chars from a list
-#define __CHAR_N(N,V...) _CHAR_##N(V)
-#define _CHAR_N(N,V...) __CHAR_N(N,V)
-#define _CHAR_1(c) SERIAL_OUT(write, c)
-#define _CHAR_2(a,b) do{ _CHAR_1(a); _CHAR_1(b); }while(0)
-#define _CHAR_3(a,V...) do{ _CHAR_1(a); _CHAR_2(V); }while(0)
-#define _CHAR_4(a,V...) do{ _CHAR_1(a); _CHAR_3(V); }while(0)
-#define _CHAR_5(a,V...) do{ _CHAR_1(a); _CHAR_4(V); }while(0)
-#define _CHAR_6(a,V...) do{ _CHAR_1(a); _CHAR_5(V); }while(0)
-#define _CHAR_7(a,V...) do{ _CHAR_1(a); _CHAR_6(V); }while(0)
-#define _CHAR_8(a,V...) do{ _CHAR_1(a); _CHAR_7(V); }while(0)
-#define _CHAR_9(a,V...) do{ _CHAR_1(a); _CHAR_8(V); }while(0)
-#define _CHAR_10(a,V...) do{ _CHAR_1(a); _CHAR_9(V); }while(0)
-
-#define SERIAL_CHAR(V...) _CHAR_N(NUM_ARGS(V),V)
+//
+// SERIAL_CHAR - Print one or more individual chars
+//
+inline void SERIAL_CHAR(char a) { SERIAL_IMPL.write(a); }
+template
+void SERIAL_CHAR(char a, Args ... args) { SERIAL_IMPL.write(a); SERIAL_CHAR(args ...); }
+/**
+ * SERIAL_ECHO - 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
+void SERIAL_ECHO(T x) { SERIAL_IMPL.print(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)
+
+// 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); }
+
+template
+void SERIAL_ECHOLN(T x) { SERIAL_IMPL.println(x); }
+
+// SERIAL_PRINT works like SERIAL_ECHO but allow to specify the encoding base of the number printed
+template
+void SERIAL_PRINT(T x, U y) { SERIAL_IMPL.print(x, y); }
+
+template
+void SERIAL_PRINTLN(T x, U y) { SERIAL_IMPL.println(x, y); }
+
+// Flush the serial port
+inline void SERIAL_FLUSH() { SERIAL_IMPL.flush(); }
+inline void SERIAL_FLUSHTX() { SERIAL_IMPL.flushTX(); }
+
+// Print a single PROGMEM string to serial
+void serialprintPGM(PGM_P str);
+
+// SERIAL_ECHOPAIR / SERIAL_ECHOPAIR_P is used to output a key value pair. The key must be a string and the value can be anything
// Print up to 12 pairs of values. Odd elements auto-wrapped in PSTR().
#define __SEP_N(N,V...) _SEP_##N(V)
#define _SEP_N(N,V...) __SEP_N(N,V)
@@ -167,6 +182,7 @@ extern uint8_t marlin_debug_flags;
#define _SEP_23_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_21_P(V); }while(0)
#define _SEP_24_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_22_P(V); }while(0)
+// SERIAL_ECHOPAIR_P is used to output a key value pair. Unlike SERIAL_ECHOPAIR, the key must be a PGM string already and the value can be anything
#define SERIAL_ECHOPAIR_P(V...) _SEP_N_P(NUM_ARGS(V),V)
// Print up to 12 pairs of values followed by newline
@@ -241,32 +257,39 @@ extern uint8_t marlin_debug_flags;
#define SERIAL_ECHOLNPAIR_P(V...) _SELP_N_P(NUM_ARGS(V),V)
-// Print up to 20 comma-separated pairs of values
-#define __SLST_N(N,V...) _SLST_##N(V)
-#define _SLST_N(N,V...) __SLST_N(N,V)
-#define _SLST_1(a) SERIAL_ECHO(a)
-#define _SLST_2(a,b) do{ SERIAL_ECHO(a); SERIAL_ECHOPAIR(", ",b); }while(0)
-#define _SLST_3(a,b,c) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_1(c); }while(0)
-#define _SLST_4(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_2(V); }while(0)
-#define _SLST_5(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_3(V); }while(0)
-#define _SLST_6(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_4(V); }while(0)
-#define _SLST_7(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_5(V); }while(0)
-#define _SLST_8(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_6(V); }while(0)
-#define _SLST_9(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_7(V); }while(0)
-#define _SLST_10(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_8(V); }while(0)
-#define _SLST_11(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_9(V); }while(0)
-#define _SLST_12(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_10(V); }while(0)
-#define _SLST_13(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_11(V); }while(0)
-#define _SLST_14(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_12(V); }while(0)
-#define _SLST_15(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_13(V); }while(0)
-#define _SLST_16(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_14(V); }while(0)
-#define _SLST_17(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_15(V); }while(0)
-#define _SLST_18(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_16(V); }while(0)
-#define _SLST_19(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_17(V); }while(0)
-#define _SLST_20(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_18(V); }while(0) // Eat two args, pass the rest up
-
-#define SERIAL_ECHOLIST(pre,V...) do{ SERIAL_ECHOPGM(pre); _SLST_N(NUM_ARGS(V),V); }while(0)
-#define SERIAL_ECHOLIST_N(N,V...) _SLST_N(N,LIST_N(N,V))
+#ifdef AllowDifferentTypeInList
+
+ inline void SERIAL_ECHOLIST_IMPL() {}
+ template
+ void SERIAL_ECHOLIST_IMPL(T && t) { SERIAL_IMPL.print(t); }
+
+ template
+ void SERIAL_ECHOLIST_IMPL(T && t, Args && ... args) {
+ SERIAL_IMPL.print(t);
+ serialprintPGM(PSTR(", "));
+ SERIAL_ECHOLIST_IMPL(args...);
+ }
+
+ template
+ void SERIAL_ECHOLIST(PGM_P const str, Args && ... args) {
+ SERIAL_IMPL.print(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
+ void SERIAL_ECHOLIST(PGM_P const str, Args && ... args) {
+ serialprintPGM(str);
+ typename Private::first_type_of::type values[] = { args... };
+ constexpr size_t argsSize = sizeof...(args);
+ for (size_t i = 0; i < argsSize; i++) {
+ if (i) serialprintPGM(PSTR(", "));
+ SERIAL_IMPL.print(values[i]);
+ }
+ }
+
+#endif
#define SERIAL_ECHOPGM_P(P) (serialprintPGM(P))
#define SERIAL_ECHOLNPGM_P(P) (serialprintPGM(P "\n"))
@@ -300,19 +323,19 @@ extern uint8_t marlin_debug_flags;
//
// Functions for serial printing from PROGMEM. (Saves loads of SRAM.)
//
+void serial_echopair_PGM(PGM_P const s_P, serial_char_t v);
void serial_echopair_PGM(PGM_P const s_P, const char *v);
void serial_echopair_PGM(PGM_P const s_P, char v);
void serial_echopair_PGM(PGM_P const s_P, int v);
-void serial_echopair_PGM(PGM_P const s_P, unsigned int v);
void serial_echopair_PGM(PGM_P const s_P, long v);
-void serial_echopair_PGM(PGM_P const s_P, unsigned long v);
void serial_echopair_PGM(PGM_P const s_P, float v);
void serial_echopair_PGM(PGM_P const s_P, double v);
-inline void serial_echopair_PGM(PGM_P const s_P, uint8_t v) { serial_echopair_PGM(s_P, (int)v); }
+void serial_echopair_PGM(PGM_P const s_P, unsigned char v);
+void serial_echopair_PGM(PGM_P const s_P, unsigned int v);
+void serial_echopair_PGM(PGM_P const s_P, unsigned long v);
inline void serial_echopair_PGM(PGM_P const s_P, bool v) { serial_echopair_PGM(s_P, (int)v); }
inline void serial_echopair_PGM(PGM_P const s_P, void *v) { serial_echopair_PGM(s_P, (uintptr_t)v); }
-void serialprintPGM(PGM_P str);
void serial_echo_start();
void serial_error_start();
void serial_ternary(const bool onoff, PGM_P const pre, PGM_P const on, PGM_P const off, PGM_P const post=nullptr);
diff --git a/Marlin/src/core/serial_base.h b/Marlin/src/core/serial_base.h
new file mode 100644
index 000000000000..81403b55f29e
--- /dev/null
+++ b/Marlin/src/core/serial_base.h
@@ -0,0 +1,193 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+#pragma once
+
+#include "../inc/MarlinConfigPre.h"
+#include "macros.h"
+
+#if ENABLED(EMERGENCY_PARSER)
+ #include "../feature/e_parser.h"
+#endif
+
+// flushTX is not implemented in all HAL, so use SFINAE to call the method where it is.
+CALL_IF_EXISTS_IMPL(void, flushTX );
+CALL_IF_EXISTS_IMPL(bool, connected, true);
+
+// In order to catch usage errors in code, we make the base to encode number explicit
+// If given a number (and not this enum), the compiler will reject the overload, falling back to the (double, digit) version
+// We don't want hidden conversion of the first parameter to double, so it has to be as hard to do for the compiler as creating this enum
+enum class PrintBase {
+ Dec = 10,
+ Hex = 16,
+ Oct = 8,
+ Bin = 2
+};
+
+// A simple forward struct that prevent the compiler to select print(double, int) as a default overload for any type different than
+// double or float. For double or float, a conversion exists so the call will be transparent
+struct EnsureDouble {
+ double a;
+ FORCE_INLINE operator double() { return a; }
+ // If the compiler breaks on ambiguity here, it's likely because you're calling print(X, base) with X not a double or a float, and a
+ // base that's not one of PrintBase's value. This exact code is made to detect such error, you NEED to set a base explicitely like this:
+ // SERIAL_PRINT(v, PrintBase::Hex)
+ FORCE_INLINE EnsureDouble(double a) : a(a) {}
+ FORCE_INLINE EnsureDouble(float a) : a(a) {}
+};
+
+// Using Curiously Recurring Template Pattern here to avoid virtual table cost when compiling.
+// Since the real serial class is known at compile time, this results in the compiler writing
+// a completely efficient code.
+template
+struct SerialBase {
+ #if ENABLED(EMERGENCY_PARSER)
+ const bool ep_enabled;
+ EmergencyParser::State emergency_state;
+ inline bool emergency_parser_enabled() { return ep_enabled; }
+ SerialBase(bool ep_capable) : ep_enabled(ep_capable), emergency_state(EmergencyParser::State::EP_RESET) {}
+ #else
+ SerialBase(const bool) {}
+ #endif
+
+ // Static dispatch methods below:
+ // The most important method here is where it all ends to:
+ size_t write(uint8_t c) { return static_cast(this)->write(c); }
+ // Called when the parser finished processing an instruction, usually build to nothing
+ void msgDone() { static_cast(this)->msgDone(); }
+ // Called upon initialization
+ void begin(const long baudRate) { static_cast(this)->begin(baudRate); }
+ // Called upon destruction
+ void end() { static_cast(this)->end(); }
+ /** Check for available data from the port
+ @param index The port index, usually 0 */
+ bool available(uint8_t index = 0) { return static_cast(this)->available(index); }
+ /** Read a value from the port
+ @param index The port index, usually 0 */
+ int read(uint8_t index = 0) { return static_cast(this)->read(index); }
+ // Check if the serial port is connected (usually bypassed)
+ bool connected() { return static_cast(this)->connected(); }
+ // Redirect flush
+ void flush() { static_cast(this)->flush(); }
+ // Not all implementation have a flushTX, so let's call them only if the child has the implementation
+ void flushTX() { CALL_IF_EXISTS(void, static_cast(this), flushTX); }
+
+ // Glue code here
+ FORCE_INLINE void write(const char* str) { while (*str) write(*str++); }
+ FORCE_INLINE void write(const uint8_t* buffer, size_t size) { while (size--) write(*buffer++); }
+ FORCE_INLINE void print(const char* str) { write(str); }
+ // No default argument to avoid ambiguity
+ NO_INLINE void print(char c, PrintBase base) { printNumber((signed long)c, (uint8_t)base); }
+ NO_INLINE void print(unsigned char c, PrintBase base) { printNumber((unsigned long)c, (uint8_t)base); }
+ NO_INLINE void print(int c, PrintBase base) { printNumber((signed long)c, (uint8_t)base); }
+ NO_INLINE void print(unsigned int c, PrintBase base) { printNumber((unsigned long)c, (uint8_t)base); }
+ void print(unsigned long c, PrintBase base) { printNumber((unsigned long)c, (uint8_t)base); }
+ void print(long c, PrintBase base) { printNumber((signed long)c, (uint8_t)base); }
+ void print(EnsureDouble c, int digits) { printFloat(c, digits); }
+
+ // Forward the call to the former's method
+ FORCE_INLINE void print(char c) { print(c, PrintBase::Dec); }
+ FORCE_INLINE void print(unsigned char c) { print(c, PrintBase::Dec); }
+ FORCE_INLINE void print(int c) { print(c, PrintBase::Dec); }
+ FORCE_INLINE void print(unsigned int c) { print(c, PrintBase::Dec); }
+ FORCE_INLINE void print(unsigned long c) { print(c, PrintBase::Dec); }
+ FORCE_INLINE void print(long c) { print(c, PrintBase::Dec); }
+ FORCE_INLINE void print(double c) { print(c, 2); }
+
+ FORCE_INLINE void println(const char s[]) { print(s); println(); }
+ FORCE_INLINE void println(char c, PrintBase base) { print(c, base); println(); }
+ FORCE_INLINE void println(unsigned char c, PrintBase base) { print(c, base); println(); }
+ FORCE_INLINE void println(int c, PrintBase base) { print(c, base); println(); }
+ FORCE_INLINE void println(unsigned int c, PrintBase base) { print(c, base); println(); }
+ FORCE_INLINE void println(long c, PrintBase base) { print(c, base); println(); }
+ FORCE_INLINE void println(unsigned long c, PrintBase base) { print(c, base); println(); }
+ FORCE_INLINE void println(double c, int digits) { print(c, digits); println(); }
+ FORCE_INLINE void println() { write('\r'); write('\n'); }
+
+ // Forward the call to the former's method
+ FORCE_INLINE void println(char c) { println(c, PrintBase::Dec); }
+ FORCE_INLINE void println(unsigned char c) { println(c, PrintBase::Dec); }
+ FORCE_INLINE void println(int c) { println(c, PrintBase::Dec); }
+ FORCE_INLINE void println(unsigned int c) { println(c, PrintBase::Dec); }
+ FORCE_INLINE void println(unsigned long c) { println(c, PrintBase::Dec); }
+ FORCE_INLINE void println(long c) { println(c, PrintBase::Dec); }
+ FORCE_INLINE void println(double c) { println(c, 2); }
+
+ // Print a number with the given base
+ NO_INLINE void printNumber(unsigned long n, const uint8_t base) {
+ if (!base) return; // Hopefully, this should raise visible bug immediately
+
+ 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--) write((char)(buf[i] + (buf[i] < 10 ? '0' : 'A' - 10)));
+ }
+ else write('0');
+ }
+ void printNumber(signed long n, const uint8_t base) {
+ if (base == 10 && n < 0) {
+ n = -n; // This works because all platforms Marlin's builds on are using 2-complement encoding for negative number
+ // On such CPU, changing the sign of a number is done by inverting the bits and adding one, so if n = 0x80000000 = -2147483648 then
+ // -n = 0x7FFFFFFF + 1 => 0x80000000 = 2147483648 (if interpreted as unsigned) or -2147483648 if interpreted as signed.
+ // On non 2-complement CPU, there would be no possible representation for 2147483648.
+ write('-');
+ }
+ printNumber((unsigned long)n , base);
+ }
+
+ // Print a decimal number
+ NO_INLINE void printFloat(double number, uint8_t digits) {
+ // Handle negative numbers
+ if (number < 0.0) {
+ write('-');
+ number = -number;
+ }
+
+ // Round correctly so that print(1.999, 2) prints as "2.00"
+ double rounding = 0.5;
+ LOOP_L_N(i, digits) 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;
+ printNumber(int_part, 10);
+
+ // Print the decimal point, but only if there are digits beyond
+ if (digits) {
+ write('.');
+ // Extract digits from the remainder one at a time
+ while (digits--) {
+ remainder *= 10.0;
+ unsigned long toPrint = (unsigned long)remainder;
+ printNumber(toPrint, 10);
+ remainder -= toPrint;
+ }
+ }
+ }
+};
+
+// All serial instances will be built by chaining the features required
+// for the function in the form of a template type definition.
diff --git a/Marlin/src/core/serial_hook.h b/Marlin/src/core/serial_hook.h
new file mode 100644
index 000000000000..ad8ec12b6e95
--- /dev/null
+++ b/Marlin/src/core/serial_hook.h
@@ -0,0 +1,240 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+#pragma once
+
+#include "macros.h"
+#include "serial_base.h"
+
+// The most basic serial class: it dispatch to the base serial class with no hook whatsoever. This will compile to nothing but the base serial class
+template
+struct BaseSerial : public SerialBase< BaseSerial >, public SerialT {
+ typedef SerialBase< BaseSerial > BaseClassT;
+
+ // It's required to implement a write method here to help compiler disambiguate what method to call
+ using SerialT::write;
+ using SerialT::flush;
+
+ void msgDone() {}
+
+ bool available(uint8_t index) { return index == 0 && SerialT::available(); }
+ int read(uint8_t index) { return index == 0 ? SerialT::read() : -1; }
+ bool connected() { return CALL_IF_EXISTS(bool, static_cast(this), connected);; }
+ void flushTX() { CALL_IF_EXISTS(void, static_cast(this), flushTX); }
+
+ // We have 2 implementation of the same method in both base class, let's say which one we want
+ using SerialT::available;
+ using SerialT::read;
+ using SerialT::begin;
+ using SerialT::end;
+
+ using BaseClassT::print;
+ using BaseClassT::println;
+
+ BaseSerial(const bool e) : BaseClassT(e) {}
+
+ // Forward constructor
+ template
+ BaseSerial(const bool e, Args... args) : BaseClassT(e), SerialT(args...) {}
+};
+
+// A serial with a condition checked at runtime for its output
+// A bit less efficient than static dispatching but since it's only used for ethernet's serial output right now, it's ok.
+template
+struct ConditionalSerial : public SerialBase< ConditionalSerial > {
+ typedef SerialBase< ConditionalSerial > BaseClassT;
+
+ bool & condition;
+ SerialT & out;
+ NO_INLINE size_t write(uint8_t c) { if (condition) return out.write(c); return 0; }
+ void flush() { if (condition) out.flush(); }
+ void begin(long br) { out.begin(br); }
+ void end() { out.end(); }
+
+ void msgDone() {}
+ bool connected() { return CALL_IF_EXISTS(bool, &out, connected); }
+ void flushTX() { CALL_IF_EXISTS(void, &out, flushTX); }
+
+ bool available(uint8_t index) { return index == 0 && out.available(); }
+ int read(uint8_t index) { return index == 0 ? out.read() : -1; }
+ using BaseClassT::available;
+ using BaseClassT::read;
+
+ ConditionalSerial(bool & conditionVariable, SerialT & out, const bool e) : BaseClassT(e), condition(conditionVariable), out(out) {}
+};
+
+// A simple foward class that taking a reference to an existing serial instance (likely created in their respective framework)
+template
+struct ForwardSerial : public SerialBase< ForwardSerial