diff --git a/.gitignore b/.gitignore
index 62f73a7c0d..f7d49cc1ed 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 4750b49e85..78a5dad7e8 100644
--- a/Marlin/Configuration.h
+++ b/Marlin/Configuration.h
@@ -418,7 +418,7 @@
#define TEMP_SENSOR_CHAMBER 0
// Dummy thermistor constant temperature readings, for use with 998 and 999
-#define DUMMY_THERMISTOR_998_VALUE 25
+#define DUMMY_THERMISTOR_998_VALUE 25
#define DUMMY_THERMISTOR_999_VALUE 100
// Resistor values when using MAX31865 sensors (-5) on TEMP_SENSOR_0 / 1
@@ -1317,10 +1317,11 @@
#define G26_MESH_VALIDATION
#if ENABLED(G26_MESH_VALIDATION)
#define MESH_TEST_NOZZLE_SIZE 0.4 // (mm) Diameter of primary nozzle.
- #define MESH_TEST_LAYER_HEIGHT 0.2 // (mm) Default layer height for the G26 Mesh Validation Tool.
- #define MESH_TEST_HOTEND_TEMP 205 // (°C) Default nozzle temperature for the G26 Mesh Validation Tool.
- #define MESH_TEST_BED_TEMP 60 // (°C) Default bed temperature for the G26 Mesh Validation Tool.
- #define G26_XY_FEEDRATE 20 // (mm/s) Feedrate for XY Moves for the G26 Mesh Validation Tool.
+ #define MESH_TEST_LAYER_HEIGHT 0.2 // (mm) Default layer height for G26.
+ #define MESH_TEST_HOTEND_TEMP 205 // (°C) Default nozzle temperature for G26.
+ #define MESH_TEST_BED_TEMP 60 // (°C) Default bed temperature for G26.
+ #define G26_XY_FEEDRATE 20 // (mm/s) Feedrate for G26 XY moves.
+ #define G26_XY_FEEDRATE_TRAVEL 100 // (mm/s) Feedrate for G26 XY travel moves.
#define G26_RETRACT_MULTIPLIER 1.0 // G26 Q (retraction) used by default between mesh test elements.
#endif
@@ -1707,6 +1708,9 @@
* View the current statistics with M78.
*/
#define PRINTCOUNTER
+#if ENABLED(PRINTCOUNTER)
+ #define PRINTCOUNTER_SAVE_INTERVAL 60 // (minutes) EEPROM save interval during print
+#endif
/**
* Password
@@ -1751,9 +1755,9 @@
* Select the language to display on the LCD. These languages are available:
*
* en, an, bg, ca, cz, da, de, el, el_gr, es, eu, fi, fr, gl, hr, hu, it,
- * jp_kana, ko_KR, nl, pl, pt, pt_br, ro, ru, sk, tr, uk, vi, zh_CN, zh_TW, test
+ * jp_kana, ko_KR, nl, pl, pt, pt_br, ro, ru, sk, sv, tr, uk, vi, zh_CN, zh_TW
*
- * :{ 'en':'English', 'an':'Aragonese', 'bg':'Bulgarian', 'ca':'Catalan', 'cz':'Czech', 'da':'Danish', 'de':'German', 'el':'Greek', 'el_gr':'Greek (Greece)', 'es':'Spanish', 'eu':'Basque-Euskera', 'fi':'Finnish', 'fr':'French', 'gl':'Galician', 'hr':'Croatian', 'hu':'Hungarian', 'it':'Italian', 'jp_kana':'Japanese', 'ko_KR':'Korean (South Korea)', 'nl':'Dutch', 'pl':'Polish', 'pt':'Portuguese', 'pt_br':'Portuguese (Brazilian)', 'ro':'Romanian', 'ru':'Russian', 'sk':'Slovak', 'tr':'Turkish', 'uk':'Ukrainian', 'vi':'Vietnamese', 'zh_CN':'Chinese (Simplified)', 'zh_TW':'Chinese (Traditional)', 'test':'TEST' }
+ * :{ 'en':'English', 'an':'Aragonese', 'bg':'Bulgarian', 'ca':'Catalan', 'cz':'Czech', 'da':'Danish', 'de':'German', 'el':'Greek', 'el_gr':'Greek (Greece)', 'es':'Spanish', 'eu':'Basque-Euskera', 'fi':'Finnish', 'fr':'French', 'gl':'Galician', 'hr':'Croatian', 'hu':'Hungarian', 'it':'Italian', 'jp_kana':'Japanese', 'ko_KR':'Korean (South Korea)', 'nl':'Dutch', 'pl':'Polish', 'pt':'Portuguese', 'pt_br':'Portuguese (Brazilian)', 'ro':'Romanian', 'ru':'Russian', 'sk':'Slovak', 'sv':'Swedish', 'tr':'Turkish', 'uk':'Ukrainian', 'vi':'Vietnamese', 'zh_CN':'Chinese (Simplified)', 'zh_TW':'Chinese (Traditional)' }
*/
#define LCD_LANGUAGE en
diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h
index f4c23b7eac..6b8eb332f4 100644
--- a/Marlin/Configuration_adv.h
+++ b/Marlin/Configuration_adv.h
@@ -163,7 +163,7 @@
#if ENABLED(CHAMBER_VENT)
#define CHAMBER_VENT_SERVO_NR 1 // Index of the vent servo
#define HIGH_EXCESS_HEAT_LIMIT 5 // How much above target temp to consider there is excess heat in the chamber
- #define LOW_EXCESS_HEAT_LIMIT 3
+ #define LOW_EXCESS_HEAT_LIMIT 3
#define MIN_COOLING_SLOPE_TIME_CHAMBER_VENT 20
#define MIN_COOLING_SLOPE_DEG_CHAMBER_VENT 1.5
#endif
@@ -284,8 +284,8 @@
// DEFAULT_Kf and PID_FAN_SCALING_LIN_FACTOR are calculated accordingly.
#define PID_FAN_SCALING_AT_FULL_SPEED 13.0 //=PID_FAN_SCALING_LIN_FACTOR*255+DEFAULT_Kf
- #define PID_FAN_SCALING_AT_MIN_SPEED 6.0 //=PID_FAN_SCALING_LIN_FACTOR*PID_FAN_SCALING_MIN_SPEED+DEFAULT_Kf
- #define PID_FAN_SCALING_MIN_SPEED 10.0 // Minimum fan speed at which to enable PID_FAN_SCALING
+ #define PID_FAN_SCALING_AT_MIN_SPEED 6.0 //=PID_FAN_SCALING_LIN_FACTOR*PID_FAN_SCALING_MIN_SPEED+DEFAULT_Kf
+ #define PID_FAN_SCALING_MIN_SPEED 10.0 // Minimum fan speed at which to enable PID_FAN_SCALING
#define DEFAULT_Kf (255.0*PID_FAN_SCALING_AT_MIN_SPEED-PID_FAN_SCALING_AT_FULL_SPEED*PID_FAN_SCALING_MIN_SPEED)/(255.0-PID_FAN_SCALING_MIN_SPEED)
#define PID_FAN_SCALING_LIN_FACTOR (PID_FAN_SCALING_AT_FULL_SPEED-DEFAULT_Kf)/255.0
@@ -1523,6 +1523,19 @@
#endif
#endif // HAS_DGUS_LCD
+//
+// Specify additional languages for the UI. Default specified by LCD_LANGUAGE.
+//
+#if EITHER(DOGLCD, TOUCH_UI_FTDI_EVE)
+ //#define LCD_LANGUAGE_2 fr
+ //#define LCD_LANGUAGE_3 de
+ //#define LCD_LANGUAGE_4 es
+ //#define LCD_LANGUAGE_5 it
+ #ifdef LCD_LANGUAGE_2
+ //#define LCD_LANGUAGE_AUTO_SAVE // Automatically save language to EEPROM on change
+ #endif
+#endif
+
//
// Touch UI for the FTDI Embedded Video Engine (EVE)
//
@@ -1598,13 +1611,6 @@
// Use a smaller font when labels don't fit buttons
#define TOUCH_UI_FIT_TEXT
- // Allow language selection from menu at run-time (otherwise use LCD_LANGUAGE)
- //#define LCD_LANGUAGE_1 en
- //#define LCD_LANGUAGE_2 fr
- //#define LCD_LANGUAGE_3 de
- //#define LCD_LANGUAGE_4 es
- //#define LCD_LANGUAGE_5 it
-
// Use a numeric passcode for "Screen lock" keypad.
// (recommended for smaller displays)
//#define TOUCH_UI_PASSCODE
@@ -2050,21 +2056,21 @@
*/
#define FWRETRACT
#if ENABLED(FWRETRACT)
- #define FWRETRACT_AUTORETRACT // Override slicer retractions
+ #define FWRETRACT_AUTORETRACT // Override slicer retractions
#if ENABLED(FWRETRACT_AUTORETRACT)
- #define MIN_AUTORETRACT 0.1 // (mm) Don't convert E moves under this length
- #define MAX_AUTORETRACT 10.0 // (mm) Don't convert E moves over this length
+ #define MIN_AUTORETRACT 0.1 // (mm) Don't convert E moves under this length
+ #define MAX_AUTORETRACT 10.0 // (mm) Don't convert E moves over this length
#endif
- #define RETRACT_LENGTH 3 // (mm) Default retract length (positive value)
- #define RETRACT_LENGTH_SWAP 13 // (mm) Default swap retract length (positive value)
- #define RETRACT_FEEDRATE 45 // (mm/s) Default feedrate for retracting
- #define RETRACT_ZRAISE 0 // (mm) Default retract Z-raise
- #define RETRACT_RECOVER_LENGTH 0 // (mm) Default additional recover length (added to retract length on recover)
- #define RETRACT_RECOVER_LENGTH_SWAP 0 // (mm) Default additional swap recover length (added to retract length on recover from toolchange)
- #define RETRACT_RECOVER_FEEDRATE 8 // (mm/s) Default feedrate for recovering from retraction
- #define RETRACT_RECOVER_FEEDRATE_SWAP 8 // (mm/s) Default feedrate for recovering from swap retraction
+ #define RETRACT_LENGTH 3 // (mm) Default retract length (positive value)
+ #define RETRACT_LENGTH_SWAP 13 // (mm) Default swap retract length (positive value)
+ #define RETRACT_FEEDRATE 45 // (mm/s) Default feedrate for retracting
+ #define RETRACT_ZRAISE 0 // (mm) Default retract Z-raise
+ #define RETRACT_RECOVER_LENGTH 0 // (mm) Default additional recover length (added to retract length on recover)
+ #define RETRACT_RECOVER_LENGTH_SWAP 0 // (mm) Default additional swap recover length (added to retract length on recover from toolchange)
+ #define RETRACT_RECOVER_FEEDRATE 8 // (mm/s) Default feedrate for recovering from retraction
+ #define RETRACT_RECOVER_FEEDRATE_SWAP 8 // (mm/s) Default feedrate for recovering from swap retraction
#if ENABLED(MIXING_EXTRUDER)
- //#define RETRACT_SYNC_MIXING // Retract and restore all mixing steppers simultaneously
+ //#define RETRACT_SYNC_MIXING // Retract and restore all mixing steppers simultaneously
#endif
#endif
@@ -3292,6 +3298,8 @@
//#define GCODE_QUOTED_STRINGS // Support for quoted string parameters
#endif
+//#define MEATPACK // Support for MeatPack G-code compression (https://github.com/scottmudge/OctoPrint-MeatPack)
+
//#define GCODE_CASE_INSENSITIVE // Accept G-code sent to the firmware in lowercase
//#define REPETIER_GCODE_M360 // Add commands originally from Repetier FW
@@ -3341,7 +3349,7 @@
//#define USER_SCRIPT_RETURN // Return to status screen after a script
#define USER_DESC_1 "Home & UBL Info"
- #define USER_GCODE_1 "G29NW"
+ #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)
@@ -3350,7 +3358,7 @@
#define USER_GCODE_3 "M140 S" STRINGIFY(PREHEAT_2_TEMP_BED) "\nM104 S" STRINGIFY(PREHEAT_2_TEMP_HOTEND)
#define USER_DESC_4 "Heat Bed/Home/Level"
- #define USER_GCODE_4 "M140 S" STRINGIFY(PREHEAT_2_TEMP_BED) "\nG29N"
+ #define USER_GCODE_4 "M140 S" STRINGIFY(PREHEAT_2_TEMP_BED) "\nG28\nG29"
#define USER_DESC_5 "Home & Info"
#define USER_GCODE_5 "G28\nM503"
diff --git a/Marlin/src/HAL/AVR/HAL.cpp b/Marlin/src/HAL/AVR/HAL.cpp
index 58d57c8ee5..4c45a5d78e 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 c7dfc3a8cb..ed913254ad 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."
diff --git a/Marlin/src/HAL/AVR/MarlinSerial.cpp b/Marlin/src/HAL/AVR/MarlinSerial.cpp
index 185ce94757..84ffe7cce2 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< MarlinSerialCfg >;
+ 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 || ENABLED(DGUS_LCD_UI_CREALITY_TOUCH)
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 28ffe899d9..17de771fdc 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 || ENABLED(DGUS_LCD_UI_CREALITY_TOUCH)
- static ring_buffer_pos_t get_tx_buffer_free();
- #endif
+ 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 || ENABLED(DGUS_LCD_UI_CREALITY_TOUCH)
+ static ring_buffer_pos_t get_tx_buffer_free();
+ #endif
- static inline bool emergency_parser_enabled() { return Cfg::EMERGENCYPARSER; }
+ 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; }
-
- 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);
+ 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;
+
+ typedef Serial0Type< MarlinSerial< MarlinSerialCfg > > MSerialT;
+ extern MSerialT customizedSerial1;
#ifdef SERIAL_PORT_2
-
- extern MarlinSerial> customizedSerial2;
-
+ 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 MSerial3 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/DUE/HAL.cpp b/Marlin/src/HAL/DUE/HAL.cpp
index 6ce85a4643..2ae70843f0 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 4783947f6f..78c8a800b9 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)
@@ -61,7 +72,7 @@
#ifdef MMU2_SERIAL_PORT
#if WITHIN(MMU2_SERIAL_PORT, 0, 3)
- #define MMU2_SERIAL MSERIAL(SERIAL_PORT)
+ #define MMU2_SERIAL MSERIAL(MMU2_SERIAL_PORT)
#else
#error "MMU2_SERIAL_PORT must be from 0 to 3. Please update your configuration."
#endif
@@ -83,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/MarlinSerial.cpp b/Marlin/src/HAL/DUE/MarlinSerial.cpp
index c9a372eeb1..50b84c0b1d 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 a194eba2f3..7fc21264bb 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 @@ public:
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 @@ public:
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 a41dbfeb7a..d85aaf14b0 100644
--- a/Marlin/src/HAL/DUE/MarlinSerialUSB.cpp
+++ b/Marlin/src/HAL/DUE/MarlinSerialUSB.cpp
@@ -50,10 +50,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) {}
@@ -111,13 +107,13 @@ 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 +125,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 2e3622e553..9643a8465a 100644
--- a/Marlin/src/HAL/DUE/MarlinSerialUSB.h
+++ b/Marlin/src/HAL/DUE/MarlinSerialUSB.h
@@ -27,20 +27,13 @@
*/
#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() {};
+struct MarlinSerialUSB {
static void begin(const long);
static void end();
static int peek();
@@ -48,7 +41,7 @@ public:
static void flush();
static void flushTX();
static bool available();
- static void write(const uint8_t c);
+ static size_t write(const uint8_t c);
#if ENABLED(SERIAL_STATS_DROPPED_RX)
FORCE_INLINE static uint32_t dropped() { return 0; }
@@ -57,43 +50,15 @@ public:
#if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
FORCE_INLINE static 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/usb/sd_mmc_spi_mem.cpp b/Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.cpp
index db5e82ec55..d92d332c1e 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 d4b2f42c53..cc5a4fc476 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 b43caea13c..27df0be4b6 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 ead448d78d..6ff1446b1c 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
// ------------------------
diff --git a/Marlin/src/HAL/ESP32/HAL.h b/Marlin/src/HAL/ESP32/HAL.h
index be87737b0f..3dc27c6493 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
// ------------------------
diff --git a/Marlin/src/HAL/ESP32/WebSocketSerial.cpp b/Marlin/src/HAL/ESP32/WebSocketSerial.cpp
index ca7f47a1f8..8825742d38 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 7a25c6dc5e..c68792c8c1 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 @@ public:
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 @@ public:
#endif
};
-extern WebSocketSerial webSocketSerial;
+typedef Serial0Type MSerialT;
+extern MSerialT webSocketSerial;
diff --git a/Marlin/src/HAL/LINUX/HAL.cpp b/Marlin/src/HAL/LINUX/HAL.cpp
index ee9e31e140..771f1d2a08 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 729f6c856e..e4f4dd3fc3 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 6aeb0db583..d4086e259a 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 e916249389..2585be25bf 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 @@ private:
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 @@ public:
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 @@ public:
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 eadc409324..c409a83e5d 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 3614e95385..27aa569fae 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
diff --git a/Marlin/src/HAL/LPC1768/HAL.h b/Marlin/src/HAL/LPC1768/HAL.h
index 44a4e88624..1dc4fe6ff9 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
@@ -84,7 +87,7 @@ extern "C" volatile uint32_t _millis;
#ifdef MMU2_SERIAL_PORT
#if MMU2_SERIAL_PORT == -1
- #define MMU2_SERIAL UsbSerial
+ #define MMU2_SERIAL USBSerial
#elif WITHIN(MMU2_SERIAL_PORT, 0, 3)
#define MMU2_SERIAL MSERIAL(MMU2_SERIAL_PORT)
#else
@@ -94,7 +97,7 @@ extern "C" volatile uint32_t _millis;
#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
@@ -214,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 baad3f8f26..454ace33b2 100644
--- a/Marlin/src/HAL/LPC1768/MarlinSerial.cpp
+++ b/Marlin/src/HAL/LPC1768/MarlinSerial.cpp
@@ -25,19 +25,19 @@
#include "MarlinSerial.h"
#if USING_SERIAL_0
- MarlinSerial MSerial(LPC_UART0);
+ MSerialT MSerial(true, LPC_UART0);
extern "C" void UART0_IRQHandler() { MSerial.IRQHandler(); }
#endif
#if USING_SERIAL_1
- MarlinSerial MSerial1((LPC_UART_TypeDef *) LPC_UART1);
+ MSerialT MSerial1(true, (LPC_UART_TypeDef *) LPC_UART1);
extern "C" void UART1_IRQHandler() { MSerial1.IRQHandler(); }
#endif
#if USING_SERIAL_2
- MarlinSerial MSerial2(LPC_UART2);
+ MSerialT MSerial2(true, LPC_UART2);
extern "C" void UART2_IRQHandler() { MSerial2.IRQHandler(); }
#endif
#if USING_SERIAL_3
- MarlinSerial MSerial3(LPC_UART3);
+ 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 8d6b64378a..de0f62f006 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/inc/Conditionals_post.h b/Marlin/src/HAL/LPC1768/inc/Conditionals_post.h
index ce6d3fdde2..94e4ce1341 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/SAMD51/HAL.cpp b/Marlin/src/HAL/SAMD51/HAL.cpp
index d985ef3787..a413c4cd80 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 fd2eb59475..f28583c771 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
@@ -59,7 +63,7 @@
#ifdef MMU2_SERIAL_PORT
#if MMU2_SERIAL_PORT == -1
- #define MMU2_SERIAL Serial
+ #define MMU2_SERIAL MSerial
#elif WITHIN(MMU2_SERIAL_PORT, 0, 3)
#define MMU2_SERIAL MSERIAL(MMU2_SERIAL_PORT)
#else
@@ -69,7 +73,7 @@
#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 fac67cf5a3..ce32eafee5 100644
--- a/Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.cpp
+++ b/Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.cpp
@@ -28,7 +28,7 @@
#include "../../inc/MarlinConfig.h"
#if USING_SERIAL_1
- Uart Serial2(&sercom4, PIN_SERIAL2_RX, PIN_SERIAL2_TX, PAD_SERIAL2_RX, PAD_SERIAL2_TX);
+ 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(); }
@@ -36,7 +36,7 @@
#endif
#if USING_SERIAL_2
- Uart Serial3(&sercom1, PIN_SERIAL3_RX, PIN_SERIAL3_TX, PAD_SERIAL3_RX, PAD_SERIAL3_TX);
+ 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(); }
@@ -44,7 +44,7 @@
#endif
#if USING_SERIAL_3
- Uart Serial4(&sercom5, PIN_SERIAL4_RX, PIN_SERIAL4_TX, PAD_SERIAL4_RX, PAD_SERIAL4_TX);
+ 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 f3821d8d5a..b7293415d1 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/STM32/HAL.cpp b/Marlin/src/HAL/STM32/HAL.cpp
index c886f9c0b9..b8db5b5e0b 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
diff --git a/Marlin/src/HAL/STM32/HAL.h b/Marlin/src/HAL/STM32/HAL.h
index 1c6f7743b8..baac7aad3e 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
@@ -67,7 +70,7 @@
#ifdef MMU2_SERIAL_PORT
#if MMU2_SERIAL_PORT == -1
- #define MMU2_SERIAL SerialUSB
+ #define MMU2_SERIAL MSerial
#elif WITHIN(MMU2_SERIAL_PORT, 1, 6)
#define MMU2_SERIAL MSERIAL(MMU2_SERIAL_PORT)
#else
@@ -77,7 +80,7 @@
#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
@@ -106,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
// ------------------------
diff --git a/Marlin/src/HAL/STM32/MarlinSerial.cpp b/Marlin/src/HAL/STM32/MarlinSerial.cpp
index 4d9177248a..c420ce40cf 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)
diff --git a/Marlin/src/HAL/STM32/MarlinSerial.h b/Marlin/src/HAL/STM32/MarlinSerial.h
index 3611cc78d7..8cc4f0dd4c 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 @@ public:
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/eeprom_flash.cpp b/Marlin/src/HAL/STM32/eeprom_flash.cpp
index 8cd62879a5..633a286dc8 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/STM32F1/HAL.cpp b/Marlin/src/HAL/STM32F1/HAL.cpp
index dfa99d83f4..c1e29a843c 100644
--- a/Marlin/src/HAL/STM32F1/HAL.cpp
+++ b/Marlin/src/HAL/STM32F1/HAL.cpp
@@ -84,6 +84,7 @@
#if defined(SERIAL_USB) && !HAS_SD_HOST_DRIVE
USBSerial SerialUSB;
+ DefaultSerial MSerial(false, SerialUSB);
#endif
uint16_t HAL_adc_result;
diff --git a/Marlin/src/HAL/STM32F1/HAL.h b/Marlin/src/HAL/STM32F1/HAL.h
index 26f321bfed..162c428fad 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
@@ -152,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 7c9625d64c..c404e81b35 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 6aa94b64ff..692e97e618 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 @@ public:
#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/eeprom_wired.cpp b/Marlin/src/HAL/STM32F1/eeprom_wired.cpp
index 6e992a22a3..16cfc24af6 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/msc_sd.cpp b/Marlin/src/HAL/STM32F1/msc_sd.cpp
index ba722b8aeb..548a6dbc57 100644
--- a/Marlin/src/HAL/STM32F1/msc_sd.cpp
+++ b/Marlin/src/HAL/STM32F1/msc_sd.cpp
@@ -23,7 +23,7 @@
#define PRODUCT_ID 0x29
USBMassStorage MarlinMSC;
-MarlinUSBCompositeSerial MarlinCompositeSerial;
+Serial0Type MarlinCompositeSerial(true);
#include "../../inc/MarlinConfig.h"
diff --git a/Marlin/src/HAL/STM32F1/msc_sd.h b/Marlin/src/HAL/STM32F1/msc_sd.h
index 1e4e4c44b1..151287f7a7 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 8c3dd83377..51636d29bf 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 9156aadb4d..5273b38637 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/TEENSY35_36/HAL.cpp b/Marlin/src/HAL/TEENSY35_36/HAL.cpp
index 92907353b8..547681de5f 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 04151e8378..94c514bf62 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/TEENSY40_41/HAL.cpp b/Marlin/src/HAL/TEENSY40_41/HAL.cpp
index 5b1b4272f5..26449d7eb2 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 28f511631e..6aa1e521a4 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/Marduino.h b/Marlin/src/HAL/shared/Marduino.h
index 2580723511..d0ee6ecc9d 100644
--- a/Marlin/src/HAL/shared/Marduino.h
+++ b/Marlin/src/HAL/shared/Marduino.h
@@ -81,3 +81,5 @@
#ifndef UNUSED
#define UNUSED(x) ((void)(x))
#endif
+
+#include "progmem.h"
diff --git a/Marlin/src/HAL/shared/progmem.h b/Marlin/src/HAL/shared/progmem.h
new file mode 100644
index 0000000000..539d02705e
--- /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 f994e2e32c..51e0efafd6 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,8 +412,8 @@ 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);
@@ -550,6 +451,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);
@@ -785,8 +687,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 +784,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 +886,27 @@ void setup() {
#endif
#define SETUP_RUN(C) do{ SETUP_LOG(STRINGIFY(C)); C; }while(0)
+ // 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)
@@ -996,12 +920,12 @@ void setup() {
MYSERIAL0.begin(BAUDRATE);
millis_t serial_connect_timeout = millis() + 1000UL;
- while (!MYSERIAL0 && PENDING(millis(), serial_connect_timeout)) { /*nada*/ }
+ 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 && PENDING(millis(), serial_connect_timeout)) { /*nada*/ }
+ while (!MYSERIAL1.connected() && PENDING(millis(), serial_connect_timeout)) { /*nada*/ }
#endif
SERIAL_ECHOLNPGM("start");
@@ -1038,14 +962,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
diff --git a/Marlin/src/MarlinCore.h b/Marlin/src/MarlinCore.h
index 908636e967..d43d46bbd8 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 13a202daed..afb6887766 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
diff --git a/Marlin/src/core/language.h b/Marlin/src/core/language.h
index d6048d293c..923ad903cb 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 d5b3342437..dcc688ae29 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")))
@@ -162,6 +163,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))
@@ -313,6 +315,32 @@
#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; };
+ }
+ // 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 6af4af2f8d..5a26edf8d4 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 0d22f7bfc0..365f28ba55 100644
--- a/Marlin/src/core/serial.cpp
+++ b/Marlin/src/core/serial.cpp
@@ -23,20 +23,41 @@
#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, 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); }
@@ -65,8 +86,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 4824866aeb..4c0c32f7d8 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,39 +55,37 @@ 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_PORTMASK(P) _BV(P)
#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
diff --git a/Marlin/src/core/serial_base.h b/Marlin/src/core/serial_base.h
new file mode 100644
index 0000000000..220ccae831
--- /dev/null
+++ b/Marlin/src/core/serial_base.h
@@ -0,0 +1,146 @@
+/**
+ * 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"
+
+#if ENABLED(EMERGENCY_PARSER)
+ #include "../feature/e_parser.h"
+#endif
+
+#ifndef DEC
+ #define DEC 10
+ #define HEX 16
+ #define OCT 8
+ #define BIN 2
+#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);
+
+// 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 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_INLINE void print(char c, int base = 0) { print((long)c, base); }
+ NO_INLINE void print(unsigned char c, int base = 0) { print((unsigned long)c, base); }
+ NO_INLINE void print(int c, int base = DEC) { print((long)c, base); }
+ NO_INLINE void print(unsigned int c, int base = DEC) { print((unsigned long)c, base); }
+ void print(long c, int base = DEC) { if (!base) write(c); write((const uint8_t*)"-", c < 0); printNumber(c < 0 ? -c : c, base); }
+ void print(unsigned long c, int base = DEC) { printNumber(c, base); }
+ void print(double c, int digits = 2) { printFloat(c, digits); }
+
+ NO_INLINE void println(const char s[]) { print(s); println(); }
+ NO_INLINE void println(char c, int base = 0) { print(c, base); println(); }
+ NO_INLINE void println(unsigned char c, int base = 0) { print(c, base); println(); }
+ NO_INLINE void println(int c, int base = DEC) { print(c, base); println(); }
+ NO_INLINE void println(unsigned int c, int base = DEC) { print(c, base); println(); }
+ NO_INLINE void println(long c, int base = DEC) { print(c, base); println(); }
+ NO_INLINE void println(unsigned long c, int base = DEC) { print(c, base); println(); }
+ NO_INLINE void println(double c, int digits = 2) { print(c, digits); println(); }
+ NO_INLINE void println() { write('\r'); write('\n'); }
+
+ // Print a number with the given base
+ void printNumber(unsigned long n, const 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--) write((char)(buf[i] + (buf[i] < 10 ? '0' : 'A' - 10)));
+ }
+ else write('0');
+ }
+
+ // Print a decimal number
+ 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;
+ int toPrint = int(remainder);
+ printNumber(toPrint, 10);
+ remainder -= toPrint;
+ }
+ }
+ }
+};
+
+// All serial instances will be built by chaining the features required for the function in a 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 0000000000..e14b821a9c
--- /dev/null
+++ b/Marlin/src/core/serial_hook.h
@@ -0,0 +1,234 @@
+/**
+ * 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 "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);; }
+ // 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); }
+
+ 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 > {
+ typedef SerialBase< ForwardSerial > BaseClassT;
+
+ SerialT & out;
+ NO_INLINE size_t write(uint8_t c) { return out.write(c); }
+ void flush() { out.flush(); }
+ void begin(long br) { out.begin(br); }
+ void end() { out.end(); }
+
+ void msgDone() {}
+ // Existing instances implement Arduino's operator bool, so use that if it's available
+ bool connected() { return Private::HasMember_connected::value ? CALL_IF_EXISTS(bool, &out, connected) : (bool)out; }
+
+ bool available(uint8_t index) { return index == 0 && out.available(); }
+ int read(uint8_t index) { return index == 0 ? out.read() : -1; }
+ bool available() { return out.available(); }
+ int read() { return out.read(); }
+
+ ForwardSerial(const bool e, SerialT & out) : BaseClassT(e), out(out) {}
+};
+
+// A class that's can be hooked and unhooked at runtime, useful to capturing the output of the serial interface
+template
+struct RuntimeSerial : public SerialBase< RuntimeSerial >, public SerialT {
+ typedef SerialBase< RuntimeSerial > BaseClassT;
+ typedef void (*WriteHook)(void * userPointer, uint8_t c);
+ typedef void (*EndOfMessageHook)(void * userPointer);
+
+ WriteHook writeHook;
+ EndOfMessageHook eofHook;
+ void * userPointer;
+
+ NO_INLINE size_t write(uint8_t c) {
+ if (writeHook) writeHook(userPointer, c);
+ return SerialT::write(c);
+ }
+
+ NO_INLINE void msgDone() {
+ if (eofHook) eofHook(userPointer);
+ }
+
+ bool available(uint8_t index) { return index == 0 && SerialT::available(); }
+ int read(uint8_t index) { return index == 0 ? SerialT::read() : -1; }
+ using SerialT::available;
+ using SerialT::read;
+ using SerialT::flush;
+ using SerialT::begin;
+ using SerialT::end;
+
+ using BaseClassT::print;
+ using BaseClassT::println;
+
+ // Underlying implementation might use Arduino's bool operator
+ bool connected() {
+ return Private::HasMember_connected::value ? CALL_IF_EXISTS(bool, static_cast(this), connected) : static_cast(this)->operator bool();
+ }
+
+ void setHook(WriteHook writeHook = 0, EndOfMessageHook eofHook = 0, void * userPointer = 0) {
+ // Order is important here as serial code can be called inside interrupts
+ // When setting a hook, the user pointer must be set first so if writeHook is called as soon as it's set, it'll be valid
+ if (userPointer) this->userPointer = userPointer;
+ this->writeHook = writeHook;
+ this->eofHook = eofHook;
+ // Order is important here because of asynchronous access here
+ // When unsetting a hook, the user pointer must be unset last so that any pending writeHook is still using the old pointer
+ if (!userPointer) this->userPointer = 0;
+ }
+
+ RuntimeSerial(const bool e) : BaseClassT(e), writeHook(0), eofHook(0), userPointer(0) {}
+
+ // Forward constructor
+ template
+ RuntimeSerial(const bool e, Args... args) : BaseClassT(e), SerialT(args...) {}
+};
+
+// A class that's duplicating its output conditionally to 2 serial interface
+template
+struct MultiSerial : public SerialBase< MultiSerial > {
+ typedef SerialBase< MultiSerial > BaseClassT;
+
+ uint8_t portMask;
+ Serial0T & serial0;
+ Serial1T & serial1;
+
+ enum Masks {
+ FirstOutputMask = (1 << offset),
+ SecondOutputMask = (1 << (offset + 1)),
+ AllMask = FirstOutputMask | SecondOutputMask,
+ };
+
+ NO_INLINE size_t write(uint8_t c) {
+ size_t ret = 0;
+ if (portMask & FirstOutputMask) ret = serial0.write(c);
+ if (portMask & SecondOutputMask) ret = serial1.write(c) | ret;
+ return ret;
+ }
+ NO_INLINE void msgDone() {
+ if (portMask & FirstOutputMask) serial0.msgDone();
+ if (portMask & SecondOutputMask) serial1.msgDone();
+ }
+ bool available(uint8_t index) {
+ switch(index) {
+ case 0 + offset: return serial0.available();
+ case 1 + offset: return serial1.available();
+ default: return false;
+ }
+ }
+ NO_INLINE int read(uint8_t index) {
+ switch(index) {
+ case 0 + offset: return serial0.read();
+ case 1 + offset: return serial1.read();
+ default: return -1;
+ }
+ }
+ void begin(const long br) {
+ if (portMask & FirstOutputMask) serial0.begin(br);
+ if (portMask & SecondOutputMask) serial1.begin(br);
+ }
+ void end() {
+ if (portMask & FirstOutputMask) serial0.end();
+ if (portMask & SecondOutputMask) serial1.end();
+ }
+ bool connected() {
+ bool ret = true;
+ if (portMask & FirstOutputMask) ret = CALL_IF_EXISTS(bool, &serial0, connected);
+ if (portMask & SecondOutputMask) ret = ret && CALL_IF_EXISTS(bool, &serial1, connected);
+ return ret;
+ }
+
+ using BaseClassT::available;
+ using BaseClassT::read;
+
+ // Redirect flush
+ NO_INLINE void flush() {
+ if (portMask & FirstOutputMask) serial0.flush();
+ if (portMask & SecondOutputMask) serial1.flush();
+ }
+ NO_INLINE void flushTX() {
+ if (portMask & FirstOutputMask) CALL_IF_EXISTS(void, &serial0, flushTX);
+ if (portMask & SecondOutputMask) CALL_IF_EXISTS(void, &serial1, flushTX);
+ }
+
+ MultiSerial(Serial0T & serial0, Serial1T & serial1, int8_t mask = AllMask, const bool e = false) :
+ BaseClassT(e),
+ portMask(mask), serial0(serial0), serial1(serial1) {}
+};
+
+// Build the actual serial object depending on current configuration
+#define Serial0Type TERN(SERIAL_RUNTIME_HOOK, RuntimeSerial, BaseSerial)
+#define ForwardSerial0Type TERN(SERIAL_RUNTIME_HOOK, RuntimeSerial, ForwardSerial)
+#ifdef HAS_MULTI_SERIAL
+ #define Serial1Type ConditionalSerial
+#endif
diff --git a/Marlin/src/feature/binary_stream.h b/Marlin/src/feature/binary_stream.h
index 32ebcce2f6..81d6e7184b 100644
--- a/Marlin/src/feature/binary_stream.h
+++ b/Marlin/src/feature/binary_stream.h
@@ -30,23 +30,11 @@
#endif
inline bool bs_serial_data_available(const uint8_t index) {
- switch (index) {
- case 0: return MYSERIAL0.available();
- #if HAS_MULTI_SERIAL
- case 1: return MYSERIAL1.available();
- #endif
- }
- return false;
+ return SERIAL_IMPL.available(index);
}
inline int bs_read_serial(const uint8_t index) {
- switch (index) {
- case 0: return MYSERIAL0.read();
- #if HAS_MULTI_SERIAL
- case 1: return MYSERIAL1.read();
- #endif
- }
- return -1;
+ return SERIAL_IMPL.read(index);
}
#if ENABLED(BINARY_STREAM_COMPRESSION)
@@ -297,7 +285,7 @@ public:
millis_t transfer_window = millis() + RX_TIMESLICE;
#if ENABLED(SDSUPPORT)
- PORT_REDIRECT(card.transfer_port_index);
+ PORT_REDIRECT(SERIAL_PORTMASK(card.transfer_port_index));
#endif
#pragma GCC diagnostic push
diff --git a/Marlin/src/feature/e_parser.h b/Marlin/src/feature/e_parser.h
index a4c07de465..659e516787 100644
--- a/Marlin/src/feature/e_parser.h
+++ b/Marlin/src/feature/e_parser.h
@@ -33,7 +33,6 @@
// External references
extern bool wait_for_user, wait_for_heatup;
-void quickstop_stepper();
class EmergencyParser {
diff --git a/Marlin/src/feature/encoder_i2c.cpp b/Marlin/src/feature/encoder_i2c.cpp
index dda165edf7..fa3cf1503f 100644
--- a/Marlin/src/feature/encoder_i2c.cpp
+++ b/Marlin/src/feature/encoder_i2c.cpp
@@ -41,6 +41,8 @@
#include
+I2CPositionEncodersMgr I2CPEM;
+
void I2CPositionEncoder::init(const uint8_t address, const AxisEnum axis) {
encoderAxis = axis;
i2cAddress = address;
diff --git a/Marlin/src/feature/host_actions.cpp b/Marlin/src/feature/host_actions.cpp
index a8b2b51dfc..5ba3a3e3d2 100644
--- a/Marlin/src/feature/host_actions.cpp
+++ b/Marlin/src/feature/host_actions.cpp
@@ -38,7 +38,7 @@
#endif
void host_action(PGM_P const pstr, const bool eol) {
- PORT_REDIRECT(SERIAL_BOTH);
+ PORT_REDIRECT(SERIAL_ALL);
SERIAL_ECHOPGM("//action:");
serialprintPGM(pstr);
if (eol) SERIAL_EOL();
@@ -78,20 +78,20 @@ void host_action(PGM_P const pstr, const bool eol) {
PromptReason host_prompt_reason = PROMPT_NOT_DEFINED;
void host_action_notify(const char * const message) {
- PORT_REDIRECT(SERIAL_BOTH);
+ PORT_REDIRECT(SERIAL_ALL);
host_action(PSTR("notification "), false);
SERIAL_ECHOLN(message);
}
void host_action_notify_P(PGM_P const message) {
- PORT_REDIRECT(SERIAL_BOTH);
+ PORT_REDIRECT(SERIAL_ALL);
host_action(PSTR("notification "), false);
serialprintPGM(message);
SERIAL_EOL();
}
void host_action_prompt(PGM_P const ptype, const bool eol=true) {
- PORT_REDIRECT(SERIAL_BOTH);
+ PORT_REDIRECT(SERIAL_ALL);
host_action(PSTR("prompt_"), false);
serialprintPGM(ptype);
if (eol) SERIAL_EOL();
@@ -99,7 +99,7 @@ void host_action(PGM_P const pstr, const bool eol) {
void host_action_prompt_plus(PGM_P const ptype, PGM_P const pstr, const char extra_char='\0') {
host_action_prompt(ptype, false);
- PORT_REDIRECT(SERIAL_BOTH);
+ PORT_REDIRECT(SERIAL_ALL);
SERIAL_CHAR(' ');
serialprintPGM(pstr);
if (extra_char != '\0') SERIAL_CHAR(extra_char);
diff --git a/Marlin/src/feature/meatpack.cpp b/Marlin/src/feature/meatpack.cpp
new file mode 100644
index 0000000000..cd6d8ce6b9
--- /dev/null
+++ b/Marlin/src/feature/meatpack.cpp
@@ -0,0 +1,228 @@
+/**
+ * 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 .
+ *
+ */
+
+/**
+ * MeatPack G-code Compression
+ *
+ * Algorithm & Implementation: Scott Mudge - mail@scottmudge.com
+ * Date: Dec. 2020
+ *
+ * Character Frequencies from ~30 MB of comment-stripped gcode:
+ * '1' -> 4451136 '4' -> 1353273 '\n' -> 1087683 '-' -> 90242
+ * '0' -> 4253577 '9' -> 1352147 'G' -> 1075806 'Z' -> 34109
+ * ' ' -> 3053297 '3' -> 1262929 'X' -> 975742 'M' -> 11879
+ * '.' -> 3035310 '5' -> 1189871 'E' -> 965275 'S' -> 9910
+ * '2' -> 1523296 '6' -> 1127900 'Y' -> 965274
+ * '8' -> 1366812 '7' -> 1112908 'F' -> 99416
+ *
+ * When space is omitted the letter 'E' is used in its place
+ */
+
+#include "../inc/MarlinConfig.h"
+
+#if ENABLED(MEATPACK)
+
+#include "meatpack.h"
+MeatPack meatpack;
+
+#define MeatPack_ProtocolVersion "PV01"
+//#define MP_DEBUG
+
+#define DEBUG_OUT ENABLED(MP_DEBUG)
+#include "../core/debug_out.h"
+
+bool MeatPack::cmd_is_next = false; // A command is pending
+uint8_t MeatPack::state = 0; // Configuration state OFF
+uint8_t MeatPack::second_char = 0; // The unpacked 2nd character from an out-of-sequence packed pair
+uint8_t MeatPack::cmd_count = 0, // Counts how many command bytes are received (need 2)
+ MeatPack::full_char_count = 0, // Counts how many full-width characters are to be received
+ MeatPack::char_out_count = 0; // Stores number of characters to be read out.
+uint8_t MeatPack::char_out_buf[2]; // Output buffer for caching up to 2 characters
+
+// The 15 most-common characters used in G-code, ~90-95% of all G-code uses these characters
+// Stored in SRAM for performance.
+uint8_t meatPackLookupTable[16] = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ '.', ' ', '\n', 'G', 'X',
+ '\0' // Unused. 0b1111 indicates a literal character
+};
+
+TERN_(MP_DEBUG, uint8_t chars_decoded = 0); // Log the first 64 bytes after each reset
+
+void MeatPack::reset_state() {
+ state = 0;
+ cmd_is_next = false;
+ second_char = 0;
+ cmd_count = full_char_count = char_out_count = 0;
+ TERN_(MP_DEBUG, chars_decoded = 0);
+}
+
+/**
+ * Unpack one or two characters from a packed byte into a buffer.
+ * Return flags indicating whether any literal bytes follow.
+ */
+uint8_t MeatPack::unpack_chars(const uint8_t pk, uint8_t* __restrict const chars_out) {
+ uint8_t out = 0;
+
+ // If lower nybble is 1111, the higher nybble is unused, and next char is full.
+ if ((pk & kFirstNotPacked) == kFirstNotPacked)
+ out = kFirstCharIsLiteral;
+ else {
+ const uint8_t chr = pk & 0x0F;
+ chars_out[0] = meatPackLookupTable[chr]; // Set the first char
+ }
+
+ // Check if upper nybble is 1111... if so, we don't need the second char.
+ if ((pk & kSecondNotPacked) == kSecondNotPacked)
+ out |= kSecondCharIsLiteral;
+ else {
+ const uint8_t chr = (pk >> 4) & 0x0F;
+ chars_out[1] = meatPackLookupTable[chr]; // Set the second char
+ }
+
+ return out;
+}
+
+/**
+ * Interpret a single (non-command) character
+ * according to the current MeatPack state.
+ */
+void MeatPack::handle_rx_char_inner(const uint8_t c) {
+ if (TEST(state, MPConfig_Bit_Active)) { // Is MeatPack active?
+ if (!full_char_count) { // No literal characters to fetch?
+ uint8_t buf[2] = { 0, 0 };
+ register const uint8_t res = unpack_chars(c, buf); // Decode the byte into one or two characters.
+ if (res & kFirstCharIsLiteral) { // The 1st character couldn't be packed.
+ ++full_char_count; // So the next stream byte is a full character.
+ if (res & kSecondCharIsLiteral) ++full_char_count; // The 2nd character couldn't be packed. Another stream byte is a full character.
+ else second_char = buf[1]; // Retain the unpacked second character.
+ }
+ else {
+ handle_output_char(buf[0]); // Send the unpacked first character out.
+ if (buf[0] != '\n') { // After a newline the next char won't be set
+ if (res & kSecondCharIsLiteral) ++full_char_count; // The 2nd character couldn't be packed. The next stream byte is a full character.
+ else handle_output_char(buf[1]); // Send the unpacked second character out.
+ }
+ }
+ }
+ else {
+ handle_output_char(c); // Pass through the character that couldn't be packed...
+ if (second_char) {
+ handle_output_char(second_char); // ...and send an unpacked 2nd character, if set.
+ second_char = 0;
+ }
+ --full_char_count; // One literal character was consumed
+ }
+ }
+ else // Packing not enabled, just copy character to output
+ handle_output_char(c);
+}
+
+/**
+ * Buffer a single output character which will be picked up in
+ * GCodeQueue::get_serial_commands via calls to get_result_char
+ */
+void MeatPack::handle_output_char(const uint8_t c) {
+ char_out_buf[char_out_count++] = c;
+
+ #if ENABLED(MP_DEBUG)
+ if (chars_decoded < 1024) {
+ ++chars_decoded;
+ DEBUG_ECHOPGM("RB: ");
+ MYSERIAL.print((char)c);
+ DEBUG_EOL();
+ }
+ #endif
+}
+
+/**
+ * Process a MeatPack command byte to update the state.
+ * Report the new state to serial.
+ */
+void MeatPack::handle_command(const MeatPack_Command c) {
+ switch (c) {
+ case MPCommand_QueryConfig: break;
+ case MPCommand_EnablePacking: SBI(state, MPConfig_Bit_Active); DEBUG_ECHOLNPGM("[MPDBG] ENA REC"); break;
+ case MPCommand_DisablePacking: CBI(state, MPConfig_Bit_Active); DEBUG_ECHOLNPGM("[MPDBG] DIS REC"); break;
+ case MPCommand_ResetAll: reset_state(); DEBUG_ECHOLNPGM("[MPDBG] RESET REC"); break;
+ case MPCommand_EnableNoSpaces:
+ SBI(state, MPConfig_Bit_NoSpaces);
+ meatPackLookupTable[kSpaceCharIdx] = kSpaceCharReplace; DEBUG_ECHOLNPGM("[MPDBG] ENA NSP"); break;
+ case MPCommand_DisableNoSpaces:
+ CBI(state, MPConfig_Bit_NoSpaces);
+ meatPackLookupTable[kSpaceCharIdx] = ' '; DEBUG_ECHOLNPGM("[MPDBG] DIS NSP"); break;
+ default: DEBUG_ECHOLNPGM("[MPDBG] UNK CMD REC");
+ }
+ report_state();
+}
+
+void MeatPack::report_state() {
+ // NOTE: if any configuration vars are added below, the outgoing sync text for host plugin
+ // should not contain the "PV' substring, as this is used to indicate protocol version
+ SERIAL_ECHOPGM("[MP] ");
+ SERIAL_ECHOPGM(MeatPack_ProtocolVersion " ");
+ serialprint_onoff(TEST(state, MPConfig_Bit_Active));
+ serialprintPGM(TEST(state, MPConfig_Bit_NoSpaces) ? PSTR(" NSP\n") : PSTR(" ESP\n"));
+}
+
+/**
+ * Interpret a single character received from serial
+ * according to the current meatpack state.
+ */
+void MeatPack::handle_rx_char(const uint8_t c, const serial_index_t serial_ind) {
+ if (c == kCommandByte) { // A command (0xFF) byte?
+ if (cmd_count) { // In fact, two in a row?
+ cmd_is_next = true; // Then a MeatPack command follows
+ cmd_count = 0;
+ }
+ else
+ ++cmd_count; // cmd_count = 1 // One command byte received so far...
+ return;
+ }
+
+ if (cmd_is_next) { // Were two command bytes received?
+ PORT_REDIRECT(serial_ind);
+ handle_command((MeatPack_Command)c); // Then the byte is a MeatPack command
+ cmd_is_next = false;
+ return;
+ }
+
+ if (cmd_count) { // Only a single 0xFF was received
+ handle_rx_char_inner(kCommandByte); // A single 0xFF is passed on literally so it can be interpreted as kFirstNotPacked|kSecondNotPacked
+ cmd_count = 0;
+ }
+
+ handle_rx_char_inner(c); // Other characters are passed on for MeatPack decoding
+}
+
+uint8_t MeatPack::get_result_char(char* const __restrict out) {
+ uint8_t res = 0;
+ if (char_out_count) {
+ res = char_out_count;
+ char_out_count = 0;
+ for (register uint8_t i = 0; i < res; ++i)
+ out[i] = (char)char_out_buf[i];
+ }
+ return res;
+}
+
+#endif // MEATPACK
diff --git a/Marlin/src/feature/meatpack.h b/Marlin/src/feature/meatpack.h
new file mode 100644
index 0000000000..2641130bd8
--- /dev/null
+++ b/Marlin/src/feature/meatpack.h
@@ -0,0 +1,123 @@
+/**
+ * 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 .
+ *
+ */
+
+/*
+ * MeatPack G-code Compression
+ *
+ * Algorithm & Implementation: Scott Mudge - mail@scottmudge.com
+ * Date: Dec. 2020
+ *
+ * Specifically optimized for 3D printing G-Code, this is a zero-cost data compression method
+ * which packs ~180-190% more data into the same amount of bytes going to the CNC controller.
+ * As a majority of G-Code can be represented by a restricted alphabet, I performed histogram
+ * analysis on a wide variety of 3D printing gcode samples, and found ~93% of all gcode could
+ * be represented by the same 15-character alphabet.
+ *
+ * This allowed me to design a system of packing 2 8-bit characters into a single byte, assuming
+ * they fall within this limited 15-character alphabet. Using a 4-bit lookup table, these 8-bit
+ * characters can be represented by a 4-bit index.
+ *
+ * Combined with some logic to allow commingling of full-width characters outside of this 15-
+ * character alphabet (at the cost of an extra 8-bits per full-width character), and by stripping
+ * out unnecessary comments, the end result is gcode which is roughly half the original size.
+ *
+ * Why did I do this? I noticed micro-stuttering and other data-bottleneck issues while printing
+ * objects with high curvature, especially at high speeds. There is also the issue of the limited
+ * baud rate provided by Prusa's Atmega2560-based boards, over the USB serial connection. So soft-
+ * ware like OctoPrint would also suffer this same micro-stuttering and poor print quality issue.
+ *
+ */
+#pragma once
+
+#include
+
+/**
+ * Commands sent to MeatPack to control its behavior.
+ * They are sent by first sending 2x MeatPack_CommandByte (0xFF) in sequence,
+ * followed by one of the command bytes below.
+ * Provided that 0xFF is an exceedingly rare character that is virtually never
+ * present in G-code naturally, it is safe to assume 2 in sequence should never
+ * happen naturally, and so it is used as a signal here.
+ *
+ * 0xFF *IS* used in "packed" G-code (used to denote that the next 2 characters are
+ * full-width), however 2 in a row will never occur, as the next 2 bytes will always
+ * some non-0xFF character.
+ */
+enum MeatPack_Command : uint8_t {
+ MPCommand_None = 0,
+ MPCommand_EnablePacking = 0xFB,
+ MPCommand_DisablePacking = 0xFA,
+ MPCommand_ResetAll = 0xF9,
+ MPCommand_QueryConfig = 0xF8,
+ MPCommand_EnableNoSpaces = 0xF7,
+ MPCommand_DisableNoSpaces = 0xF6
+};
+
+enum MeatPack_ConfigStateBits : uint8_t {
+ MPConfig_Bit_Active = 0,
+ MPConfig_Bit_NoSpaces = 1
+};
+
+class MeatPack {
+private:
+ friend class GCodeQueue;
+
+ // Utility definitions
+ static const uint8_t kCommandByte = 0b11111111,
+ kFirstNotPacked = 0b00001111,
+ kSecondNotPacked = 0b11110000,
+ kFirstCharIsLiteral = 0b00000001,
+ kSecondCharIsLiteral = 0b00000010;
+
+ static const uint8_t kSpaceCharIdx = 11;
+ static const char kSpaceCharReplace = 'E';
+
+ static bool cmd_is_next; // A command is pending
+ static uint8_t state; // Configuration state
+ static uint8_t second_char; // Buffers a character if dealing with out-of-sequence pairs
+ static uint8_t cmd_count, // Counter of command bytes received (need 2)
+ full_char_count, // Counter for full-width characters to be received
+ char_out_count; // Stores number of characters to be read out.
+ static uint8_t char_out_buf[2]; // Output buffer for caching up to 2 characters
+
+ // Pass in a character rx'd by SD card or serial. Automatically parses command/ctrl sequences,
+ // and will control state internally.
+ static void handle_rx_char(const uint8_t c, const serial_index_t serial_ind);
+
+ /**
+ * After passing in rx'd char using above method, call this to get characters out.
+ * Can return from 0 to 2 characters at once.
+ * @param out [in] Output pointer for unpacked/processed data.
+ * @return Number of characters returned. Range from 0 to 2.
+ */
+ static uint8_t get_result_char(char* const __restrict out);
+
+ static void reset_state();
+ static void report_state();
+ static uint8_t unpacked_char(register const uint8_t in);
+ static uint8_t unpack_chars(const uint8_t pk, uint8_t* __restrict const chars_out);
+ static void handle_command(const MeatPack_Command c);
+ static void handle_output_char(const uint8_t c);
+ static void handle_rx_char_inner(const uint8_t c);
+};
+
+extern MeatPack meatpack;
diff --git a/Marlin/src/feature/mmu/mmu2.cpp b/Marlin/src/feature/mmu/mmu2.cpp
index a4b7f257a9..e3036947d5 100644
--- a/Marlin/src/feature/mmu/mmu2.cpp
+++ b/Marlin/src/feature/mmu/mmu2.cpp
@@ -167,6 +167,8 @@ void MMU2::mmu_loop() {
case -1:
if (rx_start()) {
+ prev_P0_request = millis(); // Initialize finda sensor timeout
+
DEBUG_ECHOLNPGM("MMU => 'start'");
DEBUG_ECHOLNPGM("MMU <= 'S1'");
@@ -311,7 +313,7 @@ void MMU2::mmu_loop() {
// if (finda_runout_valid) DEBUG_ECHOLNPAIR_F("MMU <= 'P0'\nMMU => ", finda, 6);
if (!finda && finda_runout_valid) filament_runout();
- if (cmd == 0) ready = true;
+ if (cmd == MMU_CMD_NONE) ready = true;
state = 1;
}
else if (ELAPSED(millis(), prev_request + MMU_P0_TIMEOUT)) // Resend request after timeout (3s)
@@ -333,18 +335,20 @@ void MMU2::mmu_loop() {
#endif
if (rx_ok()) {
- // Response to C0 mmu command in MMU2S model
- bool can_reset = true;
#if HAS_PRUSA_MMU2S
- if (!mmu2s_triggered && last_cmd == MMU_CMD_C0) {
- can_reset = false;
+ // Respond to C0 MMU command in MMU2S model
+ const bool keep_trying = !mmu2s_triggered && last_cmd == MMU_CMD_C0;
+ if (keep_trying) {
// MMU ok received but filament sensor not triggered, retrying...
DEBUG_ECHOLNPGM("MMU => 'ok' (filament not present in gears)");
DEBUG_ECHOLNPGM("MMU <= 'C0' (keep trying)");
MMU2_COMMAND("C0");
}
+ #else
+ constexpr bool keep_trying = false;
#endif
- if (can_reset) {
+
+ if (!keep_trying) {
DEBUG_ECHOLNPGM("MMU => 'ok'");
ready = true;
state = 1;
@@ -370,11 +374,7 @@ void MMU2::mmu_loop() {
*/
bool MMU2::rx_start() {
// check for start message
- if (rx_str_P(PSTR("start\n"))) {
- prev_P0_request = millis();
- return true;
- }
- return false;
+ return rx_str_P(PSTR("start\n"));
}
/**
@@ -385,13 +385,13 @@ bool MMU2::rx_str_P(const char* str) {
while (MMU2_SERIAL.available()) {
rx_buffer[i++] = MMU2_SERIAL.read();
- rx_buffer[i] = '\0';
if (i == sizeof(rx_buffer) - 1) {
DEBUG_ECHOLNPGM("rx buffer overrun");
break;
}
}
+ rx_buffer[i] = '\0';
uint8_t len = strlen_P(str);
@@ -416,7 +416,6 @@ void MMU2::tx_str_P(const char* str) {
clear_rx_buffer();
uint8_t len = strlen_P(str);
LOOP_L_N(i, len) MMU2_SERIAL.write(pgm_read_byte(str++));
- rx_buffer[0] = '\0';
prev_request = millis();
}
@@ -427,7 +426,6 @@ void MMU2::tx_printf_P(const char* format, int argument = -1) {
clear_rx_buffer();
uint8_t len = sprintf_P(tx_buffer, format, argument);
LOOP_L_N(i, len) MMU2_SERIAL.write(tx_buffer[i]);
- rx_buffer[0] = '\0';
prev_request = millis();
}
@@ -438,7 +436,6 @@ void MMU2::tx_printf_P(const char* format, int argument1, int argument2) {
clear_rx_buffer();
uint8_t len = sprintf_P(tx_buffer, format, argument1, argument2);
LOOP_L_N(i, len) MMU2_SERIAL.write(tx_buffer[i]);
- rx_buffer[0] = '\0';
prev_request = millis();
}
@@ -570,7 +567,7 @@ static void mmu2_not_responding() {
case 'c': {
while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100);
- execute_extruder_sequence((const E_Step *)load_to_nozzle_sequence, COUNT(load_to_nozzle_sequence));
+ load_to_nozzle();
} break;
}
@@ -791,7 +788,7 @@ bool MMU2::get_response() {
}
/**
- * Wait for response and deal with timeout if nexcessary
+ * Wait for response and deal with timeout if necessary
*/
void MMU2::manage_response(const bool move_axes, const bool turn_off_nozzle) {
@@ -917,6 +914,7 @@ void MMU2::filament_runout() {
// Load filament into MMU2
void MMU2::load_filament(const uint8_t index) {
if (!enabled) return;
+
command(MMU_CMD_L0 + index);
manage_response(false, false);
BUZZ(200, 404);
@@ -935,6 +933,7 @@ bool MMU2::load_filament_to_nozzle(const uint8_t index) {
return false;
}
+ DISABLE_AXIS_E0();
command(MMU_CMD_T0 + index);
manage_response(true, true);
@@ -957,7 +956,6 @@ bool MMU2::load_filament_to_nozzle(const uint8_t index) {
* filament to nozzle.
*/
void MMU2::load_to_nozzle() {
- if (!enabled) return;
execute_extruder_sequence((const E_Step *)load_to_nozzle_sequence, COUNT(load_to_nozzle_sequence));
}
@@ -1020,7 +1018,8 @@ bool MMU2::unload() {
return false;
}
- filament_ramming();
+ // Unload sequence to optimize shape of the tip of the unloaded filament
+ execute_extruder_sequence((const E_Step *)ramming_sequence, sizeof(ramming_sequence) / sizeof(E_Step));
command(MMU_CMD_U0);
manage_response(false, true);
@@ -1035,13 +1034,6 @@ bool MMU2::unload() {
return true;
}
-/**
- * Unload sequence to optimize shape of the tip of the unloaded filament
- */
-void MMU2::filament_ramming() {
- execute_extruder_sequence((const E_Step *)ramming_sequence, sizeof(ramming_sequence) / sizeof(E_Step));
-}
-
void MMU2::execute_extruder_sequence(const E_Step * sequence, int steps) {
planner.synchronize();
diff --git a/Marlin/src/feature/mmu/mmu2.h b/Marlin/src/feature/mmu/mmu2.h
index 09ff3b6683..4326989a74 100644
--- a/Marlin/src/feature/mmu/mmu2.h
+++ b/Marlin/src/feature/mmu/mmu2.h
@@ -71,7 +71,6 @@ private:
static void manage_response(const bool move_axes, const bool turn_off_nozzle);
static void load_to_nozzle();
- static void filament_ramming();
static void execute_extruder_sequence(const E_Step * sequence, int steps);
static void filament_runout();
diff --git a/Marlin/src/feature/pause.cpp b/Marlin/src/feature/pause.cpp
index c8265a154f..5ab4f2b146 100644
--- a/Marlin/src/feature/pause.cpp
+++ b/Marlin/src/feature/pause.cpp
@@ -137,10 +137,7 @@ static bool ensure_safe_temperature(const bool wait=true, const PauseMode mode=P
thermalManager.setTargetHotend(thermalManager.extrude_min_temp, active_extruder);
#endif
- #if HAS_LCD_MENU
- lcd_pause_show_message(PAUSE_MESSAGE_HEATING, mode);
- #endif
- UNUSED(mode);
+ ui.pause_show_message(PAUSE_MESSAGE_HEATING, mode); UNUSED(mode);
if (wait) return thermalManager.wait_for_hotend(active_extruder);
@@ -181,19 +178,13 @@ bool load_filament(const float &slow_load_length/*=0*/, const float &fast_load_l
DEBUG_SECTION(lf, "load_filament", true);
DEBUG_ECHOLNPAIR("... slowlen:", slow_load_length, " fastlen:", fast_load_length, " purgelen:", purge_length, " maxbeep:", int(max_beep_count), " showlcd:", int(show_lcd), " pauseforuser:", int(pause_for_user), " pausemode:", int(mode) DXC_SAY);
- UNUSED(show_lcd);
-
if (!ensure_safe_temperature(false, mode)) {
- #if HAS_LCD_MENU
- if (show_lcd) lcd_pause_show_message(PAUSE_MESSAGE_STATUS, mode);
- #endif
+ if (show_lcd) ui.pause_show_message(PAUSE_MESSAGE_STATUS, mode);
return false;
}
if (pause_for_user) {
- #if HAS_LCD_MENU
- if (show_lcd) lcd_pause_show_message(PAUSE_MESSAGE_INSERT, mode);
- #endif
+ if (show_lcd) ui.pause_show_message(PAUSE_MESSAGE_INSERT, mode);
SERIAL_ECHO_MSG(_PMSG(STR_FILAMENT_CHANGE_INSERT));
first_impatient_beep(max_beep_count);
@@ -217,9 +208,7 @@ bool load_filament(const float &slow_load_length/*=0*/, const float &fast_load_l
}
}
- #if HAS_LCD_MENU
- if (show_lcd) lcd_pause_show_message(PAUSE_MESSAGE_LOAD, mode);
- #endif
+ if (show_lcd) ui.pause_show_message(PAUSE_MESSAGE_LOAD, mode);
#if ENABLED(DUAL_X_CARRIAGE)
const int8_t saved_ext = active_extruder;
@@ -250,9 +239,7 @@ bool load_filament(const float &slow_load_length/*=0*/, const float &fast_load_l
#if ENABLED(ADVANCED_PAUSE_CONTINUOUS_PURGE)
- #if HAS_LCD_MENU
- if (show_lcd) lcd_pause_show_message(PAUSE_MESSAGE_PURGE);
- #endif
+ if (show_lcd) ui.pause_show_message(PAUSE_MESSAGE_PURGE);
TERN_(HOST_PROMPT_SUPPORT, host_prompt_do(PROMPT_USER_CONTINUE, PSTR("Filament Purging..."), CONTINUE_STR));
TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired_P(PSTR("Filament Purging...")));
@@ -266,9 +253,7 @@ bool load_filament(const float &slow_load_length/*=0*/, const float &fast_load_l
do {
if (purge_length > 0) {
// "Wait for filament purge"
- #if HAS_LCD_MENU
- if (show_lcd) lcd_pause_show_message(PAUSE_MESSAGE_PURGE);
- #endif
+ if (show_lcd) ui.pause_show_message(PAUSE_MESSAGE_PURGE);
// Extrude filament to get into hotend
unscaled_e_move(purge_length, ADVANCED_PAUSE_PURGE_FEEDRATE);
@@ -281,7 +266,7 @@ bool load_filament(const float &slow_load_length/*=0*/, const float &fast_load_l
// Show "Purge More" / "Resume" menu and wait for reply
KEEPALIVE_STATE(PAUSED_FOR_USER);
wait_for_user = false;
- lcd_pause_show_message(PAUSE_MESSAGE_OPTION);
+ ui.pause_show_message(PAUSE_MESSAGE_OPTION);
while (pause_menu_response == PAUSE_RESPONSE_WAIT_FOR) idle_no_sleep();
}
#endif
@@ -330,22 +315,16 @@ bool unload_filament(const float &unload_length, const bool show_lcd/*=false*/,
#endif
);
- UNUSED(show_lcd);
-
#if !BOTH(FILAMENT_UNLOAD_ALL_EXTRUDERS, MIXING_EXTRUDER)
constexpr float mix_multiplier = 1.0;
#endif
if (!ensure_safe_temperature(false, mode)) {
- #if HAS_LCD_MENU
- if (show_lcd) lcd_pause_show_message(PAUSE_MESSAGE_STATUS);
- #endif
+ if (show_lcd) ui.pause_show_message(PAUSE_MESSAGE_STATUS);
return false;
}
- #if HAS_LCD_MENU
- if (show_lcd) lcd_pause_show_message(PAUSE_MESSAGE_UNLOAD, mode);
- #endif
+ if (show_lcd) ui.pause_show_message(PAUSE_MESSAGE_UNLOAD, mode);
// Retract filament
unscaled_e_move(-(FILAMENT_UNLOAD_PURGE_RETRACT) * mix_multiplier, (PAUSE_PARK_RETRACT_FEEDRATE) * mix_multiplier);
@@ -479,7 +458,7 @@ void show_continue_prompt(const bool is_reload) {
DEBUG_SECTION(scp, "pause_print", true);
DEBUG_ECHOLNPAIR("... is_reload:", int(is_reload));
- TERN_(HAS_LCD_MENU, lcd_pause_show_message(is_reload ? PAUSE_MESSAGE_INSERT : PAUSE_MESSAGE_WAITING));
+ ui.pause_show_message(is_reload ? PAUSE_MESSAGE_INSERT : PAUSE_MESSAGE_WAITING);
SERIAL_ECHO_START();
serialprintPGM(is_reload ? PSTR(_PMSG(STR_FILAMENT_CHANGE_INSERT) "\n") : PSTR(_PMSG(STR_FILAMENT_CHANGE_WAIT) "\n"));
}
@@ -520,7 +499,7 @@ void wait_for_confirmation(const bool is_reload/*=false*/, const int8_t max_beep
// Wait for the user to press the button to re-heat the nozzle, then
// re-heat the nozzle, re-show the continue prompt, restart idle timers, start over
if (nozzle_timed_out) {
- TERN_(HAS_LCD_MENU, lcd_pause_show_message(PAUSE_MESSAGE_HEAT));
+ ui.pause_show_message(PAUSE_MESSAGE_HEAT);
SERIAL_ECHO_MSG(_PMSG(STR_FILAMENT_CHANGE_HEAT));
TERN_(HOST_PROMPT_SUPPORT, host_prompt_do(PROMPT_USER_CONTINUE, GET_TEXT(MSG_HEATER_TIMEOUT), GET_TEXT(MSG_REHEAT)));
@@ -614,7 +593,7 @@ void resume_print(const float &slow_load_length/*=0*/, const float &fast_load_le
thermalManager.wait_for_hotend(active_extruder, false);
}
- TERN_(HAS_LCD_MENU, lcd_pause_show_message(PAUSE_MESSAGE_RESUME));
+ ui.pause_show_message(PAUSE_MESSAGE_RESUME);
// Check Temperature before moving hotend
ensure_safe_temperature();
@@ -653,7 +632,7 @@ void resume_print(const float &slow_load_length/*=0*/, const float &fast_load_le
// Write PLR now to update the z axis value
TERN_(POWER_LOSS_RECOVERY, if (recovery.enabled) recovery.save(true));
- TERN_(HAS_LCD_MENU, lcd_pause_show_message(PAUSE_MESSAGE_STATUS));
+ ui.pause_show_message(PAUSE_MESSAGE_STATUS);
#ifdef ACTION_ON_RESUMED
host_action_resumed();
diff --git a/Marlin/src/feature/pause.h b/Marlin/src/feature/pause.h
index c69ed73546..7e58d4564e 100644
--- a/Marlin/src/feature/pause.h
+++ b/Marlin/src/feature/pause.h
@@ -101,4 +101,8 @@ bool unload_filament(const float &unload_length, const bool show_lcd=false, cons
#endif
);
-#endif // ADVANCED_PAUSE_FEATURE
+#else // !ADVANCED_PAUSE_FEATURE
+
+ constexpr uint8_t did_pause_print = 0;
+
+#endif // !ADVANCED_PAUSE_FEATURE
diff --git a/Marlin/src/feature/powerloss.cpp b/Marlin/src/feature/powerloss.cpp
index 0e669a74d4..be35ff8511 100644
--- a/Marlin/src/feature/powerloss.cpp
+++ b/Marlin/src/feature/powerloss.cpp
@@ -520,7 +520,6 @@ void PrintJobRecovery::resume() {
// Resume the SD file from the last position
char *fn = info.sd_filename;
- extern const char M23_STR[];
sprintf_P(cmd, M23_STR, fn);
gcode.process_subcommands_now(cmd);
sprintf_P(cmd, PSTR("M24 S%ld T%ld"), resume_sdpos, info.print_job_elapsed);
diff --git a/Marlin/src/feature/runout.cpp b/Marlin/src/feature/runout.cpp
index 50e18e52ef..be769d2dc8 100644
--- a/Marlin/src/feature/runout.cpp
+++ b/Marlin/src/feature/runout.cpp
@@ -59,6 +59,7 @@ bool FilamentMonitorBase::enabled = true,
// Filament Runout event handler
//
#include "../MarlinCore.h"
+#include "../feature/pause.h"
#include "../gcode/queue.h"
#if ENABLED(HOST_ACTION_COMMANDS)
@@ -71,7 +72,7 @@ bool FilamentMonitorBase::enabled = true,
void event_filament_runout() {
- if (TERN0(ADVANCED_PAUSE_FEATURE, did_pause_print)) return; // Action already in progress. Purge triggered repeated runout.
+ if (did_pause_print) return; // Action already in progress. Purge triggered repeated runout.
#if ENABLED(TOOLCHANGE_MIGRATION_FEATURE)
if (migration.in_progress) {
diff --git a/Marlin/src/feature/runout.h b/Marlin/src/feature/runout.h
index 09443e6e2b..60154c5e43 100644
--- a/Marlin/src/feature/runout.h
+++ b/Marlin/src/feature/runout.h
@@ -30,6 +30,7 @@
#include "../module/planner.h"
#include "../module/stepper.h" // for block_t
#include "../gcode/queue.h"
+#include "../feature/pause.h"
#include "../inc/MarlinConfig.h"
@@ -37,10 +38,6 @@
#include "../lcd/extui/ui_api.h"
#endif
-#if ENABLED(ADVANCED_PAUSE_FEATURE)
- #include "pause.h"
-#endif
-
//#define FILAMENT_RUNOUT_SENSOR_DEBUG
#ifndef FILAMENT_RUNOUT_THRESHOLD
#define FILAMENT_RUNOUT_THRESHOLD 5
@@ -118,9 +115,7 @@ class TFilamentMonitor : public FilamentMonitorBase {
// Give the response a chance to update its counter.
static inline void run() {
- if ( enabled && !filament_ran_out
- && (printingIsActive() || TERN0(ADVANCED_PAUSE_FEATURE, did_pause_print))
- ) {
+ if (enabled && !filament_ran_out && (printingIsActive() || did_pause_print)) {
TERN_(HAS_FILAMENT_RUNOUT_DISTANCE, cli()); // Prevent RunoutResponseDelayed::block_completed from accumulating here
response.run();
sensor.run();
@@ -343,9 +338,7 @@ class FilamentSensorBase {
}
static inline void block_completed(const block_t* const b) {
- if (b->steps.x || b->steps.y || b->steps.z
- || TERN0(ADVANCED_PAUSE_FEATURE, did_pause_print) // Allow pause purge move to re-trigger runout state
- ) {
+ if (b->steps.x || b->steps.y || b->steps.z || did_pause_print) { // Allow pause purge move to re-trigger runout state
// Only trigger on extrusion with XYZ movement to allow filament change and retract/recover.
const uint8_t e = b->extruder;
const int32_t steps = b->steps.e;
diff --git a/Marlin/src/feature/spindle_laser.h b/Marlin/src/feature/spindle_laser.h
index 57fc136c8c..d50bc7eb42 100644
--- a/Marlin/src/feature/spindle_laser.h
+++ b/Marlin/src/feature/spindle_laser.h
@@ -157,7 +157,7 @@ public:
#elif CUTTER_UNIT_IS(RPM)
2
#else
- #error "CUTTER_UNIT_IS(???)"
+ #error "CUTTER_UNIT_IS(unknown)"
#endif
));
}
diff --git a/Marlin/src/feature/tmc_util.cpp b/Marlin/src/feature/tmc_util.cpp
index 29bb249cea..8d0156883b 100644
--- a/Marlin/src/feature/tmc_util.cpp
+++ b/Marlin/src/feature/tmc_util.cpp
@@ -604,8 +604,6 @@
case TMC_PWM_OFS_AUTO: SERIAL_PRINT(st.pwm_ofs_auto(), DEC); break;
case TMC_PWM_GRAD_AUTO: SERIAL_PRINT(st.pwm_grad_auto(), DEC); break;
case TMC_STEALTHCHOP: serialprint_truefalse(st.stealth()); break;
- case TMC_S2VSA: if (st.s2vsa()) SERIAL_CHAR('*'); break;
- case TMC_S2VSB: if (st.s2vsb()) SERIAL_CHAR('*'); break;
case TMC_INTERPOLATE: serialprint_truefalse(st.intpol()); break;
default: break;
}
@@ -631,6 +629,8 @@
case TMC_T150: if (st.t150()) SERIAL_CHAR('*'); break;
case TMC_T143: if (st.t143()) SERIAL_CHAR('*'); break;
case TMC_T120: if (st.t120()) SERIAL_CHAR('*'); break;
+ case TMC_S2VSA: if (st.s2vsa()) SERIAL_CHAR('*'); break;
+ case TMC_S2VSB: if (st.s2vsb()) SERIAL_CHAR('*'); break;
case TMC_DRV_CS_ACTUAL: SERIAL_PRINT(st.cs_actual(), DEC); break;
default: break;
}
diff --git a/Marlin/src/feature/twibus.cpp b/Marlin/src/feature/twibus.cpp
index 3cc20579ac..855a3188d1 100644
--- a/Marlin/src/feature/twibus.cpp
+++ b/Marlin/src/feature/twibus.cpp
@@ -28,6 +28,8 @@
#include
+TWIBus i2c;
+
TWIBus::TWIBus() {
#if I2C_SLAVE_ADDRESS == 0
Wire.begin(); // No address joins the BUS as the master
@@ -155,6 +157,14 @@ void TWIBus::flush() {
reset();
}
+ 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
#if ENABLED(DEBUG_TWIBUS)
diff --git a/Marlin/src/feature/twibus.h b/Marlin/src/feature/twibus.h
index 82aa9aa16a..5939153482 100644
--- a/Marlin/src/feature/twibus.h
+++ b/Marlin/src/feature/twibus.h
@@ -31,6 +31,17 @@
typedef void (*twiReceiveFunc_t)(int bytes);
typedef void (*twiRequestFunc_t)();
+/**
+ * For a light i2c protocol that runs on two boards running Marlin see:
+ * See https://github.com/MarlinFirmware/Marlin/issues/4776#issuecomment-246262879
+ */
+#if I2C_SLAVE_ADDRESS > 0
+
+ void i2c_on_receive(int bytes); // Demo i2c onReceive handler
+ void i2c_on_request(); // Demo i2c onRequest handler
+
+#endif
+
#define TWIBUS_BUFFER_SIZE 32
/**
@@ -238,3 +249,5 @@ class TWIBus {
static inline void debug(const char[], uint8_t) {}
#endif
};
+
+extern TWIBus i2c;
diff --git a/Marlin/src/gcode/bedlevel/G26.cpp b/Marlin/src/gcode/bedlevel/G26.cpp
index 650b039b55..5a79aaac7b 100644
--- a/Marlin/src/gcode/bedlevel/G26.cpp
+++ b/Marlin/src/gcode/bedlevel/G26.cpp
@@ -128,6 +128,10 @@
#define G26_XY_FEEDRATE (PLANNER_XY_FEEDRATE() / 3.0)
#endif
+#ifndef G26_XY_FEEDRATE_TRAVEL
+ #define G26_XY_FEEDRATE_TRAVEL (PLANNER_XY_FEEDRATE() / 1.5)
+#endif
+
#if CROSSHAIRS_SIZE >= INTERSECTION_CIRCLE_RADIUS
#error "CROSSHAIRS_SIZE must be less than INTERSECTION_CIRCLE_RADIUS."
#endif
@@ -214,22 +218,25 @@ void move_to(const float &rx, const float &ry, const float &z, const float &e_de
const xy_pos_t dest = { rx, ry };
const bool has_xy_component = dest != current_position; // Check if X or Y is involved in the movement.
+ const bool has_e_component = e_delta != 0.0;
destination = current_position;
if (z != last_z) {
last_z = destination.z = z;
- const feedRate_t feed_value = planner.settings.max_feedrate_mm_s[Z_AXIS] * 0.5f; // Use half of the Z_AXIS max feed rate
- prepare_internal_move_to_destination(feed_value);
- destination = current_position;
+ const feedRate_t fr_mm_s = planner.settings.max_feedrate_mm_s[Z_AXIS] * 0.5f; // Use half of the Z_AXIS max feed rate
+ prepare_internal_move_to_destination(fr_mm_s);
}
- // If X or Y is involved do a 'normal' move. Otherwise retract/recover/hop.
+ // If X or Y in combination with E is involved do a 'normal' move.
+ // If X or Y with no E is involved do a 'fast' move
+ // Otherwise retract/recover/hop.
destination = dest;
destination.e += e_delta;
- const feedRate_t feed_value = has_xy_component ? feedRate_t(G26_XY_FEEDRATE) : planner.settings.max_feedrate_mm_s[E_AXIS] * 0.666f;
- prepare_internal_move_to_destination(feed_value);
- destination = current_position;
+ const feedRate_t fr_mm_s = has_xy_component
+ ? (has_e_component ? feedRate_t(G26_XY_FEEDRATE) : feedRate_t(G26_XY_FEEDRATE_TRAVEL))
+ : planner.settings.max_feedrate_mm_s[E_AXIS] * 0.666f;
+ prepare_internal_move_to_destination(fr_mm_s);
}
FORCE_INLINE void move_to(const xyz_pos_t &where, const float &de) { move_to(where.x, where.y, where.z, de); }
diff --git a/Marlin/src/gcode/bedlevel/abl/G29.cpp b/Marlin/src/gcode/bedlevel/abl/G29.cpp
index 3c3bb18deb..b8194e0c21 100644
--- a/Marlin/src/gcode/bedlevel/abl/G29.cpp
+++ b/Marlin/src/gcode/bedlevel/abl/G29.cpp
@@ -194,7 +194,7 @@ G29_TYPE GcodeSuite::G29() {
// Send 'N' to force homing before G29 (internal only)
if (parser.seen('N'))
- gcode.process_subcommands_now_P(TERN(G28_L0_ENSURES_LEVELING_OFF, PSTR("G28L0"), G28_STR));
+ process_subcommands_now_P(TERN(G28_L0_ENSURES_LEVELING_OFF, PSTR("G28L0"), G28_STR));
// Don't allow auto-leveling without homing first
if (homing_needed_error()) G29_RETURN(false);
diff --git a/Marlin/src/gcode/calibrate/G76_M192_M871.cpp b/Marlin/src/gcode/calibrate/G76_M192_M871.cpp
index 7438b0e83d..5d0bb0dc1e 100644
--- a/Marlin/src/gcode/calibrate/G76_M192_M871.cpp
+++ b/Marlin/src/gcode/calibrate/G76_M192_M871.cpp
@@ -38,7 +38,7 @@
#include "../../feature/probe_temp_comp.h"
#include "../../lcd/marlinui.h"
-#include "../../MarlinCore.h" // for wait_for_heatup, idle(), G28_STR
+#include "../../MarlinCore.h" // for wait_for_heatup, idle()
#if ENABLED(PRINTJOB_TIMER_AUTOSTART)
#include "../../module/printcounter.h"
@@ -267,7 +267,7 @@ void GcodeSuite::G76() {
say_waiting_for_probe_heating();
SERIAL_ECHOLNPAIR(" Bed:", target_bed, " Probe:", target_probe);
- const millis_t probe_timeout_ms = millis() + 900UL * 1000UL;
+ const millis_t probe_timeout_ms = millis() + SEC_TO_MS(900UL);
while (thermalManager.degProbe() < target_probe) {
if (report_temps(next_temp_report, probe_timeout_ms)) {
SERIAL_ECHOLNPGM("!Probe heating timed out.");
diff --git a/Marlin/src/gcode/calibrate/M48.cpp b/Marlin/src/gcode/calibrate/M48.cpp
index 46367df10d..529d5c75d9 100644
--- a/Marlin/src/gcode/calibrate/M48.cpp
+++ b/Marlin/src/gcode/calibrate/M48.cpp
@@ -51,8 +51,6 @@
* This function requires the machine to be homed before invocation.
*/
-extern const char SP_Y_STR[];
-
void GcodeSuite::M48() {
if (homing_needed_error()) return;
diff --git a/Marlin/src/gcode/config/M217.cpp b/Marlin/src/gcode/config/M217.cpp
index b57dec31f3..f2fefb5756 100644
--- a/Marlin/src/gcode/config/M217.cpp
+++ b/Marlin/src/gcode/config/M217.cpp
@@ -33,8 +33,6 @@
#include "../../MarlinCore.h" // for SP_X_STR, etc.
-extern const char SP_X_STR[], SP_Y_STR[], SP_Z_STR[];
-
void M217_report(const bool eeprom=false) {
#if ENABLED(TOOLCHANGE_FILAMENT_SWAP)
diff --git a/Marlin/src/gcode/control/M108_M112_M410.cpp b/Marlin/src/gcode/control/M108_M112_M410.cpp
index df145d5d11..309c806c8f 100644
--- a/Marlin/src/gcode/control/M108_M112_M410.cpp
+++ b/Marlin/src/gcode/control/M108_M112_M410.cpp
@@ -25,7 +25,8 @@
#if DISABLED(EMERGENCY_PARSER)
#include "../gcode.h"
-#include "../../MarlinCore.h" // for wait_for_heatup, kill, quickstop_stepper
+#include "../../MarlinCore.h" // for wait_for_heatup, kill, M112_KILL_STR
+#include "../../module/motion.h" // for quickstop_stepper
/**
* M108: Stop the waiting for heaters in M109, M190, M303. Does not affect the target temperature.
diff --git a/Marlin/src/gcode/control/M226.cpp b/Marlin/src/gcode/control/M226.cpp
index ad717e614d..63f022e82b 100644
--- a/Marlin/src/gcode/control/M226.cpp
+++ b/Marlin/src/gcode/control/M226.cpp
@@ -28,6 +28,8 @@
#include "../../MarlinCore.h" // for pin_is_protected and idle()
#include "../../module/stepper.h"
+void protected_pin_err();
+
/**
* M226: Wait until the specified pin reaches the state required (M226 P S)
*/
diff --git a/Marlin/src/gcode/control/M42.cpp b/Marlin/src/gcode/control/M42.cpp
index c635c06ec6..6ef8455e0b 100644
--- a/Marlin/src/gcode/control/M42.cpp
+++ b/Marlin/src/gcode/control/M42.cpp
@@ -31,6 +31,10 @@
#include "../../module/temperature.h"
#endif
+void protected_pin_err() {
+ SERIAL_ERROR_MSG(STR_ERR_PROTECTED_PIN);
+}
+
/**
* M42: Change pin status via GCode
*
diff --git a/Marlin/src/gcode/control/M80_M81.cpp b/Marlin/src/gcode/control/M80_M81.cpp
index ea0f9c2b13..394b06d8ac 100644
--- a/Marlin/src/gcode/control/M80_M81.cpp
+++ b/Marlin/src/gcode/control/M80_M81.cpp
@@ -89,9 +89,10 @@
*/
void GcodeSuite::M81() {
thermalManager.disable_all_heaters();
- print_job_timer.stop();
planner.finish_and_disable();
+ print_job_timer.stop();
+
#if HAS_FAN
thermalManager.zero_fan_speeds();
#if ENABLED(PROBING_FANS_OFF)
diff --git a/Marlin/src/gcode/feature/L6470/M916-918.cpp b/Marlin/src/gcode/feature/L6470/M916-918.cpp
index 2672f91239..8a1ea48306 100644
--- a/Marlin/src/gcode/feature/L6470/M916-918.cpp
+++ b/Marlin/src/gcode/feature/L6470/M916-918.cpp
@@ -119,7 +119,7 @@ void GcodeSuite::M916() {
M91x_counter_max = 256; // KVAL_HOLD is 8 bits
uint8_t M91x_delay_s = parser.byteval('D'); // get delay in seconds
- millis_t M91x_delay_ms = M91x_delay_s * 60 * 1000;
+ millis_t M91x_delay_ms = SEC_TO_MS(M91x_delay_s * 60);
millis_t M91x_delay_end;
DEBUG_ECHOLNPGM(".\n.");
diff --git a/Marlin/src/gcode/feature/i2c/M260_M261.cpp b/Marlin/src/gcode/feature/i2c/M260_M261.cpp
index 526d9101e1..438d1527f5 100644
--- a/Marlin/src/gcode/feature/i2c/M260_M261.cpp
+++ b/Marlin/src/gcode/feature/i2c/M260_M261.cpp
@@ -26,7 +26,7 @@
#include "../../gcode.h"
-#include "../../../MarlinCore.h" // for i2c
+#include "../../../feature/twibus.h"
/**
* M260: Send data to a I2C slave device
diff --git a/Marlin/src/gcode/feature/network/M552-M554.cpp b/Marlin/src/gcode/feature/network/M552-M554.cpp
index d88c38cb5a..6ea15fefbf 100644
--- a/Marlin/src/gcode/feature/network/M552-M554.cpp
+++ b/Marlin/src/gcode/feature/network/M552-M554.cpp
@@ -47,7 +47,8 @@ void MAC_report() {
Ethernet.MACAddress(mac);
SERIAL_ECHOPGM(" MAC: ");
LOOP_L_N(i, 6) {
- SERIAL_PRINTF("%02X", mac[i]);
+ if (mac[i] < 16) SERIAL_CHAR('0');
+ SERIAL_PRINT(mac[i], HEX);
if (i < 5) SERIAL_CHAR(':');
}
}
diff --git a/Marlin/src/gcode/feature/pause/M125.cpp b/Marlin/src/gcode/feature/pause/M125.cpp
index b1d76e83ae..9391b8661b 100644
--- a/Marlin/src/gcode/feature/pause/M125.cpp
+++ b/Marlin/src/gcode/feature/pause/M125.cpp
@@ -27,13 +27,10 @@
#include "../../gcode.h"
#include "../../parser.h"
#include "../../../feature/pause.h"
+#include "../../../lcd/marlinui.h"
#include "../../../module/motion.h"
-#include "../../../sd/cardreader.h"
#include "../../../module/printcounter.h"
-
-#if HAS_LCD_MENU
- #include "../../../lcd/marlinui.h"
-#endif
+#include "../../../sd/cardreader.h"
#if ENABLED(POWER_LOSS_RECOVERY)
#include "../../../feature/powerloss.h"
@@ -76,7 +73,7 @@ void GcodeSuite::M125() {
const bool sd_printing = TERN0(SDSUPPORT, IS_SD_PRINTING());
- TERN_(HAS_LCD_MENU, lcd_pause_show_message(PAUSE_MESSAGE_PARKING, PAUSE_MODE_PAUSE_PRINT));
+ ui.pause_show_message(PAUSE_MESSAGE_PARKING, PAUSE_MODE_PAUSE_PRINT);
// If possible, show an LCD prompt with the 'P' flag
const bool show_lcd = TERN0(HAS_LCD_MENU, parser.boolval('P'));
diff --git a/Marlin/src/gcode/feature/pause/M600.cpp b/Marlin/src/gcode/feature/pause/M600.cpp
index db8bc93a9f..1c282f2052 100644
--- a/Marlin/src/gcode/feature/pause/M600.cpp
+++ b/Marlin/src/gcode/feature/pause/M600.cpp
@@ -28,15 +28,12 @@
#include "../../../feature/pause.h"
#include "../../../module/motion.h"
#include "../../../module/printcounter.h"
+#include "../../../lcd/marlinui.h"
#if HAS_MULTI_EXTRUDER
#include "../../../module/tool_change.h"
#endif
-#if HAS_LCD_MENU
- #include "../../../lcd/marlinui.h"
-#endif
-
#if ENABLED(MMU2_MENUS)
#include "../../../lcd/menu/menu_mmu2.h"
#endif
@@ -96,8 +93,8 @@ void GcodeSuite::M600() {
#endif
// Show initial "wait for start" message
- #if HAS_LCD_MENU && DISABLED(MMU2_MENUS)
- lcd_pause_show_message(PAUSE_MESSAGE_CHANGING, PAUSE_MODE_PAUSE_PRINT, target_extruder);
+ #if DISABLED(MMU2_MENUS)
+ ui.pause_show_message(PAUSE_MESSAGE_CHANGING, PAUSE_MODE_PAUSE_PRINT, target_extruder);
#endif
#if ENABLED(HOME_BEFORE_FILAMENT_CHANGE)
diff --git a/Marlin/src/gcode/feature/pause/M701_M702.cpp b/Marlin/src/gcode/feature/pause/M701_M702.cpp
index a889da8aea..9a2b774936 100644
--- a/Marlin/src/gcode/feature/pause/M701_M702.cpp
+++ b/Marlin/src/gcode/feature/pause/M701_M702.cpp
@@ -29,15 +29,12 @@
#include "../../../module/motion.h"
#include "../../../module/temperature.h"
#include "../../../feature/pause.h"
+#include "../../../lcd/marlinui.h"
#if HAS_MULTI_EXTRUDER
#include "../../../module/tool_change.h"
#endif
-#if HAS_LCD_MENU
- #include "../../../lcd/marlinui.h"
-#endif
-
#if HAS_PRUSA_MMU2
#include "../../../feature/mmu/mmu2.h"
#endif
@@ -82,7 +79,7 @@ void GcodeSuite::M701() {
if (parser.seenval('Z')) park_point.z = parser.linearval('Z');
// Show initial "wait for load" message
- TERN_(HAS_LCD_MENU, lcd_pause_show_message(PAUSE_MESSAGE_LOAD, PAUSE_MODE_LOAD_FILAMENT, target_extruder));
+ ui.pause_show_message(PAUSE_MESSAGE_LOAD, PAUSE_MODE_LOAD_FILAMENT, target_extruder);
#if HAS_MULTI_EXTRUDER && (HAS_PRUSA_MMU1 || !HAS_MMU)
// Change toolhead if specified
@@ -128,7 +125,7 @@ void GcodeSuite::M701() {
TERN_(MIXING_EXTRUDER, mixer.T(old_mixing_tool)); // Restore original mixing tool
// Show status screen
- TERN_(HAS_LCD_MENU, lcd_pause_show_message(PAUSE_MESSAGE_STATUS));
+ ui.pause_show_message(PAUSE_MESSAGE_STATUS);
}
/**
@@ -180,7 +177,7 @@ void GcodeSuite::M702() {
if (parser.seenval('Z')) park_point.z = parser.linearval('Z');
// Show initial "wait for unload" message
- TERN_(HAS_LCD_MENU, lcd_pause_show_message(PAUSE_MESSAGE_UNLOAD, PAUSE_MODE_UNLOAD_FILAMENT, target_extruder));
+ ui.pause_show_message(PAUSE_MESSAGE_UNLOAD, PAUSE_MODE_UNLOAD_FILAMENT, target_extruder);
#if HAS_MULTI_EXTRUDER && (HAS_PRUSA_MMU1 || !HAS_MMU)
// Change toolhead if specified
@@ -232,7 +229,7 @@ void GcodeSuite::M702() {
TERN_(MIXING_EXTRUDER, mixer.T(old_mixing_tool)); // Restore original mixing tool
// Show status screen
- TERN_(HAS_LCD_MENU, lcd_pause_show_message(PAUSE_MESSAGE_STATUS));
+ ui.pause_show_message(PAUSE_MESSAGE_STATUS);
}
#endif // ADVANCED_PAUSE_FEATURE
diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp
index 89bc0dc7af..f9173188dc 100644
--- a/Marlin/src/gcode/gcode.cpp
+++ b/Marlin/src/gcode/gcode.cpp
@@ -40,7 +40,7 @@ GcodeSuite gcode;
#include "../module/printcounter.h"
#endif
-#if ENABLED(HOST_PROMPT_SUPPORT)
+#if ENABLED(HOST_ACTION_COMMANDS)
#include "../feature/host_actions.h"
#endif
@@ -61,7 +61,7 @@ GcodeSuite gcode;
#include "../feature/password/password.h"
#endif
-#include "../MarlinCore.h" // for idle()
+#include "../MarlinCore.h" // for idle, kill
// Inactivity shutdown
millis_t GcodeSuite::previous_move_ms = 0,
@@ -209,6 +209,31 @@ void GcodeSuite::dwell(millis_t time) {
*/
#if BOTH(HAS_LEVELING, G29_RETRY_AND_RECOVER)
+ void GcodeSuite::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
+ process_subcommands_now_P(PSTR(G29_RECOVER_COMMANDS));
+ #endif
+ }
+
+ void GcodeSuite::event_probe_failure() {
+ #ifdef ACTION_ON_G29_FAILURE
+ host_action(PSTR(ACTION_ON_G29_FAILURE));
+ #endif
+ #ifdef G29_FAILURE_COMMANDS
+ 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
+ }
+
#ifndef G29_MAX_RETRIES
#define G29_MAX_RETRIES 0
#endif
@@ -216,7 +241,10 @@ void GcodeSuite::dwell(millis_t time) {
void GcodeSuite::G29_with_retry() {
uint8_t retries = G29_MAX_RETRIES;
while (G29()) { // G29 should return true for failed probes ONLY
- if (retries--) event_probe_recover();
+ if (retries) {
+ event_probe_recover();
+ --retries;
+ }
else {
event_probe_failure();
return;
@@ -718,6 +746,10 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
case 412: M412(); break; // M412: Enable/Disable filament runout detection
#endif
+ #if HAS_MULTI_LANGUAGE
+ case 414: M414(); break; // M414: Select multi language menu
+ #endif
+
#if HAS_LEVELING
case 420: M420(); break; // M420: Enable/Disable Bed Leveling
#endif
@@ -954,6 +986,8 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
}
if (!no_ok) queue.ok_to_send();
+
+ SERIAL_OUT(msgDone); // Call the msgDone serial hook to signal command processing done
}
/**
@@ -963,7 +997,7 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
void GcodeSuite::process_next_command() {
char * const current_command = queue.command_buffer[queue.index_r];
- PORT_REDIRECT(queue.port[queue.index_r]);
+ PORT_REDIRECT(SERIAL_PORTMASK(queue.port[queue.index_r]));
#if ENABLED(POWER_LOSS_RECOVERY)
recovery.queue_index_r = queue.index_r;
diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h
index 765cd8e591..7fd8d6904a 100644
--- a/Marlin/src/gcode/gcode.h
+++ b/Marlin/src/gcode/gcode.h
@@ -213,6 +213,7 @@
* M410 - Quickstop. Abort all planned moves.
* M412 - Enable / Disable Filament Runout Detection. (Requires FILAMENT_RUNOUT_SENSOR)
* M413 - Enable / Disable Power-Loss Recovery. (Requires POWER_LOSS_RECOVERY)
+ * M414 - Set language by index. (Requires LCD_LANGUAGE_2...)
* M420 - Enable/Disable Leveling (with current values) S1=enable S0=disable (Requires MESH_BED_LEVELING or ABL)
* M421 - Set a single Z coordinate in the Mesh Leveling grid. X Y Z (Requires MESH_BED_LEVELING, AUTO_BED_LEVELING_BILINEAR, or AUTO_BED_LEVELING_UBL)
* M422 - Set Z Stepper automatic alignment position using probe. X Y A (Requires Z_STEPPER_AUTO_ALIGN)
@@ -309,6 +310,8 @@
enum AxisRelative : uint8_t { REL_X, REL_Y, REL_Z, REL_E, E_MODE_ABS, E_MODE_REL };
+extern const char G28_STR[];
+
class GcodeSuite {
public:
@@ -370,7 +373,6 @@ public:
static void process_subcommands_now(char * gcode);
static inline void home_all_axes(const bool keep_leveling=false) {
- extern const char G28_STR[];
process_subcommands_now_P(keep_leveling ? G28_STR : TERN(G28_L0_ENSURES_LEVELING_OFF, PSTR("G28L0"), G28_STR));
}
@@ -451,6 +453,8 @@ private:
#if HAS_LEVELING
#if ENABLED(G29_RETRY_AND_RECOVER)
+ static void event_probe_failure();
+ static void event_probe_recover();
static void G29_with_retry();
#define G29_TYPE bool
#else
@@ -747,6 +751,8 @@ private:
TERN_(HAS_FILAMENT_SENSOR, static void M412());
+ TERN_(HAS_MULTI_LANGUAGE, static void M414());
+
#if HAS_LEVELING
static void M420();
static void M421();
diff --git a/Marlin/src/gcode/geometry/M206_M428.cpp b/Marlin/src/gcode/geometry/M206_M428.cpp
index efb89fbcf2..2a2cdb16ff 100644
--- a/Marlin/src/gcode/geometry/M206_M428.cpp
+++ b/Marlin/src/gcode/geometry/M206_M428.cpp
@@ -30,8 +30,6 @@
#include "../../libs/buzzer.h"
#include "../../MarlinCore.h"
-extern const char SP_Y_STR[], SP_Z_STR[];
-
void m206_report() {
SERIAL_ECHOLNPAIR_P(PSTR("M206 X"), home_offset.x, SP_Y_STR, home_offset.y, SP_Z_STR, home_offset.z);
}
diff --git a/Marlin/src/gcode/host/M115.cpp b/Marlin/src/gcode/host/M115.cpp
index 63511b606d..1b088e7d34 100644
--- a/Marlin/src/gcode/host/M115.cpp
+++ b/Marlin/src/gcode/host/M115.cpp
@@ -141,6 +141,9 @@ void GcodeSuite::M115() {
// CHAMBER_TEMPERATURE (M141, M191)
cap_line(PSTR("CHAMBER_TEMPERATURE"), ENABLED(HAS_HEATED_CHAMBER));
+ // MEATPACK Compresson
+ cap_line(PSTR("MEATPACK"), ENABLED(MEATPACK));
+
// Machine Geometry
#if ENABLED(M115_GEOMETRY_REPORT)
const xyz_pos_t dmin = { X_MIN_POS, Y_MIN_POS, Z_MIN_POS },
diff --git a/Marlin/src/gcode/host/M118.cpp b/Marlin/src/gcode/host/M118.cpp
index 27207b7172..73115d5c0a 100644
--- a/Marlin/src/gcode/host/M118.cpp
+++ b/Marlin/src/gcode/host/M118.cpp
@@ -53,21 +53,14 @@ void GcodeSuite::M118() {
}
#if HAS_MULTI_SERIAL
- const int8_t old_serial = serial_port_index;
+ const int8_t old_serial = multiSerial.portMask;
if (WITHIN(port, 0, NUM_SERIAL))
- serial_port_index = (
- port == 0 ? SERIAL_BOTH
- : port == 1 ? 0
- #if HAS_MULTI_SERIAL
- : port == 2 ? 1
- #endif
- : SERIAL_PORT
- );
+ multiSerial.portMask = port ? _BV(port - 1) : SERIAL_ALL;
#endif
if (hasE) SERIAL_ECHO_START();
if (hasA) SERIAL_ECHOPGM("//");
SERIAL_ECHOLN(p);
- TERN_(HAS_MULTI_SERIAL, serial_port_index = old_serial);
+ TERN_(HAS_MULTI_SERIAL, multiSerial.portMask = old_serial);
}
diff --git a/Marlin/src/gcode/lcd/M414.cpp b/Marlin/src/gcode/lcd/M414.cpp
new file mode 100644
index 0000000000..760028a899
--- /dev/null
+++ b/Marlin/src/gcode/lcd/M414.cpp
@@ -0,0 +1,44 @@
+/**
+ * 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 "../../inc/MarlinConfig.h"
+
+#if HAS_MULTI_LANGUAGE
+
+#include "../gcode.h"
+#include "../../MarlinCore.h"
+#include "../../lcd/marlinui.h"
+
+/**
+ * M414: Set the language for the UI
+ *
+ * Parameters
+ * S : The language to select
+ */
+void GcodeSuite::M414() {
+
+ if (parser.seenval('S'))
+ ui.set_language(parser.value_byte());
+
+}
+
+#endif // HAS_MULTI_LANGUAGE
diff --git a/Marlin/src/gcode/parser.h b/Marlin/src/gcode/parser.h
index 8633d2b1e9..cf531c4e47 100644
--- a/Marlin/src/gcode/parser.h
+++ b/Marlin/src/gcode/parser.h
@@ -282,7 +282,7 @@ public:
// Code value for use as time
static inline millis_t value_millis() { return value_ulong(); }
- static inline millis_t value_millis_from_seconds() { return (millis_t)(value_float() * 1000); }
+ static inline millis_t value_millis_from_seconds() { return (millis_t)SEC_TO_MS(value_float()); }
// Reduce to fewer bits
static inline int16_t value_int() { return (int16_t)value_long(); }
diff --git a/Marlin/src/gcode/probe/M851.cpp b/Marlin/src/gcode/probe/M851.cpp
index ee60e9ebc0..04b293de31 100644
--- a/Marlin/src/gcode/probe/M851.cpp
+++ b/Marlin/src/gcode/probe/M851.cpp
@@ -28,8 +28,6 @@
#include "../../feature/bedlevel/bedlevel.h"
#include "../../module/probe.h"
-extern const char SP_Y_STR[], SP_Z_STR[];
-
/**
* M851: Set the nozzle-to-probe offsets in current units
*/
diff --git a/Marlin/src/gcode/queue.cpp b/Marlin/src/gcode/queue.cpp
index 98fe91db40..4c42f7e353 100644
--- a/Marlin/src/gcode/queue.cpp
+++ b/Marlin/src/gcode/queue.cpp
@@ -31,6 +31,7 @@ GCodeQueue queue;
#include "../lcd/marlinui.h"
#include "../sd/cardreader.h"
+#include "../module/motion.h"
#include "../module/planner.h"
#include "../module/temperature.h"
#include "../MarlinCore.h"
@@ -47,6 +48,10 @@ GCodeQueue queue;
#include "../feature/binary_stream.h"
#endif
+#if ENABLED(MEATPACK)
+ #include "../feature/meatpack.h"
+#endif
+
#if ENABLED(POWER_LOSS_RECOVERY)
#include "../feature/powerloss.h"
#endif
@@ -55,6 +60,9 @@ GCodeQueue queue;
#include "../feature/repeat.h"
#endif
+// Frequently used G-code strings
+PGMSTR(G28_STR, "G28");
+
/**
* GCode line number handling. Hosts may opt to include line numbers when
* sending commands to Marlin, and lines will be checked for sequentiality.
@@ -81,7 +89,7 @@ char GCodeQueue::command_buffer[BUFSIZE][MAX_CMD_SIZE];
* The port that the command was received on
*/
#if HAS_MULTI_SERIAL
- int16_t GCodeQueue::port[BUFSIZE];
+ serial_index_t GCodeQueue::port[BUFSIZE];
#endif
/**
@@ -128,11 +136,11 @@ void GCodeQueue::clear() {
*/
void GCodeQueue::_commit_command(bool say_ok
#if HAS_MULTI_SERIAL
- , int16_t p/*=-1*/
+ , serial_index_t serial_ind/*=-1*/
#endif
) {
send_ok[index_w] = say_ok;
- TERN_(HAS_MULTI_SERIAL, port[index_w] = p);
+ TERN_(HAS_MULTI_SERIAL, port[index_w] = serial_ind);
TERN_(POWER_LOSS_RECOVERY, recovery.commit_sdpos(index_w));
if (++index_w >= BUFSIZE) index_w = 0;
length++;
@@ -145,14 +153,14 @@ void GCodeQueue::_commit_command(bool say_ok
*/
bool GCodeQueue::_enqueue(const char* cmd, bool say_ok/*=false*/
#if HAS_MULTI_SERIAL
- , int16_t pn/*=-1*/
+ , serial_index_t serial_ind/*=-1*/
#endif
) {
if (*cmd == ';' || length >= BUFSIZE) return false;
strcpy(command_buffer[index_w], cmd);
_commit_command(say_ok
#if HAS_MULTI_SERIAL
- , pn
+ , serial_ind
#endif
);
return true;
@@ -281,9 +289,9 @@ void GCodeQueue::enqueue_now_P(PGM_P const pgcode) {
*/
void GCodeQueue::ok_to_send() {
#if HAS_MULTI_SERIAL
- const int16_t pn = command_port();
- if (pn < 0) return;
- PORT_REDIRECT(pn); // Reply to the serial port that sent the command
+ const serial_index_t serial_ind = command_port();
+ if (serial_ind < 0) return;
+ PORT_REDIRECT(SERIAL_PORTMASK(serial_ind)); // Reply to the serial port that sent the command
#endif
if (!send_ok[index_r]) return;
SERIAL_ECHOPGM(STR_OK);
@@ -306,14 +314,14 @@ void GCodeQueue::ok_to_send() {
* indicate that a command needs to be re-sent.
*/
void GCodeQueue::flush_and_request_resend() {
- const int16_t pn = command_port();
+ const serial_index_t serial_ind = command_port();
#if HAS_MULTI_SERIAL
- if (pn < 0) return;
- PORT_REDIRECT(pn); // Reply to the serial port that sent the command
+ if (serial_ind < 0) return; // Never mind. Command came from SD or Flash Drive
+ PORT_REDIRECT(SERIAL_PORTMASK(serial_ind)); // Reply to the serial port that sent the command
#endif
SERIAL_FLUSH();
SERIAL_ECHOPGM(STR_RESEND);
- SERIAL_ECHOLN(last_N[pn] + 1);
+ SERIAL_ECHOLN(last_N[serial_ind] + 1);
ok_to_send();
}
@@ -340,14 +348,14 @@ inline int read_serial(const uint8_t index) {
}
}
-void GCodeQueue::gcode_line_error(PGM_P const err, const int8_t pn) {
- PORT_REDIRECT(pn); // Reply to the serial port that sent the command
+void GCodeQueue::gcode_line_error(PGM_P const err, const serial_index_t serial_ind) {
+ PORT_REDIRECT(SERIAL_PORTMASK(serial_ind)); // Reply to the serial port that sent the command
SERIAL_ERROR_START();
serialprintPGM(err);
- SERIAL_ECHOLN(last_N[pn]);
- while (read_serial(pn) != -1); // Clear out the RX buffer
+ SERIAL_ECHOLN(last_N[serial_ind]);
+ while (read_serial(serial_ind) != -1); // Clear out the RX buffer
flush_and_request_resend();
- serial_count[pn] = 0;
+ serial_count[serial_ind] = 0;
}
FORCE_INLINE bool is_M29(const char * const cmd) { // matches "M29" & "M29 ", but not "M290", etc
@@ -465,103 +473,114 @@ void GCodeQueue::get_serial_commands() {
* Loop while serial characters are incoming and the queue is not full
*/
while (length < BUFSIZE && serial_data_available()) {
- LOOP_L_N(i, NUM_SERIAL) {
+ LOOP_L_N(p, NUM_SERIAL) {
- const int c = read_serial(i);
+ const int c = read_serial(p);
if (c < 0) continue;
- const char serial_char = c;
+ #if ENABLED(MEATPACK)
+ meatpack.handle_rx_char(uint8_t(c), p);
+ char c_res[2] = { 0, 0 };
+ const uint8_t char_count = meatpack.get_result_char(c_res);
+ #else
+ constexpr uint8_t char_count = 1;
+ #endif
- if (ISEOL(serial_char)) {
+ LOOP_L_N(char_index, char_count) {
+ const char serial_char = TERN(MEATPACK, c_res[char_index], c);
- // Reset our state, continue if the line was empty
- if (process_line_done(serial_input_state[i], serial_line_buffer[i], serial_count[i]))
- continue;
+ if (ISEOL(serial_char)) {
- char* command = serial_line_buffer[i];
+ // Reset our state, continue if the line was empty
+ if (process_line_done(serial_input_state[p], serial_line_buffer[p], serial_count[p]))
+ continue;
- while (*command == ' ') command++; // Skip leading spaces
- char *npos = (*command == 'N') ? command : nullptr; // Require the N parameter to start the line
+ char* command = serial_line_buffer[p];
- if (npos) {
+ while (*command == ' ') command++; // Skip leading spaces
+ char *npos = (*command == 'N') ? command : nullptr; // Require the N parameter to start the line
- const bool M110 = !!strstr_P(command, PSTR("M110"));
+ if (npos) {
- if (M110) {
- char* n2pos = strchr(command + 4, 'N');
- if (n2pos) npos = n2pos;
+ const bool M110 = !!strstr_P(command, PSTR("M110"));
+
+ if (M110) {
+ char* n2pos = strchr(command + 4, 'N');
+ if (n2pos) npos = n2pos;
+ }
+
+ const long gcode_N = strtol(npos + 1, nullptr, 10);
+
+ if (gcode_N != last_N[p] + 1 && !M110)
+ return gcode_line_error(PSTR(STR_ERR_LINE_NO), p);
+
+ char *apos = strrchr(command, '*');
+ if (apos) {
+ uint8_t checksum = 0, count = uint8_t(apos - command);
+ while (count) checksum ^= command[--count];
+ if (strtol(apos + 1, nullptr, 10) != checksum)
+ return gcode_line_error(PSTR(STR_ERR_CHECKSUM_MISMATCH), p);
+ }
+ else
+ return gcode_line_error(PSTR(STR_ERR_NO_CHECKSUM), p);
+
+ last_N[p] = gcode_N;
}
+ #if ENABLED(SDSUPPORT)
+ // Pronterface "M29" and "M29 " has no line number
+ else if (card.flag.saving && !is_M29(command))
+ return gcode_line_error(PSTR(STR_ERR_NO_CHECKSUM), p);
+ #endif
- const long gcode_N = strtol(npos + 1, nullptr, 10);
+ //
+ // Movement commands give an alert when the machine is stopped
+ //
- if (gcode_N != last_N[i] + 1 && !M110)
- return gcode_line_error(PSTR(STR_ERR_LINE_NO), i);
-
- char *apos = strrchr(command, '*');
- if (apos) {
- uint8_t checksum = 0, count = uint8_t(apos - command);
- while (count) checksum ^= command[--count];
- if (strtol(apos + 1, nullptr, 10) != checksum)
- return gcode_line_error(PSTR(STR_ERR_CHECKSUM_MISMATCH), i);
- }
- else
- return gcode_line_error(PSTR(STR_ERR_NO_CHECKSUM), i);
-
- last_N[i] = gcode_N;
- }
- #if ENABLED(SDSUPPORT)
- // Pronterface "M29" and "M29 " has no line number
- else if (card.flag.saving && !is_M29(command))
- return gcode_line_error(PSTR(STR_ERR_NO_CHECKSUM), i);
- #endif
-
- //
- // Movement commands give an alert when the machine is stopped
- //
-
- if (IsStopped()) {
- char* gpos = strchr(command, 'G');
- if (gpos) {
- switch (strtol(gpos + 1, nullptr, 10)) {
- case 0: case 1:
- #if ENABLED(ARC_SUPPORT)
- case 2: case 3:
- #endif
- #if ENABLED(BEZIER_CURVE_SUPPORT)
- case 5:
- #endif
- PORT_REDIRECT(i); // Reply to the serial port that sent the command
- SERIAL_ECHOLNPGM(STR_ERR_STOPPED);
- LCD_MESSAGEPGM(MSG_STOPPED);
- break;
+ if (IsStopped()) {
+ char* gpos = strchr(command, 'G');
+ if (gpos) {
+ switch (strtol(gpos + 1, nullptr, 10)) {
+ case 0: case 1:
+ #if ENABLED(ARC_SUPPORT)
+ case 2: case 3:
+ #endif
+ #if ENABLED(BEZIER_CURVE_SUPPORT)
+ case 5:
+ #endif
+ PORT_REDIRECT(SERIAL_PORTMASK(p)); // Reply to the serial port that sent the command
+ SERIAL_ECHOLNPGM(STR_ERR_STOPPED);
+ LCD_MESSAGEPGM(MSG_STOPPED);
+ break;
+ }
}
}
- }
- #if DISABLED(EMERGENCY_PARSER)
- // Process critical commands early
- if (command[0] == 'M') switch (command[3]) {
- case '8': if (command[2] == '0' && command[1] == '1') { wait_for_heatup = false; TERN_(HAS_LCD_MENU, wait_for_user = false); } break;
- case '2': if (command[2] == '1' && command[1] == '1') kill(M112_KILL_STR, nullptr, true); break;
- case '0': if (command[1] == '4' && command[2] == '1') quickstop_stepper(); break;
- }
- #endif
-
- #if defined(NO_TIMEOUTS) && NO_TIMEOUTS > 0
- last_command_time = ms;
- #endif
-
- // Add the command to the queue
- _enqueue(serial_line_buffer[i], true
- #if HAS_MULTI_SERIAL
- , i
+ #if DISABLED(EMERGENCY_PARSER)
+ // Process critical commands early
+ if (command[0] == 'M') switch (command[3]) {
+ case '8': if (command[2] == '0' && command[1] == '1') { wait_for_heatup = false; TERN_(HAS_LCD_MENU, wait_for_user = false); } break;
+ case '2': if (command[2] == '1' && command[1] == '1') kill(M112_KILL_STR, nullptr, true); break;
+ case '0': if (command[1] == '4' && command[2] == '1') quickstop_stepper(); break;
+ }
#endif
- );
- }
- else
- process_stream_char(serial_char, serial_input_state[i], serial_line_buffer[i], serial_count[i]);
- } // for NUM_SERIAL
+ #if defined(NO_TIMEOUTS) && NO_TIMEOUTS > 0
+ last_command_time = ms;
+ #endif
+
+ // Add the command to the queue
+ _enqueue(serial_line_buffer[p], true
+ #if HAS_MULTI_SERIAL
+ , p
+ #endif
+ );
+ }
+ else
+ process_stream_char(serial_char, serial_input_state[p], serial_line_buffer[p], serial_count[p]);
+
+ } // char_count loop
+
+ } // NUM_SERIAL loop
} // queue has space, serial has data
}
diff --git a/Marlin/src/gcode/queue.h b/Marlin/src/gcode/queue.h
index 966af2871f..d677146a7d 100644
--- a/Marlin/src/gcode/queue.h
+++ b/Marlin/src/gcode/queue.h
@@ -56,12 +56,9 @@ public:
* The port that the command was received on
*/
#if HAS_MULTI_SERIAL
- static int16_t port[BUFSIZE];
+ static serial_index_t port[BUFSIZE];
#endif
-
- static int16_t command_port() {
- return TERN0(HAS_MULTI_SERIAL, port[index_r]);
- }
+ static inline serial_index_t command_port() { return TERN0(HAS_MULTI_SERIAL, port[index_r]); }
GCodeQueue();
@@ -159,13 +156,13 @@ private:
static void _commit_command(bool say_ok
#if HAS_MULTI_SERIAL
- , int16_t p=-1
+ , serial_index_t serial_ind=-1
#endif
);
static bool _enqueue(const char* cmd, bool say_ok=false
#if HAS_MULTI_SERIAL
- , int16_t p=-1
+ , serial_index_t serial_ind=-1
#endif
);
@@ -181,8 +178,10 @@ private:
*/
static bool enqueue_one(const char* cmd);
- static void gcode_line_error(PGM_P const err, const int8_t pn);
+ static void gcode_line_error(PGM_P const err, const serial_index_t serial_ind);
};
extern GCodeQueue queue;
+
+extern const char G28_STR[];
diff --git a/Marlin/src/gcode/sd/M1001.cpp b/Marlin/src/gcode/sd/M1001.cpp
index 406cd074c3..1cf700ae26 100644
--- a/Marlin/src/gcode/sd/M1001.cpp
+++ b/Marlin/src/gcode/sd/M1001.cpp
@@ -44,7 +44,7 @@
#endif
#if HAS_LEDS_OFF_FLAG
- #include "../../MarlinCore.h" // for wait_for_user_response
+ #include "../../MarlinCore.h" // for wait_for_user_response()
#include "../../feature/leds/printer_event_leds.h"
#endif
@@ -82,7 +82,7 @@ void GcodeSuite::M1001() {
// Announce SD file completion
{
- PORT_REDIRECT(SERIAL_BOTH);
+ PORT_REDIRECT(SERIAL_ALL);
SERIAL_ECHOLNPGM(STR_FILE_PRINTED);
}
@@ -92,7 +92,7 @@ void GcodeSuite::M1001() {
printerEventLEDs.onPrintCompleted();
TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired_P(GET_TEXT(MSG_PRINT_DONE)));
TERN_(HOST_PROMPT_SUPPORT, host_prompt_do(PROMPT_USER_CONTINUE, GET_TEXT(MSG_PRINT_DONE), CONTINUE_STR));
- wait_for_user_response(1000UL * TERN(HAS_LCD_MENU, PE_LEDS_COMPLETED_TIME, 30));
+ wait_for_user_response(SEC_TO_MS(TERN(HAS_LCD_MENU, PE_LEDS_COMPLETED_TIME, 30)));
printerEventLEDs.onResumeAfterWait();
}
#endif
diff --git a/Marlin/src/gcode/sd/M27.cpp b/Marlin/src/gcode/sd/M27.cpp
index 8592b8af25..a76070fda8 100644
--- a/Marlin/src/gcode/sd/M27.cpp
+++ b/Marlin/src/gcode/sd/M27.cpp
@@ -36,15 +36,17 @@ void GcodeSuite::M27() {
if (parser.seen('C')) {
SERIAL_ECHOPGM("Current file: ");
card.printFilename();
+ return;
}
#if ENABLED(AUTO_REPORT_SD_STATUS)
- else if (parser.seenval('S'))
- card.set_auto_report_interval(parser.value_byte());
+ if (parser.seenval('S')) {
+ card.auto_reporter.set_interval(parser.value_byte());
+ return;
+ }
#endif
- else
- card.report_status();
+ card.report_status();
}
#endif // SDSUPPORT
diff --git a/Marlin/src/gcode/temp/M104_M109.cpp b/Marlin/src/gcode/temp/M104_M109.cpp
index 90e1b601e4..07e46e1775 100644
--- a/Marlin/src/gcode/temp/M104_M109.cpp
+++ b/Marlin/src/gcode/temp/M104_M109.cpp
@@ -45,7 +45,7 @@
#endif
#endif
-#if ENABLED(SINGLENOZZLE)
+#if ENABLED(SINGLENOZZLE_STANDBY_TEMP)
#include "../../module/tool_change.h"
#endif
@@ -88,7 +88,7 @@ void GcodeSuite::M104() {
if (got_temp) {
#if ENABLED(SINGLENOZZLE_STANDBY_TEMP)
- singlenozzle_temp[target_extruder] = temp;
+ thermalManager.singlenozzle_temp[target_extruder] = temp;
if (target_extruder != active_extruder) return;
#endif
thermalManager.setTargetHotend(temp, target_extruder);
@@ -166,7 +166,7 @@ void GcodeSuite::M109() {
if (got_temp) {
#if ENABLED(SINGLENOZZLE_STANDBY_TEMP)
- singlenozzle_temp[target_extruder] = temp;
+ thermalManager.singlenozzle_temp[target_extruder] = temp;
if (target_extruder != active_extruder) return;
#endif
thermalManager.setTargetHotend(temp, target_extruder);
diff --git a/Marlin/src/gcode/temp/M155.cpp b/Marlin/src/gcode/temp/M155.cpp
index 30129a0e6f..48c23986ae 100644
--- a/Marlin/src/gcode/temp/M155.cpp
+++ b/Marlin/src/gcode/temp/M155.cpp
@@ -33,7 +33,7 @@
void GcodeSuite::M155() {
if (parser.seenval('S'))
- thermalManager.set_auto_report_interval(parser.value_byte());
+ thermalManager.auto_reporter.set_interval(parser.value_byte());
}
diff --git a/Marlin/src/inc/Conditionals_LCD.h b/Marlin/src/inc/Conditionals_LCD.h
index c95262fced..976b8aaf8e 100644
--- a/Marlin/src/inc/Conditionals_LCD.h
+++ b/Marlin/src/inc/Conditionals_LCD.h
@@ -320,6 +320,7 @@
// FSMC/SPI TFT Panels (LVGL)
#if ENABLED(TFT_LVGL_UI)
#define HAS_TFT_LVGL_UI 1
+ #define SERIAL_RUNTIME_HOOK 1
#endif
// FSMC/SPI TFT Panels
@@ -1155,36 +1156,37 @@
#endif
#endif
-#if ENABLED(TFT_COLOR_UI) && TFT_HEIGHT == 240
- #if ENABLED(TFT_INTERFACE_SPI)
- #define TFT_320x240_SPI
- #elif ENABLED(TFT_INTERFACE_FSMC)
- #define TFT_320x240
- #endif
-#elif ENABLED(TFT_COLOR_UI) && TFT_HEIGHT == 320
- #if ENABLED(TFT_INTERFACE_SPI)
- #define TFT_480x320_SPI
- #elif ENABLED(TFT_INTERFACE_FSMC)
- #define TFT_480x320
- #endif
-#elif ENABLED(TFT_COLOR_UI) && TFT_HEIGHT == 272
- #if ENABLED(TFT_INTERFACE_SPI)
- #define TFT_480x272_SPI
- #elif ENABLED(TFT_INTERFACE_FSMC)
- #define TFT_480x272
+#if ENABLED(TFT_COLOR_UI)
+ #if TFT_HEIGHT == 240
+ #if ENABLED(TFT_INTERFACE_SPI)
+ #define TFT_320x240_SPI
+ #elif ENABLED(TFT_INTERFACE_FSMC)
+ #define TFT_320x240
+ #endif
+ #elif TFT_HEIGHT == 320
+ #if ENABLED(TFT_INTERFACE_SPI)
+ #define TFT_480x320_SPI
+ #elif ENABLED(TFT_INTERFACE_FSMC)
+ #define TFT_480x320
+ #endif
+ #elif TFT_HEIGHT == 272
+ #if ENABLED(TFT_INTERFACE_SPI)
+ #define TFT_480x272_SPI
+ #elif ENABLED(TFT_INTERFACE_FSMC)
+ #define TFT_480x272
+ #endif
#endif
#endif
-// Fewer lines with touch buttons on-screen
#if EITHER(TFT_320x240, TFT_320x240_SPI)
#define HAS_UI_320x240 1
- #define LCD_HEIGHT TERN(TOUCH_SCREEN, 6, 7)
#elif EITHER(TFT_480x320, TFT_480x320_SPI)
#define HAS_UI_480x320 1
- #define LCD_HEIGHT TERN(TOUCH_SCREEN, 6, 7)
#elif EITHER(TFT_480x272, TFT_480x272_SPI)
#define HAS_UI_480x272 1
- #define LCD_HEIGHT TERN(TOUCH_SCREEN, 6, 7)
+#endif
+#if ANY(HAS_UI_320x240, HAS_UI_480x320, HAS_UI_480x272)
+ #define LCD_HEIGHT TERN(TOUCH_SCREEN, 6, 7) // Fewer lines with touch buttons onscreen
#endif
// This emulated DOGM has 'touch/xpt2046', not 'tft/xpt2046'
diff --git a/Marlin/src/inc/MarlinConfig.h b/Marlin/src/inc/MarlinConfig.h
index 2eafa2b417..8fdb4b9bae 100644
--- a/Marlin/src/inc/MarlinConfig.h
+++ b/Marlin/src/inc/MarlinConfig.h
@@ -55,3 +55,5 @@
#include "../core/serial.h"
#endif
+
+#include "../core/multi_language.h"
diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h
index e68a2482f4..c10c4de540 100644
--- a/Marlin/src/inc/SanityCheck.h
+++ b/Marlin/src/inc/SanityCheck.h
@@ -357,10 +357,6 @@
#error "FILAMENT_CHANGE_LOAD_LENGTH is now FILAMENT_CHANGE_FAST_LOAD_LENGTH."
#elif defined(LEVEL_CORNERS_INSET)
#error "LEVEL_CORNERS_INSET is now LEVEL_CORNERS_INSET_LFRB."
-#elif ENABLED(LEVEL_BED_CORNERS) && !defined(LEVEL_CORNERS_INSET_LFRB)
- #error "LEVEL_BED_CORNERS requires LEVEL_CORNERS_INSET_LFRB values."
-#elif BOTH(LEVEL_CORNERS_USE_PROBE, SENSORLESS_PROBING)
- #error "LEVEL_CORNERS_USE_PROBE is incompatible with SENSORLESS_PROBING."
#elif defined(BEZIER_JERK_CONTROL)
#error "BEZIER_JERK_CONTROL is now S_CURVE_ACCELERATION."
#elif HAS_JUNCTION_DEVIATION && defined(JUNCTION_DEVIATION_FACTOR)
@@ -709,6 +705,10 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS
#endif
#endif
+#if ENABLED(USE_M73_REMAINING_TIME) && DISABLED(LCD_SET_PROGRESS_MANUALLY)
+ #error "USE_M73_REMAINING_TIME requires LCD_SET_PROGRESS_MANUALLY"
+#endif
+
#if !HAS_LCD_MENU && ENABLED(SD_REPRINT_LAST_SELECTED_FILE)
#error "SD_REPRINT_LAST_SELECTED_FILE currently requires a Marlin-native LCD menu."
#endif
@@ -802,8 +802,6 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS
#if ENABLED(BABYSTEP_XY)
static_assert(BABYSTEP_MULTIPLICATOR_XY <= 0.25f, "BABYSTEP_MULTIPLICATOR_XY must be less than or equal to 0.25mm.");
#endif
- #elif ENABLED(BABYSTEP_DISPLAY_TOTAL) && ANY(TFT_320x240, TFT_320x240_SPI, TFT_480x320, TFT_480x320_SPI)
- #error "New Color UI (TFT_320x240, TFT_320x240_SPI, TFT_480x320, TFT_480x320_SPI) does not support BABYSTEP_DISPLAY_TOTAL yet."
#endif
#endif
@@ -1429,6 +1427,18 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS
#endif
+#if ENABLED(LEVEL_BED_CORNERS)
+ #ifndef LEVEL_CORNERS_INSET_LFRB
+ #error "LEVEL_BED_CORNERS requires LEVEL_CORNERS_INSET_LFRB values."
+ #elif ENABLED(LEVEL_CORNERS_USE_PROBE)
+ #if !HAS_BED_PROBE
+ #error "LEVEL_CORNERS_USE_PROBE requires a real probe."
+ #elif ENABLED(SENSORLESS_PROBING)
+ #error "LEVEL_CORNERS_USE_PROBE is incompatible with SENSORLESS_PROBING."
+ #endif
+ #endif
+#endif
+
/**
* Allow only one bed leveling option to be defined
*/
@@ -1931,16 +1941,16 @@ static_assert(hbm[Z_AXIS] >= 0, "HOMING_BUMP_MM.Z must be greater than or equal
* Basic multi hotend duplication mode
*/
#if ENABLED(MULTI_NOZZLE_DUPLICATION)
- #if HOTENDS < 2
- #error "MULTI_NOZZLE_DUPLICATION requires 2 or more hotends."
+ #if ENABLED(SINGLENOZZLE)
+ #error "MULTI_NOZZLE_DUPLICATION is incompatible with SINGLENOZZLE."
#elif ENABLED(DUAL_X_CARRIAGE)
#error "MULTI_NOZZLE_DUPLICATION is incompatible with DUAL_X_CARRIAGE."
- #elif ENABLED(SINGLENOZZLE)
- #error "MULTI_NOZZLE_DUPLICATION is incompatible with SINGLENOZZLE."
#elif ENABLED(MIXING_EXTRUDER)
#error "MULTI_NOZZLE_DUPLICATION is incompatible with MIXING_EXTRUDER."
#elif ENABLED(SWITCHING_EXTRUDER)
#error "MULTI_NOZZLE_DUPLICATION is incompatible with SWITCHING_EXTRUDER."
+ #elif HOTENDS < 2
+ #error "MULTI_NOZZLE_DUPLICATION requires 2 or more hotends."
#endif
#endif
@@ -3291,6 +3301,14 @@ static_assert( _ARR_TEST(3,0) && _ARR_TEST(3,1) && _ARR_TEST(3,2)
#endif
#endif
+
+/**
+ * Sanity Check for MEATPACK and BINARY_FILE_TRANSFER Features
+ */
+#if BOTH(MEATPACK, BINARY_FILE_TRANSFER)
+ #error "Either enable MEATPACK or enable BINARY_FILE_TRANSFER."
+#endif
+
/**
* Sanity check for valid stepper driver types
*/
diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h
index af69c47b24..3ec1f3c1c0 100644
--- a/Marlin/src/inc/Version.h
+++ b/Marlin/src/inc/Version.h
@@ -42,7 +42,7 @@
* version was tagged.
*/
#ifndef STRING_DISTRIBUTION_DATE
- #define STRING_DISTRIBUTION_DATE "2021-01-17"
+ #define STRING_DISTRIBUTION_DATE "2021-01-30"
#endif
/**
diff --git a/Marlin/src/lcd/HD44780/marlinui_HD44780.cpp b/Marlin/src/lcd/HD44780/marlinui_HD44780.cpp
index 84c477fbde..635751b3f5 100644
--- a/Marlin/src/lcd/HD44780/marlinui_HD44780.cpp
+++ b/Marlin/src/lcd/HD44780/marlinui_HD44780.cpp
@@ -471,7 +471,6 @@ void MarlinUI::clear_lcd() { lcd.clear(); }
// Show the Marlin logo and short build version
// After a delay show the website URL
//
- extern const char NUL_STR[];
logo_lines(NUL_STR);
CENTER_OR_SCROLL(SHORT_BUILD_VERSION, 1500);
CENTER_OR_SCROLL(MARLIN_WEBSITE_URL, 1500);
diff --git a/Marlin/src/lcd/dogm/dogm_Statusscreen.h b/Marlin/src/lcd/dogm/dogm_Statusscreen.h
index 15578e21d9..61fee3e048 100644
--- a/Marlin/src/lcd/dogm/dogm_Statusscreen.h
+++ b/Marlin/src/lcd/dogm/dogm_Statusscreen.h
@@ -193,7 +193,7 @@
#define STATUS_LOGO_HEIGHT (sizeof(status_logo_bmp) / (STATUS_LOGO_BYTEWIDTH))
#endif
#ifndef STATUS_LOGO_Y
- #define STATUS_LOGO_Y _MAX(0L, (28L - _MIN(28L, STATUS_LOGO_HEIGHT)) / 2L)
+ #define STATUS_LOGO_Y _MAX(0U, (28U - _MIN(28U, STATUS_LOGO_HEIGHT)) / 2U)
#endif
static_assert(
sizeof(status_logo_bmp) == (STATUS_LOGO_BYTEWIDTH) * (STATUS_LOGO_HEIGHT),
diff --git a/Marlin/src/lcd/dogm/marlinui_DOGM.cpp b/Marlin/src/lcd/dogm/marlinui_DOGM.cpp
index c326b89aa8..c7c5908b36 100644
--- a/Marlin/src/lcd/dogm/marlinui_DOGM.cpp
+++ b/Marlin/src/lcd/dogm/marlinui_DOGM.cpp
@@ -54,6 +54,7 @@
#include "../../sd/cardreader.h"
#include "../../module/temperature.h"
#include "../../module/printcounter.h"
+#include "../../MarlinCore.h"
#if ENABLED(SDSUPPORT)
#include "../../libs/duration_t.h"
@@ -455,20 +456,22 @@ void MarlinUI::clear_lcd() { } // Automatically cleared by Picture Loop
inline void draw_boxed_string(const u8g_uint_t x, const u8g_uint_t y, PGM_P const pstr, const bool inv) {
const u8g_uint_t len = utf8_strlen_P(pstr),
by = (y + 1) * (MENU_FONT_HEIGHT);
- const pixel_len_t bw = len * (MENU_FONT_WIDTH), bx = x * (MENU_FONT_WIDTH);
+ const u8g_uint_t prop = USE_WIDE_GLYPH ? 2 : 1;
+ const pixel_len_t bw = len * prop * (MENU_FONT_WIDTH), bx = x * prop * (MENU_FONT_WIDTH);
if (inv) {
u8g.setColorIndex(1);
- u8g.drawBox(bx - 1, by - (MENU_FONT_ASCENT) + 1, bw + 2, MENU_FONT_HEIGHT - 1);
+ u8g.drawBox(bx / prop - 1, by - (MENU_FONT_ASCENT) + 1, bw / prop + 2, MENU_FONT_HEIGHT - 1);
u8g.setColorIndex(0);
}
- lcd_put_u8str_P(bx, by, pstr);
+ lcd_put_u8str_P(bx / prop, by, pstr);
if (inv) u8g.setColorIndex(1);
}
void MenuItem_confirm::draw_select_screen(PGM_P const yes, PGM_P const no, const bool yesno, PGM_P const pref, const char * const string/*=nullptr*/, PGM_P const suff/*=nullptr*/) {
ui.draw_select_screen_prompt(pref, string, suff);
draw_boxed_string(1, LCD_HEIGHT - 1, no, !yesno);
- draw_boxed_string(LCD_WIDTH - (utf8_strlen_P(yes) + 1), LCD_HEIGHT - 1, yes, yesno);
+ const u8g_uint_t xpos = (LCD_WIDTH) / (USE_WIDE_GLYPH ? 2 : 1);
+ draw_boxed_string(xpos - (utf8_strlen_P(yes) + 1), LCD_HEIGHT - 1, yes, yesno);
}
#if ENABLED(SDSUPPORT)
diff --git a/Marlin/src/lcd/dogm/status_screen_DOGM.cpp b/Marlin/src/lcd/dogm/status_screen_DOGM.cpp
index 985041ede5..8ae6ab6627 100644
--- a/Marlin/src/lcd/dogm/status_screen_DOGM.cpp
+++ b/Marlin/src/lcd/dogm/status_screen_DOGM.cpp
@@ -40,6 +40,10 @@
#include "../../gcode/parser.h" // for units (and volumetric)
+#if ENABLED(LCD_SHOW_E_TOTAL)
+ #include "../../MarlinCore.h" // for printingIsActive(), marlin_state and MF_SD_COMPLETE
+#endif
+
#if ENABLED(FILAMENT_LCD_DISPLAY)
#include "../../feature/filwidth.h"
#include "../../module/planner.h"
diff --git a/Marlin/src/lcd/dwin/e3v2/dwin.cpp b/Marlin/src/lcd/dwin/e3v2/dwin.cpp
index e1655d0ed9..39f161f5ad 100644
--- a/Marlin/src/lcd/dwin/e3v2/dwin.cpp
+++ b/Marlin/src/lcd/dwin/e3v2/dwin.cpp
@@ -132,8 +132,9 @@
#define FEEDRATE_E (60)
-// Mininum unit (0.1) : multiple (10)
-#define MINUNITMULT 10
+// Minimum unit (0.1) : multiple (10)
+#define UNITFDIGITS 1
+#define MINUNITMULT pow(10, UNITFDIGITS)
#define ENCODER_WAIT 20
#define DWIN_SCROLL_UPDATE_INTERVAL 2000
@@ -1171,8 +1172,8 @@ void HMI_Move_X() {
}
NOLESS(HMI_ValueStruct.Move_X_scale, (X_MIN_POS) * MINUNITMULT);
NOMORE(HMI_ValueStruct.Move_X_scale, (X_MAX_POS) * MINUNITMULT);
- current_position.x = HMI_ValueStruct.Move_X_scale / 10;
- DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Select_Color, 3, 1, 216, MBASE(1), HMI_ValueStruct.Move_X_scale);
+ current_position.x = HMI_ValueStruct.Move_X_scale / MINUNITMULT;
+ DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Select_Color, 3, UNITFDIGITS, 216, MBASE(1), HMI_ValueStruct.Move_X_scale);
DWIN_UpdateLCD();
}
}
@@ -1194,8 +1195,8 @@ void HMI_Move_Y() {
}
NOLESS(HMI_ValueStruct.Move_Y_scale, (Y_MIN_POS) * MINUNITMULT);
NOMORE(HMI_ValueStruct.Move_Y_scale, (Y_MAX_POS) * MINUNITMULT);
- current_position.y = HMI_ValueStruct.Move_Y_scale / 10;
- DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Select_Color, 3, 1, 216, MBASE(2), HMI_ValueStruct.Move_Y_scale);
+ current_position.y = HMI_ValueStruct.Move_Y_scale / MINUNITMULT;
+ DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Select_Color, 3, UNITFDIGITS, 216, MBASE(2), HMI_ValueStruct.Move_Y_scale);
DWIN_UpdateLCD();
}
}
@@ -1206,7 +1207,7 @@ void HMI_Move_Z() {
if (Apply_Encoder(encoder_diffState, HMI_ValueStruct.Move_Z_scale)) {
checkkey = AxisMove;
EncoderRate.enabled = false;
- DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Color_Bg_Black, 3, 1, 216, MBASE(3), HMI_ValueStruct.Move_Z_scale);
+ DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Color_Bg_Black, 3, UNITFDIGITS, 216, MBASE(3), HMI_ValueStruct.Move_Z_scale);
if (!planner.is_full()) {
// Wait for planner moves to finish!
planner.synchronize();
@@ -1217,8 +1218,8 @@ void HMI_Move_Z() {
}
NOLESS(HMI_ValueStruct.Move_Z_scale, Z_MIN_POS * MINUNITMULT);
NOMORE(HMI_ValueStruct.Move_Z_scale, Z_MAX_POS * MINUNITMULT);
- current_position.z = HMI_ValueStruct.Move_Z_scale / 10;
- DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Select_Color, 3, 1, 216, MBASE(3), HMI_ValueStruct.Move_Z_scale);
+ current_position.z = HMI_ValueStruct.Move_Z_scale / MINUNITMULT;
+ DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Select_Color, 3, UNITFDIGITS, 216, MBASE(3), HMI_ValueStruct.Move_Z_scale);
DWIN_UpdateLCD();
}
}
@@ -1233,7 +1234,7 @@ void HMI_Move_Z() {
checkkey = AxisMove;
EncoderRate.enabled = false;
last_E_scale = HMI_ValueStruct.Move_E_scale;
- DWIN_Draw_Signed_Float(font8x16, Color_Bg_Black, 3, 1, 216, MBASE(4), HMI_ValueStruct.Move_E_scale);
+ DWIN_Draw_Signed_Float(font8x16, Color_Bg_Black, 3, UNITFDIGITS, 216, MBASE(4), HMI_ValueStruct.Move_E_scale);
if (!planner.is_full()) {
planner.synchronize(); // Wait for planner moves to finish!
planner.buffer_line(current_position, MMM_TO_MMS(FEEDRATE_E), active_extruder);
@@ -1245,8 +1246,8 @@ void HMI_Move_Z() {
HMI_ValueStruct.Move_E_scale = last_E_scale + (EXTRUDE_MAXLENGTH) * MINUNITMULT;
else if ((last_E_scale - HMI_ValueStruct.Move_E_scale) > (EXTRUDE_MAXLENGTH) * MINUNITMULT)
HMI_ValueStruct.Move_E_scale = last_E_scale - (EXTRUDE_MAXLENGTH) * MINUNITMULT;
- current_position.e = HMI_ValueStruct.Move_E_scale / 10;
- DWIN_Draw_Signed_Float(font8x16, Select_Color, 3, 1, 216, MBASE(4), HMI_ValueStruct.Move_E_scale);
+ current_position.e = HMI_ValueStruct.Move_E_scale / MINUNITMULT;
+ DWIN_Draw_Signed_Float(font8x16, Select_Color, 3, UNITFDIGITS, 216, MBASE(4), HMI_ValueStruct.Move_E_scale);
DWIN_UpdateLCD();
}
}
@@ -1503,7 +1504,7 @@ void HMI_MaxAccelerationXYZE() {
NOMORE(HMI_ValueStruct.Max_Jerk, default_max_jerk[HMI_flag.jerk_axis] * 2 * MINUNITMULT);
NOLESS(HMI_ValueStruct.Max_Jerk, (MIN_MAXJERK) * MINUNITMULT);
// MaxJerk value
- DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Select_Color, 3, 1, 210, MBASE(select_jerk.now), HMI_ValueStruct.Max_Jerk);
+ DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Select_Color, 3, UNITFDIGITS, 210, MBASE(select_jerk.now), HMI_ValueStruct.Max_Jerk);
}
}
@@ -1525,7 +1526,7 @@ void HMI_StepXYZE() {
NOMORE(HMI_ValueStruct.Max_Step, 999.9 * MINUNITMULT);
NOLESS(HMI_ValueStruct.Max_Step, MIN_STEP);
// Step value
- DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Select_Color, 3, 1, 210, MBASE(select_step.now), HMI_ValueStruct.Max_Step);
+ DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Select_Color, 3, UNITFDIGITS, 210, MBASE(select_step.now), HMI_ValueStruct.Max_Step);
}
}
@@ -2317,13 +2318,12 @@ void HMI_Prepare() {
select_axis.reset();
Draw_Move_Menu();
- DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Color_Bg_Black, 3, 1, 216, MBASE(1), current_position.x * MINUNITMULT);
- DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Color_Bg_Black, 3, 1, 216, MBASE(2), current_position.y * MINUNITMULT);
- DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Color_Bg_Black, 3, 1, 216, MBASE(3), current_position.z * MINUNITMULT);
+ DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Color_Bg_Black, 3, UNITFDIGITS, 216, MBASE(1), current_position.x * MINUNITMULT);
+ DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Color_Bg_Black, 3, UNITFDIGITS, 216, MBASE(2), current_position.y * MINUNITMULT);
+ DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Color_Bg_Black, 3, UNITFDIGITS, 216, MBASE(3), current_position.z * MINUNITMULT);
#if HAS_HOTEND
- queue.inject_P(PSTR("G92 E0"));
- current_position.e = HMI_ValueStruct.Move_E_scale = 0;
- DWIN_Draw_Signed_Float(font8x16, Color_Bg_Black, 3, 1, 216, MBASE(4), 0);
+ HMI_ValueStruct.Move_E_scale = current_position.e * MINUNITMULT;
+ DWIN_Draw_Signed_Float(font8x16, Color_Bg_Black, 3, 1, 216, MBASE(4), HMI_ValueStruct.Move_E_scale);
#endif
break;
case PREPARE_CASE_DISA: // Disable steppers
@@ -2573,7 +2573,7 @@ void HMI_AxisMove() {
if (HMI_flag.ETempTooLow_flag) {
if (encoder_diffState == ENCODER_DIFF_ENTER) {
HMI_flag.ETempTooLow_flag = false;
- current_position.e = HMI_ValueStruct.Move_E_scale = 0;
+ HMI_ValueStruct.Move_E_scale = current_position.e * MINUNITMULT;
Draw_Move_Menu();
DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Color_Bg_Black, 3, 1, 216, MBASE(1), HMI_ValueStruct.Move_X_scale);
DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Color_Bg_Black, 3, 1, 216, MBASE(2), HMI_ValueStruct.Move_Y_scale);
@@ -3019,11 +3019,11 @@ inline void Draw_Max_Accel_Menu() {
Draw_Back_First();
LOOP_L_N(i, 3 + ENABLED(HAS_HOTEND)) Draw_Menu_Line(i + 1, ICON_MaxSpeedJerkX + i);
- DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Color_Bg_Black, 3, 1, 210, MBASE(1), planner.max_jerk[X_AXIS] * MINUNITMULT);
- DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Color_Bg_Black, 3, 1, 210, MBASE(2), planner.max_jerk[Y_AXIS] * MINUNITMULT);
- DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Color_Bg_Black, 3, 1, 210, MBASE(3), planner.max_jerk[Z_AXIS] * MINUNITMULT);
+ DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Color_Bg_Black, 3, UNITFDIGITS, 210, MBASE(1), planner.max_jerk[X_AXIS] * MINUNITMULT);
+ DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Color_Bg_Black, 3, UNITFDIGITS, 210, MBASE(2), planner.max_jerk[Y_AXIS] * MINUNITMULT);
+ DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Color_Bg_Black, 3, UNITFDIGITS, 210, MBASE(3), planner.max_jerk[Z_AXIS] * MINUNITMULT);
#if HAS_HOTEND
- DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Color_Bg_Black, 3, 1, 210, MBASE(4), planner.max_jerk[E_AXIS] * MINUNITMULT);
+ DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Color_Bg_Black, 3, UNITFDIGITS, 210, MBASE(4), planner.max_jerk[E_AXIS] * MINUNITMULT);
#endif
}
#endif
@@ -3067,11 +3067,11 @@ inline void Draw_Steps_Menu() {
Draw_Back_First();
LOOP_L_N(i, 3 + ENABLED(HAS_HOTEND)) Draw_Menu_Line(i + 1, ICON_StepX + i);
- DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Color_Bg_Black, 3, 1, 210, MBASE(1), planner.settings.axis_steps_per_mm[X_AXIS] * MINUNITMULT);
- DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Color_Bg_Black, 3, 1, 210, MBASE(2), planner.settings.axis_steps_per_mm[Y_AXIS] * MINUNITMULT);
- DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Color_Bg_Black, 3, 1, 210, MBASE(3), planner.settings.axis_steps_per_mm[Z_AXIS] * MINUNITMULT);
+ DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Color_Bg_Black, 3, UNITFDIGITS, 210, MBASE(1), planner.settings.axis_steps_per_mm[X_AXIS] * MINUNITMULT);
+ DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Color_Bg_Black, 3, UNITFDIGITS, 210, MBASE(2), planner.settings.axis_steps_per_mm[Y_AXIS] * MINUNITMULT);
+ DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Color_Bg_Black, 3, UNITFDIGITS, 210, MBASE(3), planner.settings.axis_steps_per_mm[Z_AXIS] * MINUNITMULT);
#if HAS_HOTEND
- DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Color_Bg_Black, 3, 1, 210, MBASE(4), planner.settings.axis_steps_per_mm[E_AXIS] * MINUNITMULT);
+ DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Color_Bg_Black, 3, UNITFDIGITS, 210, MBASE(4), planner.settings.axis_steps_per_mm[E_AXIS] * MINUNITMULT);
#endif
}
@@ -3418,7 +3418,7 @@ void HMI_MaxAcceleration() {
checkkey = MaxJerk_value;
HMI_flag.jerk_axis = AxisEnum(select_jerk.now - 1);
HMI_ValueStruct.Max_Jerk = planner.max_jerk[HMI_flag.jerk_axis] * MINUNITMULT;
- DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Select_Color, 3, 1, 210, MBASE(select_jerk.now), HMI_ValueStruct.Max_Jerk);
+ DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Select_Color, 3, UNITFDIGITS, 210, MBASE(select_jerk.now), HMI_ValueStruct.Max_Jerk);
EncoderRate.enabled = true;
}
else { // Back
@@ -3448,7 +3448,7 @@ void HMI_Step() {
checkkey = Step_value;
HMI_flag.step_axis = AxisEnum(select_step.now - 1);
HMI_ValueStruct.Max_Step = planner.settings.axis_steps_per_mm[HMI_flag.step_axis] * MINUNITMULT;
- DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Select_Color, 3, 1, 210, MBASE(select_step.now), HMI_ValueStruct.Max_Step);
+ DWIN_Draw_FloatValue(true, true, 0, font8x16, Color_White, Select_Color, 3, UNITFDIGITS, 210, MBASE(select_step.now), HMI_ValueStruct.Max_Step);
EncoderRate.enabled = true;
}
else { // Back
@@ -3553,7 +3553,7 @@ void EachMomentUpdate() {
static millis_t next_remain_time_update = 0;
if (Percentrecord > 1 && ELAPSED(ms, next_remain_time_update) && !HMI_flag.heat_flag) {
remain_time = (elapsed.value - dwin_heat_time) / (Percentrecord * 0.01f) - (elapsed.value - dwin_heat_time);
- next_remain_time_update += 20 * 1000UL;
+ next_remain_time_update += SEC_TO_MS(20);
Draw_Print_ProgressRemain();
}
}
diff --git a/Marlin/src/lcd/dwin/e3v2/rotary_encoder.h b/Marlin/src/lcd/dwin/e3v2/rotary_encoder.h
index bbba753a0b..7de80dfe01 100644
--- a/Marlin/src/lcd/dwin/e3v2/rotary_encoder.h
+++ b/Marlin/src/lcd/dwin/e3v2/rotary_encoder.h
@@ -30,7 +30,6 @@
****************************************************************************/
#include "../../../inc/MarlinConfig.h"
-#include "../../../MarlinCore.h"
/*********************** Encoder Set ***********************/
diff --git a/Marlin/src/lcd/extui/dgus_lcd.cpp b/Marlin/src/lcd/extui/dgus_lcd.cpp
index 33d8bd4d89..9fcb6c8d13 100644
--- a/Marlin/src/lcd/extui/dgus_lcd.cpp
+++ b/Marlin/src/lcd/extui/dgus_lcd.cpp
@@ -35,8 +35,6 @@
#include "lib/dgus/DGUSDisplayDef.h"
#include "lib/dgus/DGUSScreenHandler.h"
-extern const char NUL_STR[];
-
namespace ExtUI {
void onStartup() {
diff --git a/Marlin/src/lcd/extui/lib/anycubic_chiron/FileNavigator.cpp b/Marlin/src/lcd/extui/lib/anycubic_chiron/FileNavigator.cpp
index fb4c84abb4..19f8ec81bc 100644
--- a/Marlin/src/lcd/extui/lib/anycubic_chiron/FileNavigator.cpp
+++ b/Marlin/src/lcd/extui/lib/anycubic_chiron/FileNavigator.cpp
@@ -44,6 +44,8 @@ using namespace ExtUI;
namespace Anycubic {
+ FileNavigator filenavigator;
+
FileList FileNavigator::filelist; // Instance of the Marlin file API
char FileNavigator::currentfoldername[MAX_PATH_LEN]; // Current folder path
uint16_t FileNavigator::lastindex;
diff --git a/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft.cpp b/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft.cpp
index b0053895a7..61057b5b10 100644
--- a/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft.cpp
+++ b/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft.cpp
@@ -54,6 +54,8 @@ namespace Anycubic {
float ChironTFT::live_Zoffset;
file_menu_t ChironTFT::file_menu;
+ ChironTFT Chiron;
+
ChironTFT::ChironTFT(){}
void ChironTFT::Startup() {
@@ -574,10 +576,11 @@ namespace Anycubic {
} break;
case 15: // A15 Resuming from outage
- if (printer_state == AC_printer_resuming_from_power_outage)
+ if (printer_state == AC_printer_resuming_from_power_outage) {
// Need to home here to restore the Z position
- injectCommands_P(AC_cmnd_power_loss_recovery);
- injectCommands_P(PSTR("M1000")); // home and start recovery
+ injectCommands(AC_cmnd_power_loss_recovery);
+ injectCommands("M1000"); // home and start recovery
+ }
break;
case 16: { // A16 Set HotEnd temp A17 S170
diff --git a/Marlin/src/lcd/extui/lib/anycubic_i3mega/anycubic_i3mega_lcd.cpp b/Marlin/src/lcd/extui/lib/anycubic_i3mega/anycubic_i3mega_lcd.cpp
index a3f7c42a5c..1508dc0d27 100644
--- a/Marlin/src/lcd/extui/lib/anycubic_i3mega/anycubic_i3mega_lcd.cpp
+++ b/Marlin/src/lcd/extui/lib/anycubic_i3mega/anycubic_i3mega_lcd.cpp
@@ -27,8 +27,8 @@
#include "../../ui_api.h"
#include "../../../../libs/numtostr.h"
-#include "../../../../module/motion.h" // for A20 read printing speed feedrate_percentage
-#include "../../../../MarlinCore.h" // for quickstop_stepper, disable_steppers, G28_STR
+#include "../../../../module/motion.h" // for quickstop_stepper, A20 read printing speed, feedrate_percentage
+#include "../../../../MarlinCore.h" // for disable_steppers
#include "../../../../inc/MarlinConfig.h"
// command sending macro's with debugging capability
diff --git a/Marlin/src/lcd/extui/lib/anycubic_i3mega/anycubic_i3mega_lcd.h b/Marlin/src/lcd/extui/lib/anycubic_i3mega/anycubic_i3mega_lcd.h
index a4ecf5604f..59050acccb 100644
--- a/Marlin/src/lcd/extui/lib/anycubic_i3mega/anycubic_i3mega_lcd.h
+++ b/Marlin/src/lcd/extui/lib/anycubic_i3mega/anycubic_i3mega_lcd.h
@@ -94,3 +94,4 @@ private:
};
extern AnycubicTFTClass AnycubicTFT;
+extern const char G28_STR[];
diff --git a/Marlin/src/lcd/extui/lib/dgus/DGUSDisplay.h b/Marlin/src/lcd/extui/lib/dgus/DGUSDisplay.h
index ee536ea219..88c119566c 100644
--- a/Marlin/src/lcd/extui/lib/dgus/DGUSDisplay.h
+++ b/Marlin/src/lcd/extui/lib/dgus/DGUSDisplay.h
@@ -25,7 +25,8 @@
#include "../../../../inc/MarlinConfigPre.h"
-#include "../../../../MarlinCore.h"
+#include // size_t
+
#if HAS_BED_PROBE
#include "../../../../module/probe.h"
#endif
@@ -96,7 +97,7 @@ private:
static void WritePGM(const char str[], uint8_t len);
static void ProcessRx();
- static inline uint16_t swap16(const uint16_t value) { return (value & 0xffU) << 8U | (value >> 8U); }
+ static inline uint16_t swap16(const uint16_t value) { return (value & 0xFFU) << 8U | (value >> 8U); }
static rx_datagram_state_t rx_datagram_state;
static uint8_t rx_datagram_len;
static bool Initialized, no_reentrance;
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/compat.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/compat.h
index 741b7076d1..c01d45ed7c 100644
--- a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/compat.h
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/compat.h
@@ -43,10 +43,11 @@
#define min(a,b) ((a)<(b)?(a):(b))
#else
namespace UI {
- static inline uint32_t safe_millis() {return millis();};
- static inline void yield() {};
+ static inline uint32_t safe_millis() { return millis(); }
+ static inline void yield() {}
};
#endif
class __FlashStringHelper;
typedef const __FlashStringHelper *progmem_str;
+extern const char G28_STR[];
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/filament_runout_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/filament_runout_screen.cpp
index c281ccb050..41e3be22ef 100644
--- a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/filament_runout_screen.cpp
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/filament_runout_screen.cpp
@@ -36,7 +36,6 @@ void FilamentRunoutScreen::onRedraw(draw_mode_t what) {
w.toggle( 2, GET_TEXT_F(MSG_RUNOUT_SENSOR), getFilamentRunoutEnabled());
#if HAS_FILAMENT_RUNOUT_DISTANCE
- extern const char NUL_STR[];
w.heading(GET_TEXT_F(MSG_RUNOUT_DISTANCE_MM));
w.units(GET_TEXT_F(MSG_UNITS_MM));
w.precision(0);
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/stress_test_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/stress_test_screen.cpp
index 0aed1b7c53..6c4aab6d31 100644
--- a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/stress_test_screen.cpp
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/stress_test_screen.cpp
@@ -120,7 +120,6 @@ void StressTestScreen::onIdle() {
if (!commandsInQueue()) {
if (!isPositionKnown()) {
- extern const char G28_STR[];
injectCommands_P(G28_STR);
}
else {
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_dialog.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_dialog.cpp
index 95077d09f2..6130e92224 100644
--- a/Marlin/src/lcd/extui/lib/mks_ui/draw_dialog.cpp
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_dialog.cpp
@@ -257,7 +257,7 @@ void lv_draw_dialog(uint8_t type) {
lv_label_set_text(labelOk, print_file_dialog_menu.confirm);
}
}
- else if (DIALOG_IS(TYPE_UPDATE_ESP_FIRMARE)) {
+ else if (DIALOG_IS(TYPE_UPDATE_ESP_FIRMWARE)) {
// nothing to do
}
#endif
@@ -426,7 +426,7 @@ void lv_draw_dialog(uint8_t type) {
lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20);
}
}
- else if (DIALOG_IS(TYPE_UPDATE_ESP_FIRMARE)) {
+ else if (DIALOG_IS(TYPE_UPDATE_ESP_FIRMWARE)) {
lv_label_set_text(labelDialog, DIALOG_UPDATE_WIFI_FIRMWARE_EN);
lv_obj_align(labelDialog, NULL, LV_ALIGN_CENTER, 0, -20);
}
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_home.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_home.cpp
index 5b65f990c1..588b940bb6 100644
--- a/Marlin/src/lcd/extui/lib/mks_ui/draw_home.cpp
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_home.cpp
@@ -31,8 +31,6 @@
#include "../../../../gcode/queue.h"
#include "../../../../inc/MarlinConfig.h"
-extern const char G28_STR[];
-
extern lv_group_t *g;
static lv_obj_t *scr;
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_manuaLevel.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_manuaLevel.cpp
index 0b09ae391d..495acda06b 100644
--- a/Marlin/src/lcd/extui/lib/mks_ui/draw_manuaLevel.cpp
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_manuaLevel.cpp
@@ -29,8 +29,6 @@
#include "../../../../gcode/queue.h"
#include "../../../../inc/MarlinConfig.h"
-extern const char G28_STR[];
-
extern lv_group_t *g;
static lv_obj_t *scr;
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_move_motor.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_move_motor.cpp
index 6db1810fcf..d10175344d 100644
--- a/Marlin/src/lcd/extui/lib/mks_ui/draw_move_motor.cpp
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_move_motor.cpp
@@ -54,14 +54,18 @@ enum {
static void event_handler(lv_obj_t *obj, lv_event_t event) {
if (event != LV_EVENT_RELEASED) return;
if (queue.length <= (BUFSIZE - 3)) {
+ bool do_inject = true;
float dist = uiCfg.move_dist;
switch (obj->mks_obj_id) {
case ID_M_X_N: dist *= -1; case ID_M_X_P: cur_label = 'X'; break;
case ID_M_Y_N: dist *= -1; case ID_M_Y_P: cur_label = 'Y'; break;
case ID_M_Z_N: dist *= -1; case ID_M_Z_P: cur_label = 'Z'; break;
+ default: do_inject = false;
+ }
+ if (do_inject) {
+ sprintf_P(public_buf_l, PSTR("G91\nG1 %c%3.1f F%d\nG90"), cur_label, dist, uiCfg.moveSpeed);
+ queue.inject(public_buf_l);
}
- sprintf_P(public_buf_l, PSTR("G91\nG1 %c%3.1f F%d\nG90"), cur_label, dist, uiCfg.moveSpeed);
- queue.inject(public_buf_l);
}
switch (obj->mks_obj_id) {
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_ui.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_ui.cpp
index 88e6fab07c..84049d51ab 100644
--- a/Marlin/src/lcd/extui/lib/mks_ui/draw_ui.cpp
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_ui.cpp
@@ -889,7 +889,7 @@ void GUI_RefreshPage() {
lv_draw_wifi_tips();
}
- if (tips_disp.timer_count >= 30 * 1000) {
+ if (tips_disp.timer_count >= SEC_TO_MS(30)) {
tips_disp.timer = TIPS_TIMER_STOP;
tips_disp.timer_count = 0;
lv_clear_wifi_tips();
@@ -898,7 +898,7 @@ void GUI_RefreshPage() {
}
break;
case TIPS_TYPE_TAILED_JOIN:
- if (tips_disp.timer_count >= 3 * 1000) {
+ if (tips_disp.timer_count >= SEC_TO_MS(3)) {
tips_disp.timer = TIPS_TIMER_STOP;
tips_disp.timer_count = 0;
@@ -908,7 +908,7 @@ void GUI_RefreshPage() {
}
break;
case TIPS_TYPE_WIFI_CONECTED:
- if (tips_disp.timer_count >= 3 * 1000) {
+ if (tips_disp.timer_count >= SEC_TO_MS(3)) {
tips_disp.timer = TIPS_TIMER_STOP;
tips_disp.timer_count = 0;
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_ui.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_ui.h
index ded6bc7825..f02a58ad43 100644
--- a/Marlin/src/lcd/extui/lib/mks_ui/draw_ui.h
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_ui.h
@@ -77,7 +77,7 @@
#include "draw_keyboard.h"
#include "draw_encoder_settings.h"
-#include "../../inc/MarlinConfigPre.h"
+#include "../../../../inc/MarlinConfigPre.h"
#if ENABLED(MKS_WIFI_MODULE)
#include "wifiSerial.h"
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/mks_hardware_test.cpp b/Marlin/src/lcd/extui/lib/mks_ui/mks_hardware_test.cpp
index d2d1c19063..8cbe319d14 100644
--- a/Marlin/src/lcd/extui/lib/mks_ui/mks_hardware_test.cpp
+++ b/Marlin/src/lcd/extui/lib/mks_ui/mks_hardware_test.cpp
@@ -157,7 +157,7 @@ void mks_gpio_test() {
&& (READ(PE6) == 0)
&& (READ(PE7) == 0)
#endif
- )
+ )
disp_det_ok();
else
disp_det_error();
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/pic_manager.cpp b/Marlin/src/lcd/extui/lib/mks_ui/pic_manager.cpp
index 1cb7ed185e..8b96587fea 100644
--- a/Marlin/src/lcd/extui/lib/mks_ui/pic_manager.cpp
+++ b/Marlin/src/lcd/extui/lib/mks_ui/pic_manager.cpp
@@ -64,7 +64,6 @@ static const char assets[][LONG_FILENAME_LENGTH] = {
"bmp_speed255.bin",
"bmp_speed127.bin",
"bmp_speed0.bin",
- "bmp_speed0.bin",
"bmp_bed.bin",
"bmp_step1_degree.bin",
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/tft_lvgl_configuration.cpp b/Marlin/src/lcd/extui/lib/mks_ui/tft_lvgl_configuration.cpp
index 65b7538b71..b7441f71f4 100644
--- a/Marlin/src/lcd/extui/lib/mks_ui/tft_lvgl_configuration.cpp
+++ b/Marlin/src/lcd/extui/lib/mks_ui/tft_lvgl_configuration.cpp
@@ -89,8 +89,8 @@ void SysTick_Callback() {
#endif
if (uiCfg.filament_loading_time_flg) {
uiCfg.filament_loading_time_cnt++;
- uiCfg.filament_rate = (uint32_t)(((uiCfg.filament_loading_time_cnt / (uiCfg.filament_loading_time * 1000.0)) * 100.0) + 0.5);
- if (uiCfg.filament_loading_time_cnt >= (uiCfg.filament_loading_time * 1000)) {
+ uiCfg.filament_rate = uint32_t(100.0f * uiCfg.filament_loading_time_cnt / SEC_TO_MS(uiCfg.filament_loading_time) + 0.5f);
+ if (uiCfg.filament_loading_time_cnt >= SEC_TO_MS(uiCfg.filament_loading_time)) {
uiCfg.filament_loading_time_cnt = 0;
uiCfg.filament_loading_time_flg = false;
uiCfg.filament_loading_completed = true;
@@ -98,8 +98,8 @@ void SysTick_Callback() {
}
if (uiCfg.filament_unloading_time_flg) {
uiCfg.filament_unloading_time_cnt++;
- uiCfg.filament_rate = (uint32_t)(((uiCfg.filament_unloading_time_cnt / (uiCfg.filament_unloading_time * 1000.0)) * 100.0) + 0.5);
- if (uiCfg.filament_unloading_time_cnt >= (uiCfg.filament_unloading_time * 1000)) {
+ uiCfg.filament_rate = uint32_t(100.0f * uiCfg.filament_unloading_time_cnt / SEC_TO_MS(uiCfg.filament_unloading_time) + 0.5f);
+ if (uiCfg.filament_unloading_time_cnt >= SEC_TO_MS(uiCfg.filament_unloading_time)) {
uiCfg.filament_unloading_time_cnt = 0;
uiCfg.filament_unloading_time_flg = false;
uiCfg.filament_unloading_completed = true;
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/tft_multi_language.cpp b/Marlin/src/lcd/extui/lib/mks_ui/tft_multi_language.cpp
index 7db5e80561..28c90486d0 100644
--- a/Marlin/src/lcd/extui/lib/mks_ui/tft_multi_language.cpp
+++ b/Marlin/src/lcd/extui/lib/mks_ui/tft_multi_language.cpp
@@ -23,8 +23,6 @@
#if HAS_TFT_LVGL_UI
-#include "../../../../MarlinCore.h"
-
#include "draw_ui.h"
#include "tft_multi_language.h"
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/wifi_module.cpp b/Marlin/src/lcd/extui/lib/mks_ui/wifi_module.cpp
index bf4f75017f..785e854c52 100644
--- a/Marlin/src/lcd/extui/lib/mks_ui/wifi_module.cpp
+++ b/Marlin/src/lcd/extui/lib/mks_ui/wifi_module.cpp
@@ -21,15 +21,13 @@
*/
#include "../../../../inc/MarlinConfigPre.h"
-#if HAS_TFT_LVGL_UI
+#if BOTH(HAS_TFT_LVGL_UI, MKS_WIFI_MODULE)
#include "draw_ui.h"
#include "wifi_module.h"
#include "wifi_upload.h"
#include "SPI_TFT.h"
-#if ENABLED(MKS_WIFI_MODULE)
-
#include "../../../../MarlinCore.h"
#include "../../../../module/temperature.h"
#include "../../../../gcode/queue.h"
@@ -39,6 +37,10 @@
#include "../../../../module/planner.h"
#include "../../../../module/servo.h"
#include "../../../../module/probe.h"
+
+#if DISABLED(EMERGENCY_PARSER)
+ #include "../../../../module/motion.h"
+#endif
#if ENABLED(POWER_LOSS_RECOVERY)
#include "../../../../feature/powerloss.h"
#endif
@@ -455,7 +457,6 @@ int package_to_wifi(WIFI_RET_TYPE type, uint8_t *buf, int len) {
return 1;
}
-
#define SEND_OK_TO_WIFI send_to_wifi((uint8_t *)"ok\r\n", strlen("ok\r\n"))
int send_to_wifi(uint8_t *buf, int len) { return package_to_wifi(WIFI_TRANS_INF, buf, len); }
@@ -549,7 +550,6 @@ typedef struct {
uint8_t tail;
} ESP_PROTOC_FRAME;
-
static int cut_msg_head(uint8_t *msg, uint16_t msgLen, uint16_t cutLen) {
if (msgLen < cutLen) return 0;
@@ -1663,7 +1663,7 @@ void mks_esp_wifi_init() {
clear_cur_ui();
- draw_dialog(DIALOG_TYPE_UPDATE_ESP_FIRMARE);
+ draw_dialog(DIALOG_TYPE_UPDATE_ESP_FIRMWARE);
if (wifi_upload(1) >= 0) {
f_unlink("1:/MKS_WIFI_CUR");
@@ -1703,7 +1703,6 @@ void mks_esp_wifi_init() {
wifi_link_state = WIFI_NOT_CONFIG;
}
-
void mks_wifi_firmware_update() {
card.openFileRead((char *)ESP_FIRMWARE_FILE);
@@ -1717,7 +1716,7 @@ void mks_wifi_firmware_update() {
clear_cur_ui();
- lv_draw_dialog(DIALOG_TYPE_UPDATE_ESP_FIRMARE);
+ lv_draw_dialog(DIALOG_TYPE_UPDATE_ESP_FIRMWARE);
lv_task_handler();
watchdog_refresh();
@@ -1822,5 +1821,4 @@ int readWifiBuf(int8_t *buf, int32_t len) {
return i;
}
-#endif // MKS_WIFI_MODULE
-#endif // HAS_TFT_LVGL_UI
+#endif // HAS_TFT_LVGL_UI && MKS_WIFI_MODULE
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/wifi_upload.cpp b/Marlin/src/lcd/extui/lib/mks_ui/wifi_upload.cpp
index f4412f3830..378de6d584 100644
--- a/Marlin/src/lcd/extui/lib/mks_ui/wifi_upload.cpp
+++ b/Marlin/src/lcd/extui/lib/mks_ui/wifi_upload.cpp
@@ -152,7 +152,7 @@ uint32_t getData(unsigned byteCnt, const uint8_t *buf, int ofst) {
uint32_t val = 0;
if (buf && byteCnt) {
unsigned int shiftCnt = 0;
- NOMORE(byteCnt, 4);
+ NOMORE(byteCnt, 4U);
do {
val |= (uint32_t)buf[ofst++] << shiftCnt;
shiftCnt += 8;
@@ -164,7 +164,7 @@ uint32_t getData(unsigned byteCnt, const uint8_t *buf, int ofst) {
// Put 1-4 bytes of a value in little-endian order into a buffer beginning at a specified offset.
void putData(uint32_t val, unsigned byteCnt, uint8_t *buf, int ofst) {
if (buf && byteCnt) {
- NOMORE(byteCnt, 4);
+ NOMORE(byteCnt, 4U);
do {
buf[ofst++] = (uint8_t)(val & 0xFF);
val >>= 8;
diff --git a/Marlin/src/lcd/extui/malyan_lcd.cpp b/Marlin/src/lcd/extui/malyan_lcd.cpp
index bdbf3802ab..6c55eea16d 100644
--- a/Marlin/src/lcd/extui/malyan_lcd.cpp
+++ b/Marlin/src/lcd/extui/malyan_lcd.cpp
@@ -414,8 +414,8 @@ void update_usb_status(const bool forceUpdate) {
// This is mildly different than stock, which
// appears to use the usb discovery status.
// This is more logical.
- if (last_usb_connected_status != MYSERIAL0 || forceUpdate) {
- last_usb_connected_status = MYSERIAL0;
+ if (last_usb_connected_status != MYSERIAL0.connected() || forceUpdate) {
+ last_usb_connected_status = MYSERIAL0.connected();
write_to_lcd_P(last_usb_connected_status ? PSTR("{R:UC}\r\n") : PSTR("{R:UD}\r\n"));
}
}
diff --git a/Marlin/src/lcd/extui/ui_api.cpp b/Marlin/src/lcd/extui/ui_api.cpp
index 0ff222a3ce..741be04bb2 100644
--- a/Marlin/src/lcd/extui/ui_api.cpp
+++ b/Marlin/src/lcd/extui/ui_api.cpp
@@ -123,7 +123,7 @@ namespace ExtUI {
// Machine was killed, reinit SysTick so we are able to compute time without ISRs
if (currTimeHI == 0) {
// Get the last time the Arduino time computed (from CMSIS) and convert it to SysTick
- currTimeHI = (uint32_t)((GetTickCount() * (uint64_t)(F_CPU / 8000)) >> 24);
+ currTimeHI = uint32_t((GetTickCount() * uint64_t(F_CPU / 8000)) >> 24);
// Reinit the SysTick timer to maximize its period
SysTick->LOAD = SysTick_LOAD_RELOAD_Msk; // get the full range for the systick timer
@@ -148,9 +148,9 @@ namespace ExtUI {
}
#endif // __SAM3X8E__
- void delay_us(unsigned long us) { DELAY_US(us); }
+ void delay_us(uint32_t us) { DELAY_US(us); }
- void delay_ms(unsigned long ms) {
+ void delay_ms(uint32_t ms) {
if (flags.printer_killed)
DELAY_US(ms * 1000);
else
diff --git a/Marlin/src/lcd/extui/ui_api.h b/Marlin/src/lcd/extui/ui_api.h
index edaaff0f1a..30bf06a963 100644
--- a/Marlin/src/lcd/extui/ui_api.h
+++ b/Marlin/src/lcd/extui/ui_api.h
@@ -155,7 +155,7 @@ namespace ExtUI {
void onMeshUpdate(const int8_t xpos, const int8_t ypos, const float zval);
inline void onMeshUpdate(const xy_int8_t &pos, const float zval) { onMeshUpdate(pos.x, pos.y, zval); }
- typedef enum : unsigned char {
+ typedef enum : uint8_t {
MESH_START, // Prior to start of probe
MESH_FINISH, // Following probe of all points
PROBE_START, // Beginning probe of grid location
@@ -303,8 +303,8 @@ namespace ExtUI {
FORCE_INLINE uint32_t safe_millis() { return millis(); } // TODO: Implement for AVR
#endif
- void delay_us(unsigned long us);
- void delay_ms(unsigned long ms);
+ void delay_us(uint32_t us);
+ void delay_ms(uint32_t ms);
void yield();
/**
diff --git a/Marlin/src/lcd/language/language_sv.h b/Marlin/src/lcd/language/language_sv.h
new file mode 100644
index 0000000000..722443fb21
--- /dev/null
+++ b/Marlin/src/lcd/language/language_sv.h
@@ -0,0 +1,681 @@
+/**
+ * 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 för more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+#pragma once
+
+/**
+ * Swedish
+ *
+ * LCD Menu Messages
+ * See also https://marlinfw.org/docs/development/lcd_language.html
+ */
+
+#define DISPLAY_CHARSET_ISO10646_1
+
+namespace Language_sv {
+ using namespace Language_en; // Inherit undefined strings from English
+
+ constexpr uint8_t CHARSIZE = 2;
+ PROGMEM Language_Str LANGUAGE = _UxGT("Swedish");
+
+ PROGMEM Language_Str WELCOME_MSG = MACHINE_NAME _UxGT(" Redo.");
+ PROGMEM Language_Str MSG_MARLIN = _UxGT("Marlin");
+ PROGMEM Language_Str MSG_YES = _UxGT("JA");
+ PROGMEM Language_Str MSG_NO = _UxGT("NEJ");
+ PROGMEM Language_Str MSG_BACK = _UxGT("Bakåt");
+ PROGMEM Language_Str MSG_MEDIA_ABORTING = _UxGT("Avbryter...");
+ PROGMEM Language_Str MSG_MEDIA_INSERTED = _UxGT("Media Instatt");
+ PROGMEM Language_Str MSG_MEDIA_REMOVED = _UxGT("Media Borttaget");
+ PROGMEM Language_Str MSG_MEDIA_WAITING = _UxGT("Väntar på media");
+ PROGMEM Language_Str MSG_SD_INIT_FAIL = _UxGT("SD init misslyckades");
+ PROGMEM Language_Str MSG_MEDIA_READ_ERROR = _UxGT("Media läsningsfel");
+ PROGMEM Language_Str MSG_MEDIA_USB_REMOVED = _UxGT("USB enhet borttagen");
+ PROGMEM Language_Str MSG_MEDIA_USB_FAILED = _UxGT("USB start misslyckad");
+ PROGMEM Language_Str MSG_KILL_SUBCALL_OVERFLOW = _UxGT("Underanrop överskriden");
+ PROGMEM Language_Str MSG_LCD_ENDSTOPS = _UxGT("Slutstop"); // Max length 8 characters
+ PROGMEM Language_Str MSG_LCD_SOFT_ENDSTOPS = _UxGT("Mjuk slutstopp");
+ PROGMEM Language_Str MSG_MAIN = _UxGT("Huvud");
+ PROGMEM Language_Str MSG_ADVANCED_SETTINGS = _UxGT("Advancerade inställningar");
+ PROGMEM Language_Str MSG_CONFIGURATION = _UxGT("Konfiguration");
+ PROGMEM Language_Str MSG_RUN_AUTO_FILES = _UxGT("Autostarta Filer");
+ PROGMEM Language_Str MSG_DISABLE_STEPPERS = _UxGT("Inaktivera Stegare");
+ PROGMEM Language_Str MSG_DEBUG_MENU = _UxGT("Debug Meny");
+ PROGMEM Language_Str MSG_PROGRESS_BAR_TEST = _UxGT("Framstegsindikator Test");
+ PROGMEM Language_Str MSG_AUTO_HOME = _UxGT("Auto Hem");
+ PROGMEM Language_Str MSG_AUTO_HOME_X = _UxGT("Hem X");
+ PROGMEM Language_Str MSG_AUTO_HOME_Y = _UxGT("Hem Y");
+ PROGMEM Language_Str MSG_AUTO_HOME_Z = _UxGT("Hem Z");
+ PROGMEM Language_Str MSG_AUTO_Z_ALIGN = _UxGT("Auto Z-Justering");
+ PROGMEM Language_Str MSG_ITERATION = _UxGT("G34 Iteration: %i");
+ PROGMEM Language_Str MSG_DECREASING_ACCURACY = _UxGT("Noggrannhet Minskar!");
+ PROGMEM Language_Str MSG_ACCURACY_ACHIEVED = _UxGT("Noggrannhet uppnådd");
+ PROGMEM Language_Str MSG_LEVEL_BED_HOMING = _UxGT("Hemning XYZ");
+ PROGMEM Language_Str MSG_LEVEL_BED_WAITING = _UxGT("Klicka för att börja");
+ PROGMEM Language_Str MSG_LEVEL_BED_NEXT_POINT = _UxGT("Nästa Punkt");
+ PROGMEM Language_Str MSG_LEVEL_BED_DONE = _UxGT("Nivellering Färdig!");
+ PROGMEM Language_Str MSG_Z_FADE_HEIGHT = _UxGT("Falna Höjd");
+ PROGMEM Language_Str MSG_SET_HOME_OFFSETS = _UxGT("Sätt Hem Offset");
+ PROGMEM Language_Str MSG_HOME_OFFSETS_APPLIED = _UxGT("Offset Tillämpad");
+ PROGMEM Language_Str MSG_SET_ORIGIN = _UxGT("Sätt Origo");
+ PROGMEM Language_Str MSG_ASSISTED_TRAMMING = _UxGT("Assisterad justering");
+ PROGMEM Language_Str MSG_TRAMMING_WIZARD = _UxGT("Justerings Wizard");
+ PROGMEM Language_Str MSG_SELECT_ORIGIN = _UxGT("Välj Origo");
+ PROGMEM Language_Str MSG_LAST_VALUE_SP = _UxGT("Senaste värde ");
+
+ #if PREHEAT_COUNT
+ PROGMEM Language_Str MSG_PREHEAT_1 = _UxGT("Förvärmning ") PREHEAT_1_LABEL;
+ PROGMEM Language_Str MSG_PREHEAT_1_H = _UxGT("Förvärmning ") PREHEAT_1_LABEL " ~";
+ PROGMEM Language_Str MSG_PREHEAT_1_END = _UxGT("Förvärmning ") PREHEAT_1_LABEL _UxGT(" Stoppa");
+ PROGMEM Language_Str MSG_PREHEAT_1_END_E = _UxGT("Förvärmning ") PREHEAT_1_LABEL _UxGT(" Stoppa ~");
+ PROGMEM Language_Str MSG_PREHEAT_1_ALL = _UxGT("Förvärmning ") PREHEAT_1_LABEL _UxGT(" Alla");
+ PROGMEM Language_Str MSG_PREHEAT_1_BEDONLY = _UxGT("Förvärmning ") PREHEAT_1_LABEL _UxGT(" Bädd");
+ PROGMEM Language_Str MSG_PREHEAT_1_SETTINGS = _UxGT("Förvärmning ") PREHEAT_1_LABEL _UxGT(" Konf");
+
+ PROGMEM Language_Str MSG_PREHEAT_M = _UxGT("Förvärmning $");
+ PROGMEM Language_Str MSG_PREHEAT_M_H = _UxGT("Förvärmning $ ~");
+ PROGMEM Language_Str MSG_PREHEAT_M_END = _UxGT("Förvärmning $ Stoppa");
+ PROGMEM Language_Str MSG_PREHEAT_M_END_E = _UxGT("Förvärmning $ Stoppa ~");
+ PROGMEM Language_Str MSG_PREHEAT_M_ALL = _UxGT("Förvärmning $ Alla");
+ PROGMEM Language_Str MSG_PREHEAT_M_BEDONLY = _UxGT("Förvärmning $ Bädd");
+ PROGMEM Language_Str MSG_PREHEAT_M_SETTINGS = _UxGT("Förvärmning $ Donf");
+ #endif
+
+ PROGMEM Language_Str MSG_PREHEAT_CUSTOM = _UxGT("Förvärmning Anpassad");
+ PROGMEM Language_Str MSG_COOLDOWN = _UxGT("Nedkylning");
+ PROGMEM Language_Str MSG_CUTTER_FREQUENCY = _UxGT("Frekvens");
+ PROGMEM Language_Str MSG_LASER_MENU = _UxGT("Laser kontroll");
+ PROGMEM Language_Str MSG_SPINDLE_MENU = _UxGT("Spindel Kontroll");
+ PROGMEM Language_Str MSG_LASER_POWER = _UxGT("Laser Styrka");
+ PROGMEM Language_Str MSG_SPINDLE_POWER = _UxGT("Spindel Styrka");
+ PROGMEM Language_Str MSG_LASER_TOGGLE = _UxGT("Växla Laser");
+ PROGMEM Language_Str MSG_LASER_PULSE_MS = _UxGT("Test Puls ms");
+ PROGMEM Language_Str MSG_LASER_FIRE_PULSE = _UxGT("Avfyra Puls");
+ PROGMEM Language_Str MSG_SPINDLE_TOGGLE = _UxGT("Växla Spindel");
+ PROGMEM Language_Str MSG_SPINDLE_FORWARD = _UxGT("Spindel Framåt");
+ PROGMEM Language_Str MSG_SPINDLE_REVERSE = _UxGT("Spindel Bakåt");
+ PROGMEM Language_Str MSG_LASER_OFF = _UxGT("Laser Av");
+ PROGMEM Language_Str MSG_LASER_ON = _UxGT("Laser På");
+ PROGMEM Language_Str MSG_SPINDLE_OFF = _UxGT("Spindel Av");
+ PROGMEM Language_Str MSG_SPINDLE_ON = _UxGT("Spindel På");
+ PROGMEM Language_Str MSG_SWITCH_PS_ON = _UxGT("Sätt på ström");
+ PROGMEM Language_Str MSG_SWITCH_PS_OFF = _UxGT("Stäng av ström");
+ PROGMEM Language_Str MSG_EXTRUDE = _UxGT("Extrudera");
+ PROGMEM Language_Str MSG_RETRACT = _UxGT("Dra tillbaka");
+ PROGMEM Language_Str MSG_MOVE_AXIS = _UxGT("Flytta Axel");
+ PROGMEM Language_Str MSG_BED_LEVELING = _UxGT("Bädd Nivellering");
+ PROGMEM Language_Str MSG_LEVEL_BED = _UxGT("Nivellera Bädd");
+ PROGMEM Language_Str MSG_LEVEL_CORNERS = _UxGT("Nivellera Hörn");
+ PROGMEM Language_Str MSG_LEVEL_CORNERS_RAISE = _UxGT("Höj Bädd tills nästa Sond Triggad");
+ PROGMEM Language_Str MSG_LEVEL_CORNERS_IN_RANGE = _UxGT("Alla Hörn inom Tolerans. Nivellering Bädd");
+ PROGMEM Language_Str MSG_LEVEL_CORNERS_GOOD_POINTS = _UxGT("Bra Punkter: ");
+ PROGMEM Language_Str MSG_LEVEL_CORNERS_LAST_Z = _UxGT("Senaste Z: ");
+ PROGMEM Language_Str MSG_NEXT_CORNER = _UxGT("Nästa Hörn");
+ PROGMEM Language_Str MSG_MESH_EDITOR = _UxGT("Nät Redigerare");
+ PROGMEM Language_Str MSG_EDIT_MESH = _UxGT("Redigera Nät");
+ PROGMEM Language_Str MSG_EDITING_STOPPED = _UxGT("Nätredigering Stoppad");
+ PROGMEM Language_Str MSG_PROBING_MESH = _UxGT("Sonderingspunkt");
+ PROGMEM Language_Str MSG_MESH_X = _UxGT("Index X");
+ PROGMEM Language_Str MSG_MESH_Y = _UxGT("Index Y");
+ PROGMEM Language_Str MSG_MESH_EDIT_Z = _UxGT("Z Värde");
+ PROGMEM Language_Str MSG_USER_MENU = _UxGT("Anpassade Kommandon");
+ PROGMEM Language_Str MSG_M48_TEST = _UxGT("M48 Sond Test");
+ PROGMEM Language_Str MSG_M48_POINT = _UxGT("M48 Punkt");
+ PROGMEM Language_Str MSG_M48_OUT_OF_BOUNDS = _UxGT("Sond utan för gränser");
+ PROGMEM Language_Str MSG_M48_DEVIATION = _UxGT("Avvikelse");
+ PROGMEM Language_Str MSG_IDEX_MENU = _UxGT("IDEX Läge");
+ PROGMEM Language_Str MSG_OFFSETS_MENU = _UxGT("Verktygsoffset");
+ PROGMEM Language_Str MSG_IDEX_MODE_AUTOPARK = _UxGT("Auto-Parkera");
+ PROGMEM Language_Str MSG_IDEX_MODE_DUPLICATE = _UxGT("Duplicering");
+ PROGMEM Language_Str MSG_IDEX_MODE_MIRRORED_COPY = _UxGT("Speglad Kopia");
+ PROGMEM Language_Str MSG_IDEX_MODE_FULL_CTRL = _UxGT("Full Kontroll");
+ PROGMEM Language_Str MSG_IDEX_DUPE_GAP = _UxGT("Duplicera X-Avstånd");
+ PROGMEM Language_Str MSG_HOTEND_OFFSET_X = _UxGT("2:a Munstycke X");
+ PROGMEM Language_Str MSG_HOTEND_OFFSET_Y = _UxGT("2:a Munstycke Y");
+ PROGMEM Language_Str MSG_HOTEND_OFFSET_Z = _UxGT("2:a Munstycke Z");
+ PROGMEM Language_Str MSG_UBL_DOING_G29 = _UxGT("Utför G29");
+ PROGMEM Language_Str MSG_UBL_TOOLS = _UxGT("UBL Verktyg");
+ PROGMEM Language_Str MSG_UBL_LEVEL_BED = _UxGT("Enad Bädd Nivellering (UBL)");
+ PROGMEM Language_Str MSG_LCD_TILTING_MESH = _UxGT("Lutningspunkt");
+ PROGMEM Language_Str MSG_UBL_MANUAL_MESH = _UxGT("Manuellt skapa nät");
+ PROGMEM Language_Str MSG_UBL_BC_INSERT = _UxGT("Placera Shim & Mät");
+ PROGMEM Language_Str MSG_UBL_BC_INSERT2 = _UxGT("Mät");
+ PROGMEM Language_Str MSG_UBL_BC_REMOVE = _UxGT("Ta bort & Mät bädd");
+ PROGMEM Language_Str MSG_UBL_MOVING_TO_NEXT = _UxGT("Flyttar till nästa");
+ PROGMEM Language_Str MSG_UBL_ACTIVATE_MESH = _UxGT("Aktivera UBL");
+ PROGMEM Language_Str MSG_UBL_DEACTIVATE_MESH = _UxGT("Avaktivera UBL");
+ PROGMEM Language_Str MSG_UBL_SET_TEMP_BED = _UxGT("Bädd Temp");
+ PROGMEM Language_Str MSG_UBL_BED_TEMP_CUSTOM = _UxGT("Bädd Temp");
+ PROGMEM Language_Str MSG_UBL_SET_TEMP_HOTEND = _UxGT("Hetände Temp");
+ PROGMEM Language_Str MSG_UBL_HOTEND_TEMP_CUSTOM = _UxGT("Hetände Temp");
+ PROGMEM Language_Str MSG_UBL_MESH_EDIT = _UxGT("Nät Redigera");
+ PROGMEM Language_Str MSG_UBL_EDIT_CUSTOM_MESH = _UxGT("Redigera Anpassat Nät");
+ PROGMEM Language_Str MSG_UBL_FINE_TUNE_MESH = _UxGT("Finjustera Nät");
+ PROGMEM Language_Str MSG_UBL_DONE_EDITING_MESH = _UxGT("Färdig Redigera Nät");
+ PROGMEM Language_Str MSG_UBL_BUILD_CUSTOM_MESH = _UxGT("Bygg Anpassat Nät");
+ PROGMEM Language_Str MSG_UBL_BUILD_MESH_MENU = _UxGT("Bygg Nät");
+ PROGMEM Language_Str MSG_UBL_BUILD_MESH_M = _UxGT("Bygg Nät ($)");
+ PROGMEM Language_Str MSG_UBL_BUILD_COLD_MESH = _UxGT("Bygg Kallt Nät");
+ PROGMEM Language_Str MSG_UBL_MESH_HEIGHT_ADJUST = _UxGT("Justera Nät Höjd");
+ PROGMEM Language_Str MSG_UBL_MESH_HEIGHT_AMOUNT = _UxGT("Höjd Antal");
+ PROGMEM Language_Str MSG_UBL_VALIDATE_MESH_MENU = _UxGT("Validera Nät");
+ PROGMEM Language_Str MSG_UBL_VALIDATE_MESH_M = _UxGT("Validera Nät ($)");
+ PROGMEM Language_Str MSG_UBL_VALIDATE_CUSTOM_MESH = _UxGT("Validera Anpassat Nät");
+ PROGMEM Language_Str MSG_G26_HEATING_BED = _UxGT("G26 Värma Bädd");
+ PROGMEM Language_Str MSG_G26_HEATING_NOZZLE = _UxGT("G26 Värma Munstycke");
+ PROGMEM Language_Str MSG_G26_MANUAL_PRIME = _UxGT("Manuel grundning...");
+ PROGMEM Language_Str MSG_G26_FIXED_LENGTH = _UxGT("Fastlängd Grundning");
+ PROGMEM Language_Str MSG_G26_PRIME_DONE = _UxGT("Färdig Grundning");
+ PROGMEM Language_Str MSG_G26_CANCELED = _UxGT("G26 Avbruten");
+ PROGMEM Language_Str MSG_G26_LEAVING = _UxGT("Nivellera G26");
+ PROGMEM Language_Str MSG_UBL_CONTINUE_MESH = _UxGT("Fortsätt Bädd Nät");
+ PROGMEM Language_Str MSG_UBL_MESH_LEVELING = _UxGT("Nät Nivellering");
+ PROGMEM Language_Str MSG_UBL_3POINT_MESH_LEVELING = _UxGT("3-Punkts Nivellering");
+ PROGMEM Language_Str MSG_UBL_GRID_MESH_LEVELING = _UxGT("Rutnät Nivellering");
+ PROGMEM Language_Str MSG_UBL_MESH_LEVEL = _UxGT("Nivellera Nät");
+ PROGMEM Language_Str MSG_UBL_SIDE_POINTS = _UxGT("Sidopunkter");
+ PROGMEM Language_Str MSG_UBL_MAP_TYPE = _UxGT("Kart Typ");
+ PROGMEM Language_Str MSG_UBL_OUTPUT_MAP = _UxGT("Utmatning Nät Map");
+ PROGMEM Language_Str MSG_UBL_OUTPUT_MAP_HOST = _UxGT("Utmatning för Värd");
+ PROGMEM Language_Str MSG_UBL_OUTPUT_MAP_CSV = _UxGT("Utmatning för CSV");
+ PROGMEM Language_Str MSG_UBL_OUTPUT_MAP_BACKUP = _UxGT("Utanför skrivare Backup");
+ PROGMEM Language_Str MSG_UBL_INFO_UBL = _UxGT("Utmatning UBL Info");
+ PROGMEM Language_Str MSG_UBL_FILLIN_AMOUNT = _UxGT("Ifyllnad Mängd");
+ PROGMEM Language_Str MSG_UBL_MANUAL_FILLIN = _UxGT("Manuell Ifyllnad");
+ PROGMEM Language_Str MSG_UBL_SMART_FILLIN = _UxGT("Smart Ifyllnad");
+ PROGMEM Language_Str MSG_UBL_FILLIN_MESH = _UxGT("Ifyllnad Nät");
+ PROGMEM Language_Str MSG_UBL_INVALIDATE_ALL = _UxGT("Ogiltigförklara Alla");
+ PROGMEM Language_Str MSG_UBL_INVALIDATE_CLOSEST = _UxGT("Ogiltigförklara Närmast");
+ PROGMEM Language_Str MSG_UBL_FINE_TUNE_ALL = _UxGT("Finjustera Alla");
+ PROGMEM Language_Str MSG_UBL_FINE_TUNE_CLOSEST = _UxGT("Finjustera Närmast");
+ PROGMEM Language_Str MSG_UBL_STORAGE_MESH_MENU = _UxGT("Nät Lagra");
+ PROGMEM Language_Str MSG_UBL_STORAGE_SLOT = _UxGT("Minnesöppning");
+ PROGMEM Language_Str MSG_UBL_LOAD_MESH = _UxGT("Ladda Bädd Nät");
+ PROGMEM Language_Str MSG_UBL_SAVE_MESH = _UxGT("Spara Bädd Nät");
+ PROGMEM Language_Str MSG_MESH_LOADED = _UxGT("Nät %i Ladda");
+ PROGMEM Language_Str MSG_MESH_SAVED = _UxGT("Nät %i Sparad");
+ PROGMEM Language_Str MSG_UBL_NO_STORAGE = _UxGT("Ingen Lagring");
+ PROGMEM Language_Str MSG_UBL_SAVE_ERROR = _UxGT("Fel: UBL Sparad");
+ PROGMEM Language_Str MSG_UBL_RESTORE_ERROR = _UxGT("Fel: UBL Återställd");
+ PROGMEM Language_Str MSG_UBL_Z_OFFSET = _UxGT("Z-Offset: ");
+ PROGMEM Language_Str MSG_UBL_Z_OFFSET_STOPPED = _UxGT("Z-Offset Stoppad");
+ PROGMEM Language_Str MSG_UBL_STEP_BY_STEP_MENU = _UxGT("Steg-för-Steg UBL");
+ PROGMEM Language_Str MSG_UBL_1_BUILD_COLD_MESH = _UxGT("1. Bygg Kallt Nät");
+ PROGMEM Language_Str MSG_UBL_2_SMART_FILLIN = _UxGT("2. Smart Ifyllnad");
+ PROGMEM Language_Str MSG_UBL_3_VALIDATE_MESH_MENU = _UxGT("3. Validera Nät");
+ PROGMEM Language_Str MSG_UBL_4_FINE_TUNE_ALL = _UxGT("4. Finjustera Alla");
+ PROGMEM Language_Str MSG_UBL_5_VALIDATE_MESH_MENU = _UxGT("5. Validera Nät");
+ PROGMEM Language_Str MSG_UBL_6_FINE_TUNE_ALL = _UxGT("6. Finjustera Alla");
+ PROGMEM Language_Str MSG_UBL_7_SAVE_MESH = _UxGT("7. Spara Bädd Nät");
+
+ PROGMEM Language_Str MSG_LED_CONTROL = _UxGT("LED Kontroll");
+ PROGMEM Language_Str MSG_LEDS = _UxGT("Ljus");
+ PROGMEM Language_Str MSG_LED_PRESETS = _UxGT("Ljus Förinställd");
+ PROGMEM Language_Str MSG_SET_LEDS_RED = _UxGT("Röd");
+ PROGMEM Language_Str MSG_SET_LEDS_ORANGE = _UxGT("Orange");
+ PROGMEM Language_Str MSG_SET_LEDS_YELLOW = _UxGT("Gul");
+ PROGMEM Language_Str MSG_SET_LEDS_GREEN = _UxGT("Grön");
+ PROGMEM Language_Str MSG_SET_LEDS_BLUE = _UxGT("Blå");
+ PROGMEM Language_Str MSG_SET_LEDS_INDIGO = _UxGT("Indigo");
+ PROGMEM Language_Str MSG_SET_LEDS_VIOLET = _UxGT("Violet");
+ PROGMEM Language_Str MSG_SET_LEDS_WHITE = _UxGT("Vitt");
+ PROGMEM Language_Str MSG_SET_LEDS_DEFAULT = _UxGT("Standard");
+ PROGMEM Language_Str MSG_LED_CHANNEL_N = _UxGT("Kanal =");
+ PROGMEM Language_Str MSG_LEDS2 = _UxGT("Ljus #2");
+ PROGMEM Language_Str MSG_NEO2_PRESETS = _UxGT("Ljus #2 Förinställd");
+ PROGMEM Language_Str MSG_NEO2_BRIGHTNESS = _UxGT("Ljusstyrka");
+ PROGMEM Language_Str MSG_CUSTOM_LEDS = _UxGT("Anpassat Ljus");
+ PROGMEM Language_Str MSG_INTENSITY_R = _UxGT("Rör Intensitet");
+ PROGMEM Language_Str MSG_INTENSITY_G = _UxGT("Grön Intensitet");
+ PROGMEM Language_Str MSG_INTENSITY_B = _UxGT("Blå Intensitet");
+ PROGMEM Language_Str MSG_INTENSITY_W = _UxGT("Vit Intensitet");
+ PROGMEM Language_Str MSG_LED_BRIGHTNESS = _UxGT("Brightness");
+
+ PROGMEM Language_Str MSG_MOVING = _UxGT("Flyttar...");
+ PROGMEM Language_Str MSG_FREE_XY = _UxGT("Fri XY");
+ PROGMEM Language_Str MSG_MOVE_X = _UxGT("Flytta X");
+ PROGMEM Language_Str MSG_MOVE_Y = _UxGT("Flytta Y");
+ PROGMEM Language_Str MSG_MOVE_Z = _UxGT("Flytta Z");
+ PROGMEM Language_Str MSG_MOVE_E = _UxGT("Extruder");
+ PROGMEM Language_Str MSG_MOVE_EN = _UxGT("Extruder *");
+ PROGMEM Language_Str MSG_HOTEND_TOO_COLD = _UxGT("Hetände för kall");
+ PROGMEM Language_Str MSG_MOVE_N_MM = _UxGT("Flytta %smm");
+ PROGMEM Language_Str MSG_MOVE_01MM = _UxGT("Flytta 0.1mm");
+ PROGMEM Language_Str MSG_MOVE_1MM = _UxGT("Flytta 1mm");
+ PROGMEM Language_Str MSG_MOVE_10MM = _UxGT("Flytta 10mm");
+ PROGMEM Language_Str MSG_MOVE_0001IN = _UxGT("Flytta 0.001tum");
+ PROGMEM Language_Str MSG_MOVE_001IN = _UxGT("Flytta 0.01tum");
+ PROGMEM Language_Str MSG_MOVE_01IN = _UxGT("Flytta 0.1tum");
+ PROGMEM Language_Str MSG_SPEED = _UxGT("Hastighet");
+ PROGMEM Language_Str MSG_BED_Z = _UxGT("Bädd Z");
+ PROGMEM Language_Str MSG_NOZZLE = _UxGT("Munstycke");
+ PROGMEM Language_Str MSG_NOZZLE_N = _UxGT("Munstycke ~");
+ PROGMEM Language_Str MSG_NOZZLE_PARKED = _UxGT("Munstycke Parkerad");
+ PROGMEM Language_Str MSG_NOZZLE_STANDBY = _UxGT("Munstycke Standby");
+ PROGMEM Language_Str MSG_BED = _UxGT("Bädd");
+ PROGMEM Language_Str MSG_CHAMBER = _UxGT("Inkapsling");
+ PROGMEM Language_Str MSG_FAN_SPEED = _UxGT("Fläkt Hastighet");
+ PROGMEM Language_Str MSG_FAN_SPEED_N = _UxGT("Fläkt Hastighet ~");
+ PROGMEM Language_Str MSG_STORED_FAN_N = _UxGT("Lagrad Fläkt ~");
+ PROGMEM Language_Str MSG_EXTRA_FAN_SPEED = _UxGT("Extra Fläkt Hastighet");
+ PROGMEM Language_Str MSG_EXTRA_FAN_SPEED_N = _UxGT("Extra Fläkt Hastighet ~");
+ PROGMEM Language_Str MSG_CONTROLLER_FAN = _UxGT("Kontroller Fläkt");
+ PROGMEM Language_Str MSG_CONTROLLER_FAN_IDLE_SPEED = _UxGT("Overksam Hastighet");
+ PROGMEM Language_Str MSG_CONTROLLER_FAN_AUTO_ON = _UxGT("Auto läga");
+ PROGMEM Language_Str MSG_CONTROLLER_FAN_SPEED = _UxGT("Aktive Hastighet");
+ PROGMEM Language_Str MSG_CONTROLLER_FAN_DURATION = _UxGT("Overksam Period");
+ PROGMEM Language_Str MSG_FLOW = _UxGT("Flöde");
+ PROGMEM Language_Str MSG_FLOW_N = _UxGT("Flöde ~");
+ PROGMEM Language_Str MSG_CONTROL = _UxGT("Kontroll");
+ PROGMEM Language_Str MSG_MIN = " " LCD_STR_THERMOMETER _UxGT(" Min");
+ PROGMEM Language_Str MSG_MAX = " " LCD_STR_THERMOMETER _UxGT(" Max");
+ PROGMEM Language_Str MSG_FACTOR = " " LCD_STR_THERMOMETER _UxGT(" Fakt");
+ PROGMEM Language_Str MSG_AUTOTEMP = _UxGT("Autotemp");
+ PROGMEM Language_Str MSG_LCD_ON = _UxGT("På");
+ PROGMEM Language_Str MSG_LCD_OFF = _UxGT("Av");
+ PROGMEM Language_Str MSG_PID_AUTOTUNE = _UxGT("PID Autojustera");
+ PROGMEM Language_Str MSG_PID_AUTOTUNE_E = _UxGT("PID Autojustera *");
+ PROGMEM Language_Str MSG_PID_AUTOTUNE_DONE = _UxGT("PID tuning done");
+ PROGMEM Language_Str MSG_PID_BAD_EXTRUDER_NUM = _UxGT("Autojustera misslyckad. Dålig extruder.");
+ PROGMEM Language_Str MSG_PID_TEMP_TOO_HIGH = _UxGT("Autojustera misslyckad. Temperatur för hög.");
+ PROGMEM Language_Str MSG_PID_TIMEOUT = _UxGT("Autojustera misslyckad! Tidsgräns.");
+ PROGMEM Language_Str MSG_SELECT = _UxGT("Välj");
+ PROGMEM Language_Str MSG_SELECT_E = _UxGT("Välj *");
+ PROGMEM Language_Str MSG_ACC = _UxGT("Accel");
+ PROGMEM Language_Str MSG_JERK = _UxGT("Ryck");
+ PROGMEM Language_Str MSG_VA_JERK = _UxGT("V") LCD_STR_A _UxGT("-Ryck");
+ PROGMEM Language_Str MSG_VB_JERK = _UxGT("V") LCD_STR_B _UxGT("-Ryck");
+ PROGMEM Language_Str MSG_VC_JERK = _UxGT("V") LCD_STR_C _UxGT("-Ryck");
+ PROGMEM Language_Str MSG_VE_JERK = _UxGT("Ve-Ryck");
+ PROGMEM Language_Str MSG_JUNCTION_DEVIATION = _UxGT("Knutpunkt Avv");
+ PROGMEM Language_Str MSG_VELOCITY = _UxGT("Hastighet");
+ PROGMEM Language_Str MSG_VMAX_A = _UxGT("Vmax ") LCD_STR_A;
+ PROGMEM Language_Str MSG_VMAX_B = _UxGT("Vmax ") LCD_STR_B;
+ PROGMEM Language_Str MSG_VMAX_C = _UxGT("Vmax ") LCD_STR_C;
+ PROGMEM Language_Str MSG_VMAX_E = _UxGT("Vmax ") LCD_STR_E;
+ PROGMEM Language_Str MSG_VMAX_EN = _UxGT("Vmax *");
+ PROGMEM Language_Str MSG_VMIN = _UxGT("Vmin");
+ PROGMEM Language_Str MSG_VTRAV_MIN = _UxGT("VTrav Min");
+ PROGMEM Language_Str MSG_ACCELERATION = _UxGT("Acceleration");
+ PROGMEM Language_Str MSG_AMAX_A = _UxGT("Amax ") LCD_STR_A;
+ PROGMEM Language_Str MSG_AMAX_B = _UxGT("Amax ") LCD_STR_B;
+ PROGMEM Language_Str MSG_AMAX_C = _UxGT("Amax ") LCD_STR_C;
+ PROGMEM Language_Str MSG_AMAX_E = _UxGT("Amax ") LCD_STR_E;
+ PROGMEM Language_Str MSG_AMAX_EN = _UxGT("Amax *");
+ PROGMEM Language_Str MSG_A_RETRACT = _UxGT("A-Dra tillbaka");
+ PROGMEM Language_Str MSG_A_TRAVEL = _UxGT("A-Färdas");
+ PROGMEM Language_Str MSG_XY_FREQUENCY_LIMIT = _UxGT("Frekvens max");
+ PROGMEM Language_Str MSG_XY_FREQUENCY_FEEDRATE = _UxGT("Flöde min");
+ PROGMEM Language_Str MSG_STEPS_PER_MM = _UxGT("Steg/mm");
+ PROGMEM Language_Str MSG_A_STEPS = LCD_STR_A _UxGT(" Steg/mm");
+ PROGMEM Language_Str MSG_B_STEPS = LCD_STR_B _UxGT(" Steg/mm");
+ PROGMEM Language_Str MSG_C_STEPS = LCD_STR_C _UxGT(" Steg/mm");
+ PROGMEM Language_Str MSG_E_STEPS = _UxGT("E Steg/mm");
+ PROGMEM Language_Str MSG_EN_STEPS = _UxGT("* Steg/mm");
+ PROGMEM Language_Str MSG_TEMPERATURE = _UxGT("Temperatur");
+ PROGMEM Language_Str MSG_MOTION = _UxGT("Rörelse");
+ PROGMEM Language_Str MSG_FILAMENT = _UxGT("Tråd");
+ PROGMEM Language_Str MSG_VOLUMETRIC_ENABLED = _UxGT("E i mm³");
+ PROGMEM Language_Str MSG_VOLUMETRIC_LIMIT = _UxGT("E Gräns i mm³");
+ PROGMEM Language_Str MSG_VOLUMETRIC_LIMIT_E = _UxGT("E Gräns *");
+ PROGMEM Language_Str MSG_FILAMENT_DIAM = _UxGT("Tråd Dia.");
+ PROGMEM Language_Str MSG_FILAMENT_DIAM_E = _UxGT("Tråd Dia. *");
+ PROGMEM Language_Str MSG_FILAMENT_UNLOAD = _UxGT("Lossa mm");
+ PROGMEM Language_Str MSG_FILAMENT_LOAD = _UxGT("Ladda mm");
+ PROGMEM Language_Str MSG_ADVANCE_K = _UxGT("Advancera K");
+ PROGMEM Language_Str MSG_ADVANCE_K_E = _UxGT("Advancera K *");
+ PROGMEM Language_Str MSG_CONTRAST = _UxGT("LCD Kontrast");
+ PROGMEM Language_Str MSG_STORE_EEPROM = _UxGT("Spara Inställningar");
+ PROGMEM Language_Str MSG_LOAD_EEPROM = _UxGT("Ladda Inställningar");
+ PROGMEM Language_Str MSG_RESTORE_DEFAULTS = _UxGT("Återställ Standard");
+ PROGMEM Language_Str MSG_INIT_EEPROM = _UxGT("Initiera EEPROM");
+ PROGMEM Language_Str MSG_ERR_EEPROM_CRC = _UxGT("EEPROM CRC Fel");
+ PROGMEM Language_Str MSG_ERR_EEPROM_INDEX = _UxGT("EEPROM Index Fel");
+ PROGMEM Language_Str MSG_ERR_EEPROM_VERSION = _UxGT("EEPROM Version Fel");
+ PROGMEM Language_Str MSG_SETTINGS_STORED = _UxGT("Inställningar Lagrad");
+ PROGMEM Language_Str MSG_MEDIA_UPDATE = _UxGT("Media Uppdatera");
+ PROGMEM Language_Str MSG_RESET_PRINTER = _UxGT("Återställ Skrivare");
+ PROGMEM Language_Str MSG_REFRESH = LCD_STR_REFRESH _UxGT("Uppdatera");
+ PROGMEM Language_Str MSG_INFO_SCREEN = _UxGT("Info Skärm");
+ PROGMEM Language_Str MSG_PREPARE = _UxGT("Förbered");
+ PROGMEM Language_Str MSG_TUNE = _UxGT("Justera");
+ PROGMEM Language_Str MSG_POWER_MONITOR = _UxGT("Ström övervakning");
+ PROGMEM Language_Str MSG_CURRENT = _UxGT("Ström");
+ PROGMEM Language_Str MSG_VOLTAGE = _UxGT("Spänning");
+ PROGMEM Language_Str MSG_POWER = _UxGT("Ström");
+ PROGMEM Language_Str MSG_START_PRINT = _UxGT("Start Utskrift");
+ PROGMEM Language_Str MSG_BUTTON_NEXT = _UxGT("Nästa");
+ PROGMEM Language_Str MSG_BUTTON_INIT = _UxGT("Initiera");
+ PROGMEM Language_Str MSG_BUTTON_STOP = _UxGT("Stoppa");
+ PROGMEM Language_Str MSG_BUTTON_PRINT = _UxGT("Skriv");
+ PROGMEM Language_Str MSG_BUTTON_RESET = _UxGT("Återställa");
+ PROGMEM Language_Str MSG_BUTTON_IGNORE = _UxGT("Ignorera");
+ PROGMEM Language_Str MSG_BUTTON_CANCEL = _UxGT("Avbryt");
+ PROGMEM Language_Str MSG_BUTTON_DONE = _UxGT("Färdig");
+ PROGMEM Language_Str MSG_BUTTON_BACK = _UxGT("Bakåt");
+ PROGMEM Language_Str MSG_BUTTON_PROCEED = _UxGT("Fortsätt");
+ PROGMEM Language_Str MSG_BUTTON_SKIP = _UxGT("Hoppa över");
+ PROGMEM Language_Str MSG_PAUSING = _UxGT("Paus..");
+ PROGMEM Language_Str MSG_PAUSE_PRINT = _UxGT("Pausera Utskrift");
+ PROGMEM Language_Str MSG_RESUME_PRINT = _UxGT("Återuppta Utskrift");
+ PROGMEM Language_Str MSG_HOST_START_PRINT = _UxGT("Värd Start");
+ PROGMEM Language_Str MSG_STOP_PRINT = _UxGT("Stoppa Utskrift");
+ PROGMEM Language_Str MSG_END_LOOPS = _UxGT("Slut Upprepningsloop");
+ PROGMEM Language_Str MSG_PRINTING_OBJECT = _UxGT("Skriver Objekt");
+ PROGMEM Language_Str MSG_CANCEL_OBJECT = _UxGT("Avbryt Objekt");
+ PROGMEM Language_Str MSG_CANCEL_OBJECT_N = _UxGT("Avbryt Objekt =");
+ PROGMEM Language_Str MSG_OUTAGE_RECOVERY = _UxGT("Ström Avbrott");
+ PROGMEM Language_Str MSG_MEDIA_MENU = _UxGT("Skriv fråm Media");
+ PROGMEM Language_Str MSG_NO_MEDIA = _UxGT("Inget Media");
+ PROGMEM Language_Str MSG_DWELL = _UxGT("Sov...");
+ PROGMEM Language_Str MSG_USERWAIT = _UxGT("Klick för att återuppta...");
+ PROGMEM Language_Str MSG_PRINT_PAUSED = _UxGT("Utskrift Pausad");
+ PROGMEM Language_Str MSG_PRINTING = _UxGT("Skriver...");
+ PROGMEM Language_Str MSG_PRINT_ABORTED = _UxGT("Utskrift Avbruten");
+ PROGMEM Language_Str MSG_PRINT_DONE = _UxGT("Utskrift Färdig");
+ PROGMEM Language_Str MSG_NO_MOVE = _UxGT("Ingen Flytt.");
+ PROGMEM Language_Str MSG_KILLED = _UxGT("DÖDAD. ");
+ PROGMEM Language_Str MSG_STOPPED = _UxGT("STOPPAD. ");
+ PROGMEM Language_Str MSG_CONTROL_RETRACT = _UxGT("Dra tillbaka mm");
+ PROGMEM Language_Str MSG_CONTROL_RETRACT_SWAP = _UxGT("Byt Dra.mm");
+ PROGMEM Language_Str MSG_CONTROL_RETRACTF = _UxGT("Dra tillbaka V");
+ PROGMEM Language_Str MSG_CONTROL_RETRACT_ZHOP = _UxGT("Hoppa mm");
+ PROGMEM Language_Str MSG_CONTROL_RETRACT_RECOVER = _UxGT("Åter dra tillbaka. mm");
+ PROGMEM Language_Str MSG_CONTROL_RETRACT_RECOVER_SWAP = _UxGT("Byt åter dra t. mm");
+ PROGMEM Language_Str MSG_CONTROL_RETRACT_RECOVERF = _UxGT("Återdrat. V");
+ PROGMEM Language_Str MSG_CONTROL_RETRACT_RECOVER_SWAPF = _UxGT("Byt åter dra. V");
+ PROGMEM Language_Str MSG_AUTORETRACT = _UxGT("Auto-Dra-tillbka");
+ PROGMEM Language_Str MSG_FILAMENT_SWAP_LENGTH = _UxGT("Byt Längd");
+ PROGMEM Language_Str MSG_FILAMENT_SWAP_EXTRA = _UxGT("Byt Extra");
+ PROGMEM Language_Str MSG_FILAMENT_PURGE_LENGTH = _UxGT("Rensa Längd");
+ PROGMEM Language_Str MSG_TOOL_CHANGE = _UxGT("Byt verktyg");
+ PROGMEM Language_Str MSG_TOOL_CHANGE_ZLIFT = _UxGT("Z Höj");
+ PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPEED = _UxGT("Grund Hastighet");
+ PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPEED = _UxGT("Återgå Hastighet");
+ PROGMEM Language_Str MSG_FILAMENT_PARK_ENABLED = _UxGT("Parkera Huvud");
+ PROGMEM Language_Str MSG_SINGLENOZZLE_UNRETRACT_SPEED = _UxGT("Återgår Hastighet");
+ PROGMEM Language_Str MSG_SINGLENOZZLE_FAN_SPEED = _UxGT("Fläkt Hastighet");
+ PROGMEM Language_Str MSG_SINGLENOZZLE_FAN_TIME = _UxGT("Fläkt Tid");
+ PROGMEM Language_Str MSG_TOOL_MIGRATION_ON = _UxGT("Auto PÅ");
+ PROGMEM Language_Str MSG_TOOL_MIGRATION_OFF = _UxGT("Auto AV");
+ PROGMEM Language_Str MSG_TOOL_MIGRATION = _UxGT("Verktyg Migration");
+ PROGMEM Language_Str MSG_TOOL_MIGRATION_AUTO = _UxGT("Auto-migration");
+ PROGMEM Language_Str MSG_TOOL_MIGRATION_END = _UxGT("Senast Extruder");
+ PROGMEM Language_Str MSG_TOOL_MIGRATION_SWAP = _UxGT("Migrera till *");
+ PROGMEM Language_Str MSG_FILAMENTCHANGE = _UxGT("Byt Tråd");
+ PROGMEM Language_Str MSG_FILAMENTCHANGE_E = _UxGT("Byt Tråd *");
+ PROGMEM Language_Str MSG_FILAMENTLOAD = _UxGT("Ladda Tråd");
+ PROGMEM Language_Str MSG_FILAMENTLOAD_E = _UxGT("Ladda *");
+ PROGMEM Language_Str MSG_FILAMENTUNLOAD = _UxGT("Lossa Tråd");
+ PROGMEM Language_Str MSG_FILAMENTUNLOAD_E = _UxGT("Lossa *");
+ PROGMEM Language_Str MSG_FILAMENTUNLOAD_ALL = _UxGT("Lossa All");
+ PROGMEM Language_Str MSG_ATTACH_MEDIA = _UxGT("Bifoga Media");
+ PROGMEM Language_Str MSG_CHANGE_MEDIA = _UxGT("Byt Media");
+ PROGMEM Language_Str MSG_RELEASE_MEDIA = _UxGT("Släpp Media");
+ PROGMEM Language_Str MSG_ZPROBE_OUT = _UxGT("Z Sond Utanför Bädd");
+ PROGMEM Language_Str MSG_SKEW_FACTOR = _UxGT("Skev Faktor");
+ PROGMEM Language_Str MSG_BLTOUCH = _UxGT("BLTouch");
+ PROGMEM Language_Str MSG_BLTOUCH_SELFTEST = _UxGT("Själv-Test");
+ PROGMEM Language_Str MSG_BLTOUCH_RESET = _UxGT("Återställ");
+ PROGMEM Language_Str MSG_BLTOUCH_STOW = _UxGT("Stuva undan");
+ PROGMEM Language_Str MSG_BLTOUCH_DEPLOY = _UxGT("Fällut");
+ PROGMEM Language_Str MSG_BLTOUCH_SW_MODE = _UxGT("SW-Läge");
+ PROGMEM Language_Str MSG_BLTOUCH_5V_MODE = _UxGT("5V-Läge");
+ PROGMEM Language_Str MSG_BLTOUCH_OD_MODE = _UxGT("OD-Läge");
+ PROGMEM Language_Str MSG_BLTOUCH_MODE_STORE = _UxGT("Läge-Lägring");
+ PROGMEM Language_Str MSG_BLTOUCH_MODE_STORE_5V = _UxGT("Sätt BLTouch to 5V");
+ PROGMEM Language_Str MSG_BLTOUCH_MODE_STORE_OD = _UxGT("Sätt BLTouch to OD");
+ PROGMEM Language_Str MSG_BLTOUCH_MODE_ECHO = _UxGT("Reportera Dränering");
+ PROGMEM Language_Str MSG_BLTOUCH_MODE_CHANGE = _UxGT("FARA: Dålig inställningar kan orsaka skada! Fortsätt ändå?");
+ PROGMEM Language_Str MSG_TOUCHMI_PROBE = _UxGT("TouchMI");
+ PROGMEM Language_Str MSG_TOUCHMI_INIT = _UxGT("Initiera TouchMI");
+ PROGMEM Language_Str MSG_TOUCHMI_ZTEST = _UxGT("Z Offset Test");
+ PROGMEM Language_Str MSG_TOUCHMI_SAVE = _UxGT("Spara");
+ PROGMEM Language_Str MSG_MANUAL_DEPLOY_TOUCHMI = _UxGT("Fällut TouchMI");
+ PROGMEM Language_Str MSG_MANUAL_DEPLOY = _UxGT("Fällut Z-Sond");
+ PROGMEM Language_Str MSG_MANUAL_STOW = _UxGT("Stuva undan Z-Sond");
+ PROGMEM Language_Str MSG_HOME_FIRST = _UxGT("Hem %s%s%s Först");
+ PROGMEM Language_Str MSG_ZPROBE_OFFSETS = _UxGT("Sond Offsets");
+ PROGMEM Language_Str MSG_ZPROBE_XOFFSET = _UxGT("Sond X Offset");
+ PROGMEM Language_Str MSG_ZPROBE_YOFFSET = _UxGT("Sond Y Offset");
+ PROGMEM Language_Str MSG_ZPROBE_ZOFFSET = _UxGT("Sond Z Offset");
+ PROGMEM Language_Str MSG_MOVE_NOZZLE_TO_BED = _UxGT("Flytta Munstycke till Bädd");
+ PROGMEM Language_Str MSG_BABYSTEP_X = _UxGT("Småsteg X");
+ PROGMEM Language_Str MSG_BABYSTEP_Y = _UxGT("Småsteg Y");
+ PROGMEM Language_Str MSG_BABYSTEP_Z = _UxGT("Småsteg Z");
+ PROGMEM Language_Str MSG_BABYSTEP_TOTAL = _UxGT("Total");
+ PROGMEM Language_Str MSG_ENDSTOP_ABORT = _UxGT("Slutstopp Avbrott");
+ PROGMEM Language_Str MSG_HEATING_FAILED_LCD = _UxGT("Värma Misslyckad");
+ PROGMEM Language_Str MSG_ERR_REDUNDANT_TEMP = _UxGT("Fel: REDUNDANT TEMP");
+ PROGMEM Language_Str MSG_THERMAL_RUNAWAY = _UxGT("TERMISK ÖVERDRIFT");
+ PROGMEM Language_Str MSG_THERMAL_RUNAWAY_BED = _UxGT("BÄDD TERMISK ÖVERDRIFT");
+ PROGMEM Language_Str MSG_THERMAL_RUNAWAY_CHAMBER = _UxGT("KAMMARE T. ÖVERDRIFT");
+ PROGMEM Language_Str MSG_ERR_MAXTEMP = _UxGT("Fel: MAXTEMP");
+ PROGMEM Language_Str MSG_ERR_MINTEMP = _UxGT("Fel: MINTEMP");
+ PROGMEM Language_Str MSG_HALTED = _UxGT("Utskrift stoppad");
+ PROGMEM Language_Str MSG_PLEASE_RESET = _UxGT("Snälla Återställ");
+ PROGMEM Language_Str MSG_SHORT_DAY = _UxGT("d"); // One character only
+ PROGMEM Language_Str MSG_SHORT_HOUR = _UxGT("t"); // One character only
+ PROGMEM Language_Str MSG_SHORT_MINUTE = _UxGT("m"); // One character only
+ PROGMEM Language_Str MSG_HEATING = _UxGT("Värmer...");
+ PROGMEM Language_Str MSG_COOLING = _UxGT("Kyler...");
+ PROGMEM Language_Str MSG_BED_HEATING = _UxGT("Bädd Värmer...");
+ PROGMEM Language_Str MSG_BED_COOLING = _UxGT("Bädd Kyler...");
+ PROGMEM Language_Str MSG_PROBE_HEATING = _UxGT("Sond Värmer...");
+ PROGMEM Language_Str MSG_PROBE_COOLING = _UxGT("Sond Kyler...");
+ PROGMEM Language_Str MSG_CHAMBER_HEATING = _UxGT("Kammare Värmer...");
+ PROGMEM Language_Str MSG_CHAMBER_COOLING = _UxGT("Kammare Kyler...");
+ PROGMEM Language_Str MSG_DELTA_CALIBRATE = _UxGT("Delta Kalibrering");
+ PROGMEM Language_Str MSG_DELTA_CALIBRATE_X = _UxGT("Kalibrera X");
+ PROGMEM Language_Str MSG_DELTA_CALIBRATE_Y = _UxGT("Kalibrera Y");
+ PROGMEM Language_Str MSG_DELTA_CALIBRATE_Z = _UxGT("Kalibrera Z");
+ PROGMEM Language_Str MSG_DELTA_CALIBRATE_CENTER = _UxGT("Kalibrera Center");
+ PROGMEM Language_Str MSG_DELTA_SETTINGS = _UxGT("Delta Inställningar");
+ PROGMEM Language_Str MSG_DELTA_AUTO_CALIBRATE = _UxGT("Auto Kalibrering");
+ PROGMEM Language_Str MSG_DELTA_HEIGHT_CALIBRATE = _UxGT("Sätt Delta Höjd");
+ PROGMEM Language_Str MSG_DELTA_Z_OFFSET_CALIBRATE = _UxGT("Sond Z-offset");
+ PROGMEM Language_Str MSG_DELTA_DIAG_ROD = _UxGT("Diag Rod");
+ PROGMEM Language_Str MSG_DELTA_HEIGHT = _UxGT("Höjd");
+ PROGMEM Language_Str MSG_DELTA_RADIUS = _UxGT("Radius");
+ PROGMEM Language_Str MSG_INFO_MENU = _UxGT("Om Skrivaren");
+ PROGMEM Language_Str MSG_INFO_PRINTER_MENU = _UxGT("Skrivare Info");
+ PROGMEM Language_Str MSG_3POINT_LEVELING = _UxGT("3-Punkt Nivellering");
+ PROGMEM Language_Str MSG_LINEAR_LEVELING = _UxGT("Linjär Nivellering");
+ PROGMEM Language_Str MSG_BILINEAR_LEVELING = _UxGT("Bilinjär Nivellering");
+ PROGMEM Language_Str MSG_UBL_LEVELING = _UxGT("Enhetlig Bädd Nivellering (UBL)");
+ PROGMEM Language_Str MSG_MESH_LEVELING = _UxGT("Nät Nivellering");
+ PROGMEM Language_Str MSG_INFO_STATS_MENU = _UxGT("Skrivar Stats");
+ PROGMEM Language_Str MSG_INFO_BOARD_MENU = _UxGT("Kort Info");
+ PROGMEM Language_Str MSG_INFO_THERMISTOR_MENU = _UxGT("Termistor");
+ PROGMEM Language_Str MSG_INFO_EXTRUDERS = _UxGT("Extruderare");
+ PROGMEM Language_Str MSG_INFO_BAUDRATE = _UxGT("Baud");
+ PROGMEM Language_Str MSG_INFO_PROTOCOL = _UxGT("Protokoll");
+ PROGMEM Language_Str MSG_INFO_RUNAWAY_OFF = _UxGT("Överdrift Övervakning: AV");
+ PROGMEM Language_Str MSG_INFO_RUNAWAY_ON = _UxGT("Överdrift Övervakning: PÅ");
+ PROGMEM Language_Str MSG_HOTEND_IDLE_TIMEOUT = _UxGT("Hetände Overksam Tidsgräns");
+
+ PROGMEM Language_Str MSG_CASE_LIGHT = _UxGT("Lådljus");
+ PROGMEM Language_Str MSG_CASE_LIGHT_BRIGHTNESS = _UxGT("Ljus ljusstyrka");
+ PROGMEM Language_Str MSG_KILL_EXPECTED_PRINTER = _UxGT("INKORREKT SKRIVARE");
+
+ #if LCD_WIDTH >= 20
+ PROGMEM Language_Str MSG_INFO_PRINT_COUNT = _UxGT("Utskriftsantal");
+ PROGMEM Language_Str MSG_INFO_COMPLETED_PRINTS = _UxGT("Färdiga");
+ PROGMEM Language_Str MSG_INFO_PRINT_TIME = _UxGT("Total Utskriftstid");
+ PROGMEM Language_Str MSG_INFO_PRINT_LONGEST = _UxGT("Längsta Jobbtid");
+ PROGMEM Language_Str MSG_INFO_PRINT_FILAMENT = _UxGT("Extruderade Totalt");
+ #else
+ PROGMEM Language_Str MSG_INFO_PRINT_COUNT = _UxGT("Utskrift");
+ PROGMEM Language_Str MSG_INFO_COMPLETED_PRINTS = _UxGT("Färdig");
+ PROGMEM Language_Str MSG_INFO_PRINT_TIME = _UxGT("Total");
+ PROGMEM Language_Str MSG_INFO_PRINT_LONGEST = _UxGT("Längsta");
+ PROGMEM Language_Str MSG_INFO_PRINT_FILAMENT = _UxGT("Extruderad");
+ #endif
+
+ PROGMEM Language_Str MSG_INFO_MIN_TEMP = _UxGT("Min Temp");
+ PROGMEM Language_Str MSG_INFO_MAX_TEMP = _UxGT("Max Temp");
+ PROGMEM Language_Str MSG_INFO_PSU = _UxGT("PSU");
+ PROGMEM Language_Str MSG_DRIVE_STRENGTH = _UxGT("Driv Styrka");
+ PROGMEM Language_Str MSG_DAC_PERCENT_X = _UxGT("X Driver %");
+ PROGMEM Language_Str MSG_DAC_PERCENT_Y = _UxGT("Y Driver %");
+ PROGMEM Language_Str MSG_DAC_PERCENT_Z = _UxGT("Z Driver %");
+ PROGMEM Language_Str MSG_DAC_PERCENT_E = _UxGT("E Driver %");
+ PROGMEM Language_Str MSG_ERROR_TMC = _UxGT("TMC KOPPLNINGSFEL");
+ PROGMEM Language_Str MSG_DAC_EEPROM_WRITE = _UxGT("DAC EEPROM Skriv");
+ PROGMEM Language_Str MSG_FILAMENT_CHANGE_HEADER = _UxGT("TRÅDBYTE");
+ PROGMEM Language_Str MSG_FILAMENT_CHANGE_HEADER_PAUSE = _UxGT("UTSKRIFTSPAUSERAD");
+ PROGMEM Language_Str MSG_FILAMENT_CHANGE_HEADER_LOAD = _UxGT("LADDA TRÅD");
+ PROGMEM Language_Str MSG_FILAMENT_CHANGE_HEADER_UNLOAD = _UxGT("LOSSA TRÅD");
+ PROGMEM Language_Str MSG_FILAMENT_CHANGE_OPTION_HEADER = _UxGT("ÅTERGÅ VAÖ:");
+ PROGMEM Language_Str MSG_FILAMENT_CHANGE_OPTION_PURGE = _UxGT("Rensa mer");
+ PROGMEM Language_Str MSG_FILAMENT_CHANGE_OPTION_RESUME = _UxGT("Fortsätt");
+ PROGMEM Language_Str MSG_FILAMENT_CHANGE_NOZZLE = _UxGT(" Munstycke: ");
+ PROGMEM Language_Str MSG_RUNOUT_SENSOR = _UxGT("Utskjut Sensor");
+ PROGMEM Language_Str MSG_RUNOUT_DISTANCE_MM = _UxGT("Utskjut Dist mm");
+ PROGMEM Language_Str MSG_KILL_HOMING_FAILED = _UxGT("Hemning Misslyckad");
+ PROGMEM Language_Str MSG_LCD_PROBING_FAILED = _UxGT("Sondering Misslyckad");
+
+ PROGMEM Language_Str MSG_MMU2_CHOOSE_FILAMENT_HEADER = _UxGT("VÄLJ TRÅD");
+ PROGMEM Language_Str MSG_MMU2_MENU = _UxGT("MMU");
+ PROGMEM Language_Str MSG_KILL_MMU2_FIRMWARE = _UxGT("Uppdatera MMU Firmware!");
+ PROGMEM Language_Str MSG_MMU2_NOT_RESPONDING = _UxGT("MMU Behöver uppmärksamhet.");
+ PROGMEM Language_Str MSG_MMU2_RESUME = _UxGT("MMU Återuppta");
+ PROGMEM Language_Str MSG_MMU2_RESUMING = _UxGT("MMU Återupptas...");
+ PROGMEM Language_Str MSG_MMU2_LOAD_FILAMENT = _UxGT("MMU Ladda");
+ PROGMEM Language_Str MSG_MMU2_LOAD_ALL = _UxGT("MMU Ladda Alla");
+ PROGMEM Language_Str MSG_MMU2_LOAD_TO_NOZZLE = _UxGT("MMU Ladda till Munstycke");
+ PROGMEM Language_Str MSG_MMU2_EJECT_FILAMENT = _UxGT("MMU Mata ut");
+ PROGMEM Language_Str MSG_MMU2_EJECT_FILAMENT_N = _UxGT("MMU Mata ut ~");
+ PROGMEM Language_Str MSG_MMU2_UNLOAD_FILAMENT = _UxGT("MMU Lossa");
+ PROGMEM Language_Str MSG_MMU2_LOADING_FILAMENT = _UxGT("Ladda Tråd %i...");
+ PROGMEM Language_Str MSG_MMU2_EJECTING_FILAMENT = _UxGT("Mata ut Tråd ...");
+ PROGMEM Language_Str MSG_MMU2_UNLOADING_FILAMENT = _UxGT("Lossa Tråd...");
+ PROGMEM Language_Str MSG_MMU2_ALL = _UxGT("Alla");
+ PROGMEM Language_Str MSG_MMU2_FILAMENT_N = _UxGT("Tråd ~");
+ PROGMEM Language_Str MSG_MMU2_RESET = _UxGT("Återställ MMU");
+ PROGMEM Language_Str MSG_MMU2_RESETTING = _UxGT("MMU Återställer...");
+ PROGMEM Language_Str MSG_MMU2_EJECT_RECOVER = _UxGT("Ta bort, Klicka");
+
+ PROGMEM Language_Str MSG_MIX = _UxGT("Mixa");
+ PROGMEM Language_Str MSG_MIX_COMPONENT_N = _UxGT("Komponent =");
+ PROGMEM Language_Str MSG_MIXER = _UxGT("Mixer");
+ PROGMEM Language_Str MSG_GRADIENT = _UxGT("Gradient");
+ PROGMEM Language_Str MSG_FULL_GRADIENT = _UxGT("Full Gradient");
+ PROGMEM Language_Str MSG_TOGGLE_MIX = _UxGT("Växla Mix");
+ PROGMEM Language_Str MSG_CYCLE_MIX = _UxGT("Totera Mix");
+ PROGMEM Language_Str MSG_GRADIENT_MIX = _UxGT("Gradient Mix");
+ PROGMEM Language_Str MSG_REVERSE_GRADIENT = _UxGT("Omvänd Gradient");
+ PROGMEM Language_Str MSG_ACTIVE_VTOOL = _UxGT("Aktive V-verktyg");
+ PROGMEM Language_Str MSG_START_VTOOL = _UxGT("Start V-verktyg");
+ PROGMEM Language_Str MSG_END_VTOOL = _UxGT(" Slut V-verktyg");
+ PROGMEM Language_Str MSG_GRADIENT_ALIAS = _UxGT("Alias V-verktyg");
+ PROGMEM Language_Str MSG_RESET_VTOOLS = _UxGT("Återställ V-verktyg");
+ PROGMEM Language_Str MSG_COMMIT_VTOOL = _UxGT("Kommitta V-verktyg Mix");
+ PROGMEM Language_Str MSG_VTOOLS_RESET = _UxGT("V-verktyg blev Återställda");
+ PROGMEM Language_Str MSG_START_Z = _UxGT("Start Z:");
+ PROGMEM Language_Str MSG_END_Z = _UxGT(" Slut Z:");
+
+ PROGMEM Language_Str MSG_GAMES = _UxGT("Spel");
+ PROGMEM Language_Str MSG_BRICKOUT = _UxGT("Brickout");
+ PROGMEM Language_Str MSG_INVADERS = _UxGT("Invaders");
+ PROGMEM Language_Str MSG_SNAKE = _UxGT("Sn4k3");
+ PROGMEM Language_Str MSG_MAZE = _UxGT("Labyrint");
+
+ PROGMEM Language_Str MSG_BAD_PAGE = _UxGT("Dålig sida index");
+ PROGMEM Language_Str MSG_BAD_PAGE_SPEED = _UxGT("Dålig sida hastighet");
+
+ PROGMEM Language_Str MSG_EDIT_PASSWORD = _UxGT("Redigera Lösenord");
+ PROGMEM Language_Str MSG_LOGIN_REQUIRED = _UxGT("Login Krävs");
+ PROGMEM Language_Str MSG_PASSWORD_SETTINGS = _UxGT("Lösenordsinställningar");
+ PROGMEM Language_Str MSG_ENTER_DIGIT = _UxGT("Ange Siffra");
+ PROGMEM Language_Str MSG_CHANGE_PASSWORD = _UxGT("Sätt/Redigera Lösenord");
+ PROGMEM Language_Str MSG_REMOVE_PASSWORD = _UxGT("Ta bort Lösenord");
+ PROGMEM Language_Str MSG_PASSWORD_SET = _UxGT("Lösenord är ");
+ PROGMEM Language_Str MSG_START_OVER = _UxGT("Börja om");
+ PROGMEM Language_Str MSG_REMINDER_SAVE_SETTINGS = _UxGT("Kom ihåg att Spara!");
+ PROGMEM Language_Str MSG_PASSWORD_REMOVED = _UxGT("Lösenord Bort taget");
+
+ //
+ // Filament Change screens show up to 3 lines on a 4-line display
+ // ...or up to 2 lines on a 3-line display
+ //
+ #if LCD_HEIGHT >= 4
+ PROGMEM Language_Str MSG_ADVANCED_PAUSE_WAITING = _UxGT(MSG_2_LINE("Tryck på knappen", "för att fortsätta utskrift"));
+ PROGMEM Language_Str MSG_PAUSE_PRINT_PARKING = _UxGT(MSG_1_LINE("Parkera..."));
+ PROGMEM Language_Str MSG_FILAMENT_CHANGE_INIT = _UxGT(MSG_3_LINE("Vänta på", "trådbyte", "att börja"));
+ PROGMEM Language_Str MSG_FILAMENT_CHANGE_INSERT = _UxGT(MSG_3_LINE("Sätt in tråd", "och tryck på knappen", "för att fortsätta"));
+ PROGMEM Language_Str MSG_FILAMENT_CHANGE_HEAT = _UxGT(MSG_2_LINE("Tryck på knappen", "för att värma munstycke"));
+ PROGMEM Language_Str MSG_FILAMENT_CHANGE_HEATING = _UxGT(MSG_2_LINE("Munstycke värms", "Var snäll och vänta..."));
+ PROGMEM Language_Str MSG_FILAMENT_CHANGE_UNLOAD = _UxGT(MSG_2_LINE("Väntar på", "trådlossning"));
+ PROGMEM Language_Str MSG_FILAMENT_CHANGE_LOAD = _UxGT(MSG_2_LINE("Väntar på", "trådladdning"));
+ PROGMEM Language_Str MSG_FILAMENT_CHANGE_PURGE = _UxGT(MSG_2_LINE("Väntar på", "tråd utrensning"));
+ PROGMEM Language_Str MSG_FILAMENT_CHANGE_CONT_PURGE = _UxGT(MSG_2_LINE("Klicka för att slutföra", "tråd utrensning"));
+ PROGMEM Language_Str MSG_FILAMENT_CHANGE_RESUME = _UxGT(MSG_2_LINE("Väntar på utskrift", "att återstarta..."));
+ #else
+ PROGMEM Language_Str MSG_ADVANCED_PAUSE_WAITING = _UxGT(MSG_1_LINE("Klick för att fortsätta"));
+ PROGMEM Language_Str MSG_PAUSE_PRINT_PARKING = _UxGT(MSG_1_LINE("Parkera..."));
+ PROGMEM Language_Str MSG_FILAMENT_CHANGE_INIT = _UxGT(MSG_1_LINE("Vänta..."));
+ PROGMEM Language_Str MSG_FILAMENT_CHANGE_INSERT = _UxGT(MSG_1_LINE("Sätt in och klicka"));
+ PROGMEM Language_Str MSG_FILAMENT_CHANGE_HEAT = _UxGT(MSG_1_LINE("Klicka för att värma"));
+ PROGMEM Language_Str MSG_FILAMENT_CHANGE_HEATING = _UxGT(MSG_1_LINE("Värmer..."));
+ PROGMEM Language_Str MSG_FILAMENT_CHANGE_UNLOAD = _UxGT(MSG_1_LINE("Lossar..."));
+ PROGMEM Language_Str MSG_FILAMENT_CHANGE_LOAD = _UxGT(MSG_1_LINE("Laddar..."));
+ PROGMEM Language_Str MSG_FILAMENT_CHANGE_PURGE = _UxGT(MSG_1_LINE("Rensar..."));
+ PROGMEM Language_Str MSG_FILAMENT_CHANGE_CONT_PURGE = _UxGT(MSG_1_LINE("Klicka för att slutföra"));
+ PROGMEM Language_Str MSG_FILAMENT_CHANGE_RESUME = _UxGT(MSG_1_LINE("Återgår..."));
+ #endif
+ PROGMEM Language_Str MSG_TMC_DRIVERS = _UxGT("TMC Drivers");
+ PROGMEM Language_Str MSG_TMC_CURRENT = _UxGT("Driver Ström");
+ PROGMEM Language_Str MSG_TMC_HYBRID_THRS = _UxGT("Hybrid Tröskelvärde");
+ PROGMEM Language_Str MSG_TMC_HOMING_THRS = _UxGT("Sensorlös Hemning");
+ PROGMEM Language_Str MSG_TMC_STEPPING_MODE = _UxGT("Stegningsläge");
+ PROGMEM Language_Str MSG_TMC_STEALTH_ENABLED = _UxGT("Smyghack Aktiverad");
+ PROGMEM Language_Str MSG_SERVICE_RESET = _UxGT("Återställ");
+ PROGMEM Language_Str MSG_SERVICE_IN = _UxGT(" in:");
+ PROGMEM Language_Str MSG_BACKLASH = _UxGT("Backlash");
+ PROGMEM Language_Str MSG_BACKLASH_A = LCD_STR_A;
+ PROGMEM Language_Str MSG_BACKLASH_B = LCD_STR_B;
+ PROGMEM Language_Str MSG_BACKLASH_C = LCD_STR_C;
+ PROGMEM Language_Str MSG_BACKLASH_CORRECTION = _UxGT("Korrigering");
+ PROGMEM Language_Str MSG_BACKLASH_SMOOTHING = _UxGT("Glättning");
+
+ PROGMEM Language_Str MSG_LEVEL_X_AXIS = _UxGT("Nivå X Axel");
+ PROGMEM Language_Str MSG_AUTO_CALIBRATE = _UxGT("Auto Kalibrera");
+ #if ENABLED(TOUCH_UI_FTDI_EVE)
+ PROGMEM Language_Str MSG_HEATER_TIMEOUT = _UxGT("Overksam tidsgräns, temperatur minskning. Tryck ok för att återvärma och igen för att fortsätta.");
+ #else
+ PROGMEM Language_Str MSG_HEATER_TIMEOUT = _UxGT("Värmare Tidsgräns");
+ #endif
+ PROGMEM Language_Str MSG_REHEAT = _UxGT("Återvärm");
+ PROGMEM Language_Str MSG_REHEATING = _UxGT("Återvärmning...");
+
+ PROGMEM Language_Str MSG_PROBE_WIZARD = _UxGT("Z Sond Wizard");
+ PROGMEM Language_Str MSG_PROBE_WIZARD_PROBING = _UxGT("Sondering Z Referens");
+ PROGMEM Language_Str MSG_PROBE_WIZARD_MOVING = _UxGT("Flyttar till Sonderings Pos");
+
+ PROGMEM Language_Str MSG_SOUND = _UxGT("Ljud");
+
+ PROGMEM Language_Str MSG_TOP_LEFT = _UxGT("Uppe Vänster");
+ PROGMEM Language_Str MSG_BOTTOM_LEFT = _UxGT("Nere Vänster");
+ PROGMEM Language_Str MSG_TOP_RIGHT = _UxGT("Uppe Höger");
+ PROGMEM Language_Str MSG_BOTTOM_RIGHT = _UxGT("Nere Höger");
+ PROGMEM Language_Str MSG_CALIBRATION_COMPLETED = _UxGT("Kalibrering Färdig");
+ PROGMEM Language_Str MSG_CALIBRATION_FAILED = _UxGT("Kalibrering Misslyckad");
+}
diff --git a/Marlin/src/lcd/language/language_uk.h b/Marlin/src/lcd/language/language_uk.h
index eb69bc1b74..069ad7066d 100644
--- a/Marlin/src/lcd/language/language_uk.h
+++ b/Marlin/src/lcd/language/language_uk.h
@@ -215,7 +215,7 @@ namespace Language_uk {
PROGMEM Language_Str MSG_UBL_MESH_HEIGHT_AMOUNT = _UxGT("Висота");
PROGMEM Language_Str MSG_UBL_VALIDATE_MESH_MENU = _UxGT("Підтвердити сітку");
PROGMEM Language_Str MSG_UBL_VALIDATE_CUSTOM_MESH = _UxGT("Підтвердити свою");
-
+
PROGMEM Language_Str MSG_G26_HEATING_BED = _UxGT("G26 нагрів столу");
PROGMEM Language_Str MSG_G26_HEATING_NOZZLE = _UxGT("G26 нагрів сопла");
PROGMEM Language_Str MSG_G26_MANUAL_PRIME = _UxGT("Ручне грунтування");
@@ -714,7 +714,7 @@ namespace Language_uk {
PROGMEM Language_Str MSG_CYCLE_MIX = _UxGT("Циклічне змішування");
PROGMEM Language_Str MSG_GRADIENT_MIX = _UxGT("Градієнт змішування");
PROGMEM Language_Str MSG_REVERSE_GRADIENT = _UxGT("Змінити градієнт");
-
+
#if LCD_WIDTH > 21
PROGMEM Language_Str MSG_ACTIVE_VTOOL = _UxGT("Активація В-інструменту");
PROGMEM Language_Str MSG_GRADIENT_ALIAS = _UxGT("Псевдонім В-інструменту");
@@ -728,7 +728,7 @@ namespace Language_uk {
PROGMEM Language_Str MSG_END_VTOOL = _UxGT("Кінець В-інструменту");
PROGMEM Language_Str MSG_COMMIT_VTOOL = _UxGT("Змішати В-інструменти");
PROGMEM Language_Str MSG_VTOOLS_RESET = _UxGT("В-інструменти зкинуті");
-
+
PROGMEM Language_Str MSG_START_Z = _UxGT("Початок Z:");
PROGMEM Language_Str MSG_END_Z = _UxGT(" Кінець Z:");
diff --git a/Marlin/src/lcd/lcdprint.cpp b/Marlin/src/lcd/lcdprint.cpp
index 2c78b14834..32f425168f 100644
--- a/Marlin/src/lcd/lcdprint.cpp
+++ b/Marlin/src/lcd/lcdprint.cpp
@@ -28,6 +28,7 @@
#if HAS_WIRED_LCD && !HAS_GRAPHICAL_TFT
+#include "marlinui.h"
#include "lcdprint.h"
/**
diff --git a/Marlin/src/lcd/marlinui.cpp b/Marlin/src/lcd/marlinui.cpp
index d4e1357e86..46db571936 100644
--- a/Marlin/src/lcd/marlinui.cpp
+++ b/Marlin/src/lcd/marlinui.cpp
@@ -78,6 +78,10 @@ constexpr uint8_t epps = ENCODER_PULSES_PER_STEP;
#endif
#endif
+#if HAS_MULTI_LANGUAGE
+ uint8_t MarlinUI::language; // Initialized by settings.load()
+#endif
+
#if ENABLED(SOUND_MENU_ITEM)
bool MarlinUI::buzzer_enabled = true;
#endif
@@ -1491,8 +1495,8 @@ void MarlinUI::update() {
#ifdef ACTION_ON_CANCEL
host_action_cancel();
#endif
+ IF_DISABLED(SDSUPPORT, print_job_timer.stop());
TERN_(HOST_PROMPT_SUPPORT, host_prompt_open(PROMPT_INFO, PSTR("UI Aborted"), DISMISS_STR));
- print_job_timer.stop();
LCD_MESSAGEPGM(MSG_PRINT_ABORTED);
TERN_(HAS_LCD_MENU, return_to_status());
}
@@ -1512,7 +1516,7 @@ void MarlinUI::update() {
LCD_MESSAGEPGM(MSG_PRINT_PAUSED);
#if ENABLED(PARK_HEAD_ON_PAUSE)
- TERN_(HAS_WIRED_LCD, lcd_pause_show_message(PAUSE_MESSAGE_PARKING, PAUSE_MODE_PAUSE_PRINT)); // Show message immediately to let user know about pause in progress
+ pause_show_message(PAUSE_MESSAGE_PARKING, PAUSE_MODE_PAUSE_PRINT); // Show message immediately to let user know about pause in progress
queue.inject_P(PSTR("M25 P\nM24"));
#elif ENABLED(SDSUPPORT)
queue.inject_P(PSTR("M25"));
@@ -1524,7 +1528,7 @@ void MarlinUI::update() {
void MarlinUI::resume_print() {
reset_status();
TERN_(PARK_HEAD_ON_PAUSE, wait_for_heatup = wait_for_user = false);
- if (IS_SD_PAUSED()) queue.inject_P(M24_STR);
+ TERN_(SDSUPPORT, if (IS_SD_PAUSED()) queue.inject_P(M24_STR));
#ifdef ACTION_ON_RESUME
host_action_resume();
#endif
diff --git a/Marlin/src/lcd/marlinui.h b/Marlin/src/lcd/marlinui.h
index a64483fcb0..2e55c9ad1d 100644
--- a/Marlin/src/lcd/marlinui.h
+++ b/Marlin/src/lcd/marlinui.h
@@ -51,15 +51,13 @@
#include "../module/printcounter.h"
#endif
+#if BOTH(HAS_LCD_MENU, ADVANCED_PAUSE_FEATURE)
+ #include "../feature/pause.h"
+ #include "../module/motion.h" // for active_extruder
+#endif
+
#if HAS_WIRED_LCD
- #include "../MarlinCore.h"
-
- #if ENABLED(ADVANCED_PAUSE_FEATURE)
- #include "../feature/pause.h"
- #include "../module/motion.h" // for active_extruder
- #endif
-
enum LCDViewAction : uint8_t {
LCDVIEW_NONE,
LCDVIEW_REDRAW_NOW,
@@ -87,12 +85,6 @@
typedef void (*screenFunc_t)();
typedef void (*menuAction_t)();
- #if ENABLED(ADVANCED_PAUSE_FEATURE)
- void lcd_pause_show_message(const PauseMessage message,
- const PauseMode mode=PAUSE_MODE_SAME,
- const uint8_t extruder=active_extruder);
- #endif
-
#if ENABLED(AUTO_BED_LEVELING_UBL)
void lcd_mesh_edit_setup(const float &initial);
float lcd_mesh_edit();
@@ -178,6 +170,17 @@ public:
TERN_(HAS_LCD_MENU, currentScreen = status_screen);
}
+ #if HAS_MULTI_LANGUAGE
+ static uint8_t language;
+ static inline void set_language(const uint8_t lang) {
+ if (lang < NUM_LANGUAGES) {
+ language = lang;
+ return_to_status();
+ refresh();
+ }
+ }
+ #endif
+
#if ENABLED(SOUND_MENU_ITEM)
static bool buzzer_enabled; // Initialized by settings.load()
#else
@@ -495,6 +498,13 @@ public:
#endif
+ #if BOTH(HAS_LCD_MENU, ADVANCED_PAUSE_FEATURE)
+ static void pause_show_message(const PauseMessage message, const PauseMode mode=PAUSE_MODE_SAME, const uint8_t extruder=active_extruder);
+ #else
+ static inline void _pause_show_message() {}
+ #define pause_show_message(...) _pause_show_message()
+ #endif
+
//
// EEPROM: Reset / Init / Load / Store
//
diff --git a/Marlin/src/lcd/menu/menu_advanced.cpp b/Marlin/src/lcd/menu/menu_advanced.cpp
index b5f8d1d5de..cb7827168b 100644
--- a/Marlin/src/lcd/menu/menu_advanced.cpp
+++ b/Marlin/src/lcd/menu/menu_advanced.cpp
@@ -155,7 +155,7 @@ void menu_backlash();
#if HAS_FILAMENT_RUNOUT_DISTANCE
editable.decimal = runout.runout_distance();
- EDIT_ITEM(float3, MSG_RUNOUT_DISTANCE_MM, &editable.decimal, 1, float(FILAMENT_RUNOUT_DISTANCE_MM) * 1.5f,
+ EDIT_ITEM_FAST(float3, MSG_RUNOUT_DISTANCE_MM, &editable.decimal, 1, 999,
[]{ runout.set_runout_distance(editable.decimal); }, true
);
#endif
diff --git a/Marlin/src/lcd/menu/menu_bed_corners.cpp b/Marlin/src/lcd/menu/menu_bed_corners.cpp
index bcf5aea8d7..751be18600 100644
--- a/Marlin/src/lcd/menu/menu_bed_corners.cpp
+++ b/Marlin/src/lcd/menu/menu_bed_corners.cpp
@@ -39,7 +39,6 @@
#ifndef LEVEL_CORNERS_Z_HOP
#define LEVEL_CORNERS_Z_HOP 4.0
#endif
-
#ifndef LEVEL_CORNERS_HEIGHT
#define LEVEL_CORNERS_HEIGHT 0.0
#endif
@@ -67,8 +66,6 @@
static_assert(LEVEL_CORNERS_Z_HOP >= 0, "LEVEL_CORNERS_Z_HOP must be >= 0. Please update your configuration.");
-extern const char G28_STR[];
-
#if HAS_LEVELING
static bool leveling_was_active = false;
#endif
@@ -177,12 +174,13 @@ static inline void _lcd_level_bed_corners_get_next_position() {
MenuItem_static::draw(0, GET_TEXT(MSG_PROBING_MESH), SS_INVERT); // "Probing Mesh" heading
- uint8_t cy = LCD_HEIGHT - 1, y = LCD_ROW_Y(cy);
+ uint8_t cy = TERN(TFT_COLOR_UI, 3, LCD_HEIGHT - 1), y = LCD_ROW_Y(cy);
// Display # of good points found vs total needed
if (PAGE_CONTAINS(y - (MENU_FONT_HEIGHT), y)) {
- SETCURSOR(0, cy);
+ SETCURSOR(TERN(TFT_COLOR_UI, 2, 0), cy);
lcd_put_u8str_P(GET_TEXT(MSG_LEVEL_CORNERS_GOOD_POINTS));
+ IF_ENABLED(TFT_COLOR_UI, lcd_moveto(12, cy));
lcd_put_u8str(GOOD_POINTS_TO_STR(good_points));
lcd_put_wchar('/');
lcd_put_u8str(GOOD_POINTS_TO_STR(nr_edge_points));
@@ -193,8 +191,9 @@ static inline void _lcd_level_bed_corners_get_next_position() {
// Display the Last Z value
if (PAGE_CONTAINS(y - (MENU_FONT_HEIGHT), y)) {
- SETCURSOR(0, cy);
+ SETCURSOR(TERN(TFT_COLOR_UI, 2, 0), cy);
lcd_put_u8str_P(GET_TEXT(MSG_LEVEL_CORNERS_LAST_Z));
+ IF_ENABLED(TFT_COLOR_UI, lcd_moveto(12, 2));
lcd_put_u8str(LAST_Z_TO_STR(last_z));
}
}
@@ -206,7 +205,7 @@ static inline void _lcd_level_bed_corners_get_next_position() {
, []{ corner_probing_done = true; wait_for_probe = false; }
, []{ wait_for_probe = false; }
, GET_TEXT(MSG_LEVEL_CORNERS_RAISE)
- , (const char*)nullptr, PSTR("")
+ , (const char*)nullptr, NUL_STR
);
}
@@ -248,7 +247,7 @@ static inline void _lcd_level_bed_corners_get_next_position() {
wait_for_probe = true;
ui.goto_screen(_lcd_draw_raise); // show raise screen
ui.set_selection(true);
- while (wait_for_probe && !probe_triggered) { //loop while waiting to bed raise and probe trigger
+ while (wait_for_probe && !probe_triggered) { // loop while waiting to bed raise and probe trigger
probe_triggered = PROBE_TRIGGERED();
if (probe_triggered) {
endstops.hit_on_purpose();
@@ -269,7 +268,7 @@ static inline void _lcd_level_bed_corners_get_next_position() {
ui.goto_screen(_lcd_draw_probing);
do {
ui.refresh(LCDVIEW_REDRAW_NOW);
- _lcd_draw_probing(); //update screen with # of good points
+ _lcd_draw_probing(); // update screen with # of good points
do_blocking_move_to_z(current_position.z + LEVEL_CORNERS_Z_HOP); // clearance
_lcd_level_bed_corners_get_next_position(); // Select next corner coordinates
@@ -330,6 +329,7 @@ static inline void _lcd_level_bed_corners_homing() {
GET_TEXT(MSG_BUTTON_NEXT), GET_TEXT(MSG_BUTTON_DONE)
, _lcd_goto_next_corner
, []{
+ line_to_z(LEVEL_CORNERS_Z_HOP); // Raise Z off the bed when done
TERN_(HAS_LEVELING, set_bed_leveling_enabled(leveling_was_active));
ui.goto_previous_screen_no_defer();
}
diff --git a/Marlin/src/lcd/menu/menu_delta_calibrate.cpp b/Marlin/src/lcd/menu/menu_delta_calibrate.cpp
index 4efcb7c8ed..a86ae74fce 100644
--- a/Marlin/src/lcd/menu/menu_delta_calibrate.cpp
+++ b/Marlin/src/lcd/menu/menu_delta_calibrate.cpp
@@ -53,6 +53,7 @@ void _man_probe_pt(const xy_pos_t &xy) {
#if ENABLED(DELTA_AUTO_CALIBRATION)
+ #include "../../MarlinCore.h" // for wait_for_user_response()
#include "../../gcode/gcode.h"
#if ENABLED(HOST_PROMPT_SUPPORT)
diff --git a/Marlin/src/lcd/menu/menu_filament.cpp b/Marlin/src/lcd/menu/menu_filament.cpp
index 7bd12bde17..19601d678e 100644
--- a/Marlin/src/lcd/menu/menu_filament.cpp
+++ b/Marlin/src/lcd/menu/menu_filament.cpp
@@ -107,6 +107,8 @@ void _menu_temp_filament_op(const PauseMode mode, const int8_t extruder) {
*/
#if E_STEPPERS > 1 || ENABLED(FILAMENT_LOAD_UNLOAD_GCODES)
+ bool printingIsPaused();
+
void menu_change_filament() {
// Say "filament change" when no print is active
editable.int8 = printingIsPaused() ? PAUSE_MODE_PAUSE_PRINT : PAUSE_MODE_CHANGE_FILAMENT;
@@ -315,7 +317,7 @@ FORCE_INLINE screenFunc_t ap_message_screen(const PauseMessage message) {
return nullptr;
}
-void lcd_pause_show_message(
+void MarlinUI::pause_show_message(
const PauseMessage message,
const PauseMode mode/*=PAUSE_MODE_SAME*/,
const uint8_t extruder/*=active_extruder*/
diff --git a/Marlin/src/lcd/menu/menu_item.h b/Marlin/src/lcd/menu/menu_item.h
index 1d9a2f6b2c..6873f209b4 100644
--- a/Marlin/src/lcd/menu/menu_item.h
+++ b/Marlin/src/lcd/menu/menu_item.h
@@ -485,7 +485,7 @@ class MenuItem_bool : public MenuEditItemBase {
#if SNFAN(1) || SNFAN(2) || SNFAN(3) || SNFAN(4) || SNFAN(5) || SNFAN(6) || SNFAN(7)
#define DEFINE_SINGLENOZZLE_ITEM() \
auto singlenozzle_item = [&](const uint8_t f) { \
- editable.uint8 = singlenozzle_fan_speed[f]; \
+ editable.uint8 = thermalManager.singlenozzle_fan_speed[f]; \
EDIT_ITEM_FAST_N(percent, f, MSG_STORED_FAN_N, &editable.uint8, 0, 255, on_fan_update); \
}
#else
diff --git a/Marlin/src/lcd/menu/menu_language.cpp b/Marlin/src/lcd/menu/menu_language.cpp
new file mode 100644
index 0000000000..4c4b7880f2
--- /dev/null
+++ b/Marlin/src/lcd/menu/menu_language.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
+ *
+ * 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 .
+ *
+ */
+
+//
+// Language Selection Menu
+//
+
+#include "../../inc/MarlinConfig.h"
+
+#if HAS_MULTI_LANGUAGE
+
+#include "menu_item.h"
+#include "../../MarlinCore.h"
+#include "../../module/settings.h"
+
+static void set_lcd_language(const uint8_t inlang) {
+ ui.set_language(inlang);
+ TERN_(LCD_LANGUAGE_AUTO_SAVE, (void)settings.save());
+}
+
+void menu_language() {
+ START_MENU();
+ BACK_ITEM(MSG_MAIN);
+
+ MENU_ITEM_P(function, GET_LANG(LCD_LANGUAGE )::LANGUAGE, []{ set_lcd_language(0); });
+ MENU_ITEM_P(function, GET_LANG(LCD_LANGUAGE_2)::LANGUAGE, []{ set_lcd_language(1); });
+ #if NUM_LANGUAGES > 2
+ MENU_ITEM_P(function, GET_LANG(LCD_LANGUAGE_3)::LANGUAGE, []{ set_lcd_language(2); });
+ #if NUM_LANGUAGES > 3
+ MENU_ITEM_P(function, GET_LANG(LCD_LANGUAGE_4)::LANGUAGE, []{ set_lcd_language(3); });
+ #if NUM_LANGUAGES > 4
+ MENU_ITEM_P(function, GET_LANG(LCD_LANGUAGE_5)::LANGUAGE, []{ set_lcd_language(4); });
+ #endif
+ #endif
+ #endif
+
+ END_MENU();
+}
+
+#endif // HAS_MULTI_LANGUAGE
diff --git a/Marlin/src/lcd/menu/menu_led.cpp b/Marlin/src/lcd/menu/menu_led.cpp
index d9540592d0..552c03a69f 100644
--- a/Marlin/src/lcd/menu/menu_led.cpp
+++ b/Marlin/src/lcd/menu/menu_led.cpp
@@ -123,11 +123,15 @@ void menu_led() {
#if ENABLED(LED_CONTROL_MENU)
editable.state = leds.lights_on;
EDIT_ITEM(bool, MSG_LEDS, &editable.state, leds.toggle);
- ACTION_ITEM(MSG_SET_LEDS_DEFAULT, leds.set_default);
+ #if ENABLED(LED_COLOR_PRESETS)
+ ACTION_ITEM(MSG_SET_LEDS_DEFAULT, leds.set_default);
+ #endif
#if ENABLED(NEOPIXEL2_SEPARATE)
editable.state = leds2.lights_on;
EDIT_ITEM(bool, MSG_LEDS2, &editable.state, leds2.toggle);
- ACTION_ITEM(MSG_SET_LEDS_DEFAULT, leds2.set_default);
+ #if ENABLED(NEO2_COLOR_PRESETS)
+ ACTION_ITEM(MSG_SET_LEDS_DEFAULT, leds2.set_default);
+ #endif
#endif
#if ENABLED(LED_COLOR_PRESETS)
SUBMENU(MSG_LED_PRESETS, menu_led_presets);
diff --git a/Marlin/src/lcd/menu/menu_main.cpp b/Marlin/src/lcd/menu/menu_main.cpp
index b7cd549e6b..878ac83a5a 100644
--- a/Marlin/src/lcd/menu/menu_main.cpp
+++ b/Marlin/src/lcd/menu/menu_main.cpp
@@ -97,7 +97,9 @@ void menu_configuration();
void menu_spindle_laser();
#endif
-extern const char M21_STR[];
+#if HAS_MULTI_LANGUAGE
+ void menu_language();
+#endif
void menu_main() {
const bool busy = printingIsActive()
@@ -152,7 +154,7 @@ void menu_main() {
if (!card_open) {
SUBMENU(MSG_MEDIA_MENU, MEDIA_MENU_GATEWAY);
#if PIN_EXISTS(SD_DETECT)
- GCODES_ITEM(MSG_CHANGE_MEDIA, M21_STR);
+ GCODES_ITEM(MSG_CHANGE_MEDIA, PSTR("M21"));
#else
GCODES_ITEM(MSG_RELEASE_MEDIA, PSTR("M22"));
#endif
@@ -162,7 +164,7 @@ void menu_main() {
#if PIN_EXISTS(SD_DETECT)
ACTION_ITEM(MSG_NO_MEDIA, nullptr);
#else
- GCODES_ITEM(MSG_ATTACH_MEDIA, M21_STR);
+ GCODES_ITEM(MSG_ATTACH_MEDIA, PSTR("M21"));
#endif
}
@@ -253,7 +255,7 @@ void menu_main() {
if (card_detected) {
if (!card_open) {
#if PIN_EXISTS(SD_DETECT)
- GCODES_ITEM(MSG_CHANGE_MEDIA, M21_STR);
+ GCODES_ITEM(MSG_CHANGE_MEDIA, PSTR("M21"));
#else
GCODES_ITEM(MSG_RELEASE_MEDIA, PSTR("M22"));
#endif
@@ -264,7 +266,7 @@ void menu_main() {
#if PIN_EXISTS(SD_DETECT)
ACTION_ITEM(MSG_NO_MEDIA, nullptr);
#else
- GCODES_ITEM(MSG_ATTACH_MEDIA, M21_STR);
+ GCODES_ITEM(MSG_ATTACH_MEDIA, PSTR("M21"));
#endif
}
}
@@ -325,6 +327,10 @@ void menu_main() {
}
#endif
+ #if HAS_MULTI_LANGUAGE
+ SUBMENU(LANGUAGE, menu_language);
+ #endif
+
END_MENU();
}
diff --git a/Marlin/src/lcd/menu/menu_mmu2.cpp b/Marlin/src/lcd/menu/menu_mmu2.cpp
index 8a34e7d296..7e71f00d25 100644
--- a/Marlin/src/lcd/menu/menu_mmu2.cpp
+++ b/Marlin/src/lcd/menu/menu_mmu2.cpp
@@ -32,15 +32,12 @@
// Load Filament
//
-void _mmu2_load_filamentToNozzle(uint8_t index) {
+inline void action_mmu2_load_filament_to_nozzle(const uint8_t tool) {
ui.reset_status();
ui.return_to_status();
- ui.status_printf_P(0, GET_TEXT(MSG_MMU2_LOADING_FILAMENT), int(index + 1));
- if (mmu2.load_filament_to_nozzle(index)) ui.reset_status();
-}
-
-inline void action_mmu2_load_filament_to_nozzle(const uint8_t tool) {
- _mmu2_load_filamentToNozzle(tool);
+ ui.status_printf_P(0, GET_TEXT(MSG_MMU2_LOADING_FILAMENT), int(tool + 1));
+ if (mmu2.load_filament_to_nozzle(tool))
+ ui.reset_status();
ui.return_to_status();
}
@@ -59,14 +56,14 @@ void menu_mmu2_load_filament() {
START_MENU();
BACK_ITEM(MSG_MMU2_MENU);
ACTION_ITEM(MSG_MMU2_ALL, action_mmu2_load_all);
- LOOP_L_N(i, 5) ACTION_ITEM_N(i, MSG_MMU2_FILAMENT_N, []{ _mmu2_load_filament(MenuItemBase::itemIndex); });
+ LOOP_L_N(i, EXTRUDERS) ACTION_ITEM_N(i, MSG_MMU2_FILAMENT_N, []{ _mmu2_load_filament(MenuItemBase::itemIndex); });
END_MENU();
}
void menu_mmu2_load_to_nozzle() {
START_MENU();
BACK_ITEM(MSG_MMU2_MENU);
- LOOP_L_N(i, 5) ACTION_ITEM_N(i, MSG_MMU2_FILAMENT_N, []{ action_mmu2_load_filament_to_nozzle(MenuItemBase::itemIndex); });
+ LOOP_L_N(i, EXTRUDERS) ACTION_ITEM_N(i, MSG_MMU2_FILAMENT_N, []{ action_mmu2_load_filament_to_nozzle(MenuItemBase::itemIndex); });
END_MENU();
}
@@ -92,7 +89,7 @@ void action_mmu2_unload_filament() {
void menu_mmu2_eject_filament() {
START_MENU();
BACK_ITEM(MSG_MMU2_MENU);
- LOOP_L_N(i, 5) ACTION_ITEM_N(i, MSG_MMU2_FILAMENT_N, []{ _mmu2_eject_filament(MenuItemBase::itemIndex); });
+ LOOP_L_N(i, EXTRUDERS) ACTION_ITEM_N(i, MSG_MMU2_FILAMENT_N, []{ _mmu2_eject_filament(MenuItemBase::itemIndex); });
END_MENU();
}
@@ -133,7 +130,7 @@ void menu_mmu2_choose_filament() {
#if LCD_HEIGHT > 2
STATIC_ITEM(MSG_MMU2_CHOOSE_FILAMENT_HEADER, SS_DEFAULT|SS_INVERT);
#endif
- LOOP_L_N(i, 5) ACTION_ITEM_N(i, MSG_MMU2_FILAMENT_N, []{ action_mmu2_chosen(MenuItemBase::itemIndex); });
+ LOOP_L_N(i, EXTRUDERS) ACTION_ITEM_N(i, MSG_MMU2_FILAMENT_N, []{ action_mmu2_chosen(MenuItemBase::itemIndex); });
END_MENU();
}
diff --git a/Marlin/src/lcd/menu/menu_motion.cpp b/Marlin/src/lcd/menu/menu_motion.cpp
index ecc378b607..71fc4246c7 100644
--- a/Marlin/src/lcd/menu/menu_motion.cpp
+++ b/Marlin/src/lcd/menu/menu_motion.cpp
@@ -189,7 +189,6 @@ void _menu_move_distance(const AxisEnum axis, const screenFunc_t func, const int
sprintf_P(tmp, label, dtostrf(FINE_MANUAL_MOVE, 1, digs, numstr));
#if DISABLED(HAS_GRAPHICAL_TFT)
- extern const char NUL_STR[];
SUBMENU_P(NUL_STR, []{ _goto_manual_move(float(FINE_MANUAL_MOVE)); });
MENU_ITEM_ADDON_START(0 + ENABLED(HAS_MARLINUI_HD44780));
lcd_put_u8str(tmp);
diff --git a/Marlin/src/lcd/menu/menu_password.cpp b/Marlin/src/lcd/menu/menu_password.cpp
index c58931cf2e..80c5c3dc66 100644
--- a/Marlin/src/lcd/menu/menu_password.cpp
+++ b/Marlin/src/lcd/menu/menu_password.cpp
@@ -49,7 +49,7 @@ void Password::menu_password_entry() {
// "Login" or "New Code"
STATIC_ITEM_P(authenticating ? GET_TEXT(MSG_LOGIN_REQUIRED) : GET_TEXT(MSG_EDIT_PASSWORD), SS_CENTER|SS_INVERT);
- STATIC_ITEM_P(PSTR(""), SS_CENTER|SS_INVERT, string);
+ STATIC_ITEM_P(NUL_STR, SS_CENTER|SS_INVERT, string);
// Make the digit edit item look like a sub-menu
PGM_P const label = GET_TEXT(MSG_ENTER_DIGIT);
diff --git a/Marlin/src/lcd/menu/menu_probe_offset.cpp b/Marlin/src/lcd/menu/menu_probe_offset.cpp
index 5b88c8e805..2f0c37b433 100644
--- a/Marlin/src/lcd/menu/menu_probe_offset.cpp
+++ b/Marlin/src/lcd/menu/menu_probe_offset.cpp
@@ -88,7 +88,6 @@ void probe_offset_wizard_menu() {
!UNEAR_ZERO((FINE_MANUAL_MOVE) * 100 - int((FINE_MANUAL_MOVE) * 100)) ? 3 : 2;
sprintf_P(tmp, GET_TEXT(MSG_MOVE_N_MM), dtostrf(FINE_MANUAL_MOVE, 1, digs, numstr));
#if DISABLED(HAS_GRAPHICAL_TFT)
- extern const char NUL_STR[];
SUBMENU_P(NUL_STR, []{ _goto_manual_move_z(float(FINE_MANUAL_MOVE)); });
MENU_ITEM_ADDON_START(0 + ENABLED(HAS_MARLINUI_HD44780));
lcd_put_u8str(tmp);
diff --git a/Marlin/src/lcd/menu/menu_temperature.cpp b/Marlin/src/lcd/menu/menu_temperature.cpp
index 2e5aff1006..01c1f8f547 100644
--- a/Marlin/src/lcd/menu/menu_temperature.cpp
+++ b/Marlin/src/lcd/menu/menu_temperature.cpp
@@ -35,6 +35,10 @@
#include "../../module/motion.h"
#endif
+#if ENABLED(SINGLENOZZLE_STANDBY_TEMP)
+ #include "../../module/tool_change.h"
+#endif
+
//
// "Temperature" submenu items
//
@@ -155,7 +159,7 @@ void menu_temperature() {
#if ENABLED(SINGLENOZZLE_STANDBY_TEMP)
LOOP_S_L_N(e, 1, EXTRUDERS)
- EDIT_ITEM_FAST_N(uint16_3, e, MSG_NOZZLE_STANDBY, &singlenozzle_temp[e], 0, thermalManager.heater_maxtemp[0] - (HOTEND_OVERSHOOT));
+ EDIT_ITEM_FAST_N(uint16_3, e, MSG_NOZZLE_STANDBY, &thermalManager.singlenozzle_temp[e], 0, thermalManager.heater_maxtemp[0] - (HOTEND_OVERSHOOT));
#endif
//
diff --git a/Marlin/src/lcd/menu/menu_tune.cpp b/Marlin/src/lcd/menu/menu_tune.cpp
index 5da25ce59a..0fbb57f2ac 100644
--- a/Marlin/src/lcd/menu/menu_tune.cpp
+++ b/Marlin/src/lcd/menu/menu_tune.cpp
@@ -34,6 +34,10 @@
#include "../../module/temperature.h"
#include "../../MarlinCore.h"
+#if ENABLED(SINGLENOZZLE_STANDBY_TEMP)
+ #include "../../module/tool_change.h"
+#endif
+
#if HAS_LEVELING
#include "../../feature/bedlevel/bedlevel.h"
#endif
@@ -67,9 +71,16 @@
const bool in_view = TERN1(HAS_MARLINUI_U8GLIB, PAGE_CONTAINS(LCD_PIXEL_HEIGHT - MENU_FONT_HEIGHT, LCD_PIXEL_HEIGHT - 1));
if (in_view) {
TERN_(HAS_MARLINUI_U8GLIB, ui.set_font(FONT_MENU));
- lcd_moveto(0, TERN(HAS_MARLINUI_U8GLIB, LCD_PIXEL_HEIGHT - MENU_FONT_DESCENT, LCD_HEIGHT - 1));
- lcd_put_u8str_P(GET_TEXT(MSG_BABYSTEP_TOTAL));
- lcd_put_wchar(':');
+ #if ENABLED(TFT_COLOR_UI)
+ lcd_moveto(4, 3);
+ lcd_put_u8str_P(GET_TEXT(MSG_BABYSTEP_TOTAL));
+ lcd_put_wchar(':');
+ lcd_moveto(10, 3);
+ #else
+ lcd_moveto(0, TERN(HAS_MARLINUI_U8GLIB, LCD_PIXEL_HEIGHT - MENU_FONT_DESCENT, LCD_HEIGHT - 1));
+ lcd_put_u8str_P(GET_TEXT(MSG_BABYSTEP_TOTAL));
+ lcd_put_wchar(':');
+ #endif
lcd_put_u8str(BABYSTEP_TO_STR(spm * babystep.axis_total[BS_TOTAL_IND(axis)]));
}
#endif
@@ -123,7 +134,7 @@ void menu_tune() {
#if ENABLED(SINGLENOZZLE_STANDBY_TEMP)
LOOP_S_L_N(e, 1, EXTRUDERS)
- EDIT_ITEM_FAST_N(uint16_3, e, MSG_NOZZLE_STANDBY, &singlenozzle_temp[e], 0, thermalManager.heater_maxtemp[0] - HOTEND_OVERSHOOT);
+ EDIT_ITEM_FAST_N(uint16_3, e, MSG_NOZZLE_STANDBY, &thermalManager.singlenozzle_temp[e], 0, thermalManager.heater_maxtemp[0] - HOTEND_OVERSHOOT);
#endif
//
diff --git a/Marlin/src/lcd/tft/tft_image.cpp b/Marlin/src/lcd/tft/tft_image.cpp
index 9cc6fb15e4..851410b2e0 100644
--- a/Marlin/src/lcd/tft/tft_image.cpp
+++ b/Marlin/src/lcd/tft/tft_image.cpp
@@ -20,8 +20,11 @@
*
*/
+#include "../../inc/MarlinConfigPre.h"
+
+#if HAS_GRAPHICAL_TFT
+
#include "tft_image.h"
-#include
const tImage NoLogo = { nullptr, 0, 0, NOCOLORS };
@@ -70,4 +73,38 @@ const tImage Leveling_32x32x4 = { (void *)leveling_32x32x4, 32, 32, GREYSC
const tImage Slider8x16x4 = { (void *)slider_8x16x4, 8, 16, GREYSCALE4 };
-extern const tImage Images[imgCount];
+const tImage Images[imgCount] = {
+ TERN(SHOW_BOOTSCREEN, TERN(BOOT_MARLIN_LOGO_SMALL, MarlinLogo195x59x16, MARLIN_LOGO_FULL_SIZE), NoLogo),
+ HotEnd_64x64x4,
+ Bed_64x64x4,
+ Bed_Heated_64x64x4,
+ Chamber_64x64x4,
+ Chamber_Heated_64x64x4,
+ Fan0_64x64x4,
+ Fan_Slow0_64x64x4,
+ Fan_Slow1_64x64x4,
+ Fan_Fast0_64x64x4,
+ Fan_Fast1_64x64x4,
+ Feedrate_32x32x4,
+ Flowrate_32x32x4,
+ SD_64x64x4,
+ Menu_64x64x4,
+ Settings_64x64x4,
+ Directory_32x32x4,
+ Confirm_64x64x4,
+ Cancel_64x64x4,
+ Increase_64x64x4,
+ Decrease_64x64x4,
+ Back_32x32x4,
+ Up_32x32x4,
+ Down_32x32x4,
+ Left_32x32x4,
+ Right_32x32x4,
+ Refresh_32x32x4,
+ Leveling_32x32x4,
+ Slider8x16x4,
+ Home_64x64x4,
+ BtnRounded_64x52x4,
+};
+
+#endif // HAS_GRAPHICAL_TFT
diff --git a/Marlin/src/lcd/tft/tft_image.h b/Marlin/src/lcd/tft/tft_image.h
index 21bd2d665f..960a4e4356 100644
--- a/Marlin/src/lcd/tft/tft_image.h
+++ b/Marlin/src/lcd/tft/tft_image.h
@@ -21,9 +21,10 @@
*/
#pragma once
-#include "stdint.h"
#include "../../inc/MarlinConfigPre.h"
+#include
+
extern const uint8_t marlin_logo_112x38x1[];
extern const uint8_t marlin_logo_228x255x2[];
extern const uint8_t marlin_logo_228x255x4[];
diff --git a/Marlin/src/lcd/tft/tft_string.cpp b/Marlin/src/lcd/tft/tft_string.cpp
index eb805ac423..31ac14cf92 100644
--- a/Marlin/src/lcd/tft/tft_string.cpp
+++ b/Marlin/src/lcd/tft/tft_string.cpp
@@ -36,7 +36,7 @@ font_t *TFT_String::font_header;
uint8_t TFT_String::data[];
uint16_t TFT_String::span;
-uint16_t TFT_String::length;
+uint8_t TFT_String::length;
void TFT_String::set_font(const uint8_t *font) {
font_header = (font_t *)font;
@@ -122,13 +122,14 @@ void TFT_String::add(uint8_t *string, int8_t index, uint8_t *itemString) {
eol();
}
-void TFT_String::add(uint8_t *string) {
+void TFT_String::add(uint8_t *string, uint8_t max_len) {
wchar_t wchar;
- while (*string) {
+ while (*string && max_len) {
string = get_utf8_value_cb(string, read_byte, &wchar);
if (wchar > 255) wchar |= 0x0080;
uint8_t ch = uint8_t(wchar & 0x00FF);
add_character(ch);
+ max_len--;
}
eol();
}
diff --git a/Marlin/src/lcd/tft/tft_string.h b/Marlin/src/lcd/tft/tft_string.h
index e800b1ded9..133889d9ae 100644
--- a/Marlin/src/lcd/tft/tft_string.h
+++ b/Marlin/src/lcd/tft/tft_string.h
@@ -69,7 +69,7 @@ class TFT_String {
static uint8_t data[MAX_STRING_LENGTH + 1];
static uint16_t span; // in pixels
- static uint16_t length; // in characters
+ static uint8_t length; // in characters
static void add_character(uint8_t character);
static void eol() { data[length] = 0x00; }
@@ -85,7 +85,7 @@ class TFT_String {
static void set();
static void add(uint8_t character) { add_character(character); eol(); }
- static void add(uint8_t *string);
+ static void add(uint8_t *string, uint8_t max_len=MAX_STRING_LENGTH);
static void add(uint8_t *string, int8_t index, uint8_t *itemString=nullptr);
static void set(uint8_t *string) { set(); add(string); };
static void set(uint8_t *string, int8_t index, const char *itemString=nullptr) { set(); add(string, index, (uint8_t *)itemString); };
@@ -96,6 +96,9 @@ class TFT_String {
static void trim(uint8_t character=0x20);
static void rtrim(uint8_t character=0x20);
static void ltrim(uint8_t character=0x20);
+
+ static void truncate(uint8_t maxlen) { if (length > maxlen) { length = maxlen; eol(); } }
+
static uint16_t width() { return span; }
static uint8_t *string() { return data; }
static uint16_t center(uint16_t width) { return span > width ? 0 : (width - span) / 2; }
diff --git a/Marlin/src/lcd/tft/ui_320x240.cpp b/Marlin/src/lcd/tft/ui_320x240.cpp
index 4c09d9803e..eadd09ef27 100644
--- a/Marlin/src/lcd/tft/ui_320x240.cpp
+++ b/Marlin/src/lcd/tft/ui_320x240.cpp
@@ -24,7 +24,7 @@
#if HAS_UI_320x240
-#include "ui_320x240.h"
+#include "ui_common.h"
#include "../marlinui.h"
#include "../menu/menu.h"
@@ -45,12 +45,6 @@
#include "../../feature/bedlevel/bedlevel.h"
#endif
-#if !HAS_LCD_MENU
- #error "Seriously? High resolution TFT screen without menu?"
-#endif
-
-static bool draw_menu_navigation = false;
-
void MarlinUI::tft_idle() {
#if ENABLED(TOUCH_SCREEN)
if (draw_menu_navigation) {
@@ -65,28 +59,6 @@ void MarlinUI::tft_idle() {
TERN_(TOUCH_SCREEN, touch.idle());
}
-void MarlinUI::init_lcd() {
- tft.init();
- tft.set_font(MENU_FONT_NAME);
- #ifdef SYMBOLS_FONT_NAME
- tft.add_glyphs(SYMBOLS_FONT_NAME);
- #endif
- TERN_(TOUCH_SCREEN, touch.init());
- clear_lcd();
-}
-
-bool MarlinUI::detected() { return true; }
-
-void MarlinUI::clear_lcd() {
- #if ENABLED(TOUCH_SCREEN)
- touch.reset();
- draw_menu_navigation = false;
- #endif
-
- tft.queue.reset();
- tft.fill(0, 0, TFT_WIDTH, TFT_HEIGHT, COLOR_BACKGROUND);
-}
-
#if ENABLED(SHOW_BOOTSCREEN)
void MarlinUI::show_bootscreen() {
tft.queue.reset();
@@ -98,8 +70,8 @@ void MarlinUI::clear_lcd() {
#define SITE_URL_Y (TFT_HEIGHT - 46)
tft.set_background(COLOR_BACKGROUND);
#else
- #define BOOT_LOGO_W 320 // MarlinLogo320x240x16
- #define BOOT_LOGO_H 240
+ #define BOOT_LOGO_W TFT_WIDTH // MarlinLogo320x240x16
+ #define BOOT_LOGO_H TFT_HEIGHT
#define SITE_URL_Y (TFT_HEIGHT - 52)
#endif
tft.add_image((TFT_WIDTH - BOOT_LOGO_W) / 2, (TFT_HEIGHT - BOOT_LOGO_H) / 2, imgBootScreen);
@@ -148,22 +120,22 @@ void draw_heater_status(uint16_t x, uint16_t y, const int8_t Heater) {
currentTemperature = thermalManager.degHotend(Heater);
targetTemperature = thermalManager.degTargetHotend(Heater);
}
-#if HAS_HEATED_BED
- else if (Heater == H_BED) {
- currentTemperature = thermalManager.degBed();
- targetTemperature = thermalManager.degTargetBed();
- }
-#endif // HAS_HEATED_BED
-#if HAS_TEMP_CHAMBER
- else if (Heater == H_CHAMBER) {
- currentTemperature = thermalManager.degChamber();
- #if HAS_HEATED_CHAMBER
- targetTemperature = thermalManager.degTargetChamber();
- #else
- targetTemperature = ABSOLUTE_ZERO;
- #endif
- }
-#endif // HAS_TEMP_CHAMBER
+ #if HAS_HEATED_BED
+ else if (Heater == H_BED) {
+ currentTemperature = thermalManager.degBed();
+ targetTemperature = thermalManager.degTargetBed();
+ }
+ #endif
+ #if HAS_TEMP_CHAMBER
+ else if (Heater == H_CHAMBER) {
+ currentTemperature = thermalManager.degChamber();
+ #if HAS_HEATED_CHAMBER
+ targetTemperature = thermalManager.degTargetChamber();
+ #else
+ targetTemperature = ABSOLUTE_ZERO;
+ #endif
+ }
+ #endif
else return;
TERN_(TOUCH_SCREEN, if (targetTemperature >= 0) touch.add_control(HEATER, x, y, 64, 100, Heater));
@@ -176,17 +148,17 @@ void draw_heater_status(uint16_t x, uint16_t y, const int8_t Heater) {
if (currentTemperature >= 50) Color = COLOR_HOTEND;
}
#if HAS_HEATED_BED
- else if (Heater == H_BED) {
- if (currentTemperature >= 50) Color = COLOR_HEATED_BED;
- image = targetTemperature > 0 ? imgBedHeated : imgBed;
- }
- #endif // HAS_HEATED_BED
+ else if (Heater == H_BED) {
+ if (currentTemperature >= 50) Color = COLOR_HEATED_BED;
+ image = targetTemperature > 0 ? imgBedHeated : imgBed;
+ }
+ #endif
#if HAS_TEMP_CHAMBER
- else if (Heater == H_CHAMBER) {
- if (currentTemperature >= 50) Color = COLOR_CHAMBER;
- image = targetTemperature > 0 ? imgChamberHeated : imgChamber;
- }
- #endif // HAS_TEMP_CHAMBER
+ else if (Heater == H_CHAMBER) {
+ if (currentTemperature >= 50) Color = COLOR_CHAMBER;
+ image = targetTemperature > 0 ? imgChamberHeated : imgChamber;
+ }
+ #endif
tft.add_image(0, 18, image, Color);
@@ -200,7 +172,6 @@ void draw_heater_status(uint16_t x, uint16_t y, const int8_t Heater) {
tft_string.add(LCD_STR_DEGREE);
tft_string.trim();
tft.add_text(tft_string.center(64) + 2, 8, Color, tft_string);
-
}
}
@@ -232,7 +203,7 @@ void MarlinUI::draw_status_screen() {
TERN_(TOUCH_SCREEN, touch.clear());
// heaters and fan
- uint16_t i, x, y = POS_Y;
+ uint16_t i, x, y = TFT_STATUS_TOP_Y;
for (i = 0 ; i < ITEMS_COUNT; i++) {
x = (320 / ITEMS_COUNT - 64) / 2 + (320 * i / ITEMS_COUNT);
@@ -341,49 +312,6 @@ void MarlinUI::draw_status_screen() {
#endif
}
-// Draw a static item with no left-right margin required. Centered by default.
-void MenuItem_static::draw(const uint8_t row, PGM_P const pstr, const uint8_t style/*=SS_DEFAULT*/, const char * const vstr/*=nullptr*/) {
- menu_item(row);
- tft_string.set(pstr, itemIndex, itemString);
- if (vstr)
- tft_string.add(vstr);
- tft.add_text(tft_string.center(TFT_WIDTH), MENU_TEXT_Y_OFFSET, COLOR_YELLOW, tft_string);
-}
-
-// Draw a generic menu item with pre_char (if selected) and post_char
-void MenuItemBase::_draw(const bool sel, const uint8_t row, PGM_P const pstr, const char pre_char, const char post_char) {
- menu_item(row, sel);
-
- uint8_t *string = (uint8_t *)pstr;
- MarlinImage image = noImage;
- switch (*string) {
- case 0x01: image = imgRefresh; break; // LCD_STR_REFRESH
- case 0x02: image = imgDirectory; break; // LCD_STR_FOLDER
- }
-
- uint8_t offset = MENU_TEXT_X_OFFSET;
- if (image != noImage) {
- string++;
- offset = 32;
- tft.add_image(0, 0, image, COLOR_MENU_TEXT, sel ? COLOR_SELECTION_BG : COLOR_BACKGROUND);
- }
-
- tft_string.set(string, itemIndex, itemString);
- tft.add_text(offset, MENU_TEXT_Y_OFFSET, COLOR_MENU_TEXT, tft_string);
-}
-
-// Draw a menu item with a (potentially) editable value
-void MenuEditItemBase::draw(const bool sel, const uint8_t row, PGM_P const pstr, const char* const data, const bool pgm) {
- menu_item(row, sel);
-
- tft_string.set(pstr, itemIndex, itemString);
- tft.add_text(MENU_TEXT_X_OFFSET, MENU_TEXT_Y_OFFSET, COLOR_MENU_TEXT, tft_string);
- if (data) {
- tft_string.set(data);
- tft.add_text(TFT_WIDTH - MENU_TEXT_X_OFFSET - tft_string.width(), MENU_TEXT_Y_OFFSET, COLOR_MENU_VALUE, tft_string);
- }
-}
-
// Low-level draw_edit_screen can be used to draw an edit screen from anyplace
void MenuEditItemBase::draw_edit_screen(PGM_P const pstr, const char* const value/*=nullptr*/) {
ui.encoder_direction_normal();
@@ -483,16 +411,8 @@ void MenuItem_confirm::draw_select_screen(PGM_P const yes, PGM_P const no, const
#endif
}
-#if ENABLED(SDSUPPORT)
- void MenuItem_sdbase::draw(const bool sel, const uint8_t row, PGM_P const, CardReader &theCard, const bool isDir) {
- menu_item(row, sel);
- if (isDir)
- tft.add_image(0, 0, imgDirectory, COLOR_MENU_TEXT, sel ? COLOR_SELECTION_BG : COLOR_BACKGROUND);
- tft.add_text(32, MENU_TEXT_Y_OFFSET, COLOR_MENU_TEXT, theCard.longest_filename());
- }
-#endif
-
#if ENABLED(ADVANCED_PAUSE_FEATURE)
+
void MarlinUI::draw_hotend_status(const uint8_t row, const uint8_t extruder) {
#if ENABLED(TOUCH_SCREEN)
touch.clear();
@@ -513,6 +433,7 @@ void MenuItem_confirm::draw_select_screen(PGM_P const yes, PGM_P const no, const
tft_string.trim();
tft.add_text(tft_string.center(TFT_WIDTH), MENU_TEXT_Y_OFFSET, COLOR_MENU_TEXT, tft_string);
}
+
#endif // ADVANCED_PAUSE_FEATURE
#if ENABLED(AUTO_BED_LEVELING_UBL)
@@ -562,18 +483,18 @@ void MenuItem_confirm::draw_select_screen(PGM_P const yes, PGM_P const no, const
tft_string.trim();
tft.add_text(96 - tft_string.width(), MENU_TEXT_Y_OFFSET, COLOR_MENU_VALUE, tft_string);
-
- tft.canvas(GRID_OFFSET_X + (GRID_WIDTH - 32) / 2, GRID_OFFSET_Y + GRID_HEIGHT + CONTROL_OFFSET - 1, 32, 32);
+ constexpr uint8_t w = (TFT_WIDTH) / 10;
+ tft.canvas(GRID_OFFSET_X + (GRID_WIDTH - w) / 2, GRID_OFFSET_Y + GRID_HEIGHT + CONTROL_OFFSET - 1, w, 32);
tft.set_background(COLOR_BACKGROUND);
tft_string.set(ui8tostr3rj(x_plot));
tft_string.trim();
- tft.add_text(tft_string.center(32), MENU_TEXT_Y_OFFSET, COLOR_MENU_VALUE, tft_string);
+ tft.add_text(tft_string.center(w), MENU_TEXT_Y_OFFSET, COLOR_MENU_VALUE, tft_string);
- tft.canvas(GRID_OFFSET_X + GRID_WIDTH + CONTROL_OFFSET, GRID_OFFSET_Y + (GRID_HEIGHT - 27) / 2, 32, 32);
+ tft.canvas(GRID_OFFSET_X + GRID_WIDTH + CONTROL_OFFSET, GRID_OFFSET_Y + (GRID_HEIGHT - 27) / 2, w, 32);
tft.set_background(COLOR_BACKGROUND);
tft_string.set(ui8tostr3rj(y_plot));
tft_string.trim();
- tft.add_text(tft_string.center(32), MENU_TEXT_Y_OFFSET, COLOR_MENU_VALUE, tft_string);
+ tft.add_text(tft_string.center(w), MENU_TEXT_Y_OFFSET, COLOR_MENU_VALUE, tft_string);
#if ENABLED(TOUCH_SCREEN)
touch.clear();
@@ -588,97 +509,6 @@ void MenuItem_confirm::draw_select_screen(PGM_P const yes, PGM_P const no, const
}
#endif // AUTO_BED_LEVELING_UBL
-#if ENABLED(TOUCH_SCREEN_CALIBRATION)
- void MarlinUI::touch_calibration_screen() {
- uint16_t x, y;
-
- calibrationState calibration_stage = touch_calibration.get_calibration_state();
-
- if (calibration_stage == CALIBRATION_NONE) {
- defer_status_screen(true);
- clear_lcd();
- calibration_stage = touch_calibration.calibration_start();
- }
- else {
- x = touch_calibration.calibration_points[_MIN(calibration_stage - 1, CALIBRATION_BOTTOM_RIGHT)].x;
- y = touch_calibration.calibration_points[_MIN(calibration_stage - 1, CALIBRATION_BOTTOM_RIGHT)].y;
- tft.canvas(x - 15, y - 15, 31, 31);
- tft.set_background(COLOR_BACKGROUND);
- }
-
- touch.clear();
-
- if (calibration_stage < CALIBRATION_SUCCESS) {
- switch (calibration_stage) {
- case CALIBRATION_TOP_LEFT: tft_string.set(GET_TEXT(MSG_TOP_LEFT)); break;
- case CALIBRATION_BOTTOM_LEFT: tft_string.set(GET_TEXT(MSG_BOTTOM_LEFT)); break;
- case CALIBRATION_TOP_RIGHT: tft_string.set(GET_TEXT(MSG_TOP_RIGHT)); break;
- case CALIBRATION_BOTTOM_RIGHT: tft_string.set(GET_TEXT(MSG_BOTTOM_RIGHT)); break;
- default: break;
- }
-
- x = touch_calibration.calibration_points[calibration_stage].x;
- y = touch_calibration.calibration_points[calibration_stage].y;
-
- tft.canvas(x - 15, y - 15, 31, 31);
- tft.set_background(COLOR_BACKGROUND);
- tft.add_bar(0, 15, 31, 1, COLOR_TOUCH_CALIBRATION);
- tft.add_bar(15, 0, 1, 31, COLOR_TOUCH_CALIBRATION);
-
- touch.add_control(CALIBRATE, 0, 0, TFT_WIDTH, TFT_HEIGHT, uint32_t(x) << 16 | uint32_t(y));
- }
- else {
- tft_string.set(calibration_stage == CALIBRATION_SUCCESS ? GET_TEXT(MSG_CALIBRATION_COMPLETED) : GET_TEXT(MSG_CALIBRATION_FAILED));
- defer_status_screen(false);
- touch_calibration.calibration_end();
- touch.add_control(BACK, 0, 0, TFT_WIDTH, TFT_HEIGHT);
- }
-
- tft.canvas(0, (TFT_HEIGHT - tft_string.font_height()) >> 1, TFT_WIDTH, tft_string.font_height());
- tft.set_background(COLOR_BACKGROUND);
- tft.add_text(tft_string.center(TFT_WIDTH), 0, COLOR_MENU_TEXT, tft_string);
- }
-#endif // TOUCH_SCREEN_CALIBRATION
-
-void menu_line(const uint8_t row, uint16_t color) {
- tft.canvas(0, 2 + 34 * row, TFT_WIDTH, 32);
- tft.set_background(color);
-}
-
-void menu_pause_option();
-
-void menu_item(const uint8_t row, bool sel ) {
- #if ENABLED(TOUCH_SCREEN)
- if (row == 0) {
- touch.clear();
- draw_menu_navigation = TERN(ADVANCED_PAUSE_FEATURE, ui.currentScreen != menu_pause_option, true);
- }
- #endif
-
- menu_line(row, sel ? COLOR_SELECTION_BG : COLOR_BACKGROUND);
- #if ENABLED(TOUCH_SCREEN)
- const TouchControlType tct = TERN(SINGLE_TOUCH_NAVIGATION, true, sel) ? MENU_CLICK : MENU_ITEM;
- touch.add_control(tct, 0, 2 + 34 * row, TFT_WIDTH, 32, encoderTopLine + row);
- #endif
-}
-
-void lcd_moveto(const lcd_uint_t col, const lcd_uint_t row) {
- #define TFT_COL_WIDTH ((TFT_WIDTH) / (LCD_WIDTH))
- tft.canvas(col * TFT_COL_WIDTH, 4 + 45 * row, TFT_WIDTH - (col * TFT_COL_WIDTH), 43);
- tft.set_background(COLOR_BACKGROUND);
-}
-
-int lcd_put_u8str_max_P(PGM_P utf8_str_P, pixel_len_t max_length) {
- tft_string.set(utf8_str_P);
- tft_string.trim();
- tft.add_text(MENU_TEXT_X_OFFSET, MENU_TEXT_Y_OFFSET, COLOR_MENU_TEXT, tft_string);
- return tft_string.width();
-}
-
-int lcd_put_u8str_max(const char * utf8_str, pixel_len_t max_length) {
- return lcd_put_u8str_max_P(utf8_str, max_length);
-}
-
void MarlinUI::move_axis_screen() {
}
diff --git a/Marlin/src/lcd/tft/ui_320x240.h b/Marlin/src/lcd/tft/ui_320x240.h
index 249a21c4f1..40b2185577 100644
--- a/Marlin/src/lcd/tft/ui_320x240.h
+++ b/Marlin/src/lcd/tft/ui_320x240.h
@@ -21,88 +21,22 @@
*/
#pragma once
-#include "../../inc/MarlinConfigPre.h"
+#define MARLIN_LOGO_FULL_SIZE MarlinLogo320x240x16
-#include "tft.h"
-#include "tft_image.h"
+#define TFT_STATUS_TOP_Y 0
+#define TFT_TOP_LINE_Y 2
-#if ENABLED(TOUCH_SCREEN)
- #include "touch.h"
-#endif
+#define MENU_TEXT_X_OFFSET 10
+#define MENU_TEXT_Y_OFFSET 7
-void draw_heater_status(uint16_t x, uint16_t y, const int8_t Heater);
-void draw_fan_status(uint16_t x, uint16_t y, const bool blink);
+#define MENU_ITEM_ICON_X 0
+#define MENU_ITEM_ICON_Y 0
+#define MENU_ITEM_ICON_SPACE 32
-#define MENU_TEXT_X_OFFSET 10
-#define MENU_TEXT_Y_OFFSET 7
-void menu_line(const uint8_t row, uint16_t color = COLOR_BACKGROUND);
-void menu_item(const uint8_t row, bool sel = false);
+#define MENU_ITEM_HEIGHT 32
+#define MENU_LINE_HEIGHT (MENU_ITEM_HEIGHT + 2)
-#define MENU_FONT_NAME Helvetica14
-#define SYMBOLS_FONT_NAME Helvetica14_symbols
+#define MENU_FONT_NAME Helvetica14
+#define SYMBOLS_FONT_NAME Helvetica14_symbols
-#define ABSOLUTE_ZERO -273.15
-
-const tImage Images[imgCount] = {
- TERN(SHOW_BOOTSCREEN, TERN(BOOT_MARLIN_LOGO_SMALL, MarlinLogo195x59x16, MarlinLogo320x240x16), NoLogo),
- HotEnd_64x64x4,
- Bed_64x64x4,
- Bed_Heated_64x64x4,
- Chamber_64x64x4,
- Chamber_Heated_64x64x4,
- Fan0_64x64x4,
- Fan_Slow0_64x64x4,
- Fan_Slow1_64x64x4,
- Fan_Fast0_64x64x4,
- Fan_Fast1_64x64x4,
- Feedrate_32x32x4,
- Flowrate_32x32x4,
- SD_64x64x4,
- Menu_64x64x4,
- Settings_64x64x4,
- Directory_32x32x4,
- Confirm_64x64x4,
- Cancel_64x64x4,
- Increase_64x64x4,
- Decrease_64x64x4,
- Back_32x32x4,
- Up_32x32x4,
- Down_32x32x4,
- Left_32x32x4,
- Right_32x32x4,
- Refresh_32x32x4,
- Leveling_32x32x4,
- Slider8x16x4,
- Home_64x64x4,
- BtnRounded_64x52x4,
-};
-
-#if HAS_TEMP_CHAMBER && HOTENDS > 1
- #define ITEM_E0 0
- #define ITEM_E1 1
- #define ITEM_BED 2
- #define ITEM_CHAMBER 3
- #define ITEM_FAN 4
- #define ITEMS_COUNT 5
- #define POS_Y 0
-#elif HAS_TEMP_CHAMBER
- #define ITEM_E0 0
- #define ITEM_BED 1
- #define ITEM_CHAMBER 2
- #define ITEM_FAN 3
- #define ITEMS_COUNT 4
- #define POS_Y 0
-#elif HOTENDS > 1
- #define ITEM_E0 0
- #define ITEM_E1 1
- #define ITEM_BED 2
- #define ITEM_FAN 3
- #define ITEMS_COUNT 4
- #define POS_Y 0
-#else
- #define ITEM_E0 0
- #define ITEM_BED 1
- #define ITEM_FAN 2
- #define ITEMS_COUNT 3
- #define POS_Y 0
-#endif
+#include "ui_common.h"
diff --git a/Marlin/src/lcd/tft/ui_480x320.cpp b/Marlin/src/lcd/tft/ui_480x320.cpp
index b6ffb4592f..5000aedc39 100644
--- a/Marlin/src/lcd/tft/ui_480x320.cpp
+++ b/Marlin/src/lcd/tft/ui_480x320.cpp
@@ -24,7 +24,7 @@
#if HAS_UI_480x320 || HAS_UI_480x272
-#include "ui_480x320.h"
+#include "ui_common.h"
#include "../marlinui.h"
#include "../menu/menu.h"
@@ -45,14 +45,6 @@
#include "../../feature/bedlevel/bedlevel.h"
#endif
-#if !HAS_LCD_MENU
- #error "Seriously? High resolution TFT screen without menu?"
-#endif
-
-#if ENABLED(TOUCH_SCREEN)
- static bool draw_menu_navigation = false;
-#endif
-
void MarlinUI::tft_idle() {
#if ENABLED(TOUCH_SCREEN)
if (draw_menu_navigation) {
@@ -67,28 +59,6 @@ void MarlinUI::tft_idle() {
TERN_(TOUCH_SCREEN, touch.idle());
}
-void MarlinUI::init_lcd() {
- tft.init();
- tft.set_font(MENU_FONT_NAME);
- #ifdef SYMBOLS_FONT_NAME
- tft.add_glyphs(SYMBOLS_FONT_NAME);
- #endif
- TERN_(TOUCH_SCREEN, touch.init());
- clear_lcd();
-}
-
-bool MarlinUI::detected() { return true; }
-
-void MarlinUI::clear_lcd() {
- #if ENABLED(TOUCH_SCREEN)
- touch.reset();
- draw_menu_navigation = false;
- #endif
-
- tft.queue.reset();
- tft.fill(0, 0, TFT_WIDTH, TFT_HEIGHT, COLOR_BACKGROUND);
-}
-
#if ENABLED(SHOW_BOOTSCREEN)
void MarlinUI::show_bootscreen() {
tft.queue.reset();
@@ -100,8 +70,8 @@ void MarlinUI::clear_lcd() {
#define SITE_URL_Y (TFT_HEIGHT - 70)
tft.set_background(COLOR_BACKGROUND);
#else
- #define BOOT_LOGO_W 480 // MarlinLogo480x320x16
- #define BOOT_LOGO_H 320
+ #define BOOT_LOGO_W TFT_WIDTH // MarlinLogo480x320x16
+ #define BOOT_LOGO_H TFT_HEIGHT
#define SITE_URL_Y (TFT_HEIGHT - 90)
#endif
tft.add_image((TFT_WIDTH - BOOT_LOGO_W) / 2, (TFT_HEIGHT - BOOT_LOGO_H) / 2, imgBootScreen);
@@ -150,22 +120,22 @@ void draw_heater_status(uint16_t x, uint16_t y, const int8_t Heater) {
currentTemperature = thermalManager.degHotend(Heater);
targetTemperature = thermalManager.degTargetHotend(Heater);
}
-#if HAS_HEATED_BED
- else if (Heater == H_BED) {
- currentTemperature = thermalManager.degBed();
- targetTemperature = thermalManager.degTargetBed();
- }
-#endif // HAS_HEATED_BED
-#if HAS_TEMP_CHAMBER
- else if (Heater == H_CHAMBER) {
- currentTemperature = thermalManager.degChamber();
- #if HAS_HEATED_CHAMBER
- targetTemperature = thermalManager.degTargetChamber();
- #else
- targetTemperature = ABSOLUTE_ZERO;
- #endif
- }
-#endif // HAS_TEMP_CHAMBER
+ #if HAS_HEATED_BED
+ else if (Heater == H_BED) {
+ currentTemperature = thermalManager.degBed();
+ targetTemperature = thermalManager.degTargetBed();
+ }
+ #endif
+ #if HAS_TEMP_CHAMBER
+ else if (Heater == H_CHAMBER) {
+ currentTemperature = thermalManager.degChamber();
+ #if HAS_HEATED_CHAMBER
+ targetTemperature = thermalManager.degTargetChamber();
+ #else
+ targetTemperature = ABSOLUTE_ZERO;
+ #endif
+ }
+ #endif
else return;
TERN_(TOUCH_SCREEN, if (targetTemperature >= 0) touch.add_control(HEATER, x, y, 80, 120, Heater));
@@ -178,17 +148,17 @@ void draw_heater_status(uint16_t x, uint16_t y, const int8_t Heater) {
if (currentTemperature >= 50) Color = COLOR_HOTEND;
}
#if HAS_HEATED_BED
- else if (Heater == H_BED) {
- if (currentTemperature >= 50) Color = COLOR_HEATED_BED;
- image = targetTemperature > 0 ? imgBedHeated : imgBed;
- }
- #endif // HAS_HEATED_BED
+ else if (Heater == H_BED) {
+ if (currentTemperature >= 50) Color = COLOR_HEATED_BED;
+ image = targetTemperature > 0 ? imgBedHeated : imgBed;
+ }
+ #endif
#if HAS_TEMP_CHAMBER
- else if (Heater == H_CHAMBER) {
- if (currentTemperature >= 50) Color = COLOR_CHAMBER;
- image = targetTemperature > 0 ? imgChamberHeated : imgChamber;
- }
- #endif // HAS_TEMP_CHAMBER
+ else if (Heater == H_CHAMBER) {
+ if (currentTemperature >= 50) Color = COLOR_CHAMBER;
+ image = targetTemperature > 0 ? imgChamberHeated : imgChamber;
+ }
+ #endif
tft.add_image(8, 28, image, Color);
@@ -233,7 +203,7 @@ void MarlinUI::draw_status_screen() {
TERN_(TOUCH_SCREEN, touch.clear());
// heaters and fan
- uint16_t i, x, y = POS_Y;
+ uint16_t i, x, y = TFT_STATUS_TOP_Y;
for (i = 0 ; i < ITEMS_COUNT; i++) {
x = (TFT_WIDTH / ITEMS_COUNT - 80) / 2 + (TFT_WIDTH * i / ITEMS_COUNT);
@@ -349,49 +319,6 @@ void MarlinUI::draw_status_screen() {
tft.add_text(tft_string.center(TFT_WIDTH), 0, COLOR_STATUS_MESSAGE, tft_string);
}
-// Draw a static item with no left-right margin required. Centered by default.
-void MenuItem_static::draw(const uint8_t row, PGM_P const pstr, const uint8_t style/*=SS_DEFAULT*/, const char * const vstr/*=nullptr*/) {
- menu_item(row);
- tft_string.set(pstr, itemIndex, itemString);
- if (vstr)
- tft_string.add(vstr);
- tft.add_text(tft_string.center(TFT_WIDTH), MENU_TEXT_Y_OFFSET, COLOR_YELLOW, tft_string);
-}
-
-// Draw a generic menu item with pre_char (if selected) and post_char
-void MenuItemBase::_draw(const bool sel, const uint8_t row, PGM_P const pstr, const char pre_char, const char post_char) {
- menu_item(row, sel);
-
- uint8_t *string = (uint8_t *)pstr;
- MarlinImage image = noImage;
- switch (*string) {
- case 0x01: image = imgRefresh; break; // LCD_STR_REFRESH
- case 0x02: image = imgDirectory; break; // LCD_STR_FOLDER
- }
-
- uint8_t offset = MENU_TEXT_X_OFFSET;
- if (image != noImage) {
- string++;
- offset = 42;
- tft.add_image(5, 5, image, COLOR_MENU_TEXT, sel ? COLOR_SELECTION_BG : COLOR_BACKGROUND);
- }
-
- tft_string.set(string, itemIndex, itemString);
- tft.add_text(offset, MENU_TEXT_Y_OFFSET, COLOR_MENU_TEXT, tft_string);
-}
-
-// Draw a menu item with a (potentially) editable value
-void MenuEditItemBase::draw(const bool sel, const uint8_t row, PGM_P const pstr, const char* const data, const bool pgm) {
- menu_item(row, sel);
-
- tft_string.set(pstr, itemIndex, itemString);
- tft.add_text(MENU_TEXT_X_OFFSET, MENU_TEXT_Y_OFFSET, COLOR_MENU_TEXT, tft_string);
- if (data) {
- tft_string.set(data);
- tft.add_text(TFT_WIDTH - MENU_TEXT_X_OFFSET - tft_string.width(), MENU_TEXT_Y_OFFSET, COLOR_MENU_VALUE, tft_string);
- }
-}
-
// Low-level draw_edit_screen can be used to draw an edit screen from anyplace
void MenuEditItemBase::draw_edit_screen(PGM_P const pstr, const char* const value/*=nullptr*/) {
ui.encoder_direction_normal();
@@ -491,16 +418,8 @@ void MenuItem_confirm::draw_select_screen(PGM_P const yes, PGM_P const no, const
#endif
}
-#if ENABLED(SDSUPPORT)
- void MenuItem_sdbase::draw(const bool sel, const uint8_t row, PGM_P const, CardReader &theCard, const bool isDir) {
- menu_item(row, sel);
- if (isDir)
- tft.add_image(5, 5, imgDirectory, COLOR_MENU_TEXT, sel ? COLOR_SELECTION_BG : COLOR_BACKGROUND);
- tft.add_text(42, MENU_TEXT_Y_OFFSET, COLOR_MENU_TEXT, theCard.longest_filename());
- }
-#endif
-
#if ENABLED(ADVANCED_PAUSE_FEATURE)
+
void MarlinUI::draw_hotend_status(const uint8_t row, const uint8_t extruder) {
#if ENABLED(TOUCH_SCREEN)
touch.clear();
@@ -521,6 +440,7 @@ void MenuItem_confirm::draw_select_screen(PGM_P const yes, PGM_P const no, const
tft_string.trim();
tft.add_text(tft_string.center(TFT_WIDTH), 0, COLOR_MENU_TEXT, tft_string);
}
+
#endif // ADVANCED_PAUSE_FEATURE
#if ENABLED(AUTO_BED_LEVELING_UBL)
@@ -570,18 +490,18 @@ void MenuItem_confirm::draw_select_screen(PGM_P const yes, PGM_P const no, const
tft_string.trim();
tft.add_text(120 - tft_string.width(), MENU_TEXT_Y_OFFSET, COLOR_MENU_VALUE, tft_string);
-
- tft.canvas(GRID_OFFSET_X + (GRID_WIDTH - 48) / 2, GRID_OFFSET_Y + GRID_HEIGHT + CONTROL_OFFSET - 5, 48, MENU_ITEM_HEIGHT);
+ constexpr uint8_t w = (TFT_WIDTH) / 10;
+ tft.canvas(GRID_OFFSET_X + (GRID_WIDTH - w) / 2, GRID_OFFSET_Y + GRID_HEIGHT + CONTROL_OFFSET - 5, w, MENU_ITEM_HEIGHT);
tft.set_background(COLOR_BACKGROUND);
tft_string.set(ui8tostr3rj(x_plot));
tft_string.trim();
- tft.add_text(tft_string.center(48), MENU_TEXT_Y_OFFSET, COLOR_MENU_VALUE, tft_string);
+ tft.add_text(tft_string.center(w), MENU_TEXT_Y_OFFSET, COLOR_MENU_VALUE, tft_string);
- tft.canvas(GRID_OFFSET_X + GRID_WIDTH + CONTROL_OFFSET + 16 - 24, GRID_OFFSET_Y + (GRID_HEIGHT - MENU_ITEM_HEIGHT) / 2, 48, MENU_ITEM_HEIGHT);
+ tft.canvas(GRID_OFFSET_X + GRID_WIDTH + CONTROL_OFFSET + 16 - 24, GRID_OFFSET_Y + (GRID_HEIGHT - MENU_ITEM_HEIGHT) / 2, w, MENU_ITEM_HEIGHT);
tft.set_background(COLOR_BACKGROUND);
tft_string.set(ui8tostr3rj(y_plot));
tft_string.trim();
- tft.add_text(tft_string.center(48), MENU_TEXT_Y_OFFSET, COLOR_MENU_VALUE, tft_string);
+ tft.add_text(tft_string.center(w), MENU_TEXT_Y_OFFSET, COLOR_MENU_VALUE, tft_string);
#if ENABLED(TOUCH_SCREEN)
touch.clear();
@@ -596,97 +516,6 @@ void MenuItem_confirm::draw_select_screen(PGM_P const yes, PGM_P const no, const
}
#endif // AUTO_BED_LEVELING_UBL
-#if ENABLED(TOUCH_SCREEN_CALIBRATION)
- void MarlinUI::touch_calibration_screen() {
- uint16_t x, y;
-
- calibrationState calibration_stage = touch_calibration.get_calibration_state();
-
- if (calibration_stage == CALIBRATION_NONE) {
- defer_status_screen(true);
- clear_lcd();
- calibration_stage = touch_calibration.calibration_start();
- }
- else {
- x = touch_calibration.calibration_points[_MIN(calibration_stage - 1, CALIBRATION_BOTTOM_RIGHT)].x;
- y = touch_calibration.calibration_points[_MIN(calibration_stage - 1, CALIBRATION_BOTTOM_RIGHT)].y;
- tft.canvas(x - 15, y - 15, 31, 31);
- tft.set_background(COLOR_BACKGROUND);
- }
-
- touch.clear();
-
- if (calibration_stage < CALIBRATION_SUCCESS) {
- switch (calibration_stage) {
- case CALIBRATION_TOP_LEFT: tft_string.set(GET_TEXT(MSG_TOP_LEFT)); break;
- case CALIBRATION_BOTTOM_LEFT: tft_string.set(GET_TEXT(MSG_BOTTOM_LEFT)); break;
- case CALIBRATION_TOP_RIGHT: tft_string.set(GET_TEXT(MSG_TOP_RIGHT)); break;
- case CALIBRATION_BOTTOM_RIGHT: tft_string.set(GET_TEXT(MSG_BOTTOM_RIGHT)); break;
- default: break;
- }
-
- x = touch_calibration.calibration_points[calibration_stage].x;
- y = touch_calibration.calibration_points[calibration_stage].y;
-
- tft.canvas(x - 15, y - 15, 31, 31);
- tft.set_background(COLOR_BACKGROUND);
- tft.add_bar(0, 15, 31, 1, COLOR_TOUCH_CALIBRATION);
- tft.add_bar(15, 0, 1, 31, COLOR_TOUCH_CALIBRATION);
-
- touch.add_control(CALIBRATE, 0, 0, TFT_WIDTH, TFT_HEIGHT, uint32_t(x) << 16 | uint32_t(y));
- }
- else {
- tft_string.set(calibration_stage == CALIBRATION_SUCCESS ? GET_TEXT(MSG_CALIBRATION_COMPLETED) : GET_TEXT(MSG_CALIBRATION_FAILED));
- defer_status_screen(false);
- touch_calibration.calibration_end();
- touch.add_control(BACK, 0, 0, TFT_WIDTH, TFT_HEIGHT);
- }
-
- tft.canvas(0, (TFT_HEIGHT - tft_string.font_height()) >> 1, TFT_WIDTH, tft_string.font_height());
- tft.set_background(COLOR_BACKGROUND);
- tft.add_text(tft_string.center(TFT_WIDTH), 0, COLOR_MENU_TEXT, tft_string);
- }
-#endif // TOUCH_SCREEN_CALIBRATION
-
-void menu_line(const uint8_t row, uint16_t color) {
- tft.canvas(0, 4 + (MENU_ITEM_HEIGHT + 2) * row, TFT_WIDTH, MENU_ITEM_HEIGHT);
- tft.set_background(color);
-}
-
-void menu_pause_option();
-
-void menu_item(const uint8_t row, bool sel ) {
- #if ENABLED(TOUCH_SCREEN)
- if (row == 0) {
- touch.clear();
- draw_menu_navigation = TERN(ADVANCED_PAUSE_FEATURE, ui.currentScreen != menu_pause_option, true);
- }
- #endif
-
- menu_line(row, sel ? COLOR_SELECTION_BG : COLOR_BACKGROUND);
- #if ENABLED(TOUCH_SCREEN)
- const TouchControlType tct = TERN(SINGLE_TOUCH_NAVIGATION, true, sel) ? MENU_CLICK : MENU_ITEM;
- touch.add_control(tct, 0, 4 + (MENU_ITEM_HEIGHT + 2) * row, TFT_WIDTH, MENU_ITEM_HEIGHT, encoderTopLine + row);
- #endif
-}
-
-void lcd_moveto(const lcd_uint_t col, const lcd_uint_t row) {
- #define TFT_COL_WIDTH ((TFT_WIDTH) / (LCD_WIDTH))
- tft.canvas(col * TFT_COL_WIDTH, 4 + 45 * row, TFT_WIDTH - (col * TFT_COL_WIDTH), 43);
- tft.set_background(COLOR_BACKGROUND);
-}
-
-int lcd_put_u8str_max_P(PGM_P utf8_str_P, pixel_len_t max_length) {
- tft_string.set(utf8_str_P);
- tft_string.trim();
- tft.add_text(MENU_TEXT_X_OFFSET, MENU_TEXT_Y_OFFSET, COLOR_MENU_TEXT, tft_string);
- return tft_string.width();
-}
-
-int lcd_put_u8str_max(const char * utf8_str, pixel_len_t max_length) {
- return lcd_put_u8str_max_P(utf8_str, max_length);
-}
-
#if ENABLED(BABYSTEP_ZPROBE_OFFSET)
#include "../../feature/babystep.h"
#endif
@@ -867,7 +696,7 @@ static void moveAxis(AxisEnum axis, const int8_t direction) {
NOMORE(ui.manual_move.offset, max - current_position[axis]);
#else
current_position[axis] += diff;
- const char *msg = PSTR(""); // clear the error
+ const char *msg = NUL_STR; // clear the error
if (direction < 0 && current_position[axis] < min) {
current_position[axis] = min;
msg = GET_TEXT(MSG_LCD_SOFT_ENDSTOPS);
@@ -889,37 +718,14 @@ static void moveAxis(AxisEnum axis, const int8_t direction) {
drawAxisValue(axis);
}
-static void e_plus() {
- moveAxis(E_AXIS, 1);
-}
-
-static void e_minus() {
- moveAxis(E_AXIS, -1);
-}
-
-static void x_minus() {
- moveAxis(X_AXIS, -1);
-}
-
-static void x_plus() {
- moveAxis(X_AXIS, 1);
-}
-
-static void y_plus() {
- moveAxis(Y_AXIS, 1);
-}
-
-static void y_minus() {
- moveAxis(Y_AXIS, -1);
-}
-
-static void z_plus() {
- moveAxis(Z_AXIS, 1);
-}
-
-static void z_minus() {
- moveAxis(Z_AXIS, -1);
-}
+static void e_plus() { moveAxis(E_AXIS, 1); }
+static void e_minus() { moveAxis(E_AXIS, -1); }
+static void x_minus() { moveAxis(X_AXIS, -1); }
+static void x_plus() { moveAxis(X_AXIS, 1); }
+static void y_plus() { moveAxis(Y_AXIS, 1); }
+static void y_minus() { moveAxis(Y_AXIS, -1); }
+static void z_plus() { moveAxis(Z_AXIS, 1); }
+static void z_minus() { moveAxis(Z_AXIS, -1); }
#if ENABLED(TOUCH_SCREEN)
static void e_select() {
@@ -1002,8 +808,9 @@ void MarlinUI::move_axis_screen() {
const bool busy = printingIsActive();
- // if we have baby step and we are printing, select baby step
- if (busy && ENABLED(BABYSTEP_ZPROBE_OFFSET)) motionAxisState.z_selection = Z_SELECTION_Z_PROBE;
+ // Babysteps during printing? Select babystep for Z probe offset
+ if (busy && ENABLED(BABYSTEP_ZPROBE_OFFSET))
+ motionAxisState.z_selection = Z_SELECTION_Z_PROBE;
// ROW 1 -> E- Y- CurY Z+
int x = X_MARGIN, y = Y_MARGIN, spacing = 0;
@@ -1089,7 +896,7 @@ void MarlinUI::move_axis_screen() {
TERN_(HAS_TFT_XPT2046, touch.add_control(BUTTON, motionAxisState.stepValuePos.x, motionAxisState.stepValuePos.y, CUR_STEP_VALUE_WIDTH, BTN_HEIGHT, (intptr_t)step_size));
}
- // alinged with x+
+ // aligned with x+
drawBtn(xplus_x, TFT_HEIGHT - Y_MARGIN - BTN_HEIGHT, "off", (intptr_t)disable_steppers, imgCancel, COLOR_WHITE, !busy);
TERN_(HAS_TFT_XPT2046, add_control(TFT_WIDTH - X_MARGIN - BTN_WIDTH, y, BACK, imgBack));
diff --git a/Marlin/src/lcd/tft/ui_480x320.h b/Marlin/src/lcd/tft/ui_480x320.h
index e3a688f112..fca9ed9c2a 100644
--- a/Marlin/src/lcd/tft/ui_480x320.h
+++ b/Marlin/src/lcd/tft/ui_480x320.h
@@ -21,97 +21,29 @@
*/
#pragma once
-#include "../../inc/MarlinConfigPre.h"
+#define MARLIN_LOGO_FULL_SIZE MarlinLogo480x320x16
-#include "tft.h"
-#include "tft_image.h"
+#include "ui_common.h"
-#if ENABLED(TOUCH_SCREEN)
- #include "touch.h"
-#endif
+#define TFT_STATUS_TOP_Y 4
+#define TFT_TOP_LINE_Y 4
-void draw_heater_status(uint16_t x, uint16_t y, const int8_t Heater);
-void draw_fan_status(uint16_t x, uint16_t y, const bool blink);
+#define MENU_TEXT_X_OFFSET 16
+#define MENU_TEXT_Y_OFFSET 7
-#define MENU_TEXT_X_OFFSET 16
-#define MENU_TEXT_Y_OFFSET 7
-void menu_line(const uint8_t row, uint16_t color = COLOR_BACKGROUND);
-void menu_item(const uint8_t row, bool sel = false);
+#define MENU_ITEM_ICON_X 5
+#define MENU_ITEM_ICON_Y 5
+#define MENU_ITEM_ICON_SPACE 42
#if HAS_UI_480x320
- #define MENU_FONT_NAME Helvetica18
- #define SYMBOLS_FONT_NAME Helvetica18_symbols
- #define MENU_ITEM_HEIGHT 43
- #define FONT_LINE_HEIGHT 34
+ #define MENU_FONT_NAME Helvetica18
+ #define SYMBOLS_FONT_NAME Helvetica18_symbols
+ #define MENU_ITEM_HEIGHT 43
+ #define FONT_LINE_HEIGHT 34
#elif HAS_UI_480x272
- #define MENU_FONT_NAME Helvetica14
- #define SYMBOLS_FONT_NAME Helvetica14_symbols
- #define MENU_ITEM_HEIGHT 36
- #define FONT_LINE_HEIGHT 24
-#endif
-
-#define ABSOLUTE_ZERO -273.15
-
-const tImage Images[imgCount] = {
- TERN(SHOW_BOOTSCREEN, TERN(BOOT_MARLIN_LOGO_SMALL, MarlinLogo195x59x16, MarlinLogo480x320x16), NoLogo),
- HotEnd_64x64x4,
- Bed_64x64x4,
- Bed_Heated_64x64x4,
- Chamber_64x64x4,
- Chamber_Heated_64x64x4,
- Fan0_64x64x4,
- Fan_Slow0_64x64x4,
- Fan_Slow1_64x64x4,
- Fan_Fast0_64x64x4,
- Fan_Fast1_64x64x4,
- Feedrate_32x32x4,
- Flowrate_32x32x4,
- SD_64x64x4,
- Menu_64x64x4,
- Settings_64x64x4,
- Directory_32x32x4,
- Confirm_64x64x4,
- Cancel_64x64x4,
- Increase_64x64x4,
- Decrease_64x64x4,
- Back_32x32x4,
- Up_32x32x4,
- Down_32x32x4,
- Left_32x32x4,
- Right_32x32x4,
- Refresh_32x32x4,
- Leveling_32x32x4,
- Slider8x16x4,
- Home_64x64x4,
- BtnRounded_64x52x4,
-};
-
-#if HAS_TEMP_CHAMBER && HOTENDS > 1
- #define ITEM_E0 0
- #define ITEM_E1 1
- #define ITEM_BED 2
- #define ITEM_CHAMBER 3
- #define ITEM_FAN 4
- #define ITEMS_COUNT 5
- #define POS_Y 4
-#elif HAS_TEMP_CHAMBER
- #define ITEM_E0 0
- #define ITEM_BED 1
- #define ITEM_CHAMBER 2
- #define ITEM_FAN 3
- #define ITEMS_COUNT 4
- #define POS_Y 4
-#elif HOTENDS > 1
- #define ITEM_E0 0
- #define ITEM_E1 1
- #define ITEM_BED 2
- #define ITEM_FAN 3
- #define ITEMS_COUNT 4
- #define POS_Y 4
-#else
- #define ITEM_E0 0
- #define ITEM_BED 1
- #define ITEM_FAN 2
- #define ITEMS_COUNT 3
- #define POS_Y 4
+ #define MENU_FONT_NAME Helvetica14
+ #define SYMBOLS_FONT_NAME Helvetica14_symbols
+ #define MENU_ITEM_HEIGHT 36
+ #define FONT_LINE_HEIGHT 24
#endif
+#define MENU_LINE_HEIGHT (MENU_ITEM_HEIGHT + 2)
diff --git a/Marlin/src/lcd/tft/ui_common.cpp b/Marlin/src/lcd/tft/ui_common.cpp
new file mode 100644
index 0000000000..842fc3909c
--- /dev/null
+++ b/Marlin/src/lcd/tft/ui_common.cpp
@@ -0,0 +1,246 @@
+/**
+ * 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 "../../inc/MarlinConfigPre.h"
+
+#if HAS_GRAPHICAL_TFT
+
+#include "ui_common.h"
+#include "../lcdprint.h"
+#include "../../libs/numtostr.h"
+#include "../menu/menu.h"
+
+void menu_pause_option();
+
+static xy_uint_t cursor;
+
+#if ENABLED(TOUCH_SCREEN)
+ bool draw_menu_navigation = false;
+#endif
+
+void menu_line(const uint8_t row, uint16_t color) {
+ cursor.set(0, row);
+ tft.canvas(0, TFT_TOP_LINE_Y + cursor.y * MENU_LINE_HEIGHT, TFT_WIDTH, MENU_ITEM_HEIGHT);
+ tft.set_background(color);
+}
+
+void menu_item(const uint8_t row, bool sel ) {
+ #if ENABLED(TOUCH_SCREEN)
+ if (row == 0) {
+ touch.clear();
+ draw_menu_navigation = TERN(ADVANCED_PAUSE_FEATURE, ui.currentScreen != menu_pause_option, true);
+ }
+ #endif
+
+ menu_line(row, sel ? COLOR_SELECTION_BG : COLOR_BACKGROUND);
+ #if ENABLED(TOUCH_SCREEN)
+ const TouchControlType tct = TERN(SINGLE_TOUCH_NAVIGATION, true, sel) ? MENU_CLICK : MENU_ITEM;
+ touch.add_control(tct, 0, TFT_TOP_LINE_Y + row * MENU_LINE_HEIGHT, TFT_WIDTH, MENU_ITEM_HEIGHT, encoderTopLine + row);
+ #endif
+}
+
+//
+// lcdprint.h functions
+//
+
+#define TFT_COL_WIDTH ((TFT_WIDTH) / (LCD_WIDTH))
+
+void lcd_gotopixel(const uint16_t x, const uint16_t y) {
+ if (x >= TFT_WIDTH) return;
+ cursor.set(x / (TFT_COL_WIDTH), y / MENU_LINE_HEIGHT);
+ tft.canvas(x, TFT_TOP_LINE_Y + y, (TFT_WIDTH) - x, MENU_ITEM_HEIGHT);
+ tft.set_background(COLOR_BACKGROUND);
+}
+
+void lcd_moveto(const lcd_uint_t col, const lcd_uint_t row) {
+ lcd_gotopixel(int(col) * (TFT_COL_WIDTH), int(row) * MENU_LINE_HEIGHT);
+}
+
+int lcd_put_wchar_max(wchar_t c, pixel_len_t max_length) {
+ if (max_length < 1) return 0;
+ tft_string.set();
+ tft_string.add(c);
+ tft.add_text(MENU_TEXT_X_OFFSET, MENU_TEXT_Y_OFFSET, COLOR_MENU_TEXT, tft_string);
+ lcd_gotopixel((cursor.x + 1) * (TFT_COL_WIDTH) + tft_string.width(), cursor.y * MENU_LINE_HEIGHT);
+ return tft_string.width();
+}
+
+int lcd_put_u8str_max_P(PGM_P utf8_str_P, pixel_len_t max_length) {
+ if (max_length < 1) return 0;
+ tft_string.set(utf8_str_P);
+ tft_string.trim();
+ tft_string.truncate(max_length);
+ tft.add_text(MENU_TEXT_X_OFFSET, MENU_TEXT_Y_OFFSET, COLOR_MENU_TEXT, tft_string);
+ lcd_gotopixel((cursor.x + 1) * (TFT_COL_WIDTH) + tft_string.width(), cursor.y * MENU_LINE_HEIGHT);
+ return tft_string.width();
+}
+
+int lcd_put_u8str_max(const char * utf8_str, pixel_len_t max_length) {
+ return lcd_put_u8str_max_P(utf8_str, max_length);
+}
+
+void lcd_put_int(const int i) {
+ // 3 digits max for this one...
+ const char* str = i16tostr3left(int16_t(i));
+ lcd_put_u8str_max(str, 3);
+}
+
+//
+// Menu Item methods
+//
+
+// Draw a generic menu item with pre_char (if selected) and post_char
+void MenuItemBase::_draw(const bool sel, const uint8_t row, PGM_P const pstr, const char pre_char, const char post_char) {
+ menu_item(row, sel);
+
+ uint8_t *string = (uint8_t *)pstr;
+ MarlinImage image = noImage;
+ switch (*string) {
+ case 0x01: image = imgRefresh; break; // LCD_STR_REFRESH
+ case 0x02: image = imgDirectory; break; // LCD_STR_FOLDER
+ }
+
+ uint8_t offset = MENU_TEXT_X_OFFSET;
+ if (image != noImage) {
+ string++;
+ offset = MENU_ITEM_ICON_SPACE;
+ tft.add_image(MENU_ITEM_ICON_X, MENU_ITEM_ICON_Y, image, COLOR_MENU_TEXT, sel ? COLOR_SELECTION_BG : COLOR_BACKGROUND);
+ }
+
+ tft_string.set(string, itemIndex, itemString);
+ tft.add_text(offset, MENU_TEXT_Y_OFFSET, COLOR_MENU_TEXT, tft_string);
+}
+
+// Draw a menu item with a (potentially) editable value
+void MenuEditItemBase::draw(const bool sel, const uint8_t row, PGM_P const pstr, const char* const data, const bool pgm) {
+ menu_item(row, sel);
+
+ tft_string.set(pstr, itemIndex, itemString);
+ tft.add_text(MENU_TEXT_X_OFFSET, MENU_TEXT_Y_OFFSET, COLOR_MENU_TEXT, tft_string);
+ if (data) {
+ tft_string.set(data);
+ tft.add_text(TFT_WIDTH - MENU_TEXT_X_OFFSET - tft_string.width(), MENU_TEXT_Y_OFFSET, COLOR_MENU_VALUE, tft_string);
+ }
+}
+
+// Draw a static item with no left-right margin required. Centered by default.
+void MenuItem_static::draw(const uint8_t row, PGM_P const pstr, const uint8_t style/*=SS_DEFAULT*/, const char * const vstr/*=nullptr*/) {
+ menu_item(row);
+ tft_string.set(pstr, itemIndex, itemString);
+ if (vstr)
+ tft_string.add(vstr);
+ tft.add_text(tft_string.center(TFT_WIDTH), MENU_TEXT_Y_OFFSET, COLOR_YELLOW, tft_string);
+}
+
+#if ENABLED(SDSUPPORT)
+
+ void MenuItem_sdbase::draw(const bool sel, const uint8_t row, PGM_P const, CardReader &theCard, const bool isDir) {
+ menu_item(row, sel);
+ if (isDir)
+ tft.add_image(MENU_ITEM_ICON_X, MENU_ITEM_ICON_Y, imgDirectory, COLOR_MENU_TEXT, sel ? COLOR_SELECTION_BG : COLOR_BACKGROUND);
+ tft.add_text(MENU_ITEM_ICON_SPACE, MENU_TEXT_Y_OFFSET, COLOR_MENU_TEXT, theCard.longest_filename());
+ }
+
+#endif
+
+//
+// MarlinUI methods
+//
+
+bool MarlinUI::detected() { return true; }
+
+void MarlinUI::init_lcd() {
+ tft.init();
+ tft.set_font(MENU_FONT_NAME);
+ #ifdef SYMBOLS_FONT_NAME
+ tft.add_glyphs(SYMBOLS_FONT_NAME);
+ #endif
+ TERN_(TOUCH_SCREEN, touch.init());
+ clear_lcd();
+}
+
+void MarlinUI::clear_lcd() {
+ #if ENABLED(TOUCH_SCREEN)
+ touch.reset();
+ draw_menu_navigation = false;
+ #endif
+
+ tft.queue.reset();
+ tft.fill(0, 0, TFT_WIDTH, TFT_HEIGHT, COLOR_BACKGROUND);
+ cursor.set(0, 0);
+}
+
+#if ENABLED(TOUCH_SCREEN_CALIBRATION)
+
+ void MarlinUI::touch_calibration_screen() {
+ uint16_t x, y;
+
+ calibrationState calibration_stage = touch_calibration.get_calibration_state();
+
+ if (calibration_stage == CALIBRATION_NONE) {
+ defer_status_screen(true);
+ clear_lcd();
+ calibration_stage = touch_calibration.calibration_start();
+ }
+ else {
+ x = touch_calibration.calibration_points[_MIN(calibration_stage - 1, CALIBRATION_BOTTOM_RIGHT)].x;
+ y = touch_calibration.calibration_points[_MIN(calibration_stage - 1, CALIBRATION_BOTTOM_RIGHT)].y;
+ tft.canvas(x - 15, y - 15, 31, 31);
+ tft.set_background(COLOR_BACKGROUND);
+ }
+
+ touch.clear();
+
+ if (calibration_stage < CALIBRATION_SUCCESS) {
+ switch (calibration_stage) {
+ case CALIBRATION_TOP_LEFT: tft_string.set(GET_TEXT(MSG_TOP_LEFT)); break;
+ case CALIBRATION_BOTTOM_LEFT: tft_string.set(GET_TEXT(MSG_BOTTOM_LEFT)); break;
+ case CALIBRATION_TOP_RIGHT: tft_string.set(GET_TEXT(MSG_TOP_RIGHT)); break;
+ case CALIBRATION_BOTTOM_RIGHT: tft_string.set(GET_TEXT(MSG_BOTTOM_RIGHT)); break;
+ default: break;
+ }
+
+ x = touch_calibration.calibration_points[calibration_stage].x;
+ y = touch_calibration.calibration_points[calibration_stage].y;
+
+ tft.canvas(x - 15, y - 15, 31, 31);
+ tft.set_background(COLOR_BACKGROUND);
+ tft.add_bar(0, 15, 31, 1, COLOR_TOUCH_CALIBRATION);
+ tft.add_bar(15, 0, 1, 31, COLOR_TOUCH_CALIBRATION);
+
+ touch.add_control(CALIBRATE, 0, 0, TFT_WIDTH, TFT_HEIGHT, uint32_t(x) << 16 | uint32_t(y));
+ }
+ else {
+ tft_string.set(calibration_stage == CALIBRATION_SUCCESS ? GET_TEXT(MSG_CALIBRATION_COMPLETED) : GET_TEXT(MSG_CALIBRATION_FAILED));
+ defer_status_screen(false);
+ touch_calibration.calibration_end();
+ touch.add_control(BACK, 0, 0, TFT_WIDTH, TFT_HEIGHT);
+ }
+
+ tft.canvas(0, (TFT_HEIGHT - tft_string.font_height()) >> 1, TFT_WIDTH, tft_string.font_height());
+ tft.set_background(COLOR_BACKGROUND);
+ tft.add_text(tft_string.center(TFT_WIDTH), 0, COLOR_MENU_TEXT, tft_string);
+ }
+
+#endif // TOUCH_SCREEN_CALIBRATION
+
+#endif // HAS_GRAPHICAL_TFT
diff --git a/Marlin/src/lcd/tft/ui_common.h b/Marlin/src/lcd/tft/ui_common.h
new file mode 100644
index 0000000000..d40e471171
--- /dev/null
+++ b/Marlin/src/lcd/tft/ui_common.h
@@ -0,0 +1,76 @@
+/**
+ * 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"
+
+#if !HAS_LCD_MENU
+ #error "Seriously? High resolution TFT screen without menu?"
+#endif
+
+#include "tft.h"
+#include "tft_image.h"
+
+#if ENABLED(TOUCH_SCREEN)
+ #include "touch.h"
+ extern bool draw_menu_navigation;
+#endif
+
+#if HAS_UI_320x240
+ #include "ui_320x240.h"
+#elif HAS_UI_480x320 || HAS_UI_480x272
+ #include "ui_480x320.h"
+#endif
+
+void draw_heater_status(uint16_t x, uint16_t y, const int8_t Heater);
+void draw_fan_status(uint16_t x, uint16_t y, const bool blink);
+
+void menu_line(const uint8_t row, uint16_t color=COLOR_BACKGROUND);
+void menu_item(const uint8_t row, bool sel = false);
+
+#define ABSOLUTE_ZERO -273.15
+
+#if HAS_TEMP_CHAMBER && HOTENDS > 1
+ #define ITEM_E0 0
+ #define ITEM_E1 1
+ #define ITEM_BED 2
+ #define ITEM_CHAMBER 3
+ #define ITEM_FAN 4
+ #define ITEMS_COUNT 5
+#elif HAS_TEMP_CHAMBER
+ #define ITEM_E0 0
+ #define ITEM_BED 1
+ #define ITEM_CHAMBER 2
+ #define ITEM_FAN 3
+ #define ITEMS_COUNT 4
+#elif HOTENDS > 1
+ #define ITEM_E0 0
+ #define ITEM_E1 1
+ #define ITEM_BED 2
+ #define ITEM_FAN 3
+ #define ITEMS_COUNT 4
+#else
+ #define ITEM_E0 0
+ #define ITEM_BED 1
+ #define ITEM_FAN 2
+ #define ITEMS_COUNT 3
+#endif
diff --git a/Marlin/src/libs/BL24CXX.cpp b/Marlin/src/libs/BL24CXX.cpp
index d34ed8340f..8de320d576 100644
--- a/Marlin/src/libs/BL24CXX.cpp
+++ b/Marlin/src/libs/BL24CXX.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/libs/autoreport.h b/Marlin/src/libs/autoreport.h
new file mode 100644
index 0000000000..9bde9f29fb
--- /dev/null
+++ b/Marlin/src/libs/autoreport.h
@@ -0,0 +1,49 @@
+/**
+ * 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/MarlinConfig.h"
+
+template
+class AutoReporter {
+public:
+ millis_t next_report_ms;
+ uint8_t report_interval;
+
+ // Override this method
+ inline void auto_report() { }
+
+ inline void set_interval(uint8_t seconds, const uint8_t limit=60) {
+ report_interval = _MIN(seconds, limit);
+ next_report_ms = millis() + SEC_TO_MS(seconds);
+ }
+
+ inline void tick() {
+ if (!report_interval) return;
+ const millis_t ms = millis();
+ if (ELAPSED(ms, next_report_ms)) {
+ next_report_ms = ms + SEC_TO_MS(report_interval);
+ PORT_REDIRECT(AR_PORT_INDEX);
+ auto_report();
+ }
+ }
+};
diff --git a/Marlin/src/libs/stopwatch.h b/Marlin/src/libs/stopwatch.h
index 6e8e95a9a5..b64a36a90e 100644
--- a/Marlin/src/libs/stopwatch.h
+++ b/Marlin/src/libs/stopwatch.h
@@ -56,6 +56,7 @@ class Stopwatch {
* @return true on success
*/
static bool stop();
+ static inline bool abort() { return stop(); } // Alias by default
/**
* @brief Pause the stopwatch
diff --git a/Marlin/src/libs/vector_3.cpp b/Marlin/src/libs/vector_3.cpp
index fd93ba09ad..6f87a523e0 100644
--- a/Marlin/src/libs/vector_3.cpp
+++ b/Marlin/src/libs/vector_3.cpp
@@ -76,8 +76,6 @@ void vector_3::apply_rotation(const matrix_3x3 &matrix) {
matrix.vectors[0][2] * _x + matrix.vectors[1][2] * _y + matrix.vectors[2][2] * _z };
}
-extern const char SP_X_STR[], SP_Y_STR[], SP_Z_STR[];
-
void vector_3::debug(PGM_P const title) {
serialprintPGM(title);
SERIAL_ECHOPAIR_F_P(SP_X_STR, x, 6);
diff --git a/Marlin/src/module/endstops.cpp b/Marlin/src/module/endstops.cpp
index b1c7c1c585..b9d2c1cdf5 100644
--- a/Marlin/src/module/endstops.cpp
+++ b/Marlin/src/module/endstops.cpp
@@ -27,7 +27,6 @@
#include "endstops.h"
#include "stepper.h"
-#include "../MarlinCore.h"
#include "../sd/cardreader.h"
#include "temperature.h"
#include "../lcd/marlinui.h"
diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp
index 99853f24df..f7fc66b27a 100644
--- a/Marlin/src/module/motion.cpp
+++ b/Marlin/src/module/motion.cpp
@@ -236,8 +236,17 @@ void report_current_position_projected() {
}
/**
- * sync_plan_position
- *
+ * Run out the planner buffer and re-sync the current
+ * position from the last-updated stepper positions.
+ */
+void quickstop_stepper() {
+ planner.quick_stop();
+ planner.synchronize();
+ set_current_from_steppers_for_axis(ALL_AXES);
+ sync_plan_position();
+}
+
+/**
* Set the planner/stepper positions directly from current_position with
* no kinematic translation. Used for homing axes and cartesian/core syncing.
*/
diff --git a/Marlin/src/module/motion.h b/Marlin/src/module/motion.h
index 9352a4e4e6..887da1aa18 100644
--- a/Marlin/src/module/motion.h
+++ b/Marlin/src/module/motion.h
@@ -212,6 +212,8 @@ void report_current_position_projected();
void get_cartesian_from_steppers();
void set_current_from_steppers_for_axis(const AxisEnum axis);
+void quickstop_stepper();
+
/**
* sync_plan_position
*
diff --git a/Marlin/src/module/printcounter.cpp b/Marlin/src/module/printcounter.cpp
index ab87717f01..45072c8f01 100644
--- a/Marlin/src/module/printcounter.cpp
+++ b/Marlin/src/module/printcounter.cpp
@@ -41,6 +41,10 @@ Stopwatch print_job_timer; // Global Print Job Timer instance
#include "../libs/buzzer.h"
#endif
+#if PRINTCOUNTER_SYNC
+ #include "../module/planner.h"
+#endif
+
// Service intervals
#if HAS_SERVICE_INTERVALS
#if SERVICE_INTERVAL_1 > 0
@@ -160,6 +164,8 @@ void PrintCounter::saveStats() {
// Refuses to save data if object is not loaded
if (!isLoaded()) return;
+ TERN_(PRINTCOUNTER_SYNC, planner.synchronize());
+
// Saves the struct to EEPROM
persistentStore.access_start();
persistentStore.write_data(address + sizeof(uint8_t), (uint8_t*)&data, sizeof(printStatistics));
@@ -224,9 +230,12 @@ void PrintCounter::tick() {
millis_t now = millis();
- static uint32_t update_next; // = 0
+ static millis_t update_next; // = 0
if (ELAPSED(now, update_next)) {
+ update_next = now + updateInterval;
+
TERN_(DEBUG_PRINTCOUNTER, debug(PSTR("tick")));
+
millis_t delta = deltaDuration();
data.printTime += delta;
@@ -239,15 +248,15 @@ void PrintCounter::tick() {
#if SERVICE_INTERVAL_3 > 0
data.nextService3 -= _MIN(delta, data.nextService3);
#endif
-
- update_next = now + updateInterval * 1000;
}
- static uint32_t eeprom_next; // = 0
- if (ELAPSED(now, eeprom_next)) {
- eeprom_next = now + saveInterval * 1000;
- saveStats();
- }
+ #if PRINTCOUNTER_SAVE_INTERVAL > 0
+ static millis_t eeprom_next; // = 0
+ if (ELAPSED(now, eeprom_next)) {
+ eeprom_next = now + saveInterval;
+ saveStats();
+ }
+ #endif
}
// @Override
@@ -267,21 +276,20 @@ bool PrintCounter::start() {
return false;
}
-// @Override
-bool PrintCounter::stop() {
+bool PrintCounter::_stop(const bool completed) {
TERN_(DEBUG_PRINTCOUNTER, debug(PSTR("stop")));
- if (super::stop()) {
- data.finishedPrints++;
+ const bool did_stop = super::stop();
+ if (did_stop) {
data.printTime += deltaDuration();
-
- if (duration() > data.longestPrint)
- data.longestPrint = duration();
-
- saveStats();
- return true;
+ if (completed) {
+ data.finishedPrints++;
+ if (duration() > data.longestPrint)
+ data.longestPrint = duration();
+ }
}
- else return false;
+ saveStats();
+ return did_stop;
}
// @Override
diff --git a/Marlin/src/module/printcounter.h b/Marlin/src/module/printcounter.h
index 66d8cbb7b3..4deae45a65 100644
--- a/Marlin/src/module/printcounter.h
+++ b/Marlin/src/module/printcounter.h
@@ -71,19 +71,18 @@ class PrintCounter: public Stopwatch {
* @brief Interval in seconds between counter updates
* @details This const value defines what will be the time between each
* accumulator update. This is different from the EEPROM save interval.
- *
- * @note The max value for this option is 60(s), otherwise integer
- * overflow will happen.
*/
- static constexpr uint16_t updateInterval = 10;
+ static constexpr millis_t updateInterval = SEC_TO_MS(10);
- /**
- * @brief Interval in seconds between EEPROM saves
- * @details This const value defines what will be the time between each
- * EEPROM save cycle, the development team recommends to set this value
- * no lower than 3600 secs (1 hour).
- */
- static constexpr uint16_t saveInterval = 3600;
+ #if PRINTCOUNTER_SAVE_INTERVAL > 0
+ /**
+ * @brief Interval in seconds between EEPROM saves
+ * @details This const value defines what will be the time between each
+ * EEPROM save cycle, the development team recommends to set this value
+ * no lower than 3600 secs (1 hour).
+ */
+ static constexpr millis_t saveInterval = MIN_TO_MS(PRINTCOUNTER_SAVE_INTERVAL);
+ #endif
/**
* @brief Timestamp of the last call to deltaDuration()
@@ -176,7 +175,10 @@ class PrintCounter: public Stopwatch {
* The following functions are being overridden
*/
static bool start();
- static bool stop();
+ static bool _stop(const bool completed);
+ static inline bool stop() { return _stop(true); }
+ static inline bool abort() { return _stop(false); }
+
static void reset();
#if HAS_SERVICE_INTERVALS
diff --git a/Marlin/src/module/probe.cpp b/Marlin/src/module/probe.cpp
index cc5c5e8815..94c409eb72 100644
--- a/Marlin/src/module/probe.cpp
+++ b/Marlin/src/module/probe.cpp
@@ -38,7 +38,7 @@
#include "../gcode/gcode.h"
#include "../lcd/marlinui.h"
-#include "../MarlinCore.h" // for stop(), disable_e_steppers
+#include "../MarlinCore.h" // for stop(), disable_e_steppers(), wait_for_user_response()
#if HAS_LEVELING
#include "../feature/bedlevel/bedlevel.h"
diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp
index 58cdd5296f..6908635d6e 100644
--- a/Marlin/src/module/settings.cpp
+++ b/Marlin/src/module/settings.cpp
@@ -36,7 +36,7 @@
*/
// Change EEPROM version if the structure changes
-#define EEPROM_VERSION "V82"
+#define EEPROM_VERSION "V83"
#define EEPROM_OFFSET 100
// Check the integrity of data offsets.
@@ -176,8 +176,6 @@ static const uint32_t _DMA[] PROGMEM = DEFAULT_MAX_ACCELERATION;
static const float _DASU[] PROGMEM = DEFAULT_AXIS_STEPS_PER_UNIT;
static const feedRate_t _DMF[] PROGMEM = DEFAULT_MAX_FEEDRATE;
-extern const char SP_X_STR[], SP_Y_STR[], SP_Z_STR[], SP_E_STR[];
-
/**
* Current EEPROM Layout
*
@@ -457,6 +455,11 @@ typedef struct SettingsDataStruct {
#if ENABLED(SOUND_MENU_ITEM)
bool buzzer_enabled;
#endif
+
+ #if HAS_MULTI_LANGUAGE
+ uint8_t ui_language; // M414 S
+ #endif
+
} SettingsData;
//static_assert(sizeof(SettingsData) <= MARLIN_EEPROM_SIZE, "EEPROM too small to contain SettingsData!");
@@ -1382,6 +1385,13 @@ void MarlinSettings::postprocess() {
EEPROM_WRITE(ui.buzzer_enabled);
#endif
+ //
+ // Selected LCD language
+ //
+ #if HAS_MULTI_LANGUAGE
+ EEPROM_WRITE(ui.language);
+ #endif
+
//
// Report final CRC and Data Size
//
@@ -2261,6 +2271,18 @@ void MarlinSettings::postprocess() {
EEPROM_READ(ui.buzzer_enabled);
#endif
+ //
+ // Selected LCD language
+ //
+ #if HAS_MULTI_LANGUAGE
+ {
+ uint8_t ui_language;
+ EEPROM_READ(ui_language);
+ if (ui_language >= NUM_LANGUAGES) ui_language = 0;
+ ui.set_language(ui_language);
+ }
+ #endif
+
//
// Validate Final Size and CRC
//
@@ -3157,7 +3179,7 @@ void MarlinSettings::reset() {
#elif ENABLED(AUTO_BED_LEVELING_UBL)
- config_heading(forReplay, PSTR(""), false);
+ config_heading(forReplay, NUL_STR, false);
if (!forReplay) {
ubl.echo_name();
SERIAL_CHAR(':');
@@ -3846,6 +3868,11 @@ void MarlinSettings::reset() {
CONFIG_ECHO_START(); SERIAL_ECHO_SP(2); M553_report();
CONFIG_ECHO_START(); SERIAL_ECHO_SP(2); M554_report();
#endif
+
+ #if HAS_MULTI_LANGUAGE
+ CONFIG_ECHO_HEADING("UI Language:");
+ SERIAL_ECHO_MSG(" M414 S", int(ui.language));
+ #endif
}
#endif // !DISABLE_M503
diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp
index 85222a3463..e1fd00dcd6 100644
--- a/Marlin/src/module/temperature.cpp
+++ b/Marlin/src/module/temperature.cpp
@@ -27,14 +27,17 @@
// Useful when debugging thermocouples
//#define IGNORE_THERMOCOUPLE_ERRORS
+#include "../MarlinCore.h"
+#include "../HAL/shared/Delay.h"
+#include "../lcd/marlinui.h"
+
#include "temperature.h"
#include "endstops.h"
-
-#include "../MarlinCore.h"
#include "planner.h"
-#include "../HAL/shared/Delay.h"
-#include "../lcd/marlinui.h"
+#if ENABLED(EMERGENCY_PARSER)
+ #include "motion.h"
+#endif
#if ENABLED(DWIN_CREALITY_LCD)
#include "../lcd/dwin/e3v2/dwin.h"
@@ -250,7 +253,7 @@ const char str_t_thermal_runaway[] PROGMEM = STR_T_THERMAL_RUNAWAY,
*/
void Temperature::report_fan_speed(const uint8_t target) {
if (target >= FAN_COUNT) return;
- PORT_REDIRECT(SERIAL_BOTH);
+ PORT_REDIRECT(SERIAL_ALL);
SERIAL_ECHOLNPAIR("M106 P", target, " S", fan_speed[target]);
}
#endif
@@ -377,6 +380,13 @@ volatile bool Temperature::raw_temps_ready = false;
Temperature::soft_pwm_count_fan[FAN_COUNT];
#endif
+#if ENABLED(SINGLENOZZLE_STANDBY_TEMP)
+ uint16_t Temperature::singlenozzle_temp[EXTRUDERS];
+ #if HAS_FAN
+ uint8_t Temperature::singlenozzle_fan_speed[EXTRUDERS];
+ #endif
+#endif
+
#if ENABLED(PROBING_HEATERS_OFF)
bool Temperature::paused;
#endif
@@ -1266,7 +1276,7 @@ void Temperature::manage_heater() {
// temperature didn't drop at least MIN_COOLING_SLOPE_DEG_CHAMBER_VENT
if (next_cool_check_ms_2 == 0 || ELAPSED(ms, next_cool_check_ms_2)) {
if (old_temp - temp_chamber.celsius < float(MIN_COOLING_SLOPE_DEG_CHAMBER_VENT)) flag_chamber_excess_heat = true; //the bed is heating the chamber too much
- next_cool_check_ms_2 = ms + 1000UL * MIN_COOLING_SLOPE_TIME_CHAMBER_VENT;
+ next_cool_check_ms_2 = ms + SEC_TO_MS(MIN_COOLING_SLOPE_TIME_CHAMBER_VENT);
old_temp = temp_chamber.celsius;
}
}
@@ -2176,7 +2186,6 @@ void Temperature::disable_all_heaters() {
#endif
-
#if ENABLED(PROBING_HEATERS_OFF)
void Temperature::pause(const bool p) {
@@ -2195,6 +2204,24 @@ void Temperature::disable_all_heaters() {
#endif // PROBING_HEATERS_OFF
+#if ENABLED(SINGLENOZZLE_STANDBY_TEMP)
+
+ void Temperature::singlenozzle_change(const uint8_t old_tool, const uint8_t new_tool) {
+ #if HAS_FAN
+ singlenozzle_fan_speed[old_tool] = fan_speed[0];
+ fan_speed[0] = singlenozzle_fan_speed[new_tool];
+ #endif
+ singlenozzle_temp[old_tool] = temp_hotend[0].target;
+ if (singlenozzle_temp[new_tool] && singlenozzle_temp[new_tool] != singlenozzle_temp[old_tool]) {
+ setTargetHotend(singlenozzle_temp[new_tool], 0);
+ TERN_(AUTOTEMP, planner.autotemp_update());
+ TERN_(HAS_DISPLAY, set_heating_message(0));
+ (void)wait_for_hotend(0, false); // Wait for heating or cooling
+ }
+ }
+
+#endif
+
#if HAS_MAX6675
#ifndef THERMOCOUPLE_MAX_ERRORS
@@ -3096,20 +3123,12 @@ void Temperature::tick() {
}
#if ENABLED(AUTO_REPORT_TEMPERATURES)
-
- uint8_t Temperature::auto_report_temp_interval;
- millis_t Temperature::next_temp_report_ms;
-
- void Temperature::auto_report_temperatures() {
- if (auto_report_temp_interval && ELAPSED(millis(), next_temp_report_ms)) {
- next_temp_report_ms = millis() + 1000UL * auto_report_temp_interval;
- PORT_REDIRECT(SERIAL_BOTH);
- print_heater_states(active_extruder);
- SERIAL_EOL();
- }
+ Temperature::AutoReportTemp Temperature::auto_reporter;
+ void Temperature::AutoReportTemp::auto_report() {
+ print_heater_states(active_extruder);
+ SERIAL_EOL();
}
-
- #endif // AUTO_REPORT_TEMPERATURES
+ #endif
#if HAS_HOTEND && HAS_DISPLAY
void Temperature::set_heating_message(const uint8_t e) {
@@ -3225,7 +3244,7 @@ void Temperature::tick() {
// if the temperature did not drop at least MIN_COOLING_SLOPE_DEG
if (!next_cool_check_ms || ELAPSED(now, next_cool_check_ms)) {
if (old_temp - temp < float(MIN_COOLING_SLOPE_DEG)) break;
- next_cool_check_ms = now + 1000UL * MIN_COOLING_SLOPE_TIME;
+ next_cool_check_ms = now + SEC_TO_MS(MIN_COOLING_SLOPE_TIME);
old_temp = temp;
}
}
@@ -3350,7 +3369,7 @@ void Temperature::tick() {
// if the temperature did not drop at least MIN_COOLING_SLOPE_DEG_BED
if (!next_cool_check_ms || ELAPSED(now, next_cool_check_ms)) {
if (old_temp - temp < float(MIN_COOLING_SLOPE_DEG_BED)) break;
- next_cool_check_ms = now + 1000UL * MIN_COOLING_SLOPE_TIME_BED;
+ next_cool_check_ms = now + SEC_TO_MS(MIN_COOLING_SLOPE_TIME_BED);
old_temp = temp;
}
}
@@ -3434,7 +3453,7 @@ void Temperature::tick() {
SERIAL_ECHOLNPGM("Timed out waiting for probe temperature.");
break;
}
- next_delta_check_ms = now + 1000UL * MIN_DELTA_SLOPE_TIME_PROBE;
+ next_delta_check_ms = now + SEC_TO_MS(MIN_DELTA_SLOPE_TIME_PROBE);
old_temp = temp;
}
@@ -3539,7 +3558,7 @@ void Temperature::tick() {
// if the temperature did not drop at least MIN_COOLING_SLOPE_DEG_CHAMBER
if (!next_cool_check_ms || ELAPSED(now, next_cool_check_ms)) {
if (old_temp - temp < float(MIN_COOLING_SLOPE_DEG_CHAMBER)) break;
- next_cool_check_ms = now + 1000UL * MIN_COOLING_SLOPE_TIME_CHAMBER;
+ next_cool_check_ms = now + SEC_TO_MS(MIN_COOLING_SLOPE_TIME_CHAMBER);
old_temp = temp;
}
}
diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h
index f570fe2107..1401e0d354 100644
--- a/Marlin/src/module/temperature.h
+++ b/Marlin/src/module/temperature.h
@@ -33,6 +33,10 @@
#include "../feature/power.h"
#endif
+#if ENABLED(AUTO_REPORT_TEMPERATURES)
+ #include "../libs/autoreport.h"
+#endif
+
#ifndef SOFT_PWM_SCALE
#define SOFT_PWM_SCALE 0
#endif
@@ -335,6 +339,14 @@ class Temperature {
FORCE_INLINE static bool hotEnoughToExtrude(const uint8_t e) { return !tooColdToExtrude(e); }
FORCE_INLINE static bool targetHotEnoughToExtrude(const uint8_t e) { return !targetTooColdToExtrude(e); }
+ #if ENABLED(SINGLENOZZLE_STANDBY_FAN)
+ static uint16_t singlenozzle_temp[EXTRUDERS];
+ #if HAS_FAN
+ static uint8_t singlenozzle_fan_speed[EXTRUDERS];
+ #endif
+ static void singlenozzle_change(const uint8_t old_tool, const uint8_t new_tool);
+ #endif
+
#if HEATER_IDLE_HANDLER
// Heater idle handling. Marlin creates one per hotend and one for the heated bed.
@@ -786,14 +798,8 @@ class Temperature {
#endif
);
#if ENABLED(AUTO_REPORT_TEMPERATURES)
- static uint8_t auto_report_temp_interval;
- static millis_t next_temp_report_ms;
- static void auto_report_temperatures();
- static inline void set_auto_report_interval(uint8_t v) {
- NOMORE(v, 60);
- auto_report_temp_interval = v;
- next_temp_report_ms = millis() + 1000UL * v;
- }
+ class AutoReportTemp : public AutoReporter { void auto_report(); };
+ static AutoReportTemp auto_reporter;
#endif
#endif
diff --git a/Marlin/src/module/tool_change.cpp b/Marlin/src/module/tool_change.cpp
index 95f32f2faa..867ae5d927 100644
--- a/Marlin/src/module/tool_change.cpp
+++ b/Marlin/src/module/tool_change.cpp
@@ -49,14 +49,6 @@
bool toolchange_extruder_ready[EXTRUDERS];
#endif
-#if ENABLED(SINGLENOZZLE_STANDBY_TEMP)
- uint16_t singlenozzle_temp[EXTRUDERS];
-#endif
-
-#if BOTH(HAS_FAN, SINGLENOZZLE_STANDBY_FAN)
- uint8_t singlenozzle_fan_speed[EXTRUDERS];
-#endif
-
#if ENABLED(MAGNETIC_PARKING_EXTRUDER) || defined(EVENT_GCODE_AFTER_TOOLCHANGE) || (ENABLED(PARKING_EXTRUDER) && PARKING_EXTRUDER_SOLENOIDS_DELAY > 0)
#include "../gcode/gcode.h"
#endif
@@ -836,7 +828,7 @@ inline void fast_line_to_current(const AxisEnum fr_axis) { _line_to_current(fr_a
// Cool down with fan
#if HAS_FAN && TOOLCHANGE_FS_FAN >= 0
thermalManager.fan_speed[TOOLCHANGE_FS_FAN] = toolchange_settings.fan_speed;
- gcode.dwell(toolchange_settings.fan_time * 1000);
+ gcode.dwell(SEC_TO_MS(toolchange_settings.fan_time));
thermalManager.fan_speed[TOOLCHANGE_FS_FAN] = 0;
#endif
@@ -1081,20 +1073,7 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) {
const bool should_move = safe_to_move && !no_move && IsRunning();
if (should_move) {
- #if BOTH(HAS_FAN, SINGLENOZZLE_STANDBY_FAN)
- singlenozzle_fan_speed[old_tool] = thermalManager.fan_speed[0];
- thermalManager.fan_speed[0] = singlenozzle_fan_speed[new_tool];
- #endif
-
- #if ENABLED(SINGLENOZZLE_STANDBY_TEMP)
- singlenozzle_temp[old_tool] = thermalManager.temp_hotend[0].target;
- if (singlenozzle_temp[new_tool] && singlenozzle_temp[new_tool] != singlenozzle_temp[old_tool]) {
- thermalManager.setTargetHotend(singlenozzle_temp[new_tool], 0);
- TERN_(AUTOTEMP, planner.autotemp_update());
- TERN_(HAS_DISPLAY, thermalManager.set_heating_message(0));
- (void)thermalManager.wait_for_hotend(0, false); // Wait for heating or cooling
- }
- #endif
+ TERN_(SINGLENOZZLE_STANDBY_TEMP, thermalManager.singlenozzle_change(old_tool, new_tool));
#if ENABLED(TOOLCHANGE_FILAMENT_SWAP)
if (should_swap && !too_cold) {
@@ -1123,7 +1102,7 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) {
// Cool down with fan
#if HAS_FAN && TOOLCHANGE_FS_FAN >= 0
thermalManager.fan_speed[TOOLCHANGE_FS_FAN] = toolchange_settings.fan_speed;
- gcode.dwell(toolchange_settings.fan_time * 1000);
+ gcode.dwell(SEC_TO_MS(toolchange_settings.fan_time));
thermalManager.fan_speed[TOOLCHANGE_FS_FAN] = 0;
#endif
}
diff --git a/Marlin/src/module/tool_change.h b/Marlin/src/module/tool_change.h
index 6b739604f0..4f88ca7432 100644
--- a/Marlin/src/module/tool_change.h
+++ b/Marlin/src/module/tool_change.h
@@ -114,14 +114,6 @@
#endif
-#if ENABLED(SINGLENOZZLE_STANDBY_TEMP)
- extern uint16_t singlenozzle_temp[EXTRUDERS];
-#endif
-
-#if BOTH(HAS_FAN, SINGLENOZZLE_STANDBY_FAN)
- extern uint8_t singlenozzle_fan_speed[EXTRUDERS];
-#endif
-
TERN_(ELECTROMAGNETIC_SWITCHING_TOOLHEAD, void est_init());
TERN_(SWITCHING_TOOLHEAD, void swt_init());
diff --git a/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_4.h b/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_4.h
index 2e9aba02cf..dfe86b12b7 100644
--- a/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_4.h
+++ b/Marlin/src/pins/lpc1768/pins_BTT_SKR_V1_4.h
@@ -60,6 +60,13 @@
#else
#define X_MIN_PIN P1_26 // E0DET
#endif
+#elif ENABLED(X_DUAL_ENDSTOPS)
+ #ifndef X_MIN_PIN
+ #define X_MIN_PIN P1_29 // X-STOP
+ #endif
+ #ifndef X_MAX_PIN
+ #define X_MAX_PIN P1_26 // E0DET
+ #endif
#else
#define X_STOP_PIN P1_29 // X-STOP
#endif
@@ -71,6 +78,13 @@
#else
#define Y_MIN_PIN P1_25 // E1DET
#endif
+#elif ENABLED(Y_DUAL_ENDSTOPS)
+ #ifndef Y_MIN_PIN
+ #define Y_MIN_PIN P1_28 // Y-STOP
+ #endif
+ #ifndef Y_MAX_PIN
+ #define Y_MAX_PIN P1_25 // E1DET
+ #endif
#else
#define Y_STOP_PIN P1_28 // Y-STOP
#endif
@@ -82,6 +96,13 @@
#else
#define Z_MIN_PIN P1_00 // PWRDET
#endif
+#elif ENABLED(Z_MULTI_ENDSTOPS)
+ #ifndef Z_MIN_PIN
+ #define Z_MIN_PIN P1_27 // Z-STOP
+ #endif
+ #ifndef Z_MAX_PIN
+ #define Z_MAX_PIN P1_00 // PWRDET
+ #endif
#else
#ifndef Z_STOP_PIN
#define Z_STOP_PIN P1_27 // Z-STOP
@@ -337,6 +358,8 @@
#define LCD_PINS_ENABLE EXPA1_05_PIN
#define LCD_PINS_D4 EXPA1_07_PIN
+ #define BEEPER_PIN EXPA1_10_PIN
+
#elif ENABLED(CR10_STOCKDISPLAY)
#define BTN_ENC EXPA1_09_PIN // (58) open-drain
#define LCD_PINS_RS EXPA1_04_PIN
diff --git a/Marlin/src/pins/lpc1768/pins_MKS_SBASE.h b/Marlin/src/pins/lpc1768/pins_MKS_SBASE.h
index ea9748ca54..fbddc66e7c 100644
--- a/Marlin/src/pins/lpc1768/pins_MKS_SBASE.h
+++ b/Marlin/src/pins/lpc1768/pins_MKS_SBASE.h
@@ -27,7 +27,7 @@
#if defined(MKS_HAS_LPC1769) && NOT_TARGET(MCU_LPC1769)
#error "Oops! Make sure you have the LPC1769 environment selected in your IDE."
-#elif NOT_TARGET(MKS_HAS_LPC1769, MCU_LPC1768)
+#elif !defined(MKS_HAS_LPC1769) && NOT_TARGET(MCU_LPC1768)
#error "Oops! Make sure you have the LPC1768 environment selected in your IDE."
#endif
diff --git a/Marlin/src/pins/lpc1768/pins_RAMPS_RE_ARM.h b/Marlin/src/pins/lpc1768/pins_RAMPS_RE_ARM.h
index 7d0f494c34..65840308ca 100644
--- a/Marlin/src/pins/lpc1768/pins_RAMPS_RE_ARM.h
+++ b/Marlin/src/pins/lpc1768/pins_RAMPS_RE_ARM.h
@@ -325,6 +325,10 @@
#define LCD_PINS_ENABLE P0_18 // J3-10 & AUX-3 (SID, MOSI)
#define LCD_PINS_D4 P2_06 // J3-8 & AUX-3 (SCK, CLK)
+#elif ENABLED(ZONESTAR_LCD)
+
+ #error "CAUTION! ZONESTAR_LCD on REARM requires wiring modifications. NB. ADCs are not 5V tolerant. Comment out this line to continue."
+
#elif IS_TFTGLCD_PANEL
#if ENABLED(TFTGLCD_PANEL_SPI)
diff --git a/Marlin/src/pins/pins.h b/Marlin/src/pins/pins.h
index c0995e8826..737c8869d1 100644
--- a/Marlin/src/pins/pins.h
+++ b/Marlin/src/pins/pins.h
@@ -548,6 +548,8 @@
#include "stm32f1/pins_FLSUN_HISPEED.h" // STM32F1 env:flsun_hispeed
#elif MB(BEAST)
#include "stm32f1/pins_BEAST.h" // STM32F1 env:STM32F103RE
+#elif MB(MINGDA_MPX_ARM_MINI)
+ #include "stm32f1/pins_MINGDA_MPX_ARM_MINI.h" // STM32F1 env:STM32F103RE
//
// ARM Cortex-M4F
@@ -573,19 +575,19 @@
#elif MB(STEVAL_3DP001V1)
#include "stm32f4/pins_STEVAL_3DP001V1.h" // STM32F4 env:STM32F401VE_STEVAL
#elif MB(BTT_SKR_PRO_V1_1)
- #include "stm32f4/pins_BTT_SKR_PRO_V1_1.h" // STM32F4 env:BIGTREE_SKR_PRO
+ #include "stm32f4/pins_BTT_SKR_PRO_V1_1.h" // STM32F4 env:BIGTREE_SKR_PRO env:BIGTREE_SKR_PRO_usb_flash_drive
#elif MB(BTT_SKR_PRO_V1_2)
- #include "stm32f4/pins_BTT_SKR_PRO_V1_2.h" // STM32F4 env:BIGTREE_SKR_PRO
+ #include "stm32f4/pins_BTT_SKR_PRO_V1_2.h" // STM32F4 env:BIGTREE_SKR_PRO env:BIGTREE_SKR_PRO_usb_flash_drive
#elif MB(BTT_GTR_V1_0)
- #include "stm32f4/pins_BTT_GTR_V1_0.h" // STM32F4 env:BIGTREE_GTR_V1_0
+ #include "stm32f4/pins_BTT_GTR_V1_0.h" // STM32F4 env:BIGTREE_GTR_V1_0 env:BIGTREE_GTR_V1_0_usb_flash_drive
#elif MB(BTT_BTT002_V1_0)
#include "stm32f4/pins_BTT_BTT002_V1_0.h" // STM32F4 env:BIGTREE_BTT002
#elif MB(LERDGE_K)
- #include "stm32f4/pins_LERDGE_K.h" // STM32F4 env:LERDGEK
+ #include "stm32f4/pins_LERDGE_K.h" // STM32F4 env:LERDGEK env:LERDGEK_usb_flash_drive
#elif MB(LERDGE_S)
- #include "stm32f4/pins_LERDGE_S.h" // STM32F4 env:LERDGES
+ #include "stm32f4/pins_LERDGE_S.h" // STM32F4 env:LERDGES env:LERDGES_usb_flash_drive
#elif MB(LERDGE_X)
- #include "stm32f4/pins_LERDGE_X.h" // STM32F4 env:LERDGEX
+ #include "stm32f4/pins_LERDGE_X.h" // STM32F4 env:LERDGEX env:LERDGEX_usb_flash_drive
#elif MB(VAKE403D)
#include "stm32f4/pins_VAKE403D.h" // STM32F4
#elif MB(FYSETC_S6)
@@ -599,11 +601,13 @@
#elif MB(MKS_ROBIN_PRO_V2)
#include "stm32f4/pins_MKS_ROBIN_PRO_V2.h" // STM32F4 env:mks_robin_pro2
#elif MB(MKS_ROBIN_NANO_V3)
- #include "stm32f4/pins_MKS_ROBIN_NANO_V3.h" // STM32F4 env:mks_robin_nano_v3
+ #include "stm32f4/pins_MKS_ROBIN_NANO_V3.h" // STM32F4 env:mks_robin_nano_v3 env:mks_robin_nano_v3_usb_flash_drive
#elif MB(ANET_ET4)
#include "stm32f4/pins_ANET_ET4.h" // STM32F4 env:Anet_ET4_OpenBLT
#elif MB(ANET_ET4P)
#include "stm32f4/pins_ANET_ET4P.h" // STM32F4 env:Anet_ET4_OpenBLT
+#elif MB(FYSETC_CHEETAH_V20)
+ #include "stm32f4/pins_FYSETC_CHEETAH_V20.h" // STM32F4 env:FYSETC_CHEETAH_V20
//
// ARM Cortex M7
diff --git a/Marlin/src/pins/ramps/pins_RAMPS.h b/Marlin/src/pins/ramps/pins_RAMPS.h
index ab5711bd5c..5bcd877dcd 100644
--- a/Marlin/src/pins/ramps/pins_RAMPS.h
+++ b/Marlin/src/pins/ramps/pins_RAMPS.h
@@ -468,6 +468,7 @@
#elif ENABLED(ZONESTAR_LCD)
+ #error "CAUTION! ZONESTAR_LCD on RAMPS requires wiring modifications. It plugs into AUX2 but GND and 5V need to be swapped. Comment out this line to continue."
#define LCD_PINS_RS 64
#define LCD_PINS_ENABLE 44
#define LCD_PINS_D4 63
diff --git a/Marlin/src/pins/sanguino/pins_SANGUINOLOLU_11.h b/Marlin/src/pins/sanguino/pins_SANGUINOLOLU_11.h
index ffed79de79..af27159936 100644
--- a/Marlin/src/pins/sanguino/pins_SANGUINOLOLU_11.h
+++ b/Marlin/src/pins/sanguino/pins_SANGUINOLOLU_11.h
@@ -163,6 +163,8 @@
#define LCD_PINS_RS 17
#define LCD_PINS_ENABLE 16
#define LCD_PINS_D4 11
+ #define KILL_PIN 10
+ #define BEEPER_PIN 27
#ifndef BOARD_ST7920_DELAY_1
#define BOARD_ST7920_DELAY_1 DELAY_NS(0)
diff --git a/Marlin/src/pins/stm32f1/pins_MINGDA_MPX_ARM_MINI.h b/Marlin/src/pins/stm32f1/pins_MINGDA_MPX_ARM_MINI.h
new file mode 100644
index 0000000000..429cf14ac5
--- /dev/null
+++ b/Marlin/src/pins/stm32f1/pins_MINGDA_MPX_ARM_MINI.h
@@ -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 .
+ *
+ */
+#pragma once
+
+/**
+ * MKS Robin mini (STM32F130VET6) board pin assignments
+ */
+
+#if NOT_TARGET(STM32F1, STM32F1xx)
+ #error "Oops! Select an STM32F1 board in 'Tools > Board.'"
+#elif HOTENDS > 2 || E_STEPPERS > 2
+ #error "MKS Robin supports up to 2 hotends / E-steppers. Comment out this line to continue."
+#endif
+
+#define BOARD_INFO_NAME "Mingda MPX_ARM_MINI"
+
+#define BOARD_NO_NATIVE_USB
+#define DISABLE_DEBUG
+
+//
+// EEPROM
+//
+
+/*
+//Mingda used an unknown EEPROM chip ATMLH753, so I turned on the emulation below.
+//It is connected to EEPROM PB6 PB7
+
+#define I2C_EEPROM
+#undef NO_EEPROM_SELECTED
+#define MARLIN_EEPROM_SIZE 0x1000 // 4KB
+#define USE_SHARED_EEPROM 1 // Use Platform-independent Arduino functions for I2C EEPROM
+#define E2END 0xFFFF // EEPROM end address AT24C256 (32kB)
+*/
+
+#if EITHER(NO_EEPROM_SELECTED, FLASH_EEPROM_EMULATION)
+ #define FLASH_EEPROM_EMULATION
+ #define EEPROM_PAGE_SIZE 0x800U // 2KB
+ #define EEPROM_START_ADDRESS (0x8000000UL + (STM32_FLASH_SIZE) * 1024UL - (EEPROM_PAGE_SIZE) * 2UL)
+ #define MARLIN_EEPROM_SIZE EEPROM_PAGE_SIZE // 2KB
+#endif
+
+#define SPI_DEVICE 2
+
+//
+// Limit Switches
+//
+#define X_MIN_PIN PD6
+#define X_MAX_PIN PG15
+#define Y_MIN_PIN PG9
+#define Y_MAX_PIN PG14
+#define Z_MIN_PIN PG10
+#define Z_MAX_PIN PG13
+
+#ifndef FIL_RUNOUT_PIN
+ #define FIL_RUNOUT_PIN PG11
+#endif
+
+//
+// Steppers
+//
+#define X_ENABLE_PIN PD13
+#define X_STEP_PIN PD12
+#define X_DIR_PIN PD11
+
+#define Y_ENABLE_PIN PG4
+#define Y_STEP_PIN PG3
+#define Y_DIR_PIN PG2
+
+#define Z_ENABLE_PIN PG7
+#define Z_STEP_PIN PG6
+#define Z_DIR_PIN PG5
+
+#define E0_ENABLE_PIN PC7
+#define E0_STEP_PIN PC6
+#define E0_DIR_PIN PG8
+
+//
+// Temperature Sensors
+//
+//#define TEMP_0_PIN PF6 // THERM_E0
+//#define TEMP_0_PIN PB3 // E0 K+
+#define TEMP_BED_PIN PF7 // THERM_BED
+
+#define MAX6675_SS_PIN PB5
+#define MAX6675_SCK_PIN PB3
+#define MAX6675_DO_PIN PB4
+#define MAX6675_MOSI_PIN PA14
+
+//
+// Heaters / Fans
+//
+#define HEATER_0_PIN PB0
+#define HEATER_BED_PIN PB1
+
+#define FAN_PIN PA0 // FAN
+
+//
+// SD Card
+//
+#ifndef SDCARD_CONNECTION
+ #define SDCARD_CONNECTION ONBOARD
+#endif
+
+#define SDIO_SUPPORT
+#define SDIO_CLOCK 4500000 // 4.5 MHz
+#define SDIO_READ_RETRIES 16
+
+#define SD_DETECT_PIN PC5
+#define ONBOARD_SPI_DEVICE 1 // SPI1
+#define ONBOARD_SD_CS_PIN PC10
+
+//
+// LCD / Controller
+//
+#define BEEPER_PIN PE4
+
+/**
+ * Note: MKS Robin TFT screens use various TFT controllers.
+ * If the screen stays white, disable 'LCD_RESET_PIN'
+ * to let the bootloader init the screen.
+ */
+#if HAS_FSMC_TFT
+ /**
+ * Note: MKS Robin TFT screens use various TFT controllers
+ * Supported screens are based on the ILI9341, ST7789V and ILI9328 (320x240)
+ * ILI9488 is not supported
+ * Define init sequences for other screens in u8g_dev_tft_320x240_upscale_from_128x64.cpp
+ *
+ * If the screen stays white, disable 'TFT_RESET_PIN'
+ * to let the bootloader init the screen.
+ *
+ * Setting an 'TFT_RESET_PIN' may cause a flicker when entering the LCD menu
+ * because Marlin uses the reset as a failsafe to revive a glitchy LCD.
+ */
+ #define TFT_CS_PIN PD7 // NE4
+ #define TFT_RS_PIN PG0 // A0
+
+ #define FSMC_CS_PIN TFT_CS_PIN
+ #define FSMC_RS_PIN TFT_RS_PIN
+
+ #define LCD_USE_DMA_FSMC // Use DMA transfers to send data to the TFT
+ #define FSMC_DMA_DEV DMA2
+ #define FSMC_DMA_CHANNEL DMA_CH5
+
+ #define TFT_RESET_PIN PF15
+ #define TFT_BACKLIGHT_PIN PF11
+
+ #define TOUCH_BUTTONS_HW_SPI
+ #define TOUCH_BUTTONS_HW_SPI_DEVICE 1
+#endif
+
+#if NEED_TOUCH_PINS
+ #define TOUCH_CS_PIN PA4 // SPI2_NSS
+ #define TOUCH_SCK_PIN PA5 // SPI2_SCK
+ #define TOUCH_MISO_PIN PA6 // SPI2_MISO
+ #define TOUCH_MOSI_PIN PA7 // SPI2_MOSI
+#endif
diff --git a/Marlin/src/pins/stm32f4/pins_ANET_ET4.h b/Marlin/src/pins/stm32f4/pins_ANET_ET4.h
index a63ed1ddf0..487080f46b 100644
--- a/Marlin/src/pins/stm32f4/pins_ANET_ET4.h
+++ b/Marlin/src/pins/stm32f4/pins_ANET_ET4.h
@@ -16,7 +16,7 @@
* 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 .
+ * along with this program. If not, see .
*
*/
diff --git a/Marlin/src/pins/stm32f4/pins_ANET_ET4P.h b/Marlin/src/pins/stm32f4/pins_ANET_ET4P.h
index eecabbaf98..f5ebf82a48 100644
--- a/Marlin/src/pins/stm32f4/pins_ANET_ET4P.h
+++ b/Marlin/src/pins/stm32f4/pins_ANET_ET4P.h
@@ -16,7 +16,7 @@
* 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 .
+ * along with this program. If not, see .
*
*/
diff --git a/Marlin/src/pins/stm32f4/pins_BTT_GTR_V1_0.h b/Marlin/src/pins/stm32f4/pins_BTT_GTR_V1_0.h
index 981064fa4d..cd9d60d2f0 100644
--- a/Marlin/src/pins/stm32f4/pins_BTT_GTR_V1_0.h
+++ b/Marlin/src/pins/stm32f4/pins_BTT_GTR_V1_0.h
@@ -39,6 +39,7 @@
#define HAS_OTG_USB_HOST_SUPPORT
#define TP // Enable to define servo and probe pins
+#define M5_EXTENDER // The M5 extender is attached
//
// Servos
@@ -101,11 +102,13 @@
//
// Pins on the extender
//
-//#define X_MIN_PIN PI4
-//#define X2_MIN_PIN PF12
-//#define Y_MIN_PIN PF4
-//#define Y2_MIN_PIN PI7
-//#define Z_MIN_PIN PF6
+#if ENABLED(M5_EXTENDER)
+ #define X2_STOP_PIN PI4 // M5 M1_STOP
+ #define Y2_STOP_PIN PF12 // M5 M5_STOP
+ #define Z2_STOP_PIN PF4 // M5 M2_STOP
+ #define Z3_STOP_PIN PI7 // M5 M4_STOP
+ #define Z4_STOP_PIN PF6 // M5 M3_STOP
+#endif
#if ENABLED(TP) && !defined(Z_MIN_PROBE_PIN)
#define Z_MIN_PROBE_PIN PH11 // Z Probe must be PH11
@@ -156,39 +159,43 @@
#define E2_CS_PIN PC12
#endif
-#define E3_STEP_PIN PF3
-#define E3_DIR_PIN PG3
-#define E3_ENABLE_PIN PF8
-#ifndef E3_CS_PIN
- #define E3_CS_PIN PG4
-#endif
+#if ENABLED(M5_EXTENDER)
-#define E4_STEP_PIN PD14
-#define E4_DIR_PIN PD11
-#define E4_ENABLE_PIN PG2
-#ifndef E4_CS_PIN
- #define E4_CS_PIN PE15
-#endif
+ #define E3_STEP_PIN PF3
+ #define E3_DIR_PIN PG3
+ #define E3_ENABLE_PIN PF8
+ #ifndef E3_CS_PIN
+ #define E3_CS_PIN PG4
+ #endif
-#define E5_STEP_PIN PE12
-#define E5_DIR_PIN PE10
-#define E5_ENABLE_PIN PF14
-#ifndef E5_CS_PIN
- #define E5_CS_PIN PE7
-#endif
+ #define E4_STEP_PIN PD14
+ #define E4_DIR_PIN PD11
+ #define E4_ENABLE_PIN PG2
+ #ifndef E4_CS_PIN
+ #define E4_CS_PIN PE15
+ #endif
-#define E6_STEP_PIN PG0
-#define E6_DIR_PIN PG1
-#define E6_ENABLE_PIN PE8
-#ifndef E6_CS_PIN
- #define E6_CS_PIN PF15
-#endif
+ #define E5_STEP_PIN PE12
+ #define E5_DIR_PIN PE10
+ #define E5_ENABLE_PIN PF14
+ #ifndef E5_CS_PIN
+ #define E5_CS_PIN PE7
+ #endif
+
+ #define E6_STEP_PIN PG0
+ #define E6_DIR_PIN PG1
+ #define E6_ENABLE_PIN PE8
+ #ifndef E6_CS_PIN
+ #define E6_CS_PIN PF15
+ #endif
+
+ #define E7_STEP_PIN PH12
+ #define E7_DIR_PIN PH15
+ #define E7_ENABLE_PIN PI0
+ #ifndef E7_CS_PIN
+ #define E7_CS_PIN PH14
+ #endif
-#define E7_STEP_PIN PH12
-#define E7_DIR_PIN PH15
-#define E7_ENABLE_PIN PI0
-#ifndef E7_CS_PIN
- #define E7_CS_PIN PH14
#endif
//
@@ -222,11 +229,11 @@
//#define E0_HARDWARE_SERIAL Serial1
//#define E1_HARDWARE_SERIAL Serial1
//#define E2_HARDWARE_SERIAL Serial1
- //#define E3_HARDWARE_SERIAL Serial1
- //#define E4_HARDWARE_SERIAL Serial1
- //#define E5_HARDWARE_SERIAL Serial1
- //#define E6_HARDWARE_SERIAL Serial1
- //#define E7_HARDWARE_SERIAL Serial1
+ //#define E3_HARDWARE_SERIAL Serial1 // M5 MOTOR 1
+ //#define E4_HARDWARE_SERIAL Serial1 // M5 MOTOR 2
+ //#define E5_HARDWARE_SERIAL Serial1 // M5 MOTOR 3
+ //#define E6_HARDWARE_SERIAL Serial1 // M5 MOTOR 4
+ //#define E7_HARDWARE_SERIAL Serial1 // M5 MOTOR 5
//
// Software serial
@@ -249,20 +256,22 @@
#define E2_SERIAL_TX_PIN PC12
#define E2_SERIAL_RX_PIN PC12
- #define E3_SERIAL_TX_PIN PG4
- #define E3_SERIAL_RX_PIN PG4
+ #if ENABLED(M5_EXTENDER)
+ #define E3_SERIAL_TX_PIN PG4
+ #define E3_SERIAL_RX_PIN PG4
- #define E4_SERIAL_TX_PIN PE15
- #define E4_SERIAL_RX_PIN PE15
+ #define E4_SERIAL_TX_PIN PE15
+ #define E4_SERIAL_RX_PIN PE15
- #define E5_SERIAL_TX_PIN PE7
- #define E5_SERIAL_RX_PIN PE7
+ #define E5_SERIAL_TX_PIN PE7
+ #define E5_SERIAL_RX_PIN PE7
- #define E6_SERIAL_TX_PIN PF15
- #define E6_SERIAL_RX_PIN PF15
+ #define E6_SERIAL_TX_PIN PF15
+ #define E6_SERIAL_RX_PIN PF15
- #define E7_SERIAL_TX_PIN PH14
- #define E7_SERIAL_RX_PIN PH14
+ #define E7_SERIAL_TX_PIN PH14
+ #define E7_SERIAL_RX_PIN PH14
+ #endif
// Reduce baud rate to improve software serial reliability
#define TMC_BAUD_RATE 19200
@@ -275,11 +284,13 @@
#define TEMP_1_PIN PC2 // T2 <-> E1
#define TEMP_2_PIN PC3 // T3 <-> E2
-#define TEMP_3_PIN PA3 // T4 <-> E3
-#define TEMP_4_PIN PF9 // T5 <-> E4
-#define TEMP_5_PIN PF10 // T6 <-> E5
-#define TEMP_6_PIN PF7 // T7 <-> E6
-#define TEMP_7_PIN PF5 // T8 <-> E7
+#if ENABLED(M5_EXTENDER)
+ #define TEMP_3_PIN PA3 // M5 TEMP1
+ #define TEMP_4_PIN PF9 // M5 TEMP2
+ #define TEMP_5_PIN PF10 // M5 TEMP3
+ #define TEMP_6_PIN PF7 // M5 TEMP4
+ #define TEMP_7_PIN PF5 // M5 TEMP5
+#endif
#define TEMP_BED_PIN PC0 // T0 <-> Bed
@@ -289,8 +300,8 @@
#define THERMO_SCK_PIN PI1 // SCK
#define THERMO_DO_PIN PI2 // MISO
-#define THERMO_CS1_PIN PH9 // CS1
-#define THERMO_CS2_PIN PH2 // CS2
+#define THERMO_CS1_PIN PH9 // GTR K-TEMP
+#define THERMO_CS2_PIN PH2 // M5 K-TEMP
#define MAX6675_SS_PIN THERMO_CS1_PIN
#define MAX6675_SS2_PIN THERMO_CS2_PIN
@@ -304,11 +315,13 @@
#define HEATER_1_PIN PA1 // Heater1
#define HEATER_2_PIN PB0 // Heater2
-#define HEATER_3_PIN PD15 // Heater3
-#define HEATER_4_PIN PD13 // Heater4
-#define HEATER_5_PIN PD12 // Heater5
-#define HEATER_6_PIN PE13 // Heater6
-#define HEATER_7_PIN PI6 // Heater7
+#if ENABLED(M5_EXTENDER)
+ #define HEATER_3_PIN PD15 // M5 HEAT1
+ #define HEATER_4_PIN PD13 // M5 HEAT2
+ #define HEATER_5_PIN PD12 // M5 HEAT3
+ #define HEATER_6_PIN PE13 // M5 HEAT4
+ #define HEATER_7_PIN PI6 // M5 HEAT5
+#endif
#define HEATER_BED_PIN PA2 // Hotbed
@@ -316,11 +329,13 @@
#define FAN1_PIN PE6 // Fan1
#define FAN2_PIN PC8 // Fan2
-#define FAN3_PIN PI5 // Fan3
-#define FAN4_PIN PE9 // Fan4
-#define FAN5_PIN PE11 // Fan5
-//#define FAN6_PIN PC9 // Fan6
-//#define FAN7_PIN PE14 // Fan7
+#if ENABLED(M5_EXTENDER)
+ #define FAN3_PIN PI5 // M5 FAN1
+ #define FAN4_PIN PE9 // M5 FAN2
+ #define FAN5_PIN PE11 // M5 FAN3
+ //#define FAN6_PIN PC9 // M5 FAN4
+ //#define FAN7_PIN PE14 // M5 FAN5
+#endif
#ifndef SDCARD_CONNECTION
#define SDCARD_CONNECTION ONBOARD
@@ -456,3 +471,4 @@
#endif // HAS_WIRED_LCD
#undef TP
+#undef M5_EXTENDER
diff --git a/Marlin/src/pins/stm32f4/pins_FYSETC_CHEETAH_V20.h b/Marlin/src/pins/stm32f4/pins_FYSETC_CHEETAH_V20.h
new file mode 100644
index 0000000000..18e689d1d9
--- /dev/null
+++ b/Marlin/src/pins/stm32f4/pins_FYSETC_CHEETAH_V20.h
@@ -0,0 +1,271 @@
+/**
+ * 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
+
+#if NOT_TARGET(STM32F4)
+ #error "Oops! Select an STM32F4 board in 'Tools > Board.'"
+#endif
+
+#define DEFAULT_MACHINE_NAME "3D Printer"
+
+#define BOARD_INFO_NAME "FYSETC Cheetah V2.0"
+#define BOARD_WEBSITE_URL "fysetc.com"
+
+// USB Flash Drive support
+//#define HAS_OTG_USB_HOST_SUPPORT
+
+// Ignore temp readings during development.
+//#define BOGUS_TEMPERATURE_GRACE_PERIOD 2000
+
+#if EITHER(NO_EEPROM_SELECTED, FLASH_EEPROM_EMULATION)
+ #define FLASH_EEPROM_EMULATION
+ #define FLASH_EEPROM_LEVELING
+
+ #define FLASH_SECTOR 2
+ #define FLASH_UNIT_SIZE 0x4000 // 16k
+ #define FLASH_ADDRESS_START 0x8008000
+#endif
+
+//
+// Z Probe
+//
+#if ENABLED(BLTOUCH)
+ #error "You need to set jumper to 5v for Bltouch, then comment out this line to proceed."
+ #define SERVO0_PIN PA0
+#elif !defined(Z_MIN_PROBE_PIN)
+ #define Z_MIN_PROBE_PIN PA0
+#endif
+
+//
+// Limit Switches
+//
+#define X_STOP_PIN PB4
+#define Y_STOP_PIN PB3
+#define Z_STOP_PIN PB1
+
+//
+// Filament runout
+//
+#define FIL_RUNOUT_PIN PB5
+
+//
+// Steppers
+//
+#define X_STEP_PIN PC0
+#define X_DIR_PIN PC1
+#define X_ENABLE_PIN PA8
+
+#define Y_STEP_PIN PC14
+#define Y_DIR_PIN PC13
+#define Y_ENABLE_PIN PC15
+
+#define Z_STEP_PIN PB9
+#define Z_DIR_PIN PB8
+#define Z_ENABLE_PIN PC2
+
+#define E0_STEP_PIN PB2
+#define E0_DIR_PIN PA15
+#define E0_ENABLE_PIN PD2
+
+#if HAS_TMC_UART
+ #define X_HARDWARE_SERIAL Serial2
+ #define Y_HARDWARE_SERIAL Serial2
+ #define Z_HARDWARE_SERIAL Serial2
+ #define E0_HARDWARE_SERIAL Serial2
+
+ // Default TMC slave addresses
+ #ifndef X_SLAVE_ADDRESS
+ #define X_SLAVE_ADDRESS 0
+ #endif
+ #ifndef Y_SLAVE_ADDRESS
+ #define Y_SLAVE_ADDRESS 2
+ #endif
+ #ifndef Z_SLAVE_ADDRESS
+ #define Z_SLAVE_ADDRESS 1
+ #endif
+ #ifndef E0_SLAVE_ADDRESS
+ #define E0_SLAVE_ADDRESS 3
+ #endif
+#endif
+
+//
+// Heaters / Fans
+//
+#define HEATER_0_PIN PC6
+#define HEATER_BED_PIN PC7
+#ifndef FAN_PIN
+ #define FAN_PIN PA1
+#endif
+#define FAN1_PIN PC8
+
+//
+// Temperature Sensors
+//
+#define TEMP_BED_PIN PC5 // Analog Input
+#define TEMP_0_PIN PC4 // Analog Input
+
+//
+// Misc. Functions
+//
+#define SDSS PA4
+#define SD_DETECT_PIN PC3
+
+#ifndef RGB_LED_R_PIN
+ #define RGB_LED_R_PIN PB0
+#endif
+#ifndef RGB_LED_G_PIN
+ #define RGB_LED_G_PIN PB7
+#endif
+#ifndef RGB_LED_B_PIN
+ #define RGB_LED_B_PIN PB6
+#endif
+
+/**
+ * _____ _____
+ * 5V | 1 2 | GND 5V | 1 2 | GND
+ * RESET | 3 4 | PC3 (SD_DETECT) (LCD_D7) PB7 | 3 4 | PB6 (LCD_D6)
+ * (SD_MOSI) PA7 5 6 | PC11 (BTN_EN2) (LCD_D5) PB14 5 6 | PB13 (LCD_D4)
+ * (SD_SS) PA4 | 7 8 | PC10 (BTN_EN1) (LCD_RS) PB12 | 7 8 | PB15 (LCD_EN)
+ * (SD_SCK) PA5 | 9 10| PA6 (SD_MISO) (BTN_ENC) PC12 | 9 10| PC9 (BEEPER)
+ * ----- -----
+ * EXP2 EXP1
+ */
+
+/**
+* _____
+* (BEEPER) PC9 | 1 2 | PC12 (BTN_ENC)
+* (BTN_EN1) PC10 | 3 4 | PB14 (LCD_D5/MISO)
+* (BTN_EN2) PC11 5 6 | PB13 (LCD_D4/SCK)
+* (LCD_RS) PB12 | 7 8 | PB15 (LCD_EN/MOSI)
+* GND | 9 10| 5V
+* -----
+* EXP3
+*/
+
+#define EXPA1_03_PIN PB7
+#define EXPA1_04_PIN PB6
+#define EXPA1_05_PIN PB14
+#define EXPA1_06_PIN PB13
+#define EXPA1_07_PIN PB12
+#define EXPA1_08_PIN PB15
+#define EXPA1_09_PIN PC12
+#define EXPA1_10_PIN PC9
+
+#define EXPA2_03_PIN -1
+#define EXPA2_04_PIN PC3
+#define EXPA2_05_PIN PA7
+#define EXPA2_06_PIN PC11
+#define EXPA2_07_PIN PA4
+#define EXPA2_08_PIN PC10
+#define EXPA2_09_PIN PA5
+#define EXPA2_10_PIN PA6
+
+#if HAS_WIRED_LCD
+
+ #define BEEPER_PIN EXPA1_10_PIN
+ #define BTN_ENC EXPA1_09_PIN
+
+ #if ENABLED(CR10_STOCKDISPLAY)
+
+ #define LCD_PINS_RS EXPA1_07_PIN
+
+ #define BTN_EN1 EXPA2_08_PIN
+ #define BTN_EN2 EXPA2_06_PIN
+
+ #define LCD_PINS_ENABLE EXPA1_08_PIN
+ #define LCD_PINS_D4 EXPA1_06_PIN
+
+ // CR10_STOCKDISPLAY default timing is too fast
+ #undef BOARD_ST7920_DELAY_1
+ #undef BOARD_ST7920_DELAY_2
+ #undef BOARD_ST7920_DELAY_3
+
+ #elif ENABLED(MKS_MINI_12864)
+
+ #define DOGLCD_A0 EXPA1_04_PIN
+ #define DOGLCD_CS EXPA1_05_PIN
+ #define BTN_EN1 EXPA2_08_PIN
+ #define BTN_EN2 EXPA2_06_PIN
+
+ #else
+
+ #define LCD_PINS_RS EXPA1_07_PIN
+
+ #define BTN_EN1 EXPA2_06_PIN
+ #define BTN_EN2 EXPA2_08_PIN
+
+ #define LCD_PINS_ENABLE EXPA1_08_PIN
+ #define LCD_PINS_D4 EXPA1_06_PIN
+
+ #if ENABLED(FYSETC_MINI_12864)
+ #define DOGLCD_CS EXPA1_08_PIN
+ #define DOGLCD_A0 EXPA1_07_PIN
+ //#define LCD_BACKLIGHT_PIN -1
+ #define LCD_RESET_PIN EXPA1_06_PIN // Must be high or open for LCD to operate normally.
+ #if EITHER(FYSETC_MINI_12864_1_2, FYSETC_MINI_12864_2_0)
+ #ifndef RGB_LED_R_PIN
+ #define RGB_LED_R_PIN EXPA1_05_PIN
+ #endif
+ #ifndef RGB_LED_G_PIN
+ #define RGB_LED_G_PIN EXPA1_04_PIN
+ #endif
+ #ifndef RGB_LED_B_PIN
+ #define RGB_LED_B_PIN EXPA1_03_PIN
+ #endif
+ #elif ENABLED(FYSETC_MINI_12864_2_1)
+ #define NEOPIXEL_PIN EXPA1_05_PIN
+ #endif
+ #endif // !FYSETC_MINI_12864
+
+ #if IS_ULTIPANEL
+ #define LCD_PINS_D5 EXPA1_05_PIN
+ #define LCD_PINS_D6 EXPA1_04_PIN
+ #define LCD_PINS_D7 EXPA1_03_PIN
+
+ #if ENABLED(REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER)
+ #define BTN_ENC_EN LCD_PINS_D7 // Detect the presence of the encoder
+ #endif
+
+ #endif
+
+ #endif
+
+#endif // HAS_WIRED_LCD
+
+// Alter timing for graphical display
+#if HAS_MARLINUI_U8GLIB
+ #ifndef BOARD_ST7920_DELAY_1
+ #define BOARD_ST7920_DELAY_1 DELAY_NS(96)
+ #endif
+ #ifndef BOARD_ST7920_DELAY_2
+ #define BOARD_ST7920_DELAY_2 DELAY_NS(48)
+ #endif
+ #ifndef BOARD_ST7920_DELAY_3
+ #define BOARD_ST7920_DELAY_3 DELAY_NS(600)
+ #endif
+#endif
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+ #define BEEPER_PIN EXPA1_10_PIN
+ #define CLCD_MOD_RESET EXPA2_08_PIN
+ #define CLCD_SPI_CS EXPA2_06_PIN
+#endif
diff --git a/Marlin/src/pins/stm32f4/pins_LERDGE_K.h b/Marlin/src/pins/stm32f4/pins_LERDGE_K.h
index 18cbdeaaf5..bf6df03562 100644
--- a/Marlin/src/pins/stm32f4/pins_LERDGE_K.h
+++ b/Marlin/src/pins/stm32f4/pins_LERDGE_K.h
@@ -29,6 +29,9 @@
#define I2C_EEPROM
+// USB Flash Drive support
+#define HAS_OTG_USB_HOST_SUPPORT
+
//
// Servos
//
diff --git a/Marlin/src/pins/stm32f4/pins_LERDGE_S.h b/Marlin/src/pins/stm32f4/pins_LERDGE_S.h
index 486aabfd8e..c6cfa98831 100644
--- a/Marlin/src/pins/stm32f4/pins_LERDGE_S.h
+++ b/Marlin/src/pins/stm32f4/pins_LERDGE_S.h
@@ -32,6 +32,9 @@
//#define I2C_EEPROM
+// USB Flash Drive support
+#define HAS_OTG_USB_HOST_SUPPORT
+
//
// Servos
//
diff --git a/Marlin/src/pins/stm32f4/pins_LERDGE_X.h b/Marlin/src/pins/stm32f4/pins_LERDGE_X.h
index c73b9927ac..606d932c57 100644
--- a/Marlin/src/pins/stm32f4/pins_LERDGE_X.h
+++ b/Marlin/src/pins/stm32f4/pins_LERDGE_X.h
@@ -32,6 +32,9 @@
#define I2C_EEPROM
+// USB Flash Drive support
+#define HAS_OTG_USB_HOST_SUPPORT
+
//
// Servos
//
diff --git a/Marlin/src/pins/stm32f4/pins_MKS_ROBIN_NANO_V3.h b/Marlin/src/pins/stm32f4/pins_MKS_ROBIN_NANO_V3.h
index 47997c4677..49ee420aae 100644
--- a/Marlin/src/pins/stm32f4/pins_MKS_ROBIN_NANO_V3.h
+++ b/Marlin/src/pins/stm32f4/pins_MKS_ROBIN_NANO_V3.h
@@ -16,7 +16,7 @@
* 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 .
+ * along with this program. If not, see .
*
*/
#pragma once
diff --git a/Marlin/src/sd/cardreader.cpp b/Marlin/src/sd/cardreader.cpp
index 7b162f7343..e3732e5ef8 100644
--- a/Marlin/src/sd/cardreader.cpp
+++ b/Marlin/src/sd/cardreader.cpp
@@ -57,6 +57,11 @@
#include "../core/debug_out.h"
#include "../libs/hex_print.h"
+// extern
+
+PGMSTR(M23_STR, "M23 %s");
+PGMSTR(M24_STR, "M24");
+
// public:
card_flags_t CardReader::flag;
@@ -481,7 +486,6 @@ void CardReader::release() {
*/
void CardReader::openAndPrintFile(const char *name) {
char cmd[4 + strlen(name) + 1 + 3 + 1]; // Room for "M23 ", filename, "\n", "M24", and null
- extern const char M23_STR[];
sprintf_P(cmd, M23_STR, name);
for (char *c = &cmd[4]; *c; c++) *c = tolower(*c);
strcat_P(cmd, PSTR("\nM24"));
@@ -546,12 +550,11 @@ void openFailed(const char * const fname) {
void announceOpen(const uint8_t doing, const char * const path) {
if (doing) {
- PORT_REDIRECT(SERIAL_BOTH);
+ PORT_REDIRECT(SERIAL_ALL);
SERIAL_ECHO_START();
SERIAL_ECHOPGM("Now ");
serialprintPGM(doing == 1 ? PSTR("doing") : PSTR("fresh"));
SERIAL_ECHOLNPAIR(" file: ", path);
- PORT_RESTORE();
}
}
@@ -613,10 +616,11 @@ void CardReader::openFileRead(char * const path, const uint8_t subcall_type/*=0*
filesize = file.fileSize();
sdpos = 0;
- PORT_REDIRECT(SERIAL_BOTH);
- SERIAL_ECHOLNPAIR(STR_SD_FILE_OPENED, fname, STR_SD_SIZE, filesize);
- SERIAL_ECHOLNPGM(STR_SD_FILE_SELECTED);
- PORT_RESTORE();
+ { // Don't remove this block, as the PORT_REDIRECT is a RAII
+ PORT_REDIRECT(SERIAL_ALL);
+ SERIAL_ECHOLNPAIR(STR_SD_FILE_OPENED, fname, STR_SD_SIZE, filesize);
+ SERIAL_ECHOLNPGM(STR_SD_FILE_SELECTED);
+ }
selectFileByName(fname);
ui.set_status(longFilename[0] ? longFilename : fname);
@@ -1222,21 +1226,10 @@ void CardReader::fileHasFinished() {
}
#if ENABLED(AUTO_REPORT_SD_STATUS)
- uint8_t CardReader::auto_report_sd_interval = 0;
- millis_t CardReader::next_sd_report_ms;
- #if HAS_MULTI_SERIAL
- int8_t CardReader::auto_report_port;
- #endif
-
- void CardReader::auto_report_sd_status() {
- millis_t current_ms = millis();
- if (auto_report_sd_interval && ELAPSED(current_ms, next_sd_report_ms)) {
- next_sd_report_ms = current_ms + 1000UL * auto_report_sd_interval;
- PORT_REDIRECT(auto_report_port);
- report_status();
- }
- }
-#endif // AUTO_REPORT_SD_STATUS
+ TERN_(HAS_MULTI_SERIAL, serial_index_t CardReader::auto_report_port);
+ CardReader::AutoReportSD CardReader::auto_reporter;
+ void CardReader::AutoReportSD::auto_report() { report_status(); }
+#endif
#if ENABLED(POWER_LOSS_RECOVERY)
diff --git a/Marlin/src/sd/cardreader.h b/Marlin/src/sd/cardreader.h
index b775d8a873..b10a5acd0d 100644
--- a/Marlin/src/sd/cardreader.h
+++ b/Marlin/src/sd/cardreader.h
@@ -27,6 +27,8 @@
#if ENABLED(SDSUPPORT)
+extern const char M23_STR[], M24_STR[];
+
#if BOTH(SDCARD_SORT_ALPHA, SDSORT_DYNAMIC_RAM)
#define SD_RESORT 1
#endif
@@ -57,6 +59,10 @@ typedef struct {
;
} card_flags_t;
+#if ENABLED(AUTO_REPORT_SD_STATUS)
+ #include "../libs/autoreport.h"
+#endif
+
class CardReader {
public:
static card_flags_t flag; // Flags (above)
@@ -170,13 +176,16 @@ public:
static Sd2Card& getSd2Card() { return sd2card; }
#if ENABLED(AUTO_REPORT_SD_STATUS)
- static void auto_report_sd_status();
- static inline void set_auto_report_interval(uint8_t v) {
- TERN_(HAS_MULTI_SERIAL, auto_report_port = serial_port_index);
- NOMORE(v, 60);
- auto_report_sd_interval = v;
- next_sd_report_ms = millis() + 1000UL * v;
- }
+ //
+ // SD Auto Reporting
+ //
+ #if HAS_MULTI_SERIAL
+ static serial_index_t auto_report_port;
+ #else
+ static constexpr serial_index_t auto_report_port = 0;
+ #endif
+ class AutoReportSD : public AutoReporter { void auto_report(); };
+ static AutoReportSD auto_reporter;
#endif
private:
@@ -258,17 +267,6 @@ private:
static char proc_filenames[SD_PROCEDURE_DEPTH][MAXPATHNAMELENGTH];
#endif
- //
- // SD Auto Reporting
- //
- #if ENABLED(AUTO_REPORT_SD_STATUS)
- static uint8_t auto_report_sd_interval;
- static millis_t next_sd_report_ms;
- #if HAS_MULTI_SERIAL
- static int8_t auto_report_port;
- #endif
- #endif
-
//
// Directory items
//
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_macros.h b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_macros.h
index c5458208d2..fb2e8b3871 100644
--- a/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_macros.h
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_macros.h
@@ -144,169 +144,7 @@ e-mail : support@circuitsathome.com
#define UHS_GET_DPI(x) (x)
#endif
-#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) strncmp((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, ...) ((s), (n), __VA_ARGS__)
-#endif
-#ifndef vsprintf_P
-#define vsprintf_P(s, ...) ((s),__VA_ARGS__)
-#endif
-#ifndef vsnprintf_P
-#define vsnprintf_P(s, n, ...) ((s), (n),__VA_ARGS__)
-#endif
-#ifndef fprintf_P
-#define fprintf_P(s, ...) ((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
-
-#endif
-
+#include "../../../../HAL/shared/progmem.h"
////////////////////////////////////////////////////////////////////////////////
// HANDY MACROS
diff --git a/buildroot/share/PlatformIO/boards/FYSETC_CHEETAH_V20.json b/buildroot/share/PlatformIO/boards/FYSETC_CHEETAH_V20.json
new file mode 100644
index 0000000000..ff082fdc1f
--- /dev/null
+++ b/buildroot/share/PlatformIO/boards/FYSETC_CHEETAH_V20.json
@@ -0,0 +1,66 @@
+{
+ "build": {
+ "core": "stm32",
+ "cpu": "cortex-m4",
+ "extra_flags": "-DSTM32F401xx",
+ "f_cpu": "84000000L",
+ "hwids": [
+ [
+ "0x1EAF",
+ "0x0003"
+ ],
+ [
+ "0x0483",
+ "0x3748"
+ ]
+ ],
+ "ldscript": "stm32f401rc.ld",
+ "mcu": "stm32f401rct6",
+ "variant": "FYSETC_CHEETAH_V20"
+ },
+ "debug": {
+ "jlink_device": "STM32F401RC",
+ "openocd_target": "stm32f4x",
+ "svd_path": "STM32F40x.svd",
+ "tools": {
+ "stlink": {
+ "server": {
+ "arguments": [
+ "-f",
+ "scripts/interface/stlink.cfg",
+ "-c",
+ "transport select hla_swd",
+ "-f",
+ "scripts/target/stm32f4x.cfg",
+ "-c",
+ "reset_config none"
+ ],
+ "executable": "bin/openocd",
+ "package": "tool-openocd"
+ }
+ }
+ }
+ },
+ "frameworks": [
+ "arduino",
+ "stm32cube"
+ ],
+ "name": "STM32F401RC (64k RAM. 256k Flash)",
+ "upload": {
+ "disable_flushing": false,
+ "maximum_ram_size": 65536,
+ "maximum_size": 262144,
+ "protocol": "stlink",
+ "protocols": [
+ "stlink",
+ "dfu",
+ "jlink"
+ ],
+ "offset_address": "0x800C000",
+ "require_upload_port": true,
+ "use_1200bps_touch": false,
+ "wait_for_upload_port": false
+ },
+ "url": "https://www.fysetc.com",
+ "vendor": "Generic"
+}
diff --git a/buildroot/share/PlatformIO/scripts/common-dependencies.py b/buildroot/share/PlatformIO/scripts/common-dependencies.py
index 2f4ad3e502..4500f529a6 100644
--- a/buildroot/share/PlatformIO/scripts/common-dependencies.py
+++ b/buildroot/share/PlatformIO/scripts/common-dependencies.py
@@ -69,16 +69,23 @@ def add_to_feat_cnf(feature, flines):
except:
FEATURE_CONFIG[feature] = {}
+ # Get a reference to the FEATURE_CONFIG under construction
feat = FEATURE_CONFIG[feature]
- atoms = re.sub(',\\s*', '\n', flines).strip().split('\n')
- for dep in atoms:
- parts = dep.split('=')
+
+ # Split up passed lines on commas or newlines and iterate
+ # Add common options to the features config under construction
+ # For lib_deps replace a previous instance of the same library
+ atoms = re.sub(r',\\s*', '\n', flines).strip().split('\n')
+ for line in atoms:
+ parts = line.split('=')
name = parts.pop(0)
- rest = '='.join(parts)
if name in ['build_flags', 'extra_scripts', 'src_filter', 'lib_ignore']:
- feat[name] = rest
+ feat[name] = '='.join(parts)
else:
- feat['lib_deps'] += [dep]
+ for dep in line.split(','):
+ lib_name = re.sub(r'@([~^]|[<>]=?)?[\d.]+', '', dep.strip()).split('=').pop(0)
+ lib_re = re.compile('(?!^' + lib_name + '\\b)')
+ feat['lib_deps'] = list(filter(lib_re.match, feat['lib_deps'])) + [dep]
def load_config():
config = configparser.ConfigParser()
@@ -185,8 +192,8 @@ def apply_features_config():
blab("Adding src_filter for %s... " % feature)
src_filter = ' '.join(env.GetProjectOption('src_filter'))
# first we need to remove the references to the same folder
- my_srcs = re.findall( r'[+-](<.*?>)', feat['src_filter'])
- cur_srcs = re.findall( r'[+-](<.*?>)', src_filter)
+ my_srcs = re.findall(r'[+-](<.*?>)', feat['src_filter'])
+ cur_srcs = re.findall(r'[+-](<.*?>)', src_filter)
for d in my_srcs:
if d in cur_srcs:
src_filter = re.sub(r'[+-]' + d, '', src_filter)
diff --git a/buildroot/share/PlatformIO/scripts/fysetc_cheetah_v20.py b/buildroot/share/PlatformIO/scripts/fysetc_cheetah_v20.py
new file mode 100644
index 0000000000..10471d3753
--- /dev/null
+++ b/buildroot/share/PlatformIO/scripts/fysetc_cheetah_v20.py
@@ -0,0 +1,9 @@
+import os
+Import("env")
+
+custom_ld_script = os.path.abspath("buildroot/share/PlatformIO/variants/FYSETC_CHEETAH_V20/ldscript.ld")
+for i, flag in enumerate(env["LINKFLAGS"]):
+ if "-Wl,-T" in flag:
+ env["LINKFLAGS"][i] = "-Wl,-T" + custom_ld_script
+ elif flag == "-T":
+ env["LINKFLAGS"][i + 1] = custom_ld_script
diff --git a/buildroot/share/PlatformIO/variants/FYSETC_CHEETAH_V20/PeripheralPins.c b/buildroot/share/PlatformIO/variants/FYSETC_CHEETAH_V20/PeripheralPins.c
new file mode 100644
index 0000000000..3957069f28
--- /dev/null
+++ b/buildroot/share/PlatformIO/variants/FYSETC_CHEETAH_V20/PeripheralPins.c
@@ -0,0 +1,266 @@
+/*
+ *******************************************************************************
+ * Copyright (c) 2019, STMicroelectronics
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *******************************************************************************
+ * Automatically generated from STM32F401R[(B-C)|(D-E)]Tx.xml
+ */
+#include "Arduino.h"
+#include "PeripheralPins.h"
+
+/* =====
+ * Note: Commented lines are alternative possibilities which are not used per default.
+ * If you change them, you will have to know what you do
+ * =====
+ */
+
+//*** ADC ***
+
+#ifdef HAL_ADC_MODULE_ENABLED
+WEAK const PinMap PinMap_ADC[] = {
+ {PA_0, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 0, 0)}, // ADC1_IN0
+ {PA_1, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 1, 0)}, // ADC1_IN1
+ {PA_2, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 2, 0)}, // ADC1_IN2
+ {PA_3, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 3, 0)}, // ADC1_IN3
+ {PA_4, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 4, 0)}, // ADC1_IN4
+ {PA_5, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 5, 0)}, // ADC1_IN5
+ {PA_6, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 6, 0)}, // ADC1_IN6
+ {PA_7, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 7, 0)}, // ADC1_IN7
+ {PB_0, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 8, 0)}, // ADC1_IN8
+ {PB_1, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 9, 0)}, // ADC1_IN9
+ {PC_0, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 10, 0)}, // ADC1_IN10
+ {PC_1, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 11, 0)}, // ADC1_IN11
+ {PC_2, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 12, 0)}, // ADC1_IN12
+ {PC_3, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 13, 0)}, // ADC1_IN13
+ {PC_4, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 14, 0)}, // ADC1_IN14
+ {PC_5, ADC1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 15, 0)}, // ADC1_IN15
+ {NC, NP, 0}
+};
+#endif
+
+//*** No DAC ***
+
+//*** I2C ***
+
+#ifdef HAL_I2C_MODULE_ENABLED
+WEAK const PinMap PinMap_I2C_SDA[] = {
+ {PB_3, I2C2, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF9_I2C2)},
+ {PB_4, I2C3, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF9_I2C3)},
+ {PB_7, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C1)},
+ {PB_9, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C1)},
+ {PC_9, I2C3, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C3)},
+ {NC, NP, 0}
+};
+#endif
+
+#ifdef HAL_I2C_MODULE_ENABLED
+WEAK const PinMap PinMap_I2C_SCL[] = {
+ {PA_8, I2C3, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C3)},
+ {PB_6, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C1)},
+ {PB_8, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C1)},
+ {PB_10, I2C2, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF4_I2C2)},
+ {NC, NP, 0}
+};
+#endif
+
+//*** PWM ***
+
+#ifdef HAL_TIM_MODULE_ENABLED
+WEAK const PinMap PinMap_PWM[] = {
+ // {PA_0, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 1, 0)}, // TIM2_CH1
+ {PA_0, TIM5, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 1, 0)}, // TIM5_CH1
+ // {PA_1, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 2, 0)}, // TIM2_CH2
+ {PA_1, TIM5, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 2, 0)}, // TIM5_CH2
+ // {PA_2, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 3, 0)}, // TIM2_CH3
+ {PA_2, TIM5, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 3, 0)}, // TIM5_CH3
+ // {PA_2, TIM9, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM9, 1, 0)}, // TIM9_CH1
+ // {PA_3, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 4, 0)}, // TIM2_CH4
+ {PA_3, TIM5, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 4, 0)}, // TIM5_CH4
+ // {PA_3, TIM9, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM9, 2, 0)}, // TIM9_CH2
+ {PA_5, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 1, 0)}, // TIM2_CH1
+ {PA_6, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 1, 0)}, // TIM3_CH1
+ // {PA_7, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 1)}, // TIM1_CH1N
+ {PA_7, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 2, 0)}, // TIM3_CH2
+ {PA_8, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 0)}, // TIM1_CH1
+ {PA_9, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 0)}, // TIM1_CH2
+ {PA_10, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 0)}, // TIM1_CH3
+ {PA_11, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 4, 0)}, // TIM1_CH4
+ {PA_15, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 1, 0)}, // TIM2_CH1
+ // {PB_0, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 1)}, // TIM1_CH2N
+ {PB_0, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 3, 0)}, // TIM3_CH3
+ // {PB_1, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 1)}, // TIM1_CH3N
+ {PB_1, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 4, 0)}, // TIM3_CH4
+ {PB_3, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 2, 0)}, // TIM2_CH2
+ {PB_4, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 1, 0)}, // TIM3_CH1
+ {PB_5, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 2, 0)}, // TIM3_CH2
+ {PB_6, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 1, 0)}, // TIM4_CH1
+ {PB_7, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 2, 0)}, // TIM4_CH2
+ {PB_8, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 3, 0)}, // TIM4_CH3
+ // {PB_8, TIM10, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM10, 1, 0)}, // TIM10_CH1
+ {PB_9, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 4, 0)}, // TIM4_CH4
+ // {PB_9, TIM11, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM11, 1, 0)}, // TIM11_CH1
+ {PB_10, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 3, 0)}, // TIM2_CH3
+ {PB_13, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 1)}, // TIM1_CH1N
+ {PB_14, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 1)}, // TIM1_CH2N
+ {PB_15, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 1)}, // TIM1_CH3N
+ {PC_6, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 1, 0)}, // TIM3_CH1
+ {PC_7, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 2, 0)}, // TIM3_CH2
+ {PC_8, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 3, 0)}, // TIM3_CH3
+ {PC_9, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 4, 0)}, // TIM3_CH4
+ {NC, NP, 0}
+};
+#endif
+
+//*** SERIAL ***
+
+#ifdef HAL_UART_MODULE_ENABLED
+WEAK const PinMap PinMap_UART_TX[] = {
+ {PA_2, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)},
+ {PA_9, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)},
+ {PA_11, USART6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_USART6)},
+ {PB_6, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)},
+ {PC_6, USART6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_USART6)},
+ {NC, NP, 0}
+};
+#endif
+
+#ifdef HAL_UART_MODULE_ENABLED
+WEAK const PinMap PinMap_UART_RX[] = {
+ {PA_3, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)},
+ {PA_10, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)},
+ {PA_12, USART6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_USART6)},
+ {PB_7, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)},
+ {PC_7, USART6, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_USART6)},
+ {NC, NP, 0}
+};
+#endif
+
+#ifdef HAL_UART_MODULE_ENABLED
+WEAK const PinMap PinMap_UART_RTS[] = {
+ {PA_1, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)},
+ {PA_12, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)},
+ {NC, NP, 0}
+};
+#endif
+
+#ifdef HAL_UART_MODULE_ENABLED
+WEAK const PinMap PinMap_UART_CTS[] = {
+ {PA_0, USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)},
+ {PA_11, USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)},
+ {NC, NP, 0}
+};
+#endif
+
+//*** SPI ***
+
+#ifdef HAL_SPI_MODULE_ENABLED
+WEAK const PinMap PinMap_SPI_MOSI[] = {
+ {PA_7, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)},
+ // {PB_5, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)},
+ {PB_5, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)},
+ {PB_15, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)},
+ {PC_3, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)},
+ {PC_12, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)},
+ {NC, NP, 0}
+};
+#endif
+
+#ifdef HAL_SPI_MODULE_ENABLED
+WEAK const PinMap PinMap_SPI_MISO[] = {
+ {PA_6, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)},
+ // {PB_4, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)},
+ {PB_4, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)},
+ {PB_14, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)},
+ {PC_2, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)},
+ {PC_11, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)},
+ {NC, NP, 0}
+};
+#endif
+
+#ifdef HAL_SPI_MODULE_ENABLED
+WEAK const PinMap PinMap_SPI_SCLK[] = {
+ {PA_5, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)},
+ // {PB_3, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)},
+ {PB_3, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)},
+ {PB_10, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)},
+ {PB_13, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)},
+ {PC_10, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)},
+ {NC, NP, 0}
+};
+#endif
+
+#ifdef HAL_SPI_MODULE_ENABLED
+WEAK const PinMap PinMap_SPI_SSEL[] = {
+ {PA_4, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)},
+ // {PA_4, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)},
+ // {PA_15, SPI1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI1)},
+ {PA_15, SPI3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF6_SPI3)},
+ {PB_9, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)},
+ {PB_12, SPI2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF5_SPI2)},
+ {NC, NP, 0}
+};
+#endif
+
+//*** No CAN ***
+
+//*** No ETHERNET ***
+
+//*** No QUADSPI ***
+
+//*** USB ***
+
+#ifdef HAL_PCD_MODULE_ENABLED
+WEAK const PinMap PinMap_USB_OTG_FS[] = {
+#ifndef ARDUINO_CoreBoard_F401RC
+ {PA_8, USB_OTG_FS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_FS)}, // USB_OTG_FS_SOF
+ {PA_9, USB_OTG_FS, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, GPIO_AF_NONE)}, // USB_OTG_FS_VBUS
+ {PA_10, USB_OTG_FS, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_PULLUP, GPIO_AF10_OTG_FS)}, // USB_OTG_FS_ID
+#endif
+ {PA_11, USB_OTG_FS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_FS)}, // USB_OTG_FS_DM
+ {PA_12, USB_OTG_FS, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_OTG_FS)}, // USB_OTG_FS_DP
+ {NC, NP, 0}
+};
+#endif
+
+//*** No USB_OTG_HS ***
+
+//*** SD ***
+
+#ifdef HAL_SD_MODULE_ENABLED
+WEAK const PinMap PinMap_SD[] = {
+ {PB_8, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D4
+ {PB_9, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D5
+ {PC_6, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D6
+ {PC_7, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D7
+ {PC_8, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D0
+ {PC_9, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D1
+ {PC_10, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D2
+ {PC_11, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF12_SDIO)}, // SDIO_D3
+ {PC_12, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF12_SDIO)}, // SDIO_CK
+ {PD_2, SDIO, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF12_SDIO)}, // SDIO_CMD
+ {NC, NP, 0}
+};
+#endif
diff --git a/buildroot/share/PlatformIO/variants/FYSETC_CHEETAH_V20/PinNamesVar.h b/buildroot/share/PlatformIO/variants/FYSETC_CHEETAH_V20/PinNamesVar.h
new file mode 100644
index 0000000000..e1536bcf30
--- /dev/null
+++ b/buildroot/share/PlatformIO/variants/FYSETC_CHEETAH_V20/PinNamesVar.h
@@ -0,0 +1,33 @@
+/* SYS_WKUP */
+#ifdef PWR_WAKEUP_PIN1
+ SYS_WKUP1 = PA_0,
+#endif
+#ifdef PWR_WAKEUP_PIN2
+ SYS_WKUP2 = NC,
+#endif
+#ifdef PWR_WAKEUP_PIN3
+ SYS_WKUP3 = NC,
+#endif
+#ifdef PWR_WAKEUP_PIN4
+ SYS_WKUP4 = NC,
+#endif
+#ifdef PWR_WAKEUP_PIN5
+ SYS_WKUP5 = NC,
+#endif
+#ifdef PWR_WAKEUP_PIN6
+ SYS_WKUP6 = NC,
+#endif
+#ifdef PWR_WAKEUP_PIN7
+ SYS_WKUP7 = NC,
+#endif
+#ifdef PWR_WAKEUP_PIN8
+ SYS_WKUP8 = NC,
+#endif
+/* USB */
+#ifdef USBCON
+ USB_OTG_FS_SOF = PA_8,
+ USB_OTG_FS_VBUS = PA_9,
+ USB_OTG_FS_ID = PA_10,
+ USB_OTG_FS_DM = PA_11,
+ USB_OTG_FS_DP = PA_12,
+#endif
\ No newline at end of file
diff --git a/buildroot/share/PlatformIO/variants/FYSETC_CHEETAH_V20/hal_conf_custom.h b/buildroot/share/PlatformIO/variants/FYSETC_CHEETAH_V20/hal_conf_custom.h
new file mode 100644
index 0000000000..1b9df2b47a
--- /dev/null
+++ b/buildroot/share/PlatformIO/variants/FYSETC_CHEETAH_V20/hal_conf_custom.h
@@ -0,0 +1,496 @@
+/**
+ ******************************************************************************
+ * @file stm32f4xx_hal_conf.h
+ * @brief HAL configuration file.
+ ******************************************************************************
+ * @attention
+ *
+ * © Copyright (c) 2017 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under BSD 3-Clause license,
+ * the "License"; You may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ * opensource.org/licenses/BSD-3-Clause
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F4xx_HAL_CONF_CUSTOM
+#define __STM32F4xx_HAL_CONF_CUSTOM
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+/* ########################## Module Selection ############################## */
+ /**
+ * @brief This is the list of modules to be used in the HAL driver
+ */
+#define HAL_MODULE_ENABLED
+#define HAL_ADC_MODULE_ENABLED
+/* #define HAL_CAN_MODULE_ENABLED */
+/* #define HAL_CAN_LEGACY_MODULE_ENABLED */
+#define HAL_CRC_MODULE_ENABLED
+/* #define HAL_CEC_MODULE_ENABLED */
+/* #define HAL_CRYP_MODULE_ENABLED */
+//#define HAL_DAC_MODULE_ENABLED
+/* #define HAL_DCMI_MODULE_ENABLED */
+#define HAL_DMA_MODULE_ENABLED
+/* #define HAL_DMA2D_MODULE_ENABLED */
+/* #define HAL_ETH_MODULE_ENABLED */
+#define HAL_FLASH_MODULE_ENABLED
+/* #define HAL_NAND_MODULE_ENABLED */
+/* #define HAL_NOR_MODULE_ENABLED */
+/* #define HAL_PCCARD_MODULE_ENABLED */
+/* #define HAL_SRAM_MODULE_ENABLED */
+/* #define HAL_SDRAM_MODULE_ENABLED */
+/* #define HAL_HASH_MODULE_ENABLED */
+#define HAL_GPIO_MODULE_ENABLED
+/* #define HAL_EXTI_MODULE_ENABLED */
+#define HAL_I2C_MODULE_ENABLED
+/* #define HAL_SMBUS_MODULE_ENABLED */
+/* #define HAL_I2S_MODULE_ENABLED */
+#define HAL_IWDG_MODULE_ENABLED
+/* #define HAL_LTDC_MODULE_ENABLED */
+/* #define HAL_DSI_MODULE_ENABLED */
+#define HAL_PWR_MODULE_ENABLED
+/* #define HAL_QSPI_MODULE_ENABLED */
+#define HAL_RCC_MODULE_ENABLED
+/* #define HAL_RNG_MODULE_ENABLED */
+#define HAL_RTC_MODULE_ENABLED
+/* #define HAL_SAI_MODULE_ENABLED */
+//#define HAL_SD_MODULE_ENABLED
+#define HAL_SPI_MODULE_ENABLED
+#define HAL_TIM_MODULE_ENABLED
+/* #define HAL_UART_MODULE_ENABLED */
+/* #define HAL_USART_MODULE_ENABLED */
+/* #define HAL_IRDA_MODULE_ENABLED */
+/* #define HAL_SMARTCARD_MODULE_ENABLED */
+/* #define HAL_WWDG_MODULE_ENABLED */
+#define HAL_CORTEX_MODULE_ENABLED
+#ifndef HAL_PCD_MODULE_ENABLED
+ #define HAL_PCD_MODULE_ENABLED //Since STM32 v3.10700.191028 this is automatically added if any type of USB is enabled (as in Arduino IDE)
+#endif
+/* #define HAL_HCD_MODULE_ENABLED */
+/* #define HAL_FMPI2C_MODULE_ENABLED */
+/* #define HAL_SPDIFRX_MODULE_ENABLED */
+/* #define HAL_DFSDM_MODULE_ENABLED */
+/* #define HAL_LPTIM_MODULE_ENABLED */
+/* #define HAL_MMC_MODULE_ENABLED */
+
+/* ########################## HSE/HSI Values adaptation ##################### */
+/**
+ * @brief Adjust the value of External High Speed oscillator (HSE) used in your application.
+ * This value is used by the RCC HAL module to compute the system frequency
+ * (when HSE is used as system clock source, directly or through the PLL).
+ */
+#ifndef HSE_VALUE
+#define HSE_VALUE 8000000U /*!< Value of the External oscillator in Hz */
+#endif /* HSE_VALUE */
+
+#ifndef HSE_STARTUP_TIMEOUT
+#define HSE_STARTUP_TIMEOUT 100U /*!< Time out for HSE start up, in ms */
+#endif /* HSE_STARTUP_TIMEOUT */
+
+/**
+ * @brief Internal High Speed oscillator (HSI) value.
+ * This value is used by the RCC HAL module to compute the system frequency
+ * (when HSI is used as system clock source, directly or through the PLL).
+ */
+#ifndef HSI_VALUE
+#define HSI_VALUE 16000000U /*!< Value of the Internal oscillator in Hz */
+#endif /* HSI_VALUE */
+
+/**
+ * @brief Internal Low Speed oscillator (LSI) value.
+ */
+#ifndef LSI_VALUE
+#define LSI_VALUE 32000U /*!< LSI Typical Value in Hz */
+#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz
+The real value may vary depending on the variations
+in voltage and temperature. */
+/**
+ * @brief External Low Speed oscillator (LSE) value.
+ */
+#ifndef LSE_VALUE
+#define LSE_VALUE 32768U /*!< Value of the External Low Speed oscillator in Hz */
+#endif /* LSE_VALUE */
+
+#ifndef LSE_STARTUP_TIMEOUT
+#define LSE_STARTUP_TIMEOUT 5000U /*!< Time out for LSE start up, in ms */
+#endif /* LSE_STARTUP_TIMEOUT */
+
+/**
+ * @brief External clock source for I2S peripheral
+ * This value is used by the I2S HAL module to compute the I2S clock source
+ * frequency, this source is inserted directly through I2S_CKIN pad.
+ */
+#ifndef EXTERNAL_CLOCK_VALUE
+#define EXTERNAL_CLOCK_VALUE 12288000U /*!< Value of the External oscillator in Hz*/
+#endif /* EXTERNAL_CLOCK_VALUE */
+
+/* Tip: To avoid modifying this file each time you need to use different HSE,
+ === you can define the HSE value in your toolchain compiler preprocessor. */
+
+/* ########################### System Configuration ######################### */
+/**
+ * @brief This is the HAL system configuration section
+ */
+#if !defined (VDD_VALUE)
+#define VDD_VALUE 3300U /*!< Value of VDD in mv */
+#endif
+#if !defined (TICK_INT_PRIORITY)
+#define TICK_INT_PRIORITY 0x00U /*!< tick interrupt priority */
+#endif
+#if !defined (USE_RTOS)
+#define USE_RTOS 0U
+#endif
+#if !defined (PREFETCH_ENABLE)
+#define PREFETCH_ENABLE 1U
+#endif
+#if !defined (INSTRUCTION_CACHE_ENABLE)
+#define INSTRUCTION_CACHE_ENABLE 1U
+#endif
+#if !defined (DATA_CACHE_ENABLE)
+#define DATA_CACHE_ENABLE 1U
+#endif
+
+#define USE_HAL_ADC_REGISTER_CALLBACKS 0U /* ADC register callback disabled */
+#define USE_HAL_CAN_REGISTER_CALLBACKS 0U /* CAN register callback disabled */
+#define USE_HAL_CEC_REGISTER_CALLBACKS 0U /* CEC register callback disabled */
+#define USE_HAL_CRYP_REGISTER_CALLBACKS 0U /* CRYP register callback disabled */
+#define USE_HAL_DAC_REGISTER_CALLBACKS 0U /* DAC register callback disabled */
+#define USE_HAL_DCMI_REGISTER_CALLBACKS 0U /* DCMI register callback disabled */
+#define USE_HAL_DFSDM_REGISTER_CALLBACKS 0U /* DFSDM register callback disabled */
+#define USE_HAL_DMA2D_REGISTER_CALLBACKS 0U /* DMA2D register callback disabled */
+#define USE_HAL_DSI_REGISTER_CALLBACKS 0U /* DSI register callback disabled */
+#define USE_HAL_ETH_REGISTER_CALLBACKS 0U /* ETH register callback disabled */
+#define USE_HAL_HASH_REGISTER_CALLBACKS 0U /* HASH register callback disabled */
+#define USE_HAL_HCD_REGISTER_CALLBACKS 0U /* HCD register callback disabled */
+#define USE_HAL_I2C_REGISTER_CALLBACKS 0U /* I2C register callback disabled */
+#define USE_HAL_FMPI2C_REGISTER_CALLBACKS 0U /* FMPI2C register callback disabled */
+#define USE_HAL_I2S_REGISTER_CALLBACKS 0U /* I2S register callback disabled */
+#define USE_HAL_IRDA_REGISTER_CALLBACKS 0U /* IRDA register callback disabled */
+#define USE_HAL_LPTIM_REGISTER_CALLBACKS 0U /* LPTIM register callback disabled */
+#define USE_HAL_LTDC_REGISTER_CALLBACKS 0U /* LTDC register callback disabled */
+#define USE_HAL_MMC_REGISTER_CALLBACKS 0U /* MMC register callback disabled */
+#define USE_HAL_NAND_REGISTER_CALLBACKS 0U /* NAND register callback disabled */
+#define USE_HAL_NOR_REGISTER_CALLBACKS 0U /* NOR register callback disabled */
+#define USE_HAL_PCCARD_REGISTER_CALLBACKS 0U /* PCCARD register callback disabled */
+#define USE_HAL_PCD_REGISTER_CALLBACKS 0U /* PCD register callback disabled */
+#define USE_HAL_QSPI_REGISTER_CALLBACKS 0U /* QSPI register callback disabled */
+#define USE_HAL_RNG_REGISTER_CALLBACKS 0U /* RNG register callback disabled */
+#define USE_HAL_RTC_REGISTER_CALLBACKS 0U /* RTC register callback disabled */
+#define USE_HAL_SAI_REGISTER_CALLBACKS 0U /* SAI register callback disabled */
+#define USE_HAL_SD_REGISTER_CALLBACKS 0U /* SD register callback disabled */
+#define USE_HAL_SMARTCARD_REGISTER_CALLBACKS 0U /* SMARTCARD register callback disabled */
+#define USE_HAL_SDRAM_REGISTER_CALLBACKS 0U /* SDRAM register callback disabled */
+#define USE_HAL_SRAM_REGISTER_CALLBACKS 0U /* SRAM register callback disabled */
+#define USE_HAL_SPDIFRX_REGISTER_CALLBACKS 0U /* SPDIFRX register callback disabled */
+#define USE_HAL_SMBUS_REGISTER_CALLBACKS 0U /* SMBUS register callback disabled */
+#define USE_HAL_SPI_REGISTER_CALLBACKS 0U /* SPI register callback disabled */
+#define USE_HAL_TIM_REGISTER_CALLBACKS 0U /* TIM register callback disabled */
+#define USE_HAL_UART_REGISTER_CALLBACKS 0U /* UART register callback disabled */
+#define USE_HAL_USART_REGISTER_CALLBACKS 0U /* USART register callback disabled */
+#define USE_HAL_WWDG_REGISTER_CALLBACKS 0U /* WWDG register callback disabled */
+
+/* ########################## Assert Selection ############################## */
+/**
+ * @brief Uncomment the line below to expanse the "assert_param" macro in the
+ * HAL drivers code
+ */
+/* #define USE_FULL_ASSERT 1U */
+
+/* ################## Ethernet peripheral configuration ##################### */
+
+/* Section 1 : Ethernet peripheral configuration */
+
+/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */
+#define MAC_ADDR0 2U
+#define MAC_ADDR1 0U
+#define MAC_ADDR2 0U
+#define MAC_ADDR3 0U
+#define MAC_ADDR4 0U
+#define MAC_ADDR5 0U
+
+/* Definition of the Ethernet driver buffers size and count */
+#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */
+#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */
+#define ETH_RXBUFNB ((uint32_t)4U) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */
+#define ETH_TXBUFNB ((uint32_t)4U) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */
+
+/* Section 2: PHY configuration section */
+
+/* DP83848_PHY_ADDRESS Address*/
+#define DP83848_PHY_ADDRESS 0x01U
+/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
+#define PHY_RESET_DELAY 0x000000FFU
+/* PHY Configuration delay */
+#define PHY_CONFIG_DELAY 0x00000FFFU
+
+#define PHY_READ_TO 0x0000FFFFU
+#define PHY_WRITE_TO 0x0000FFFFU
+
+/* Section 3: Common PHY Registers */
+
+#define PHY_BCR ((uint16_t)0x0000) /*!< Transceiver Basic Control Register */
+#define PHY_BSR ((uint16_t)0x0001) /*!< Transceiver Basic Status Register */
+
+#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */
+#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */
+#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */
+#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */
+#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */
+#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */
+#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */
+#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */
+#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */
+#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */
+
+#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */
+#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */
+#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */
+
+/* Section 4: Extended PHY Registers */
+#define PHY_SR ((uint16_t)0x10U) /*!< PHY status register Offset */
+
+#define PHY_SPEED_STATUS ((uint16_t)0x0002U) /*!< PHY Speed mask */
+#define PHY_DUPLEX_STATUS ((uint16_t)0x0004U) /*!< PHY Duplex mask */
+
+/* ################## SPI peripheral configuration ########################## */
+
+/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver
+ * Activated: CRC code is present inside driver
+ * Deactivated: CRC code cleaned from driver
+ */
+#ifndef USE_SPI_CRC
+#define USE_SPI_CRC 0U
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+/**
+ * @brief Include module's header file
+ */
+
+#ifdef HAL_RCC_MODULE_ENABLED
+#include "stm32f4xx_hal_rcc.h"
+#endif /* HAL_RCC_MODULE_ENABLED */
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+#include "stm32f4xx_hal_gpio.h"
+#endif /* HAL_GPIO_MODULE_ENABLED */
+
+#ifdef HAL_EXTI_MODULE_ENABLED
+#include "stm32f4xx_hal_exti.h"
+#endif /* HAL_EXTI_MODULE_ENABLED */
+
+#ifdef HAL_DMA_MODULE_ENABLED
+#include "stm32f4xx_hal_dma.h"
+#endif /* HAL_DMA_MODULE_ENABLED */
+
+#ifdef HAL_CORTEX_MODULE_ENABLED
+#include "stm32f4xx_hal_cortex.h"
+#endif /* HAL_CORTEX_MODULE_ENABLED */
+
+#ifdef HAL_ADC_MODULE_ENABLED
+#include "stm32f4xx_hal_adc.h"
+#endif /* HAL_ADC_MODULE_ENABLED */
+
+#ifdef HAL_CAN_MODULE_ENABLED
+#include "stm32f4xx_hal_can.h"
+#endif /* HAL_CAN_MODULE_ENABLED */
+
+#ifdef HAL_CAN_LEGACY_MODULE_ENABLED
+#include "stm32f4xx_hal_can_legacy.h"
+#endif /* HAL_CAN_LEGACY_MODULE_ENABLED */
+
+#ifdef HAL_CRC_MODULE_ENABLED
+#include "stm32f4xx_hal_crc.h"
+#endif /* HAL_CRC_MODULE_ENABLED */
+
+#ifdef HAL_CRYP_MODULE_ENABLED
+#include "stm32f4xx_hal_cryp.h"
+#endif /* HAL_CRYP_MODULE_ENABLED */
+
+#ifdef HAL_DMA2D_MODULE_ENABLED
+#include "stm32f4xx_hal_dma2d.h"
+#endif /* HAL_DMA2D_MODULE_ENABLED */
+
+#ifdef HAL_DAC_MODULE_ENABLED
+#include "stm32f4xx_hal_dac.h"
+#endif /* HAL_DAC_MODULE_ENABLED */
+
+#ifdef HAL_DCMI_MODULE_ENABLED
+#include "stm32f4xx_hal_dcmi.h"
+#endif /* HAL_DCMI_MODULE_ENABLED */
+
+#ifdef HAL_ETH_MODULE_ENABLED
+#include "stm32f4xx_hal_eth.h"
+#endif /* HAL_ETH_MODULE_ENABLED */
+
+#ifdef HAL_FLASH_MODULE_ENABLED
+#include "stm32f4xx_hal_flash.h"
+#endif /* HAL_FLASH_MODULE_ENABLED */
+
+#ifdef HAL_SRAM_MODULE_ENABLED
+#include "stm32f4xx_hal_sram.h"
+#endif /* HAL_SRAM_MODULE_ENABLED */
+
+#ifdef HAL_NOR_MODULE_ENABLED
+#include "stm32f4xx_hal_nor.h"
+#endif /* HAL_NOR_MODULE_ENABLED */
+
+#ifdef HAL_NAND_MODULE_ENABLED
+#include "stm32f4xx_hal_nand.h"
+#endif /* HAL_NAND_MODULE_ENABLED */
+
+#ifdef HAL_PCCARD_MODULE_ENABLED
+#include "stm32f4xx_hal_pccard.h"
+#endif /* HAL_PCCARD_MODULE_ENABLED */
+
+#ifdef HAL_SDRAM_MODULE_ENABLED
+#include "stm32f4xx_hal_sdram.h"
+#endif /* HAL_SDRAM_MODULE_ENABLED */
+
+#ifdef HAL_HASH_MODULE_ENABLED
+#include "stm32f4xx_hal_hash.h"
+#endif /* HAL_HASH_MODULE_ENABLED */
+
+#ifdef HAL_I2C_MODULE_ENABLED
+#include "stm32f4xx_hal_i2c.h"
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+#ifdef HAL_SMBUS_MODULE_ENABLED
+#include "stm32f4xx_hal_smbus.h"
+#endif /* HAL_SMBUS_MODULE_ENABLED */
+
+#ifdef HAL_I2S_MODULE_ENABLED
+#include "stm32f4xx_hal_i2s.h"
+#endif /* HAL_I2S_MODULE_ENABLED */
+
+#ifdef HAL_IWDG_MODULE_ENABLED
+#include "stm32f4xx_hal_iwdg.h"
+#endif /* HAL_IWDG_MODULE_ENABLED */
+
+#ifdef HAL_LTDC_MODULE_ENABLED
+#include "stm32f4xx_hal_ltdc.h"
+#endif /* HAL_LTDC_MODULE_ENABLED */
+
+#ifdef HAL_PWR_MODULE_ENABLED
+#include "stm32f4xx_hal_pwr.h"
+#endif /* HAL_PWR_MODULE_ENABLED */
+
+#ifdef HAL_RNG_MODULE_ENABLED
+#include "stm32f4xx_hal_rng.h"
+#endif /* HAL_RNG_MODULE_ENABLED */
+
+#ifdef HAL_RTC_MODULE_ENABLED
+#include "stm32f4xx_hal_rtc.h"
+#endif /* HAL_RTC_MODULE_ENABLED */
+
+#ifdef HAL_SAI_MODULE_ENABLED
+#include "stm32f4xx_hal_sai.h"
+#endif /* HAL_SAI_MODULE_ENABLED */
+
+#ifdef HAL_SD_MODULE_ENABLED
+#include "stm32f4xx_hal_sd.h"
+#endif /* HAL_SD_MODULE_ENABLED */
+
+#ifdef HAL_SPI_MODULE_ENABLED
+#include "stm32f4xx_hal_spi.h"
+#endif /* HAL_SPI_MODULE_ENABLED */
+
+#ifdef HAL_TIM_MODULE_ENABLED
+#include "stm32f4xx_hal_tim.h"
+#endif /* HAL_TIM_MODULE_ENABLED */
+
+#ifdef HAL_UART_MODULE_ENABLED
+#include "stm32f4xx_hal_uart.h"
+#endif /* HAL_UART_MODULE_ENABLED */
+
+#ifdef HAL_USART_MODULE_ENABLED
+#include "stm32f4xx_hal_usart.h"
+#endif /* HAL_USART_MODULE_ENABLED */
+
+#ifdef HAL_IRDA_MODULE_ENABLED
+#include "stm32f4xx_hal_irda.h"
+#endif /* HAL_IRDA_MODULE_ENABLED */
+
+#ifdef HAL_SMARTCARD_MODULE_ENABLED
+#include "stm32f4xx_hal_smartcard.h"
+#endif /* HAL_SMARTCARD_MODULE_ENABLED */
+
+#ifdef HAL_WWDG_MODULE_ENABLED
+#include "stm32f4xx_hal_wwdg.h"
+#endif /* HAL_WWDG_MODULE_ENABLED */
+
+#ifdef HAL_PCD_MODULE_ENABLED
+#include "stm32f4xx_hal_pcd.h"
+#endif /* HAL_PCD_MODULE_ENABLED */
+
+#ifdef HAL_HCD_MODULE_ENABLED
+#include "stm32f4xx_hal_hcd.h"
+#endif /* HAL_HCD_MODULE_ENABLED */
+
+#ifdef HAL_DSI_MODULE_ENABLED
+#include "stm32f4xx_hal_dsi.h"
+#endif /* HAL_DSI_MODULE_ENABLED */
+
+#ifdef HAL_QSPI_MODULE_ENABLED
+#include "stm32f4xx_hal_qspi.h"
+#endif /* HAL_QSPI_MODULE_ENABLED */
+
+#ifdef HAL_CEC_MODULE_ENABLED
+#include "stm32f4xx_hal_cec.h"
+#endif /* HAL_CEC_MODULE_ENABLED */
+
+#ifdef HAL_FMPI2C_MODULE_ENABLED
+#include "stm32f4xx_hal_fmpi2c.h"
+#endif /* HAL_FMPI2C_MODULE_ENABLED */
+
+#ifdef HAL_SPDIFRX_MODULE_ENABLED
+#include "stm32f4xx_hal_spdifrx.h"
+#endif /* HAL_SPDIFRX_MODULE_ENABLED */
+
+#ifdef HAL_DFSDM_MODULE_ENABLED
+#include "stm32f4xx_hal_dfsdm.h"
+#endif /* HAL_DFSDM_MODULE_ENABLED */
+
+#ifdef HAL_LPTIM_MODULE_ENABLED
+#include "stm32f4xx_hal_lptim.h"
+#endif /* HAL_LPTIM_MODULE_ENABLED */
+
+#ifdef HAL_MMC_MODULE_ENABLED
+#include "stm32f4xx_hal_mmc.h"
+#endif /* HAL_MMC_MODULE_ENABLED */
+
+/* Exported macro ------------------------------------------------------------*/
+#ifdef USE_FULL_ASSERT
+/**
+ * @brief The assert_param macro is used for function's parameters check.
+ * @param expr If expr is false, it calls assert_failed function
+ * which reports the name of the source file and the source
+ * line number of the call that failed.
+ * If expr is true, it returns no value.
+ * @retval None
+ */
+#define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__))
+/* Exported functions ------------------------------------------------------- */
+void assert_failed(uint8_t *file, uint32_t line);
+#else
+#define assert_param(expr) ((void)0U)
+#endif /* USE_FULL_ASSERT */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32F4xx_HAL_CONF_CUSTOM_H */
+
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/buildroot/share/PlatformIO/variants/FYSETC_CHEETAH_V20/ldscript.ld b/buildroot/share/PlatformIO/variants/FYSETC_CHEETAH_V20/ldscript.ld
new file mode 100644
index 0000000000..2dbc5177ac
--- /dev/null
+++ b/buildroot/share/PlatformIO/variants/FYSETC_CHEETAH_V20/ldscript.ld
@@ -0,0 +1,187 @@
+/*
+*****************************************************************************
+**
+
+** File : LinkerScript.ld
+**
+** Abstract : Linker script for STM32F401RETx Device with
+** 512KByte FLASH, 96KByte RAM
+**
+** Set heap size, stack size and stack location according
+** to application requirements.
+**
+** Set memory bank area and size if external memory is used.
+**
+** Target : STMicroelectronics STM32
+**
+**
+** Distribution: The file is distributed as is, without any warranty
+** of any kind.
+**
+*****************************************************************************
+** @attention
+**
+** © COPYRIGHT(c) 2014 Ac6
+**
+** Redistribution and use in source and binary forms, with or without modification,
+** are permitted provided that the following conditions are met:
+** 1. Redistributions of source code must retain the above copyright notice,
+** this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright notice,
+** this list of conditions and the following disclaimer in the documentation
+** and/or other materials provided with the distribution.
+** 3. Neither the name of Ac6 nor the names of its contributors
+** may be used to endorse or promote products derived from this software
+** without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**
+*****************************************************************************
+*/
+
+/* Entry Point */
+ENTRY(Reset_Handler)
+
+/* Highest address of the user mode stack */
+_estack = 0x20010000; /* end of RAM */
+
+/* Generate a link error if heap and stack don't fit into RAM */
+_Min_Heap_Size = 0x200;; /* required amount of heap */
+_Min_Stack_Size = 0x400;; /* required amount of stack */
+
+/* Specify the memory areas */
+MEMORY
+{
+FLASH (rx) : ORIGIN = 0x800C000, LENGTH = 256K
+RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
+}
+
+/* Define output sections */
+SECTIONS
+{
+ /* The startup code goes first into FLASH */
+ .isr_vector :
+ {
+ . = ALIGN(4);
+ KEEP(*(.isr_vector)) /* Startup code */
+ . = ALIGN(4);
+ } >FLASH
+
+ /* The program code and other data goes into FLASH */
+ .text ALIGN(4):
+ {
+ . = ALIGN(4);
+ *(.text) /* .text sections (code) */
+ *(.text*) /* .text* sections (code) */
+ *(.glue_7) /* glue arm to thumb code */
+ *(.glue_7t) /* glue thumb to arm code */
+ *(.eh_frame)
+
+ KEEP (*(.init))
+ KEEP (*(.fini))
+
+ . = ALIGN(4);
+ _etext = .; /* define a global symbols at end of code */
+ } >FLASH
+
+ /* Constant data goes into FLASH */
+ .rodata :
+ {
+ . = ALIGN(4);
+ *(.rodata) /* .rodata sections (constants, strings, etc.) */
+ *(.rodata*) /* .rodata* sections (constants, strings, etc.) */
+ . = ALIGN(4);
+ } >FLASH
+
+ .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
+ .ARM : {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >FLASH
+
+ .preinit_array :
+ {
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP (*(.preinit_array*))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+ } >FLASH
+ .init_array :
+ {
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array*))
+ PROVIDE_HIDDEN (__init_array_end = .);
+ } >FLASH
+ .fini_array :
+ {
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ KEEP (*(SORT(.fini_array.*)))
+ KEEP (*(.fini_array*))
+ PROVIDE_HIDDEN (__fini_array_end = .);
+ } >FLASH
+
+ /* used by the startup to initialize data */
+ _sidata = LOADADDR(.data);
+
+ /* Initialized data sections goes into RAM, load LMA copy after code */
+ .data :
+ {
+ . = ALIGN(4);
+ _sdata = .; /* create a global symbol at data start */
+ *(.data) /* .data sections */
+ *(.data*) /* .data* sections */
+
+ . = ALIGN(4);
+ _edata = .; /* define a global symbol at data end */
+ } >RAM AT> FLASH
+
+
+ /* Uninitialized data section */
+ . = ALIGN(4);
+ .bss :
+ {
+ /* This is used by the startup in order to initialize the .bss secion */
+ _sbss = .; /* define a global symbol at bss start */
+ __bss_start__ = _sbss;
+ *(.bss)
+ *(.bss*)
+ *(COMMON)
+
+ . = ALIGN(4);
+ _ebss = .; /* define a global symbol at bss end */
+ __bss_end__ = _ebss;
+ } >RAM
+
+ /* User_heap_stack section, used to check that there is enough RAM left */
+ ._user_heap_stack :
+ {
+ . = ALIGN(8);
+ PROVIDE ( end = . );
+ PROVIDE ( _end = . );
+ . = . + _Min_Heap_Size;
+ . = . + _Min_Stack_Size;
+ . = ALIGN(8);
+ } >RAM
+
+
+
+ /* Remove information from the standard libraries */
+ /DISCARD/ :
+ {
+ libc.a ( * )
+ libm.a ( * )
+ libgcc.a ( * )
+ }
+
+ .ARM.attributes 0 : { *(.ARM.attributes) }
+}
\ No newline at end of file
diff --git a/buildroot/share/PlatformIO/variants/FYSETC_CHEETAH_V20/variant.cpp b/buildroot/share/PlatformIO/variants/FYSETC_CHEETAH_V20/variant.cpp
new file mode 100644
index 0000000000..71f3509ed5
--- /dev/null
+++ b/buildroot/share/PlatformIO/variants/FYSETC_CHEETAH_V20/variant.cpp
@@ -0,0 +1,238 @@
+/*
+ Copyright (c) 2011 Arduino. All right reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "pins_arduino.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Digital PinName array
+const PinName digitalPin[] = {
+ PA_0, // Digital pin 0
+ PA_1, // Digital pin 1
+ PA_2, // Digital pin 2
+ PA_3, // Digital pin 3
+ PA_4, // Digital pin 4
+ PA_5, // Digital pin 5
+ PA_6, // Digital pin 6
+ PA_7, // Digital pin 7
+ PA_8, // Digital pin 8
+ PA_9, // Digital pin 9
+ PA_10, // Digital pin 10
+ PA_11, // Digital pin 11
+ PA_12, // Digital pin 12
+ PA_13, // Digital pin 13
+ PA_14, // Digital pin 14
+ PA_15, // Digital pin 15
+
+ PB_0, // Digital pin 16
+ PB_1, // Digital pin 17
+ PB_2, // Digital pin 18
+ PB_3, // Digital pin 19
+ PB_4, // Digital pin 20
+ PB_5, // Digital pin 21
+ PB_6, // Digital pin 22
+ PB_7, // Digital pin 23
+ PB_8, // Digital pin 24
+ PB_9, // Digital pin 25
+ PB_10, // Digital pin 26
+ PB_12, // Digital pin 27
+ PB_13, // Digital pin 28
+ PB_14, // Digital pin 29
+ PB_15, // Digital pin 30
+
+ PC_0, // Digital pin 31
+ PC_1, // Digital pin 32
+ PC_2, // Digital pin 33
+ PC_3, // Digital pin 34
+ PC_4, // Digital pin 35
+ PC_5, // Digital pin 36
+ PC_6, // Digital pin 37
+ PC_7, // Digital pin 38
+ PC_8, // Digital pin 39
+ PC_9, // Digital pin 40
+ PC_10, // Digital pin 41
+ PC_11, // Digital pin 42
+ PC_12, // Digital pin 43
+ PC_13, // Digital pin 44
+ PC_14, // Digital pin 45
+ PC_15, // Digital pin 46
+
+ PD_2, // Digital pin 47
+
+ PH_0, // Digital pin 48, used by the external oscillator
+ PH_1 // Digital pin 49, used by the external oscillator
+};
+
+// Analog (Ax) pin number array
+const uint32_t analogInputPin[] = {
+ 0, // A0, PA0
+ 1, // A1, PA1
+ 2, // A2, PA2
+ 3, // A3, PA3
+ 4, // A4, PA4
+ 5, // A5, PA5
+ 6, // A6, PA6
+ 7, // A7, PA7
+ 16, // A8, PB0
+ 17, // A9, PB1
+ 31, // A10, PC0
+ 32, // A11, PC1
+ 33, // A12, PC2
+ 34, // A13, PC3
+ 35, // A14, PC4
+ 36 // A15, PC5
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+// ----------------------------------------------------------------------------
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * @brief Configures the System clock source, PLL Multiplier and Divider factors,
+ * AHB/APBx prescalers and Flash settings
+ * @note This function should be called only once the RCC clock configuration
+ * is reset to the default reset state (done in SystemInit() function).
+ * @param None
+ * @retval None
+ */
+
+/******************************************************************************/
+/* PLL (clocked by HSE) used as System clock source */
+/******************************************************************************/
+static uint8_t SetSysClock_PLL_HSE(uint8_t bypass)
+{
+ RCC_OscInitTypeDef RCC_OscInitStruct;
+ RCC_ClkInitTypeDef RCC_ClkInitStruct;
+
+ /* The voltage scaling allows optimizing the power consumption when the device is
+ clocked below the maximum system frequency, to update the voltage scaling value
+ regarding system frequency refer to product datasheet. */
+ __HAL_RCC_PWR_CLK_ENABLE();
+ __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
+
+ // Enable HSE oscillator and activate PLL with HSE as source
+ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
+ if (bypass == 0) {
+ RCC_OscInitStruct.HSEState = RCC_HSE_ON; // External 8 MHz xtal on OSC_IN/OSC_OUT
+ } else {
+ RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS; // External 8 MHz clock on OSC_IN
+ }
+
+ RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
+ RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
+ RCC_OscInitStruct.PLL.PLLM = HSE_VALUE / 1000000L; // Expects an 8 MHz external clock by default. Redefine HSE_VALUE if not
+ RCC_OscInitStruct.PLL.PLLN = 336; // VCO output clock = 336 MHz (1 MHz * 336)
+ RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4; // PLLCLK = 84 MHz (336 MHz / 4)
+ RCC_OscInitStruct.PLL.PLLQ = 7; // USB clock = 48 MHz (336 MHz / 7) --> OK for USB
+ if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
+ return 0; // FAIL
+ }
+
+ // Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 clocks dividers
+ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
+ RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; // 84 MHz
+ RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // 84 MHz
+ RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; // 42 MHz
+ RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; // 84 MHz
+ if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) {
+ return 0; // FAIL
+ }
+
+ /* Output clock on MCO1 pin(PA8) for debugging purpose */
+ /*
+ if (bypass == 0)
+ HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_HSE, RCC_MCODIV_2); // 4 MHz
+ else
+ HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_HSE, RCC_MCODIV_1); // 8 MHz
+ */
+
+ return 1; // OK
+}
+
+/******************************************************************************/
+/* PLL (clocked by HSI) used as System clock source */
+/******************************************************************************/
+uint8_t SetSysClock_PLL_HSI(void)
+{
+ RCC_OscInitTypeDef RCC_OscInitStruct;
+ RCC_ClkInitTypeDef RCC_ClkInitStruct;
+
+ /* The voltage scaling allows optimizing the power consumption when the device is
+ clocked below the maximum system frequency, to update the voltage scaling value
+ regarding system frequency refer to product datasheet. */
+ __HAL_RCC_PWR_CLK_ENABLE();
+ __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
+
+ // Enable HSI oscillator and activate PLL with HSI as source
+ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI | RCC_OSCILLATORTYPE_HSE;
+ RCC_OscInitStruct.HSIState = RCC_HSI_ON;
+ RCC_OscInitStruct.HSEState = RCC_HSE_OFF;
+ RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
+ RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
+ RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
+ RCC_OscInitStruct.PLL.PLLM = 16; // VCO input clock = 1 MHz (16 MHz / 16)
+ RCC_OscInitStruct.PLL.PLLN = 336; // VCO output clock = 336 MHz (1 MHz * 336)
+ RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4; // PLLCLK = 84 MHz (336 MHz / 4)
+ RCC_OscInitStruct.PLL.PLLQ = 7; // USB clock = 48 MHz (336 MHz / 7) --> freq is ok but not precise enough
+ if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
+ return 0; // FAIL
+ }
+
+ /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 clocks dividers */
+ RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
+ RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; // 84 MHz
+ RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // 84 MHz
+ RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; // 42 MHz
+ RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; // 84 MHz
+ if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) {
+ return 0; // FAIL
+ }
+
+ /* Output clock on MCO1 pin(PA8) for debugging purpose */
+ //HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_HSI, RCC_MCODIV_1); // 16 MHz
+
+ return 1; // OK
+}
+
+WEAK void SystemClock_Config(void)
+{
+ /* 1- If fail try to start with HSE and external xtal */
+ if (SetSysClock_PLL_HSE(0) == 0) {
+ /* 2- Try to start with HSE and external clock */
+ if (SetSysClock_PLL_HSE(1) == 0) {
+ /* 3- If fail start with HSI clock */
+ if (SetSysClock_PLL_HSI() == 0) {
+ Error_Handler();
+ }
+ }
+ }
+ /* Output clock on MCO2 pin(PC9) for debugging purpose */
+ //HAL_RCC_MCOConfig(RCC_MCO2, RCC_MCO2SOURCE_SYSCLK, RCC_MCODIV_4);
+}
+
+#ifdef __cplusplus
+}
+#endif
\ No newline at end of file
diff --git a/buildroot/share/PlatformIO/variants/FYSETC_CHEETAH_V20/variant.h b/buildroot/share/PlatformIO/variants/FYSETC_CHEETAH_V20/variant.h
new file mode 100644
index 0000000000..d0fb0d9db0
--- /dev/null
+++ b/buildroot/share/PlatformIO/variants/FYSETC_CHEETAH_V20/variant.h
@@ -0,0 +1,151 @@
+/*
+ Copyright (c) 2011 Arduino. All right reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef _VARIANT_ARDUINO_STM32_
+#define _VARIANT_ARDUINO_STM32_
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+
+// | DIGITAL | ANALOG | USART | TWI | SPI | SPECIAL |
+// |---------|--------|-----------|----------|------------------------|-----------|
+#define PA0 A0 // | 0 | A0 | | | | |
+#define PA1 A1 // | 1 | A1 | | | | |
+#define PA2 A2 // | 2 | A2 | USART2_TX | | | |
+#define PA3 A3 // | 3 | A3 | USART2_RX | | | |
+#define PA4 A4 // | 4 | A4 | | | SPI1_SS, (SPI3_SS) | |
+#define PA5 A5 // | 5 | A5 | | | SPI1_SCK | |
+#define PA6 A6 // | 6 | A6 | | | SPI1_MISO | |
+#define PA7 A7 // | 7 | A7 | | | SPI1_MOSI | |
+#define PA8 8 // | 8 | | | TWI3_SCL | | |
+#define PA9 9 // | 9 | | USART1_TX | | | |
+#define PA10 10 // | 10 | | USART1_RX | | | |
+#define PA11 11 // | 11 | | USART6_TX | | | |
+#define PA12 12 // | 12 | | USART6_RX | | | |
+#define PA13 13 // | 13 | | | | | SWD_SWDIO |
+#define PA14 14 // | 14 | | | | | SWD_SWCLK |
+#define PA15 15 // | 15 | | | | SPI3_SS, (SPI1_SS) | |
+// |---------|--------|-----------|----------|------------------------|-----------|
+#define PB0 A8 // | 16 | A8 | | | | |
+#define PB1 A9 // | 17 | A9 | | | | |
+#define PB2 18 // | 18 | | | | | BOOT1 |
+#define PB3 19 // | 19 | | | TWI2_SDA | SPI3_SCK, (SPI1_SCK) | |
+#define PB4 20 // | 20 | | | TWI3_SDA | SPI3_MISO, (SPI1_MISO) | |
+#define PB5 21 // | 21 | | | | SPI3_MOSI, (SPI1_MOSI) | |
+#define PB6 22 // | 22 | | USART1_TX | TWI1_SCL | | |
+#define PB7 23 // | 23 | | USART1_RX | TWI1_SDA | | |
+#define PB8 24 // | 24 | | | TWI1_SCL | | |
+#define PB9 25 // | 25 | | | TWI1_SDA | SPI2_SS | |
+#define PB10 26 // | 26 | | | TWI2_SCL | SPI2_SCK | |
+#define PB12 27 // | 27 | | | | SPI2_SS | |
+#define PB13 28 // | 28 | | | | SPI2_SCK | |
+#define PB14 29 // | 29 | | | | SPI2_MISO | |
+#define PB15 30 // | 30 | | | | SPI2_MOSI | |
+// |---------|--------|-----------|----------|------------------------|-----------|
+#define PC0 A10 // | 31 | A10 | | | | |
+#define PC1 A11 // | 32 | A11 | | | | |
+#define PC2 A12 // | 33 | A12 | | | SPI2_MISO | |
+#define PC3 A13 // | 34 | A13 | | | SPI2_MOSI | |
+#define PC4 A14 // | 35 | A14 | | | | |
+#define PC5 A15 // | 36 | A15 | | | | |
+#define PC6 37 // | 37 | | USART6_TX | | | |
+#define PC7 38 // | 38 | | USART6_RX | | | |
+#define PC8 39 // | 39 | | | | | |
+#define PC9 40 // | 40 | | | TWI3_SDA | | |
+#define PC10 41 // | 41 | | | | SPI3_SCK | |
+#define PC11 42 // | 42 | | | | SPI3_MISO | |
+#define PC12 43 // | 43 | | | | SPI3_MOSI | |
+#define PC13 44 // | 44 | | | | | |
+#define PC14 45 // | 45 | | | | | OSC32_IN |
+#define PC15 46 // | 46 | | | | | OSC32_OUT |
+// |---------|--------|-----------|----------|------------------------|-----------|
+#define PD2 47 // | 47 | | | | | |
+// |---------|--------|-----------|----------|------------------------|-----------|
+#define PH0 48 // | 48 | | | | | OSC_IN |
+#define PH1 49 // | 49 | | | | | OSC_OUT |
+// |---------|--------|-----------|----------|------------------------|-----------|
+
+// This must be a literal
+#define NUM_DIGITAL_PINS 50
+#define NUM_ANALOG_INPUTS 16
+
+// SPI definitions
+#define PIN_SPI_SS PA4
+#define PIN_SPI_SS1 PA4
+#define PIN_SPI_MOSI PA7
+#define PIN_SPI_MISO PA6
+#define PIN_SPI_SCK PA5
+
+
+// Timer Definitions
+#define TIMER_TONE TIM2
+#define TIMER_SERVO TIM5
+#define TIMER_SERIAL TIM11
+
+// UART Definitions
+//#define ENABLE_HWSERIAL1 done automatically by the #define SERIAL_UART_INSTANCE below
+#define ENABLE_HWSERIAL2
+
+
+// Define here Serial instance number to map on Serial generic name (if not already used by SerialUSB)
+#define SERIAL_UART_INSTANCE 1 //1 for Serial = Serial1 (USART1)
+
+// Default pin used for 'Serial' instance
+// Mandatory for Firmata
+#define PIN_SERIAL_RX PA10
+#define PIN_SERIAL_TX PA9
+
+// Used when user instanciate a hardware Serial using its peripheral name.
+// Example: HardwareSerial mySerial(USART3);
+// will use PIN_SERIAL3_RX and PIN_SERIAL3_TX if defined.
+#define PIN_SERIAL1_RX PA10
+#define PIN_SERIAL1_TX PA9
+#define PIN_SERIAL2_RX PA3
+#define PIN_SERIAL2_TX PA2
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+/*----------------------------------------------------------------------------
+ * Arduino objects - C++ only
+ *----------------------------------------------------------------------------*/
+
+#ifdef __cplusplus
+ // These serial port names are intended to allow libraries and architecture-neutral
+ // sketches to automatically default to the correct port name for a particular type
+ // of use. For example, a GPS module would normally connect to SERIAL_PORT_HARDWARE_OPEN,
+ // the first hardware serial port whose RX/TX pins are not dedicated to another use.
+ //
+ // SERIAL_PORT_MONITOR Port which normally prints to the Arduino Serial Monitor
+ //
+ // SERIAL_PORT_USBVIRTUAL Port which is USB virtual serial
+ //
+ // SERIAL_PORT_LINUXBRIDGE Port which connects to a Linux system via Bridge library
+ //
+ // SERIAL_PORT_HARDWARE Hardware serial port, physical RX & TX pins.
+ //
+ // SERIAL_PORT_HARDWARE_OPEN Hardware serial ports which are open for use. Their RX & TX
+ // pins are NOT connected to anything by default.
+ #define SERIAL_PORT_MONITOR Serial
+ #define SERIAL_PORT_HARDWARE Serial1
+ #define SERIAL_PORT_HARDWARE_OPEN Serial2
+#endif
+
+#endif /* _VARIANT_ARDUINO_STM32_ */
\ No newline at end of file
diff --git a/buildroot/share/fonts/genallfont.sh b/buildroot/share/fonts/genallfont.sh
index 820da187df..0a66990212 100755
--- a/buildroot/share/fonts/genallfont.sh
+++ b/buildroot/share/fonts/genallfont.sh
@@ -62,7 +62,7 @@ OLDWD=`pwd`
#
# By default loop through all languages
#
-LANGS_DEFAULT="an bg ca cz da de el el_gr en es eu fi fr gl hr hu it jp_kana ko_KR nl pl pt pt_br ro ru sk tr uk vi zh_CN zh_TW test"
+LANGS_DEFAULT="an bg ca cz da de el el_gr en es eu fi fr gl hr hu it jp_kana ko_KR nl pl pt pt_br ro ru sk sv tr uk vi zh_CN zh_TW test"
#
# Generate data for language list MARLIN_LANGS or all if not provided
diff --git a/buildroot/share/git/mftest b/buildroot/share/git/mftest
index fda864672a..11d0ac3881 100755
--- a/buildroot/share/git/mftest
+++ b/buildroot/share/git/mftest
@@ -138,6 +138,15 @@ if ((AUTO_BUILD)); then
#
# List environments that apply to the current MOTHERBOARD.
#
+ case $(uname | tr '[:upper:]' '[:lower:]') in
+ darwin) SYS='mac' ;;
+ *linux) SYS='lin' ;;
+ win*) SYS='win' ;;
+ msys*) SYS='win' ;;
+ cygwin*) SYS='win' ;;
+ mingw*) SYS='win' ;;
+ *) SYS='uni' ;;
+ esac
echo ; echo -n "Auto " ; ((AUTO_BUILD == 2)) && echo "Upload..." || echo "Build..."
MB=$( grep -E "^\s*#define MOTHERBOARD" Marlin/Configuration.h | awk '{ print $3 }' | $SED 's/BOARD_//' )
[[ -z $MB ]] && { echo "Error - Can't read MOTHERBOARD setting." ; exit 1 ; }
@@ -145,7 +154,7 @@ if ((AUTO_BUILD)); then
BNUM=$( $SED -E 's/^.+BOARD_[^ ]+ +([0-9]+).+$/\1/' <<<"$BLINE" )
BDESC=$( $SED -E 's/^.+\/\/ *(.+)$/\1/' <<<"$BLINE" )
[[ -z $BNUM ]] && { echo "Error - Can't find $MB in boards list." ; exit 1 ; }
- ENVS=( $( grep -EA1 "MB\(.*\b$MB\b.*\)" Marlin/src/pins/pins.h | grep -E '#include.+//.+env:[^ ]+' | grep -oE 'env:[^ ]+' | $SED -E 's/env://' ) )
+ ENVS=( $( grep -EA1 "MB\(.*\b$MB\b.*\)" Marlin/src/pins/pins.h | grep -E "#include.+//.+(env|$SYS):[^ ]+" | grep -oE "(env|$SYS):[^ ]+" | $SED -E "s/(env|$SYS)://" ) )
[[ -z $ENVS ]] && { errout "Error - Can't find target(s) for $MB ($BNUM)." ; exit 1 ; }
ECOUNT=${#ENVS[*]}
diff --git a/buildroot/tests/FYSETC_F6-tests b/buildroot/tests/FYSETC_F6-tests
index cc7f334099..e1eb6684a5 100755
--- a/buildroot/tests/FYSETC_F6-tests
+++ b/buildroot/tests/FYSETC_F6-tests
@@ -39,6 +39,7 @@ exec_test $1 $2 "DELTA, RAMPS, L6470, UBL, Allen Key, EEPROM, OLED_PANEL_TINYBOY
restore_configs
opt_set MOTHERBOARD BOARD_FYSETC_F6_13
opt_set LCD_LANGUAGE vi
+opt_set LCD_LANGUAGE_2 fr
opt_set X_DRIVER_TYPE TMC2160
opt_set Y_DRIVER_TYPE TMC5160
opt_set Z_DRIVER_TYPE TMC2208_STANDALONE
diff --git a/buildroot/tests/FYSETC_S6-tests b/buildroot/tests/FYSETC_S6-tests
index 18951ebb79..c7f7a16bbd 100755
--- a/buildroot/tests/FYSETC_S6-tests
+++ b/buildroot/tests/FYSETC_S6-tests
@@ -9,6 +9,7 @@ set -e
# Build examples
restore_configs
use_example_configs FYSETC/S6
+opt_enable MEATPACK
opt_set Y_DRIVER_TYPE TMC2209
opt_set Z_DRIVER_TYPE TMC2130
exec_test $1 $2 "FYSETC S6 Example" "$3"
diff --git a/buildroot/tests/mega2560-tests b/buildroot/tests/mega2560-tests
index 12bbceab87..105258d402 100755
--- a/buildroot/tests/mega2560-tests
+++ b/buildroot/tests/mega2560-tests
@@ -72,7 +72,7 @@ opt_set TEMP_SENSOR_1 1
opt_set TEMP_SENSOR_2 1
opt_set TEMP_SENSOR_3 1
opt_set TEMP_SENSOR_4 1
-opt_enable ZONESTAR_LCD Z_PROBE_SERVO_NR Z_SERVO_ANGLES DEACTIVATE_SERVOS_AFTER_MOVE BOOT_MARLIN_LOGO_ANIMATED \
+opt_enable VIKI2 Z_PROBE_SERVO_NR Z_SERVO_ANGLES DEACTIVATE_SERVOS_AFTER_MOVE BOOT_MARLIN_LOGO_ANIMATED \
AUTO_BED_LEVELING_3POINT DEBUG_LEVELING_FEATURE EEPROM_SETTINGS EEPROM_CHITCHAT M114_DETAIL \
NO_VOLUMETRICS EXTENDED_CAPABILITIES_REPORT AUTO_REPORT_TEMPERATURES AUTOTEMP G38_PROBE_TARGET JOYSTICK \
DIRECT_STEPPING DETECT_BROKEN_ENDSTOP \
@@ -200,11 +200,11 @@ exec_test $1 $2 "Azteeg X3 | Mixing Extruder (x5) | Gradient Mix | Greek" "$3"
#
#restore_configs
#opt_enable REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER SDSUPPORT
-#for lang in an bg ca cz da de el el_gr en es eu fi fr gl hr hu it jp_kana nl pl pt pt_br ro ru sk tr uk vi zh_CN zh_TW test; do opt_set LCD_LANGUAGE $lang; echo "compile with language $lang ..."; exec_test $1 $2 "Stuff" "$3"; done
+#for lang in an bg ca cz da de el el_gr en es eu fi fr gl hr hu it jp_kana nl pl pt pt_br ro ru sk sv tr uk vi zh_CN zh_TW test; do opt_set LCD_LANGUAGE $lang; echo "compile with language $lang ..."; exec_test $1 $2 "Stuff" "$3"; done
#
#restore_configs
#opt_enable REPRAP_DISCOUNT_SMART_CONTROLLER SDSUPPORT
-#for lang in an bg ca cz da de el el_gr en es eu fi fr gl hr hu it jp_kana nl pl pt pt_br ro ru sk tr uk vi zh_CN zh_TW test; do opt_set LCD_LANGUAGE $lang; echo "compile with language $lang ..."; exec_test $1 $2 "Stuff" "$3"; done
+#for lang in an bg ca cz da de el el_gr en es eu fi fr gl hr hu it jp_kana nl pl pt pt_br ro ru sk sv tr uk vi zh_CN zh_TW test; do opt_set LCD_LANGUAGE $lang; echo "compile with language $lang ..."; exec_test $1 $2 "Stuff" "$3"; done
######## Example Configurations ##############
#
diff --git a/buildroot/tests/mks_robin_nano35-tests b/buildroot/tests/mks_robin_nano35-tests
index 3c5d1bb66f..6e2f9f1b0c 100755
--- a/buildroot/tests/mks_robin_nano35-tests
+++ b/buildroot/tests/mks_robin_nano35-tests
@@ -30,9 +30,9 @@ exec_test $1 $2 "MKS Robin v2 nano Emulated DOGM SPI" "$3"
#
use_example_configs Mks/Robin
opt_set MOTHERBOARD BOARD_MKS_ROBIN_NANO_V2
-opt_disable TFT_INTERFACE_FSMC TFT_COLOR_UI TOUCH_SCREEN TFT_RES_320x240
-opt_enable TFT_INTERFACE_SPI TFT_LVGL_UI TFT_RES_480x320
-exec_test $1 $2 "MKS Robin v2 nano LVGL SPI" "$3"
+opt_disable TFT_INTERFACE_FSMC TFT_COLOR_UI TOUCH_SCREEN TFT_RES_320x240 SERIAL_PORT_2
+opt_enable TFT_INTERFACE_SPI TFT_LVGL_UI TFT_RES_480x320 MKS_WIFI_MODULE
+exec_test $1 $2 "MKS Robin v2 nano LVGL SPI w/ WiFi" "$3"
#
# MKS Robin v2 nano New Color UI 480x320 SPI
diff --git a/buildroot/tests/run_tests b/buildroot/tests/run_tests
index a0eef6a05f..c4286f4695 100755
--- a/buildroot/tests/run_tests
+++ b/buildroot/tests/run_tests
@@ -20,7 +20,7 @@ exec_test () {
if [[ -z "$VERBOSE_PLATFORMIO" ]] ; then
silent="--silent"
else
- silent=""
+ silent="-v"
fi
if platformio run --project-dir $1 -e $2 $silent; then
printf "\033[0;32mPassed\033[0m\n"
diff --git a/buildroot/tests/sanguino1284p-tests b/buildroot/tests/sanguino1284p-tests
index a513f095f9..55cdf418da 100755
--- a/buildroot/tests/sanguino1284p-tests
+++ b/buildroot/tests/sanguino1284p-tests
@@ -7,7 +7,7 @@
set -e
#
-# Build with the default configurations
+# Start with default configurations...
#
restore_configs
opt_set MOTHERBOARD BOARD_SANGUINOLOLU_12
@@ -16,6 +16,13 @@ opt_enable MINIPANEL USE_CONTROLLER_FAN CONTROLLER_FAN_EDITABLE
opt_set CONTROLLER_FAN_PIN 27
exec_test $1 $2 "Default Configuration | MINIPANAL | CONTROLLER_FAN" "$3"
+#
+# Start with default configurations...
+#
+restore_configs
+opt_set MOTHERBOARD BOARD_MELZI
+opt_enable ZONESTAR_LCD
+exec_test $1 $2 "Default Configuration | ZONESTAR_LCD " "$3"
# clean up
restore_configs
diff --git a/docs/Serial.md b/docs/Serial.md
new file mode 100644
index 0000000000..317f5f8c93
--- /dev/null
+++ b/docs/Serial.md
@@ -0,0 +1,44 @@
+# Serial port architecture in Marlin
+
+Marlin is targeting a pletora of different CPU architecture and platforms. Each of these platforms has its own serial interface.
+While many provide a Arduino-like Serial class, it's not all of them, and the differences in the existing API create a very complex brain teaser for writing code that works more or less on each platform.
+
+Moreover, many platform have intrinsic needs about serial port (like forwarding the output on multiple serial port, providing a *serial-like* telnet server, mixing USB-based serial port with SD card emulation) that are difficult to handle cleanly in the other platform serial logic.
+
+
+Starting with version `2.0.9`, Marlin provides a common interface for its serial needs.
+
+## Common interface
+
+This interface is declared in `Marlin/src/core/serial_base.h`
+Any implementation will need to follow this interface for being used transparently in Marlin's codebase.
+
+The implementation was written to prioritize performance over abstraction, so the base interface is not using virtual inheritance to avoid the cost of virtual dispatching while calling methods.
+Instead, the Curiously Recurring Template Pattern (**CRTP**) is used so that, upon compilation, the interface abstraction does not incur a performance cost.
+
+Because some platform do not follow the same interface, the missing method in the actual low-level implementation are detected via SFINAE and a wrapper is generated when such method are missing. See `CALL_IF_EXISTS` macro in `Marlin/src/core/macros.h` for the documentation of this technic.
+
+## Composing the desired feature
+The different specificities for each architecture are provided by composing the serial type based on desired functionality.
+In the `Marlin/src/core/serial_hook.h` file, the different serial feature are declared and defined in each templated type:
+1. `BaseSerial` is a simple 1:1 wrapper to the underlying, Arduino compatible, `Serial`'s class. It derives from it. You'll use this if the platform does not do anything specific for the `Serial` object (for example, if an interrupt callback calls directly the serial **instance** in the platform's framework code, this is not the right class to use). This wrapper is completely inlined so that it does not generate any code upon compilation. `BaseSerial` constructor forwards any parameter to the platform's `Serial`'s constructor.
+2. `ForwardSerial` is a composing wrapper. It references an actual Arduino compatible `Serial` instance. You'll use this if the instance is declared in the platform's framework and is being referred directly in the framework. This is not as efficient as the `BaseSerial` implementation since static dereferencing is done for each method call (it'll still be faster than virtual dispatching)
+3. `ConditionalSerial` is working a bit like the `ForwardSerial` interface, but it checks a boolean condition before calling the referenced instance. You'll use it when the serial output can be switch off at runtime, for example in a *telnet* like serial output that should not emit any packet if no client is connected.
+4. `RuntimeSerial` is providing a runtime-modifiable hooking method for its `write` and `msgDone` method. You'll use it if you need to capture the serial output of Marlin, for example to display the G-Code parser's output on a GUI interface. The hooking interface is setup via the `setHook` method.
+5. `MultiSerial` is a runtime modifiable serial output multiplexer. It can output (*respectively input*) to 2 different interface based on a port *mask*. You'll use this if you need to output the same serial stream to multiple port. You can plug a `MultiSerial` to itself to duplicate to more than 2 ports.
+
+## Plumbing
+Since all the types above are using CRTP, it's possible to combine them to get the appropriate functionality.
+This is easily done via type definition of the feature.
+
+For example, to present a serial interface that's outputting to 2 serial port, the first one being hooked at runtime and the second one connected to a runtime switchable telnet client, you'll declare the type to use as:
+```
+typedef MultiSerial< RuntimeSerial, ConditionalSerial > Serial0Type;
+```
+
+## Emergency parser
+By default, the serial base interface provide an emergency parser that's only enable for serial classes that support it.
+Because of this condition, all underlying type takes a first `bool emergencyParserEnabled` argument to their constructor. You must take into account this parameter when defining the actual type used.
+
+
+*This document was written by [X-Ryl669](https://blog.cyril.by) and is under [CC-SA license](https://creativecommons.org/licenses/by-sa)*
\ No newline at end of file
diff --git a/platformio.ini b/platformio.ini
index b6ed572bfb..556b5769c5 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -39,6 +39,7 @@ default_src_filter = + - - +
-
-
-