aboutsummaryrefslogtreecommitdiff
path: root/Marlin/src/core
diff options
context:
space:
mode:
authorGeorgiy Bondarenko <69736697+nehilo@users.noreply.github.com>2021-03-04 20:54:23 +0300
committerGeorgiy Bondarenko <69736697+nehilo@users.noreply.github.com>2021-03-04 20:54:23 +0300
commite8701195e66f2d27ffe17fb514eae8173795aaf7 (patch)
tree9f519c4abf6556b9ae7190a6210d87ead1dfadde /Marlin/src/core
downloadkp3s-lgvl-e8701195e66f2d27ffe17fb514eae8173795aaf7.tar.xz
kp3s-lgvl-e8701195e66f2d27ffe17fb514eae8173795aaf7.zip
Initial commit
Diffstat (limited to 'Marlin/src/core')
-rw-r--r--Marlin/src/core/boards.h419
-rw-r--r--Marlin/src/core/debug_out.h121
-rw-r--r--Marlin/src/core/debug_section.h49
-rw-r--r--Marlin/src/core/drivers.h197
-rw-r--r--Marlin/src/core/language.h408
-rw-r--r--Marlin/src/core/macros.h545
-rw-r--r--Marlin/src/core/millis_t.h33
-rw-r--r--Marlin/src/core/multi_language.h86
-rw-r--r--Marlin/src/core/serial.cpp93
-rw-r--r--Marlin/src/core/serial.h335
-rw-r--r--Marlin/src/core/serial_base.h159
-rw-r--r--Marlin/src/core/serial_hook.h235
-rw-r--r--Marlin/src/core/types.h503
-rw-r--r--Marlin/src/core/utility.cpp177
-rw-r--r--Marlin/src/core/utility.h79
15 files changed, 3439 insertions, 0 deletions
diff --git a/Marlin/src/core/boards.h b/Marlin/src/core/boards.h
new file mode 100644
index 0000000..afb6887
--- /dev/null
+++ b/Marlin/src/core/boards.h
@@ -0,0 +1,419 @@
+/**
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "macros.h"
+
+#define BOARD_UNKNOWN -1
+
+//
+// RAMPS 1.3 / 1.4 - ATmega1280, ATmega2560
+//
+
+#define BOARD_RAMPS_OLD 1000 // MEGA/RAMPS up to 1.2
+
+#define BOARD_RAMPS_13_EFB 1010 // RAMPS 1.3 (Power outputs: Hotend, Fan, Bed)
+#define BOARD_RAMPS_13_EEB 1011 // RAMPS 1.3 (Power outputs: Hotend0, Hotend1, Bed)
+#define BOARD_RAMPS_13_EFF 1012 // RAMPS 1.3 (Power outputs: Hotend, Fan0, Fan1)
+#define BOARD_RAMPS_13_EEF 1013 // RAMPS 1.3 (Power outputs: Hotend0, Hotend1, Fan)
+#define BOARD_RAMPS_13_SF 1014 // RAMPS 1.3 (Power outputs: Spindle, Controller Fan)
+
+#define BOARD_RAMPS_14_EFB 1020 // RAMPS 1.4 (Power outputs: Hotend, Fan, Bed)
+#define BOARD_RAMPS_14_EEB 1021 // RAMPS 1.4 (Power outputs: Hotend0, Hotend1, Bed)
+#define BOARD_RAMPS_14_EFF 1022 // RAMPS 1.4 (Power outputs: Hotend, Fan0, Fan1)
+#define BOARD_RAMPS_14_EEF 1023 // RAMPS 1.4 (Power outputs: Hotend0, Hotend1, Fan)
+#define BOARD_RAMPS_14_SF 1024 // RAMPS 1.4 (Power outputs: Spindle, Controller Fan)
+
+#define BOARD_RAMPS_PLUS_EFB 1030 // RAMPS Plus 3DYMY (Power outputs: Hotend, Fan, Bed)
+#define BOARD_RAMPS_PLUS_EEB 1031 // RAMPS Plus 3DYMY (Power outputs: Hotend0, Hotend1, Bed)
+#define BOARD_RAMPS_PLUS_EFF 1032 // RAMPS Plus 3DYMY (Power outputs: Hotend, Fan0, Fan1)
+#define BOARD_RAMPS_PLUS_EEF 1033 // RAMPS Plus 3DYMY (Power outputs: Hotend0, Hotend1, Fan)
+#define BOARD_RAMPS_PLUS_SF 1034 // RAMPS Plus 3DYMY (Power outputs: Spindle, Controller Fan)
+
+//
+// RAMPS Derivatives - ATmega1280, ATmega2560
+//
+
+#define BOARD_3DRAG 1100 // 3Drag Controller
+#define BOARD_K8200 1101 // Velleman K8200 Controller (derived from 3Drag Controller)
+#define BOARD_K8400 1102 // Velleman K8400 Controller (derived from 3Drag Controller)
+#define BOARD_K8600 1103 // Velleman K8600 Controller (Vertex Nano)
+#define BOARD_K8800 1104 // Velleman K8800 Controller (Vertex Delta)
+#define BOARD_BAM_DICE 1105 // 2PrintBeta BAM&DICE with STK drivers
+#define BOARD_BAM_DICE_DUE 1106 // 2PrintBeta BAM&DICE Due with STK drivers
+#define BOARD_MKS_BASE 1107 // MKS BASE v1.0
+#define BOARD_MKS_BASE_14 1108 // MKS BASE v1.4 with Allegro A4982 stepper drivers
+#define BOARD_MKS_BASE_15 1109 // MKS BASE v1.5 with Allegro A4982 stepper drivers
+#define BOARD_MKS_BASE_16 1110 // MKS BASE v1.6 with Allegro A4982 stepper drivers
+#define BOARD_MKS_BASE_HEROIC 1111 // MKS BASE 1.0 with Heroic HR4982 stepper drivers
+#define BOARD_MKS_GEN_13 1112 // MKS GEN v1.3 or 1.4
+#define BOARD_MKS_GEN_L 1113 // MKS GEN L
+#define BOARD_KFB_2 1114 // BigTreeTech or BIQU KFB2.0
+#define BOARD_ZRIB_V20 1115 // zrib V2.0 control board (Chinese knock off RAMPS replica)
+#define BOARD_ZRIB_V52 1116 // zrib V5.2 control board (Chinese knock off RAMPS replica)
+#define BOARD_FELIX2 1117 // Felix 2.0+ Electronics Board (RAMPS like)
+#define BOARD_RIGIDBOARD 1118 // Invent-A-Part RigidBoard
+#define BOARD_RIGIDBOARD_V2 1119 // Invent-A-Part RigidBoard V2
+#define BOARD_SAINSMART_2IN1 1120 // Sainsmart 2-in-1 board
+#define BOARD_ULTIMAKER 1121 // Ultimaker
+#define BOARD_ULTIMAKER_OLD 1122 // Ultimaker (Older electronics. Pre 1.5.4. This is rare)
+#define BOARD_AZTEEG_X3 1123 // Azteeg X3
+#define BOARD_AZTEEG_X3_PRO 1124 // Azteeg X3 Pro
+#define BOARD_ULTIMAIN_2 1125 // Ultimainboard 2.x (Uses TEMP_SENSOR 20)
+#define BOARD_RUMBA 1126 // Rumba
+#define BOARD_RUMBA_RAISE3D 1127 // Raise3D N series Rumba derivative
+#define BOARD_RL200 1128 // Rapide Lite 200 (v1, low-cost RUMBA clone with drv)
+#define BOARD_FORMBOT_TREX2PLUS 1129 // Formbot T-Rex 2 Plus
+#define BOARD_FORMBOT_TREX3 1130 // Formbot T-Rex 3
+#define BOARD_FORMBOT_RAPTOR 1131 // Formbot Raptor
+#define BOARD_FORMBOT_RAPTOR2 1132 // Formbot Raptor 2
+#define BOARD_BQ_ZUM_MEGA_3D 1133 // bq ZUM Mega 3D
+#define BOARD_MAKEBOARD_MINI 1134 // MakeBoard Mini v2.1.2 is a control board sold by MicroMake
+#define BOARD_TRIGORILLA_13 1135 // TriGorilla Anycubic version 1.3-based on RAMPS EFB
+#define BOARD_TRIGORILLA_14 1136 // ... Ver 1.4
+#define BOARD_TRIGORILLA_14_11 1137 // ... Rev 1.1 (new servo pin order)
+#define BOARD_RAMPS_ENDER_4 1138 // Creality: Ender-4, CR-8
+#define BOARD_RAMPS_CREALITY 1139 // Creality: CR10S, CR20, CR-X
+#define BOARD_DAGOMA_F5 1140 // Dagoma F5
+#define BOARD_FYSETC_F6_13 1141 // FYSETC F6 1.3
+#define BOARD_FYSETC_F6_14 1142 // FYSETC F6 1.4
+#define BOARD_DUPLICATOR_I3_PLUS 1143 // Wanhao Duplicator i3 Plus
+#define BOARD_VORON 1144 // VORON Design
+#define BOARD_TRONXY_V3_1_0 1145 // Tronxy TRONXY-V3-1.0
+#define BOARD_Z_BOLT_X_SERIES 1146 // Z-Bolt X Series
+#define BOARD_TT_OSCAR 1147 // TT OSCAR
+#define BOARD_OVERLORD 1148 // Overlord/Overlord Pro
+#define BOARD_HJC2560C_REV1 1149 // ADIMLab Gantry v1
+#define BOARD_HJC2560C_REV2 1150 // ADIMLab Gantry v2
+#define BOARD_TANGO 1151 // BIQU Tango V1
+#define BOARD_MKS_GEN_L_V2 1152 // MKS GEN L V2
+#define BOARD_MKS_GEN_L_V21 1153 // MKS GEN L V2.1
+#define BOARD_COPYMASTER_3D 1154 // Copymaster 3D
+#define BOARD_ORTUR_4 1155 // Ortur 4
+#define BOARD_TENLOG_D3_HERO 1156 // Tenlog D3 Hero IDEX printer
+#define BOARD_RAMPS_S_12_EEFB 1157 // Ramps S 1.2 by Sakul.cz (Power outputs: Hotend0, Hotend1, Fan, Bed)
+#define BOARD_RAMPS_S_12_EEEB 1158 // Ramps S 1.2 by Sakul.cz (Power outputs: Hotend0, Hotend1, Hotend2, Bed)
+#define BOARD_RAMPS_S_12_EFFB 1159 // Ramps S 1.2 by Sakul.cz (Power outputs: Hotend, Fan0, Fan1, Bed)
+#define BOARD_LONGER3D_LK1_PRO 1160 // Longer LK1 PRO / Alfawise U20 Pro (PRO version)
+#define BOARD_LONGER3D_LKx_PRO 1161 // Longer LKx PRO / Alfawise Uxx Pro (PRO version)
+
+//
+// RAMBo and derivatives
+//
+
+#define BOARD_RAMBO 1200 // Rambo
+#define BOARD_MINIRAMBO 1201 // Mini-Rambo
+#define BOARD_MINIRAMBO_10A 1202 // Mini-Rambo 1.0a
+#define BOARD_EINSY_RAMBO 1203 // Einsy Rambo
+#define BOARD_EINSY_RETRO 1204 // Einsy Retro
+#define BOARD_SCOOVO_X9H 1205 // abee Scoovo X9H
+
+//
+// Other ATmega1280, ATmega2560
+//
+
+#define BOARD_CNCONTROLS_11 1300 // Cartesio CN Controls V11
+#define BOARD_CNCONTROLS_12 1301 // Cartesio CN Controls V12
+#define BOARD_CNCONTROLS_15 1302 // Cartesio CN Controls V15
+#define BOARD_CHEAPTRONIC 1303 // Cheaptronic v1.0
+#define BOARD_CHEAPTRONIC_V2 1304 // Cheaptronic v2.0
+#define BOARD_MIGHTYBOARD_REVE 1305 // Makerbot Mightyboard Revision E
+#define BOARD_MEGATRONICS 1306 // Megatronics
+#define BOARD_MEGATRONICS_2 1307 // Megatronics v2.0
+#define BOARD_MEGATRONICS_3 1308 // Megatronics v3.0
+#define BOARD_MEGATRONICS_31 1309 // Megatronics v3.1
+#define BOARD_MEGATRONICS_32 1310 // Megatronics v3.2
+#define BOARD_ELEFU_3 1311 // Elefu Ra Board (v3)
+#define BOARD_LEAPFROG 1312 // Leapfrog
+#define BOARD_MEGACONTROLLER 1313 // Mega controller
+#define BOARD_GT2560_REV_A 1314 // Geeetech GT2560 Rev. A
+#define BOARD_GT2560_REV_A_PLUS 1315 // Geeetech GT2560 Rev. A+ (with auto level probe)
+#define BOARD_GT2560_V3 1316 // Geeetech GT2560 Rev B for A10(M/D)
+#define BOARD_GT2560_V3_MC2 1317 // Geeetech GT2560 Rev B for Mecreator2
+#define BOARD_GT2560_V3_A20 1318 // Geeetech GT2560 Rev B for A20(M/D)
+#define BOARD_EINSTART_S 1319 // Einstart retrofit
+#define BOARD_WANHAO_ONEPLUS 1320 // Wanhao 0ne+ i3 Mini
+#define BOARD_LEAPFROG_XEED2015 1321 // Leapfrog Xeed 2015
+#define BOARD_PICA_REVB 1322 // PICA Shield (original version)
+#define BOARD_PICA 1323 // PICA Shield (rev C or later)
+#define BOARD_INTAMSYS40 1324 // Intamsys 4.0 (Funmat HT)
+
+//
+// ATmega1281, ATmega2561
+//
+
+#define BOARD_MINITRONICS 1400 // Minitronics v1.0/1.1
+#define BOARD_SILVER_GATE 1401 // Silvergate v1.0
+
+//
+// Sanguinololu and Derivatives - ATmega644P, ATmega1284P
+//
+
+#define BOARD_SANGUINOLOLU_11 1500 // Sanguinololu < 1.2
+#define BOARD_SANGUINOLOLU_12 1501 // Sanguinololu 1.2 and above
+#define BOARD_MELZI 1502 // Melzi
+#define BOARD_MELZI_V2 1503 // Melzi V2
+#define BOARD_MELZI_MAKR3D 1504 // Melzi with ATmega1284 (MaKr3d version)
+#define BOARD_MELZI_CREALITY 1505 // Melzi Creality3D board (for CR-10 etc)
+#define BOARD_MELZI_MALYAN 1506 // Melzi Malyan M150 board
+#define BOARD_MELZI_TRONXY 1507 // Tronxy X5S
+#define BOARD_STB_11 1508 // STB V1.1
+#define BOARD_AZTEEG_X1 1509 // Azteeg X1
+#define BOARD_ANET_10 1510 // Anet 1.0 (Melzi clone)
+#define BOARD_ZMIB_V2 1511 // ZoneStar ZMIB V2
+
+//
+// Other ATmega644P, ATmega644, ATmega1284P
+//
+
+#define BOARD_GEN3_MONOLITHIC 1600 // Gen3 Monolithic Electronics
+#define BOARD_GEN3_PLUS 1601 // Gen3+
+#define BOARD_GEN6 1602 // Gen6
+#define BOARD_GEN6_DELUXE 1603 // Gen6 deluxe
+#define BOARD_GEN7_CUSTOM 1604 // Gen7 custom (Alfons3 Version) https://github.com/Alfons3/Generation_7_Electronics
+#define BOARD_GEN7_12 1605 // Gen7 v1.1, v1.2
+#define BOARD_GEN7_13 1606 // Gen7 v1.3
+#define BOARD_GEN7_14 1607 // Gen7 v1.4
+#define BOARD_OMCA_A 1608 // Alpha OMCA board
+#define BOARD_OMCA 1609 // Final OMCA board
+#define BOARD_SETHI 1610 // Sethi 3D_1
+
+//
+// Teensyduino - AT90USB1286, AT90USB1286P
+//
+
+#define BOARD_TEENSYLU 1700 // Teensylu
+#define BOARD_PRINTRBOARD 1701 // Printrboard (AT90USB1286)
+#define BOARD_PRINTRBOARD_REVF 1702 // Printrboard Revision F (AT90USB1286)
+#define BOARD_BRAINWAVE 1703 // Brainwave (AT90USB646)
+#define BOARD_BRAINWAVE_PRO 1704 // Brainwave Pro (AT90USB1286)
+#define BOARD_SAV_MKI 1705 // SAV Mk-I (AT90USB1286)
+#define BOARD_TEENSY2 1706 // Teensy++2.0 (AT90USB1286)
+#define BOARD_5DPRINT 1707 // 5DPrint D8 Driver Board
+
+//
+// LPC1768 ARM Cortex M3
+//
+
+#define BOARD_RAMPS_14_RE_ARM_EFB 2000 // Re-ARM with RAMPS 1.4 (Power outputs: Hotend, Fan, Bed)
+#define BOARD_RAMPS_14_RE_ARM_EEB 2001 // Re-ARM with RAMPS 1.4 (Power outputs: Hotend0, Hotend1, Bed)
+#define BOARD_RAMPS_14_RE_ARM_EFF 2002 // Re-ARM with RAMPS 1.4 (Power outputs: Hotend, Fan0, Fan1)
+#define BOARD_RAMPS_14_RE_ARM_EEF 2003 // Re-ARM with RAMPS 1.4 (Power outputs: Hotend0, Hotend1, Fan)
+#define BOARD_RAMPS_14_RE_ARM_SF 2004 // Re-ARM with RAMPS 1.4 (Power outputs: Spindle, Controller Fan)
+#define BOARD_MKS_SBASE 2005 // MKS-Sbase (Power outputs: Hotend0, Hotend1, Bed, Fan)
+#define BOARD_AZSMZ_MINI 2006 // AZSMZ Mini
+#define BOARD_BIQU_BQ111_A4 2007 // BIQU BQ111-A4 (Power outputs: Hotend, Fan, Bed)
+#define BOARD_SELENA_COMPACT 2008 // Selena Compact (Power outputs: Hotend0, Hotend1, Bed0, Bed1, Fan0, Fan1)
+#define BOARD_BIQU_B300_V1_0 2009 // BIQU B300_V1.0 (Power outputs: Hotend0, Fan, Bed, SPI Driver)
+#define BOARD_MKS_SGEN_L 2010 // MKS-SGen-L (Power outputs: Hotend0, Hotend1, Bed, Fan)
+#define BOARD_GMARSH_X6_REV1 2011 // GMARSH X6 board, revision 1 prototype
+#define BOARD_BTT_SKR_V1_1 2012 // BigTreeTech SKR v1.1 (Power outputs: Hotend0, Hotend1, Fan, Bed)
+#define BOARD_BTT_SKR_V1_3 2013 // BigTreeTech SKR v1.3 (Power outputs: Hotend0, Hotend1, Fan, Bed)
+#define BOARD_BTT_SKR_V1_4 2014 // BigTreeTech SKR v1.4 (Power outputs: Hotend0, Hotend1, Fan, Bed)
+
+//
+// LPC1769 ARM Cortex M3
+//
+
+#define BOARD_MKS_SGEN 2500 // MKS-SGen (Power outputs: Hotend0, Hotend1, Bed, Fan)
+#define BOARD_AZTEEG_X5_GT 2501 // Azteeg X5 GT (Power outputs: Hotend0, Hotend1, Bed, Fan)
+#define BOARD_AZTEEG_X5_MINI 2502 // Azteeg X5 Mini (Power outputs: Hotend0, Bed, Fan)
+#define BOARD_AZTEEG_X5_MINI_WIFI 2503 // Azteeg X5 Mini Wifi (Power outputs: Hotend0, Bed, Fan)
+#define BOARD_COHESION3D_REMIX 2504 // Cohesion3D ReMix
+#define BOARD_COHESION3D_MINI 2505 // Cohesion3D Mini
+#define BOARD_SMOOTHIEBOARD 2506 // Smoothieboard
+#define BOARD_TH3D_EZBOARD 2507 // TH3D EZBoard v1.0
+#define BOARD_BTT_SKR_V1_4_TURBO 2508 // BigTreeTech SKR v1.4 TURBO (Power outputs: Hotend0, Hotend1, Fan, Bed)
+#define BOARD_MKS_SGEN_L_V2 2509 // MKS SGEN_L V2 (Power outputs: Hotend0, Hotend1, Bed, Fan)
+#define BOARD_BTT_SKR_E3_TURBO 2510 // BigTreeTech SKR E3 Turbo (Power outputs: Hotend0, Hotend1, Bed, Fan0, Fan1)
+#define BOARD_FLY_CDY 2511 // FLY_CDY (Power outputs: Hotend0, Hotend1, Hotend2, Bed, Fan0, Fan1, Fan2)
+
+//
+// SAM3X8E ARM Cortex M3
+//
+
+#define BOARD_DUE3DOM 3000 // DUE3DOM for Arduino DUE
+#define BOARD_DUE3DOM_MINI 3001 // DUE3DOM MINI for Arduino DUE
+#define BOARD_RADDS 3002 // RADDS
+#define BOARD_RAMPS_FD_V1 3003 // RAMPS-FD v1
+#define BOARD_RAMPS_FD_V2 3004 // RAMPS-FD v2
+#define BOARD_RAMPS_SMART_EFB 3005 // RAMPS-SMART (Power outputs: Hotend, Fan, Bed)
+#define BOARD_RAMPS_SMART_EEB 3006 // RAMPS-SMART (Power outputs: Hotend0, Hotend1, Bed)
+#define BOARD_RAMPS_SMART_EFF 3007 // RAMPS-SMART (Power outputs: Hotend, Fan0, Fan1)
+#define BOARD_RAMPS_SMART_EEF 3008 // RAMPS-SMART (Power outputs: Hotend0, Hotend1, Fan)
+#define BOARD_RAMPS_SMART_SF 3009 // RAMPS-SMART (Power outputs: Spindle, Controller Fan)
+#define BOARD_RAMPS_DUO_EFB 3010 // RAMPS Duo (Power outputs: Hotend, Fan, Bed)
+#define BOARD_RAMPS_DUO_EEB 3011 // RAMPS Duo (Power outputs: Hotend0, Hotend1, Bed)
+#define BOARD_RAMPS_DUO_EFF 3012 // RAMPS Duo (Power outputs: Hotend, Fan0, Fan1)
+#define BOARD_RAMPS_DUO_EEF 3013 // RAMPS Duo (Power outputs: Hotend0, Hotend1, Fan)
+#define BOARD_RAMPS_DUO_SF 3014 // RAMPS Duo (Power outputs: Spindle, Controller Fan)
+#define BOARD_RAMPS4DUE_EFB 3015 // RAMPS4DUE (Power outputs: Hotend, Fan, Bed)
+#define BOARD_RAMPS4DUE_EEB 3016 // RAMPS4DUE (Power outputs: Hotend0, Hotend1, Bed)
+#define BOARD_RAMPS4DUE_EFF 3017 // RAMPS4DUE (Power outputs: Hotend, Fan0, Fan1)
+#define BOARD_RAMPS4DUE_EEF 3018 // RAMPS4DUE (Power outputs: Hotend0, Hotend1, Fan)
+#define BOARD_RAMPS4DUE_SF 3019 // RAMPS4DUE (Power outputs: Spindle, Controller Fan)
+#define BOARD_RURAMPS4D_11 3020 // RuRAMPS4Duo v1.1 (Power outputs: Hotend0, Hotend1, Hotend2, Fan0, Fan1, Bed)
+#define BOARD_RURAMPS4D_13 3021 // RuRAMPS4Duo v1.3 (Power outputs: Hotend0, Hotend1, Hotend2, Fan0, Fan1, Bed)
+#define BOARD_ULTRATRONICS_PRO 3022 // ReprapWorld Ultratronics Pro V1.0
+#define BOARD_ARCHIM1 3023 // UltiMachine Archim1 (with DRV8825 drivers)
+#define BOARD_ARCHIM2 3024 // UltiMachine Archim2 (with TMC2130 drivers)
+#define BOARD_ALLIGATOR 3025 // Alligator Board R2
+#define BOARD_CNCONTROLS_15D 3026 // Cartesio CN Controls V15 on DUE
+
+//
+// SAM3X8C ARM Cortex M3
+//
+
+#define BOARD_PRINTRBOARD_G2 3100 // PRINTRBOARD G2
+#define BOARD_ADSK 3101 // Arduino DUE Shield Kit (ADSK)
+
+//
+// STM32 ARM Cortex-M3
+//
+
+#define BOARD_MALYAN_M200_V2 4000 // STM32F070CB controller
+#define BOARD_MALYAN_M300 4001 // STM32F070-based delta
+#define BOARD_STM32F103RE 4002 // STM32F103RE Libmaple-based STM32F1 controller
+#define BOARD_MALYAN_M200 4003 // STM32C8T6 Libmaple-based STM32F1 controller
+#define BOARD_STM3R_MINI 4004 // STM32F103RE Libmaple-based STM32F1 controller
+#define BOARD_GTM32_PRO_VB 4005 // STM32F103VET6 controller
+#define BOARD_GTM32_MINI 4006 // STM32F103VET6 controller
+#define BOARD_GTM32_MINI_A30 4007 // STM32F103VET6 controller
+#define BOARD_GTM32_REV_B 4008 // STM32F103VET6 controller
+#define BOARD_MORPHEUS 4009 // STM32F103C8 / STM32F103CB Libmaple-based STM32F1 controller
+#define BOARD_CHITU3D 4010 // Chitu3D (STM32F103RET6)
+#define BOARD_MKS_ROBIN 4011 // MKS Robin (STM32F103ZET6)
+#define BOARD_MKS_ROBIN_MINI 4012 // MKS Robin Mini (STM32F103VET6)
+#define BOARD_MKS_ROBIN_NANO 4013 // MKS Robin Nano (STM32F103VET6)
+#define BOARD_MKS_ROBIN_NANO_V2 4014 // MKS Robin Nano V2 (STM32F103VET6)
+#define BOARD_MKS_ROBIN_LITE 4015 // MKS Robin Lite/Lite2 (STM32F103RCT6)
+#define BOARD_MKS_ROBIN_LITE3 4016 // MKS Robin Lite3 (STM32F103RCT6)
+#define BOARD_MKS_ROBIN_PRO 4017 // MKS Robin Pro (STM32F103ZET6)
+#define BOARD_MKS_ROBIN_E3 4018 // MKS Robin E3 (STM32F103RCT6)
+#define BOARD_MKS_ROBIN_E3_V1_1 4019 // MKS Robin E3 V1.1 (STM32F103RCT6)
+#define BOARD_MKS_ROBIN_E3D 4020 // MKS Robin E3D (STM32F103RCT6)
+#define BOARD_MKS_ROBIN_E3D_V1_1 4021 // MKS Robin E3D V1.1 (STM32F103RCT6)
+#define BOARD_MKS_ROBIN_E3P 4022 // MKS Robin E3p (STM32F103VET6)
+#define BOARD_BTT_SKR_MINI_V1_1 4023 // BigTreeTech SKR Mini v1.1 (STM32F103RC)
+#define BOARD_BTT_SKR_MINI_E3_V1_0 4024 // BigTreeTech SKR Mini E3 (STM32F103RC)
+#define BOARD_BTT_SKR_MINI_E3_V1_2 4025 // BigTreeTech SKR Mini E3 V1.2 (STM32F103RC)
+#define BOARD_BTT_SKR_MINI_E3_V2_0 4026 // BigTreeTech SKR Mini E3 V2.0 (STM32F103RC)
+#define BOARD_BTT_SKR_MINI_MZ_V1_0 4027 // BigTreeTech SKR Mini MZ V1.0 (STM32F103RC)
+#define BOARD_BTT_SKR_E3_DIP 4028 // BigTreeTech SKR E3 DIP V1.0 (STM32F103RC / STM32F103RE)
+#define BOARD_BTT_SKR_CR6 4029 // BigTreeTech SKR CR6 v1.0 (STM32F103RE)
+#define BOARD_JGAURORA_A5S_A1 4030 // JGAurora A5S A1 (STM32F103ZET6)
+#define BOARD_FYSETC_AIO_II 4031 // FYSETC AIO_II
+#define BOARD_FYSETC_CHEETAH 4032 // FYSETC Cheetah
+#define BOARD_FYSETC_CHEETAH_V12 4033 // FYSETC Cheetah V1.2
+#define BOARD_LONGER3D_LK 4034 // Alfawise U20/U20+/U30 (Longer3D LK1/2) / STM32F103VET6
+#define BOARD_CCROBOT_MEEB_3DP 4035 // ccrobot-online.com MEEB_3DP (STM32F103RC)
+#define BOARD_CHITU3D_V5 4036 // Chitu3D TronXY X5SA V5 Board
+#define BOARD_CHITU3D_V6 4037 // Chitu3D TronXY X5SA V5 Board
+#define BOARD_CREALITY_V4 4038 // Creality v4.x (STM32F103RE)
+#define BOARD_CREALITY_V427 4039 // Creality v4.2.7 (STM32F103RE)
+#define BOARD_CREALITY_V4210 4040 // Creality v4.2.10 (STM32F103RE) as found in the CR-30
+#define BOARD_CREALITY_V431 4041 // Creality v4.3.1 (STM32F103RE)
+#define BOARD_CREALITY_V452 4042 // Creality v4.5.2 (STM32F103RE)
+#define BOARD_CREALITY_V453 4043 // Creality v4.5.3 (STM32F103RE)
+#define BOARD_TRIGORILLA_PRO 4044 // Trigorilla Pro (STM32F103ZET6)
+#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
+//
+
+#define BOARD_TEENSY31_32 4100 // Teensy3.1 and Teensy3.2
+#define BOARD_TEENSY35_36 4101 // Teensy3.5 and Teensy3.6
+
+//
+// STM32 ARM Cortex-M4F
+//
+
+#define BOARD_ARMED 4200 // Arm'ed STM32F4-based controller
+#define BOARD_RUMBA32_V1_0 4201 // RUMBA32 STM32F446VET6 based controller from Aus3D
+#define BOARD_RUMBA32_V1_1 4202 // RUMBA32 STM32F446VET6 based controller from Aus3D
+#define BOARD_RUMBA32_MKS 4203 // RUMBA32 STM32F446VET6 based controller from Makerbase
+#define BOARD_BLACK_STM32F407VE 4204 // BLACK_STM32F407VE
+#define BOARD_BLACK_STM32F407ZE 4205 // BLACK_STM32F407ZE
+#define BOARD_STEVAL_3DP001V1 4206 // STEVAL-3DP001V1 3D PRINTER BOARD
+#define BOARD_BTT_SKR_PRO_V1_1 4207 // BigTreeTech SKR Pro v1.1 (STM32F407ZG)
+#define BOARD_BTT_SKR_PRO_V1_2 4208 // BigTreeTech SKR Pro v1.2 (STM32F407ZG)
+#define BOARD_BTT_BTT002_V1_0 4209 // BigTreeTech BTT002 v1.0 (STM32F407VG)
+#define BOARD_BTT_GTR_V1_0 4210 // BigTreeTech GTR v1.0 (STM32F407IGT)
+#define BOARD_LERDGE_K 4211 // Lerdge K (STM32F407ZG)
+#define BOARD_LERDGE_S 4212 // Lerdge S (STM32F407VE)
+#define BOARD_LERDGE_X 4213 // Lerdge X (STM32F407VE)
+#define BOARD_VAKE403D 4214 // VAkE 403D (STM32F446VET6)
+#define BOARD_FYSETC_S6 4215 // FYSETC S6 board
+#define BOARD_FYSETC_S6_V2_0 4216 // FYSETC S6 v2.0 board
+#define BOARD_FLYF407ZG 4217 // FLYF407ZG board (STM32F407ZG)
+#define BOARD_MKS_ROBIN2 4218 // MKS_ROBIN2 (STM32F407ZE)
+#define BOARD_MKS_ROBIN_PRO_V2 4219 // MKS Robin Pro V2 (STM32F407VE)
+#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
+//
+
+#define BOARD_REMRAM_V1 5000 // RemRam v1
+#define BOARD_TEENSY41 5001 // Teensy 4.1
+#define BOARD_T41U5XBB 5002 // T41U5XBB Teensy 4.1 breakout board
+#define BOARD_NUCLEO_F767ZI 5003 // ST NUCLEO-F767ZI Dev Board
+
+//
+// Espressif ESP32 WiFi
+//
+
+#define BOARD_ESPRESSIF_ESP32 6000 // Generic ESP32
+#define BOARD_MRR_ESPA 6001 // MRR ESPA board based on ESP32 (native pins only)
+#define BOARD_MRR_ESPE 6002 // MRR ESPE board based on ESP32 (with I2S stepper stream)
+#define BOARD_E4D_BOX 6003 // E4d@BOX
+#define BOARD_FYSETC_E4 6004 // FYSETC E4
+
+//
+// SAMD51 ARM Cortex M4
+//
+
+#define BOARD_AGCM4_RAMPS_144 6100 // RAMPS 1.4.4
+
+//
+// Custom board
+//
+
+#define BOARD_CUSTOM 9998 // Custom pins definition for development and/or rare boards
+
+//
+// Simulations
+//
+
+#define BOARD_LINUX_RAMPS 9999
+
+#define _MB_1(B) (defined(BOARD_##B) && MOTHERBOARD==BOARD_##B)
+#define MB(V...) DO(MB,||,V)
+
+#define IS_MELZI MB(MELZI, MELZI_CREALITY, MELZI_MAKR3D, MELZI_MALYAN, MELZI_TRONXY, MELZI_V2)
diff --git a/Marlin/src/core/debug_out.h b/Marlin/src/core/debug_out.h
new file mode 100644
index 0000000..6ae1b9d
--- /dev/null
+++ b/Marlin/src/core/debug_out.h
@@ -0,0 +1,121 @@
+/**
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+//
+// Serial aliases for debugging.
+// Include this header after defining DEBUG_OUT
+// (or not) in a given .cpp file
+//
+
+#undef DEBUG_SECTION
+#undef DEBUG_PRINT_P
+#undef DEBUG_ECHO_START
+#undef DEBUG_ERROR_START
+#undef DEBUG_CHAR
+#undef DEBUG_ECHO
+#undef DEBUG_DECIMAL
+#undef DEBUG_ECHO_F
+#undef DEBUG_ECHOLN
+#undef DEBUG_ECHOPGM
+#undef DEBUG_ECHOLNPGM
+#undef DEBUG_ECHOPAIR
+#undef DEBUG_ECHOPAIR_P
+#undef DEBUG_ECHOPAIR_F
+#undef DEBUG_ECHOPAIR_F_P
+#undef DEBUG_ECHOLNPAIR
+#undef DEBUG_ECHOLNPAIR_P
+#undef DEBUG_ECHOLNPAIR_F
+#undef DEBUG_ECHOLNPAIR_F_P
+#undef DEBUG_ECHO_MSG
+#undef DEBUG_ERROR_MSG
+#undef DEBUG_EOL
+#undef DEBUG_FLUSH
+#undef DEBUG_POS
+#undef DEBUG_XYZ
+#undef DEBUG_DELAY
+#undef DEBUG_SYNCHRONIZE
+
+#if DEBUG_OUT
+
+ #include "debug_section.h"
+ #define DEBUG_SECTION(N,S,D) SectionLog N(PSTR(S),D)
+
+ #define DEBUG_PRINT_P(P) serialprintPGM(P)
+ #define DEBUG_ECHO_START SERIAL_ECHO_START
+ #define DEBUG_ERROR_START SERIAL_ERROR_START
+ #define DEBUG_CHAR SERIAL_CHAR
+ #define DEBUG_ECHO SERIAL_ECHO
+ #define DEBUG_DECIMAL SERIAL_DECIMAL
+ #define DEBUG_ECHO_F SERIAL_ECHO_F
+ #define DEBUG_ECHOLN SERIAL_ECHOLN
+ #define DEBUG_ECHOPGM SERIAL_ECHOPGM
+ #define DEBUG_ECHOLNPGM SERIAL_ECHOLNPGM
+ #define DEBUG_ECHOPAIR SERIAL_ECHOPAIR
+ #define DEBUG_ECHOPAIR_P SERIAL_ECHOPAIR_P
+ #define DEBUG_ECHOPAIR_F SERIAL_ECHOPAIR_F
+ #define DEBUG_ECHOPAIR_F_P SERIAL_ECHOPAIR_F_P
+ #define DEBUG_ECHOLNPAIR SERIAL_ECHOLNPAIR
+ #define DEBUG_ECHOLNPAIR_P SERIAL_ECHOLNPAIR_P
+ #define DEBUG_ECHOLNPAIR_F SERIAL_ECHOLNPAIR_F
+ #define DEBUG_ECHOLNPAIR_F_P SERIAL_ECHOLNPAIR_F_P
+ #define DEBUG_ECHO_MSG SERIAL_ECHO_MSG
+ #define DEBUG_ERROR_MSG SERIAL_ERROR_MSG
+ #define DEBUG_EOL SERIAL_EOL
+ #define DEBUG_FLUSH SERIAL_FLUSH
+ #define DEBUG_POS SERIAL_POS
+ #define DEBUG_XYZ SERIAL_XYZ
+ #define DEBUG_DELAY(ms) serial_delay(ms)
+ #define DEBUG_SYNCHRONIZE() planner.synchronize()
+
+#else
+
+ #define DEBUG_SECTION(...) NOOP
+ #define DEBUG_PRINT_P(P) NOOP
+ #define DEBUG_ECHO_START() NOOP
+ #define DEBUG_ERROR_START() NOOP
+ #define DEBUG_CHAR(...) NOOP
+ #define DEBUG_ECHO(...) NOOP
+ #define DEBUG_DECIMAL(...) NOOP
+ #define DEBUG_ECHO_F(...) NOOP
+ #define DEBUG_ECHOLN(...) NOOP
+ #define DEBUG_ECHOPGM(...) NOOP
+ #define DEBUG_ECHOLNPGM(...) NOOP
+ #define DEBUG_ECHOPAIR(...) NOOP
+ #define DEBUG_ECHOPAIR_P(...) NOOP
+ #define DEBUG_ECHOPAIR_F(...) NOOP
+ #define DEBUG_ECHOPAIR_F_P(...) NOOP
+ #define DEBUG_ECHOLNPAIR(...) NOOP
+ #define DEBUG_ECHOLNPAIR_P(...) NOOP
+ #define DEBUG_ECHOLNPAIR_F(...) NOOP
+ #define DEBUG_ECHOLNPAIR_F_P(...) NOOP
+ #define DEBUG_ECHO_MSG(...) NOOP
+ #define DEBUG_ERROR_MSG(...) NOOP
+ #define DEBUG_EOL() NOOP
+ #define DEBUG_FLUSH() NOOP
+ #define DEBUG_POS(...) NOOP
+ #define DEBUG_XYZ(...) NOOP
+ #define DEBUG_DELAY(...) NOOP
+ #define DEBUG_SYNCHRONIZE() NOOP
+
+#endif
+
+#undef DEBUG_OUT
diff --git a/Marlin/src/core/debug_section.h b/Marlin/src/core/debug_section.h
new file mode 100644
index 0000000..7f39bc7
--- /dev/null
+++ b/Marlin/src/core/debug_section.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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "serial.h"
+#include "../module/motion.h"
+
+class SectionLog {
+public:
+ SectionLog(PGM_P const msg=nullptr, bool inbug=true) {
+ the_msg = msg;
+ if ((debug = inbug)) echo_msg(PSTR(">>>"));
+ }
+
+ ~SectionLog() { if (debug) echo_msg(PSTR("<<<")); }
+
+private:
+ PGM_P the_msg;
+ bool debug;
+
+ void echo_msg(PGM_P const pre) {
+ serialprintPGM(pre);
+ if (the_msg) {
+ SERIAL_CHAR(' ');
+ serialprintPGM(the_msg);
+ }
+ SERIAL_CHAR(' ');
+ print_xyz(current_position);
+ }
+};
diff --git a/Marlin/src/core/drivers.h b/Marlin/src/core/drivers.h
new file mode 100644
index 0000000..3a0e620
--- /dev/null
+++ b/Marlin/src/core/drivers.h
@@ -0,0 +1,197 @@
+/**
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+//
+// Included by MarlinConfigPre.h ahead of Configuration_adv.h.
+// Don't use #if in this file for anything not defined early!
+//
+
+#define _A4988 0x4988
+#define _A5984 0x5984
+#define _DRV8825 0x8825
+#define _LV8729 0x8729
+#define _L6470 0x6470
+#define _L6474 0x6474
+#define _L6480 0x6480
+#define _POWERSTEP01 0xF00D
+#define _TB6560 0x6560
+#define _TB6600 0x6600
+#define _TMC2100 0x2100
+#define _TMC2130 0x2130A
+#define _TMC2130_STANDALONE 0x2130B
+#define _TMC2160 0x2160A
+#define _TMC2160_STANDALONE 0x2160B
+#define _TMC2208 0x2208A
+#define _TMC2208_STANDALONE 0x2208B
+#define _TMC2209 0x2209A
+#define _TMC2209_STANDALONE 0x2209B
+#define _TMC26X 0x2600A
+#define _TMC26X_STANDALONE 0x2600B
+#define _TMC2660 0x2660A
+#define _TMC2660_STANDALONE 0x2660B
+#define _TMC5130 0x5130A
+#define _TMC5130_STANDALONE 0x5130B
+#define _TMC5160 0x5160A
+#define _TMC5160_STANDALONE 0x5160B
+
+#define _DRIVER_ID(V) _CAT(_, V)
+#define _AXIS_DRIVER_TYPE(A,T) (_DRIVER_ID(A##_DRIVER_TYPE) == _DRIVER_ID(T))
+
+#define AXIS_DRIVER_TYPE_X(T) _AXIS_DRIVER_TYPE(X,T)
+#define AXIS_DRIVER_TYPE_Y(T) _AXIS_DRIVER_TYPE(Y,T)
+#define AXIS_DRIVER_TYPE_Z(T) _AXIS_DRIVER_TYPE(Z,T)
+
+#define AXIS_DRIVER_TYPE_X2(T) (EITHER(X_DUAL_STEPPER_DRIVERS, DUAL_X_CARRIAGE) && _AXIS_DRIVER_TYPE(X2,T))
+#define AXIS_DRIVER_TYPE_Y2(T) (ENABLED(Y_DUAL_STEPPER_DRIVERS) && _AXIS_DRIVER_TYPE(Y2,T))
+#define AXIS_DRIVER_TYPE_Z2(T) (NUM_Z_STEPPER_DRIVERS >= 2 && _AXIS_DRIVER_TYPE(Z2,T))
+#define AXIS_DRIVER_TYPE_Z3(T) (NUM_Z_STEPPER_DRIVERS >= 3 && _AXIS_DRIVER_TYPE(Z3,T))
+#define AXIS_DRIVER_TYPE_Z4(T) (NUM_Z_STEPPER_DRIVERS >= 4 && _AXIS_DRIVER_TYPE(Z4,T))
+
+#define AXIS_DRIVER_TYPE_E(N,T) (E_STEPPERS > N && _AXIS_DRIVER_TYPE(E##N,T))
+#define AXIS_DRIVER_TYPE_E0(T) AXIS_DRIVER_TYPE_E(0,T)
+#define AXIS_DRIVER_TYPE_E1(T) AXIS_DRIVER_TYPE_E(1,T)
+#define AXIS_DRIVER_TYPE_E2(T) AXIS_DRIVER_TYPE_E(2,T)
+#define AXIS_DRIVER_TYPE_E3(T) AXIS_DRIVER_TYPE_E(3,T)
+#define AXIS_DRIVER_TYPE_E4(T) AXIS_DRIVER_TYPE_E(4,T)
+#define AXIS_DRIVER_TYPE_E5(T) AXIS_DRIVER_TYPE_E(5,T)
+#define AXIS_DRIVER_TYPE_E6(T) AXIS_DRIVER_TYPE_E(6,T)
+#define AXIS_DRIVER_TYPE_E7(T) AXIS_DRIVER_TYPE_E(7,T)
+
+#define AXIS_DRIVER_TYPE(A,T) AXIS_DRIVER_TYPE_##A(T)
+
+#define _OR_ADTE(N,T) || AXIS_DRIVER_TYPE_E(N,T)
+#define HAS_E_DRIVER(T) (0 RREPEAT2(E_STEPPERS, _OR_ADTE, T))
+
+#define HAS_DRIVER(T) ( AXIS_DRIVER_TYPE_X(T) || AXIS_DRIVER_TYPE_Y(T) || AXIS_DRIVER_TYPE_Z(T) \
+ || AXIS_DRIVER_TYPE_X2(T) || AXIS_DRIVER_TYPE_Y2(T) || AXIS_DRIVER_TYPE_Z2(T) \
+ || AXIS_DRIVER_TYPE_Z3(T) || AXIS_DRIVER_TYPE_Z4(T) || HAS_E_DRIVER(T) )
+
+//
+// Trinamic Stepper Drivers
+//
+
+// Test for supported TMC drivers that require advanced configuration
+// Does not match standalone configurations
+#if ( HAS_DRIVER(TMC2130) || HAS_DRIVER(TMC2160) \
+ || HAS_DRIVER(TMC2208) || HAS_DRIVER(TMC2209) \
+ || HAS_DRIVER(TMC2660) \
+ || HAS_DRIVER(TMC5130) || HAS_DRIVER(TMC5160) )
+ #define HAS_TRINAMIC_CONFIG 1
+#endif
+
+#define HAS_TRINAMIC HAS_TRINAMIC_CONFIG
+
+#if ( HAS_DRIVER(TMC2130_STANDALONE) || HAS_DRIVER(TMC2160_STANDALONE) \
+ || HAS_DRIVER(TMC2208_STANDALONE) || HAS_DRIVER(TMC2209_STANDALONE) \
+ || HAS_DRIVER(TMC26X_STANDALONE) || HAS_DRIVER(TMC2660_STANDALONE) \
+ || HAS_DRIVER(TMC5130_STANDALONE) || HAS_DRIVER(TMC5160_STANDALONE) )
+ #define HAS_TRINAMIC_STANDALONE 1
+#endif
+
+#if HAS_DRIVER(TMC2130) || HAS_DRIVER(TMC2160) || HAS_DRIVER(TMC5130) || HAS_DRIVER(TMC5160)
+ #define HAS_TMCX1X0 1
+#endif
+
+#if HAS_DRIVER(TMC2208) || HAS_DRIVER(TMC2209)
+ #define HAS_TMC220x 1
+#endif
+
+#define AXIS_IS_TMC(A) ( AXIS_DRIVER_TYPE(A,TMC2130) || AXIS_DRIVER_TYPE(A,TMC2160) \
+ || AXIS_DRIVER_TYPE(A,TMC2208) || AXIS_DRIVER_TYPE(A,TMC2209) \
+ || AXIS_DRIVER_TYPE(A,TMC2660) \
+ || AXIS_DRIVER_TYPE(A,TMC5130) || AXIS_DRIVER_TYPE(A,TMC5160) )
+
+// Test for a driver that uses SPI - this allows checking whether a _CS_ pin
+// is considered sensitive
+#define AXIS_HAS_SPI(A) ( AXIS_DRIVER_TYPE(A,TMC2130) || AXIS_DRIVER_TYPE(A,TMC2160) \
+ || AXIS_DRIVER_TYPE(A,TMC2660) \
+ || AXIS_DRIVER_TYPE(A,TMC5130) || AXIS_DRIVER_TYPE(A,TMC5160) )
+
+#define AXIS_HAS_UART(A) ( AXIS_DRIVER_TYPE(A,TMC2208) || AXIS_DRIVER_TYPE(A,TMC2209) )
+
+#define AXIS_HAS_RXTX AXIS_HAS_UART
+
+#define AXIS_HAS_HW_SERIAL(A) ( AXIS_HAS_UART(A) && defined(A##_HARDWARE_SERIAL) )
+#define AXIS_HAS_SW_SERIAL(A) ( AXIS_HAS_UART(A) && !defined(A##_HARDWARE_SERIAL) )
+
+#define AXIS_HAS_STALLGUARD(A) ( AXIS_DRIVER_TYPE(A,TMC2130) || AXIS_DRIVER_TYPE(A,TMC2160) \
+ || AXIS_DRIVER_TYPE(A,TMC2209) \
+ || AXIS_DRIVER_TYPE(A,TMC2660) \
+ || AXIS_DRIVER_TYPE(A,TMC5130) || AXIS_DRIVER_TYPE(A,TMC5160) )
+
+#define AXIS_HAS_STEALTHCHOP(A) ( AXIS_DRIVER_TYPE(A,TMC2130) || AXIS_DRIVER_TYPE(A,TMC2160) \
+ || AXIS_DRIVER_TYPE(A,TMC2208) || AXIS_DRIVER_TYPE(A,TMC2209) \
+ || AXIS_DRIVER_TYPE(A,TMC5130) || AXIS_DRIVER_TYPE(A,TMC5160) )
+
+#define AXIS_HAS_SG_RESULT(A) ( AXIS_DRIVER_TYPE(A,TMC2130) || AXIS_DRIVER_TYPE(A,TMC2160) \
+ || AXIS_DRIVER_TYPE(A,TMC2208) || AXIS_DRIVER_TYPE(A,TMC2209) )
+
+#define AXIS_HAS_COOLSTEP(A) ( AXIS_DRIVER_TYPE(A,TMC2130) \
+ || AXIS_DRIVER_TYPE(A,TMC2209) \
+ || AXIS_DRIVER_TYPE(A,TMC5130) || AXIS_DRIVER_TYPE(A,TMC5160) )
+
+#define _OR_EAH(N,T) || AXIS_HAS_##T(E##N)
+#define E_AXIS_HAS(T) (0 _OR_EAH(0,T) _OR_EAH(1,T) _OR_EAH(2,T) _OR_EAH(3,T) _OR_EAH(4,T) _OR_EAH(5,T) _OR_EAH(6,T) _OR_EAH(7,T))
+
+#define ANY_AXIS_HAS(T) ( AXIS_HAS_##T(X) || AXIS_HAS_##T(Y) || AXIS_HAS_##T(Z) \
+ || AXIS_HAS_##T(X2) || AXIS_HAS_##T(Y2) || AXIS_HAS_##T(Z2) \
+ || AXIS_HAS_##T(Z3) || AXIS_HAS_##T(Z4) || E_AXIS_HAS(T) )
+
+#if ANY_AXIS_HAS(STEALTHCHOP)
+ #define HAS_STEALTHCHOP 1
+#endif
+#if ANY_AXIS_HAS(STALLGUARD)
+ #define HAS_STALLGUARD 1
+#endif
+#if ANY_AXIS_HAS(SG_RESULT)
+ #define HAS_SG_RESULT 1
+#endif
+#if ANY_AXIS_HAS(COOLSTEP)
+ #define HAS_COOLSTEP 1
+#endif
+#if ANY_AXIS_HAS(RXTX)
+ #define HAS_TMC_UART 1
+#endif
+#if ANY_AXIS_HAS(SPI)
+ #define HAS_TMC_SPI 1
+#endif
+
+//
+// TMC26XX Stepper Drivers
+//
+#if HAS_DRIVER(TMC26X)
+ #define HAS_TMC26X 1
+#endif
+
+//
+// L64XX Stepper Drivers
+//
+
+#if HAS_DRIVER(L6470) || HAS_DRIVER(L6474) || HAS_DRIVER(L6480) || HAS_DRIVER(POWERSTEP01)
+ #define HAS_L64XX 1
+#endif
+#if HAS_L64XX && !HAS_DRIVER(L6474)
+ #define HAS_L64XX_NOT_L6474 1
+#endif
+
+#define AXIS_IS_L64XX(A) (AXIS_DRIVER_TYPE_##A(L6470) || AXIS_DRIVER_TYPE_##A(L6474) || AXIS_DRIVER_TYPE_##A(L6480) || AXIS_DRIVER_TYPE_##A(POWERSTEP01))
diff --git a/Marlin/src/core/language.h b/Marlin/src/core/language.h
new file mode 100644
index 0000000..923ad90
--- /dev/null
+++ b/Marlin/src/core/language.h
@@ -0,0 +1,408 @@
+/**
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "../inc/MarlinConfig.h"
+
+#define _UxGT(a) a
+
+// Fallback if no language is set. DON'T CHANGE
+#ifndef LCD_LANGUAGE
+ #define LCD_LANGUAGE en
+#endif
+
+// For character-based LCD controllers (DISPLAY_CHARSET_HD44780)
+#define JAPANESE 1
+#define WESTERN 2
+#define CYRILLIC 3
+
+// NOTE: IF YOU CHANGE LANGUAGE FILES OR MERGE A FILE WITH CHANGES
+//
+// ==> ALWAYS TRY TO COMPILE MARLIN WITH/WITHOUT "ULTIPANEL" / "ULTRA_LCD" / "SDSUPPORT" #define IN "Configuration.h"
+// ==> ALSO TRY ALL AVAILABLE LANGUAGE OPTIONS
+// See also https://marlinfw.org/docs/development/lcd_language.html
+
+// Languages
+// an Aragonese
+// bg Bulgarian
+// ca Catalan
+// cz Czech
+// da Danish
+// de German
+// el Greek
+// el_gr Greek (Greece)
+// en English
+// 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)
+
+#ifdef DEFAULT_SOURCE_CODE_URL
+ #undef SOURCE_CODE_URL
+ #define SOURCE_CODE_URL DEFAULT_SOURCE_CODE_URL
+#endif
+
+#ifdef CUSTOM_MACHINE_NAME
+ #undef MACHINE_NAME
+ #define MACHINE_NAME CUSTOM_MACHINE_NAME
+#elif defined(DEFAULT_MACHINE_NAME)
+ #undef MACHINE_NAME
+ #define MACHINE_NAME DEFAULT_MACHINE_NAME
+#endif
+
+#ifndef MACHINE_UUID
+ #define MACHINE_UUID DEFAULT_MACHINE_UUID
+#endif
+
+#define MARLIN_WEBSITE_URL "marlinfw.org"
+
+//#if !defined(STRING_SPLASH_LINE3) && defined(WEBSITE_URL)
+// #define STRING_SPLASH_LINE3 WEBSITE_URL
+//#endif
+
+//
+// Common Serial Console Messages
+// Don't change these strings because serial hosts look for them.
+//
+
+#define STR_ENQUEUEING "enqueueing \""
+#define STR_POWERUP "PowerUp"
+#define STR_EXTERNAL_RESET " External Reset"
+#define STR_BROWNOUT_RESET " Brown out Reset"
+#define STR_WATCHDOG_RESET " Watchdog Reset"
+#define STR_SOFTWARE_RESET " Software Reset"
+#define STR_FREE_MEMORY " Free Memory: "
+#define STR_PLANNER_BUFFER_BYTES " PlannerBufferBytes: "
+#define STR_OK "ok"
+#define STR_WAIT "wait"
+#define STR_STATS "Stats: "
+#define STR_FILE_SAVED "Done saving file."
+#define STR_ERR_LINE_NO "Line Number is not Last Line Number+1, Last Line: "
+#define STR_ERR_CHECKSUM_MISMATCH "checksum mismatch, Last Line: "
+#define STR_ERR_NO_CHECKSUM "No Checksum with line number, Last Line: "
+#define STR_FILE_PRINTED "Done printing file"
+#define STR_NO_MEDIA "No media"
+#define STR_BEGIN_FILE_LIST "Begin file list"
+#define STR_END_FILE_LIST "End file list"
+#define STR_INVALID_EXTRUDER "Invalid extruder"
+#define STR_INVALID_E_STEPPER "Invalid E stepper"
+#define STR_E_STEPPER_NOT_SPECIFIED "E stepper not specified"
+#define STR_INVALID_SOLENOID "Invalid solenoid"
+#define STR_COUNT_X " Count X:"
+#define STR_COUNT_A " Count A:"
+#define STR_WATCHDOG_FIRED "Watchdog timeout. Reset required."
+#define STR_ERR_KILLED "Printer halted. kill() called!"
+#define STR_ERR_STOPPED "Printer stopped due to errors. Fix the error and use M999 to restart. (Temperature is reset. Set it after restarting)"
+#define STR_BUSY_PROCESSING "busy: processing"
+#define STR_BUSY_PAUSED_FOR_USER "busy: paused for user"
+#define STR_BUSY_PAUSED_FOR_INPUT "busy: paused for input"
+#define STR_Z_MOVE_COMP "Z_move_comp"
+#define STR_RESEND "Resend: "
+#define STR_UNKNOWN_COMMAND "Unknown command: \""
+#define STR_ACTIVE_EXTRUDER "Active Extruder: "
+#define STR_X_MIN "x_min"
+#define STR_X_MAX "x_max"
+#define STR_X2_MIN "x2_min"
+#define STR_X2_MAX "x2_max"
+#define STR_Y_MIN "y_min"
+#define STR_Y_MAX "y_max"
+#define STR_Y2_MIN "y2_min"
+#define STR_Y2_MAX "y2_max"
+#define STR_Z_MIN "z_min"
+#define STR_Z_MAX "z_max"
+#define STR_Z2_MIN "z2_min"
+#define STR_Z2_MAX "z2_max"
+#define STR_Z3_MIN "z3_min"
+#define STR_Z3_MAX "z3_max"
+#define STR_Z4_MIN "z4_min"
+#define STR_Z4_MAX "z4_max"
+#define STR_Z_PROBE "z_probe"
+#define STR_PROBE_EN "probe_en"
+#define STR_FILAMENT_RUNOUT_SENSOR "filament"
+#define STR_PROBE_OFFSET "Probe Offset"
+#define STR_SKEW_MIN "min_skew_factor: "
+#define STR_SKEW_MAX "max_skew_factor: "
+#define STR_ERR_MATERIAL_INDEX "M145 S<index> out of range (0-1)"
+#define STR_ERR_M421_PARAMETERS "M421 incorrect parameter usage"
+#define STR_ERR_BAD_PLANE_MODE "G5 requires XY plane mode"
+#define STR_ERR_MESH_XY "Mesh point out of range"
+#define STR_ERR_ARC_ARGS "G2/G3 bad parameters"
+#define STR_ERR_PROTECTED_PIN "Protected Pin"
+#define STR_ERR_M420_FAILED "Failed to enable Bed Leveling"
+#define STR_ERR_M428_TOO_FAR "Too far from reference point"
+#define STR_ERR_M303_DISABLED "PIDTEMP disabled"
+#define STR_M119_REPORT "Reporting endstop status"
+#define STR_ON "ON"
+#define STR_OFF "OFF"
+#define STR_ENDSTOP_HIT "TRIGGERED"
+#define STR_ENDSTOP_OPEN "open"
+#define STR_HOTEND_OFFSET "Hotend offsets:"
+#define STR_DUPLICATION_MODE "Duplication mode: "
+#define STR_SOFT_ENDSTOPS "Soft endstops: "
+#define STR_SOFT_MIN " Min: "
+#define STR_SOFT_MAX " Max: "
+
+#define STR_SAVED_POS "Position saved"
+#define STR_RESTORING_POS "Restoring position"
+#define STR_INVALID_POS_SLOT "Invalid slot. Total: "
+
+#define STR_SD_CANT_OPEN_SUBDIR "Cannot open subdir "
+#define STR_SD_INIT_FAIL "No SD card"
+#define STR_SD_VOL_INIT_FAIL "volume.init failed"
+#define STR_SD_OPENROOT_FAIL "openRoot failed"
+#define STR_SD_CARD_OK "SD card ok"
+#define STR_SD_WORKDIR_FAIL "workDir open failed"
+#define STR_SD_OPEN_FILE_FAIL "open failed, File: "
+#define STR_SD_FILE_OPENED "File opened: "
+#define STR_SD_SIZE " Size: "
+#define STR_SD_FILE_SELECTED "File selected"
+#define STR_SD_WRITE_TO_FILE "Writing to file: "
+#define STR_SD_PRINTING_BYTE "SD printing byte "
+#define STR_SD_NOT_PRINTING "Not SD printing"
+#define STR_SD_ERR_WRITE_TO_FILE "error writing to file"
+#define STR_SD_ERR_READ "SD read error"
+#define STR_SD_CANT_ENTER_SUBDIR "Cannot enter subdir: "
+
+#define STR_ENDSTOPS_HIT "endstops hit: "
+#define STR_ERR_COLD_EXTRUDE_STOP " cold extrusion prevented"
+#define STR_ERR_LONG_EXTRUDE_STOP " too long extrusion prevented"
+#define STR_ERR_HOTEND_TOO_COLD "Hotend too cold"
+#define STR_ERR_EEPROM_WRITE "Error writing to EEPROM!"
+
+#define STR_FILAMENT_CHANGE_HEAT_LCD "Press button to heat nozzle"
+#define STR_FILAMENT_CHANGE_INSERT_LCD "Insert filament and press button"
+#define STR_FILAMENT_CHANGE_WAIT_LCD "Press button to resume"
+#define STR_FILAMENT_CHANGE_HEAT_M108 "Send M108 to heat nozzle"
+#define STR_FILAMENT_CHANGE_INSERT_M108 "Insert filament and send M108"
+#define STR_FILAMENT_CHANGE_WAIT_M108 "Send M108 to resume"
+
+#define STR_STOP_BLTOUCH "!! STOP called because of BLTouch error - restart with M999"
+#define STR_STOP_UNHOMED "!! STOP called because of unhomed error - restart with M999"
+#define STR_KILL_INACTIVE_TIME "!! KILL caused by too much inactive time - current command: "
+#define STR_KILL_BUTTON "!! KILL caused by KILL button/pin"
+
+// temperature.cpp strings
+#define STR_PID_AUTOTUNE_START "PID Autotune start"
+#define STR_PID_BAD_EXTRUDER_NUM "PID Autotune failed! Bad extruder number"
+#define STR_PID_TEMP_TOO_HIGH "PID Autotune failed! Temperature too high"
+#define STR_PID_TIMEOUT "PID Autotune failed! timeout"
+#define STR_BIAS " bias: "
+#define STR_D_COLON " d: "
+#define STR_T_MIN " min: "
+#define STR_T_MAX " max: "
+#define STR_KU " Ku: "
+#define STR_TU " Tu: "
+#define STR_CLASSIC_PID " Classic PID "
+#define STR_KP " Kp: "
+#define STR_KI " Ki: "
+#define STR_KD " Kd: "
+#define STR_PID_AUTOTUNE_FINISHED "PID Autotune finished! Put the last Kp, Ki and Kd constants from below into Configuration.h"
+#define STR_PID_DEBUG " PID_DEBUG "
+#define STR_PID_DEBUG_INPUT ": Input "
+#define STR_PID_DEBUG_OUTPUT " Output "
+#define STR_PID_DEBUG_PTERM " pTerm "
+#define STR_PID_DEBUG_ITERM " iTerm "
+#define STR_PID_DEBUG_DTERM " dTerm "
+#define STR_PID_DEBUG_CTERM " cTerm "
+#define STR_INVALID_EXTRUDER_NUM " - Invalid extruder number !"
+
+#define STR_HEATER_BED "bed"
+#define STR_HEATER_CHAMBER "chamber"
+
+#define STR_STOPPED_HEATER ", system stopped! Heater_ID: "
+#define STR_REDUNDANCY "Heater switched off. Temperature difference between temp sensors is too high !"
+#define STR_T_HEATING_FAILED "Heating failed"
+#define STR_T_THERMAL_RUNAWAY "Thermal Runaway"
+#define STR_T_MAXTEMP "MAXTEMP triggered"
+#define STR_T_MINTEMP "MINTEMP triggered"
+#define STR_ERR_PROBING_FAILED "Probing Failed"
+#define STR_ZPROBE_OUT_SER "Z Probe Past Bed"
+
+// Debug
+#define STR_DEBUG_PREFIX "DEBUG:"
+#define STR_DEBUG_OFF "off"
+#define STR_DEBUG_ECHO "ECHO"
+#define STR_DEBUG_INFO "INFO"
+#define STR_DEBUG_ERRORS "ERRORS"
+#define STR_DEBUG_DRYRUN "DRYRUN"
+#define STR_DEBUG_COMMUNICATION "COMMUNICATION"
+#define STR_DEBUG_LEVELING "LEVELING"
+
+#define STR_PRINTER_LOCKED "Printer locked! (Unlock with M511 or LCD)"
+#define STR_WRONG_PASSWORD "Incorrect Password"
+#define STR_PASSWORD_TOO_LONG "Password too long"
+#define STR_PASSWORD_REMOVED "Password removed"
+#define STR_REMINDER_SAVE_SETTINGS "Remember to save!"
+#define STR_PASSWORD_SET "Password is "
+
+// LCD Menu Messages
+
+#define LANGUAGE_DATA_INCL_(M) STRINGIFY_(fontdata/langdata_##M.h)
+#define LANGUAGE_DATA_INCL(M) LANGUAGE_DATA_INCL_(M)
+
+#define LANGUAGE_INCL_(M) STRINGIFY_(../lcd/language/language_##M.h)
+#define LANGUAGE_INCL(M) LANGUAGE_INCL_(M)
+
+#define STR_X "X"
+#define STR_Y "Y"
+#define STR_Z "Z"
+#define STR_E "E"
+#if IS_KINEMATIC
+ #define STR_A "A"
+ #define STR_B "B"
+ #define STR_C "C"
+#else
+ #define STR_A "X"
+ #define STR_B "Y"
+ #define STR_C "Z"
+#endif
+#define STR_X2 "X2"
+#define STR_Y2 "Y2"
+#define STR_Z2 "Z2"
+#define STR_Z3 "Z3"
+#define STR_Z4 "Z4"
+
+#define LCD_STR_A STR_A
+#define LCD_STR_B STR_B
+#define LCD_STR_C STR_C
+#define LCD_STR_E STR_E
+
+#if EITHER(HAS_MARLINUI_HD44780, IS_TFTGLCD_PANEL)
+
+ // Custom characters defined in the first 8 characters of the LCD
+ #define LCD_STR_BEDTEMP "\x00" // Print only as a char. This will have 'unexpected' results when used in a string!
+ #define LCD_STR_DEGREE "\x01"
+ #define LCD_STR_THERMOMETER "\x02" // Still used with string concatenation
+ #define LCD_STR_UPLEVEL "\x03"
+ #define LCD_STR_REFRESH "\x04"
+ #define LCD_STR_FOLDER "\x05"
+ #define LCD_STR_FEEDRATE "\x06"
+ #define LCD_STR_CLOCK "\x07"
+ #define LCD_STR_ARROW_RIGHT ">" /* from the default character set */
+
+#else
+ //
+ // Custom characters from Marlin_symbols.fon which was merged into ISO10646-0-3.bdf
+ // \x00 intentionally skipped to avoid problems in strings
+ //
+ #define LCD_STR_REFRESH "\x01"
+ #define LCD_STR_FOLDER "\x02"
+ #define LCD_STR_ARROW_RIGHT "\x03"
+ #define LCD_STR_UPLEVEL "\x04"
+ #define LCD_STR_CLOCK "\x05"
+ #define LCD_STR_FEEDRATE "\x06"
+ #define LCD_STR_BEDTEMP "\x07"
+ #define LCD_STR_THERMOMETER "\x08"
+ #define LCD_STR_DEGREE "\x09"
+
+ #define LCD_STR_SPECIAL_MAX '\x09'
+ // Maximum here is 0x1F because 0x20 is ' ' (space) and the normal charsets begin.
+ // Better stay below 0x10 because DISPLAY_CHARSET_HD44780_WESTERN begins here.
+
+ // Symbol characters
+ #define LCD_STR_FILAM_DIA "\xF8"
+ #define LCD_STR_FILAM_MUL "\xA4"
+
+#endif
+
+/**
+ * Tool indexes for LCD display only
+ *
+ * By convention the LCD shows "E1" for the first extruder.
+ * However, internal to Marlin E0/T0 is the first tool, and
+ * most board silkscreens say "E0." Zero-based labels will
+ * make these indexes consistent but this defies expectation.
+ */
+#if ENABLED(NUMBER_TOOLS_FROM_0)
+ #define LCD_FIRST_TOOL 0
+ #define LCD_STR_N0 "0"
+ #define LCD_STR_N1 "1"
+ #define LCD_STR_N2 "2"
+ #define LCD_STR_N3 "3"
+ #define LCD_STR_N4 "4"
+ #define LCD_STR_N5 "5"
+ #define LCD_STR_N6 "6"
+ #define LCD_STR_N7 "7"
+#else
+ #define LCD_FIRST_TOOL 1
+ #define LCD_STR_N0 "1"
+ #define LCD_STR_N1 "2"
+ #define LCD_STR_N2 "3"
+ #define LCD_STR_N3 "4"
+ #define LCD_STR_N4 "5"
+ #define LCD_STR_N5 "6"
+ #define LCD_STR_N6 "7"
+ #define LCD_STR_N7 "8"
+#endif
+
+#define LCD_STR_E0 "E" LCD_STR_N0
+#define LCD_STR_E1 "E" LCD_STR_N1
+#define LCD_STR_E2 "E" LCD_STR_N2
+#define LCD_STR_E3 "E" LCD_STR_N3
+#define LCD_STR_E4 "E" LCD_STR_N4
+#define LCD_STR_E5 "E" LCD_STR_N5
+#define LCD_STR_E6 "E" LCD_STR_N6
+#define LCD_STR_E7 "E" LCD_STR_N7
+
+// Use superscripts, if possible. Evaluated at point of use.
+#define SUPERSCRIPT_TWO TERN(NOT_EXTENDED_ISO10646_1_5X7, "^2", "²")
+#define SUPERSCRIPT_THREE TERN(NOT_EXTENDED_ISO10646_1_5X7, "^3", "³")
+
+#include "multi_language.h" // Allow multiple languages
+
+#include "../lcd/language/language_en.h"
+#include LANGUAGE_INCL(LCD_LANGUAGE)
+#include LANGUAGE_INCL(LCD_LANGUAGE_2)
+#include LANGUAGE_INCL(LCD_LANGUAGE_3)
+#include LANGUAGE_INCL(LCD_LANGUAGE_4)
+#include LANGUAGE_INCL(LCD_LANGUAGE_5)
+
+#if NONE(DISPLAY_CHARSET_ISO10646_1, \
+ DISPLAY_CHARSET_ISO10646_5, \
+ DISPLAY_CHARSET_ISO10646_KANA, \
+ DISPLAY_CHARSET_ISO10646_GREEK, \
+ DISPLAY_CHARSET_ISO10646_CN, \
+ DISPLAY_CHARSET_ISO10646_TR, \
+ DISPLAY_CHARSET_ISO10646_PL, \
+ DISPLAY_CHARSET_ISO10646_CZ, \
+ DISPLAY_CHARSET_ISO10646_SK)
+ #define DISPLAY_CHARSET_ISO10646_1 // use the better font on full graphic displays.
+#endif
diff --git a/Marlin/src/core/macros.h b/Marlin/src/core/macros.h
new file mode 100644
index 0000000..905b85d
--- /dev/null
+++ b/Marlin/src/core/macros.h
@@ -0,0 +1,545 @@
+/**
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#if !defined(__has_include)
+ #define __has_include(...) 1
+#endif
+
+#define ABCE 4
+#define XYZE 4
+#define ABC 3
+#define XYZ 3
+#define XY 2
+
+#define _AXIS(A) (A##_AXIS)
+
+#define _XMIN_ 100
+#define _YMIN_ 200
+#define _ZMIN_ 300
+#define _XMAX_ 101
+#define _YMAX_ 201
+#define _ZMAX_ 301
+#define _XDIAG_ 102
+#define _YDIAG_ 202
+#define _ZDIAG_ 302
+#define _E0DIAG_ 400
+#define _E1DIAG_ 401
+#define _E2DIAG_ 402
+#define _E3DIAG_ 403
+#define _E4DIAG_ 404
+#define _E5DIAG_ 405
+#define _E6DIAG_ 406
+#define _E7DIAG_ 407
+
+#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")))
+#define _O1 __attribute__((optimize("O1")))
+#define _O2 __attribute__((optimize("O2")))
+#define _O3 __attribute__((optimize("O3")))
+
+#ifndef UNUSED
+ #define UNUSED(x) ((void)(x))
+#endif
+
+// Clock speed factors
+#if !defined(CYCLES_PER_MICROSECOND) && !defined(__STM32F1__)
+ #define CYCLES_PER_MICROSECOND (F_CPU / 1000000UL) // 16 or 20 on AVR
+#endif
+
+// Nanoseconds per cycle
+#define NANOSECONDS_PER_CYCLE (1000000000.0 / F_CPU)
+
+// Macros to make a string from a macro
+#define STRINGIFY_(M) #M
+#define STRINGIFY(M) STRINGIFY_(M)
+
+#define A(CODE) " " CODE "\n\t"
+#define L(CODE) CODE ":\n\t"
+
+// Macros for bit masks
+#undef _BV
+#define _BV(n) (1<<(n))
+#define TEST(n,b) (!!((n)&_BV(b)))
+#define SET_BIT_TO(N,B,TF) do{ if (TF) SBI(N,B); else CBI(N,B); }while(0)
+#ifndef SBI
+ #define SBI(A,B) (A |= _BV(B))
+#endif
+#ifndef CBI
+ #define CBI(A,B) (A &= ~_BV(B))
+#endif
+#define TBI(N,B) (N ^= _BV(B))
+#define _BV32(b) (1UL << (b))
+#define TEST32(n,b) !!((n)&_BV32(b))
+#define SBI32(n,b) (n |= _BV32(b))
+#define CBI32(n,b) (n &= ~_BV32(b))
+#define TBI32(N,B) (N ^= _BV32(B))
+
+#define cu(x) ({__typeof__(x) _x = (x); (_x)*(_x)*(_x);})
+#define RADIANS(d) ((d)*float(M_PI)/180.0f)
+#define DEGREES(r) ((r)*180.0f/float(M_PI))
+#define HYPOT2(x,y) (sq(x)+sq(y))
+
+#define CIRCLE_AREA(R) (float(M_PI) * sq(float(R)))
+#define CIRCLE_CIRC(R) (2 * float(M_PI) * float(R))
+
+#define SIGN(a) ({__typeof__(a) _a = (a); (_a>0)-(_a<0);})
+#define IS_POWER_OF_2(x) ((x) && !((x) & ((x) - 1)))
+
+// Macros to constrain values
+#ifdef __cplusplus
+
+ // C++11 solution that is standards compliant.
+ template <class V, class N> static inline constexpr void NOLESS(V& v, const N n) {
+ if (n > v) v = n;
+ }
+ template <class V, class N> static inline constexpr void NOMORE(V& v, const N n) {
+ if (n < v) v = n;
+ }
+ template <class V, class N1, class N2> static inline constexpr void LIMIT(V& v, const N1 n1, const N2 n2) {
+ if (n1 > v) v = n1;
+ else if (n2 < v) v = n2;
+ }
+
+#else
+
+ #define NOLESS(v, n) \
+ do{ \
+ __typeof__(n) _n = (n); \
+ if (_n > v) v = _n; \
+ }while(0)
+
+ #define NOMORE(v, n) \
+ do{ \
+ __typeof__(n) _n = (n); \
+ if (_n < v) v = _n; \
+ }while(0)
+
+ #define LIMIT(v, n1, n2) \
+ do{ \
+ __typeof__(n1) _n1 = (n1); \
+ __typeof__(n2) _n2 = (n2); \
+ if (_n1 > v) v = _n1; \
+ else if (_n2 < v) v = _n2; \
+ }while(0)
+
+#endif
+
+// Macros to chain up to 14 conditions
+#define _DO_1(W,C,A) (_##W##_1(A))
+#define _DO_2(W,C,A,B) (_##W##_1(A) C _##W##_1(B))
+#define _DO_3(W,C,A,V...) (_##W##_1(A) C _DO_2(W,C,V))
+#define _DO_4(W,C,A,V...) (_##W##_1(A) C _DO_3(W,C,V))
+#define _DO_5(W,C,A,V...) (_##W##_1(A) C _DO_4(W,C,V))
+#define _DO_6(W,C,A,V...) (_##W##_1(A) C _DO_5(W,C,V))
+#define _DO_7(W,C,A,V...) (_##W##_1(A) C _DO_6(W,C,V))
+#define _DO_8(W,C,A,V...) (_##W##_1(A) C _DO_7(W,C,V))
+#define _DO_9(W,C,A,V...) (_##W##_1(A) C _DO_8(W,C,V))
+#define _DO_10(W,C,A,V...) (_##W##_1(A) C _DO_9(W,C,V))
+#define _DO_11(W,C,A,V...) (_##W##_1(A) C _DO_10(W,C,V))
+#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))
+
+// Macros to support option testing
+#define _CAT(a,V...) a##V
+#define CAT(a,V...) _CAT(a,V)
+
+#define _ISENA_ ~,1
+#define _ISENA_1 ~,1
+#define _ISENA_0x1 ~,1
+#define _ISENA_true ~,1
+#define _ISENA(V...) IS_PROBE(V)
+
+#define _ENA_1(O) _ISENA(CAT(_IS,CAT(ENA_, O)))
+#define _DIS_1(O) NOT(_ENA_1(O))
+#define ENABLED(V...) DO(ENA,&&,V)
+#define DISABLED(V...) DO(DIS,&&,V)
+#define COUNT_ENABLED(V...) DO(ENA,+,V)
+
+#define TERN(O,A,B) _TERN(_ENA_1(O),B,A) // OPTION converted to '0' or '1'
+#define TERN0(O,A) _TERN(_ENA_1(O),0,A) // OPTION converted to A or '0'
+#define TERN1(O,A) _TERN(_ENA_1(O),1,A) // OPTION converted to A or '1'
+#define TERN_(O,A) _TERN(_ENA_1(O),,A) // OPTION converted to A or '<nul>'
+#define _TERN(E,V...) __TERN(_CAT(T_,E),V) // Prepend 'T_' to get 'T_0' or 'T_1'
+#define __TERN(T,V...) ___TERN(_CAT(_NO,T),V) // Prepend '_NO' to get '_NOT_0' or '_NOT_1'
+#define ___TERN(P,V...) THIRD(P,V) // If first argument has a comma, A. Else B.
+
+#define IF_ENABLED TERN_
+#define IF_DISABLED(O,A) TERN(O,,A)
+
+#define ANY(V...) !DISABLED(V)
+#define NONE(V...) DISABLED(V)
+#define ALL(V...) ENABLED(V)
+#define BOTH(V1,V2) ALL(V1,V2)
+#define EITHER(V1,V2) ANY(V1,V2)
+#define MANY(V...) (COUNT_ENABLED(V) > 1)
+
+// Macros to support pins/buttons exist testing
+#define PIN_EXISTS(PN) (defined(PN##_PIN) && PN##_PIN >= 0)
+#define _PINEX_1 PIN_EXISTS
+#define PINS_EXIST(V...) DO(PINEX,&&,V)
+#define ANY_PIN(V...) DO(PINEX,||,V)
+
+#define BUTTON_EXISTS(BN) (defined(BTN_##BN) && BTN_##BN >= 0)
+#define _BTNEX_1 BUTTON_EXISTS
+#define BUTTONS_EXIST(V...) DO(BTNEX,&&,V)
+#define ANY_BUTTON(V...) DO(BTNEX,||,V)
+
+#define WITHIN(N,L,H) ((N) >= (L) && (N) <= (H))
+#define ISEOL(C) ((C) == '\n' || (C) == '\r')
+#define NUMERIC(a) WITHIN(a, '0', '9')
+#define DECIMAL(a) (NUMERIC(a) || a == '.')
+#define HEXCHR(a) (NUMERIC(a) ? (a) - '0' : WITHIN(a, 'a', 'f') ? ((a) - 'a' + 10) : WITHIN(a, 'A', 'F') ? ((a) - 'A' + 10) : -1)
+#define NUMERIC_SIGNED(a) (NUMERIC(a) || (a) == '-' || (a) == '+')
+#define DECIMAL_SIGNED(a) (DECIMAL(a) || (a) == '-' || (a) == '+')
+#define COUNT(a) (sizeof(a)/sizeof(*a))
+#define ZERO(a) memset(a,0,sizeof(a))
+#define COPY(a,b) do{ \
+ static_assert(sizeof(a[0]) == sizeof(b[0]), "COPY: '" STRINGIFY(a) "' and '" STRINGIFY(b) "' types (sizes) don't match!"); \
+ memcpy(&a[0],&b[0],_MIN(sizeof(a),sizeof(b))); \
+ }while(0)
+
+// Macros for initializing arrays
+#define LIST_16(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P
+#define LIST_15(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O
+#define LIST_14(A,B,C,D,E,F,G,H,I,J,K,L,M,N,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N
+#define LIST_13(A,B,C,D,E,F,G,H,I,J,K,L,M,...) A,B,C,D,E,F,G,H,I,J,K,L,M
+#define LIST_12(A,B,C,D,E,F,G,H,I,J,K,L,...) A,B,C,D,E,F,G,H,I,J,K,L
+#define LIST_11(A,B,C,D,E,F,G,H,I,J,K,...) A,B,C,D,E,F,G,H,I,J,K
+#define LIST_10(A,B,C,D,E,F,G,H,I,J,...) A,B,C,D,E,F,G,H,I,J
+#define LIST_9( A,B,C,D,E,F,G,H,I,...) A,B,C,D,E,F,G,H,I
+#define LIST_8( A,B,C,D,E,F,G,H,...) A,B,C,D,E,F,G,H
+#define LIST_7( A,B,C,D,E,F,G,...) A,B,C,D,E,F,G
+#define LIST_6( A,B,C,D,E,F,...) A,B,C,D,E,F
+#define LIST_5( A,B,C,D,E,...) A,B,C,D,E
+#define LIST_4( A,B,C,D,...) A,B,C,D
+#define LIST_3( A,B,C,...) A,B,C
+#define LIST_2( A,B,...) A,B
+#define LIST_1( A,...) A
+
+#define _LIST_N(N,V...) LIST_##N(V)
+#define LIST_N(N,V...) _LIST_N(N,V)
+#define ARRAY_N(N,V...) { _LIST_N(N,V) }
+
+#define _JOIN_1(O) (O)
+#define JOIN_N(N,C,V...) (DO(JOIN,C,LIST_N(N,V)))
+
+#define LOOP_S_LE_N(VAR, S, N) for (uint8_t VAR=(S); VAR<=(N); VAR++)
+#define LOOP_S_L_N(VAR, S, N) for (uint8_t VAR=(S); VAR<(N); VAR++)
+#define LOOP_LE_N(VAR, N) LOOP_S_LE_N(VAR, 0, N)
+#define LOOP_L_N(VAR, N) LOOP_S_L_N(VAR, 0, N)
+
+#define NOOP (void(0))
+
+#define CEILING(x,y) (((x) + (y) - 1) / (y))
+
+#undef ABS
+#ifdef __cplusplus
+ template <class T> static inline constexpr const T ABS(const T v) { return v >= 0 ? v : -v; }
+#else
+ #define ABS(a) ({__typeof__(a) _a = (a); _a >= 0 ? _a : -_a;})
+#endif
+
+#define UNEAR_ZERO(x) ((x) < 0.000001f)
+#define NEAR_ZERO(x) WITHIN(x, -0.000001f, 0.000001f)
+#define NEAR(x,y) NEAR_ZERO((x)-(y))
+
+#define RECIPROCAL(x) (NEAR_ZERO(x) ? 0 : (1 / float(x)))
+#define FIXFLOAT(f) ({__typeof__(f) _f = (f); _f + (_f < 0 ? -0.0000005f : 0.0000005f);})
+
+//
+// Maths macros that can be overridden by HAL
+//
+#define ACOS(x) acosf(x)
+#define ATAN2(y, x) atan2f(y, x)
+#define POW(x, y) powf(x, y)
+#define SQRT(x) sqrtf(x)
+#define RSQRT(x) (1.0f / sqrtf(x))
+#define CEIL(x) ceilf(x)
+#define FLOOR(x) floorf(x)
+#define TRUNC(x) truncf(x)
+#define LROUND(x) lroundf(x)
+#define FMOD(x, y) fmodf(x, y)
+#define HYPOT(x,y) SQRT(HYPOT2(x,y))
+
+// Use NUM_ARGS(__VA_ARGS__) to get the number of variadic arguments
+#define _NUM_ARGS(_,Z,Y,X,W,V,U,T,S,R,Q,P,O,N,M,L,K,J,I,H,G,F,E,D,C,B,A,OUT,...) OUT
+#define NUM_ARGS(V...) _NUM_ARGS(0,V,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)
+
+#ifdef __cplusplus
+
+ #ifndef _MINMAX_H_
+ #define _MINMAX_H_
+
+ extern "C++" {
+
+ // C++11 solution that is standards compliant. Return type is deduced automatically
+ template <class L, class R> static inline constexpr auto _MIN(const L lhs, const R rhs) -> decltype(lhs + rhs) {
+ return lhs < rhs ? lhs : rhs;
+ }
+ template <class L, class R> static inline constexpr auto _MAX(const L lhs, const R rhs) -> decltype(lhs + rhs) {
+ return lhs > rhs ? lhs : rhs;
+ }
+ template<class T, class ... Ts> static inline constexpr const T _MIN(T V, Ts... Vs) { return _MIN(V, _MIN(Vs...)); }
+ template<class T, class ... Ts> static inline constexpr const T _MAX(T V, Ts... Vs) { return _MAX(V, _MAX(Vs...)); }
+
+ }
+
+ #endif
+
+ // C++11 solution that is standard compliant. <type_traits> is not available on all platform
+ namespace Private {
+ template<bool, typename _Tp = void> struct enable_if { };
+ template<typename _Tp> struct enable_if<true, _Tp> { 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<Type> structure containing 'value' set to true if the member exists
+ #define HAS_MEMBER_IMPL(Member) \
+ namespace Private { \
+ template <typename Type, typename Yes=char, typename No=long> struct HasMember_ ## Member { \
+ template <typename C> static Yes& test( decltype(&C::Member) ) ; \
+ template <typename C> static No& test(...); \
+ enum { value = sizeof(test<Type>(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 <typename T, typename ... Args> FORCE_INLINE typename enable_if<HasMember_ ## Method <T>::value, Return>::type Call_ ## Method(T * t, Args... a) { return static_cast<Return>(t->Method(a...)); } \
+ _UNUSED static Return Call_ ## Method(...) { return __VA_ARGS__; } \
+ }
+ #define CALL_IF_EXISTS(Return, That, Method, ...) \
+ static_cast<Return>(Private::Call_ ## Method(That, ##__VA_ARGS__))
+
+#else
+
+ #define MIN_2(a,b) ((a)<(b)?(a):(b))
+ #define MIN_3(a,V...) MIN_2(a,MIN_2(V))
+ #define MIN_4(a,V...) MIN_2(a,MIN_3(V))
+ #define MIN_5(a,V...) MIN_2(a,MIN_4(V))
+ #define MIN_6(a,V...) MIN_2(a,MIN_5(V))
+ #define MIN_7(a,V...) MIN_2(a,MIN_6(V))
+ #define MIN_8(a,V...) MIN_2(a,MIN_7(V))
+ #define MIN_9(a,V...) MIN_2(a,MIN_8(V))
+ #define MIN_10(a,V...) MIN_2(a,MIN_9(V))
+ #define __MIN_N(N,V...) MIN_##N(V)
+ #define _MIN_N(N,V...) __MIN_N(N,V)
+ #define _MIN(V...) _MIN_N(NUM_ARGS(V), V)
+
+ #define MAX_2(a,b) ((a)>(b)?(a):(b))
+ #define MAX_3(a,V...) MAX_2(a,MAX_2(V))
+ #define MAX_4(a,V...) MAX_2(a,MAX_3(V))
+ #define MAX_5(a,V...) MAX_2(a,MAX_4(V))
+ #define MAX_6(a,V...) MAX_2(a,MAX_5(V))
+ #define MAX_7(a,V...) MAX_2(a,MAX_6(V))
+ #define MAX_8(a,V...) MAX_2(a,MAX_7(V))
+ #define MAX_9(a,V...) MAX_2(a,MAX_8(V))
+ #define MAX_10(a,V...) MAX_2(a,MAX_9(V))
+ #define __MAX_N(N,V...) MAX_##N(V)
+ #define _MAX_N(N,V...) __MAX_N(N,V)
+ #define _MAX(V...) _MAX_N(NUM_ARGS(V), V)
+
+#endif
+
+// Macros for adding
+#define INC_0 1
+#define INC_1 2
+#define INC_2 3
+#define INC_3 4
+#define INC_4 5
+#define INC_5 6
+#define INC_6 7
+#define INC_7 8
+#define INC_8 9
+#define INC_9 10
+#define INC_10 11
+#define INC_11 12
+#define INC_12 13
+#define INC_13 14
+#define INC_14 15
+#define INC_15 16
+#define INCREMENT_(n) INC_##n
+#define INCREMENT(n) INCREMENT_(n)
+
+#define ADD0(N) N
+#define ADD1(N) INCREMENT_(N)
+#define ADD2(N) ADD1(ADD1(N))
+#define ADD3(N) ADD1(ADD2(N))
+#define ADD4(N) ADD2(ADD2(N))
+#define ADD5(N) ADD2(ADD3(N))
+#define ADD6(N) ADD3(ADD3(N))
+#define ADD7(N) ADD3(ADD4(N))
+#define ADD8(N) ADD4(ADD4(N))
+#define ADD9(N) ADD4(ADD5(N))
+#define ADD10(N) ADD5(ADD5(N))
+
+// Macros for subtracting
+#define DEC_0 0
+#define DEC_1 0
+#define DEC_2 1
+#define DEC_3 2
+#define DEC_4 3
+#define DEC_5 4
+#define DEC_6 5
+#define DEC_7 6
+#define DEC_8 7
+#define DEC_9 8
+#define DEC_10 9
+#define DEC_11 10
+#define DEC_12 11
+#define DEC_13 12
+#define DEC_14 13
+#define DEC_15 14
+#define DECREMENT_(n) DEC_##n
+#define DECREMENT(n) DECREMENT_(n)
+
+#define SUB0(N) N
+#define SUB1(N) DECREMENT_(N)
+#define SUB2(N) SUB1(SUB1(N))
+#define SUB3(N) SUB1(SUB2(N))
+#define SUB4(N) SUB2(SUB2(N))
+#define SUB5(N) SUB2(SUB3(N))
+#define SUB6(N) SUB3(SUB3(N))
+#define SUB7(N) SUB3(SUB4(N))
+#define SUB8(N) SUB4(SUB4(N))
+#define SUB9(N) SUB4(SUB5(N))
+#define SUB10(N) SUB5(SUB5(N))
+
+//
+// Primitives supporting precompiler REPEAT
+//
+#define FIRST(a,...) a
+#define SECOND(a,b,...) b
+#define THIRD(a,b,c,...) c
+
+// Defer expansion
+#define EMPTY()
+#define DEFER(M) M EMPTY()
+#define DEFER2(M) M EMPTY EMPTY()()
+#define DEFER3(M) M EMPTY EMPTY EMPTY()()()
+#define DEFER4(M) M EMPTY EMPTY EMPTY EMPTY()()()()
+
+// Force define expansion
+#define EVAL(V...) EVAL16(V)
+#define EVAL1024(V...) EVAL512(EVAL512(V))
+#define EVAL512(V...) EVAL256(EVAL256(V))
+#define EVAL256(V...) EVAL128(EVAL128(V))
+#define EVAL128(V...) EVAL64(EVAL64(V))
+#define EVAL64(V...) EVAL32(EVAL32(V))
+#define EVAL32(V...) EVAL16(EVAL16(V))
+#define EVAL16(V...) EVAL8(EVAL8(V))
+#define EVAL8(V...) EVAL4(EVAL4(V))
+#define EVAL4(V...) EVAL2(EVAL2(V))
+#define EVAL2(V...) EVAL1(EVAL1(V))
+#define EVAL1(V...) V
+
+#define IS_PROBE(V...) SECOND(V, 0) // Get the second item passed, or 0
+#define PROBE() ~, 1 // Second item will be 1 if this is passed
+#define _NOT_0 PROBE()
+#define NOT(x) IS_PROBE(_CAT(_NOT_, x)) // NOT('0') gets '1'. Anything else gets '0'.
+#define _BOOL(x) NOT(NOT(x)) // NOT('0') gets '0'. Anything else gets '1'.
+
+#define IF_ELSE(TF) _IF_ELSE(_BOOL(TF))
+#define _IF_ELSE(TF) _CAT(_IF_, TF)
+
+#define _IF_1(V...) V _IF_1_ELSE
+#define _IF_0(...) _IF_0_ELSE
+
+#define _IF_1_ELSE(...)
+#define _IF_0_ELSE(V...) V
+
+#define HAS_ARGS(V...) _BOOL(FIRST(_END_OF_ARGUMENTS_ V)())
+#define _END_OF_ARGUMENTS_() 0
+
+
+// Simple Inline IF Macros, friendly to use in other macro definitions
+#define IF(O, A, B) ((O) ? (A) : (B))
+#define IF_0(O, A) IF(O, A, 0)
+#define IF_1(O, A) IF(O, A, 1)
+
+//
+// REPEAT core macros. Recurse N times with ascending I.
+//
+
+// Call OP(I) N times with ascending counter.
+#define _REPEAT(_RPT_I,_RPT_N,_RPT_OP) \
+ _RPT_OP(_RPT_I) \
+ IF_ELSE(SUB1(_RPT_N)) \
+ ( DEFER2(__REPEAT)()(ADD1(_RPT_I),SUB1(_RPT_N),_RPT_OP) ) \
+ ( /* Do nothing */ )
+#define __REPEAT() _REPEAT
+
+// Call OP(I, ...) N times with ascending counter.
+#define _REPEAT2(_RPT_I,_RPT_N,_RPT_OP,V...) \
+ _RPT_OP(_RPT_I,V) \
+ IF_ELSE(SUB1(_RPT_N)) \
+ ( DEFER2(__REPEAT2)()(ADD1(_RPT_I),SUB1(_RPT_N),_RPT_OP,V) ) \
+ ( /* Do nothing */ )
+#define __REPEAT2() _REPEAT2
+
+// Repeat a macro passing S...N-1.
+#define REPEAT_S(S,N,OP) EVAL(_REPEAT(S,SUB##S(N),OP))
+#define REPEAT(N,OP) REPEAT_S(0,N,OP)
+
+// Repeat a macro passing 0...N-1 plus additional arguments.
+#define REPEAT2_S(S,N,OP,V...) EVAL(_REPEAT2(S,SUB##S(N),OP,V))
+#define REPEAT2(N,OP,V...) REPEAT2_S(0,N,OP,V)
+
+// Use RREPEAT macros with REPEAT macros for nesting
+#define _RREPEAT(_RPT_I,_RPT_N,_RPT_OP) \
+ _RPT_OP(_RPT_I) \
+ IF_ELSE(SUB1(_RPT_N)) \
+ ( DEFER2(__RREPEAT)()(ADD1(_RPT_I),SUB1(_RPT_N),_RPT_OP) ) \
+ ( /* Do nothing */ )
+#define __RREPEAT() _RREPEAT
+#define _RREPEAT2(_RPT_I,_RPT_N,_RPT_OP,V...) \
+ _RPT_OP(_RPT_I,V) \
+ IF_ELSE(SUB1(_RPT_N)) \
+ ( DEFER2(__RREPEAT2)()(ADD1(_RPT_I),SUB1(_RPT_N),_RPT_OP,V) ) \
+ ( /* Do nothing */ )
+#define __RREPEAT2() _RREPEAT2
+#define RREPEAT_S(S,N,OP) EVAL1024(_RREPEAT(S,SUB##S(N),OP))
+#define RREPEAT(N,OP) RREPEAT_S(0,N,OP)
+#define RREPEAT2_S(S,N,OP,V...) EVAL1024(_RREPEAT2(S,SUB##S(N),OP,V))
+#define RREPEAT2(N,OP,V...) RREPEAT2_S(0,N,OP,V)
+
+// See https://github.com/swansontec/map-macro
+#define MAP_OUT
+#define MAP_END(...)
+#define MAP_GET_END() 0, MAP_END
+#define MAP_NEXT0(test, next, ...) next MAP_OUT
+#define MAP_NEXT1(test, next) MAP_NEXT0 (test, next, 0)
+#define MAP_NEXT(test, next) MAP_NEXT1 (MAP_GET_END test, next)
+#define MAP0(f, x, peek, ...) f(x) MAP_NEXT (peek, MAP1) (f, peek, __VA_ARGS__)
+#define MAP1(f, x, peek, ...) f(x) MAP_NEXT (peek, MAP0) (f, peek, __VA_ARGS__)
+#define MAP(f, ...) EVAL512 (MAP1 (f, __VA_ARGS__, (), 0))
diff --git a/Marlin/src/core/millis_t.h b/Marlin/src/core/millis_t.h
new file mode 100644
index 0000000..95bc40e
--- /dev/null
+++ b/Marlin/src/core/millis_t.h
@@ -0,0 +1,33 @@
+/**
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include <stdint.h>
+
+typedef uint32_t millis_t;
+
+#define SEC_TO_MS(N) millis_t((N)*1000UL)
+#define MIN_TO_MS(N) SEC_TO_MS((N)*60UL)
+#define MS_TO_SEC(N) millis_t((N)/1000UL)
+
+#define PENDING(NOW,SOON) ((int32_t)(NOW-(SOON))<0)
+#define ELAPSED(NOW,SOON) (!PENDING(NOW,SOON))
diff --git a/Marlin/src/core/multi_language.h b/Marlin/src/core/multi_language.h
new file mode 100644
index 0000000..5a26edf
--- /dev/null
+++ b/Marlin/src/core/multi_language.h
@@ -0,0 +1,86 @@
+/********************
+ * multi_language.h *
+ ********************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2019 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+#pragma once
+
+#include "../inc/MarlinConfigPre.h"
+
+typedef const char Language_Str[];
+
+#ifdef LCD_LANGUAGE_5
+ #define NUM_LANGUAGES 5
+#elif defined(LCD_LANGUAGE_4)
+ #define NUM_LANGUAGES 4
+#elif defined(LCD_LANGUAGE_3)
+ #define NUM_LANGUAGES 3
+#elif defined(LCD_LANGUAGE_2)
+ #define NUM_LANGUAGES 2
+#else
+ #define NUM_LANGUAGES 1
+#endif
+
+// Setting the unused languages equal to each other allows
+// the compiler to optimize away the conditionals
+
+#ifndef LCD_LANGUAGE_2
+ #define LCD_LANGUAGE_2 LCD_LANGUAGE
+#endif
+
+#ifndef LCD_LANGUAGE_3
+ #define LCD_LANGUAGE_3 LCD_LANGUAGE_2
+#endif
+
+#ifndef LCD_LANGUAGE_4
+ #define LCD_LANGUAGE_4 LCD_LANGUAGE_3
+#endif
+
+#ifndef LCD_LANGUAGE_5
+ #define LCD_LANGUAGE_5 LCD_LANGUAGE_4
+#endif
+
+#define _GET_LANG(LANG) Language_##LANG
+#define GET_LANG(LANG) _GET_LANG(LANG)
+
+#if NUM_LANGUAGES > 1
+ #define HAS_MULTI_LANGUAGE 1
+ #define GET_TEXT(MSG) ( \
+ 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 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"
+#define MSG_3_LINE(A,B,C) A "\0" B "\0" C
diff --git a/Marlin/src/core/serial.cpp b/Marlin/src/core/serial.cpp
new file mode 100644
index 0000000..365f28b
--- /dev/null
+++ b/Marlin/src/core/serial.cpp
@@ -0,0 +1,93 @@
+/**
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "serial.h"
+#include "../inc/MarlinConfig.h"
+
+#if HAS_ETHERNET
+ #include "../feature/ethernet.h"
+#endif
+
+uint8_t marlin_debug_flags = MARLIN_DEBUG_NONE;
+
+// 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
+ #ifdef SERIAL_CATCHALL
+ SerialOutputT multiSerial(MYSERIAL, SERIAL_CATCHALL);
+ #else
+ #if HAS_ETHERNET
+ // Runtime checking of the condition variable
+ ConditionalSerial<decltype(MYSERIAL1)> 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() { 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); }
+void serial_echopair_PGM(PGM_P const s_P, int v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
+void serial_echopair_PGM(PGM_P const s_P, long v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
+void serial_echopair_PGM(PGM_P const s_P, float v) { serialprintPGM(s_P); SERIAL_DECIMAL(v); }
+void serial_echopair_PGM(PGM_P const s_P, double v) { serialprintPGM(s_P); SERIAL_DECIMAL(v); }
+void serial_echopair_PGM(PGM_P const s_P, unsigned int v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
+void serial_echopair_PGM(PGM_P const s_P, unsigned long v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
+
+void serial_spaces(uint8_t count) { count *= (PROPORTIONAL_FONT_RATIO); while (count--) SERIAL_CHAR(' '); }
+
+void serial_ternary(const bool onoff, PGM_P const pre, PGM_P const on, PGM_P const off, PGM_P const post/*=nullptr*/) {
+ if (pre) serialprintPGM(pre);
+ serialprintPGM(onoff ? on : off);
+ if (post) serialprintPGM(post);
+}
+void serialprint_onoff(const bool onoff) { serialprintPGM(onoff ? PSTR(STR_ON) : PSTR(STR_OFF)); }
+void serialprintln_onoff(const bool onoff) { serialprint_onoff(onoff); SERIAL_EOL(); }
+void serialprint_truefalse(const bool tf) { serialprintPGM(tf ? PSTR("true") : PSTR("false")); }
+
+void print_bin(uint16_t val) {
+ for (uint8_t i = 16; i--;) {
+ SERIAL_CHAR('0' + TEST(val, i));
+ if (!(i & 0x3) && i) SERIAL_CHAR(' ');
+ }
+}
+
+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);
+ if (suffix) serialprintPGM(suffix); else SERIAL_EOL();
+}
diff --git a/Marlin/src/core/serial.h b/Marlin/src/core/serial.h
new file mode 100644
index 0000000..4c0c32f
--- /dev/null
+++ b/Marlin/src/core/serial.h
@@ -0,0 +1,335 @@
+/**
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "../inc/MarlinConfig.h"
+#include "serial_hook.h"
+
+// 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[];
+
+//
+// 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
+ MARLIN_DEBUG_INFO = _BV(1), ///< Print messages for code that has debug output
+ MARLIN_DEBUG_ERRORS = _BV(2), ///< Not implemented
+ MARLIN_DEBUG_DRYRUN = _BV(3), ///< Ignore temperature setting and E movement commands
+ MARLIN_DEBUG_COMMUNICATION = _BV(4), ///< Not implemented
+ #if ENABLED(DEBUG_LEVELING_FEATURE)
+ MARLIN_DEBUG_LEVELING = _BV(5), ///< Print detailed output for homing and leveling
+ MARLIN_DEBUG_MESH_ADJUST = _BV(6), ///< UBL bed leveling
+ #else
+ MARLIN_DEBUG_LEVELING = 0,
+ MARLIN_DEBUG_MESH_ADJUST = 0,
+ #endif
+ MARLIN_DEBUG_ALL = 0xFF
+};
+
+extern uint8_t marlin_debug_flags;
+#define DEBUGGING(F) (marlin_debug_flags & (MARLIN_DEBUG_## F))
+
+//
+// Serial redirection
+//
+typedef int8_t serial_index_t;
+#define SERIAL_ALL 0x7F
+#if HAS_MULTI_SERIAL
+ #define _PORT_REDIRECT(n,p) REMEMBER(n,multiSerial.portMask,p)
+ #define SERIAL_ASSERT(P) if(multiSerial.portMask!=(P)){ debugger(); }
+ #ifdef SERIAL_CATCHALL
+ typedef MultiSerial<decltype(MYSERIAL), decltype(SERIAL_CATCHALL), 0> SerialOutputT;
+ #else
+ typedef MultiSerial<decltype(MYSERIAL0), TERN(HAS_ETHERNET, ConditionalSerial<decltype(MYSERIAL1)>, decltype(MYSERIAL1)), 0> SerialOutputT;
+ #endif
+ extern SerialOutputT multiSerial;
+ #define SERIAL_IMPL multiSerial
+#else
+ #define _PORT_REDIRECT(n,p) NOOP
+ #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 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_FLUSH() SERIAL_OUT(flush)
+
+#ifdef ARDUINO_ARCH_STM32
+ #define SERIAL_FLUSHTX() SERIAL_OUT(flush)
+#elif TX_BUFFER_SIZE > 0
+ #define SERIAL_FLUSHTX() SERIAL_OUT(flushTX)
+#else
+ #define SERIAL_FLUSHTX()
+#endif
+
+// Print up to 10 chars from a list
+#define __CHAR_N(N,V...) _CHAR_##N(V)
+#define _CHAR_N(N,V...) __CHAR_N(N,V)
+#define _CHAR_1(c) SERIAL_OUT(write, c)
+#define _CHAR_2(a,b) do{ _CHAR_1(a); _CHAR_1(b); }while(0)
+#define _CHAR_3(a,V...) do{ _CHAR_1(a); _CHAR_2(V); }while(0)
+#define _CHAR_4(a,V...) do{ _CHAR_1(a); _CHAR_3(V); }while(0)
+#define _CHAR_5(a,V...) do{ _CHAR_1(a); _CHAR_4(V); }while(0)
+#define _CHAR_6(a,V...) do{ _CHAR_1(a); _CHAR_5(V); }while(0)
+#define _CHAR_7(a,V...) do{ _CHAR_1(a); _CHAR_6(V); }while(0)
+#define _CHAR_8(a,V...) do{ _CHAR_1(a); _CHAR_7(V); }while(0)
+#define _CHAR_9(a,V...) do{ _CHAR_1(a); _CHAR_8(V); }while(0)
+#define _CHAR_10(a,V...) do{ _CHAR_1(a); _CHAR_9(V); }while(0)
+
+#define SERIAL_CHAR(V...) _CHAR_N(NUM_ARGS(V),V)
+
+// Print up to 12 pairs of values. Odd elements auto-wrapped in PSTR().
+#define __SEP_N(N,V...) _SEP_##N(V)
+#define _SEP_N(N,V...) __SEP_N(N,V)
+#define _SEP_1(PRE) SERIAL_ECHOPGM(PRE)
+#define _SEP_2(PRE,V) serial_echopair_PGM(PSTR(PRE),V)
+#define _SEP_3(a,b,c) do{ _SEP_2(a,b); SERIAL_ECHOPGM(c); }while(0)
+#define _SEP_4(a,b,V...) do{ _SEP_2(a,b); _SEP_2(V); }while(0)
+#define _SEP_5(a,b,V...) do{ _SEP_2(a,b); _SEP_3(V); }while(0)
+#define _SEP_6(a,b,V...) do{ _SEP_2(a,b); _SEP_4(V); }while(0)
+#define _SEP_7(a,b,V...) do{ _SEP_2(a,b); _SEP_5(V); }while(0)
+#define _SEP_8(a,b,V...) do{ _SEP_2(a,b); _SEP_6(V); }while(0)
+#define _SEP_9(a,b,V...) do{ _SEP_2(a,b); _SEP_7(V); }while(0)
+#define _SEP_10(a,b,V...) do{ _SEP_2(a,b); _SEP_8(V); }while(0)
+#define _SEP_11(a,b,V...) do{ _SEP_2(a,b); _SEP_9(V); }while(0)
+#define _SEP_12(a,b,V...) do{ _SEP_2(a,b); _SEP_10(V); }while(0)
+#define _SEP_13(a,b,V...) do{ _SEP_2(a,b); _SEP_11(V); }while(0)
+#define _SEP_14(a,b,V...) do{ _SEP_2(a,b); _SEP_12(V); }while(0)
+#define _SEP_15(a,b,V...) do{ _SEP_2(a,b); _SEP_13(V); }while(0)
+#define _SEP_16(a,b,V...) do{ _SEP_2(a,b); _SEP_14(V); }while(0)
+#define _SEP_17(a,b,V...) do{ _SEP_2(a,b); _SEP_15(V); }while(0)
+#define _SEP_18(a,b,V...) do{ _SEP_2(a,b); _SEP_16(V); }while(0)
+#define _SEP_19(a,b,V...) do{ _SEP_2(a,b); _SEP_17(V); }while(0)
+#define _SEP_20(a,b,V...) do{ _SEP_2(a,b); _SEP_18(V); }while(0)
+#define _SEP_21(a,b,V...) do{ _SEP_2(a,b); _SEP_19(V); }while(0)
+#define _SEP_22(a,b,V...) do{ _SEP_2(a,b); _SEP_20(V); }while(0)
+#define _SEP_23(a,b,V...) do{ _SEP_2(a,b); _SEP_21(V); }while(0)
+#define _SEP_24(a,b,V...) do{ _SEP_2(a,b); _SEP_22(V); }while(0)
+
+#define SERIAL_ECHOPAIR(V...) _SEP_N(NUM_ARGS(V),V)
+
+// Print up to 12 pairs of values. Odd elements must be PSTR pointers.
+#define __SEP_N_P(N,V...) _SEP_##N##_P(V)
+#define _SEP_N_P(N,V...) __SEP_N_P(N,V)
+#define _SEP_1_P(PRE) serialprintPGM(PRE)
+#define _SEP_2_P(PRE,V) serial_echopair_PGM(PRE,V)
+#define _SEP_3_P(a,b,c) do{ _SEP_2_P(a,b); serialprintPGM(c); }while(0)
+#define _SEP_4_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_2_P(V); }while(0)
+#define _SEP_5_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_3_P(V); }while(0)
+#define _SEP_6_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_4_P(V); }while(0)
+#define _SEP_7_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_5_P(V); }while(0)
+#define _SEP_8_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_6_P(V); }while(0)
+#define _SEP_9_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_7_P(V); }while(0)
+#define _SEP_10_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_8_P(V); }while(0)
+#define _SEP_11_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_9_P(V); }while(0)
+#define _SEP_12_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_10_P(V); }while(0)
+#define _SEP_13_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_11_P(V); }while(0)
+#define _SEP_14_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_12_P(V); }while(0)
+#define _SEP_15_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_13_P(V); }while(0)
+#define _SEP_16_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_14_P(V); }while(0)
+#define _SEP_17_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_15_P(V); }while(0)
+#define _SEP_18_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_16_P(V); }while(0)
+#define _SEP_19_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_17_P(V); }while(0)
+#define _SEP_20_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_18_P(V); }while(0)
+#define _SEP_21_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_19_P(V); }while(0)
+#define _SEP_22_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_20_P(V); }while(0)
+#define _SEP_23_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_21_P(V); }while(0)
+#define _SEP_24_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_22_P(V); }while(0)
+
+#define SERIAL_ECHOPAIR_P(V...) _SEP_N_P(NUM_ARGS(V),V)
+
+// Print up to 12 pairs of values followed by newline
+#define __SELP_N(N,V...) _SELP_##N(V)
+#define _SELP_N(N,V...) __SELP_N(N,V)
+#define _SELP_1(PRE) SERIAL_ECHOLNPGM(PRE)
+#define _SELP_2(PRE,V) do{ serial_echopair_PGM(PSTR(PRE),V); SERIAL_EOL(); }while(0)
+#define _SELP_3(a,b,c) do{ _SEP_2(a,b); SERIAL_ECHOLNPGM(c); }while(0)
+#define _SELP_4(a,b,V...) do{ _SEP_2(a,b); _SELP_2(V); }while(0)
+#define _SELP_5(a,b,V...) do{ _SEP_2(a,b); _SELP_3(V); }while(0)
+#define _SELP_6(a,b,V...) do{ _SEP_2(a,b); _SELP_4(V); }while(0)
+#define _SELP_7(a,b,V...) do{ _SEP_2(a,b); _SELP_5(V); }while(0)
+#define _SELP_8(a,b,V...) do{ _SEP_2(a,b); _SELP_6(V); }while(0)
+#define _SELP_9(a,b,V...) do{ _SEP_2(a,b); _SELP_7(V); }while(0)
+#define _SELP_10(a,b,V...) do{ _SEP_2(a,b); _SELP_8(V); }while(0)
+#define _SELP_11(a,b,V...) do{ _SEP_2(a,b); _SELP_9(V); }while(0)
+#define _SELP_12(a,b,V...) do{ _SEP_2(a,b); _SELP_10(V); }while(0)
+#define _SELP_13(a,b,V...) do{ _SEP_2(a,b); _SELP_11(V); }while(0)
+#define _SELP_14(a,b,V...) do{ _SEP_2(a,b); _SELP_12(V); }while(0)
+#define _SELP_15(a,b,V...) do{ _SEP_2(a,b); _SELP_13(V); }while(0)
+#define _SELP_16(a,b,V...) do{ _SEP_2(a,b); _SELP_14(V); }while(0)
+#define _SELP_17(a,b,V...) do{ _SEP_2(a,b); _SELP_15(V); }while(0)
+#define _SELP_18(a,b,V...) do{ _SEP_2(a,b); _SELP_16(V); }while(0)
+#define _SELP_19(a,b,V...) do{ _SEP_2(a,b); _SELP_17(V); }while(0)
+#define _SELP_20(a,b,V...) do{ _SEP_2(a,b); _SELP_18(V); }while(0)
+#define _SELP_21(a,b,V...) do{ _SEP_2(a,b); _SELP_19(V); }while(0)
+#define _SELP_22(a,b,V...) do{ _SEP_2(a,b); _SELP_20(V); }while(0)
+#define _SELP_23(a,b,V...) do{ _SEP_2(a,b); _SELP_21(V); }while(0)
+#define _SELP_24(a,b,V...) do{ _SEP_2(a,b); _SELP_22(V); }while(0)
+#define _SELP_25(a,b,V...) do{ _SEP_2(a,b); _SELP_23(V); }while(0)
+#define _SELP_26(a,b,V...) do{ _SEP_2(a,b); _SELP_24(V); }while(0)
+#define _SELP_27(a,b,V...) do{ _SEP_2(a,b); _SELP_25(V); }while(0)
+#define _SELP_28(a,b,V...) do{ _SEP_2(a,b); _SELP_26(V); }while(0)
+#define _SELP_29(a,b,V...) do{ _SEP_2(a,b); _SELP_27(V); }while(0)
+#define _SELP_30(a,b,V...) do{ _SEP_2(a,b); _SELP_28(V); }while(0) // Eat two args, pass the rest up
+
+#define SERIAL_ECHOLNPAIR(V...) _SELP_N(NUM_ARGS(V),V)
+
+// Print up to 12 pairs of values followed by newline
+#define __SELP_N_P(N,V...) _SELP_##N##_P(V)
+#define _SELP_N_P(N,V...) __SELP_N_P(N,V)
+#define _SELP_1_P(PRE) serialprintPGM(PRE)
+#define _SELP_2_P(PRE,V) do{ serial_echopair_PGM(PRE,V); SERIAL_EOL(); }while(0)
+#define _SELP_3_P(a,b,c) do{ _SEP_2_P(a,b); serialprintPGM(c); }while(0)
+#define _SELP_4_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_2_P(V); }while(0)
+#define _SELP_5_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_3_P(V); }while(0)
+#define _SELP_6_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_4_P(V); }while(0)
+#define _SELP_7_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_5_P(V); }while(0)
+#define _SELP_8_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_6_P(V); }while(0)
+#define _SELP_9_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_7_P(V); }while(0)
+#define _SELP_10_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_8_P(V); }while(0)
+#define _SELP_11_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_9_P(V); }while(0)
+#define _SELP_12_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_10_P(V); }while(0)
+#define _SELP_13_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_11_P(V); }while(0)
+#define _SELP_14_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_12_P(V); }while(0)
+#define _SELP_15_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_13_P(V); }while(0)
+#define _SELP_16_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_14_P(V); }while(0)
+#define _SELP_17_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_15_P(V); }while(0)
+#define _SELP_18_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_16_P(V); }while(0)
+#define _SELP_19_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_17_P(V); }while(0)
+#define _SELP_20_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_18_P(V); }while(0)
+#define _SELP_21_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_19_P(V); }while(0)
+#define _SELP_22_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_20_P(V); }while(0)
+#define _SELP_23_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_21_P(V); }while(0)
+#define _SELP_24_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_22_P(V); }while(0)
+#define _SELP_25_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_23_P(V); }while(0)
+#define _SELP_26_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_24_P(V); }while(0)
+#define _SELP_27_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_25_P(V); }while(0)
+#define _SELP_28_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_26_P(V); }while(0)
+#define _SELP_29_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_27_P(V); }while(0)
+#define _SELP_30_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_28_P(V); }while(0) // Eat two args, pass the rest up
+
+#define SERIAL_ECHOLNPAIR_P(V...) _SELP_N_P(NUM_ARGS(V),V)
+
+// Print up to 20 comma-separated pairs of values
+#define __SLST_N(N,V...) _SLST_##N(V)
+#define _SLST_N(N,V...) __SLST_N(N,V)
+#define _SLST_1(a) SERIAL_ECHO(a)
+#define _SLST_2(a,b) do{ SERIAL_ECHO(a); SERIAL_ECHOPAIR(", ",b); }while(0)
+#define _SLST_3(a,b,c) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_1(c); }while(0)
+#define _SLST_4(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_2(V); }while(0)
+#define _SLST_5(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_3(V); }while(0)
+#define _SLST_6(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_4(V); }while(0)
+#define _SLST_7(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_5(V); }while(0)
+#define _SLST_8(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_6(V); }while(0)
+#define _SLST_9(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_7(V); }while(0)
+#define _SLST_10(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_8(V); }while(0)
+#define _SLST_11(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_9(V); }while(0)
+#define _SLST_12(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_10(V); }while(0)
+#define _SLST_13(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_11(V); }while(0)
+#define _SLST_14(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_12(V); }while(0)
+#define _SLST_15(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_13(V); }while(0)
+#define _SLST_16(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_14(V); }while(0)
+#define _SLST_17(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_15(V); }while(0)
+#define _SLST_18(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_16(V); }while(0)
+#define _SLST_19(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_17(V); }while(0)
+#define _SLST_20(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_18(V); }while(0) // Eat two args, pass the rest up
+
+#define SERIAL_ECHOLIST(pre,V...) do{ SERIAL_ECHOPGM(pre); _SLST_N(NUM_ARGS(V),V); }while(0)
+#define SERIAL_ECHOLIST_N(N,V...) _SLST_N(N,LIST_N(N,V))
+
+#define SERIAL_ECHOPGM_P(P) (serialprintPGM(P))
+#define SERIAL_ECHOLNPGM_P(P) (serialprintPGM(P "\n"))
+
+#define SERIAL_ECHOPGM(S) (serialprintPGM(PSTR(S)))
+#define SERIAL_ECHOLNPGM(S) (serialprintPGM(PSTR(S "\n")))
+
+#define SERIAL_ECHOPAIR_F_P(P,V...) do{ serialprintPGM(P); SERIAL_ECHO_F(V); }while(0)
+#define SERIAL_ECHOLNPAIR_F_P(V...) do{ SERIAL_ECHOPAIR_F_P(V); SERIAL_EOL(); }while(0)
+
+#define SERIAL_ECHOPAIR_F(S,V...) SERIAL_ECHOPAIR_F_P(PSTR(S),V)
+#define SERIAL_ECHOLNPAIR_F(V...) do{ SERIAL_ECHOPAIR_F(V); SERIAL_EOL(); }while(0)
+
+#define SERIAL_ECHO_START() serial_echo_start()
+#define SERIAL_ERROR_START() serial_error_start()
+#define SERIAL_EOL() SERIAL_CHAR('\n')
+
+#define SERIAL_ECHO_MSG(V...) do{ SERIAL_ECHO_START(); SERIAL_ECHOLNPAIR(V); }while(0)
+#define SERIAL_ERROR_MSG(V...) do{ SERIAL_ERROR_START(); SERIAL_ECHOLNPAIR(V); }while(0)
+
+#define SERIAL_ECHO_SP(C) serial_spaces(C)
+
+#define SERIAL_ECHO_TERNARY(TF, PRE, ON, OFF, POST) serial_ternary(TF, PSTR(PRE), PSTR(ON), PSTR(OFF), PSTR(POST))
+
+#if SERIAL_FLOAT_PRECISION
+ #define SERIAL_DECIMAL(V) SERIAL_PRINT(V, SERIAL_FLOAT_PRECISION)
+#else
+ #define SERIAL_DECIMAL(V) SERIAL_ECHO(V)
+#endif
+
+//
+// Functions for serial printing from PROGMEM. (Saves loads of SRAM.)
+//
+void serial_echopair_PGM(PGM_P const s_P, const char *v);
+void serial_echopair_PGM(PGM_P const s_P, char v);
+void serial_echopair_PGM(PGM_P const s_P, int v);
+void serial_echopair_PGM(PGM_P const s_P, unsigned int v);
+void serial_echopair_PGM(PGM_P const s_P, long v);
+void serial_echopair_PGM(PGM_P const s_P, unsigned long v);
+void serial_echopair_PGM(PGM_P const s_P, float v);
+void serial_echopair_PGM(PGM_P const s_P, double v);
+inline void serial_echopair_PGM(PGM_P const s_P, uint8_t v) { serial_echopair_PGM(s_P, (int)v); }
+inline void serial_echopair_PGM(PGM_P const s_P, bool v) { serial_echopair_PGM(s_P, (int)v); }
+inline void serial_echopair_PGM(PGM_P const s_P, void *v) { serial_echopair_PGM(s_P, (uintptr_t)v); }
+
+void serialprintPGM(PGM_P str);
+void serial_echo_start();
+void serial_error_start();
+void serial_ternary(const bool onoff, PGM_P const pre, PGM_P const on, PGM_P const off, PGM_P const post=nullptr);
+void serialprint_onoff(const bool onoff);
+void serialprintln_onoff(const bool onoff);
+void serialprint_truefalse(const bool tf);
+void serial_spaces(uint8_t count);
+
+void print_bin(const uint16_t val);
+void print_xyz(const float &x, const float &y, const float &z, PGM_P const prefix=nullptr, PGM_P const suffix=nullptr);
+
+inline void print_xyz(const xyz_pos_t &xyz, PGM_P const prefix=nullptr, PGM_P const suffix=nullptr) {
+ print_xyz(xyz.x, xyz.y, xyz.z, prefix, suffix);
+}
+
+#define SERIAL_POS(SUFFIX,VAR) do { print_xyz(VAR, PSTR(" " STRINGIFY(VAR) "="), PSTR(" : " SUFFIX "\n")); }while(0)
+#define SERIAL_XYZ(PREFIX,V...) do { print_xyz(V, PSTR(PREFIX), nullptr); }while(0)
diff --git a/Marlin/src/core/serial_base.h b/Marlin/src/core/serial_base.h
new file mode 100644
index 0000000..f52fa11
--- /dev/null
+++ b/Marlin/src/core/serial_base.h
@@ -0,0 +1,159 @@
+/**
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#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 <class Child>
+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<Child*>(this)->write(c); }
+ // Called when the parser finished processing an instruction, usually build to nothing
+ void msgDone() { static_cast<Child*>(this)->msgDone(); }
+ // Called upon initialization
+ void begin(const long baudRate) { static_cast<Child*>(this)->begin(baudRate); }
+ // Called upon destruction
+ void end() { static_cast<Child*>(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<Child*>(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<Child*>(this)->read(index); }
+ // Check if the serial port is connected (usually bypassed)
+ bool connected() { return static_cast<Child*>(this)->connected(); }
+ // Redirect flush
+ void flush() { static_cast<Child*>(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<Child*>(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(unsigned long c, int base = DEC) { printNumber(c, base); }
+ void print(double c, int digits = 2) { printFloat(c, digits); }
+ void print(long c, int base = DEC) {
+ if (!base) {
+ write(c);
+ return;
+ }
+ if (base == DEC && c < 0) {
+ write((uint8_t)'-'); c = -c;
+ }
+ printNumber(c, base);
+ }
+
+ 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 (!base) {
+ write((uint8_t)n);
+ return;
+ }
+ 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 0000000..45e64d7
--- /dev/null
+++ b/Marlin/src/core/serial_hook.h
@@ -0,0 +1,235 @@
+/**
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#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 <class SerialT>
+struct BaseSerial : public SerialBase< BaseSerial<SerialT> >, public SerialT {
+ typedef SerialBase< BaseSerial<SerialT> > 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<SerialT*>(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 <typename... Args>
+ 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 <class SerialT>
+struct ConditionalSerial : public SerialBase< ConditionalSerial<SerialT> > {
+ typedef SerialBase< ConditionalSerial<SerialT> > 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 <class SerialT>
+struct ForwardSerial : public SerialBase< ForwardSerial<SerialT> > {
+ typedef SerialBase< ForwardSerial<SerialT> > 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<SerialT>::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 <class SerialT>
+struct RuntimeSerial : public SerialBase< RuntimeSerial<SerialT> >, public SerialT {
+ typedef SerialBase< RuntimeSerial<SerialT> > 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<SerialT>::value ? CALL_IF_EXISTS(bool, static_cast<SerialT*>(this), connected) : static_cast<SerialT*>(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 <typename... Args>
+ RuntimeSerial(const bool e, Args... args) : BaseClassT(e), SerialT(args...) {}
+};
+
+// A class that's duplicating its output conditionally to 2 serial interface
+template <class Serial0T, class Serial1T, const uint8_t offset = 0>
+struct MultiSerial : public SerialBase< MultiSerial<Serial0T, Serial1T, offset> > {
+ typedef SerialBase< MultiSerial<Serial0T, Serial1T, offset> > 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/core/types.h b/Marlin/src/core/types.h
new file mode 100644
index 0000000..20519e1
--- /dev/null
+++ b/Marlin/src/core/types.h
@@ -0,0 +1,503 @@
+/**
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include <math.h>
+#include <stddef.h>
+
+#include "../inc/MarlinConfigPre.h"
+
+class __FlashStringHelper;
+typedef const __FlashStringHelper *progmem_str;
+
+//
+// Enumerated axis indices
+//
+// - X_AXIS, Y_AXIS, and Z_AXIS should be used for axes in Cartesian space
+// - A_AXIS, B_AXIS, and C_AXIS should be used for Steppers, corresponding to XYZ on Cartesians
+// - X_HEAD, Y_HEAD, and Z_HEAD should be used for Steppers on Core kinematics
+//
+enum AxisEnum : uint8_t {
+ X_AXIS = 0, A_AXIS = 0,
+ Y_AXIS = 1, B_AXIS = 1,
+ Z_AXIS = 2, C_AXIS = 2,
+ E_AXIS = 3,
+ X_HEAD = 4, Y_HEAD = 5, Z_HEAD = 6,
+ E0_AXIS = 3,
+ E1_AXIS, E2_AXIS, E3_AXIS, E4_AXIS, E5_AXIS, E6_AXIS, E7_AXIS,
+ ALL_AXES = 0xFE, NO_AXIS = 0xFF
+};
+
+//
+// Loop over XYZE axes
+//
+#define LOOP_XYZ(VAR) LOOP_S_LE_N(VAR, X_AXIS, Z_AXIS)
+#define LOOP_XYZE(VAR) LOOP_S_LE_N(VAR, X_AXIS, E_AXIS)
+#define LOOP_XYZE_N(VAR) LOOP_S_L_N(VAR, X_AXIS, XYZE_N)
+#define LOOP_ABC(VAR) LOOP_S_LE_N(VAR, A_AXIS, C_AXIS)
+#define LOOP_ABCE(VAR) LOOP_S_LE_N(VAR, A_AXIS, E_AXIS)
+#define LOOP_ABCE_N(VAR) LOOP_S_L_N(VAR, A_AXIS, XYZE_N)
+
+//
+// Conditional type assignment magic. For example...
+//
+// typename IF<(MYOPT==12), int, float>::type myvar;
+//
+template <bool, class L, class R>
+struct IF { typedef R type; };
+template <class L, class R>
+struct IF<true, L, R> { typedef L type; };
+
+//
+// feedRate_t is just a humble float
+//
+typedef float feedRate_t;
+
+// Conversion macros
+#define MMM_TO_MMS(MM_M) feedRate_t(float(MM_M) / 60.0f)
+#define MMS_TO_MMM(MM_S) (float(MM_S) * 60.0f)
+
+//
+// Coordinates structures for XY, XYZ, XYZE...
+//
+
+// Helpers
+#define _RECIP(N) ((N) ? 1.0f / float(N) : 0.0f)
+#define _ABS(N) ((N) < 0 ? -(N) : (N))
+#define _LS(N) (N = (T)(uint32_t(N) << v))
+#define _RS(N) (N = (T)(uint32_t(N) >> v))
+#define FI FORCE_INLINE
+
+// Forward declarations
+template<typename T> struct XYval;
+template<typename T> struct XYZval;
+template<typename T> struct XYZEval;
+
+typedef struct XYval<bool> xy_bool_t;
+typedef struct XYZval<bool> xyz_bool_t;
+typedef struct XYZEval<bool> xyze_bool_t;
+
+typedef struct XYval<char> xy_char_t;
+typedef struct XYZval<char> xyz_char_t;
+typedef struct XYZEval<char> xyze_char_t;
+
+typedef struct XYval<unsigned char> xy_uchar_t;
+typedef struct XYZval<unsigned char> xyz_uchar_t;
+typedef struct XYZEval<unsigned char> xyze_uchar_t;
+
+typedef struct XYval<int8_t> xy_int8_t;
+typedef struct XYZval<int8_t> xyz_int8_t;
+typedef struct XYZEval<int8_t> xyze_int8_t;
+
+typedef struct XYval<uint8_t> xy_uint8_t;
+typedef struct XYZval<uint8_t> xyz_uint8_t;
+typedef struct XYZEval<uint8_t> xyze_uint8_t;
+
+typedef struct XYval<int16_t> xy_int_t;
+typedef struct XYZval<int16_t> xyz_int_t;
+typedef struct XYZEval<int16_t> xyze_int_t;
+
+typedef struct XYval<uint16_t> xy_uint_t;
+typedef struct XYZval<uint16_t> xyz_uint_t;
+typedef struct XYZEval<uint16_t> xyze_uint_t;
+
+typedef struct XYval<int32_t> xy_long_t;
+typedef struct XYZval<int32_t> xyz_long_t;
+typedef struct XYZEval<int32_t> xyze_long_t;
+
+typedef struct XYval<uint32_t> xy_ulong_t;
+typedef struct XYZval<uint32_t> xyz_ulong_t;
+typedef struct XYZEval<uint32_t> xyze_ulong_t;
+
+typedef struct XYZval<volatile int32_t> xyz_vlong_t;
+typedef struct XYZEval<volatile int32_t> xyze_vlong_t;
+
+typedef struct XYval<float> xy_float_t;
+typedef struct XYZval<float> xyz_float_t;
+typedef struct XYZEval<float> xyze_float_t;
+
+typedef struct XYval<feedRate_t> xy_feedrate_t;
+typedef struct XYZval<feedRate_t> xyz_feedrate_t;
+typedef struct XYZEval<feedRate_t> xyze_feedrate_t;
+
+typedef xy_uint8_t xy_byte_t;
+typedef xyz_uint8_t xyz_byte_t;
+typedef xyze_uint8_t xyze_byte_t;
+
+typedef xyz_long_t abc_long_t;
+typedef xyze_long_t abce_long_t;
+typedef xyz_ulong_t abc_ulong_t;
+typedef xyze_ulong_t abce_ulong_t;
+
+typedef xy_float_t xy_pos_t;
+typedef xyz_float_t xyz_pos_t;
+typedef xyze_float_t xyze_pos_t;
+
+typedef xy_float_t ab_float_t;
+typedef xyz_float_t abc_float_t;
+typedef xyze_float_t abce_float_t;
+
+typedef ab_float_t ab_pos_t;
+typedef abc_float_t abc_pos_t;
+typedef abce_float_t abce_pos_t;
+
+// External conversion methods
+void toLogical(xy_pos_t &raw);
+void toLogical(xyz_pos_t &raw);
+void toLogical(xyze_pos_t &raw);
+void toNative(xy_pos_t &raw);
+void toNative(xyz_pos_t &raw);
+void toNative(xyze_pos_t &raw);
+
+//
+// XY coordinates, counters, etc.
+//
+template<typename T>
+struct XYval {
+ union {
+ struct { T x, y; };
+ struct { T a, b; };
+ T pos[2];
+ };
+ FI void set(const T px) { x = px; }
+ FI void set(const T px, const T py) { x = px; y = py; }
+ FI void set(const T (&arr)[XY]) { x = arr[0]; y = arr[1]; }
+ FI void set(const T (&arr)[XYZ]) { x = arr[0]; y = arr[1]; }
+ FI void set(const T (&arr)[XYZE]) { x = arr[0]; y = arr[1]; }
+ #if XYZE_N > XYZE
+ FI void set(const T (&arr)[XYZE_N]) { x = arr[0]; y = arr[1]; }
+ #endif
+ FI void reset() { x = y = 0; }
+ FI T magnitude() const { return (T)sqrtf(x*x + y*y); }
+ FI operator T* () { return pos; }
+ FI operator bool() { return x || y; }
+ FI XYval<T> copy() const { return *this; }
+ FI XYval<T> ABS() const { return { T(_ABS(x)), T(_ABS(y)) }; }
+ FI XYval<int16_t> asInt() { return { int16_t(x), int16_t(y) }; }
+ FI XYval<int16_t> asInt() const { return { int16_t(x), int16_t(y) }; }
+ FI XYval<int32_t> asLong() { return { int32_t(x), int32_t(y) }; }
+ FI XYval<int32_t> asLong() const { return { int32_t(x), int32_t(y) }; }
+ FI XYval<int32_t> ROUNDL() { return { int32_t(LROUND(x)), int32_t(LROUND(y)) }; }
+ FI XYval<int32_t> ROUNDL() const { return { int32_t(LROUND(x)), int32_t(LROUND(y)) }; }
+ FI XYval<float> asFloat() { return { float(x), float(y) }; }
+ FI XYval<float> asFloat() const { return { float(x), float(y) }; }
+ FI XYval<float> reciprocal() const { return { _RECIP(x), _RECIP(y) }; }
+ FI XYval<float> asLogical() const { XYval<float> o = asFloat(); toLogical(o); return o; }
+ FI XYval<float> asNative() const { XYval<float> o = asFloat(); toNative(o); return o; }
+ FI operator XYZval<T>() { return { x, y }; }
+ FI operator XYZval<T>() const { return { x, y }; }
+ FI operator XYZEval<T>() { return { x, y }; }
+ FI operator XYZEval<T>() const { return { x, y }; }
+ FI T& operator[](const int i) { return pos[i]; }
+ FI const T& operator[](const int i) const { return pos[i]; }
+ FI XYval<T>& operator= (const T v) { set(v, v ); return *this; }
+ FI XYval<T>& operator= (const XYZval<T> &rs) { set(rs.x, rs.y); return *this; }
+ FI XYval<T>& operator= (const XYZEval<T> &rs) { set(rs.x, rs.y); return *this; }
+ FI XYval<T> operator+ (const XYval<T> &rs) const { XYval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; }
+ FI XYval<T> operator+ (const XYval<T> &rs) { XYval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; }
+ FI XYval<T> operator- (const XYval<T> &rs) const { XYval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; }
+ FI XYval<T> operator- (const XYval<T> &rs) { XYval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; }
+ FI XYval<T> operator* (const XYval<T> &rs) const { XYval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; }
+ FI XYval<T> operator* (const XYval<T> &rs) { XYval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; }
+ FI XYval<T> operator/ (const XYval<T> &rs) const { XYval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; }
+ FI XYval<T> operator/ (const XYval<T> &rs) { XYval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; }
+ FI XYval<T> operator+ (const XYZval<T> &rs) const { XYval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; }
+ FI XYval<T> operator+ (const XYZval<T> &rs) { XYval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; }
+ FI XYval<T> operator- (const XYZval<T> &rs) const { XYval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; }
+ FI XYval<T> operator- (const XYZval<T> &rs) { XYval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; }
+ FI XYval<T> operator* (const XYZval<T> &rs) const { XYval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; }
+ FI XYval<T> operator* (const XYZval<T> &rs) { XYval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; }
+ FI XYval<T> operator/ (const XYZval<T> &rs) const { XYval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; }
+ FI XYval<T> operator/ (const XYZval<T> &rs) { XYval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; }
+ FI XYval<T> operator+ (const XYZEval<T> &rs) const { XYval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; }
+ FI XYval<T> operator+ (const XYZEval<T> &rs) { XYval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; }
+ FI XYval<T> operator- (const XYZEval<T> &rs) const { XYval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; }
+ FI XYval<T> operator- (const XYZEval<T> &rs) { XYval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; }
+ FI XYval<T> operator* (const XYZEval<T> &rs) const { XYval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; }
+ FI XYval<T> operator* (const XYZEval<T> &rs) { XYval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; }
+ FI XYval<T> operator/ (const XYZEval<T> &rs) const { XYval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; }
+ FI XYval<T> operator/ (const XYZEval<T> &rs) { XYval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; }
+ FI XYval<T> operator* (const float &v) const { XYval<T> ls = *this; ls.x *= v; ls.y *= v; return ls; }
+ FI XYval<T> operator* (const float &v) { XYval<T> ls = *this; ls.x *= v; ls.y *= v; return ls; }
+ FI XYval<T> operator* (const int &v) const { XYval<T> ls = *this; ls.x *= v; ls.y *= v; return ls; }
+ FI XYval<T> operator* (const int &v) { XYval<T> ls = *this; ls.x *= v; ls.y *= v; return ls; }
+ FI XYval<T> operator/ (const float &v) const { XYval<T> ls = *this; ls.x /= v; ls.y /= v; return ls; }
+ FI XYval<T> operator/ (const float &v) { XYval<T> ls = *this; ls.x /= v; ls.y /= v; return ls; }
+ FI XYval<T> operator/ (const int &v) const { XYval<T> ls = *this; ls.x /= v; ls.y /= v; return ls; }
+ FI XYval<T> operator/ (const int &v) { XYval<T> ls = *this; ls.x /= v; ls.y /= v; return ls; }
+ FI XYval<T> operator>>(const int &v) const { XYval<T> ls = *this; _RS(ls.x); _RS(ls.y); return ls; }
+ FI XYval<T> operator>>(const int &v) { XYval<T> ls = *this; _RS(ls.x); _RS(ls.y); return ls; }
+ FI XYval<T> operator<<(const int &v) const { XYval<T> ls = *this; _LS(ls.x); _LS(ls.y); return ls; }
+ FI XYval<T> operator<<(const int &v) { XYval<T> ls = *this; _LS(ls.x); _LS(ls.y); return ls; }
+ FI XYval<T>& operator+=(const XYval<T> &rs) { x += rs.x; y += rs.y; return *this; }
+ FI XYval<T>& operator-=(const XYval<T> &rs) { x -= rs.x; y -= rs.y; return *this; }
+ FI XYval<T>& operator*=(const XYval<T> &rs) { x *= rs.x; y *= rs.y; return *this; }
+ FI XYval<T>& operator+=(const XYZval<T> &rs) { x += rs.x; y += rs.y; return *this; }
+ FI XYval<T>& operator-=(const XYZval<T> &rs) { x -= rs.x; y -= rs.y; return *this; }
+ FI XYval<T>& operator*=(const XYZval<T> &rs) { x *= rs.x; y *= rs.y; return *this; }
+ FI XYval<T>& operator+=(const XYZEval<T> &rs) { x += rs.x; y += rs.y; return *this; }
+ FI XYval<T>& operator-=(const XYZEval<T> &rs) { x -= rs.x; y -= rs.y; return *this; }
+ FI XYval<T>& operator*=(const XYZEval<T> &rs) { x *= rs.x; y *= rs.y; return *this; }
+ FI XYval<T>& operator*=(const float &v) { x *= v; y *= v; return *this; }
+ FI XYval<T>& operator*=(const int &v) { x *= v; y *= v; return *this; }
+ FI XYval<T>& operator>>=(const int &v) { _RS(x); _RS(y); return *this; }
+ FI XYval<T>& operator<<=(const int &v) { _LS(x); _LS(y); return *this; }
+ FI bool operator==(const XYval<T> &rs) { return x == rs.x && y == rs.y; }
+ FI bool operator==(const XYZval<T> &rs) { return x == rs.x && y == rs.y; }
+ FI bool operator==(const XYZEval<T> &rs) { return x == rs.x && y == rs.y; }
+ FI bool operator==(const XYval<T> &rs) const { return x == rs.x && y == rs.y; }
+ FI bool operator==(const XYZval<T> &rs) const { return x == rs.x && y == rs.y; }
+ FI bool operator==(const XYZEval<T> &rs) const { return x == rs.x && y == rs.y; }
+ FI bool operator!=(const XYval<T> &rs) { return !operator==(rs); }
+ FI bool operator!=(const XYZval<T> &rs) { return !operator==(rs); }
+ FI bool operator!=(const XYZEval<T> &rs) { return !operator==(rs); }
+ FI bool operator!=(const XYval<T> &rs) const { return !operator==(rs); }
+ FI bool operator!=(const XYZval<T> &rs) const { return !operator==(rs); }
+ FI bool operator!=(const XYZEval<T> &rs) const { return !operator==(rs); }
+ FI XYval<T> operator-() { XYval<T> o = *this; o.x = -x; o.y = -y; return o; }
+ FI const XYval<T> operator-() const { XYval<T> o = *this; o.x = -x; o.y = -y; return o; }
+};
+
+//
+// XYZ coordinates, counters, etc.
+//
+template<typename T>
+struct XYZval {
+ union {
+ struct { T x, y, z; };
+ struct { T a, b, c; };
+ T pos[3];
+ };
+ FI void set(const T px) { x = px; }
+ FI void set(const T px, const T py) { x = px; y = py; }
+ FI void set(const T px, const T py, const T pz) { x = px; y = py; z = pz; }
+ FI void set(const XYval<T> pxy, const T pz) { x = pxy.x; y = pxy.y; z = pz; }
+ FI void set(const T (&arr)[XY]) { x = arr[0]; y = arr[1]; }
+ FI void set(const T (&arr)[XYZ]) { x = arr[0]; y = arr[1]; z = arr[2]; }
+ FI void set(const T (&arr)[XYZE]) { x = arr[0]; y = arr[1]; z = arr[2]; }
+ #if XYZE_N > XYZE
+ FI void set(const T (&arr)[XYZE_N]) { x = arr[0]; y = arr[1]; z = arr[2]; }
+ #endif
+ FI void reset() { x = y = z = 0; }
+ FI T magnitude() const { return (T)sqrtf(x*x + y*y + z*z); }
+ FI operator T* () { return pos; }
+ FI operator bool() { return z || x || y; }
+ FI XYZval<T> copy() const { XYZval<T> o = *this; return o; }
+ FI XYZval<T> ABS() const { return { T(_ABS(x)), T(_ABS(y)), T(_ABS(z)) }; }
+ FI XYZval<int16_t> asInt() { return { int16_t(x), int16_t(y), int16_t(z) }; }
+ FI XYZval<int16_t> asInt() const { return { int16_t(x), int16_t(y), int16_t(z) }; }
+ FI XYZval<int32_t> asLong() { return { int32_t(x), int32_t(y), int32_t(z) }; }
+ FI XYZval<int32_t> asLong() const { return { int32_t(x), int32_t(y), int32_t(z) }; }
+ FI XYZval<int32_t> ROUNDL() { return { int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)) }; }
+ FI XYZval<int32_t> ROUNDL() const { return { int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)) }; }
+ FI XYZval<float> asFloat() { return { float(x), float(y), float(z) }; }
+ FI XYZval<float> asFloat() const { return { float(x), float(y), float(z) }; }
+ FI XYZval<float> reciprocal() const { return { _RECIP(x), _RECIP(y), _RECIP(z) }; }
+ FI XYZval<float> asLogical() const { XYZval<float> o = asFloat(); toLogical(o); return o; }
+ FI XYZval<float> asNative() const { XYZval<float> o = asFloat(); toNative(o); return o; }
+ FI operator XYval<T>&() { return *(XYval<T>*)this; }
+ FI operator const XYval<T>&() const { return *(const XYval<T>*)this; }
+ FI operator XYZEval<T>() const { return { x, y, z }; }
+ FI T& operator[](const int i) { return pos[i]; }
+ FI const T& operator[](const int i) const { return pos[i]; }
+ FI XYZval<T>& operator= (const T v) { set(v, v, v ); return *this; }
+ FI XYZval<T>& operator= (const XYval<T> &rs) { set(rs.x, rs.y ); return *this; }
+ FI XYZval<T>& operator= (const XYZEval<T> &rs) { set(rs.x, rs.y, rs.z); return *this; }
+ FI XYZval<T> operator+ (const XYval<T> &rs) const { XYZval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; }
+ FI XYZval<T> operator+ (const XYval<T> &rs) { XYZval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; }
+ FI XYZval<T> operator- (const XYval<T> &rs) const { XYZval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; }
+ FI XYZval<T> operator- (const XYval<T> &rs) { XYZval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; }
+ FI XYZval<T> operator* (const XYval<T> &rs) const { XYZval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; }
+ FI XYZval<T> operator* (const XYval<T> &rs) { XYZval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; }
+ FI XYZval<T> operator/ (const XYval<T> &rs) const { XYZval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; }
+ FI XYZval<T> operator/ (const XYval<T> &rs) { XYZval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; }
+ FI XYZval<T> operator+ (const XYZval<T> &rs) const { XYZval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; ls.z += rs.z; return ls; }
+ FI XYZval<T> operator+ (const XYZval<T> &rs) { XYZval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; ls.z += rs.z; return ls; }
+ FI XYZval<T> operator- (const XYZval<T> &rs) const { XYZval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; ls.z -= rs.z; return ls; }
+ FI XYZval<T> operator- (const XYZval<T> &rs) { XYZval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; ls.z -= rs.z; return ls; }
+ FI XYZval<T> operator* (const XYZval<T> &rs) const { XYZval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; ls.z *= rs.z; return ls; }
+ FI XYZval<T> operator* (const XYZval<T> &rs) { XYZval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; ls.z *= rs.z; return ls; }
+ FI XYZval<T> operator/ (const XYZval<T> &rs) const { XYZval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; return ls; }
+ FI XYZval<T> operator/ (const XYZval<T> &rs) { XYZval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; return ls; }
+ FI XYZval<T> operator+ (const XYZEval<T> &rs) const { XYZval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; ls.z += rs.z; return ls; }
+ FI XYZval<T> operator+ (const XYZEval<T> &rs) { XYZval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; ls.z += rs.z; return ls; }
+ FI XYZval<T> operator- (const XYZEval<T> &rs) const { XYZval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; ls.z -= rs.z; return ls; }
+ FI XYZval<T> operator- (const XYZEval<T> &rs) { XYZval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; ls.z -= rs.z; return ls; }
+ FI XYZval<T> operator* (const XYZEval<T> &rs) const { XYZval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; ls.z *= rs.z; return ls; }
+ FI XYZval<T> operator* (const XYZEval<T> &rs) { XYZval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; ls.z *= rs.z; return ls; }
+ FI XYZval<T> operator/ (const XYZEval<T> &rs) const { XYZval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; return ls; }
+ FI XYZval<T> operator/ (const XYZEval<T> &rs) { XYZval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; return ls; }
+ FI XYZval<T> operator* (const float &v) const { XYZval<T> ls = *this; ls.x *= v; ls.y *= v; ls.z *= v; return ls; }
+ FI XYZval<T> operator* (const float &v) { XYZval<T> ls = *this; ls.x *= v; ls.y *= v; ls.z *= v; return ls; }
+ FI XYZval<T> operator* (const int &v) const { XYZval<T> ls = *this; ls.x *= v; ls.y *= v; ls.z *= v; return ls; }
+ FI XYZval<T> operator* (const int &v) { XYZval<T> ls = *this; ls.x *= v; ls.y *= v; ls.z *= v; return ls; }
+ FI XYZval<T> operator/ (const float &v) const { XYZval<T> ls = *this; ls.x /= v; ls.y /= v; ls.z /= v; return ls; }
+ FI XYZval<T> operator/ (const float &v) { XYZval<T> ls = *this; ls.x /= v; ls.y /= v; ls.z /= v; return ls; }
+ FI XYZval<T> operator/ (const int &v) const { XYZval<T> ls = *this; ls.x /= v; ls.y /= v; ls.z /= v; return ls; }
+ FI XYZval<T> operator/ (const int &v) { XYZval<T> ls = *this; ls.x /= v; ls.y /= v; ls.z /= v; return ls; }
+ FI XYZval<T> operator>>(const int &v) const { XYZval<T> ls = *this; _RS(ls.x); _RS(ls.y); _RS(ls.z); return ls; }
+ FI XYZval<T> operator>>(const int &v) { XYZval<T> ls = *this; _RS(ls.x); _RS(ls.y); _RS(ls.z); return ls; }
+ FI XYZval<T> operator<<(const int &v) const { XYZval<T> ls = *this; _LS(ls.x); _LS(ls.y); _LS(ls.z); return ls; }
+ FI XYZval<T> operator<<(const int &v) { XYZval<T> ls = *this; _LS(ls.x); _LS(ls.y); _LS(ls.z); return ls; }
+ FI XYZval<T>& operator+=(const XYval<T> &rs) { x += rs.x; y += rs.y; return *this; }
+ FI XYZval<T>& operator-=(const XYval<T> &rs) { x -= rs.x; y -= rs.y; return *this; }
+ FI XYZval<T>& operator*=(const XYval<T> &rs) { x *= rs.x; y *= rs.y; return *this; }
+ FI XYZval<T>& operator/=(const XYval<T> &rs) { x /= rs.x; y /= rs.y; return *this; }
+ FI XYZval<T>& operator+=(const XYZval<T> &rs) { x += rs.x; y += rs.y; z += rs.z; return *this; }
+ FI XYZval<T>& operator-=(const XYZval<T> &rs) { x -= rs.x; y -= rs.y; z -= rs.z; return *this; }
+ FI XYZval<T>& operator*=(const XYZval<T> &rs) { x *= rs.x; y *= rs.y; z *= rs.z; return *this; }
+ FI XYZval<T>& operator/=(const XYZval<T> &rs) { x /= rs.x; y /= rs.y; z /= rs.z; return *this; }
+ FI XYZval<T>& operator+=(const XYZEval<T> &rs) { x += rs.x; y += rs.y; z += rs.z; return *this; }
+ FI XYZval<T>& operator-=(const XYZEval<T> &rs) { x -= rs.x; y -= rs.y; z -= rs.z; return *this; }
+ FI XYZval<T>& operator*=(const XYZEval<T> &rs) { x *= rs.x; y *= rs.y; z *= rs.z; return *this; }
+ FI XYZval<T>& operator/=(const XYZEval<T> &rs) { x /= rs.x; y /= rs.y; z /= rs.z; return *this; }
+ FI XYZval<T>& operator*=(const float &v) { x *= v; y *= v; z *= v; return *this; }
+ FI XYZval<T>& operator*=(const int &v) { x *= v; y *= v; z *= v; return *this; }
+ FI XYZval<T>& operator>>=(const int &v) { _RS(x); _RS(y); _RS(z); return *this; }
+ FI XYZval<T>& operator<<=(const int &v) { _LS(x); _LS(y); _LS(z); return *this; }
+ FI bool operator==(const XYZEval<T> &rs) { return x == rs.x && y == rs.y && z == rs.z; }
+ FI bool operator!=(const XYZEval<T> &rs) { return !operator==(rs); }
+ FI bool operator==(const XYZEval<T> &rs) const { return x == rs.x && y == rs.y && z == rs.z; }
+ FI bool operator!=(const XYZEval<T> &rs) const { return !operator==(rs); }
+ FI XYZval<T> operator-() { XYZval<T> o = *this; o.x = -x; o.y = -y; o.z = -z; return o; }
+ FI const XYZval<T> operator-() const { XYZval<T> o = *this; o.x = -x; o.y = -y; o.z = -z; return o; }
+};
+
+//
+// XYZE coordinates, counters, etc.
+//
+template<typename T>
+struct XYZEval {
+ union {
+ struct{ T x, y, z, e; };
+ struct{ T a, b, c; };
+ T pos[4];
+ };
+ FI void reset() { x = y = z = e = 0; }
+ FI T magnitude() const { return (T)sqrtf(x*x + y*y + z*z + e*e); }
+ FI operator T* () { return pos; }
+ FI operator bool() { return e || z || x || y; }
+ FI void set(const T px) { x = px; }
+ FI void set(const T px, const T py) { x = px; y = py; }
+ FI void set(const T px, const T py, const T pz) { x = px; y = py; z = pz; }
+ FI void set(const T px, const T py, const T pz, const T pe) { x = px; y = py; z = pz; e = pe; }
+ FI void set(const XYval<T> pxy) { x = pxy.x; y = pxy.y; }
+ FI void set(const XYval<T> pxy, const T pz) { x = pxy.x; y = pxy.y; z = pz; }
+ FI void set(const XYZval<T> pxyz) { x = pxyz.x; y = pxyz.y; z = pxyz.z; }
+ FI void set(const XYval<T> pxy, const T pz, const T pe) { x = pxy.x; y = pxy.y; z = pz; e = pe; }
+ FI void set(const XYval<T> pxy, const XYval<T> pze) { x = pxy.x; y = pxy.y; z = pze.z; e = pze.e; }
+ FI void set(const XYZval<T> pxyz, const T pe) { x = pxyz.x; y = pxyz.y; z = pxyz.z; e = pe; }
+ FI void set(const T (&arr)[XY]) { x = arr[0]; y = arr[1]; }
+ FI void set(const T (&arr)[XYZ]) { x = arr[0]; y = arr[1]; z = arr[2]; }
+ FI void set(const T (&arr)[XYZE]) { x = arr[0]; y = arr[1]; z = arr[2]; e = arr[3]; }
+ #if XYZE_N > XYZE
+ FI void set(const T (&arr)[XYZE_N]) { x = arr[0]; y = arr[1]; z = arr[2]; e = arr[3]; }
+ #endif
+ FI XYZEval<T> copy() const { return *this; }
+ FI XYZEval<T> ABS() const { return { T(_ABS(x)), T(_ABS(y)), T(_ABS(z)), T(_ABS(e)) }; }
+ FI XYZEval<int16_t> asInt() { return { int16_t(x), int16_t(y), int16_t(z), int16_t(e) }; }
+ FI XYZEval<int16_t> asInt() const { return { int16_t(x), int16_t(y), int16_t(z), int16_t(e) }; }
+ FI XYZEval<int32_t> asLong() { return { int32_t(x), int32_t(y), int32_t(z), int32_t(e) }; }
+ FI XYZEval<int32_t> asLong() const { return { int32_t(x), int32_t(y), int32_t(z), int32_t(e) }; }
+ FI XYZEval<int32_t> ROUNDL() { return { int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(e)) }; }
+ FI XYZEval<int32_t> ROUNDL() const { return { int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(e)) }; }
+ FI XYZEval<float> asFloat() { return { float(x), float(y), float(z), float(e) }; }
+ FI XYZEval<float> asFloat() const { return { float(x), float(y), float(z), float(e) }; }
+ FI XYZEval<float> reciprocal() const { return { _RECIP(x), _RECIP(y), _RECIP(z), _RECIP(e) }; }
+ FI XYZEval<float> asLogical() const { XYZEval<float> o = asFloat(); toLogical(o); return o; }
+ FI XYZEval<float> asNative() const { XYZEval<float> o = asFloat(); toNative(o); return o; }
+ FI operator XYval<T>&() { return *(XYval<T>*)this; }
+ FI operator const XYval<T>&() const { return *(const XYval<T>*)this; }
+ FI operator XYZval<T>&() { return *(XYZval<T>*)this; }
+ FI operator const XYZval<T>&() const { return *(const XYZval<T>*)this; }
+ FI T& operator[](const int i) { return pos[i]; }
+ FI const T& operator[](const int i) const { return pos[i]; }
+ FI XYZEval<T>& operator= (const T v) { set(v, v, v, v); return *this; }
+ FI XYZEval<T>& operator= (const XYval<T> &rs) { set(rs.x, rs.y); return *this; }
+ FI XYZEval<T>& operator= (const XYZval<T> &rs) { set(rs.x, rs.y, rs.z); return *this; }
+ FI XYZEval<T> operator+ (const XYval<T> &rs) const { XYZEval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; }
+ FI XYZEval<T> operator+ (const XYval<T> &rs) { XYZEval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; }
+ FI XYZEval<T> operator- (const XYval<T> &rs) const { XYZEval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; }
+ FI XYZEval<T> operator- (const XYval<T> &rs) { XYZEval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; }
+ FI XYZEval<T> operator* (const XYval<T> &rs) const { XYZEval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; }
+ FI XYZEval<T> operator* (const XYval<T> &rs) { XYZEval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; }
+ FI XYZEval<T> operator/ (const XYval<T> &rs) const { XYZEval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; }
+ FI XYZEval<T> operator/ (const XYval<T> &rs) { XYZEval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; }
+ FI XYZEval<T> operator+ (const XYZval<T> &rs) const { XYZEval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; ls.z += rs.z; return ls; }
+ FI XYZEval<T> operator+ (const XYZval<T> &rs) { XYZEval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; ls.z += rs.z; return ls; }
+ FI XYZEval<T> operator- (const XYZval<T> &rs) const { XYZEval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; ls.z -= rs.z; return ls; }
+ FI XYZEval<T> operator- (const XYZval<T> &rs) { XYZEval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; ls.z -= rs.z; return ls; }
+ FI XYZEval<T> operator* (const XYZval<T> &rs) const { XYZEval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; ls.z *= rs.z; return ls; }
+ FI XYZEval<T> operator* (const XYZval<T> &rs) { XYZEval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; ls.z *= rs.z; return ls; }
+ FI XYZEval<T> operator/ (const XYZval<T> &rs) const { XYZEval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; return ls; }
+ FI XYZEval<T> operator/ (const XYZval<T> &rs) { XYZEval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; return ls; }
+ FI XYZEval<T> operator+ (const XYZEval<T> &rs) const { XYZEval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; ls.z += rs.z; ls.e += rs.e; return ls; }
+ FI XYZEval<T> operator+ (const XYZEval<T> &rs) { XYZEval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; ls.z += rs.z; ls.e += rs.e; return ls; }
+ FI XYZEval<T> operator- (const XYZEval<T> &rs) const { XYZEval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; ls.z -= rs.z; ls.e -= rs.e; return ls; }
+ FI XYZEval<T> operator- (const XYZEval<T> &rs) { XYZEval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; ls.z -= rs.z; ls.e -= rs.e; return ls; }
+ FI XYZEval<T> operator* (const XYZEval<T> &rs) const { XYZEval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; ls.z *= rs.z; ls.e *= rs.e; return ls; }
+ FI XYZEval<T> operator* (const XYZEval<T> &rs) { XYZEval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; ls.z *= rs.z; ls.e *= rs.e; return ls; }
+ FI XYZEval<T> operator/ (const XYZEval<T> &rs) const { XYZEval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; ls.e /= rs.e; return ls; }
+ FI XYZEval<T> operator/ (const XYZEval<T> &rs) { XYZEval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; ls.e /= rs.e; return ls; }
+ FI XYZEval<T> operator* (const float &v) const { XYZEval<T> ls = *this; ls.x *= v; ls.y *= v; ls.z *= v; ls.e *= v; return ls; }
+ FI XYZEval<T> operator* (const float &v) { XYZEval<T> ls = *this; ls.x *= v; ls.y *= v; ls.z *= v; ls.e *= v; return ls; }
+ FI XYZEval<T> operator* (const int &v) const { XYZEval<T> ls = *this; ls.x *= v; ls.y *= v; ls.z *= v; ls.e *= v; return ls; }
+ FI XYZEval<T> operator* (const int &v) { XYZEval<T> ls = *this; ls.x *= v; ls.y *= v; ls.z *= v; ls.e *= v; return ls; }
+ FI XYZEval<T> operator/ (const float &v) const { XYZEval<T> ls = *this; ls.x /= v; ls.y /= v; ls.z /= v; ls.e /= v; return ls; }
+ FI XYZEval<T> operator/ (const float &v) { XYZEval<T> ls = *this; ls.x /= v; ls.y /= v; ls.z /= v; ls.e /= v; return ls; }
+ FI XYZEval<T> operator/ (const int &v) const { XYZEval<T> ls = *this; ls.x /= v; ls.y /= v; ls.z /= v; ls.e /= v; return ls; }
+ FI XYZEval<T> operator/ (const int &v) { XYZEval<T> ls = *this; ls.x /= v; ls.y /= v; ls.z /= v; ls.e /= v; return ls; }
+ FI XYZEval<T> operator>>(const int &v) const { XYZEval<T> ls = *this; _RS(ls.x); _RS(ls.y); _RS(ls.z); _RS(ls.e); return ls; }
+ FI XYZEval<T> operator>>(const int &v) { XYZEval<T> ls = *this; _RS(ls.x); _RS(ls.y); _RS(ls.z); _RS(ls.e); return ls; }
+ FI XYZEval<T> operator<<(const int &v) const { XYZEval<T> ls = *this; _LS(ls.x); _LS(ls.y); _LS(ls.z); _LS(ls.e); return ls; }
+ FI XYZEval<T> operator<<(const int &v) { XYZEval<T> ls = *this; _LS(ls.x); _LS(ls.y); _LS(ls.z); _LS(ls.e); return ls; }
+ FI XYZEval<T>& operator+=(const XYval<T> &rs) { x += rs.x; y += rs.y; return *this; }
+ FI XYZEval<T>& operator-=(const XYval<T> &rs) { x -= rs.x; y -= rs.y; return *this; }
+ FI XYZEval<T>& operator*=(const XYval<T> &rs) { x *= rs.x; y *= rs.y; return *this; }
+ FI XYZEval<T>& operator/=(const XYval<T> &rs) { x /= rs.x; y /= rs.y; return *this; }
+ FI XYZEval<T>& operator+=(const XYZval<T> &rs) { x += rs.x; y += rs.y; z += rs.z; return *this; }
+ FI XYZEval<T>& operator-=(const XYZval<T> &rs) { x -= rs.x; y -= rs.y; z -= rs.z; return *this; }
+ FI XYZEval<T>& operator*=(const XYZval<T> &rs) { x *= rs.x; y *= rs.y; z *= rs.z; return *this; }
+ FI XYZEval<T>& operator/=(const XYZval<T> &rs) { x /= rs.x; y /= rs.y; z /= rs.z; return *this; }
+ FI XYZEval<T>& operator+=(const XYZEval<T> &rs) { x += rs.x; y += rs.y; z += rs.z; e += rs.e; return *this; }
+ FI XYZEval<T>& operator-=(const XYZEval<T> &rs) { x -= rs.x; y -= rs.y; z -= rs.z; e -= rs.e; return *this; }
+ FI XYZEval<T>& operator*=(const XYZEval<T> &rs) { x *= rs.x; y *= rs.y; z *= rs.z; e *= rs.e; return *this; }
+ FI XYZEval<T>& operator/=(const XYZEval<T> &rs) { x /= rs.x; y /= rs.y; z /= rs.z; e /= rs.e; return *this; }
+ FI XYZEval<T>& operator*=(const T &v) { x *= v; y *= v; z *= v; e *= v; return *this; }
+ FI XYZEval<T>& operator>>=(const int &v) { _RS(x); _RS(y); _RS(z); _RS(e); return *this; }
+ FI XYZEval<T>& operator<<=(const int &v) { _LS(x); _LS(y); _LS(z); _LS(e); return *this; }
+ FI bool operator==(const XYZval<T> &rs) { return x == rs.x && y == rs.y && z == rs.z; }
+ FI bool operator!=(const XYZval<T> &rs) { return !operator==(rs); }
+ FI bool operator==(const XYZval<T> &rs) const { return x == rs.x && y == rs.y && z == rs.z; }
+ FI bool operator!=(const XYZval<T> &rs) const { return !operator==(rs); }
+ FI XYZEval<T> operator-() { return { -x, -y, -z, -e }; }
+ FI const XYZEval<T> operator-() const { return { -x, -y, -z, -e }; }
+};
+
+#undef _RECIP
+#undef _ABS
+#undef _LS
+#undef _RS
+#undef FI
+
+const xyze_char_t axis_codes { 'X', 'Y', 'Z', 'E' };
+#define XYZ_CHAR(A) ((char)('X' + A))
diff --git a/Marlin/src/core/utility.cpp b/Marlin/src/core/utility.cpp
new file mode 100644
index 0000000..f999568
--- /dev/null
+++ b/Marlin/src/core/utility.cpp
@@ -0,0 +1,177 @@
+/**
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "utility.h"
+
+#include "../MarlinCore.h"
+#include "../module/temperature.h"
+
+void safe_delay(millis_t ms) {
+ while (ms > 50) {
+ ms -= 50;
+ delay(50);
+ thermalManager.manage_heater();
+ }
+ delay(ms);
+ thermalManager.manage_heater(); // This keeps us safe if too many small safe_delay() calls are made
+}
+
+// A delay to provide brittle hosts time to receive bytes
+#if ENABLED(SERIAL_OVERRUN_PROTECTION)
+
+ #include "../gcode/gcode.h" // for set_autoreport_paused
+
+ void serial_delay(const millis_t ms) {
+ const bool was = gcode.set_autoreport_paused(true);
+ safe_delay(ms);
+ gcode.set_autoreport_paused(was);
+ }
+#endif
+
+#if ENABLED(DEBUG_LEVELING_FEATURE)
+
+ #include "../module/probe.h"
+ #include "../module/motion.h"
+ #include "../module/stepper.h"
+ #include "../libs/numtostr.h"
+ #include "../feature/bedlevel/bedlevel.h"
+
+ void log_machine_info() {
+ SERIAL_ECHOLNPGM("Machine Type: "
+ TERN_(DELTA, "Delta")
+ TERN_(IS_SCARA, "SCARA")
+ TERN_(IS_CORE, "Core")
+ TERN_(MARKFORGED_XY, "MarkForged")
+ TERN_(IS_CARTESIAN, "Cartesian")
+ );
+
+ SERIAL_ECHOLNPGM("Probe: "
+ TERN_(PROBE_MANUALLY, "PROBE_MANUALLY")
+ TERN_(NOZZLE_AS_PROBE, "NOZZLE_AS_PROBE")
+ TERN_(FIX_MOUNTED_PROBE, "FIX_MOUNTED_PROBE")
+ TERN_(HAS_Z_SERVO_PROBE, TERN(BLTOUCH, "BLTOUCH", "SERVO PROBE"))
+ TERN_(TOUCH_MI_PROBE, "TOUCH_MI_PROBE")
+ TERN_(Z_PROBE_SLED, "Z_PROBE_SLED")
+ TERN_(Z_PROBE_ALLEN_KEY, "Z_PROBE_ALLEN_KEY")
+ TERN_(SOLENOID_PROBE, "SOLENOID_PROBE")
+ TERN(PROBE_SELECTED, "", "NONE")
+ );
+
+ #if HAS_BED_PROBE
+
+ #if !HAS_PROBE_XY_OFFSET
+ SERIAL_ECHOPAIR("Probe Offset X0 Y0 Z", probe.offset.z, " (");
+ #else
+ SERIAL_ECHOPAIR_P(PSTR("Probe Offset X"), probe.offset_xy.x, SP_Y_STR, probe.offset_xy.y, SP_Z_STR, probe.offset.z);
+ if (probe.offset_xy.x > 0)
+ SERIAL_ECHOPGM(" (Right");
+ else if (probe.offset_xy.x < 0)
+ SERIAL_ECHOPGM(" (Left");
+ else if (probe.offset_xy.y != 0)
+ SERIAL_ECHOPGM(" (Middle");
+ else
+ SERIAL_ECHOPGM(" (Aligned With");
+
+ if (probe.offset_xy.y > 0)
+ serialprintPGM(ENABLED(IS_SCARA) ? PSTR("-Distal") : PSTR("-Back"));
+ else if (probe.offset_xy.y < 0)
+ serialprintPGM(ENABLED(IS_SCARA) ? PSTR("-Proximal") : PSTR("-Front"));
+ else if (probe.offset_xy.x != 0)
+ SERIAL_ECHOPGM("-Center");
+
+ SERIAL_ECHOPGM(" & ");
+
+ #endif
+
+ serialprintPGM(probe.offset.z < 0 ? PSTR("Below") : probe.offset.z > 0 ? PSTR("Above") : PSTR("Same Z as"));
+ SERIAL_ECHOLNPGM(" Nozzle)");
+
+ #endif
+
+ #if HAS_ABL_OR_UBL
+ SERIAL_ECHOPGM("Auto Bed Leveling: "
+ TERN_(AUTO_BED_LEVELING_LINEAR, "LINEAR")
+ TERN_(AUTO_BED_LEVELING_BILINEAR, "BILINEAR")
+ TERN_(AUTO_BED_LEVELING_3POINT, "3POINT")
+ TERN_(AUTO_BED_LEVELING_UBL, "UBL")
+ );
+
+ if (planner.leveling_active) {
+ SERIAL_ECHOLNPGM(" (enabled)");
+ #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
+ if (planner.z_fade_height)
+ SERIAL_ECHOLNPAIR("Z Fade: ", planner.z_fade_height);
+ #endif
+ #if ABL_PLANAR
+ SERIAL_ECHOPGM("ABL Adjustment X");
+ LOOP_XYZ(a) {
+ const float v = planner.get_axis_position_mm(AxisEnum(a)) - current_position[a];
+ SERIAL_CHAR(' ', XYZ_CHAR(a));
+ if (v > 0) SERIAL_CHAR('+');
+ SERIAL_DECIMAL(v);
+ }
+ #else
+ #if ENABLED(AUTO_BED_LEVELING_UBL)
+ SERIAL_ECHOPGM("UBL Adjustment Z");
+ const float rz = ubl.get_z_correction(current_position);
+ #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
+ SERIAL_ECHOPGM("ABL Adjustment Z");
+ const float rz = bilinear_z_offset(current_position);
+ #endif
+ SERIAL_ECHO(ftostr43sign(rz, '+'));
+ #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
+ if (planner.z_fade_height) {
+ SERIAL_ECHOPAIR(" (", ftostr43sign(rz * planner.fade_scaling_factor_for_z(current_position.z), '+'));
+ SERIAL_CHAR(')');
+ }
+ #endif
+ #endif
+ }
+ else
+ SERIAL_ECHOLNPGM(" (disabled)");
+
+ SERIAL_EOL();
+
+ #elif ENABLED(MESH_BED_LEVELING)
+
+ SERIAL_ECHOPGM("Mesh Bed Leveling");
+ if (planner.leveling_active) {
+ SERIAL_ECHOLNPGM(" (enabled)");
+ SERIAL_ECHOPAIR("MBL Adjustment Z", ftostr43sign(mbl.get_z(current_position), '+'));
+ #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
+ if (planner.z_fade_height) {
+ SERIAL_ECHOPAIR(" (", ftostr43sign(
+ mbl.get_z(current_position, planner.fade_scaling_factor_for_z(current_position.z)), '+'
+ ));
+ SERIAL_CHAR(')');
+ }
+ #endif
+ }
+ else
+ SERIAL_ECHOPGM(" (disabled)");
+
+ SERIAL_EOL();
+
+ #endif // MESH_BED_LEVELING
+ }
+
+#endif // DEBUG_LEVELING_FEATURE
diff --git a/Marlin/src/core/utility.h b/Marlin/src/core/utility.h
new file mode 100644
index 0000000..645a4be
--- /dev/null
+++ b/Marlin/src/core/utility.h
@@ -0,0 +1,79 @@
+/**
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "../inc/MarlinConfigPre.h"
+#include "../core/types.h"
+#include "../core/millis_t.h"
+
+// Delay that ensures heaters and watchdog are kept alive
+void safe_delay(millis_t ms);
+
+#if ENABLED(SERIAL_OVERRUN_PROTECTION)
+ void serial_delay(const millis_t ms);
+#else
+ inline void serial_delay(const millis_t) {}
+#endif
+
+#if GRID_MAX_POINTS_X && GRID_MAX_POINTS_Y
+
+ // 16x16 bit arrays
+ template <int W, int H>
+ struct FlagBits {
+ typename IF<(W>8), uint16_t, uint8_t>::type bits[H];
+ void fill() { memset(bits, 0xFF, sizeof(bits)); }
+ void reset() { memset(bits, 0x00, sizeof(bits)); }
+ void unmark(const uint8_t x, const uint8_t y) { CBI(bits[y], x); }
+ void mark(const uint8_t x, const uint8_t y) { SBI(bits[y], x); }
+ bool marked(const uint8_t x, const uint8_t y) { return TEST(bits[y], x); }
+ inline void unmark(const xy_int8_t &xy) { unmark(xy.x, xy.y); }
+ inline void mark(const xy_int8_t &xy) { mark(xy.x, xy.y); }
+ inline bool marked(const xy_int8_t &xy) { return marked(xy.x, xy.y); }
+ };
+
+ typedef FlagBits<GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y> MeshFlags;
+
+#endif
+
+#if ENABLED(DEBUG_LEVELING_FEATURE)
+ void log_machine_info();
+#else
+ #define log_machine_info() NOOP
+#endif
+
+template<typename T>
+class restorer {
+ T& ref_;
+ T val_;
+public:
+ restorer(T& perm) : ref_(perm), val_(perm) {}
+ restorer(T& perm, T temp_val) : ref_(perm), val_(perm) { perm = temp_val; }
+ ~restorer() { restore(); }
+ inline void restore() { ref_ = val_; }
+};
+
+#define REMEMBER(N,X,V...) restorer<__typeof__(X)> restorer_##N(X, ##V)
+#define RESTORE(N) restorer_##N.restore()
+
+// Converts from an uint8_t in the range of 0-255 to an uint8_t
+// in the range 0-100 while avoiding rounding artifacts
+constexpr uint8_t ui8_to_percent(const uint8_t i) { return (int(i) * 100 + 127) / 255; }