diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h
index e36b83ed1c..149b59453e 100644
--- a/Marlin/Configuration_adv.h
+++ b/Marlin/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/default/Configuration_adv.h b/Marlin/src/config/default/Configuration_adv.h
index e36b83ed1c..149b59453e 100755
--- a/Marlin/src/config/default/Configuration_adv.h
+++ b/Marlin/src/config/default/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/AlephObjects/TAZ4/Configuration_adv.h b/Marlin/src/config/examples/AlephObjects/TAZ4/Configuration_adv.h
index bc4ae0539c..9d03e89548 100644
--- a/Marlin/src/config/examples/AlephObjects/TAZ4/Configuration_adv.h
+++ b/Marlin/src/config/examples/AlephObjects/TAZ4/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/Anet/A2/Configuration_adv.h b/Marlin/src/config/examples/Anet/A2/Configuration_adv.h
index 34e82f154f..e27d9c014c 100644
--- a/Marlin/src/config/examples/Anet/A2/Configuration_adv.h
+++ b/Marlin/src/config/examples/Anet/A2/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/Anet/A2plus/Configuration_adv.h b/Marlin/src/config/examples/Anet/A2plus/Configuration_adv.h
index 34e82f154f..e27d9c014c 100644
--- a/Marlin/src/config/examples/Anet/A2plus/Configuration_adv.h
+++ b/Marlin/src/config/examples/Anet/A2plus/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/Anet/A6/Configuration_adv.h b/Marlin/src/config/examples/Anet/A6/Configuration_adv.h
index 0c19e5cdd4..1a224cfa71 100644
--- a/Marlin/src/config/examples/Anet/A6/Configuration_adv.h
+++ b/Marlin/src/config/examples/Anet/A6/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/Anet/A8/Configuration_adv.h b/Marlin/src/config/examples/Anet/A8/Configuration_adv.h
index d0f7ea485f..0f97e54d55 100644
--- a/Marlin/src/config/examples/Anet/A8/Configuration_adv.h
+++ b/Marlin/src/config/examples/Anet/A8/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/ArmEd/Configuration_adv.h b/Marlin/src/config/examples/ArmEd/Configuration_adv.h
index 9d7b64da93..174f825427 100644
--- a/Marlin/src/config/examples/ArmEd/Configuration_adv.h
+++ b/Marlin/src/config/examples/ArmEd/Configuration_adv.h
@@ -731,7 +731,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/BIBO/TouchX/cyclops/Configuration_adv.h b/Marlin/src/config/examples/BIBO/TouchX/cyclops/Configuration_adv.h
index ab614c3b3b..2634bc8650 100644
--- a/Marlin/src/config/examples/BIBO/TouchX/cyclops/Configuration_adv.h
+++ b/Marlin/src/config/examples/BIBO/TouchX/cyclops/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/BIBO/TouchX/default/Configuration_adv.h b/Marlin/src/config/examples/BIBO/TouchX/default/Configuration_adv.h
index d9a1d756c5..334fe1c3b9 100644
--- a/Marlin/src/config/examples/BIBO/TouchX/default/Configuration_adv.h
+++ b/Marlin/src/config/examples/BIBO/TouchX/default/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/BQ/Hephestos/Configuration_adv.h b/Marlin/src/config/examples/BQ/Hephestos/Configuration_adv.h
index bc54eceff3..afbeb9eb42 100644
--- a/Marlin/src/config/examples/BQ/Hephestos/Configuration_adv.h
+++ b/Marlin/src/config/examples/BQ/Hephestos/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/BQ/Hephestos_2/Configuration_adv.h b/Marlin/src/config/examples/BQ/Hephestos_2/Configuration_adv.h
index b77aa12778..f013ccf4c0 100644
--- a/Marlin/src/config/examples/BQ/Hephestos_2/Configuration_adv.h
+++ b/Marlin/src/config/examples/BQ/Hephestos_2/Configuration_adv.h
@@ -746,7 +746,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/BQ/WITBOX/Configuration_adv.h b/Marlin/src/config/examples/BQ/WITBOX/Configuration_adv.h
index bc54eceff3..afbeb9eb42 100644
--- a/Marlin/src/config/examples/BQ/WITBOX/Configuration_adv.h
+++ b/Marlin/src/config/examples/BQ/WITBOX/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/Cartesio/Configuration_adv.h b/Marlin/src/config/examples/Cartesio/Configuration_adv.h
index c7610cd771..eddd117c11 100644
--- a/Marlin/src/config/examples/Cartesio/Configuration_adv.h
+++ b/Marlin/src/config/examples/Cartesio/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/Creality/CR-10/Configuration_adv.h b/Marlin/src/config/examples/Creality/CR-10/Configuration_adv.h
index 0457785b40..fa2eaad486 100755
--- a/Marlin/src/config/examples/Creality/CR-10/Configuration_adv.h
+++ b/Marlin/src/config/examples/Creality/CR-10/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/Creality/CR-10S/Configuration_adv.h b/Marlin/src/config/examples/Creality/CR-10S/Configuration_adv.h
index c40de27fda..f2a642b81b 100644
--- a/Marlin/src/config/examples/Creality/CR-10S/Configuration_adv.h
+++ b/Marlin/src/config/examples/Creality/CR-10S/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/Creality/CR-10mini/Configuration_adv.h b/Marlin/src/config/examples/Creality/CR-10mini/Configuration_adv.h
index c6490233e8..2eb7baad9d 100644
--- a/Marlin/src/config/examples/Creality/CR-10mini/Configuration_adv.h
+++ b/Marlin/src/config/examples/Creality/CR-10mini/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/Creality/CR-8/Configuration_adv.h b/Marlin/src/config/examples/Creality/CR-8/Configuration_adv.h
index 24bdcef69f..e6ef7567c1 100644
--- a/Marlin/src/config/examples/Creality/CR-8/Configuration_adv.h
+++ b/Marlin/src/config/examples/Creality/CR-8/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/Creality/Ender-2/Configuration_adv.h b/Marlin/src/config/examples/Creality/Ender-2/Configuration_adv.h
index 308e7c878c..a256498211 100644
--- a/Marlin/src/config/examples/Creality/Ender-2/Configuration_adv.h
+++ b/Marlin/src/config/examples/Creality/Ender-2/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/Creality/Ender-3/Configuration_adv.h b/Marlin/src/config/examples/Creality/Ender-3/Configuration_adv.h
index be3912f184..3690c8f049 100644
--- a/Marlin/src/config/examples/Creality/Ender-3/Configuration_adv.h
+++ b/Marlin/src/config/examples/Creality/Ender-3/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/Creality/Ender-4/Configuration_adv.h b/Marlin/src/config/examples/Creality/Ender-4/Configuration_adv.h
index 077b585034..15bb2fd157 100644
--- a/Marlin/src/config/examples/Creality/Ender-4/Configuration_adv.h
+++ b/Marlin/src/config/examples/Creality/Ender-4/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/Einstart-S/Configuration_adv.h b/Marlin/src/config/examples/Einstart-S/Configuration_adv.h
index 875c832555..39a2a48808 100644
--- a/Marlin/src/config/examples/Einstart-S/Configuration_adv.h
+++ b/Marlin/src/config/examples/Einstart-S/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/Felix/Configuration_adv.h b/Marlin/src/config/examples/Felix/Configuration_adv.h
index d9e94c3835..414f0c52fe 100644
--- a/Marlin/src/config/examples/Felix/Configuration_adv.h
+++ b/Marlin/src/config/examples/Felix/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/FolgerTech/i3-2020/Configuration_adv.h b/Marlin/src/config/examples/FolgerTech/i3-2020/Configuration_adv.h
index 80392c84ad..c0b69d6acd 100644
--- a/Marlin/src/config/examples/FolgerTech/i3-2020/Configuration_adv.h
+++ b/Marlin/src/config/examples/FolgerTech/i3-2020/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/Formbot/Raptor/Configuration_adv.h b/Marlin/src/config/examples/Formbot/Raptor/Configuration_adv.h
index a2775ff88d..0161e47397 100644
--- a/Marlin/src/config/examples/Formbot/Raptor/Configuration_adv.h
+++ b/Marlin/src/config/examples/Formbot/Raptor/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/Formbot/T_Rex_2+/Configuration_adv.h b/Marlin/src/config/examples/Formbot/T_Rex_2+/Configuration_adv.h
index eeb653ae57..7131368f44 100644
--- a/Marlin/src/config/examples/Formbot/T_Rex_2+/Configuration_adv.h
+++ b/Marlin/src/config/examples/Formbot/T_Rex_2+/Configuration_adv.h
@@ -742,7 +742,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/Formbot/T_Rex_3/Configuration_adv.h b/Marlin/src/config/examples/Formbot/T_Rex_3/Configuration_adv.h
index e4283edd54..159cce83d3 100644
--- a/Marlin/src/config/examples/Formbot/T_Rex_3/Configuration_adv.h
+++ b/Marlin/src/config/examples/Formbot/T_Rex_3/Configuration_adv.h
@@ -743,7 +743,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/Geeetech/MeCreator2/Configuration_adv.h b/Marlin/src/config/examples/Geeetech/MeCreator2/Configuration_adv.h
index ca2d42f927..c58aaf028e 100644
--- a/Marlin/src/config/examples/Geeetech/MeCreator2/Configuration_adv.h
+++ b/Marlin/src/config/examples/Geeetech/MeCreator2/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/Geeetech/Prusa i3 Pro C/Configuration_adv.h b/Marlin/src/config/examples/Geeetech/Prusa i3 Pro C/Configuration_adv.h
index 80a7ffefe9..f86b428c02 100644
--- a/Marlin/src/config/examples/Geeetech/Prusa i3 Pro C/Configuration_adv.h
+++ b/Marlin/src/config/examples/Geeetech/Prusa i3 Pro C/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/Geeetech/Prusa i3 Pro W/Configuration_adv.h b/Marlin/src/config/examples/Geeetech/Prusa i3 Pro W/Configuration_adv.h
index 80a7ffefe9..f86b428c02 100644
--- a/Marlin/src/config/examples/Geeetech/Prusa i3 Pro W/Configuration_adv.h
+++ b/Marlin/src/config/examples/Geeetech/Prusa i3 Pro W/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/Infitary/i3-M508/Configuration_adv.h b/Marlin/src/config/examples/Infitary/i3-M508/Configuration_adv.h
index 06c9c1d665..ec9248761c 100644
--- a/Marlin/src/config/examples/Infitary/i3-M508/Configuration_adv.h
+++ b/Marlin/src/config/examples/Infitary/i3-M508/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/JGAurora/A5/Configuration_adv.h b/Marlin/src/config/examples/JGAurora/A5/Configuration_adv.h
index 47b3f65165..8258cb449b 100644
--- a/Marlin/src/config/examples/JGAurora/A5/Configuration_adv.h
+++ b/Marlin/src/config/examples/JGAurora/A5/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/MakerParts/Configuration_adv.h b/Marlin/src/config/examples/MakerParts/Configuration_adv.h
index 3a6b8067c6..d3d46efed8 100644
--- a/Marlin/src/config/examples/MakerParts/Configuration_adv.h
+++ b/Marlin/src/config/examples/MakerParts/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/Malyan/M150/Configuration_adv.h b/Marlin/src/config/examples/Malyan/M150/Configuration_adv.h
index ea1b3fd694..ed75f9530b 100644
--- a/Marlin/src/config/examples/Malyan/M150/Configuration_adv.h
+++ b/Marlin/src/config/examples/Malyan/M150/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/Malyan/M200/Configuration_adv.h b/Marlin/src/config/examples/Malyan/M200/Configuration_adv.h
index 607f085a34..43c59b9054 100644
--- a/Marlin/src/config/examples/Malyan/M200/Configuration_adv.h
+++ b/Marlin/src/config/examples/Malyan/M200/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/Micromake/C1/enhanced/Configuration_adv.h b/Marlin/src/config/examples/Micromake/C1/enhanced/Configuration_adv.h
index 4cfb2a5567..5fd51f776a 100644
--- a/Marlin/src/config/examples/Micromake/C1/enhanced/Configuration_adv.h
+++ b/Marlin/src/config/examples/Micromake/C1/enhanced/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/Mks/Sbase/Configuration_adv.h b/Marlin/src/config/examples/Mks/Sbase/Configuration_adv.h
index 200fbbe4a6..a983d1f7f7 100644
--- a/Marlin/src/config/examples/Mks/Sbase/Configuration_adv.h
+++ b/Marlin/src/config/examples/Mks/Sbase/Configuration_adv.h
@@ -739,7 +739,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/RigidBot/Configuration_adv.h b/Marlin/src/config/examples/RigidBot/Configuration_adv.h
index 2a117cb310..8d86f88dda 100644
--- a/Marlin/src/config/examples/RigidBot/Configuration_adv.h
+++ b/Marlin/src/config/examples/RigidBot/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/SCARA/Configuration_adv.h b/Marlin/src/config/examples/SCARA/Configuration_adv.h
index cfe8b6c0e9..41eeb218e3 100644
--- a/Marlin/src/config/examples/SCARA/Configuration_adv.h
+++ b/Marlin/src/config/examples/SCARA/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/Sanguinololu/Configuration_adv.h b/Marlin/src/config/examples/Sanguinololu/Configuration_adv.h
index 4e54c8bfcc..b348823c0e 100644
--- a/Marlin/src/config/examples/Sanguinololu/Configuration_adv.h
+++ b/Marlin/src/config/examples/Sanguinololu/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/TheBorg/Configuration_adv.h b/Marlin/src/config/examples/TheBorg/Configuration_adv.h
index 681f935bc8..ec225d4957 100644
--- a/Marlin/src/config/examples/TheBorg/Configuration_adv.h
+++ b/Marlin/src/config/examples/TheBorg/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/TinyBoy2/Configuration_adv.h b/Marlin/src/config/examples/TinyBoy2/Configuration_adv.h
index 2f81e35784..273f8aec87 100644
--- a/Marlin/src/config/examples/TinyBoy2/Configuration_adv.h
+++ b/Marlin/src/config/examples/TinyBoy2/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/Tronxy/X3A/Configuration_adv.h b/Marlin/src/config/examples/Tronxy/X3A/Configuration_adv.h
index 88fddbc4fb..940dd96575 100644
--- a/Marlin/src/config/examples/Tronxy/X3A/Configuration_adv.h
+++ b/Marlin/src/config/examples/Tronxy/X3A/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/UltiMachine/Archim2/Configuration_adv.h b/Marlin/src/config/examples/UltiMachine/Archim2/Configuration_adv.h
index 5a9967a18e..f608bce3ca 100644
--- a/Marlin/src/config/examples/UltiMachine/Archim2/Configuration_adv.h
+++ b/Marlin/src/config/examples/UltiMachine/Archim2/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/Velleman/K8200/Configuration_adv.h b/Marlin/src/config/examples/Velleman/K8200/Configuration_adv.h
index c2e0fd6866..c90e75e905 100644
--- a/Marlin/src/config/examples/Velleman/K8200/Configuration_adv.h
+++ b/Marlin/src/config/examples/Velleman/K8200/Configuration_adv.h
@@ -751,7 +751,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/Velleman/K8400/Configuration_adv.h b/Marlin/src/config/examples/Velleman/K8400/Configuration_adv.h
index 03bb73a4e1..f5c4445d63 100644
--- a/Marlin/src/config/examples/Velleman/K8400/Configuration_adv.h
+++ b/Marlin/src/config/examples/Velleman/K8400/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/Wanhao/Duplicator 6/Configuration_adv.h b/Marlin/src/config/examples/Wanhao/Duplicator 6/Configuration_adv.h
index 618a9906bc..276ff73bc4 100644
--- a/Marlin/src/config/examples/Wanhao/Duplicator 6/Configuration_adv.h
+++ b/Marlin/src/config/examples/Wanhao/Duplicator 6/Configuration_adv.h
@@ -740,7 +740,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/delta/Anycubic/Kossel/Configuration_adv.h b/Marlin/src/config/examples/delta/Anycubic/Kossel/Configuration_adv.h
index 992f3e021f..c1f5c62422 100644
--- a/Marlin/src/config/examples/delta/Anycubic/Kossel/Configuration_adv.h
+++ b/Marlin/src/config/examples/delta/Anycubic/Kossel/Configuration_adv.h
@@ -740,7 +740,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/delta/FLSUN/auto_calibrate/Configuration_adv.h b/Marlin/src/config/examples/delta/FLSUN/auto_calibrate/Configuration_adv.h
index 707fc6cbac..edba6cedcd 100644
--- a/Marlin/src/config/examples/delta/FLSUN/auto_calibrate/Configuration_adv.h
+++ b/Marlin/src/config/examples/delta/FLSUN/auto_calibrate/Configuration_adv.h
@@ -740,7 +740,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/delta/FLSUN/kossel/Configuration_adv.h b/Marlin/src/config/examples/delta/FLSUN/kossel/Configuration_adv.h
index 707fc6cbac..edba6cedcd 100644
--- a/Marlin/src/config/examples/delta/FLSUN/kossel/Configuration_adv.h
+++ b/Marlin/src/config/examples/delta/FLSUN/kossel/Configuration_adv.h
@@ -740,7 +740,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/delta/FLSUN/kossel_mini/Configuration_adv.h b/Marlin/src/config/examples/delta/FLSUN/kossel_mini/Configuration_adv.h
index 417e6bfeb6..aa7f0ff2dc 100644
--- a/Marlin/src/config/examples/delta/FLSUN/kossel_mini/Configuration_adv.h
+++ b/Marlin/src/config/examples/delta/FLSUN/kossel_mini/Configuration_adv.h
@@ -740,7 +740,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/delta/generic/Configuration_adv.h b/Marlin/src/config/examples/delta/generic/Configuration_adv.h
index 417e6bfeb6..aa7f0ff2dc 100644
--- a/Marlin/src/config/examples/delta/generic/Configuration_adv.h
+++ b/Marlin/src/config/examples/delta/generic/Configuration_adv.h
@@ -740,7 +740,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/delta/kossel_mini/Configuration_adv.h b/Marlin/src/config/examples/delta/kossel_mini/Configuration_adv.h
index 417e6bfeb6..aa7f0ff2dc 100644
--- a/Marlin/src/config/examples/delta/kossel_mini/Configuration_adv.h
+++ b/Marlin/src/config/examples/delta/kossel_mini/Configuration_adv.h
@@ -740,7 +740,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/delta/kossel_xl/Configuration_adv.h b/Marlin/src/config/examples/delta/kossel_xl/Configuration_adv.h
index db745753dd..0f8f9bb221 100644
--- a/Marlin/src/config/examples/delta/kossel_xl/Configuration_adv.h
+++ b/Marlin/src/config/examples/delta/kossel_xl/Configuration_adv.h
@@ -740,7 +740,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/gCreate/gMax1.5+/Configuration_adv.h b/Marlin/src/config/examples/gCreate/gMax1.5+/Configuration_adv.h
index 8a94476172..e438ac5095 100644
--- a/Marlin/src/config/examples/gCreate/gMax1.5+/Configuration_adv.h
+++ b/Marlin/src/config/examples/gCreate/gMax1.5+/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/makibox/Configuration_adv.h b/Marlin/src/config/examples/makibox/Configuration_adv.h
index c4bfabb69b..5ceea6a7e5 100644
--- a/Marlin/src/config/examples/makibox/Configuration_adv.h
+++ b/Marlin/src/config/examples/makibox/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/tvrrug/Round2/Configuration_adv.h b/Marlin/src/config/examples/tvrrug/Round2/Configuration_adv.h
index 44c36b8503..7a6ce41ba8 100644
--- a/Marlin/src/config/examples/tvrrug/Round2/Configuration_adv.h
+++ b/Marlin/src/config/examples/tvrrug/Round2/Configuration_adv.h
@@ -738,7 +738,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/config/examples/wt150/Configuration_adv.h b/Marlin/src/config/examples/wt150/Configuration_adv.h
index 4994ee17ea..3195fe78b3 100644
--- a/Marlin/src/config/examples/wt150/Configuration_adv.h
+++ b/Marlin/src/config/examples/wt150/Configuration_adv.h
@@ -739,7 +739,7 @@
* controller events, as there is a trade-off between reliable
* printing performance versus fast display updates.
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
// Show SD percentage next to the progress bar
//#define DOGM_SD_PERCENT
diff --git a/Marlin/src/core/language.h b/Marlin/src/core/language.h
index 00f0ecc97b..b6bddd2b8f 100644
--- a/Marlin/src/core/language.h
+++ b/Marlin/src/core/language.h
@@ -264,7 +264,7 @@
// LCD Menu Messages
-#define LANGUAGE_DATA_INCL_(M) STRINGIFY_(../lcd/dogm/language_data_##M.h)
+#define LANGUAGE_DATA_INCL_(M) STRINGIFY_(fontdata/language_data_##M.h)
#define LANGUAGE_DATA_INCL(M) LANGUAGE_DATA_INCL_(M)
#define INCLUDE_LANGUAGE_DATA LANGUAGE_DATA_INCL(LCD_LANGUAGE)
diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp
index 99b91bf5a7..438c41b6a2 100644
--- a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp
+++ b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp
@@ -628,7 +628,7 @@
LEAVE:
- #if ENABLED(NEWPANEL)
+ #if ENABLED(ULTIPANEL)
lcd_reset_alert_level();
lcd_quick_feedback(true);
lcd_reset_status();
diff --git a/Marlin/src/feature/power_loss_recovery.h b/Marlin/src/feature/power_loss_recovery.h
index d173b87c54..d5a0aea69d 100644
--- a/Marlin/src/feature/power_loss_recovery.h
+++ b/Marlin/src/feature/power_loss_recovery.h
@@ -19,14 +19,12 @@
* along with this program. If not, see .
*
*/
+#pragma once
/**
* power_loss_recovery.h - Resume an SD print after power-loss
*/
-#ifndef _POWER_LOSS_RECOVERY_H_
-#define _POWER_LOSS_RECOVERY_H_
-
#include "../sd/cardreader.h"
#include "../core/millis_t.h"
#include "../inc/MarlinConfigPre.h"
@@ -99,5 +97,3 @@ extern uint8_t job_recovery_commands_count;
void check_print_job_recovery();
void save_job_recovery_info();
-
-#endif // _POWER_LOSS_RECOVERY_H_
diff --git a/Marlin/src/gcode/calibrate/G28.cpp b/Marlin/src/gcode/calibrate/G28.cpp
index 6553fc5cfc..6f6ea3393a 100644
--- a/Marlin/src/gcode/calibrate/G28.cpp
+++ b/Marlin/src/gcode/calibrate/G28.cpp
@@ -210,7 +210,6 @@ void GcodeSuite::G28(const bool always_home_all) {
// Cancel the active G29 session
#if ENABLED(PROBE_MANUALLY)
- extern bool g29_in_progress;
g29_in_progress = false;
#endif
diff --git a/Marlin/src/inc/Conditionals_LCD.h b/Marlin/src/inc/Conditionals_LCD.h
index be95a1d0b7..dd17605a1d 100644
--- a/Marlin/src/inc/Conditionals_LCD.h
+++ b/Marlin/src/inc/Conditionals_LCD.h
@@ -298,7 +298,13 @@
#define ULTIPANEL
#endif
-#if ENABLED(DOGLCD) // Change number of lines to match the DOG graphic display
+#if ENABLED(NO_LCD_MENUS)
+ #undef ULTIPANEL
+#endif
+
+#define HAS_GRAPHICAL_LCD ENABLED(DOGLCD)
+
+#if HAS_GRAPHICAL_LCD
#ifndef LCD_WIDTH
#ifdef LCD_WIDTH_OVERRIDE
#define LCD_WIDTH LCD_WIDTH_OVERRIDE
@@ -311,10 +317,6 @@
#endif
#endif
-#if ENABLED(NO_LCD_MENUS)
- #undef ULTIPANEL
-#endif
-
#if ENABLED(ULTIPANEL)
#define NEWPANEL // Disable this if you actually have no click-encoder panel
#define ULTRA_LCD
@@ -333,7 +335,14 @@
#endif
#endif
-#if ENABLED(DOGLCD)
+// Aliases for LCD features
+#define HAS_SPI_LCD ENABLED(ULTRA_LCD)
+#define HAS_CHARACTER_LCD (ENABLED(ULTRA_LCD) && DISABLED(DOGLCD))
+#define HAS_DIGITAL_ENCODER (HAS_SPI_LCD && ENABLED(NEWPANEL))
+#define HAS_LCD_MENU ENABLED(ULTIPANEL)
+#define HAS_DEBUG_MENU (HAS_LCD_MENU && ENABLED(LCD_PROGRESS_BAR_TEST))
+
+#if HAS_GRAPHICAL_LCD
/* Custom characters defined in font Marlin_symbols.fon which was merged to ISO10646-0-3.bdf */
// \x00 intentionally skipped to avoid problems in strings
#define LCD_STR_REFRESH "\x01"
@@ -369,7 +378,7 @@
/**
* Default LCD contrast for dogm-like LCD displays
*/
-#if ENABLED(DOGLCD)
+#if HAS_GRAPHICAL_LCD
#define HAS_LCD_CONTRAST ( \
ENABLED(MAKRPANEL) \
@@ -394,14 +403,12 @@
#endif
// Boot screens
-#if DISABLED(ULTRA_LCD)
+#if !HAS_SPI_LCD
#undef SHOW_BOOTSCREEN
#elif !defined(BOOTSCREEN_TIMEOUT)
#define BOOTSCREEN_TIMEOUT 2500
#endif
-#define HAS_DEBUG_MENU (ENABLED(ULTIPANEL) && ENABLED(LCD_PROGRESS_BAR_TEST))
-
/**
* Extruders have some combination of stepper motors and hotends
* so we separate these concepts into the defines:
diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h
index b173cb7a32..709c8b2888 100644
--- a/Marlin/src/inc/SanityCheck.h
+++ b/Marlin/src/inc/SanityCheck.h
@@ -458,7 +458,7 @@ static_assert(X_MAX_LENGTH >= X_BED_SIZE && Y_MAX_LENGTH >= Y_BED_SIZE,
* LCD Info Screen Style
*/
#if LCD_INFO_SCREEN_STYLE > 0
- #if ENABLED(DOGLCD) || LCD_WIDTH < 20 || LCD_HEIGHT < 4
+ #if HAS_GRAPHICAL_LCD || LCD_WIDTH < 20 || LCD_HEIGHT < 4
#error "Alternative LCD_INFO_SCREEN_STYLE requires 20x4 Character LCD."
#elif LCD_INFO_SCREEN_STYLE > 1
#error "LCD_INFO_SCREEN_STYLE only has options 0 and 1 at this time."
@@ -471,14 +471,14 @@ static_assert(X_MAX_LENGTH >= X_BED_SIZE && Y_MAX_LENGTH >= Y_BED_SIZE,
#if ENABLED(LCD_PROGRESS_BAR)
#if DISABLED(SDSUPPORT) && DISABLED(LCD_SET_PROGRESS_MANUALLY)
#error "LCD_PROGRESS_BAR requires SDSUPPORT or LCD_SET_PROGRESS_MANUALLY."
- #elif DISABLED(ULTRA_LCD)
+ #elif !HAS_CHARACTER_LCD
#error "LCD_PROGRESS_BAR requires a character LCD."
- #elif ENABLED(DOGLCD)
+ #elif HAS_GRAPHICAL_LCD
#error "LCD_PROGRESS_BAR does not apply to graphical displays."
#elif ENABLED(FILAMENT_LCD_DISPLAY)
#error "LCD_PROGRESS_BAR and FILAMENT_LCD_DISPLAY are not fully compatible. Comment out this line to use both."
#endif
-#elif ENABLED(LCD_SET_PROGRESS_MANUALLY) && DISABLED(DOGLCD)
+#elif ENABLED(LCD_SET_PROGRESS_MANUALLY) && !HAS_GRAPHICAL_LCD
#error "LCD_SET_PROGRESS_MANUALLY requires LCD_PROGRESS_BAR or Graphical LCD."
#endif
diff --git a/Marlin/src/lcd/lcdprint_hd44780.cpp b/Marlin/src/lcd/HD44780/lcdprint_hd44780.cpp
similarity index 99%
rename from Marlin/src/lcd/lcdprint_hd44780.cpp
rename to Marlin/src/lcd/HD44780/lcdprint_hd44780.cpp
index 85c23b2d8c..b5793d0743 100644
--- a/Marlin/src/lcd/lcdprint_hd44780.cpp
+++ b/Marlin/src/lcd/HD44780/lcdprint_hd44780.cpp
@@ -12,17 +12,16 @@
* Western(English), Cyrillic(Russian), Kana(Japanese) charsets.
*/
-#include "../inc/MarlinConfigPre.h"
-#include "../inc/MarlinConfig.h"
+#include "../../inc/MarlinConfigPre.h"
-#if ENABLED(ULTRA_LCD)
-#include "ultralcd.h"
-#include "../Marlin.h"
+#if ENABLED(ULTRA_LCD) && DISABLED(DOGLCD)
+
+#include "../ultralcd.h"
+#include "../../Marlin.h"
-#if DISABLED(DOGLCD)
#include
-#include "fontutils.h"
-#include "lcdprint.h"
+#include "../fontutils.h"
+#include "../lcdprint.h"
#include "ultralcd_common_HD44780.h"
#ifndef LCD_CLASS
@@ -1040,5 +1039,4 @@ int lcd_put_u8str_max_P(PGM_P utf8_str_P, pixel_len_t max_length) {
return lcd_put_u8str_max_cb(utf8_str_P, read_byte_rom, max_length);
}
-#endif // DOGLCD
-#endif // ULTRA_LCD
+#endif // ULTRA_LCD && !DOGLCD
diff --git a/Marlin/src/lcd/ultralcd_common_HD44780.h b/Marlin/src/lcd/HD44780/ultralcd_common_HD44780.h
similarity index 92%
rename from Marlin/src/lcd/ultralcd_common_HD44780.h
rename to Marlin/src/lcd/HD44780/ultralcd_common_HD44780.h
index 970dbbf35a..d4dd2afae5 100644
--- a/Marlin/src/lcd/ultralcd_common_HD44780.h
+++ b/Marlin/src/lcd/HD44780/ultralcd_common_HD44780.h
@@ -19,23 +19,21 @@
* along with this program. If not, see .
*
*/
-
-#ifndef ULTRALCD_COMMON_HD44780_H
-#define ULTRALCD_COMMON_HD44780_H
+#pragma once
/**
* Implementation of the LCD display routines for a Hitachi HD44780 display.
* These are the most common LCD character displays.
*/
-#include "../inc/MarlinConfig.h"
+#include "../../inc/MarlinConfig.h"
#if LCD_HEIGHT > 3
- #include "../libs/duration_t.h"
+ #include "../../libs/duration_t.h"
#endif
#if ENABLED(AUTO_BED_LEVELING_UBL)
- #include "../feature/bedlevel/ubl/ubl.h"
+ #include "../../feature/bedlevel/ubl/ubl.h"
#if ENABLED(ULTIPANEL)
#define ULTRA_X_PIXELS_PER_CHAR 5
@@ -52,8 +50,6 @@
#endif
#endif
-extern volatile uint8_t buttons; //an extended version of the last checked buttons in a bit array.
-
////////////////////////////////////
// Setup button and encode mappings for each panel (into 'buttons' variable
//
@@ -63,6 +59,8 @@ extern volatile uint8_t buttons; //an extended version of the last checked butt
#if ENABLED(ULTIPANEL)
+ extern volatile uint8_t buttons;
+
//
// Setup other button mappings of each panel
//
@@ -183,17 +181,9 @@ extern volatile uint8_t buttons; //an extended version of the last checked butt
#endif
-#include "fontutils.h"
-#include "lcdprint.h"
+#include "../fontutils.h"
+#include "../lcdprint.h"
#if ENABLED(LCD_PROGRESS_BAR)
#define LCD_STR_PROGRESS "\x03\x04\x05"
#endif
-
-enum HD44780CharSet : char {
- CHARSET_MENU,
- CHARSET_INFO,
- CHARSET_BOOT
-};
-
-#endif // ULTRALCD_COMMON_HD44780_H
diff --git a/Marlin/src/lcd/ultralcd_impl_HD44780.h b/Marlin/src/lcd/HD44780/ultralcd_impl_HD44780.cpp
similarity index 95%
rename from Marlin/src/lcd/ultralcd_impl_HD44780.h
rename to Marlin/src/lcd/HD44780/ultralcd_impl_HD44780.cpp
index 5f37de5e56..6528d69a03 100644
--- a/Marlin/src/lcd/ultralcd_impl_HD44780.h
+++ b/Marlin/src/lcd/HD44780/ultralcd_impl_HD44780.cpp
@@ -20,15 +20,25 @@
*
*/
-#ifndef ULTRALCD_IMPL_HD44780_H
-#define ULTRALCD_IMPL_HD44780_H
+#include "../../inc/MarlinConfigPre.h"
+
+#if ENABLED(ULTRA_LCD) && DISABLED(DOGLCD)
/**
+ * ultralcd_impl_HD44780.cpp
+ *
* Implementation of the LCD display routines for a Hitachi HD44780 display.
* These are the most common LCD character displays.
*/
#include "ultralcd_common_HD44780.h"
+#include "../ultralcd.h"
+
+#include "../../sd/cardreader.h"
+#include "../../module/temperature.h"
+#include "../../module/printcounter.h"
+#include "../../module/planner.h"
+#include "../../module/motion.h"
////////////////////////////////////
// Create LCD class instance and chipset-specific information
@@ -69,8 +79,8 @@
LCD_CLASS lcd(LCD_PINS_RS, LCD_PINS_ENABLE, LCD_PINS_D4, LCD_PINS_D5, LCD_PINS_D6, LCD_PINS_D7); //RS,Enable,D4,D5,D6,D7
#endif
-#include "fontutils.h"
-#include "lcdprint.h"
+#include "../fontutils.h"
+#include "../lcdprint.h"
#if ENABLED(LCD_PROGRESS_BAR)
static millis_t progress_bar_ms = 0; // Start millis of the current progress bar cycle
@@ -90,7 +100,7 @@ static void createChar_P(const char c, const byte * const ptr) {
lcd.createChar(c, temp);
}
-static void lcd_set_custom_characters(
+void lcd_set_custom_characters(
#if ENABLED(LCD_PROGRESS_BAR) || ENABLED(SHOW_BOOTSCREEN)
const uint8_t screen_charset=CHARSET_INFO
#endif
@@ -308,7 +318,7 @@ static void lcd_set_custom_characters(
}
-static void lcd_implementation_init(
+void lcd_implementation_init(
#if ENABLED(LCD_PROGRESS_BAR)
const uint8_t screen_charset=CHARSET_INFO
#endif
@@ -744,7 +754,7 @@ FORCE_INLINE void _draw_status_message(const bool blink) {
* |01234567890123456789|
*/
- static void lcd_impl_status_screen_0() {
+ void lcd_impl_status_screen_0() {
const bool blink = lcd_blink();
// ========== Line 1 ==========
@@ -969,7 +979,7 @@ FORCE_INLINE void _draw_status_message(const bool blink) {
#if ENABLED(ADVANCED_PAUSE_FEATURE)
- static void lcd_implementation_hotend_status(const uint8_t row, const uint8_t extruder=active_extruder) {
+ void lcd_implementation_hotend_status(const uint8_t row, const uint8_t extruder) {
if (row < LCD_HEIGHT) {
lcd_moveto(LCD_WIDTH - 9, row);
_draw_heater_status(extruder, LCD_STR_THERMOMETER[0], lcd_blink());
@@ -978,7 +988,7 @@ FORCE_INLINE void _draw_status_message(const bool blink) {
#endif // ADVANCED_PAUSE_FEATURE
- static void lcd_implementation_drawmenu_static(const uint8_t row, PGM_P pstr, const bool center=true, const bool invert=false, const char *valstr=NULL) {
+ void lcd_implementation_drawmenu_static(const uint8_t row, PGM_P pstr, const bool center/*=true*/, const bool invert/*=false*/, const char *valstr/*=NULL*/) {
UNUSED(invert);
int8_t n = LCD_WIDTH;
lcd_moveto(0, row);
@@ -991,7 +1001,7 @@ FORCE_INLINE void _draw_status_message(const bool blink) {
for (; n > 0; --n) lcd_put_wchar(' ');
}
- static void lcd_implementation_drawmenu_generic(const bool sel, const uint8_t row, PGM_P pstr, const char pre_char, const char post_char) {
+ void lcd_implementation_drawmenu_generic(const bool sel, const uint8_t row, PGM_P pstr, const char pre_char, const char post_char) {
uint8_t n = LCD_WIDTH - 2;
lcd_moveto(0, row);
lcd_put_wchar(sel ? pre_char : ' ');
@@ -1000,7 +1010,7 @@ FORCE_INLINE void _draw_status_message(const bool blink) {
lcd_put_wchar(post_char);
}
- static void lcd_implementation_drawmenu_setting_edit_generic(const bool sel, const uint8_t row, PGM_P pstr, const char pre_char, const char* const data) {
+ void lcd_implementation_drawmenu_setting_edit_generic(const bool sel, const uint8_t row, PGM_P pstr, const char pre_char, const char* const data) {
uint8_t n = LCD_WIDTH - 2 - utf8_strlen(data);
lcd_moveto(0, row);
lcd_put_wchar(sel ? pre_char : ' ');
@@ -1009,7 +1019,7 @@ FORCE_INLINE void _draw_status_message(const bool blink) {
while (n--) lcd_put_wchar(' ');
lcd_put_u8str(data);
}
- static void lcd_implementation_drawmenu_setting_edit_generic_P(const bool sel, const uint8_t row, PGM_P pstr, const char pre_char, const char* const data) {
+ void lcd_implementation_drawmenu_setting_edit_generic_P(const bool sel, const uint8_t row, PGM_P pstr, const char pre_char, const char* const data) {
uint8_t n = LCD_WIDTH - 2 - utf8_strlen_P(data);
lcd_moveto(0, row);
lcd_put_wchar(sel ? pre_char : ' ');
@@ -1019,10 +1029,7 @@ FORCE_INLINE void _draw_status_message(const bool blink) {
lcd_put_u8str_P(data);
}
- #define DRAWMENU_SETTING_EDIT_GENERIC(_src) lcd_implementation_drawmenu_setting_edit_generic(sel, row, pstr, '>', _src)
- #define DRAW_BOOL_SETTING(sel, row, pstr, data) lcd_implementation_drawmenu_setting_edit_generic_P(sel, row, pstr, '>', (*(data))?PSTR(MSG_ON):PSTR(MSG_OFF))
-
- void lcd_implementation_drawedit(PGM_P pstr, const char* const value=NULL) {
+ void lcd_implementation_drawedit(PGM_P pstr, const char* const value/*=NULL*/) {
lcd_moveto(1, 1);
lcd_put_u8str_P(pstr);
if (value != NULL) {
@@ -1046,6 +1053,7 @@ FORCE_INLINE void _draw_status_message(const bool blink) {
const char *outstr = theCard.longest_filename();
if (theCard.longFilename[0]) {
#if ENABLED(SCROLL_LONG_FILENAMES)
+ static uint8_t filename_scroll_hash;
if (sel) {
uint8_t name_hash = row;
for (uint8_t l = FILENAME_LENGTH; l--;)
@@ -1071,21 +1079,16 @@ FORCE_INLINE void _draw_status_message(const bool blink) {
lcd_put_wchar(post_char);
}
- static void lcd_implementation_drawmenu_sdfile(const bool sel, const uint8_t row, PGM_P pstr, CardReader &theCard) {
+ void lcd_implementation_drawmenu_sdfile(const bool sel, const uint8_t row, PGM_P pstr, CardReader &theCard) {
lcd_implementation_drawmenu_sd(sel, row, pstr, theCard, 2, ' ');
}
- static void lcd_implementation_drawmenu_sddirectory(const bool sel, const uint8_t row, PGM_P pstr, CardReader &theCard) {
+ void lcd_implementation_drawmenu_sddirectory(const bool sel, const uint8_t row, PGM_P pstr, CardReader &theCard) {
lcd_implementation_drawmenu_sd(sel, row, pstr, theCard, 2, LCD_STR_FOLDER[0]);
}
#endif // SDSUPPORT
- #define lcd_implementation_drawmenu_back(sel, row, pstr, dummy) lcd_implementation_drawmenu_generic(sel, row, pstr, LCD_UPLEVEL_CHAR, LCD_UPLEVEL_CHAR)
- #define lcd_implementation_drawmenu_submenu(sel, row, pstr, data) lcd_implementation_drawmenu_generic(sel, row, pstr, '>', LCD_STR_ARROW_RIGHT[0])
- #define lcd_implementation_drawmenu_gcode(sel, row, pstr, gcode) lcd_implementation_drawmenu_generic(sel, row, pstr, '>', ' ')
- #define lcd_implementation_drawmenu_function(sel, row, pstr, data) lcd_implementation_drawmenu_generic(sel, row, pstr, '>', ' ')
-
#if ENABLED(LCD_HAS_SLOW_BUTTONS)
extern millis_t next_button_update_ms;
@@ -1580,4 +1583,4 @@ FORCE_INLINE void _draw_status_message(const bool blink) {
#endif // ULTIPANEL
-#endif // ULTRALCD_IMPL_HD44780_H
+#endif // ULTRA_LCD && !DOGLCD
diff --git a/Marlin/src/lcd/dogm/HAL_LCD_class_defines.h b/Marlin/src/lcd/dogm/HAL_LCD_class_defines.h
index 4b860a1f6e..93d57bb792 100644
--- a/Marlin/src/lcd/dogm/HAL_LCD_class_defines.h
+++ b/Marlin/src/lcd/dogm/HAL_LCD_class_defines.h
@@ -19,7 +19,7 @@
* along with this program. If not, see .
*
*/
-
+#pragma once
// use this file to create the public interface for device drivers that are NOT in the U8G library
@@ -36,7 +36,6 @@ class U8GLIB_64128N_2X_HAL : public U8GLIB
{ }
};
-
extern u8g_dev_t u8g_dev_st7920_128x64_HAL_4x_sw_spi;
extern u8g_dev_t u8g_dev_st7920_128x64_HAL_4x_hw_spi;
class U8GLIB_ST7920_128X64_4X_HAL : public U8GLIB
@@ -50,7 +49,6 @@ class U8GLIB_ST7920_128X64_4X_HAL : public U8GLIB
{ }
};
-
// AVR version uses ultralcd_st7920_u8glib_rrd_AVR.cpp, HAL version uses u8g_dev_st7920_128x64_HAL.cpp
extern u8g_dev_t u8g_dev_st7920_128x64_rrd_sw_spi;
class U8GLIB_ST7920_128X64_RRD : public U8GLIB
@@ -61,7 +59,6 @@ class U8GLIB_ST7920_128X64_RRD : public U8GLIB
{ }
};
-
extern u8g_dev_t u8g_dev_sh1106_128x64_2x_i2c_2_wire;
class U8GLIB_SH1106_128X64_2X_I2C_2_WIRE : public U8GLIB {
public:
@@ -70,8 +67,6 @@ class U8GLIB_SH1106_128X64_2X_I2C_2_WIRE : public U8GLIB {
{ }
};
-
-
extern u8g_dev_t u8g_dev_ssd1306_128x64_2x_i2c_2_wire;
class U8GLIB_SSD1306_128X64_2X_I2C_2_WIRE : public U8GLIB {
public:
diff --git a/Marlin/src/lcd/dogm/dogm_Bootscreen.h b/Marlin/src/lcd/dogm/dogm_Bootscreen.h
new file mode 100644
index 0000000000..efb299b359
--- /dev/null
+++ b/Marlin/src/lcd/dogm/dogm_Bootscreen.h
@@ -0,0 +1,137 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+/**
+ * Standard Marlin Boot Screen bitmaps
+ *
+ * Use the Marlin Bitmap Converter to make your own:
+ * http://marlinfw.org/tools/u8glib/converter.html
+ */
+
+#include
+
+#include "../../inc/MarlinConfig.h"
+
+#if ENABLED(SHOW_BOOTSCREEN)
+
+ //#define START_BMPHIGH // Costs 399 bytes more flash
+
+ #if ENABLED(SHOW_CUSTOM_BOOTSCREEN)
+
+ #include "../../../_Bootscreen.h"
+
+ #ifndef CUSTOM_BOOTSCREEN_TIMEOUT
+ #define CUSTOM_BOOTSCREEN_TIMEOUT 2500
+ #endif
+
+ #endif
+
+ #if ENABLED(START_BMPHIGH)
+
+ #define START_BMPWIDTH 112
+
+ const unsigned char start_bmp[] PROGMEM = {
+ B00000001,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,
+ B00001111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,
+ B00011110,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000111,B11111111,B11111111,
+ B00111000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,B11111111,B11111111,
+ B01110000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000001,B11111111,B11111111,
+ B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B11111111,B11111111,
+ B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01111111,B11111111,
+ B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01111000,B00000000,B00000000,B00111111,B11111111,
+ B11000000,B00001111,B11000000,B11111100,B00000000,B00000000,B00000000,B00000000,B00000000,B01111000,B00011000,B00000000,B00011111,B11111111,
+ B11000000,B00111111,B11100001,B11111111,B00000000,B00000000,B00000000,B00000000,B00000000,B01111000,B00111100,B00000000,B00001111,B11111111,
+ B11000000,B01111111,B11110011,B11111111,B10000000,B00000000,B00000000,B00000000,B00000000,B01111000,B00111100,B00000000,B00000111,B11111111,
+ B11000000,B11111111,B11111111,B11111111,B11000000,B00000000,B00000000,B00000000,B00000000,B01111000,B00111100,B00000000,B00000011,B11111111,
+ B11000001,B11111000,B01111111,B10000111,B11100000,B00000000,B00000000,B00000000,B00000000,B01111000,B00000000,B00000000,B00000001,B11111111,
+ B11000001,B11110000,B00111111,B00000011,B11100000,B00000000,B00000000,B00000000,B00000000,B01111000,B00000000,B00000000,B00000000,B11111111,
+ B11000001,B11100000,B00011110,B00000001,B11100000,B00011111,B00000000,B00000011,B11100000,B01111000,B00111100,B00000011,B11110000,B01111111,
+ B11000001,B11100000,B00011110,B00000001,B11100000,B01111111,B11000000,B00001111,B11111000,B01111000,B00111100,B00000111,B11111100,B00111111,
+ B11000001,B11100000,B00011110,B00000001,B11100001,B11111111,B11100000,B00011111,B11111100,B01111000,B00111100,B00001111,B11111110,B00011111,
+ B11000001,B11100000,B00011110,B00000001,B11100011,B11111111,B11110000,B00111111,B11111110,B01111000,B00111100,B00011111,B11111110,B00001111,
+ B11000001,B11100000,B00011110,B00000001,B11100011,B11110011,B11111000,B00111111,B00111110,B01111000,B00111100,B00111111,B00111111,B00000111,
+ B11000001,B11100000,B00011110,B00000001,B11100111,B11100000,B11111100,B01111100,B00011111,B01111000,B00111100,B00111110,B00011111,B00000111,
+ B11000001,B11100000,B00011110,B00000001,B11100111,B11000000,B01111100,B01111100,B00001111,B01111000,B00111100,B00111100,B00001111,B00000011,
+ B11000001,B11100000,B00011110,B00000001,B11100111,B10000000,B01111100,B01111000,B00001111,B01111000,B00111100,B00111100,B00001111,B00000011,
+ B11000001,B11100000,B00011110,B00000001,B11100111,B10000000,B00111100,B01111000,B00000000,B01111000,B00111100,B00111100,B00001111,B00000011,
+ B11000001,B11100000,B00011110,B00000001,B11100111,B10000000,B00111100,B01111000,B00000000,B01111000,B00111100,B00111100,B00001111,B00000011,
+ B11000001,B11100000,B00011110,B00000001,B11100111,B10000000,B00111100,B01111000,B00000000,B01111000,B00111100,B00111100,B00001111,B00000011,
+ B11000001,B11100000,B00011110,B00000001,B11100111,B11000000,B00111100,B01111000,B00000000,B01111000,B00111100,B00111100,B00001111,B00000011,
+ B11000001,B11100000,B00011110,B00000001,B11100011,B11100000,B00111100,B01111000,B00000000,B01111100,B00111100,B00111100,B00001111,B00000011,
+ B11000001,B11100000,B00011110,B00000001,B11100011,B11111111,B00111111,B11111000,B00000000,B01111111,B10111100,B00111100,B00001111,B00000011,
+ B11000001,B11100000,B00011110,B00000001,B11100001,B11111111,B00111111,B11111000,B00000000,B00111111,B10111111,B11111100,B00001111,B00000011,
+ B11000001,B11100000,B00011110,B00000001,B11100000,B11111111,B00111111,B11111000,B00000000,B00011111,B10111111,B11111100,B00001111,B00000011,
+ B11000001,B11100000,B00011110,B00000001,B11100000,B01111111,B00111111,B11111000,B00000000,B00001111,B10111111,B11111100,B00001111,B00000011,
+ B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000111,
+ B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000110,
+ B01110000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00001110,
+ B00111000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00011100,
+ B00011110,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01111000,
+ B00001111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11110000,
+ B00000001,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B10000000
+ };
+
+ #else
+
+ #define START_BMPWIDTH 56
+
+ const unsigned char start_bmp[] PROGMEM = {
+ B00011111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,
+ B01100000,B00000000,B00000000,B00000000,B00000000,B00000001,B11111111,
+ B01000000,B00000000,B00000000,B00000000,B00000000,B00000000,B11111111,
+ B10000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01111111,
+ B10000011,B11001111,B00000000,B00000000,B00001100,B00110000,B00111111,
+ B10000111,B11111111,B10000000,B00000000,B00001100,B00110000,B00011111,
+ B10000110,B01111001,B10000000,B00000000,B00001100,B00000000,B00001111,
+ B10001100,B00110000,B11000111,B10000011,B10001100,B00110000,B11100111,
+ B10001100,B00110000,B11001111,B11000111,B11001100,B00110001,B11110011,
+ B10001100,B00110000,B11011100,B11101100,B11101100,B00110011,B10111001,
+ B10001100,B00110000,B11011000,B01101100,B01101100,B00110011,B00011001,
+ B10001100,B00110000,B11010000,B01101100,B00001100,B00110011,B00011001,
+ B10001100,B00110000,B11011000,B01101100,B00001100,B00110011,B00011001,
+ B10001100,B00110000,B11011100,B01101100,B00001110,B00111011,B00011001,
+ B10001100,B00110000,B11001111,B01111100,B00000111,B10011111,B00011001,
+ B10001100,B00110000,B11000111,B01111100,B00000011,B10001111,B00011001,
+ B01000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000010,
+ B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000110,
+ B00011111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111000
+ };
+
+ #endif
+
+ #ifndef START_BMP_BYTEWIDTH
+ #define START_BMP_BYTEWIDTH ((START_BMPWIDTH + 7) / 8)
+ #endif
+ #ifndef START_BMPHEIGHT
+ #define START_BMPHEIGHT (sizeof(start_bmp) / (START_BMP_BYTEWIDTH))
+ #endif
+
+ static_assert(sizeof(start_bmp) == (START_BMP_BYTEWIDTH) * (START_BMPHEIGHT), "Bootscreen (start_bmp) dimensions don't match data.");
+
+#endif
+
+#ifndef CUSTOM_BOOTSCREEN_BMP_BYTEWIDTH
+ #define CUSTOM_BOOTSCREEN_BMP_BYTEWIDTH ((CUSTOM_BOOTSCREEN_BMPWIDTH + 7) / 8)
+#endif
+#ifndef CUSTOM_BOOTSCREEN_BMPHEIGHT
+ #define CUSTOM_BOOTSCREEN_BMPHEIGHT (sizeof(custom_start_bmp) / (CUSTOM_BOOTSCREEN_BMP_BYTEWIDTH))
+#endif
diff --git a/Marlin/src/lcd/dogm/dogm_bitmaps.h b/Marlin/src/lcd/dogm/dogm_Statusscreen.h
similarity index 91%
rename from Marlin/src/lcd/dogm/dogm_bitmaps.h
rename to Marlin/src/lcd/dogm/dogm_Statusscreen.h
index c610ce4a36..2618965061 100644
--- a/Marlin/src/lcd/dogm/dogm_bitmaps.h
+++ b/Marlin/src/lcd/dogm/dogm_Statusscreen.h
@@ -21,7 +21,7 @@
*/
/**
- * Standard Marlin Boot and Status Screen bitmaps
+ * Standard Marlin Status Screen bitmaps
*
* Use the Marlin Bitmap Converter to make your own:
* http://marlinfw.org/tools/u8glib/converter.html
@@ -31,109 +31,18 @@
#include "../../inc/MarlinConfig.h"
-#if ENABLED(SHOW_BOOTSCREEN)
-
- //#define START_BMPHIGH // Costs 399 bytes more flash
-
- #if ENABLED(SHOW_CUSTOM_BOOTSCREEN)
-
- #include "../../../_Bootscreen.h"
-
- #ifndef CUSTOM_BOOTSCREEN_TIMEOUT
- #define CUSTOM_BOOTSCREEN_TIMEOUT 2500
- #endif
-
- #endif
-
- #if ENABLED(START_BMPHIGH)
-
- #define START_BMPWIDTH 112
-
- const unsigned char start_bmp[] PROGMEM = {
- B00000001,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,
- B00001111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,
- B00011110,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000111,B11111111,B11111111,
- B00111000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,B11111111,B11111111,
- B01110000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000001,B11111111,B11111111,
- B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B11111111,B11111111,
- B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01111111,B11111111,
- B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01111000,B00000000,B00000000,B00111111,B11111111,
- B11000000,B00001111,B11000000,B11111100,B00000000,B00000000,B00000000,B00000000,B00000000,B01111000,B00011000,B00000000,B00011111,B11111111,
- B11000000,B00111111,B11100001,B11111111,B00000000,B00000000,B00000000,B00000000,B00000000,B01111000,B00111100,B00000000,B00001111,B11111111,
- B11000000,B01111111,B11110011,B11111111,B10000000,B00000000,B00000000,B00000000,B00000000,B01111000,B00111100,B00000000,B00000111,B11111111,
- B11000000,B11111111,B11111111,B11111111,B11000000,B00000000,B00000000,B00000000,B00000000,B01111000,B00111100,B00000000,B00000011,B11111111,
- B11000001,B11111000,B01111111,B10000111,B11100000,B00000000,B00000000,B00000000,B00000000,B01111000,B00000000,B00000000,B00000001,B11111111,
- B11000001,B11110000,B00111111,B00000011,B11100000,B00000000,B00000000,B00000000,B00000000,B01111000,B00000000,B00000000,B00000000,B11111111,
- B11000001,B11100000,B00011110,B00000001,B11100000,B00011111,B00000000,B00000011,B11100000,B01111000,B00111100,B00000011,B11110000,B01111111,
- B11000001,B11100000,B00011110,B00000001,B11100000,B01111111,B11000000,B00001111,B11111000,B01111000,B00111100,B00000111,B11111100,B00111111,
- B11000001,B11100000,B00011110,B00000001,B11100001,B11111111,B11100000,B00011111,B11111100,B01111000,B00111100,B00001111,B11111110,B00011111,
- B11000001,B11100000,B00011110,B00000001,B11100011,B11111111,B11110000,B00111111,B11111110,B01111000,B00111100,B00011111,B11111110,B00001111,
- B11000001,B11100000,B00011110,B00000001,B11100011,B11110011,B11111000,B00111111,B00111110,B01111000,B00111100,B00111111,B00111111,B00000111,
- B11000001,B11100000,B00011110,B00000001,B11100111,B11100000,B11111100,B01111100,B00011111,B01111000,B00111100,B00111110,B00011111,B00000111,
- B11000001,B11100000,B00011110,B00000001,B11100111,B11000000,B01111100,B01111100,B00001111,B01111000,B00111100,B00111100,B00001111,B00000011,
- B11000001,B11100000,B00011110,B00000001,B11100111,B10000000,B01111100,B01111000,B00001111,B01111000,B00111100,B00111100,B00001111,B00000011,
- B11000001,B11100000,B00011110,B00000001,B11100111,B10000000,B00111100,B01111000,B00000000,B01111000,B00111100,B00111100,B00001111,B00000011,
- B11000001,B11100000,B00011110,B00000001,B11100111,B10000000,B00111100,B01111000,B00000000,B01111000,B00111100,B00111100,B00001111,B00000011,
- B11000001,B11100000,B00011110,B00000001,B11100111,B10000000,B00111100,B01111000,B00000000,B01111000,B00111100,B00111100,B00001111,B00000011,
- B11000001,B11100000,B00011110,B00000001,B11100111,B11000000,B00111100,B01111000,B00000000,B01111000,B00111100,B00111100,B00001111,B00000011,
- B11000001,B11100000,B00011110,B00000001,B11100011,B11100000,B00111100,B01111000,B00000000,B01111100,B00111100,B00111100,B00001111,B00000011,
- B11000001,B11100000,B00011110,B00000001,B11100011,B11111111,B00111111,B11111000,B00000000,B01111111,B10111100,B00111100,B00001111,B00000011,
- B11000001,B11100000,B00011110,B00000001,B11100001,B11111111,B00111111,B11111000,B00000000,B00111111,B10111111,B11111100,B00001111,B00000011,
- B11000001,B11100000,B00011110,B00000001,B11100000,B11111111,B00111111,B11111000,B00000000,B00011111,B10111111,B11111100,B00001111,B00000011,
- B11000001,B11100000,B00011110,B00000001,B11100000,B01111111,B00111111,B11111000,B00000000,B00001111,B10111111,B11111100,B00001111,B00000011,
- B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000111,
- B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000110,
- B01110000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00001110,
- B00111000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00011100,
- B00011110,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01111000,
- B00001111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11110000,
- B00000001,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B10000000
- };
-
- #else
-
- #define START_BMPWIDTH 56
-
- const unsigned char start_bmp[] PROGMEM = {
- B00011111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,
- B01100000,B00000000,B00000000,B00000000,B00000000,B00000001,B11111111,
- B01000000,B00000000,B00000000,B00000000,B00000000,B00000000,B11111111,
- B10000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01111111,
- B10000011,B11001111,B00000000,B00000000,B00001100,B00110000,B00111111,
- B10000111,B11111111,B10000000,B00000000,B00001100,B00110000,B00011111,
- B10000110,B01111001,B10000000,B00000000,B00001100,B00000000,B00001111,
- B10001100,B00110000,B11000111,B10000011,B10001100,B00110000,B11100111,
- B10001100,B00110000,B11001111,B11000111,B11001100,B00110001,B11110011,
- B10001100,B00110000,B11011100,B11101100,B11101100,B00110011,B10111001,
- B10001100,B00110000,B11011000,B01101100,B01101100,B00110011,B00011001,
- B10001100,B00110000,B11010000,B01101100,B00001100,B00110011,B00011001,
- B10001100,B00110000,B11011000,B01101100,B00001100,B00110011,B00011001,
- B10001100,B00110000,B11011100,B01101100,B00001110,B00111011,B00011001,
- B10001100,B00110000,B11001111,B01111100,B00000111,B10011111,B00011001,
- B10001100,B00110000,B11000111,B01111100,B00000011,B10001111,B00011001,
- B01000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000010,
- B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000110,
- B00011111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111000
- };
-
- #endif
-
- #ifndef START_BMP_BYTEWIDTH
- #define START_BMP_BYTEWIDTH ((START_BMPWIDTH + 7) / 8)
- #endif
- #ifndef START_BMPHEIGHT
- #define START_BMPHEIGHT (sizeof(start_bmp) / (START_BMP_BYTEWIDTH))
- #endif
-
- static_assert(sizeof(start_bmp) == (START_BMP_BYTEWIDTH) * (START_BMPHEIGHT), "Bootscreen (start_bmp) dimensions don't match data.");
-
-#endif
-
#if ENABLED(CUSTOM_STATUS_SCREEN_IMAGE)
- // This file must define STATUS_SCREENWIDTH and status_screen[012]_bmp.
- // It can also define STATUS_SCREEN_X, STATUS_SCREEN_{BED,FAN}_TEXT_X and
- // STATUS_SCREEN_HOTEND_TEXT_X(i) to modify draw locations.
+ /**
+ * Custom _Statusscreen.h files must define STATUS_SCREENWIDTH and status_screen[012]_bmp.
+ * There's no need to define STATUS_SCREENHEIGHT since it's calculated automatically.
+ * You can also define these to modify drawing and animation:
+ *
+ * - STATUS_SCREEN_X
+ * - STATUS_SCREEN_{BED,FAN}_TEXT_X
+ * - STATUS_SCREEN_HOTEND_TEXT_X(i)
+ * - FAN_ANIM_FRAMES
+ */
#include "../../../_Statusscreen.h"
#else // !CUSTOM_STATUS_SCREEN_IMAGE
@@ -1161,106 +1070,6 @@
#endif // !CUSTOM_STATUS_SCREEN_IMAGE
-#if ENABLED(BABYSTEP_ZPROBE_GFX_OVERLAY) || ENABLED(MESH_EDIT_GFX_OVERLAY)
-
- const unsigned char cw_bmp[] PROGMEM = {
- B00000011,B11111000,B00000000,
- B00001111,B11111110,B00000000,
- B00011110,B00001111,B00000000,
- B00111000,B00000111,B00000000,
- B00111000,B00000011,B10000000,
- B01110000,B00000011,B10000000,
- B01110000,B00001111,B11100000,
- B01110000,B00000111,B11000000,
- B01110000,B00000011,B10000000,
- B01110000,B00000001,B00000000,
- B01110000,B00000000,B00000000,
- B00111000,B00000000,B00000000,
- B00111000,B00000111,B00000000,
- B00011110,B00001111,B00000000,
- B00001111,B11111110,B00000000,
- B00000011,B11111000,B00000000
- };
-
- const unsigned char ccw_bmp[] PROGMEM = {
- B00000000,B11111110,B00000000,
- B00000011,B11111111,B10000000,
- B00000111,B10000011,B11000000,
- B00001110,B00000001,B11000000,
- B00001110,B00000000,B11100000,
- B00011100,B00000000,B11100000,
- B01111111,B00000000,B11100000,
- B00111110,B00000000,B11100000,
- B00011100,B00000000,B11100000,
- B00001000,B00000000,B11100000,
- B00000000,B00000000,B11100000,
- B00000000,B00000001,B11000000,
- B00001110,B00000001,B11000000,
- B00001111,B00000111,B10000000,
- B00000111,B11111111,B00000000,
- B00000001,B11111100,B00000000
- };
-
- const unsigned char up_arrow_bmp[] PROGMEM = {
- B00000100,B00000000,
- B00001110,B00000000,
- B00011111,B00000000,
- B00111111,B10000000,
- B01111111,B11000000,
- B00001110,B00000000,
- B00001110,B00000000,
- B00001110,B00000000,
- B00001110,B00000000,
- B00001110,B00000000,
- B00001110,B00000000,
- B00001110,B00000000,
- B00001110,B00000000
- };
-
- const unsigned char down_arrow_bmp[] PROGMEM = {
- B00001110,B00000000,
- B00001110,B00000000,
- B00001110,B00000000,
- B00001110,B00000000,
- B00001110,B00000000,
- B00001110,B00000000,
- B00001110,B00000000,
- B00001110,B00000000,
- B01111111,B11000000,
- B00111111,B10000000,
- B00011111,B00000000,
- B00001110,B00000000,
- B00000100,B00000000
- };
-
- const unsigned char offset_bedline_bmp[] PROGMEM = {
- B11111111,B11111111,B11111111
- };
-
- const unsigned char nozzle_bmp[] PROGMEM = {
- B01111111,B10000000,
- B11111111,B11000000,
- B11111111,B11000000,
- B11111111,B11000000,
- B01111111,B10000000,
- B01111111,B10000000,
- B11111111,B11000000,
- B11111111,B11000000,
- B11111111,B11000000,
- B00111111,B00000000,
- B00011110,B00000000,
- B00001100,B00000000
- };
-
-#endif // BABYSTEP_ZPROBE_GFX_OVERLAY || MESH_EDIT_GFX_OVERLAY
-
-#ifndef CUSTOM_BOOTSCREEN_BMP_BYTEWIDTH
- #define CUSTOM_BOOTSCREEN_BMP_BYTEWIDTH ((CUSTOM_BOOTSCREEN_BMPWIDTH + 7) / 8)
-#endif
-#ifndef CUSTOM_BOOTSCREEN_BMPHEIGHT
- #define CUSTOM_BOOTSCREEN_BMPHEIGHT (sizeof(custom_start_bmp) / (CUSTOM_BOOTSCREEN_BMP_BYTEWIDTH))
-#endif
-
#ifndef FAN_ANIM_FRAMES
#define FAN_ANIM_FRAMES 2
#elif FAN_ANIM_FRAMES > 3
diff --git a/Marlin/src/lcd/dogm/dogm_font_data_6x9_marlin.h b/Marlin/src/lcd/dogm/fontdata/fontdata_6x9_marlin.h
similarity index 100%
rename from Marlin/src/lcd/dogm/dogm_font_data_6x9_marlin.h
rename to Marlin/src/lcd/dogm/fontdata/fontdata_6x9_marlin.h
diff --git a/Marlin/src/lcd/dogm/dogm_font_data_ISO10646_1.h b/Marlin/src/lcd/dogm/fontdata/fontdata_ISO10646_1.h
similarity index 100%
rename from Marlin/src/lcd/dogm/dogm_font_data_ISO10646_1.h
rename to Marlin/src/lcd/dogm/fontdata/fontdata_ISO10646_1.h
diff --git a/Marlin/src/lcd/dogm/language_data_an.h b/Marlin/src/lcd/dogm/fontdata/language_data_an.h
similarity index 100%
rename from Marlin/src/lcd/dogm/language_data_an.h
rename to Marlin/src/lcd/dogm/fontdata/language_data_an.h
diff --git a/Marlin/src/lcd/dogm/language_data_bg.h b/Marlin/src/lcd/dogm/fontdata/language_data_bg.h
similarity index 100%
rename from Marlin/src/lcd/dogm/language_data_bg.h
rename to Marlin/src/lcd/dogm/fontdata/language_data_bg.h
diff --git a/Marlin/src/lcd/dogm/language_data_ca.h b/Marlin/src/lcd/dogm/fontdata/language_data_ca.h
similarity index 100%
rename from Marlin/src/lcd/dogm/language_data_ca.h
rename to Marlin/src/lcd/dogm/fontdata/language_data_ca.h
diff --git a/Marlin/src/lcd/dogm/language_data_cz.h b/Marlin/src/lcd/dogm/fontdata/language_data_cz.h
similarity index 100%
rename from Marlin/src/lcd/dogm/language_data_cz.h
rename to Marlin/src/lcd/dogm/fontdata/language_data_cz.h
diff --git a/Marlin/src/lcd/dogm/language_data_da.h b/Marlin/src/lcd/dogm/fontdata/language_data_da.h
similarity index 100%
rename from Marlin/src/lcd/dogm/language_data_da.h
rename to Marlin/src/lcd/dogm/fontdata/language_data_da.h
diff --git a/Marlin/src/lcd/dogm/language_data_de.h b/Marlin/src/lcd/dogm/fontdata/language_data_de.h
similarity index 100%
rename from Marlin/src/lcd/dogm/language_data_de.h
rename to Marlin/src/lcd/dogm/fontdata/language_data_de.h
diff --git a/Marlin/src/lcd/dogm/language_data_el-gr.h b/Marlin/src/lcd/dogm/fontdata/language_data_el-gr.h
similarity index 100%
rename from Marlin/src/lcd/dogm/language_data_el-gr.h
rename to Marlin/src/lcd/dogm/fontdata/language_data_el-gr.h
diff --git a/Marlin/src/lcd/dogm/language_data_el.h b/Marlin/src/lcd/dogm/fontdata/language_data_el.h
similarity index 100%
rename from Marlin/src/lcd/dogm/language_data_el.h
rename to Marlin/src/lcd/dogm/fontdata/language_data_el.h
diff --git a/Marlin/src/lcd/dogm/language_data_en.h b/Marlin/src/lcd/dogm/fontdata/language_data_en.h
similarity index 100%
rename from Marlin/src/lcd/dogm/language_data_en.h
rename to Marlin/src/lcd/dogm/fontdata/language_data_en.h
diff --git a/Marlin/src/lcd/dogm/language_data_es.h b/Marlin/src/lcd/dogm/fontdata/language_data_es.h
similarity index 100%
rename from Marlin/src/lcd/dogm/language_data_es.h
rename to Marlin/src/lcd/dogm/fontdata/language_data_es.h
diff --git a/Marlin/src/lcd/dogm/language_data_eu.h b/Marlin/src/lcd/dogm/fontdata/language_data_eu.h
similarity index 100%
rename from Marlin/src/lcd/dogm/language_data_eu.h
rename to Marlin/src/lcd/dogm/fontdata/language_data_eu.h
diff --git a/Marlin/src/lcd/dogm/language_data_fi.h b/Marlin/src/lcd/dogm/fontdata/language_data_fi.h
similarity index 100%
rename from Marlin/src/lcd/dogm/language_data_fi.h
rename to Marlin/src/lcd/dogm/fontdata/language_data_fi.h
diff --git a/Marlin/src/lcd/dogm/language_data_fr.h b/Marlin/src/lcd/dogm/fontdata/language_data_fr.h
similarity index 100%
rename from Marlin/src/lcd/dogm/language_data_fr.h
rename to Marlin/src/lcd/dogm/fontdata/language_data_fr.h
diff --git a/Marlin/src/lcd/dogm/language_data_gl.h b/Marlin/src/lcd/dogm/fontdata/language_data_gl.h
similarity index 100%
rename from Marlin/src/lcd/dogm/language_data_gl.h
rename to Marlin/src/lcd/dogm/fontdata/language_data_gl.h
diff --git a/Marlin/src/lcd/dogm/language_data_hr.h b/Marlin/src/lcd/dogm/fontdata/language_data_hr.h
similarity index 100%
rename from Marlin/src/lcd/dogm/language_data_hr.h
rename to Marlin/src/lcd/dogm/fontdata/language_data_hr.h
diff --git a/Marlin/src/lcd/dogm/language_data_it.h b/Marlin/src/lcd/dogm/fontdata/language_data_it.h
similarity index 100%
rename from Marlin/src/lcd/dogm/language_data_it.h
rename to Marlin/src/lcd/dogm/fontdata/language_data_it.h
diff --git a/Marlin/src/lcd/dogm/language_data_jp-kana.h b/Marlin/src/lcd/dogm/fontdata/language_data_jp-kana.h
similarity index 100%
rename from Marlin/src/lcd/dogm/language_data_jp-kana.h
rename to Marlin/src/lcd/dogm/fontdata/language_data_jp-kana.h
diff --git a/Marlin/src/lcd/dogm/language_data_ko_KR.h b/Marlin/src/lcd/dogm/fontdata/language_data_ko_KR.h
similarity index 100%
rename from Marlin/src/lcd/dogm/language_data_ko_KR.h
rename to Marlin/src/lcd/dogm/fontdata/language_data_ko_KR.h
diff --git a/Marlin/src/lcd/dogm/language_data_nl.h b/Marlin/src/lcd/dogm/fontdata/language_data_nl.h
similarity index 100%
rename from Marlin/src/lcd/dogm/language_data_nl.h
rename to Marlin/src/lcd/dogm/fontdata/language_data_nl.h
diff --git a/Marlin/src/lcd/dogm/language_data_pl.h b/Marlin/src/lcd/dogm/fontdata/language_data_pl.h
similarity index 100%
rename from Marlin/src/lcd/dogm/language_data_pl.h
rename to Marlin/src/lcd/dogm/fontdata/language_data_pl.h
diff --git a/Marlin/src/lcd/dogm/language_data_pt-br.h b/Marlin/src/lcd/dogm/fontdata/language_data_pt-br.h
similarity index 100%
rename from Marlin/src/lcd/dogm/language_data_pt-br.h
rename to Marlin/src/lcd/dogm/fontdata/language_data_pt-br.h
diff --git a/Marlin/src/lcd/dogm/language_data_pt.h b/Marlin/src/lcd/dogm/fontdata/language_data_pt.h
similarity index 100%
rename from Marlin/src/lcd/dogm/language_data_pt.h
rename to Marlin/src/lcd/dogm/fontdata/language_data_pt.h
diff --git a/Marlin/src/lcd/dogm/language_data_ru.h b/Marlin/src/lcd/dogm/fontdata/language_data_ru.h
similarity index 100%
rename from Marlin/src/lcd/dogm/language_data_ru.h
rename to Marlin/src/lcd/dogm/fontdata/language_data_ru.h
diff --git a/Marlin/src/lcd/dogm/language_data_sk.h b/Marlin/src/lcd/dogm/fontdata/language_data_sk.h
similarity index 100%
rename from Marlin/src/lcd/dogm/language_data_sk.h
rename to Marlin/src/lcd/dogm/fontdata/language_data_sk.h
diff --git a/Marlin/src/lcd/dogm/language_data_test.h b/Marlin/src/lcd/dogm/fontdata/language_data_test.h
similarity index 100%
rename from Marlin/src/lcd/dogm/language_data_test.h
rename to Marlin/src/lcd/dogm/fontdata/language_data_test.h
diff --git a/Marlin/src/lcd/dogm/language_data_tr.h b/Marlin/src/lcd/dogm/fontdata/language_data_tr.h
similarity index 100%
rename from Marlin/src/lcd/dogm/language_data_tr.h
rename to Marlin/src/lcd/dogm/fontdata/language_data_tr.h
diff --git a/Marlin/src/lcd/dogm/language_data_uk.h b/Marlin/src/lcd/dogm/fontdata/language_data_uk.h
similarity index 100%
rename from Marlin/src/lcd/dogm/language_data_uk.h
rename to Marlin/src/lcd/dogm/fontdata/language_data_uk.h
diff --git a/Marlin/src/lcd/dogm/language_data_zh_CN.h b/Marlin/src/lcd/dogm/fontdata/language_data_zh_CN.h
similarity index 100%
rename from Marlin/src/lcd/dogm/language_data_zh_CN.h
rename to Marlin/src/lcd/dogm/fontdata/language_data_zh_CN.h
diff --git a/Marlin/src/lcd/dogm/language_data_zh_TW.h b/Marlin/src/lcd/dogm/fontdata/language_data_zh_TW.h
similarity index 100%
rename from Marlin/src/lcd/dogm/language_data_zh_TW.h
rename to Marlin/src/lcd/dogm/fontdata/language_data_zh_TW.h
diff --git a/Marlin/src/lcd/lcdprint_u8g.cpp b/Marlin/src/lcd/dogm/lcdprint_u8g.cpp
similarity index 91%
rename from Marlin/src/lcd/lcdprint_u8g.cpp
rename to Marlin/src/lcd/dogm/lcdprint_u8g.cpp
index 3c827c6963..b19f32c54a 100644
--- a/Marlin/src/lcd/lcdprint_u8g.cpp
+++ b/Marlin/src/lcd/dogm/lcdprint_u8g.cpp
@@ -7,7 +7,7 @@
* @copyright GPL/BSD
*/
-#include "../inc/MarlinConfigPre.h"
+#include "../../inc/MarlinConfigPre.h"
#if ENABLED(DOGLCD)
@@ -16,12 +16,12 @@ extern U8GLIB *pu8g;
#define _lcd_write(a) pu8g->print(a)
#define _lcd_setcursor(col, row) pu8g->setPrintPos((col), (row));
-#include "ultralcd.h"
-#include "../Marlin.h"
+#include "../ultralcd.h"
+#include "../../Marlin.h"
-#include "fontutils.h"
+#include "../fontutils.h"
#include "u8g_fontutf8.h"
-#include "lcdprint.h"
+#include "../lcdprint.h"
int lcd_glyph_height(void) {
return u8g_GetFontBBXHeight(pu8g->getU8g());
diff --git a/Marlin/src/lcd/dogm/status_screen_DOGM.h b/Marlin/src/lcd/dogm/status_screen_DOGM.cpp
similarity index 88%
rename from Marlin/src/lcd/dogm/status_screen_DOGM.h
rename to Marlin/src/lcd/dogm/status_screen_DOGM.cpp
index 50fc85d3f9..65408c6ab8 100644
--- a/Marlin/src/lcd/dogm/status_screen_DOGM.h
+++ b/Marlin/src/lcd/dogm/status_screen_DOGM.cpp
@@ -20,14 +20,28 @@
*
*/
-/**
- * status_screen_DOGM.h
- *
- * Standard Status Screen for Graphical Display
- */
+//
+// status_screen_DOGM.cpp
+// Standard Status Screen for Graphical Display
+//
-#ifndef _STATUS_SCREEN_DOGM_H_
-#define _STATUS_SCREEN_DOGM_H_
+#include "../../inc/MarlinConfigPre.h"
+
+#if HAS_GRAPHICAL_LCD && DISABLED(LIGHTWEIGHT_UI)
+
+#include "dogm_Statusscreen.h"
+#include "../ultralcd.h"
+#include "../lcdprint.h"
+#include "../../module/motion.h"
+#include "../../module/temperature.h"
+
+#if ENABLED(SDSUPPORT)
+ #include "../../sd/cardreader.h"
+#endif
+
+#if HAS_PRINT_PROGRESS
+ #include "../../module/printcounter.h"
+#endif
FORCE_INLINE void _draw_centered_temp(const int16_t temp, const uint8_t x, const uint8_t y) {
const char * const str = itostr3(temp);
@@ -121,7 +135,7 @@ FORCE_INLINE void _draw_axis_value(const AxisEnum axis, const char *value, const
}
}
-inline void lcd_implementation_status_message(const bool blink) {
+FORCE_INLINE void lcd_implementation_status_message(const bool blink) {
#if ENABLED(STATUS_MESSAGE_SCROLLING)
static bool last_blink = false;
@@ -198,10 +212,33 @@ inline void lcd_implementation_status_message(const bool blink) {
#endif
}
-static void lcd_impl_status_screen_0() {
+// The current graphical page being rendered
+u8g_page_t &page = ((u8g_pb_t *)((u8g.getU8g())->dev->dev_mem))->p;
+
+void lcd_impl_status_screen_0() {
const bool blink = lcd_blink();
+ // Status Menu Font
+ lcd_setFont(FONT_STATUSMENU);
+
+ //
+ // Fan Animation
+ //
+ // Draw the entire heading image bitmap rather than each element
+ // separately. This is an optimization because it's slower to draw
+ // multiple elements than a single bitmap.
+ //
+ // The bitmap:
+ // - May be offset in X
+ // - Includes all nozzle(s), bed(s), and the fan.
+ //
+ // TODO:
+ //
+ // - Only draw the whole header on the first
+ // entry to the status screen. Nozzle, bed, and
+ // fan outline bits don't change.
+ //
#if FAN_ANIM_FRAMES > 2
static bool old_blink;
static uint8_t fan_frame;
@@ -211,29 +248,7 @@ static void lcd_impl_status_screen_0() {
}
#endif
- // Status Menu Font
- lcd_setFont(FONT_STATUSMENU);
-
- //
- // Fan Animation
- //
- // Draws the whole heading image as a B/W bitmap rather than
- // drawing the elements separately.
- // This was done as an optimization, as it was slower to draw
- // multiple parts compared to a single bitmap.
- //
- // The bitmap:
- // - May be offset in X
- // - Includes all nozzle(s), bed(s), and the fan.
- //
- // TODO:
- //
- // - Only draw the whole header on the first
- // entry to the status screen. Nozzle, bed, and
- // fan outline bits don't change.
- //
- if (PAGE_UNDER(STATUS_SCREENHEIGHT + 1)) {
-
+ if (PAGE_UNDER(STATUS_SCREENHEIGHT + 1))
u8g.drawBitmapP(
STATUS_SCREEN_X, STATUS_SCREEN_Y,
(STATUS_SCREENWIDTH + 7) / 8, STATUS_SCREENHEIGHT,
@@ -251,8 +266,6 @@ static void lcd_impl_status_screen_0() {
status_screen0_bmp
);
- }
-
//
// Temperature Graphics and Info
//
@@ -283,15 +296,15 @@ static void lcd_impl_status_screen_0() {
//
// SD Card Symbol
//
- if (card.isFileOpen() && PAGE_CONTAINS(42 - (TALL_FONT_CORRECTION), 51 - (TALL_FONT_CORRECTION))) {
+ if (card.isFileOpen() && PAGE_CONTAINS(42, 51)) {
// Upper box
- u8g.drawBox(42, 42 - (TALL_FONT_CORRECTION), 8, 7); // 42-48 (or 41-47)
+ u8g.drawBox(42, 42, 8, 7); // 42-48 (or 41-47)
// Right edge
- u8g.drawBox(50, 44 - (TALL_FONT_CORRECTION), 2, 5); // 44-48 (or 43-47)
+ u8g.drawBox(50, 44, 2, 5); // 44-48 (or 43-47)
// Bottom hollow box
- u8g.drawFrame(42, 49 - (TALL_FONT_CORRECTION), 10, 4); // 49-52 (or 48-51)
+ u8g.drawFrame(42, 49, 10, 4); // 49-52 (or 48-51)
// Corner pixel
- u8g.drawPixel(50, 43 - (TALL_FONT_CORRECTION)); // 43 (or 42)
+ u8g.drawPixel(50, 43); // 43 (or 42)
}
#endif // SDSUPPORT
@@ -302,10 +315,10 @@ static void lcd_impl_status_screen_0() {
#define PROGRESS_BAR_X 54
#define PROGRESS_BAR_WIDTH (LCD_PIXEL_WIDTH - PROGRESS_BAR_X)
- if (PAGE_CONTAINS(49, 52 - (TALL_FONT_CORRECTION))) // 49-52 (or 49-51)
+ if (PAGE_CONTAINS(49, 52)) // 49-52 (or 49-51)
u8g.drawFrame(
PROGRESS_BAR_X, 49,
- PROGRESS_BAR_WIDTH, 4 - (TALL_FONT_CORRECTION)
+ PROGRESS_BAR_WIDTH, 4
);
#if DISABLED(LCD_SET_PROGRESS_MANUALLY)
@@ -318,10 +331,10 @@ static void lcd_impl_status_screen_0() {
// Progress bar solid part
//
- if (PAGE_CONTAINS(50, 51 - (TALL_FONT_CORRECTION))) // 50-51 (or just 50)
+ if (PAGE_CONTAINS(50, 51)) // 50-51 (or just 50)
u8g.drawBox(
PROGRESS_BAR_X + 1, 50,
- (uint16_t)((PROGRESS_BAR_WIDTH - 2) * progress_bar_percent * 0.01), 2 - (TALL_FONT_CORRECTION)
+ (uint16_t)((PROGRESS_BAR_WIDTH - 2) * progress_bar_percent * 0.01), 2
);
//
@@ -357,7 +370,7 @@ static void lcd_impl_status_screen_0() {
lcd_put_u8str(buffer);
}
- #endif // SDSUPPORT || LCD_SET_PROGRESS_MANUALLY
+ #endif // HAS_PRINT_PROGRESS
//
// XYZ Coordinates
@@ -492,4 +505,4 @@ static void lcd_impl_status_screen_0() {
}
}
-#endif // _STATUS_SCREEN_DOGM_H_
+#endif // HAS_GRAPHICAL_LCD && !LIGHTWEIGHT_UI
diff --git a/Marlin/src/lcd/dogm/status_screen_lite_ST7920.h b/Marlin/src/lcd/dogm/status_screen_lite_ST7920.cpp
similarity index 98%
rename from Marlin/src/lcd/dogm/status_screen_lite_ST7920.h
rename to Marlin/src/lcd/dogm/status_screen_lite_ST7920.cpp
index df1d6cb1cc..73851ecefb 100644
--- a/Marlin/src/lcd/dogm/status_screen_lite_ST7920.h
+++ b/Marlin/src/lcd/dogm/status_screen_lite_ST7920.cpp
@@ -36,9 +36,28 @@
* bar, so updates are sporadic.
*/
+//
+// status_screen_lite_ST7920.cpp
+// Lightweight Status Screen for Graphical Display
+//
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if ENABLED(LIGHTWEIGHT_UI)
+
#include "status_screen_lite_ST7920_class.h"
+#include "../ultralcd.h"
+#include "../fontutils.h"
+#include "../lcdprint.h"
#include "../../libs/duration_t.h"
+#include "../../module/motion.h"
+#include "../../module/printcounter.h"
+#include "../../module/temperature.h"
+
+#if ENABLED(SDSUPPORT)
+ #include "../../sd/cardreader.h"
+#endif
#define BUFFER_WIDTH 256
#define BUFFER_HEIGHT 32
@@ -947,7 +966,7 @@ void ST7920_Lite_Status_Screen::clear_text_buffer() {
ncs();
}
-static void lcd_impl_status_screen_0() {
+void lcd_impl_status_screen_0() {
ST7920_Lite_Status_Screen::update(false);
}
@@ -963,7 +982,7 @@ static void lcd_impl_status_screen_0() {
* entered the Status Screen and calls the on_entry()
* and on_exit() methods for cleanup.
*/
-static void lcd_in_status(const bool inStatus) {
+void lcd_in_status(const bool inStatus) {
static bool lastInStatus = false;
if (lastInStatus == inStatus) return;
if ((lastInStatus = inStatus))
@@ -971,3 +990,5 @@ static void lcd_in_status(const bool inStatus) {
else
ST7920_Lite_Status_Screen::on_exit();
}
+
+#endif // LIGHTWEIGHT_UI
diff --git a/Marlin/src/lcd/dogm/status_screen_lite_ST7920_class.h b/Marlin/src/lcd/dogm/status_screen_lite_ST7920_class.h
index 3bbbd31d6a..323d951c36 100644
--- a/Marlin/src/lcd/dogm/status_screen_lite_ST7920_class.h
+++ b/Marlin/src/lcd/dogm/status_screen_lite_ST7920_class.h
@@ -13,9 +13,7 @@
* FOR A PARTICULAR PURPOSE. See the GNU GPL for more details.
*
*/
-
-#ifndef STATUS_SCREEN_LITE_ST7920_CLASS_H
-#define STATUS_SCREEN_LITE_ST7920_CLASS_H
+#pragma once
#include "../../core/macros.h"
#include "../../libs/duration_t.h"
@@ -107,5 +105,3 @@ class ST7920_Lite_Status_Screen {
static void on_exit();
static void clear_text_buffer();
};
-
-#endif // STATUS_SCREEN_LITE_ST7920_CLASS_H
diff --git a/Marlin/src/lcd/u8g_fontutf8.cpp b/Marlin/src/lcd/dogm/u8g_fontutf8.cpp
similarity index 99%
rename from Marlin/src/lcd/u8g_fontutf8.cpp
rename to Marlin/src/lcd/dogm/u8g_fontutf8.cpp
index f3944be2a1..1f5f5de506 100644
--- a/Marlin/src/lcd/u8g_fontutf8.cpp
+++ b/Marlin/src/lcd/dogm/u8g_fontutf8.cpp
@@ -7,12 +7,12 @@
* @copyright GPL/BSD
*/
-#include "../inc/MarlinConfigPre.h"
+#include "../../inc/MarlinConfigPre.h"
#if ENABLED(DOGLCD)
#include
-#include "fontutils.h"
+#include "../fontutils.h"
#include "u8g_fontutf8.h"
////////////////////////////////////////////////////////////
diff --git a/Marlin/src/lcd/u8g_fontutf8.h b/Marlin/src/lcd/dogm/u8g_fontutf8.h
similarity index 58%
rename from Marlin/src/lcd/u8g_fontutf8.h
rename to Marlin/src/lcd/dogm/u8g_fontutf8.h
index 883b24ca6b..34e365cf95 100644
--- a/Marlin/src/lcd/u8g_fontutf8.h
+++ b/Marlin/src/lcd/dogm/u8g_fontutf8.h
@@ -6,11 +6,10 @@
* @date 2015-02-19
* @copyright GPL/BSD
*/
-#ifndef _UXG_FONTUTF8_H
-#define _UXG_FONTUTF8_H 1
+#pragma once
#include
-#include "fontutils.h"
+#include "../fontutils.h"
// the macro to indicate a UTF-8 string
// You should to save the C/C++ source in UTF-8 encoding!
@@ -25,16 +24,14 @@ typedef struct _uxg_fontinfo_t {
const u8g_fntpgm_uint8_t *fntdata;
} uxg_fontinfo_t;
-int uxg_SetUtf8Fonts (const uxg_fontinfo_t * fntinfo, int number); // fntinfo is type of PROGMEM
+int uxg_SetUtf8Fonts(const uxg_fontinfo_t * fntinfo, int number); // fntinfo is type of PROGMEM
-unsigned int uxg_DrawWchar (u8g_t *pu8g, unsigned int x, unsigned int y, wchar_t ch, pixel_len_t max_length);
+unsigned int uxg_DrawWchar(u8g_t *pu8g, unsigned int x, unsigned int y, wchar_t ch, pixel_len_t max_length);
-unsigned int uxg_DrawUtf8Str (u8g_t *pu8g, unsigned int x, unsigned int y, const char *utf8_msg, pixel_len_t max_length);
-unsigned int uxg_DrawUtf8StrP (u8g_t *pu8g, unsigned int x, unsigned int y, PGM_P utf8_msg, pixel_len_t max_length);
+unsigned int uxg_DrawUtf8Str(u8g_t *pu8g, unsigned int x, unsigned int y, const char *utf8_msg, pixel_len_t max_length);
+unsigned int uxg_DrawUtf8StrP(u8g_t *pu8g, unsigned int x, unsigned int y, PGM_P utf8_msg, pixel_len_t max_length);
int uxg_GetUtf8StrPixelWidth(u8g_t *pu8g, const char *utf8_msg);
int uxg_GetUtf8StrPixelWidthP(u8g_t *pu8g, PGM_P utf8_msg);
#define uxg_GetFont(puxg) ((puxg)->font)
-
-#endif // _UXG_FONTUTF8_H
diff --git a/Marlin/src/lcd/ultralcd_impl_DOGM.h b/Marlin/src/lcd/dogm/ultralcd_impl_DOGM.cpp
similarity index 62%
rename from Marlin/src/lcd/ultralcd_impl_DOGM.h
rename to Marlin/src/lcd/dogm/ultralcd_impl_DOGM.cpp
index 4bd4016d80..c6547c4655 100644
--- a/Marlin/src/lcd/ultralcd_impl_DOGM.h
+++ b/Marlin/src/lcd/dogm/ultralcd_impl_DOGM.cpp
@@ -21,9 +21,11 @@
*/
/**
- * ultralcd_impl_DOGM.h
+ * ultralcd_impl_DOGM.cpp
+ *
+ * Implementation of the LCD display routines for a DOGM128 graphic display.
+ * by STB for ErikZalm/Marlin. Common LCD 128x64 pixel graphic displays.
*
- * Graphics LCD implementation for 128x64 pixel LCDs by STB for ErikZalm/Marlin
* Demonstrator: http://www.reprap.org/wiki/STB_Electronics
* License: http://opensource.org/licenses/BSD-3-Clause
*
@@ -33,191 +35,69 @@
* License: http://opensource.org/licenses/BSD-3-Clause
*/
-#ifndef ULTRALCD_IMPL_DOGM_H
-#define ULTRALCD_IMPL_DOGM_H
+#include "../../inc/MarlinConfigPre.h"
-#include "../inc/MarlinConfig.h"
+#if HAS_GRAPHICAL_LCD
-/**
- * Implementation of the LCD display routines for a DOGM128 graphic display.
- * These are common LCD 128x64 pixel graphic displays.
- */
-#include "ultralcd.h"
-
-/*
-#if ENABLED(U8GLIB_ST7565_64128N)
- #include "dogm/ultralcd_st7565_u8glib_VIKI.h"
-#elif ENABLED(U8GLIB_ST7920)
- #include "dogm/ultralcd_st7920_u8glib_rrd.h"
-#endif
-*/
-
-#include "dogm/dogm_bitmaps.h"
-
-#if ENABLED(SDSUPPORT)
- #include "../libs/duration_t.h"
-#endif
+#include "../ultralcd.h"
#include
-
-#include "fontutils.h"
+#include "HAL_LCD_class_defines.h"
#include "u8g_fontutf8.h"
+#include "../lcdprint.h"
+#include "../fontutils.h"
+#include "dogm_Bootscreen.h"
-#include "dogm/HAL_LCD_class_defines.h"
+#include "../../sd/cardreader.h"
+#include "../../module/temperature.h"
+#include "../../module/printcounter.h"
+
+#if ENABLED(SDSUPPORT)
+ #include "../../libs/duration_t.h"
+#endif
#if ENABLED(AUTO_BED_LEVELING_UBL)
- #include "../feature/bedlevel/ubl/ubl.h"
-#endif
-
-// Only Western languages support big / small fonts
-#if DISABLED(DISPLAY_CHARSET_ISO10646_1)
- #undef USE_BIG_EDIT_FONT
- #undef USE_SMALL_INFOFONT
+ #include "../../feature/bedlevel/ubl/ubl.h"
#endif
+#define FONT_SPECIAL_NAME ISO10646_1_5x7
+#define FONT_MENU_NAME ISO10646_1_5x7
+#include "fontdata/fontdata_ISO10646_1.h"
#if ENABLED(USE_SMALL_INFOFONT)
- #include "dogm/dogm_font_data_6x9_marlin.h"
+ #include "fontdata/fontdata_6x9_marlin.h"
#define FONT_STATUSMENU_NAME u8g_font_6x9
- #define INFO_FONT_HEIGHT 7
#else
#define FONT_STATUSMENU_NAME FONT_MENU_NAME
- #define INFO_FONT_HEIGHT 8
#endif
-// The Marlin special symbols is now in the dogm_font_data_ISO10646_1.h
-#define FONT_SPECIAL_NAME ISO10646_1_5x7
+#define START_COL 0
+
+U8G_CLASS u8g(U8G_PARAM);
+U8GLIB *pu8g = &u8g;
#include LANGUAGE_DATA_INCL(LCD_LANGUAGE)
-#include "dogm/dogm_font_data_ISO10646_1.h"
-#define FONT_MENU_NAME ISO10646_1_5x7
+#if HAS_LCD_CONTRAST
-//#define FONT_STATUSMENU_NAME FONT_MENU_NAME
+ int16_t lcd_contrast; // Initialized by settings.load()
-#define FONT_STATUSMENU 1
-#define FONT_SPECIAL 2
-#define FONT_MENU_EDIT 3
-#define FONT_MENU 4
+ void set_lcd_contrast(const int16_t value) {
+ lcd_contrast = constrain(value, LCD_CONTRAST_MIN, LCD_CONTRAST_MAX);
+ u8g.setContrast(lcd_contrast);
+ }
-// DOGM parameters (size in pixels)
-#define DOG_CHAR_WIDTH 6
-#define DOG_CHAR_HEIGHT 12
-#if ENABLED(USE_BIG_EDIT_FONT)
- #define FONT_MENU_EDIT_NAME u8g_font_9x18
- #define DOG_CHAR_WIDTH_EDIT 9
- #define DOG_CHAR_HEIGHT_EDIT 18
-#else
- #define FONT_MENU_EDIT_NAME FONT_MENU_NAME
- #define DOG_CHAR_WIDTH_EDIT DOG_CHAR_WIDTH
- #define DOG_CHAR_HEIGHT_EDIT DOG_CHAR_HEIGHT
#endif
-#ifndef TALL_FONT_CORRECTION
- #define TALL_FONT_CORRECTION 0
-#endif
-
-#define START_COL 0
-
-// LCD selection
-#if ENABLED(REPRAPWORLD_GRAPHICAL_LCD)
- #if DISABLED(SDSUPPORT) && (LCD_PINS_D4 == SCK_PIN) && (LCD_PINS_ENABLE == MOSI_PIN)
- U8GLIB_ST7920_128X64_4X u8g(LCD_PINS_RS); // 2 stripes, HW SPI (shared with SD card)
- #else
- U8GLIB_ST7920_128X64_4X u8g(LCD_PINS_D4, LCD_PINS_ENABLE, LCD_PINS_RS); // Original u8glib device. 2 stripes, SW SPI
- #endif
-
-#elif ENABLED(U8GLIB_ST7920)
- // RepRap Discount Full Graphics Smart Controller
- #if DISABLED(SDSUPPORT) && (LCD_PINS_D4 == SCK_PIN) && (LCD_PINS_ENABLE == MOSI_PIN)
- U8GLIB_ST7920_128X64_4X_HAL u8g(LCD_PINS_RS); // 2 stripes, HW SPI (shared with SD card, on AVR does not use standard LCD adapter)
- #else
- //U8GLIB_ST7920_128X64_4X u8g(LCD_PINS_D4, LCD_PINS_ENABLE, LCD_PINS_RS); // Original u8glib device. 2 stripes, SW SPI
- U8GLIB_ST7920_128X64_RRD u8g(LCD_PINS_D4, LCD_PINS_ENABLE, LCD_PINS_RS); // Number of stripes can be adjusted in ultralcd_st7920_u8glib_rrd.h with PAGE_HEIGHT
- // AVR version ignores these pin settings
- // HAL version uses these pin settings
- #endif
-
-#elif ENABLED(CARTESIO_UI)
- // The CartesioUI display
- //U8GLIB_DOGM128_2X u8g(DOGLCD_SCK, DOGLCD_MOSI, DOGLCD_CS, DOGLCD_A0); // 4 stripes
- U8GLIB_DOGM128_2X u8g(DOGLCD_CS, DOGLCD_A0); // 4 stripes
-
-#elif ENABLED(U8GLIB_LM6059_AF)
- // Based on the Adafruit ST7565 (http://www.adafruit.com/products/250)
- //U8GLIB_LM6059 u8g(DOGLCD_CS, DOGLCD_A0); // 8 stripes
- U8GLIB_LM6059_2X u8g(DOGLCD_CS, DOGLCD_A0); // 4 stripes
-
-#elif ENABLED(U8GLIB_ST7565_64128N)
- // The MaKrPanel, Mini Viki, Viki 2.0 & AZSMZ 12864 ST7565 controller
- #define SMART_RAMPS (MB(RAMPS_SMART_EFB) || MB(RAMPS_SMART_EEB) || MB(RAMPS_SMART_EFF) || MB(RAMPS_SMART_EEF) || MB(RAMPS_SMART_SF))
- #if DOGLCD_SCK == SCK_PIN && DOGLCD_MOSI == MOSI_PIN && !SMART_RAMPS
- U8GLIB_64128N_2X_HAL u8g(DOGLCD_CS, DOGLCD_A0); // using HW-SPI
- #else
- U8GLIB_64128N_2X_HAL u8g(DOGLCD_SCK, DOGLCD_MOSI, DOGLCD_CS, DOGLCD_A0); // using SW-SPI
- #endif
-
-#elif ENABLED(MKS_12864OLED_SSD1306)
- // MKS 128x64 (SSD1306) OLED I2C LCD
- U8GLIB_SSD1306_128X64 u8g(DOGLCD_SCK, DOGLCD_MOSI, DOGLCD_CS, DOGLCD_A0); // 8 stripes
- //U8GLIB_SSD1306_128X64_2X u8g(DOGLCD_SCK, DOGLCD_MOSI, DOGLCD_CS, DOGLCD_A0); // 4 stripes
-
-#elif ENABLED(U8GLIB_SSD1306)
- // Generic support for SSD1306 OLED I2C LCDs
- //U8GLIB_SSD1306_128X64_2X_I2C_2_WIRE u8g(U8G_I2C_OPT_NONE | U8G_I2C_OPT_FAST); // 4 stripes
- U8GLIB_SSD1306_128X64_2X u8g(U8G_I2C_OPT_NONE | U8G_I2C_OPT_FAST); // 4 stripes
-
-#elif ENABLED(MKS_12864OLED)
- // MKS 128x64 (SH1106) OLED I2C LCD
- U8GLIB_SH1106_128X64 u8g(DOGLCD_SCK, DOGLCD_MOSI, DOGLCD_CS, DOGLCD_A0); // 8 stripes
- //U8GLIB_SH1106_128X64_2X u8g(DOGLCD_SCK, DOGLCD_MOSI, DOGLCD_CS, DOGLCD_A0); // 4 stripes
-#elif ENABLED(U8GLIB_SH1106)
- // Generic support for SH1106 OLED I2C LCDs
- //U8GLIB_SH1106_128X64_2X_I2C_2_WIRE u8g(U8G_I2C_OPT_NONE | U8G_I2C_OPT_FAST); // 4 stripes
- U8GLIB_SH1106_128X64_2X u8g(U8G_I2C_OPT_NONE | U8G_I2C_OPT_FAST); // 4 stripes
-#elif ENABLED(U8GLIB_SSD1309)
- // Generic support for SSD1309 OLED I2C LCDs
- U8GLIB_SSD1309_128X64 u8g(U8G_I2C_OPT_NONE | U8G_I2C_OPT_FAST);
-#elif ENABLED(MINIPANEL)
- // The MINIPanel display
- //U8GLIB_MINI12864 u8g(DOGLCD_CS, DOGLCD_A0); // 8 stripes
- U8GLIB_MINI12864_2X u8g(DOGLCD_CS, DOGLCD_A0); // 4 stripes
-#elif ENABLED(U8GLIB_SH1106_EINSTART)
- // Connected via motherboard header
- U8GLIB_SH1106_128X64 u8g(DOGLCD_SCK, DOGLCD_MOSI, DOGLCD_CS, LCD_PINS_DC, LCD_PINS_RS);
-#else
- // for regular DOGM128 display with HW-SPI
- //U8GLIB_DOGM128 u8g(DOGLCD_CS, DOGLCD_A0); // HW-SPI Com: CS, A0 // 8 stripes
- U8GLIB_DOGM128_2X u8g(DOGLCD_CS, DOGLCD_A0); // HW-SPI Com: CS, A0 // 4 stripes
-#endif
-
-U8GLIB *pu8g = &u8g;
-
-#ifndef LCD_PIXEL_WIDTH
- #define LCD_PIXEL_WIDTH 128
-#endif
-#ifndef LCD_PIXEL_HEIGHT
- #define LCD_PIXEL_HEIGHT 64
-#endif
-
-#include "lcdprint.h"
-
-int16_t lcd_contrast; // Initialized by settings.load()
-static char currentfont = 0;
-
-// The current graphical page being rendered
-u8g_page_t &page = ((u8g_pb_t *)((u8g.getU8g())->dev->dev_mem))->p;
-
-// For selective rendering within a Y range
-#define PAGE_UNDER(yb) (u8g.getU8g()->current_page.y0 <= (yb))
-#define PAGE_CONTAINS(ya, yb) (PAGE_UNDER(yb) && u8g.getU8g()->current_page.y1 >= (ya))
-
-static void lcd_setFont(const char font_nr) {
- switch (font_nr) {
- case FONT_STATUSMENU : {u8g.setFont(FONT_STATUSMENU_NAME); currentfont = FONT_STATUSMENU;}; break;
- default:
- case FONT_MENU : {u8g.setFont(FONT_MENU_NAME); currentfont = FONT_MENU;}; break;
- case FONT_SPECIAL : {u8g.setFont(FONT_SPECIAL_NAME); currentfont = FONT_SPECIAL;}; break;
- case FONT_MENU_EDIT : {u8g.setFont(FONT_MENU_EDIT_NAME); currentfont = FONT_MENU_EDIT;}; break;
+void lcd_setFont(const MarlinFont font_nr) {
+ static char currentfont = 0;
+ if (font_nr != currentfont) {
+ switch ((currentfont = font_nr)) {
+ case FONT_STATUSMENU : u8g.setFont(FONT_STATUSMENU_NAME); break;
+ default:
+ case FONT_MENU : u8g.setFont(FONT_MENU_NAME); break;
+ case FONT_SPECIAL : u8g.setFont(FONT_SPECIAL_NAME); break;
+ case FONT_MENU_EDIT : u8g.setFont(FONT_MENU_EDIT_NAME); break;
+ }
}
}
@@ -302,13 +182,11 @@ static void lcd_setFont(const char font_nr) {
#endif // SHOW_BOOTSCREEN
#if ENABLED(LIGHTWEIGHT_UI)
- #include "dogm/status_screen_lite_ST7920.h"
-#else
- #include "dogm/status_screen_DOGM.h"
+ #include "status_screen_lite_ST7920_class.h"
#endif
// Initialize or re-initialize the LCD
-static void lcd_implementation_init() {
+void lcd_implementation_init() {
#if PIN_EXISTS(LCD_BACKLIGHT) // Enable LCD backlight
OUT_WRITE(LCD_BACKLIGHT_PIN, HIGH);
@@ -332,8 +210,8 @@ static void lcd_implementation_init() {
u8g.begin();
#endif
- #if DISABLED(MINIPANEL) // setContrast not working for Mini Panel
- u8g.setContrast(lcd_contrast);
+ #if HAS_LCD_CONTRAST
+ set_lcd_contrast(lcd_contrast);
#endif
#if ENABLED(LCD_SCREEN_ROT_90)
@@ -344,7 +222,7 @@ static void lcd_implementation_init() {
u8g.setRot270(); // Rotate screen by 270°
#endif
- uxg_SetUtf8Fonts (g_fontinfo, NUM_ARRAY(g_fontinfo));
+ uxg_SetUtf8Fonts(g_fontinfo, NUM_ARRAY(g_fontinfo));
}
// The kill screen is displayed for unrecoverable conditions
@@ -370,13 +248,12 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop
#if ENABLED(ULTIPANEL)
uint8_t row_y1, row_y2;
- uint8_t constexpr row_height = DOG_CHAR_HEIGHT + 2 * (TALL_FONT_CORRECTION);
#if ENABLED(ADVANCED_PAUSE_FEATURE)
- static void lcd_implementation_hotend_status(const uint8_t row, const uint8_t extruder=active_extruder) {
- row_y1 = row * row_height + 1;
- row_y2 = row_y1 + row_height - 1;
+ void lcd_implementation_hotend_status(const uint8_t row, const uint8_t extruder) {
+ row_y1 = row * (DOG_CHAR_HEIGHT) + 1;
+ row_y2 = row_y1 + DOG_CHAR_HEIGHT - 1;
if (!PAGE_CONTAINS(row_y1 + 1, row_y2 + 2)) return;
@@ -394,9 +271,9 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop
#endif // ADVANCED_PAUSE_FEATURE
// Set the colors for a menu item based on whether it is selected
- static bool lcd_implementation_mark_as_selected(const uint8_t row, const bool isSelected) {
- row_y1 = row * row_height + 1;
- row_y2 = row_y1 + row_height - 1;
+ static bool mark_as_selected(const uint8_t row, const bool isSelected) {
+ row_y1 = row * (DOG_CHAR_HEIGHT) + 1;
+ row_y2 = row_y1 + DOG_CHAR_HEIGHT - 1;
if (!PAGE_CONTAINS(row_y1 + 1, row_y2 + 2)) return false;
@@ -406,7 +283,7 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop
u8g.drawHLine(0, row_y2 + 2, LCD_PIXEL_WIDTH);
#else
u8g.setColorIndex(1); // black on white
- u8g.drawBox(0, row_y1 + 2, LCD_PIXEL_WIDTH, row_height - 1);
+ u8g.drawBox(0, row_y1 + 2, LCD_PIXEL_WIDTH, DOG_CHAR_HEIGHT - 1);
u8g.setColorIndex(0); // white on black
#endif
}
@@ -423,9 +300,9 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop
}
// Draw a static line of text in the same idiom as a menu item
- static void lcd_implementation_drawmenu_static(const uint8_t row, PGM_P pstr, const bool center=true, const bool invert=false, const char* valstr=NULL) {
+ void lcd_implementation_drawmenu_static(const uint8_t row, PGM_P pstr, const bool center/*=true*/, const bool invert/*=false*/, const char* valstr/*=NULL*/) {
- if (lcd_implementation_mark_as_selected(row, invert)) {
+ if (mark_as_selected(row, invert)) {
uint8_t n = LCD_PIXEL_WIDTH - (DOG_CHAR_WIDTH) * (START_COL); // pixel width of string allowed
@@ -443,10 +320,10 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop
}
// Draw a generic menu item
- static void lcd_implementation_drawmenu_generic(const bool isSelected, const uint8_t row, PGM_P pstr, const char pre_char, const char post_char) {
+ void lcd_implementation_drawmenu_generic(const bool isSelected, const uint8_t row, PGM_P pstr, const char pre_char, const char post_char) {
UNUSED(pre_char);
- if (lcd_implementation_mark_as_selected(row, isSelected)) {
+ if (mark_as_selected(row, isSelected)) {
uint8_t n = LCD_WIDTH - (START_COL) - 2;
n *= DOG_CHAR_WIDTH;
n -= lcd_put_u8str_max_P(pstr, n);
@@ -457,15 +334,9 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop
}
}
- // Macros for specific types of menu items
- #define lcd_implementation_drawmenu_back(sel, row, pstr, dummy) lcd_implementation_drawmenu_generic(sel, row, pstr, LCD_STR_UPLEVEL[0], LCD_STR_UPLEVEL[0])
- #define lcd_implementation_drawmenu_submenu(sel, row, pstr, data) lcd_implementation_drawmenu_generic(sel, row, pstr, '>', LCD_STR_ARROW_RIGHT[0])
- #define lcd_implementation_drawmenu_gcode(sel, row, pstr, gcode) lcd_implementation_drawmenu_generic(sel, row, pstr, '>', ' ')
- #define lcd_implementation_drawmenu_function(sel, row, pstr, data) lcd_implementation_drawmenu_generic(sel, row, pstr, '>', ' ')
-
// Draw a menu item with an editable value
- static void _drawmenu_setting_edit_generic(const bool isSelected, const uint8_t row, PGM_P pstr, const char* const data, const bool pgm) {
- if (lcd_implementation_mark_as_selected(row, isSelected)) {
+ void _drawmenu_setting_edit_generic(const bool isSelected, const uint8_t row, PGM_P pstr, const char* const data, const bool pgm) {
+ if (mark_as_selected(row, isSelected)) {
const uint8_t vallen = (pgm ? utf8_strlen_P(data) : utf8_strlen((char*)data));
uint8_t n = LCD_WIDTH - (START_COL) - 2 - vallen;
n *= DOG_CHAR_WIDTH;
@@ -477,14 +348,7 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop
}
}
- // Macros for edit items
- #define lcd_implementation_drawmenu_setting_edit_generic(sel, row, pstr, data) _drawmenu_setting_edit_generic(sel, row, pstr, data, false)
- #define lcd_implementation_drawmenu_setting_edit_generic_P(sel, row, pstr, data) _drawmenu_setting_edit_generic(sel, row, pstr, data, true)
-
- #define DRAWMENU_SETTING_EDIT_GENERIC(_src) lcd_implementation_drawmenu_setting_edit_generic(sel, row, pstr, _src)
- #define DRAW_BOOL_SETTING(sel, row, pstr, data) lcd_implementation_drawmenu_setting_edit_generic_P(sel, row, pstr, (*(data))?PSTR(MSG_ON):PSTR(MSG_OFF))
-
- void lcd_implementation_drawedit(PGM_P const pstr, const char* const value=NULL) {
+ void lcd_implementation_drawedit(PGM_P const pstr, const char* const value/*=NULL*/) {
const uint8_t labellen = utf8_strlen_P(pstr),
vallen = utf8_strlen(value);
@@ -536,10 +400,10 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop
#if ENABLED(SDSUPPORT)
- static void _drawmenu_sd(const bool isSelected, const uint8_t row, PGM_P const pstr, CardReader &theCard, const bool isDir) {
+ void _drawmenu_sd(const bool isSelected, const uint8_t row, PGM_P const pstr, CardReader &theCard, const bool isDir) {
UNUSED(pstr);
- lcd_implementation_mark_as_selected(row, isSelected);
+ mark_as_selected(row, isSelected);
if (!PAGE_CONTAINS(row_y1, row_y2)) return;
@@ -547,6 +411,7 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop
const char *outstr = theCard.longest_filename();
if (theCard.longFilename[0]) {
#if ENABLED(SCROLL_LONG_FILENAMES)
+ static uint8_t filename_scroll_hash;
if (isSelected) {
uint8_t name_hash = row;
for (uint8_t l = FILENAME_LENGTH; l--;)
@@ -572,9 +437,6 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop
while (n - DOG_CHAR_WIDTH > 0) { n -= lcd_put_wchar(' '); }
}
- #define lcd_implementation_drawmenu_sdfile(sel, row, pstr, theCard) _drawmenu_sd(sel, row, pstr, theCard, false)
- #define lcd_implementation_drawmenu_sddirectory(sel, row, pstr, theCard) _drawmenu_sd(sel, row, pstr, theCard, true)
-
#endif // SDSUPPORT
#if ENABLED(AUTO_BED_LEVELING_UBL)
@@ -666,6 +528,133 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop
#endif // AUTO_BED_LEVELING_UBL
+ #if ENABLED(BABYSTEP_ZPROBE_GFX_OVERLAY) || ENABLED(MESH_EDIT_GFX_OVERLAY)
+
+ const unsigned char cw_bmp[] PROGMEM = {
+ B00000011,B11111000,B00000000,
+ B00001111,B11111110,B00000000,
+ B00011110,B00001111,B00000000,
+ B00111000,B00000111,B00000000,
+ B00111000,B00000011,B10000000,
+ B01110000,B00000011,B10000000,
+ B01110000,B00001111,B11100000,
+ B01110000,B00000111,B11000000,
+ B01110000,B00000011,B10000000,
+ B01110000,B00000001,B00000000,
+ B01110000,B00000000,B00000000,
+ B00111000,B00000000,B00000000,
+ B00111000,B00000111,B00000000,
+ B00011110,B00001111,B00000000,
+ B00001111,B11111110,B00000000,
+ B00000011,B11111000,B00000000
+ };
+
+ const unsigned char ccw_bmp[] PROGMEM = {
+ B00000000,B11111110,B00000000,
+ B00000011,B11111111,B10000000,
+ B00000111,B10000011,B11000000,
+ B00001110,B00000001,B11000000,
+ B00001110,B00000000,B11100000,
+ B00011100,B00000000,B11100000,
+ B01111111,B00000000,B11100000,
+ B00111110,B00000000,B11100000,
+ B00011100,B00000000,B11100000,
+ B00001000,B00000000,B11100000,
+ B00000000,B00000000,B11100000,
+ B00000000,B00000001,B11000000,
+ B00001110,B00000001,B11000000,
+ B00001111,B00000111,B10000000,
+ B00000111,B11111111,B00000000,
+ B00000001,B11111100,B00000000
+ };
+
+ const unsigned char up_arrow_bmp[] PROGMEM = {
+ B00000100,B00000000,
+ B00001110,B00000000,
+ B00011111,B00000000,
+ B00111111,B10000000,
+ B01111111,B11000000,
+ B00001110,B00000000,
+ B00001110,B00000000,
+ B00001110,B00000000,
+ B00001110,B00000000,
+ B00001110,B00000000,
+ B00001110,B00000000,
+ B00001110,B00000000,
+ B00001110,B00000000
+ };
+
+ const unsigned char down_arrow_bmp[] PROGMEM = {
+ B00001110,B00000000,
+ B00001110,B00000000,
+ B00001110,B00000000,
+ B00001110,B00000000,
+ B00001110,B00000000,
+ B00001110,B00000000,
+ B00001110,B00000000,
+ B00001110,B00000000,
+ B01111111,B11000000,
+ B00111111,B10000000,
+ B00011111,B00000000,
+ B00001110,B00000000,
+ B00000100,B00000000
+ };
+
+ const unsigned char offset_bedline_bmp[] PROGMEM = {
+ B11111111,B11111111,B11111111
+ };
+
+ const unsigned char nozzle_bmp[] PROGMEM = {
+ B01111111,B10000000,
+ B11111111,B11000000,
+ B11111111,B11000000,
+ B11111111,B11000000,
+ B01111111,B10000000,
+ B01111111,B10000000,
+ B11111111,B11000000,
+ B11111111,B11000000,
+ B11111111,B11000000,
+ B00111111,B00000000,
+ B00011110,B00000000,
+ B00001100,B00000000
+ };
+
+ void _lcd_zoffset_overlay_gfx(const float zvalue) {
+ // Determine whether the user is raising or lowering the nozzle.
+ static int8_t dir;
+ static float old_zvalue;
+ if (zvalue != old_zvalue) {
+ dir = zvalue ? zvalue < old_zvalue ? -1 : 1 : 0;
+ old_zvalue = zvalue;
+ }
+
+ #if ENABLED(OVERLAY_GFX_REVERSE)
+ const unsigned char *rot_up = ccw_bmp, *rot_down = cw_bmp;
+ #else
+ const unsigned char *rot_up = cw_bmp, *rot_down = ccw_bmp;
+ #endif
+
+ #if ENABLED(USE_BIG_EDIT_FONT)
+ const int left = 0, right = 45, nozzle = 95;
+ #else
+ const int left = 5, right = 90, nozzle = 60;
+ #endif
+
+ // Draw a representation of the nozzle
+ if (PAGE_CONTAINS(3, 16)) u8g.drawBitmapP(nozzle + 6, 4 - dir, 2, 12, nozzle_bmp);
+ if (PAGE_CONTAINS(20, 20)) u8g.drawBitmapP(nozzle + 0, 20, 3, 1, offset_bedline_bmp);
+
+ // Draw cw/ccw indicator and up/down arrows.
+ if (PAGE_CONTAINS(47, 62)) {
+ u8g.drawBitmapP(left + 0, 47, 3, 16, rot_down);
+ u8g.drawBitmapP(right + 0, 47, 3, 16, rot_up);
+ u8g.drawBitmapP(right + 20, 48 - dir, 2, 13, up_arrow_bmp);
+ u8g.drawBitmapP(left + 20, 49 - dir, 2, 13, down_arrow_bmp);
+ }
+ }
+
+ #endif // BABYSTEP_ZPROBE_GFX_OVERLAY || MESH_EDIT_GFX_OVERLAY
+
#endif // ULTIPANEL
-#endif // __ULTRALCD_IMPL_DOGM_H
+#endif // HAS_GRAPHICAL_LCD
diff --git a/Marlin/src/lcd/fontutils.h b/Marlin/src/lcd/fontutils.h
index 62c1471d8d..183c8ed399 100644
--- a/Marlin/src/lcd/fontutils.h
+++ b/Marlin/src/lcd/fontutils.h
@@ -6,8 +6,7 @@
* @date 2016-08-19
* @copyright GPL/BSD
*/
-#ifndef _FONT_UTILS_H
-#define _FONT_UTILS_H
+#pragma once
#include
#include
@@ -45,5 +44,3 @@ uint8_t* get_utf8_value_cb(uint8_t *pstart, read_byte_cb_t cb_read_byte, wchar_t
/* Returns lenght of string in CHARACTERS, NOT BYTES */
uint8_t utf8_strlen(const char *pstart);
uint8_t utf8_strlen_P(PGM_P pstart);
-
-#endif // _FONT_UTILS_H
diff --git a/Marlin/src/lcd/language/language_zh_CN.h b/Marlin/src/lcd/language/language_zh_CN.h
index d61cbc2909..16c932032b 100644
--- a/Marlin/src/lcd/language/language_zh_CN.h
+++ b/Marlin/src/lcd/language/language_zh_CN.h
@@ -30,8 +30,6 @@
#ifndef LANGUAGE_ZH_CN_H
#define LANGUAGE_ZH_CN_H
-//#define TALL_FONT_CORRECTION (1)
-
#define CHARSIZE 3
#define WELCOME_MSG MACHINE_NAME _UxGT("已就绪.") //" ready."
@@ -229,7 +227,7 @@
#define MSG_E6STEPS _UxGT("挤出机6步数/mm") //"E6steps/mm"
#define MSG_TEMPERATURE _UxGT("温度") //"Temperature"
#define MSG_MOTION _UxGT("运动") //"Motion"
-#define MSG_FILAMENT _UxGT("丝料测容") //"Filament" lcd_control_volumetric_menu
+#define MSG_FILAMENT _UxGT("丝料测容") //"Filament" menu_advanced_filament
#define MSG_VOLUMETRIC_ENABLED _UxGT("测容积mm³") //"E in mm3" volumetric_enabled
#define MSG_FILAMENT_DIAM _UxGT("丝料直径") //"Fil. Dia."
#define MSG_FILAMENT_UNLOAD _UxGT("卸载 mm") // "Unload mm"
diff --git a/Marlin/src/lcd/language/language_zh_TW.h b/Marlin/src/lcd/language/language_zh_TW.h
index 1116a9eab1..ff2d690650 100644
--- a/Marlin/src/lcd/language/language_zh_TW.h
+++ b/Marlin/src/lcd/language/language_zh_TW.h
@@ -30,8 +30,6 @@
#ifndef LANGUAGE_ZH_TW_H
#define LANGUAGE_ZH_TW_H
-//#define TALL_FONT_CORRECTION (1)
-
#define CHARSIZE 3
#define WELCOME_MSG MACHINE_NAME _UxGT("已就緒.") //" ready."
@@ -229,7 +227,7 @@
#define MSG_E6STEPS _UxGT("擠出機6步數/mm") //"E6steps/mm"
#define MSG_TEMPERATURE _UxGT("溫度") //"Temperature"
#define MSG_MOTION _UxGT("運作") //"Motion"
-#define MSG_FILAMENT _UxGT("絲料測容") //"Filament" lcd_control_volumetric_menu
+#define MSG_FILAMENT _UxGT("絲料測容") //"Filament" menu_control_volumetric
#define MSG_VOLUMETRIC_ENABLED _UxGT("測容積mm³") //"E in mm3" volumetric_enabled
#define MSG_FILAMENT_DIAM _UxGT("絲料直徑") //"Fil. Dia."
#define MSG_FILAMENT_UNLOAD _UxGT("卸載 mm") // "Unload mm"
diff --git a/Marlin/src/lcd/lcdprint.h b/Marlin/src/lcd/lcdprint.h
index 47f14a5aea..b7366aff89 100644
--- a/Marlin/src/lcd/lcdprint.h
+++ b/Marlin/src/lcd/lcdprint.h
@@ -6,15 +6,16 @@
* @date 2016-08-19
* @copyright GPL/BSD
*/
-#ifndef _LCDPRINT_H
-#define _LCDPRINT_H
+#pragma once
#include "fontutils.h"
-#if DISABLED(DOGLCD)
- #define _UxGT(a) a
+#include "../inc/MarlinConfigPre.h"
+
+#if HAS_GRAPHICAL_LCD
+ #include "dogm/u8g_fontutf8.h"
#else
- #include "u8g_fontutf8.h"
+ #define _UxGT(a) a
#endif
#define START_OF_UTF8_CHAR(C) (((C) & 0xC0u) != 0x80u)
@@ -54,5 +55,3 @@ inline int lcd_put_u8str_P(PGM_P str) { return lcd_put_u8str_max_P(str, PIXEL_LE
inline int lcd_put_u8str(const char* str) { return lcd_put_u8str_max(str, PIXEL_LEN_NOLIMIT); }
inline int lcd_put_wchar(wchar_t c) { return lcd_put_wchar_max(c, PIXEL_LEN_NOLIMIT); }
-
-#endif // _LCDPRINT_H
diff --git a/Marlin/src/lcd/menu/menu.cpp b/Marlin/src/lcd/menu/menu.cpp
new file mode 100644
index 0000000000..181d067333
--- /dev/null
+++ b/Marlin/src/lcd/menu/menu.cpp
@@ -0,0 +1,479 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if ENABLED(ULTIPANEL)
+
+#include "menu.h"
+#include "../ultralcd.h"
+#include "../../module/planner.h"
+#include "../../module/motion.h"
+#include "../../gcode/queue.h"
+#include "../../sd/cardreader.h"
+
+#if ENABLED(EEPROM_SETTINGS)
+ #include "../../module/configuration_store.h"
+#endif
+
+#if WATCH_HOTENDS || WATCH_THE_BED
+ #include "../../module/temperature.h"
+#endif
+
+#if ENABLED(BABYSTEP_ZPROBE_OFFSET)
+ #include "../../module/probe.h"
+#endif
+
+#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT) || ENABLED(AUTO_BED_LEVELING_UBL)
+ #include "../../feature/bedlevel/bedlevel.h"
+#endif
+
+////////////////////////////////////////////
+///////////// Global Variables /////////////
+////////////////////////////////////////////
+
+// Menu Navigation
+int8_t encoderTopLine;
+typedef struct {
+ screenFunc_t menu_function;
+ uint32_t encoder_position;
+} menuPosition;
+menuPosition screen_history[6];
+uint8_t screen_history_depth = 0;
+bool screen_changed, defer_return_to_status;
+
+// Value Editing
+PGM_P editLabel;
+void *editValue;
+int32_t minEditValue, maxEditValue;
+screenFunc_t callbackFunc;
+bool liveEdit;
+
+// Prevent recursion into screen handlers
+bool no_reentry = false;
+
+////////////////////////////////////////////
+//////// Menu Navigation & History /////////
+////////////////////////////////////////////
+
+void lcd_status_screen();
+
+void lcd_return_to_status() { lcd_goto_screen(lcd_status_screen); }
+
+void lcd_save_previous_screen() {
+ if (screen_history_depth < COUNT(screen_history)) {
+ screen_history[screen_history_depth].menu_function = currentScreen;
+ screen_history[screen_history_depth].encoder_position = encoderPosition;
+ ++screen_history_depth;
+ }
+}
+
+void lcd_goto_previous_menu() {
+ if (screen_history_depth > 0) {
+ --screen_history_depth;
+ lcd_goto_screen(
+ screen_history[screen_history_depth].menu_function,
+ screen_history[screen_history_depth].encoder_position
+ );
+ }
+ else
+ lcd_return_to_status();
+}
+
+void lcd_goto_previous_menu_no_defer() {
+ defer_return_to_status = false;
+ lcd_goto_previous_menu();
+}
+
+////////////////////////////////////////////
+/////////// Common Menu Actions ////////////
+////////////////////////////////////////////
+
+void _menu_action_back() { lcd_goto_previous_menu(); }
+void menu_action_submenu(screenFunc_t func) { lcd_save_previous_screen(); lcd_goto_screen(func); }
+void menu_action_gcode(PGM_P pgcode) { enqueue_and_echo_commands_P(pgcode); }
+void menu_action_function(screenFunc_t func) { (*func)(); }
+
+////////////////////////////////////////////
+/////////// Menu Editing Actions ///////////
+////////////////////////////////////////////
+
+/**
+ * Functions for editing single values
+ *
+ * The "DEFINE_MENU_EDIT_TYPE" macro generates the functions needed to edit a numerical value.
+ *
+ * For example, DEFINE_MENU_EDIT_TYPE(int16_t, int3, itostr3, 1) expands into these functions:
+ *
+ * bool _menu_edit_int3();
+ * void menu_edit_int3(); // edit int16_t (interactively)
+ * void menu_edit_callback_int3(); // edit int16_t (interactively) with callback on completion
+ * void _menu_action_setting_edit_int3(PGM_P const pstr, int16_t * const ptr, const int16_t minValue, const int16_t maxValue);
+ * void menu_action_setting_edit_int3(PGM_P const pstr, int16_t * const ptr, const int16_t minValue, const int16_t maxValue);
+ * void menu_action_setting_edit_callback_int3(PGM_P const pstr, int16_t * const ptr, const int16_t minValue, const int16_t maxValue, const screenFunc_t callback, const bool live); // edit int16_t with callback
+ *
+ * You can then use one of the menu macros to present the edit interface:
+ * MENU_ITEM_EDIT(int3, MSG_SPEED, &feedrate_percentage, 10, 999)
+ *
+ * This expands into a more primitive menu item:
+ * MENU_ITEM(setting_edit_int3, MSG_SPEED, PSTR(MSG_SPEED), &feedrate_percentage, 10, 999)
+ *
+ * ...which calls:
+ * menu_action_setting_edit_int3(PSTR(MSG_SPEED), &feedrate_percentage, 10, 999)
+ */
+#define DEFINE_MENU_EDIT_TYPE(TYPE, NAME, STRFUNC, SCALE) \
+ bool _menu_edit_ ## NAME() { \
+ ENCODER_DIRECTION_NORMAL(); \
+ if ((int32_t)encoderPosition < 0) encoderPosition = 0; \
+ if ((int32_t)encoderPosition > maxEditValue) encoderPosition = maxEditValue; \
+ if (lcdDrawUpdate) \
+ lcd_implementation_drawedit(editLabel, STRFUNC(((TYPE)((int32_t)encoderPosition + minEditValue)) * (1.0f / SCALE))); \
+ if (lcd_clicked || (liveEdit && lcdDrawUpdate)) { \
+ TYPE value = ((TYPE)((int32_t)encoderPosition + minEditValue)) * (1.0f / SCALE); \
+ if (editValue != NULL) *((TYPE*)editValue) = value; \
+ if (callbackFunc && (liveEdit || lcd_clicked)) (*callbackFunc)(); \
+ if (lcd_clicked) lcd_goto_previous_menu(); \
+ } \
+ return use_click(); \
+ } \
+ void menu_edit_ ## NAME() { _menu_edit_ ## NAME(); } \
+ void _menu_action_setting_edit_ ## NAME(PGM_P const pstr, TYPE* const ptr, const TYPE minValue, const TYPE maxValue) { \
+ lcd_save_previous_screen(); \
+ lcd_refresh(); \
+ \
+ editLabel = pstr; \
+ editValue = ptr; \
+ minEditValue = minValue * SCALE; \
+ maxEditValue = maxValue * SCALE - minEditValue; \
+ encoderPosition = (*ptr) * SCALE - minEditValue; \
+ } \
+ void menu_action_setting_edit_callback_ ## NAME(PGM_P const pstr, TYPE * const ptr, const TYPE minValue, const TYPE maxValue, const screenFunc_t callback/*=NULL*/, const bool live/*=false*/) { \
+ _menu_action_setting_edit_ ## NAME(pstr, ptr, minValue, maxValue); \
+ currentScreen = menu_edit_ ## NAME; \
+ callbackFunc = callback; \
+ liveEdit = live; \
+ } \
+ typedef void NAME##_void
+
+DEFINE_MENU_EDIT_TYPE(int16_t, int3, itostr3, 1);
+DEFINE_MENU_EDIT_TYPE(int16_t, int4, itostr4sign, 1);
+DEFINE_MENU_EDIT_TYPE(uint8_t, int8, i8tostr3, 1);
+DEFINE_MENU_EDIT_TYPE(float, float3, ftostr3, 1);
+DEFINE_MENU_EDIT_TYPE(float, float52, ftostr52, 100);
+DEFINE_MENU_EDIT_TYPE(float, float43, ftostr43sign, 1000);
+DEFINE_MENU_EDIT_TYPE(float, float5, ftostr5rj, 0.01f);
+DEFINE_MENU_EDIT_TYPE(float, float51, ftostr51sign, 10);
+DEFINE_MENU_EDIT_TYPE(float, float52sign, ftostr52sign, 100);
+DEFINE_MENU_EDIT_TYPE(float, float62, ftostr62rj, 100);
+DEFINE_MENU_EDIT_TYPE(uint32_t, long5, ftostr5rj, 0.01f);
+
+void menu_action_setting_edit_bool(PGM_P pstr, bool* ptr) { UNUSED(pstr); *ptr ^= true; lcd_refresh(); }
+void menu_action_setting_edit_callback_bool(PGM_P pstr, bool* ptr, screenFunc_t callback) {
+ menu_action_setting_edit_bool(pstr, ptr);
+ (*callback)();
+}
+
+////////////////////////////////////////////
+///////////////// Menu Tree ////////////////
+////////////////////////////////////////////
+
+#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
+ float lcd_z_fade_height;
+ void _lcd_set_z_fade_height() { set_z_fade_height(lcd_z_fade_height); }
+#endif
+
+bool printer_busy() { return planner.movesplanned() || IS_SD_PRINTING(); }
+
+#if HAS_CHARACTER_LCD && (ENABLED(LCD_PROGRESS_BAR) || ENABLED(LCD_PROGRESS_BAR_TEST) || ENABLED(AUTO_BED_LEVELING_UBL))
+ void lcd_set_custom_characters(
+ #if ENABLED(LCD_PROGRESS_BAR) || ENABLED(SHOW_BOOTSCREEN)
+ const uint8_t screen_charset=CHARSET_INFO
+ #endif
+ );
+#endif
+
+/**
+ * General function to go directly to a screen
+ */
+void lcd_goto_screen(screenFunc_t screen, const uint32_t encoder/*=0*/) {
+ if (currentScreen != screen) {
+
+ #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
+ // Shadow for editing the fade height
+ lcd_z_fade_height = planner.z_fade_height;
+ #endif
+
+ #if ENABLED(DOUBLECLICK_FOR_Z_BABYSTEPPING) && ENABLED(BABYSTEPPING)
+ static millis_t doubleclick_expire_ms = 0;
+ // Going to menu_main from status screen? Remember first click time.
+ // Going back to status screen within a very short time? Go to Z babystepping.
+ if (screen == menu_main) {
+ if (currentScreen == lcd_status_screen)
+ doubleclick_expire_ms = millis() + DOUBLECLICK_MAX_INTERVAL;
+ }
+ else if (screen == lcd_status_screen && currentScreen == menu_main && PENDING(millis(), doubleclick_expire_ms)) {
+ if (printer_busy()) {
+ screen =
+ #if ENABLED(BABYSTEP_ZPROBE_OFFSET)
+ lcd_babystep_zoffset
+ #else
+ lcd_babystep_z
+ #endif
+ ;
+ }
+ #if ENABLED(MOVE_Z_WHEN_IDLE)
+ else {
+ move_menu_scale = MOVE_Z_IDLE_MULTIPLICATOR;
+ screen = lcd_move_z;
+ }
+ #endif
+ }
+ #endif
+
+ currentScreen = screen;
+ encoderPosition = encoder;
+ if (screen == lcd_status_screen) {
+ defer_return_to_status = false;
+ #if ENABLED(AUTO_BED_LEVELING_UBL)
+ ubl.lcd_map_control = false;
+ #endif
+ screen_history_depth = 0;
+ }
+ lcd_implementation_clear();
+ // Re-initialize custom characters that may be re-used
+ #if HAS_CHARACTER_LCD && ENABLED(AUTO_BED_LEVELING_UBL)
+ if (!ubl.lcd_map_control) {
+ lcd_set_custom_characters(
+ #if ENABLED(LCD_PROGRESS_BAR)
+ screen == lcd_status_screen ? CHARSET_INFO : CHARSET_MENU
+ #endif
+ );
+ }
+ #elif ENABLED(LCD_PROGRESS_BAR)
+ lcd_set_custom_characters(screen == lcd_status_screen ? CHARSET_INFO : CHARSET_MENU);
+ #endif
+ lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NEXT;
+ screen_changed = true;
+ #if HAS_GRAPHICAL_LCD
+ drawing_screen = false;
+ #endif
+ }
+}
+
+////////////////////////////////////////////
+///////////// Manual Movement //////////////
+////////////////////////////////////////////
+
+//
+// Display the synchronize screen until moves are
+// finished, and don't return to the caller until
+// done. ** This blocks the command queue! **
+//
+static PGM_P sync_message;
+
+void _lcd_synchronize() {
+ if (lcdDrawUpdate) lcd_implementation_drawmenu_static(LCD_HEIGHT >= 4 ? 1 : 0, sync_message);
+ if (no_reentry) return;
+ // Make this the current handler till all moves are done
+ no_reentry = true;
+ const screenFunc_t old_screen = currentScreen;
+ lcd_goto_screen(_lcd_synchronize);
+ planner.synchronize(); // idle() is called until moves complete
+ no_reentry = false;
+ lcd_goto_screen(old_screen);
+}
+
+// Display the synchronize screen with a custom message
+// ** This blocks the command queue! **
+void lcd_synchronize(PGM_P const msg/*=NULL*/) {
+ static const char moving[] PROGMEM = MSG_MOVING;
+ sync_message = msg ? msg : moving;
+ _lcd_synchronize();
+}
+
+/**
+ * Scrolling for menus and other line-based screens
+ *
+ * encoderLine is the position based on the encoder
+ * encoderTopLine is the top menu line to display
+ * _lcdLineNr is the index of the LCD line (e.g., 0-3)
+ * _menuLineNr is the menu item to draw and process
+ * _thisItemNr is the index of each MENU_ITEM or STATIC_ITEM
+ * screen_items is the total number of items in the menu (after one call)
+ */
+int8_t encoderLine, screen_items;
+void scroll_screen(const uint8_t limit, const bool is_menu) {
+ ENCODER_DIRECTION_MENUS();
+ ENCODER_RATE_MULTIPLY(false);
+ if (encoderPosition > 0x8000) encoderPosition = 0;
+ if (first_page) {
+ encoderLine = encoderPosition / (ENCODER_STEPS_PER_MENU_ITEM);
+ screen_changed = false;
+ }
+ if (screen_items > 0 && encoderLine >= screen_items - limit) {
+ encoderLine = MAX(0, screen_items - limit);
+ encoderPosition = encoderLine * (ENCODER_STEPS_PER_MENU_ITEM);
+ }
+ if (is_menu) {
+ NOMORE(encoderTopLine, encoderLine);
+ if (encoderLine >= encoderTopLine + LCD_HEIGHT)
+ encoderTopLine = encoderLine - LCD_HEIGHT + 1;
+ }
+ else
+ encoderTopLine = encoderLine;
+}
+
+void lcd_completion_feedback(const bool good/*=true*/) {
+ if (good) {
+ lcd_buzz(100, 659);
+ lcd_buzz(100, 698);
+ }
+ else lcd_buzz(20, 440);
+}
+
+#if HAS_LINE_TO_Z
+
+ void line_to_z(const float &z) {
+ current_position[Z_AXIS] = z;
+ planner.buffer_line(current_position, MMM_TO_MMS(manual_feedrate_mm_m[Z_AXIS]), active_extruder);
+ }
+
+#endif
+
+#if ENABLED(BABYSTEP_ZPROBE_OFFSET)
+
+ void lcd_babystep_zoffset() {
+ if (use_click()) { return lcd_goto_previous_menu_no_defer(); }
+ defer_return_to_status = true;
+ #if ENABLED(BABYSTEP_HOTEND_Z_OFFSET)
+ const bool do_probe = (active_extruder == 0);
+ #else
+ constexpr bool do_probe = true;
+ #endif
+ ENCODER_DIRECTION_NORMAL();
+ if (encoderPosition) {
+ const int16_t babystep_increment = (int32_t)encoderPosition * (BABYSTEP_MULTIPLICATOR);
+ encoderPosition = 0;
+
+ const float diff = planner.steps_to_mm[Z_AXIS] * babystep_increment,
+ new_probe_offset = zprobe_zoffset + diff,
+ new_offs =
+ #if ENABLED(BABYSTEP_HOTEND_Z_OFFSET)
+ do_probe ? new_probe_offset : hotend_offset[Z_AXIS][active_extruder] - diff
+ #else
+ new_probe_offset
+ #endif
+ ;
+ if (WITHIN(new_offs, Z_PROBE_OFFSET_RANGE_MIN, Z_PROBE_OFFSET_RANGE_MAX)) {
+
+ thermalManager.babystep_axis(Z_AXIS, babystep_increment);
+
+ if (do_probe) zprobe_zoffset = new_offs;
+ #if ENABLED(BABYSTEP_HOTEND_Z_OFFSET)
+ else hotend_offset[Z_AXIS][active_extruder] = new_offs;
+ #endif
+
+ lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NEXT;
+ }
+ }
+ if (lcdDrawUpdate) {
+ #if ENABLED(BABYSTEP_HOTEND_Z_OFFSET)
+ if (!do_probe)
+ lcd_implementation_drawedit(PSTR(MSG_IDEX_Z_OFFSET), ftostr43sign(hotend_offset[Z_AXIS][active_extruder]));
+ else
+ #endif
+ lcd_implementation_drawedit(PSTR(MSG_ZPROBE_ZOFFSET), ftostr43sign(zprobe_zoffset));
+
+ #if ENABLED(BABYSTEP_ZPROBE_GFX_OVERLAY)
+ if (do_probe) _lcd_zoffset_overlay_gfx(zprobe_zoffset);
+ #endif
+ }
+ }
+
+#endif // BABYSTEP_ZPROBE_OFFSET
+
+/**
+ * Watch temperature callbacks
+ */
+#if HAS_TEMP_HOTEND
+ #if WATCH_HOTENDS
+ #define _WATCH_FUNC(N) thermalManager.start_watching_heater(N)
+ #else
+ #define _WATCH_FUNC(N) NOOP
+ #endif
+ void watch_temp_callback_E0() { _WATCH_FUNC(0); }
+ #if HOTENDS > 1
+ void watch_temp_callback_E1() { _WATCH_FUNC(1); }
+ #if HOTENDS > 2
+ void watch_temp_callback_E2() { _WATCH_FUNC(2); }
+ #if HOTENDS > 3
+ void watch_temp_callback_E3() { _WATCH_FUNC(3); }
+ #if HOTENDS > 4
+ void watch_temp_callback_E4() { _WATCH_FUNC(4); }
+ #if HOTENDS > 5
+ void watch_temp_callback_E5() { _WATCH_FUNC(5); }
+ #endif // HOTENDS > 5
+ #endif // HOTENDS > 4
+ #endif // HOTENDS > 3
+ #endif // HOTENDS > 2
+ #endif // HOTENDS > 1
+#endif // HAS_TEMP_HOTEND
+
+void watch_temp_callback_bed() {
+ #if WATCH_THE_BED
+ thermalManager.start_watching_bed();
+ #endif
+}
+
+#if ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(PID_AUTOTUNE_MENU) || ENABLED(ADVANCED_PAUSE_FEATURE)
+
+ void lcd_enqueue_command(const char * const cmd) {
+ no_reentry = true;
+ enqueue_and_echo_command_now(cmd);
+ no_reentry = false;
+ }
+
+ void lcd_enqueue_commands_P(PGM_P const cmd) {
+ no_reentry = true;
+ enqueue_and_echo_commands_now_P(cmd);
+ no_reentry = false;
+ }
+
+#endif
+
+#if ENABLED(EEPROM_SETTINGS)
+ void lcd_store_settings() { lcd_completion_feedback(settings.save()); }
+ void lcd_load_settings() { lcd_completion_feedback(settings.load()); }
+#endif
+
+void _lcd_draw_homing() {
+ constexpr uint8_t line = (LCD_HEIGHT - 1) / 2;
+ if (lcdDrawUpdate) lcd_implementation_drawmenu_static(line, PSTR(MSG_LEVEL_BED_HOMING));
+ lcdDrawUpdate = LCDVIEW_CALL_NO_REDRAW;
+}
+
+#if ENABLED(LCD_BED_LEVELING) || (HAS_LEVELING && DISABLED(SLIM_LCD_MENUS))
+ #include "../../feature/bedlevel/bedlevel.h"
+ void _lcd_toggle_bed_leveling() { set_bed_leveling_enabled(!planner.leveling_active); }
+#endif
+
+#endif // ULTIPANEL
diff --git a/Marlin/src/lcd/menu/menu.h b/Marlin/src/lcd/menu/menu.h
new file mode 100644
index 0000000000..fbbb00392b
--- /dev/null
+++ b/Marlin/src/lcd/menu/menu.h
@@ -0,0 +1,396 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+#pragma once
+
+#include "../ultralcd.h"
+#include "../../inc/MarlinConfig.h"
+
+extern uint32_t encoderPosition;
+extern int8_t encoderLine, encoderTopLine, screen_items;
+extern millis_t lastEncoderMovementMillis;
+extern bool screen_changed;
+
+constexpr int16_t heater_maxtemp[HOTENDS] = ARRAY_BY_HOTENDS(HEATER_0_MAXTEMP, HEATER_1_MAXTEMP, HEATER_2_MAXTEMP, HEATER_3_MAXTEMP, HEATER_4_MAXTEMP);
+
+void scroll_screen(const uint8_t limit, const bool is_menu);
+bool use_click();
+bool printer_busy();
+void lcd_completion_feedback(const bool good=true);
+void lcd_goto_previous_menu();
+void lcd_goto_previous_menu_no_defer();
+
+////////////////////////////////////////////
+///////// Menu Item Draw Functions /////////
+////////////////////////////////////////////
+
+#if ENABLED(SDSUPPORT)
+ class CardReader;
+#endif
+
+void lcd_implementation_drawmenu_generic(const bool isSelected, const uint8_t row, const char* pstr, const char pre_char, const char post_char);
+void lcd_implementation_drawmenu_static(const uint8_t row, const char* pstr, const bool center=true, const bool invert=false, const char *valstr=NULL);
+void lcd_implementation_drawedit(const char* const pstr, const char* const value=NULL);
+#if ENABLED(ADVANCED_PAUSE_FEATURE)
+ void lcd_implementation_hotend_status(const uint8_t row, const uint8_t extruder);
+#endif
+#if HAS_GRAPHICAL_LCD
+ void _drawmenu_setting_edit_generic(const bool isSelected, const uint8_t row, const char* pstr, const char* const data, const bool pgm);
+ #define lcd_implementation_drawmenu_back(sel, row, pstr, dummy) lcd_implementation_drawmenu_generic(sel, row, pstr, LCD_STR_UPLEVEL[0], LCD_STR_UPLEVEL[0])
+ #define lcd_implementation_drawmenu_setting_edit_generic(sel, row, pstr, data) _drawmenu_setting_edit_generic(sel, row, pstr, data, false)
+ #define lcd_implementation_drawmenu_setting_edit_generic_P(sel, row, pstr, data) _drawmenu_setting_edit_generic(sel, row, pstr, data, true)
+ #define DRAWMENU_SETTING_EDIT_GENERIC(SRC) lcd_implementation_drawmenu_setting_edit_generic(sel, row, pstr, SRC)
+ #define DRAW_BOOL_SETTING(sel, row, pstr, data) lcd_implementation_drawmenu_setting_edit_generic_P(sel, row, pstr, (*(data))?PSTR(MSG_ON):PSTR(MSG_OFF))
+ #if ENABLED(SDSUPPORT)
+ void _drawmenu_sd(const bool isSelected, const uint8_t row, PGM_P const pstr, CardReader &theCard, const bool isDir);
+ #define lcd_implementation_drawmenu_sdfile(sel, row, pstr, theCard) _drawmenu_sd(sel, row, pstr, theCard, false)
+ #define lcd_implementation_drawmenu_sddirectory(sel, row, pstr, theCard) _drawmenu_sd(sel, row, pstr, theCard, true)
+ #endif
+ #if ENABLED(BABYSTEP_ZPROBE_GFX_OVERLAY) || ENABLED(MESH_EDIT_GFX_OVERLAY)
+ void _lcd_zoffset_overlay_gfx(const float zvalue);
+ #endif
+#else
+ #define lcd_implementation_drawmenu_back(sel, row, pstr, dummy) lcd_implementation_drawmenu_generic(sel, row, pstr, LCD_UPLEVEL_CHAR, LCD_UPLEVEL_CHAR)
+ void lcd_implementation_drawmenu_setting_edit_generic(const bool sel, const uint8_t row, const char* pstr, const char pre_char, const char* const data);
+ void lcd_implementation_drawmenu_setting_edit_generic_P(const bool sel, const uint8_t row, const char* pstr, const char pre_char, const char* const data);
+ #define DRAWMENU_SETTING_EDIT_GENERIC(SRC) lcd_implementation_drawmenu_setting_edit_generic(sel, row, pstr, '>', SRC)
+ #define DRAW_BOOL_SETTING(sel, row, pstr, data) lcd_implementation_drawmenu_setting_edit_generic_P(sel, row, pstr, '>', (*(data))?PSTR(MSG_ON):PSTR(MSG_OFF))
+ #if ENABLED(SDSUPPORT)
+ void lcd_implementation_drawmenu_sdfile(const bool sel, const uint8_t row, PGM_P pstr, CardReader &theCard);
+ void lcd_implementation_drawmenu_sddirectory(const bool sel, const uint8_t row, PGM_P pstr, CardReader &theCard);
+ #endif
+#endif
+#define lcd_implementation_drawmenu_submenu(sel, row, pstr, data) lcd_implementation_drawmenu_generic(sel, row, pstr, '>', LCD_STR_ARROW_RIGHT[0])
+#define lcd_implementation_drawmenu_gcode(sel, row, pstr, gcode) lcd_implementation_drawmenu_generic(sel, row, pstr, '>', ' ')
+#define lcd_implementation_drawmenu_function(sel, row, pstr, data) lcd_implementation_drawmenu_generic(sel, row, pstr, '>', ' ')
+
+#if ENABLED(AUTO_BED_LEVELING_UBL)
+ void lcd_implementation_ubl_plot(const uint8_t x, const uint8_t inverted_y);
+#endif
+
+////////////////////////////////////////////
+/////// Edit Setting Draw Functions ////////
+////////////////////////////////////////////
+
+#define DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(TYPE, NAME, STRFUNC) \
+ FORCE_INLINE void lcd_implementation_drawmenu_setting_edit_ ## NAME (const bool sel, const uint8_t row, PGM_P pstr, PGM_P pstr2, TYPE * const data, ...) { \
+ UNUSED(pstr2); \
+ DRAWMENU_SETTING_EDIT_GENERIC(STRFUNC(*(data))); \
+ } \
+ FORCE_INLINE void lcd_implementation_drawmenu_setting_edit_callback_ ## NAME (const bool sel, const uint8_t row, PGM_P pstr, PGM_P pstr2, TYPE * const data, ...) { \
+ UNUSED(pstr2); \
+ DRAWMENU_SETTING_EDIT_GENERIC(STRFUNC(*(data))); \
+ } \
+ FORCE_INLINE void lcd_implementation_drawmenu_setting_edit_accessor_ ## NAME (const bool sel, const uint8_t row, PGM_P pstr, PGM_P pstr2, TYPE (*pget)(), void (*pset)(TYPE), ...) { \
+ UNUSED(pstr2); UNUSED(pset); \
+ DRAWMENU_SETTING_EDIT_GENERIC(STRFUNC(pget())); \
+ } \
+ typedef void NAME##_void
+DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(int16_t, int3, itostr3);
+DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(int16_t, int4, itostr4sign);
+DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(uint8_t, int8, i8tostr3);
+DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(float, float3, ftostr3);
+DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(float, float52, ftostr52);
+DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(float, float43, ftostr43sign);
+DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(float, float5, ftostr5rj);
+DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(float, float51, ftostr51sign);
+DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(float, float52sign, ftostr52sign);
+DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(float, float62, ftostr62rj);
+DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(uint32_t, long5, ftostr5rj);
+
+#define lcd_implementation_drawmenu_setting_edit_bool(sel, row, pstr, pstr2, data) DRAW_BOOL_SETTING(sel, row, pstr, data)
+#define lcd_implementation_drawmenu_setting_edit_callback_bool(sel, row, pstr, pstr2, data, callback) DRAW_BOOL_SETTING(sel, row, pstr, data)
+#define lcd_implementation_drawmenu_setting_edit_accessor_bool(sel, row, pstr, pstr2, pget, pset) DRAW_BOOL_SETTING(sel, row, pstr, data)
+
+////////////////////////////////////////////
+/////////////// Menu Actions ///////////////
+////////////////////////////////////////////
+
+#define menu_action_back(dummy) _menu_action_back()
+void _menu_action_back();
+void menu_action_submenu(screenFunc_t data);
+void menu_action_function(menuAction_t data);
+void menu_action_gcode(const char* pgcode);
+
+////////////////////////////////////////////
+/////////// Menu Editing Actions ///////////
+////////////////////////////////////////////
+
+#define DECLARE_MENU_EDIT_TYPE(TYPE, NAME) \
+ bool _menu_edit_ ## NAME(); \
+ void menu_edit_ ## NAME(); \
+ void menu_edit_callback_ ## NAME(); \
+ void _menu_action_setting_edit_ ## NAME(PGM_P const pstr, TYPE* const ptr, const TYPE minValue, const TYPE maxValue); \
+ void menu_action_setting_edit_callback_ ## NAME(PGM_P const pstr, TYPE * const ptr, const TYPE minValue, const TYPE maxValue, const screenFunc_t callback=NULL, const bool live=false); \
+ FORCE_INLINE void menu_action_setting_edit_ ## NAME(PGM_P const pstr, TYPE * const ptr, const TYPE minValue, const TYPE maxValue) { \
+ menu_action_setting_edit_callback_ ## NAME(pstr, ptr, minValue, maxValue); \
+ } \
+ typedef void NAME##_void
+
+DECLARE_MENU_EDIT_TYPE(int16_t, int3);
+DECLARE_MENU_EDIT_TYPE(int16_t, int4);
+DECLARE_MENU_EDIT_TYPE(uint8_t, int8);
+DECLARE_MENU_EDIT_TYPE(float, float3);
+DECLARE_MENU_EDIT_TYPE(float, float52);
+DECLARE_MENU_EDIT_TYPE(float, float43);
+DECLARE_MENU_EDIT_TYPE(float, float5);
+DECLARE_MENU_EDIT_TYPE(float, float51);
+DECLARE_MENU_EDIT_TYPE(float, float52sign);
+DECLARE_MENU_EDIT_TYPE(float, float62);
+DECLARE_MENU_EDIT_TYPE(uint32_t, long5);
+
+void menu_action_setting_edit_bool(PGM_P pstr, bool* ptr);
+void menu_action_setting_edit_callback_bool(PGM_P pstr, bool* ptr, screenFunc_t callbackFunc);
+
+////////////////////////////////////////////
+//////////// Menu System Macros ////////////
+////////////////////////////////////////////
+
+/**
+ * SCREEN_OR_MENU_LOOP generates init code for a screen or menu
+ *
+ * encoderTopLine is the top menu line to display
+ * _lcdLineNr is the index of the LCD line (e.g., 0-3)
+ * _menuLineNr is the menu item to draw and process
+ * _thisItemNr is the index of each MENU_ITEM or STATIC_ITEM
+ */
+#define SCREEN_OR_MENU_LOOP() \
+ int8_t _menuLineNr = encoderTopLine, _thisItemNr; \
+ for (int8_t _lcdLineNr = 0; _lcdLineNr < LCD_HEIGHT; _lcdLineNr++, _menuLineNr++) { \
+ _thisItemNr = 0
+
+/**
+ * START_SCREEN Opening code for a screen having only static items.
+ * Do simplified scrolling of the entire screen.
+ *
+ * START_MENU Opening code for a screen with menu items.
+ * Scroll as-needed to keep the selected line in view.
+ */
+#define START_SCREEN() \
+ scroll_screen(LCD_HEIGHT, false); \
+ bool _skipStatic = false; \
+ SCREEN_OR_MENU_LOOP()
+
+#define START_MENU() \
+ scroll_screen(1, true); \
+ bool _skipStatic = true; \
+ SCREEN_OR_MENU_LOOP()
+
+#define END_SCREEN() \
+ } \
+ screen_items = _thisItemNr
+
+#define END_MENU() \
+ } \
+ screen_items = _thisItemNr; \
+ UNUSED(_skipStatic)
+
+/**
+ * REVERSE_MENU_DIRECTION
+ *
+ * To reverse the menu direction we need a general way to reverse
+ * the direction of the encoder everywhere. So encoderDirection is
+ * added to allow the encoder to go the other way.
+ *
+ * This behavior is limited to scrolling Menus and SD card listings,
+ * and is disabled in other contexts.
+ */
+#if ENABLED(REVERSE_MENU_DIRECTION)
+ extern int8_t encoderDirection;
+ #define ENCODER_DIRECTION_NORMAL() (encoderDirection = 1)
+ #define ENCODER_DIRECTION_MENUS() (encoderDirection = -1)
+#else
+ #define ENCODER_DIRECTION_NORMAL() NOOP
+ #define ENCODER_DIRECTION_MENUS() NOOP
+#endif
+
+#if ENABLED(ENCODER_RATE_MULTIPLIER)
+
+ extern bool encoderRateMultiplierEnabled;
+ #define ENCODER_RATE_MULTIPLY(F) (encoderRateMultiplierEnabled = F)
+
+ //#define ENCODER_RATE_MULTIPLIER_DEBUG // If defined, output the encoder steps per second value
+
+ /**
+ * MENU_MULTIPLIER_ITEM generates drawing and handling code for a multiplier menu item
+ */
+ #define MENU_MULTIPLIER_ITEM(TYPE, LABEL, ...) do { \
+ _MENU_ITEM_PART_1(TYPE, ## __VA_ARGS__); \
+ encoderRateMultiplierEnabled = true; \
+ lastEncoderMovementMillis = 0; \
+ _MENU_ITEM_PART_2(TYPE, PSTR(LABEL), ## __VA_ARGS__); \
+ }while(0)
+
+#else // !ENCODER_RATE_MULTIPLIER
+ #define ENCODER_RATE_MULTIPLY(F) NOOP
+#endif // !ENCODER_RATE_MULTIPLIER
+
+/**
+ * MENU_ITEM generates draw & handler code for a menu item, potentially calling:
+ *
+ * lcd_implementation_drawmenu_[type](sel, row, label, arg3...)
+ * menu_action_[type](arg3...)
+ *
+ * Examples:
+ * MENU_ITEM(back, MSG_WATCH, 0 [dummy parameter] )
+ * or
+ * MENU_BACK(MSG_WATCH)
+ * lcd_implementation_drawmenu_back(sel, row, PSTR(MSG_WATCH))
+ * menu_action_back()
+ *
+ * MENU_ITEM(function, MSG_PAUSE_PRINT, lcd_sdcard_pause)
+ * lcd_implementation_drawmenu_function(sel, row, PSTR(MSG_PAUSE_PRINT), lcd_sdcard_pause)
+ * menu_action_function(lcd_sdcard_pause)
+ *
+ * MENU_ITEM_EDIT(int3, MSG_SPEED, &feedrate_percentage, 10, 999)
+ * MENU_ITEM(setting_edit_int3, MSG_SPEED, PSTR(MSG_SPEED), &feedrate_percentage, 10, 999)
+ * lcd_implementation_drawmenu_setting_edit_int3(sel, row, PSTR(MSG_SPEED), PSTR(MSG_SPEED), &feedrate_percentage, 10, 999)
+ * menu_action_setting_edit_int3(PSTR(MSG_SPEED), &feedrate_percentage, 10, 999)
+ *
+ */
+#define _MENU_ITEM_PART_1(TYPE, ...) \
+ if (_menuLineNr == _thisItemNr) { \
+ if (encoderLine == _thisItemNr && lcd_clicked) { \
+ lcd_clicked = false
+
+#define _MENU_ITEM_PART_2(TYPE, PLABEL, ...) \
+ menu_action_ ## TYPE(__VA_ARGS__); \
+ if (screen_changed) return; \
+ } \
+ if (lcdDrawUpdate) \
+ lcd_implementation_drawmenu_ ## TYPE(encoderLine == _thisItemNr, _lcdLineNr, PLABEL, ## __VA_ARGS__); \
+ } \
+ ++_thisItemNr
+
+#define MENU_ITEM_P(TYPE, PLABEL, ...) do { \
+ _skipStatic = false; \
+ _MENU_ITEM_PART_1(TYPE, ## __VA_ARGS__); \
+ _MENU_ITEM_PART_2(TYPE, PLABEL, ## __VA_ARGS__); \
+ }while(0)
+
+#define MENU_ITEM(TYPE, LABEL, ...) MENU_ITEM_P(TYPE, PSTR(LABEL), ## __VA_ARGS__)
+
+#define MENU_ITEM_ADDON_START(X) \
+ if (lcdDrawUpdate && _menuLineNr == _thisItemNr - 1) { \
+ SETCURSOR(X, _lcdLineNr)
+
+#define MENU_ITEM_ADDON_END() } (0)
+
+#define MENU_BACK(LABEL) MENU_ITEM(back, LABEL, 0)
+
+// Used to print static text with no visible cursor.
+// Parameters: label [, bool center [, bool invert [, char *value] ] ]
+#define STATIC_ITEM_P(LABEL, ...) do{ \
+ if (_menuLineNr == _thisItemNr) { \
+ if (_skipStatic && encoderLine <= _thisItemNr) { \
+ encoderPosition += ENCODER_STEPS_PER_MENU_ITEM; \
+ ++encoderLine; \
+ } \
+ if (lcdDrawUpdate) \
+ lcd_implementation_drawmenu_static(_lcdLineNr, LABEL, ## __VA_ARGS__); \
+ } \
+ ++_thisItemNr; } while(0)
+
+#define STATIC_ITEM(LABEL, ...) STATIC_ITEM_P(PSTR(LABEL), ## __VA_ARGS__)
+
+#define MENU_ITEM_DUMMY() do { _thisItemNr++; }while(0)
+#define MENU_ITEM_EDIT(TYPE, LABEL, ...) MENU_ITEM(_CAT(setting_edit_,TYPE), LABEL, PSTR(LABEL), ## __VA_ARGS__)
+#define MENU_ITEM_EDIT_CALLBACK(TYPE, LABEL, ...) MENU_ITEM(_CAT(setting_edit_callback_,TYPE), LABEL, PSTR(LABEL), ## __VA_ARGS__)
+#if ENABLED(ENCODER_RATE_MULTIPLIER)
+ #define MENU_MULTIPLIER_ITEM_EDIT(TYPE, LABEL, ...) MENU_MULTIPLIER_ITEM(_CAT(setting_edit_,TYPE), LABEL, PSTR(LABEL), ## __VA_ARGS__)
+ #define MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(TYPE, LABEL, ...) MENU_MULTIPLIER_ITEM(_CAT(setting_edit_callback_,TYPE), LABEL, PSTR(LABEL), ## __VA_ARGS__)
+#else // !ENCODER_RATE_MULTIPLIER
+ #define MENU_MULTIPLIER_ITEM_EDIT(TYPE, LABEL, ...) MENU_ITEM(_CAT(setting_edit_,TYPE), LABEL, PSTR(LABEL), ## __VA_ARGS__)
+ #define MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(TYPE, LABEL, ...) MENU_ITEM(_CAT(setting_edit_callback_,TYPE), LABEL, PSTR(LABEL), ## __VA_ARGS__)
+#endif // !ENCODER_RATE_MULTIPLIER
+
+////////////////////////////////////////////
+/////////////// Menu Screens ///////////////
+////////////////////////////////////////////
+
+void menu_main();
+void menu_move();
+
+#if ENABLED(SDSUPPORT)
+ void menu_sdcard();
+#endif
+
+// First Fan Speed title in "Tune" and "Control>Temperature" menus
+#if FAN_COUNT > 0 && HAS_FAN0
+ #if FAN_COUNT > 1
+ #define FAN_SPEED_1_SUFFIX " 1"
+ #else
+ #define FAN_SPEED_1_SUFFIX ""
+ #endif
+#endif
+
+////////////////////////////////////////////
+//////// Menu Item Helper Functions ////////
+////////////////////////////////////////////
+
+void lcd_move_z();
+void lcd_synchronize(PGM_P const msg=NULL);
+void _lcd_draw_homing();
+
+void watch_temp_callback_E0();
+void watch_temp_callback_E1();
+void watch_temp_callback_E2();
+void watch_temp_callback_E3();
+void watch_temp_callback_E4();
+void watch_temp_callback_E5();
+void watch_temp_callback_bed();
+
+#define HAS_LINE_TO_Z (ENABLED(DELTA) || ENABLED(PROBE_MANUALLY) || ENABLED(MESH_BED_LEVELING) || ENABLED(LEVEL_BED_CORNERS))
+
+#if HAS_LINE_TO_Z
+ void line_to_z(const float &z);
+#endif
+
+#if ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(PID_AUTOTUNE_MENU) || ENABLED(ADVANCED_PAUSE_FEATURE)
+ void lcd_enqueue_command(const char * const cmd);
+ void lcd_enqueue_commands_P(PGM_P const cmd);
+#endif
+
+#if ENABLED(LEVEL_BED_CORNERS)
+ void _lcd_level_bed_corners();
+#endif
+
+#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
+ extern float lcd_z_fade_height;
+ void _lcd_set_z_fade_height();
+#endif
+
+#if ENABLED(LCD_BED_LEVELING) || (HAS_LEVELING && DISABLED(SLIM_LCD_MENUS))
+ void _lcd_toggle_bed_leveling();
+#endif
+
+#if ENABLED(BABYSTEPPING)
+ #if ENABLED(BABYSTEP_ZPROBE_OFFSET)
+ void lcd_babystep_zoffset();
+ #else
+ void lcd_babystep_z();
+ #endif
+#endif
+
+#if ENABLED(EEPROM_SETTINGS)
+ void lcd_store_settings();
+ void lcd_load_settings();
+#endif
diff --git a/Marlin/src/lcd/menu/menu_advanced.cpp b/Marlin/src/lcd/menu/menu_advanced.cpp
new file mode 100644
index 0000000000..6fb5317e9c
--- /dev/null
+++ b/Marlin/src/lcd/menu/menu_advanced.cpp
@@ -0,0 +1,644 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+//
+// Advanced Settings Menus
+//
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if HAS_LCD_MENU
+
+#include "menu.h"
+#include "../../module/planner.h"
+
+#if DISABLED(NO_VOLUMETRICS)
+ #include "../../gcode/parser.h"
+#endif
+
+#if HAS_BED_PROBE
+ #include "../../module/probe.h"
+ #if ENABLED(BLTOUCH)
+ #include "../../module/endstops.h"
+ #endif
+#endif
+
+#if ENABLED(PIDTEMP)
+ #include "../../module/temperature.h"
+#endif
+
+#if HAS_M206_COMMAND
+ //
+ // Set the home offset based on the current_position
+ //
+ void _lcd_set_home_offsets() {
+ enqueue_and_echo_commands_P(PSTR("M428"));
+ lcd_return_to_status();
+ }
+#endif
+
+#if ENABLED(SD_FIRMWARE_UPDATE)
+
+ #include "../../module/configuration_store.h"
+
+ //
+ // Toggle the SD Firmware Update state in EEPROM
+ //
+ static void _lcd_toggle_sd_update() {
+ const bool new_state = !settings.sd_update_status();
+ lcd_completion_feedback(settings.set_sd_update_status(new_state));
+ lcd_return_to_status();
+ if (new_state) LCD_MESSAGEPGM(MSG_RESET_PRINTER); else lcd_reset_status();
+ }
+#endif
+
+#if DISABLED(NO_VOLUMETRICS) || ENABLED(ADVANCED_PAUSE_FEATURE)
+ //
+ // Advanced Settings > Filament
+ //
+ void menu_advanced_filament() {
+ START_MENU();
+ MENU_BACK(MSG_ADVANCED_SETTINGS);
+
+ #if ENABLED(LIN_ADVANCE)
+ #if EXTRUDERS == 1
+ MENU_ITEM_EDIT(float52, MSG_ADVANCE_K, &planner.extruder_advance_K[0], 0, 999);
+ #elif EXTRUDERS > 1
+ #define EDIT_ADVANCE_K(N) MENU_ITEM_EDIT(float52, MSG_ADVANCE_K MSG_E##N, &planner.extruder_advance_K[N-1], 0, 999)
+ EDIT_ADVANCE_K(1);
+ EDIT_ADVANCE_K(2);
+ #if EXTRUDERS > 2
+ EDIT_ADVANCE_K(3);
+ #if EXTRUDERS > 3
+ EDIT_ADVANCE_K(4);
+ #if EXTRUDERS > 4
+ EDIT_ADVANCE_K(5);
+ #if EXTRUDERS > 5
+ EDIT_ADVANCE_K(6);
+ #endif // EXTRUDERS > 5
+ #endif // EXTRUDERS > 4
+ #endif // EXTRUDERS > 3
+ #endif // EXTRUDERS > 2
+ #endif // EXTRUDERS > 1
+ #endif
+
+ #if DISABLED(NO_VOLUMETRICS)
+ MENU_ITEM_EDIT_CALLBACK(bool, MSG_VOLUMETRIC_ENABLED, &parser.volumetric_enabled, planner.calculate_volumetric_multipliers);
+
+ if (parser.volumetric_enabled) {
+ #if EXTRUDERS == 1
+ MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM, &planner.filament_size[0], 1.5f, 3.25f, planner.calculate_volumetric_multipliers);
+ #else // EXTRUDERS > 1
+ #define EDIT_FIL_DIAM(N) MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM MSG_DIAM_E##N, &planner.filament_size[N-1], 1.5f, 3.25f, planner.calculate_volumetric_multipliers)
+ MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM, &planner.filament_size[active_extruder], 1.5f, 3.25f, planner.calculate_volumetric_multipliers);
+ EDIT_FIL_DIAM(1);
+ EDIT_FIL_DIAM(2);
+ #if EXTRUDERS > 2
+ EDIT_FIL_DIAM(3);
+ #if EXTRUDERS > 3
+ EDIT_FIL_DIAM(4);
+ #if EXTRUDERS > 4
+ EDIT_FIL_DIAM(5);
+ #if EXTRUDERS > 5
+ EDIT_FIL_DIAM(6);
+ #endif // EXTRUDERS > 5
+ #endif // EXTRUDERS > 4
+ #endif // EXTRUDERS > 3
+ #endif // EXTRUDERS > 2
+ #endif // EXTRUDERS > 1
+ }
+ #endif
+
+ #if ENABLED(ADVANCED_PAUSE_FEATURE)
+ constexpr float extrude_maxlength =
+ #if ENABLED(PREVENT_LENGTHY_EXTRUDE)
+ EXTRUDE_MAXLENGTH
+ #else
+ 999
+ #endif
+ ;
+
+ #if EXTRUDERS == 1
+ MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_UNLOAD, &fc_settings[0].unload_length, 0, extrude_maxlength);
+ #else // EXTRUDERS > 1
+ #define EDIT_FIL_UNLOAD(N) MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_UNLOAD MSG_DIAM_E##N, &fc_settings[N-1].unload_length, 0, extrude_maxlength)
+ MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_UNLOAD, &fc_settings[active_extruder].unload_length, 0, extrude_maxlength);
+ EDIT_FIL_UNLOAD(1);
+ EDIT_FIL_UNLOAD(2);
+ #if EXTRUDERS > 2
+ EDIT_FIL_UNLOAD(3);
+ #if EXTRUDERS > 3
+ EDIT_FIL_UNLOAD(4);
+ #if EXTRUDERS > 4
+ EDIT_FIL_UNLOAD(5);
+ #if EXTRUDERS > 5
+ EDIT_FIL_UNLOAD(6);
+ #endif // EXTRUDERS > 5
+ #endif // EXTRUDERS > 4
+ #endif // EXTRUDERS > 3
+ #endif // EXTRUDERS > 2
+ #endif // EXTRUDERS > 1
+
+ #if EXTRUDERS == 1
+ MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_LOAD, &fc_settings[0].load_length, 0, extrude_maxlength);
+ #else // EXTRUDERS > 1
+ #define EDIT_FIL_LOAD(N) MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_LOAD MSG_DIAM_E##N, &fc_settings[N-1].load_length, 0, extrude_maxlength)
+ MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_LOAD, &fc_settings[active_extruder].load_length, 0, extrude_maxlength);
+ EDIT_FIL_LOAD(1);
+ EDIT_FIL_LOAD(2);
+ #if EXTRUDERS > 2
+ EDIT_FIL_LOAD(3);
+ #if EXTRUDERS > 3
+ EDIT_FIL_LOAD(4);
+ #if EXTRUDERS > 4
+ EDIT_FIL_LOAD(5);
+ #if EXTRUDERS > 5
+ EDIT_FIL_LOAD(6);
+ #endif // EXTRUDERS > 5
+ #endif // EXTRUDERS > 4
+ #endif // EXTRUDERS > 3
+ #endif // EXTRUDERS > 2
+ #endif // EXTRUDERS > 1
+ #endif
+
+ END_MENU();
+ }
+
+#endif // !NO_VOLUMETRICS || ADVANCED_PAUSE_FEATURE
+
+//
+// Advanced Settings > Temperature helpers
+//
+
+#if ENABLED(PID_AUTOTUNE_MENU)
+
+ #if ENABLED(PIDTEMP)
+ int16_t autotune_temp[HOTENDS] = ARRAY_BY_HOTENDS1(150);
+ #endif
+
+ #if ENABLED(PIDTEMPBED)
+ int16_t autotune_temp_bed = 70;
+ #endif
+
+ void _lcd_autotune(const int16_t e) {
+ char cmd[30];
+ sprintf_P(cmd, PSTR("M303 U1 E%i S%i"), e,
+ #if HAS_PID_FOR_BOTH
+ e < 0 ? autotune_temp_bed : autotune_temp[e]
+ #elif ENABLED(PIDTEMPBED)
+ autotune_temp_bed
+ #else
+ autotune_temp[e]
+ #endif
+ );
+ lcd_enqueue_command(cmd);
+ }
+
+#endif // PID_AUTOTUNE_MENU
+
+#if ENABLED(PIDTEMP)
+
+ float raw_Ki, raw_Kd; // place-holders for Ki and Kd edits
+
+ // Helpers for editing PID Ki & Kd values
+ // grab the PID value out of the temp variable; scale it; then update the PID driver
+ void copy_and_scalePID_i(int16_t e) {
+ #if DISABLED(PID_PARAMS_PER_HOTEND) || HOTENDS == 1
+ UNUSED(e);
+ #endif
+ PID_PARAM(Ki, e) = scalePID_i(raw_Ki);
+ thermalManager.updatePID();
+ }
+ void copy_and_scalePID_d(int16_t e) {
+ #if DISABLED(PID_PARAMS_PER_HOTEND) || HOTENDS == 1
+ UNUSED(e);
+ #endif
+ PID_PARAM(Kd, e) = scalePID_d(raw_Kd);
+ thermalManager.updatePID();
+ }
+ #define _DEFINE_PIDTEMP_BASE_FUNCS(N) \
+ void copy_and_scalePID_i_E ## N() { copy_and_scalePID_i(N); } \
+ void copy_and_scalePID_d_E ## N() { copy_and_scalePID_d(N); }
+
+ #if ENABLED(PID_AUTOTUNE_MENU)
+ #define DEFINE_PIDTEMP_FUNCS(N) \
+ _DEFINE_PIDTEMP_BASE_FUNCS(N); \
+ void lcd_autotune_callback_E ## N() { _lcd_autotune(N); } typedef void _pid_##N##_void
+ #else
+ #define DEFINE_PIDTEMP_FUNCS(N) _DEFINE_PIDTEMP_BASE_FUNCS(N) typedef void _pid_##N##_void
+ #endif
+
+ DEFINE_PIDTEMP_FUNCS(0);
+ #if ENABLED(PID_PARAMS_PER_HOTEND)
+ #if HOTENDS > 1
+ DEFINE_PIDTEMP_FUNCS(1);
+ #if HOTENDS > 2
+ DEFINE_PIDTEMP_FUNCS(2);
+ #if HOTENDS > 3
+ DEFINE_PIDTEMP_FUNCS(3);
+ #if HOTENDS > 4
+ DEFINE_PIDTEMP_FUNCS(4);
+ #if HOTENDS > 5
+ DEFINE_PIDTEMP_FUNCS(5);
+ #endif // HOTENDS > 5
+ #endif // HOTENDS > 4
+ #endif // HOTENDS > 3
+ #endif // HOTENDS > 2
+ #endif // HOTENDS > 1
+ #endif // PID_PARAMS_PER_HOTEND
+
+#endif // PIDTEMP
+
+//
+// Advanced Settings > Temperature
+//
+void menu_advanced_temperature() {
+ START_MENU();
+ MENU_BACK(MSG_ADVANCED_SETTINGS);
+ //
+ // Autotemp, Min, Max, Fact
+ //
+ #if ENABLED(AUTOTEMP) && HAS_TEMP_HOTEND
+ MENU_ITEM_EDIT(bool, MSG_AUTOTEMP, &planner.autotemp_enabled);
+ MENU_ITEM_EDIT(float3, MSG_MIN, &planner.autotemp_min, 0, float(HEATER_0_MAXTEMP) - 15);
+ MENU_ITEM_EDIT(float3, MSG_MAX, &planner.autotemp_max, 0, float(HEATER_0_MAXTEMP) - 15);
+ MENU_ITEM_EDIT(float52, MSG_FACTOR, &planner.autotemp_factor, 0, 1);
+ #endif
+
+ //
+ // PID-P, PID-I, PID-D, PID-C, PID Autotune
+ // PID-P E1, PID-I E1, PID-D E1, PID-C E1, PID Autotune E1
+ // PID-P E2, PID-I E2, PID-D E2, PID-C E2, PID Autotune E2
+ // PID-P E3, PID-I E3, PID-D E3, PID-C E3, PID Autotune E3
+ // PID-P E4, PID-I E4, PID-D E4, PID-C E4, PID Autotune E4
+ // PID-P E5, PID-I E5, PID-D E5, PID-C E5, PID Autotune E5
+ //
+ #if ENABLED(PIDTEMP)
+
+ #define _PID_BASE_MENU_ITEMS(ELABEL, eindex) \
+ raw_Ki = unscalePID_i(PID_PARAM(Ki, eindex)); \
+ raw_Kd = unscalePID_d(PID_PARAM(Kd, eindex)); \
+ MENU_ITEM_EDIT(float52sign, MSG_PID_P ELABEL, &PID_PARAM(Kp, eindex), 1, 9990); \
+ MENU_ITEM_EDIT_CALLBACK(float52sign, MSG_PID_I ELABEL, &raw_Ki, 0.01f, 9990, copy_and_scalePID_i_E ## eindex); \
+ MENU_ITEM_EDIT_CALLBACK(float52sign, MSG_PID_D ELABEL, &raw_Kd, 1, 9990, copy_and_scalePID_d_E ## eindex)
+
+ #if ENABLED(PID_EXTRUSION_SCALING)
+ #define _PID_MENU_ITEMS(ELABEL, eindex) \
+ _PID_BASE_MENU_ITEMS(ELABEL, eindex); \
+ MENU_ITEM_EDIT(float3, MSG_PID_C ELABEL, &PID_PARAM(Kc, eindex), 1, 9990)
+ #else
+ #define _PID_MENU_ITEMS(ELABEL, eindex) _PID_BASE_MENU_ITEMS(ELABEL, eindex)
+ #endif
+
+ #if ENABLED(PID_AUTOTUNE_MENU)
+ #define PID_MENU_ITEMS(ELABEL, eindex) \
+ _PID_MENU_ITEMS(ELABEL, eindex); \
+ MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_PID_AUTOTUNE ELABEL, &autotune_temp[eindex], 150, heater_maxtemp[eindex] - 15, lcd_autotune_callback_E ## eindex)
+ #else
+ #define PID_MENU_ITEMS(ELABEL, eindex) _PID_MENU_ITEMS(ELABEL, eindex)
+ #endif
+
+ #if ENABLED(PID_PARAMS_PER_HOTEND) && HOTENDS > 1
+ PID_MENU_ITEMS(" " MSG_E1, 0);
+ PID_MENU_ITEMS(" " MSG_E2, 1);
+ #if HOTENDS > 2
+ PID_MENU_ITEMS(" " MSG_E3, 2);
+ #if HOTENDS > 3
+ PID_MENU_ITEMS(" " MSG_E4, 3);
+ #if HOTENDS > 4
+ PID_MENU_ITEMS(" " MSG_E5, 4);
+ #if HOTENDS > 5
+ PID_MENU_ITEMS(" " MSG_E6, 5);
+ #endif // HOTENDS > 5
+ #endif // HOTENDS > 4
+ #endif // HOTENDS > 3
+ #endif // HOTENDS > 2
+ #else // !PID_PARAMS_PER_HOTEND || HOTENDS == 1
+ PID_MENU_ITEMS("", 0);
+ #endif // !PID_PARAMS_PER_HOTEND || HOTENDS == 1
+
+ #endif // PIDTEMP
+
+ END_MENU();
+}
+
+#if DISABLED(SLIM_LCD_MENUS)
+
+ void _reset_acceleration_rates() { planner.reset_acceleration_rates(); }
+ #if ENABLED(DISTINCT_E_FACTORS)
+ void _reset_e_acceleration_rate(const uint8_t e) { if (e == active_extruder) _reset_acceleration_rates(); }
+ void _reset_e0_acceleration_rate() { _reset_e_acceleration_rate(0); }
+ void _reset_e1_acceleration_rate() { _reset_e_acceleration_rate(1); }
+ #if E_STEPPERS > 2
+ void _reset_e2_acceleration_rate() { _reset_e_acceleration_rate(2); }
+ #if E_STEPPERS > 3
+ void _reset_e3_acceleration_rate() { _reset_e_acceleration_rate(3); }
+ #if E_STEPPERS > 4
+ void _reset_e4_acceleration_rate() { _reset_e_acceleration_rate(4); }
+ #if E_STEPPERS > 5
+ void _reset_e5_acceleration_rate() { _reset_e_acceleration_rate(5); }
+ #endif // E_STEPPERS > 5
+ #endif // E_STEPPERS > 4
+ #endif // E_STEPPERS > 3
+ #endif // E_STEPPERS > 2
+ #endif
+
+ void _planner_refresh_positioning() { planner.refresh_positioning(); }
+ #if ENABLED(DISTINCT_E_FACTORS)
+ void _planner_refresh_e_positioning(const uint8_t e) {
+ if (e == active_extruder)
+ _planner_refresh_positioning();
+ else
+ planner.steps_to_mm[E_AXIS + e] = 1.0f / planner.settings.axis_steps_per_mm[E_AXIS + e];
+ }
+ void _planner_refresh_e0_positioning() { _planner_refresh_e_positioning(0); }
+ void _planner_refresh_e1_positioning() { _planner_refresh_e_positioning(1); }
+ #if E_STEPPERS > 2
+ void _planner_refresh_e2_positioning() { _planner_refresh_e_positioning(2); }
+ #if E_STEPPERS > 3
+ void _planner_refresh_e3_positioning() { _planner_refresh_e_positioning(3); }
+ #if E_STEPPERS > 4
+ void _planner_refresh_e4_positioning() { _planner_refresh_e_positioning(4); }
+ #if E_STEPPERS > 5
+ void _planner_refresh_e5_positioning() { _planner_refresh_e_positioning(5); }
+ #endif // E_STEPPERS > 5
+ #endif // E_STEPPERS > 4
+ #endif // E_STEPPERS > 3
+ #endif // E_STEPPERS > 2
+ #endif
+
+ // M203 / M205 Velocity options
+ void menu_advanced_velocity() {
+ START_MENU();
+ MENU_BACK(MSG_ADVANCED_SETTINGS);
+
+ // M203 Max Feedrate
+ #define EDIT_VMAX(N) MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_VMAX MSG_A, &planner.settings.max_feedrate_mm_s[A_AXIS], 1, 999)
+ EDIT_VMAX(A);
+ EDIT_VMAX(B);
+ EDIT_VMAX(C);
+
+ #if ENABLED(DISTINCT_E_FACTORS)
+ #define EDIT_VMAX_E(N) MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_VMAX MSG_E##N, &planner.settings.max_feedrate_mm_s[E_AXIS_N(N-1)], 1, 999)
+ MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_VMAX MSG_E, &planner.settings.max_feedrate_mm_s[E_AXIS_N(active_extruder)], 1, 999);
+ EDIT_VMAX_E(1);
+ EDIT_VMAX_E(2);
+ #if E_STEPPERS > 2
+ EDIT_VMAX_E(3);
+ #if E_STEPPERS > 3
+ EDIT_VMAX_E(4);
+ #if E_STEPPERS > 4
+ EDIT_VMAX_E(5);
+ #if E_STEPPERS > 5
+ EDIT_VMAX_E(6);
+ #endif // E_STEPPERS > 5
+ #endif // E_STEPPERS > 4
+ #endif // E_STEPPERS > 3
+ #endif // E_STEPPERS > 2
+ #else
+ MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_VMAX MSG_E, &planner.settings.max_feedrate_mm_s[E_AXIS], 1, 999);
+ #endif
+
+ // M205 S Min Feedrate
+ MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_VMIN, &planner.settings.min_feedrate_mm_s, 0, 999);
+
+ // M205 T Min Travel Feedrate
+ MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_VTRAV_MIN, &planner.settings.min_travel_feedrate_mm_s, 0, 999);
+
+ END_MENU();
+ }
+
+ // M201 / M204 Accelerations
+ void menu_advanced_acceleration() {
+ START_MENU();
+ MENU_BACK(MSG_ADVANCED_SETTINGS);
+
+ // M204 P Acceleration
+ MENU_MULTIPLIER_ITEM_EDIT(float5, MSG_ACC, &planner.settings.acceleration, 10, 99000);
+
+ // M204 R Retract Acceleration
+ MENU_MULTIPLIER_ITEM_EDIT(float5, MSG_A_RETRACT, &planner.settings.retract_acceleration, 100, 99000);
+
+ // M204 T Travel Acceleration
+ MENU_MULTIPLIER_ITEM_EDIT(float5, MSG_A_TRAVEL, &planner.settings.travel_acceleration, 100, 99000);
+
+ // M201 settings
+ #define EDIT_AMAX(Q,L) MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_##Q, &planner.settings.max_acceleration_mm_per_s2[_AXIS(Q)], L, 99000, _reset_acceleration_rates)
+ EDIT_AMAX(A,100);
+ EDIT_AMAX(B,100);
+ EDIT_AMAX(C, 10);
+
+ #if ENABLED(DISTINCT_E_FACTORS)
+ #define EDIT_AMAX_E(N,E) MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_E##N, &planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(E)], 100, 99000, _reset_e##E##_acceleration_rate)
+ MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_E, &planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(active_extruder)], 100, 99000, _reset_acceleration_rates);
+ EDIT_AMAX_E(1,0);
+ EDIT_AMAX_E(2,1);
+ #if E_STEPPERS > 2
+ EDIT_AMAX_E(3,2);
+ #if E_STEPPERS > 3
+ EDIT_AMAX_E(4,3);
+ #if E_STEPPERS > 4
+ EDIT_AMAX_E(5,4);
+ #if E_STEPPERS > 5
+ EDIT_AMAX_E(6,5);
+ #endif // E_STEPPERS > 5
+ #endif // E_STEPPERS > 4
+ #endif // E_STEPPERS > 3
+ #endif // E_STEPPERS > 2
+ #else
+ MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_E, &planner.settings.max_acceleration_mm_per_s2[E_AXIS], 100, 99000, _reset_acceleration_rates);
+ #endif
+
+ END_MENU();
+ }
+
+ // M205 Jerk
+ void menu_advanced_jerk() {
+ START_MENU();
+ MENU_BACK(MSG_ADVANCED_SETTINGS);
+
+ #if ENABLED(JUNCTION_DEVIATION)
+ #if ENABLED(LIN_ADVANCE)
+ MENU_ITEM_EDIT_CALLBACK(float43, MSG_JUNCTION_DEVIATION, &planner.junction_deviation_mm, 0.01f, 0.3f, planner.recalculate_max_e_jerk);
+ #else
+ MENU_ITEM_EDIT(float43, MSG_JUNCTION_DEVIATION, &planner.junction_deviation_mm, 0.01f, 0.3f);
+ #endif
+ #endif
+ #if HAS_CLASSIC_JERK
+ #define EDIT_JERK(N) MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_V##N##_JERK, &planner.max_jerk[_AXIS(N)], 1, 990)
+ EDIT_JERK(A);
+ EDIT_JERK(B);
+ #if ENABLED(DELTA)
+ EDIT_JERK(C);
+ #else
+ MENU_MULTIPLIER_ITEM_EDIT(float52sign, MSG_VC_JERK, &planner.max_jerk[C_AXIS], 0.1f, 990);
+ #endif
+ #if DISABLED(JUNCTION_DEVIATION) || DISABLED(LIN_ADVANCE)
+ EDIT_JERK(E);
+ #endif
+ #endif
+
+ END_MENU();
+ }
+
+ // M92 Steps-per-mm
+ void menu_advanced_steps_per_mm() {
+ START_MENU();
+ MENU_BACK(MSG_ADVANCED_SETTINGS);
+
+ #define EDIT_QSTEPS(Q) MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float62, MSG_##Q##STEPS, &planner.settings.axis_steps_per_mm[_AXIS(Q)], 5, 9999, _planner_refresh_positioning)
+ EDIT_QSTEPS(A);
+ EDIT_QSTEPS(B);
+ EDIT_QSTEPS(C);
+
+ #if ENABLED(DISTINCT_E_FACTORS)
+ #define EDIT_ESTEPS(N,E) MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float62, MSG_E##N##STEPS, &planner.settings.axis_steps_per_mm[E_AXIS_N(E)], 5, 9999, _planner_refresh_e##E##_positioning)
+ MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float62, MSG_ESTEPS, &planner.settings.axis_steps_per_mm[E_AXIS_N(active_extruder)], 5, 9999, _planner_refresh_positioning);
+ EDIT_ESTEPS(1,0);
+ EDIT_ESTEPS(2,1);
+ #if E_STEPPERS > 2
+ EDIT_ESTEPS(3,2);
+ #if E_STEPPERS > 3
+ EDIT_ESTEPS(4,3);
+ #if E_STEPPERS > 4
+ EDIT_ESTEPS(5,4);
+ #if E_STEPPERS > 5
+ EDIT_ESTEPS(6,5);
+ #endif // E_STEPPERS > 5
+ #endif // E_STEPPERS > 4
+ #endif // E_STEPPERS > 3
+ #endif // E_STEPPERS > 2
+ #else
+ MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float62, MSG_ESTEPS, &planner.settings.axis_steps_per_mm[E_AXIS], 5, 9999, _planner_refresh_positioning);
+ #endif
+
+ END_MENU();
+ }
+
+ #if ENABLED(EEPROM_SETTINGS)
+
+ #include "../../module/configuration_store.h"
+
+ static void lcd_init_eeprom() {
+ lcd_completion_feedback(settings.init_eeprom());
+ lcd_goto_previous_menu();
+ }
+
+ static void lcd_init_eeprom_confirm() {
+ START_MENU();
+ MENU_BACK(MSG_ADVANCED_SETTINGS);
+ MENU_ITEM(function, MSG_INIT_EEPROM, lcd_init_eeprom);
+ END_MENU();
+ }
+
+ #endif
+
+#endif // !SLIM_LCD_MENUS
+
+void menu_advanced_settings() {
+ START_MENU();
+ MENU_BACK(MSG_CONFIGURATION);
+
+ #if ENABLED(BABYSTEP_ZPROBE_OFFSET)
+ MENU_ITEM(submenu, MSG_ZPROBE_ZOFFSET, lcd_babystep_zoffset);
+ #elif HAS_BED_PROBE
+ MENU_ITEM_EDIT(float52, MSG_ZPROBE_ZOFFSET, &zprobe_zoffset, Z_PROBE_OFFSET_RANGE_MIN, Z_PROBE_OFFSET_RANGE_MAX);
+ #endif
+
+ #if DISABLED(SLIM_LCD_MENUS)
+
+ #if HAS_M206_COMMAND
+ //
+ // Set Home Offsets
+ //
+ MENU_ITEM(function, MSG_SET_HOME_OFFSETS, _lcd_set_home_offsets);
+ #endif
+
+ // M203 / M205 - Feedrate items
+ MENU_ITEM(submenu, MSG_VELOCITY, menu_advanced_velocity);
+
+ // M201 - Acceleration items
+ MENU_ITEM(submenu, MSG_ACCELERATION, menu_advanced_acceleration);
+
+ // M205 - Max Jerk
+ MENU_ITEM(submenu, MSG_JERK, menu_advanced_jerk);
+
+ if (!printer_busy()) {
+ // M92 - Steps Per mm
+ MENU_ITEM(submenu, MSG_STEPS_PER_MM, menu_advanced_steps_per_mm);
+ }
+
+ #endif // !SLIM_LCD_MENUS
+
+ MENU_ITEM(submenu, MSG_TEMPERATURE, menu_advanced_temperature);
+
+ #if DISABLED(NO_VOLUMETRICS) || ENABLED(ADVANCED_PAUSE_FEATURE)
+ MENU_ITEM(submenu, MSG_FILAMENT, menu_advanced_filament);
+ #elif ENABLED(LIN_ADVANCE)
+ #if EXTRUDERS == 1
+ MENU_ITEM_EDIT(float52, MSG_ADVANCE_K, &planner.extruder_advance_K[0], 0, 999);
+ #elif EXTRUDERS > 1
+ #define EDIT_ADVANCE_K(N) MENU_ITEM_EDIT(float52, MSG_ADVANCE_K MSG_E##N, &planner.extruder_advance_K[N-1], 0, 999)
+ EDIT_ADVANCE_K(1);
+ EDIT_ADVANCE_K(2);
+ #if EXTRUDERS > 2
+ EDIT_ADVANCE_K(3);
+ #if EXTRUDERS > 3
+ EDIT_ADVANCE_K(4);
+ #if EXTRUDERS > 4
+ EDIT_ADVANCE_K(5);
+ #if EXTRUDERS > 5
+ EDIT_ADVANCE_K(6);
+ #endif // EXTRUDERS > 5
+ #endif // EXTRUDERS > 4
+ #endif // EXTRUDERS > 3
+ #endif // EXTRUDERS > 2
+ #endif // EXTRUDERS > 1
+ #endif
+
+ // M540 S - Abort on endstop hit when SD printing
+ #if ENABLED(ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED)
+ MENU_ITEM_EDIT(bool, MSG_ENDSTOP_ABORT, &planner.abort_on_endstop_hit);
+ #endif
+
+ //
+ // BLTouch Self-Test and Reset
+ //
+ #if ENABLED(BLTOUCH)
+ MENU_ITEM(gcode, MSG_BLTOUCH_SELFTEST, PSTR("M280 P" STRINGIFY(Z_PROBE_SERVO_NR) " S" STRINGIFY(BLTOUCH_SELFTEST)));
+ if (!endstops.z_probe_enabled && TEST_BLTOUCH())
+ MENU_ITEM(gcode, MSG_BLTOUCH_RESET, PSTR("M280 P" STRINGIFY(Z_PROBE_SERVO_NR) " S" STRINGIFY(BLTOUCH_RESET)));
+ #endif
+
+ #if ENABLED(SD_FIRMWARE_UPDATE)
+ bool sd_update_state = settings.sd_update_status();
+ MENU_ITEM_EDIT_CALLBACK(bool, MSG_SD_UPDATE, &sd_update_state, _lcd_toggle_sd_update);
+ #endif
+
+ #if ENABLED(EEPROM_SETTINGS) && DISABLED(SLIM_LCD_MENUS)
+ MENU_ITEM(submenu, MSG_INIT_EEPROM, lcd_init_eeprom_confirm);
+ #endif
+
+ END_MENU();
+}
+
+#endif // HAS_LCD_MENU
diff --git a/Marlin/src/lcd/menu/menu_bed_leveling.cpp b/Marlin/src/lcd/menu/menu_bed_leveling.cpp
new file mode 100644
index 0000000000..5c172b6cf6
--- /dev/null
+++ b/Marlin/src/lcd/menu/menu_bed_leveling.cpp
@@ -0,0 +1,339 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+//
+// Bed Leveling Menus
+//
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if HAS_LCD_MENU && ENABLED(LCD_BED_LEVELING)
+
+#include "menu.h"
+#include "../../module/planner.h"
+#include "../../feature/bedlevel/bedlevel.h"
+
+#if ENABLED(PROBE_MANUALLY) || ENABLED(MESH_BED_LEVELING)
+
+ #include "../../module/motion.h"
+ #include "../../gcode/queue.h"
+
+ //
+ // Motion > Level Bed handlers
+ //
+
+ static uint8_t manual_probe_index;
+
+ // LCD probed points are from defaults
+ constexpr uint8_t total_probe_points = (
+ #if ENABLED(AUTO_BED_LEVELING_3POINT)
+ 3
+ #elif ABL_GRID || ENABLED(MESH_BED_LEVELING)
+ GRID_MAX_POINTS
+ #endif
+ );
+
+ bool lcd_wait_for_move;
+
+ //
+ // Bed leveling is done. Wait for G29 to complete.
+ // A flag is used so that this can release control
+ // and allow the command queue to be processed.
+ //
+ // When G29 finishes the last move:
+ // - Raise Z to the "manual probe height"
+ // - Don't return until done.
+ //
+ // ** This blocks the command queue! **
+ //
+ void _lcd_level_bed_done() {
+ if (!lcd_wait_for_move) {
+ #if MANUAL_PROBE_HEIGHT > 0 && DISABLED(MESH_BED_LEVELING)
+ // Display "Done" screen and wait for moves to complete
+ line_to_z(MANUAL_PROBE_HEIGHT);
+ lcd_synchronize(PSTR(MSG_LEVEL_BED_DONE));
+ #endif
+ lcd_goto_previous_menu_no_defer();
+ lcd_completion_feedback();
+ }
+ if (lcdDrawUpdate) lcd_implementation_drawmenu_static(LCD_HEIGHT >= 4 ? 1 : 0, PSTR(MSG_LEVEL_BED_DONE));
+ lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NEXT;
+ }
+
+ void _lcd_level_goto_next_point();
+
+ //
+ // Step 7: Get the Z coordinate, click goes to the next point or exits
+ //
+ void _lcd_level_bed_get_z() {
+ ENCODER_DIRECTION_NORMAL();
+
+ if (use_click()) {
+
+ //
+ // Save the current Z position and move
+ //
+
+ // If done...
+ if (++manual_probe_index >= total_probe_points) {
+ //
+ // The last G29 records the point and enables bed leveling
+ //
+ lcd_wait_for_move = true;
+ lcd_goto_screen(_lcd_level_bed_done);
+ #if ENABLED(MESH_BED_LEVELING)
+ enqueue_and_echo_commands_P(PSTR("G29 S2"));
+ #elif ENABLED(PROBE_MANUALLY)
+ enqueue_and_echo_commands_P(PSTR("G29 V1"));
+ #endif
+ }
+ else
+ _lcd_level_goto_next_point();
+
+ return;
+ }
+
+ //
+ // Encoder knob or keypad buttons adjust the Z position
+ //
+ if (encoderPosition) {
+ const float z = current_position[Z_AXIS] + float((int32_t)encoderPosition) * (MBL_Z_STEP);
+ line_to_z(constrain(z, -(LCD_PROBE_Z_RANGE) * 0.5f, (LCD_PROBE_Z_RANGE) * 0.5f));
+ lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NEXT;
+ encoderPosition = 0;
+ }
+
+ //
+ // Draw on first display, then only on Z change
+ //
+ if (lcdDrawUpdate) {
+ const float v = current_position[Z_AXIS];
+ lcd_implementation_drawedit(PSTR(MSG_MOVE_Z), ftostr43sign(v + (v < 0 ? -0.0001f : 0.0001f), '+'));
+ }
+ }
+
+ //
+ // Step 6: Display "Next point: 1 / 9" while waiting for move to finish
+ //
+ void _lcd_level_bed_moving() {
+ if (lcdDrawUpdate) {
+ char msg[10];
+ sprintf_P(msg, PSTR("%i / %u"), (int)(manual_probe_index + 1), total_probe_points);
+ lcd_implementation_drawedit(PSTR(MSG_LEVEL_BED_NEXT_POINT), msg);
+ }
+ lcdDrawUpdate = LCDVIEW_CALL_NO_REDRAW;
+ if (!lcd_wait_for_move) lcd_goto_screen(_lcd_level_bed_get_z);
+ }
+
+ //
+ // Step 5: Initiate a move to the next point
+ //
+ void _lcd_level_goto_next_point() {
+ lcd_goto_screen(_lcd_level_bed_moving);
+
+ // G29 Records Z, moves, and signals when it pauses
+ lcd_wait_for_move = true;
+ #if ENABLED(MESH_BED_LEVELING)
+ enqueue_and_echo_commands_P(manual_probe_index ? PSTR("G29 S2") : PSTR("G29 S1"));
+ #elif ENABLED(PROBE_MANUALLY)
+ enqueue_and_echo_commands_P(PSTR("G29 V1"));
+ #endif
+ }
+
+ //
+ // Step 4: Display "Click to Begin", wait for click
+ // Move to the first probe position
+ //
+ void _lcd_level_bed_homing_done() {
+ if (lcdDrawUpdate) lcd_implementation_drawedit(PSTR(MSG_LEVEL_BED_WAITING));
+ if (use_click()) {
+ manual_probe_index = 0;
+ _lcd_level_goto_next_point();
+ }
+ }
+
+ //
+ // Step 3: Display "Homing XYZ" - Wait for homing to finish
+ //
+ void _lcd_level_bed_homing() {
+ _lcd_draw_homing();
+ if (all_axes_homed()) lcd_goto_screen(_lcd_level_bed_homing_done);
+ }
+
+ #if ENABLED(PROBE_MANUALLY)
+ extern bool g29_in_progress;
+ #endif
+
+ //
+ // Step 2: Continue Bed Leveling...
+ //
+ void _lcd_level_bed_continue() {
+ defer_return_to_status = true;
+ axis_homed = 0;
+ lcd_goto_screen(_lcd_level_bed_homing);
+ enqueue_and_echo_commands_P(PSTR("G28"));
+ }
+
+#endif // PROBE_MANUALLY || MESH_BED_LEVELING
+
+#if ENABLED(LEVEL_BED_CORNERS)
+
+ /**
+ * Level corners, starting in the front-left corner.
+ */
+ static int8_t bed_corner;
+ void _lcd_goto_next_corner() {
+ line_to_z(4.0);
+ switch (bed_corner) {
+ case 0:
+ current_position[X_AXIS] = X_MIN_BED + LEVEL_CORNERS_INSET;
+ current_position[Y_AXIS] = Y_MIN_BED + LEVEL_CORNERS_INSET;
+ break;
+ case 1:
+ current_position[X_AXIS] = X_MAX_BED - LEVEL_CORNERS_INSET;
+ break;
+ case 2:
+ current_position[Y_AXIS] = Y_MAX_BED - LEVEL_CORNERS_INSET;
+ break;
+ case 3:
+ current_position[X_AXIS] = X_MIN_BED + LEVEL_CORNERS_INSET;
+ break;
+ #if ENABLED(LEVEL_CENTER_TOO)
+ case 4:
+ current_position[X_AXIS] = X_CENTER;
+ current_position[Y_AXIS] = Y_CENTER;
+ break;
+ #endif
+ }
+ planner.buffer_line(current_position, MMM_TO_MMS(manual_feedrate_mm_m[X_AXIS]), active_extruder);
+ line_to_z(0.0);
+ if (++bed_corner > 3
+ #if ENABLED(LEVEL_CENTER_TOO)
+ + 1
+ #endif
+ ) bed_corner = 0;
+ }
+
+ void _lcd_corner_submenu() {
+ START_MENU();
+ MENU_ITEM(function,
+ #if ENABLED(LEVEL_CENTER_TOO)
+ MSG_LEVEL_BED_NEXT_POINT
+ #else
+ MSG_NEXT_CORNER
+ #endif
+ , _lcd_goto_next_corner);
+ MENU_ITEM(function, MSG_BACK, lcd_goto_previous_menu_no_defer);
+ END_MENU();
+ }
+
+ void _lcd_level_bed_corners_homing() {
+ _lcd_draw_homing();
+ if (all_axes_homed()) {
+ bed_corner = 0;
+ lcd_goto_screen(_lcd_corner_submenu);
+ _lcd_goto_next_corner();
+ }
+ }
+
+ void _lcd_level_bed_corners() {
+ defer_return_to_status = true;
+ if (!all_axes_known()) {
+ axis_homed = 0;
+ enqueue_and_echo_commands_P(PSTR("G28"));
+ }
+ lcd_goto_screen(_lcd_level_bed_corners_homing);
+ }
+
+#endif // LEVEL_BED_CORNERS
+
+/**
+ * Step 1: Bed Level entry-point
+ *
+ * << Motion
+ * Auto Home (if homing needed)
+ * Leveling On/Off (if data exists, and homed)
+ * Fade Height: --- (Req: ENABLE_LEVELING_FADE_HEIGHT)
+ * Mesh Z Offset: --- (Req: MESH_BED_LEVELING)
+ * Z Probe Offset: --- (Req: HAS_BED_PROBE, Opt: BABYSTEP_ZPROBE_OFFSET)
+ * Level Bed >
+ * Level Corners > (if homed)
+ * Load Settings (Req: EEPROM_SETTINGS)
+ * Save Settings (Req: EEPROM_SETTINGS)
+ */
+void menu_bed_leveling() {
+ START_MENU();
+ MENU_BACK(MSG_MOTION);
+
+ const bool is_homed = all_axes_known();
+
+ // Auto Home if not using manual probing
+ #if DISABLED(PROBE_MANUALLY) && DISABLED(MESH_BED_LEVELING)
+ if (!is_homed) MENU_ITEM(gcode, MSG_AUTO_HOME, PSTR("G28"));
+ #endif
+
+ // Level Bed
+ #if ENABLED(PROBE_MANUALLY) || ENABLED(MESH_BED_LEVELING)
+ // Manual leveling uses a guided procedure
+ MENU_ITEM(submenu, MSG_LEVEL_BED, _lcd_level_bed_continue);
+ #else
+ // Automatic leveling can just run the G-code
+ MENU_ITEM(gcode, MSG_LEVEL_BED, is_homed ? PSTR("G29") : PSTR("G28\nG29"));
+ #endif
+
+ // Homed and leveling is valid? Then leveling can be toggled.
+ if (is_homed && leveling_is_valid()) {
+ bool new_level_state = planner.leveling_active;
+ MENU_ITEM_EDIT_CALLBACK(bool, MSG_BED_LEVELING, &new_level_state, _lcd_toggle_bed_leveling);
+ }
+
+ // Z Fade Height
+ #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
+ MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float3, MSG_Z_FADE_HEIGHT, &lcd_z_fade_height, 0, 100, _lcd_set_z_fade_height);
+ #endif
+
+ //
+ // MBL Z Offset
+ //
+ #if ENABLED(MESH_BED_LEVELING)
+ MENU_ITEM_EDIT(float43, MSG_BED_Z, &mbl.z_offset, -1, 1);
+ #endif
+
+ #if ENABLED(BABYSTEP_ZPROBE_OFFSET)
+ MENU_ITEM(submenu, MSG_ZPROBE_ZOFFSET, lcd_babystep_zoffset);
+ #elif HAS_BED_PROBE
+ MENU_ITEM_EDIT(float52, MSG_ZPROBE_ZOFFSET, &zprobe_zoffset, Z_PROBE_OFFSET_RANGE_MIN, Z_PROBE_OFFSET_RANGE_MAX);
+ #endif
+
+ #if ENABLED(LEVEL_BED_CORNERS)
+ // Move to the next corner for leveling
+ MENU_ITEM(submenu, MSG_LEVEL_CORNERS, _lcd_level_bed_corners);
+ #endif
+
+ #if ENABLED(EEPROM_SETTINGS)
+ MENU_ITEM(function, MSG_LOAD_EEPROM, lcd_load_settings);
+ MENU_ITEM(function, MSG_STORE_EEPROM, lcd_store_settings);
+ #endif
+ END_MENU();
+}
+
+#endif // HAS_LCD_MENU && LCD_BED_LEVELING
diff --git a/Marlin/src/lcd/menu/menu_configuration.cpp b/Marlin/src/lcd/menu/menu_configuration.cpp
new file mode 100644
index 0000000000..9124a218bf
--- /dev/null
+++ b/Marlin/src/lcd/menu/menu_configuration.cpp
@@ -0,0 +1,373 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+//
+// Configuration Menu
+//
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if HAS_LCD_MENU
+
+#include "menu.h"
+
+#include "../../module/configuration_store.h"
+
+#if ENABLED(FILAMENT_RUNOUT_SENSOR)
+ #include "../../feature/runout.h"
+#endif
+
+void menu_advanced_settings();
+void menu_delta_calibrate();
+
+#if HAS_LCD_CONTRAST
+ void lcd_callback_set_contrast() { set_lcd_contrast(lcd_contrast); }
+#endif
+
+static void lcd_factory_settings() {
+ settings.reset();
+ lcd_completion_feedback();
+}
+
+#if ENABLED(LCD_PROGRESS_BAR_TEST)
+
+ static void progress_bar_test() {
+ static int8_t bar_percent = 0;
+ if (use_click()) {
+ lcd_goto_previous_menu();
+ lcd_set_custom_characters(CHARSET_MENU);
+ return;
+ }
+ bar_percent += (int8_t)encoderPosition;
+ bar_percent = constrain(bar_percent, 0, 100);
+ encoderPosition = 0;
+ lcd_implementation_drawmenu_static(0, PSTR(MSG_PROGRESS_BAR_TEST), true, true);
+ lcd_moveto((LCD_WIDTH) / 2 - 2, LCD_HEIGHT - 2);
+ lcd_put_u8str(int(bar_percent)); lcd_put_wchar('%');
+ lcd_moveto(0, LCD_HEIGHT - 1); lcd_draw_progress_bar(bar_percent);
+ }
+
+ void _progress_bar_test() {
+ lcd_goto_screen(progress_bar_test);
+ lcd_set_custom_characters();
+ }
+
+#endif // LCD_PROGRESS_BAR_TEST
+
+#if HAS_DEBUG_MENU
+
+ void menu_debug() {
+ START_MENU();
+
+ MENU_BACK(MSG_MAIN);
+
+ #if ENABLED(LCD_PROGRESS_BAR_TEST)
+ MENU_ITEM(submenu, MSG_PROGRESS_BAR_TEST, _progress_bar_test);
+ #endif
+
+ END_MENU();
+ }
+
+#endif
+
+#if EXTRUDERS > 1
+
+ #include "../../module/tool_change.h"
+
+ void menu_tool_change() {
+ START_MENU();
+ MENU_BACK(MSG_MAIN);
+ #if ENABLED(SINGLENOZZLE)
+ MENU_ITEM_EDIT(float3, MSG_FILAMENT_SWAP_LENGTH, &toolchange_settings.swap_length, 0, 200);
+ MENU_MULTIPLIER_ITEM_EDIT(int4, MSG_SINGLENOZZLE_RETRACT_SPD, &toolchange_settings.retract_speed, 10, 5400);
+ MENU_MULTIPLIER_ITEM_EDIT(int4, MSG_SINGLENOZZLE_PRIME_SPD, &toolchange_settings.prime_speed, 10, 5400);
+ #endif
+ MENU_ITEM_EDIT(float3, MSG_TOOL_CHANGE_ZLIFT, &toolchange_settings.z_raise, 0, 10);
+ END_MENU();
+ }
+
+#endif
+
+#if ENABLED(DUAL_X_CARRIAGE)
+
+ #include "../../module/motion.h"
+ #include "../../gcode/queue.h"
+
+ void _recalc_IDEX_settings() {
+ if (active_extruder) { // For the 2nd extruder re-home so the next tool-change gets the new offsets.
+ enqueue_and_echo_commands_P(PSTR("G28")); // In future, we can babystep the 2nd extruder (if active), making homing unnecessary.
+ active_extruder = 0;
+ }
+ }
+
+ void menu_IDEX() {
+ START_MENU();
+ MENU_BACK(MSG_MAIN);
+
+ MENU_ITEM(gcode, MSG_IDEX_MODE_AUTOPARK, PSTR("M605 S1\nG28 X\nG1 X100"));
+ const bool need_g28 = !(TEST(axis_known_position, Y_AXIS) && TEST(axis_known_position, Z_AXIS));
+ MENU_ITEM(gcode, MSG_IDEX_MODE_DUPLICATE, need_g28
+ ? PSTR("M605 S1\nT0\nG28\nM605 S2 X200\nG28 X\nG1 X100") // If Y or Z is not homed, do a full G28 first
+ : PSTR("M605 S1\nT0\nM605 S2 X200\nG28 X\nG1 X100")
+ );
+ //MENU_ITEM(gcode, MSG_IDEX_MODE_SCALED_COPY, need_g28
+ // ? PSTR("M605 S1\nT0\nG28\nM605 S2 X200\nG28 X\nG1 X100\nM605 S3 X200") // If Y or Z is not homed, do a full G28 first
+ // : PSTR("M605 S1\nT0\nM605 S2 X200\nG28 X\nG1 X100\nM605 S3 X200")
+ //);
+ MENU_ITEM(gcode, MSG_IDEX_MODE_FULL_CTRL, PSTR("M605 S0\nG28 X"));
+ MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float52, MSG_IDEX_X_OFFSET , &hotend_offset[X_AXIS][1], MIN(X2_HOME_POS, X2_MAX_POS) - 25.0, MAX(X2_HOME_POS, X2_MAX_POS) + 25.0, _recalc_IDEX_settings);
+ MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float52, MSG_IDEX_Y_OFFSET , &hotend_offset[Y_AXIS][1], -10.0, 10.0, _recalc_IDEX_settings);
+ MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float52, MSG_IDEX_Z_OFFSET , &hotend_offset[Z_AXIS][1], -10.0, 10.0, _recalc_IDEX_settings);
+ MENU_ITEM(gcode, MSG_IDEX_SAVE_OFFSETS, PSTR("M500"));
+ END_MENU();
+ }
+
+#endif
+
+#if ENABLED(BLTOUCH)
+
+ void menu_bltouch() {
+ START_MENU();
+ MENU_BACK(MSG_MAIN);
+ MENU_ITEM(gcode, MSG_BLTOUCH_RESET, PSTR("M280 P" STRINGIFY(Z_PROBE_SERVO_NR) " S" STRINGIFY(BLTOUCH_RESET)));
+ MENU_ITEM(gcode, MSG_BLTOUCH_SELFTEST, PSTR("M280 P" STRINGIFY(Z_PROBE_SERVO_NR) " S" STRINGIFY(BLTOUCH_SELFTEST)));
+ MENU_ITEM(gcode, MSG_BLTOUCH_DEPLOY, PSTR("M280 P" STRINGIFY(Z_PROBE_SERVO_NR) " S" STRINGIFY(BLTOUCH_DEPLOY)));
+ MENU_ITEM(gcode, MSG_BLTOUCH_STOW, PSTR("M280 P" STRINGIFY(Z_PROBE_SERVO_NR) " S" STRINGIFY(BLTOUCH_STOW)));
+ END_MENU();
+ }
+
+#endif
+
+#if ENABLED(MENU_ITEM_CASE_LIGHT)
+
+ #include "../../feature/caselight.h"
+
+ void menu_case_light() {
+ START_MENU();
+ MENU_BACK(MSG_MAIN);
+ MENU_ITEM_EDIT_CALLBACK(int8, MSG_CASE_LIGHT_BRIGHTNESS, &case_light_brightness, 0, 255, update_case_light, true);
+ MENU_ITEM_EDIT_CALLBACK(bool, MSG_CASE_LIGHT, (bool*)&case_light_on, update_case_light);
+ END_MENU();
+ }
+
+#endif
+
+#if ENABLED(FWRETRACT)
+
+ #include "../../feature/fwretract.h"
+
+ void menu_config_retract() {
+ START_MENU();
+ MENU_BACK(MSG_CONTROL);
+ #if ENABLED(FWRETRACT_AUTORETRACT)
+ MENU_ITEM_EDIT_CALLBACK(bool, MSG_AUTORETRACT, &fwretract.autoretract_enabled, fwretract.refresh_autoretract);
+ #endif
+ MENU_ITEM_EDIT(float52sign, MSG_CONTROL_RETRACT, &fwretract.settings.retract_length, 0, 100);
+ #if EXTRUDERS > 1
+ MENU_ITEM_EDIT(float52sign, MSG_CONTROL_RETRACT_SWAP, &fwretract.settings.swap_retract_length, 0, 100);
+ #endif
+ MENU_ITEM_EDIT(float3, MSG_CONTROL_RETRACTF, &fwretract.settings.retract_feedrate_mm_s, 1, 999);
+ MENU_ITEM_EDIT(float52sign, MSG_CONTROL_RETRACT_ZHOP, &fwretract.settings.retract_zraise, 0, 999);
+ MENU_ITEM_EDIT(float52sign, MSG_CONTROL_RETRACT_RECOVER, &fwretract.settings.retract_recover_length, -100, 100);
+ #if EXTRUDERS > 1
+ MENU_ITEM_EDIT(float52sign, MSG_CONTROL_RETRACT_RECOVER_SWAP, &fwretract.settings.swap_retract_recover_length, -100, 100);
+ #endif
+ MENU_ITEM_EDIT(float3, MSG_CONTROL_RETRACT_RECOVERF, &fwretract.settings.retract_recover_feedrate_mm_s, 1, 999);
+ #if EXTRUDERS > 1
+ MENU_ITEM_EDIT(float3, MSG_CONTROL_RETRACT_RECOVER_SWAPF, &fwretract.settings.swap_retract_recover_feedrate_mm_s, 1, 999);
+ #endif
+ END_MENU();
+ }
+
+#endif
+
+#if ENABLED(DAC_STEPPER_CURRENT)
+
+ #include "../../feature/dac/stepper_dac.h"
+
+ uint8_t driverPercent[XYZE];
+ inline void dac_driver_getValues() { LOOP_XYZE(i) driverPercent[i] = dac_current_get_percent((AxisEnum)i); }
+ static void dac_driver_commit() { dac_current_set_percents(driverPercent); }
+
+ void menu_dac() {
+ dac_driver_getValues();
+ START_MENU();
+ MENU_BACK(MSG_CONTROL);
+ #define EDIT_DAC_PERCENT(N) MENU_ITEM_EDIT_CALLBACK(int8, MSG_##N " " MSG_DAC_PERCENT, &driverPercent[_AXIS(N)], 0, 100, dac_driver_commit)
+ EDIT_DAC_PERCENT(X);
+ EDIT_DAC_PERCENT(Y);
+ EDIT_DAC_PERCENT(Z);
+ EDIT_DAC_PERCENT(E);
+ MENU_ITEM(function, MSG_DAC_EEPROM_WRITE, dac_commit_eeprom);
+ END_MENU();
+ }
+
+#endif
+
+#if HAS_MOTOR_CURRENT_PWM
+
+ #include "../../module/stepper.h"
+
+ void menu_pwm() {
+ START_MENU();
+ MENU_BACK(MSG_CONTROL);
+ #define EDIT_CURRENT_PWM(LABEL,I) MENU_ITEM_EDIT_CALLBACK(long5, LABEL, &stepper.motor_current_setting[I], 100, 2000, stepper.refresh_motor_power)
+ #if PIN_EXISTS(MOTOR_CURRENT_PWM_XY)
+ EDIT_CURRENT_PWM(MSG_X MSG_Y, 0);
+ #endif
+ #if PIN_EXISTS(MOTOR_CURRENT_PWM_Z)
+ EDIT_CURRENT_PWM(MSG_Z, 1);
+ #endif
+ #if PIN_EXISTS(MOTOR_CURRENT_PWM_E)
+ EDIT_CURRENT_PWM(MSG_E, 2);
+ #endif
+ END_MENU();
+ }
+
+#endif
+
+#if DISABLED(SLIM_LCD_MENUS)
+
+ void _menu_configuration_preheat_settings(const uint8_t material) {
+ #if HOTENDS > 5
+ #define MINTEMP_ALL MIN(HEATER_0_MINTEMP, HEATER_1_MINTEMP, HEATER_2_MINTEMP, HEATER_3_MINTEMP, HEATER_4_MINTEMP, HEATER_5_MINTEMP)
+ #define MAXTEMP_ALL MAX(HEATER_0_MAXTEMP, HEATER_1_MAXTEMP, HEATER_2_MAXTEMP, HEATER_3_MAXTEMP, HEATER_4_MAXTEMP, HEATER_5_MAXTEMP)
+ #elif HOTENDS > 4
+ #define MINTEMP_ALL MIN(HEATER_0_MINTEMP, HEATER_1_MINTEMP, HEATER_2_MINTEMP, HEATER_3_MINTEMP, HEATER_4_MINTEMP)
+ #define MAXTEMP_ALL MAX(HEATER_0_MAXTEMP, HEATER_1_MAXTEMP, HEATER_2_MAXTEMP, HEATER_3_MAXTEMP, HEATER_4_MAXTEMP)
+ #elif HOTENDS > 3
+ #define MINTEMP_ALL MIN(HEATER_0_MINTEMP, HEATER_1_MINTEMP, HEATER_2_MINTEMP, HEATER_3_MINTEMP)
+ #define MAXTEMP_ALL MAX(HEATER_0_MAXTEMP, HEATER_1_MAXTEMP, HEATER_2_MAXTEMP, HEATER_3_MAXTEMP)
+ #elif HOTENDS > 2
+ #define MINTEMP_ALL MIN(HEATER_0_MINTEMP, HEATER_1_MINTEMP, HEATER_2_MINTEMP)
+ #define MAXTEMP_ALL MAX(HEATER_0_MAXTEMP, HEATER_1_MAXTEMP, HEATER_2_MAXTEMP)
+ #elif HOTENDS > 1
+ #define MINTEMP_ALL MIN(HEATER_0_MINTEMP, HEATER_1_MINTEMP)
+ #define MAXTEMP_ALL MAX(HEATER_0_MAXTEMP, HEATER_1_MAXTEMP)
+ #else
+ #define MINTEMP_ALL HEATER_0_MINTEMP
+ #define MAXTEMP_ALL HEATER_0_MAXTEMP
+ #endif
+ START_MENU();
+ MENU_BACK(MSG_CONFIGURATION);
+ MENU_ITEM_EDIT(int8, MSG_FAN_SPEED, &lcd_preheat_fan_speed[material], 0, 255);
+ #if HAS_TEMP_HOTEND
+ MENU_ITEM_EDIT(int3, MSG_NOZZLE, &lcd_preheat_hotend_temp[material], MINTEMP_ALL, MAXTEMP_ALL - 15);
+ #endif
+ #if HAS_HEATED_BED
+ MENU_ITEM_EDIT(int3, MSG_BED, &lcd_preheat_bed_temp[material], BED_MINTEMP, BED_MAXTEMP - 15);
+ #endif
+ #if ENABLED(EEPROM_SETTINGS)
+ MENU_ITEM(function, MSG_STORE_EEPROM, lcd_store_settings);
+ #endif
+ END_MENU();
+ }
+
+ void menu_preheat_material1_settings() { _menu_configuration_preheat_settings(0); }
+ void menu_preheat_material2_settings() { _menu_configuration_preheat_settings(1); }
+
+#endif
+
+void menu_configuration() {
+ START_MENU();
+ MENU_BACK(MSG_MAIN);
+
+ //
+ // Debug Menu when certain options are enabled
+ //
+ #if HAS_DEBUG_MENU
+ MENU_ITEM(submenu, MSG_DEBUG_MENU, menu_debug);
+ #endif
+
+ MENU_ITEM(submenu, MSG_ADVANCED_SETTINGS, menu_advanced_settings);
+
+ const bool busy = printer_busy();
+ if (!busy) {
+ //
+ // Delta Calibration
+ //
+ #if ENABLED(DELTA_CALIBRATION_MENU) || ENABLED(DELTA_AUTO_CALIBRATION)
+ MENU_ITEM(submenu, MSG_DELTA_CALIBRATE, menu_delta_calibrate);
+ #endif
+
+ #if ENABLED(DUAL_X_CARRIAGE)
+ MENU_ITEM(submenu, MSG_IDEX_MENU, menu_IDEX);
+ #endif
+
+ #if ENABLED(BLTOUCH)
+ MENU_ITEM(submenu, MSG_BLTOUCH, menu_bltouch);
+ #endif
+ }
+
+ //
+ // Set single nozzle filament retract and prime length
+ //
+ #if EXTRUDERS > 1
+ MENU_ITEM(submenu, MSG_TOOL_CHANGE, menu_tool_change);
+ #endif
+
+ //
+ // Set Case light on/off/brightness
+ //
+ #if ENABLED(MENU_ITEM_CASE_LIGHT)
+ if (USEABLE_HARDWARE_PWM(CASE_LIGHT_PIN))
+ MENU_ITEM(submenu, MSG_CASE_LIGHT, menu_case_light);
+ else
+ MENU_ITEM_EDIT_CALLBACK(bool, MSG_CASE_LIGHT, (bool*)&case_light_on, update_case_light);
+ #endif
+
+ #if HAS_LCD_CONTRAST
+ MENU_ITEM_EDIT_CALLBACK(int3, MSG_CONTRAST, &lcd_contrast, LCD_CONTRAST_MIN, LCD_CONTRAST_MAX, lcd_callback_set_contrast, true);
+ #endif
+ #if ENABLED(FWRETRACT)
+ MENU_ITEM(submenu, MSG_RETRACT, menu_config_retract);
+ #endif
+ #if ENABLED(DAC_STEPPER_CURRENT)
+ MENU_ITEM(submenu, MSG_DRIVE_STRENGTH, menu_dac);
+ #endif
+ #if HAS_MOTOR_CURRENT_PWM
+ MENU_ITEM(submenu, MSG_DRIVE_STRENGTH, menu_pwm);
+ #endif
+
+ #if ENABLED(FILAMENT_RUNOUT_SENSOR)
+ MENU_ITEM_EDIT(bool, MSG_RUNOUT_SENSOR_ENABLE, &runout.enabled);
+ #endif
+
+ #if DISABLED(SLIM_LCD_MENUS)
+ // Preheat configurations
+ MENU_ITEM(submenu, MSG_PREHEAT_1_SETTINGS, menu_preheat_material1_settings);
+ MENU_ITEM(submenu, MSG_PREHEAT_2_SETTINGS, menu_preheat_material2_settings);
+ #endif
+
+ #if ENABLED(EEPROM_SETTINGS)
+ MENU_ITEM(function, MSG_STORE_EEPROM, lcd_store_settings);
+ if (!busy)
+ MENU_ITEM(function, MSG_LOAD_EEPROM, lcd_load_settings);
+ #endif
+
+ if (!busy)
+ MENU_ITEM(function, MSG_RESTORE_FAILSAFE, lcd_factory_settings);
+
+ END_MENU();
+}
+
+#endif // HAS_LCD_MENU
diff --git a/Marlin/src/lcd/menu/menu_custom.cpp b/Marlin/src/lcd/menu/menu_custom.cpp
new file mode 100644
index 0000000000..f823a1049f
--- /dev/null
+++ b/Marlin/src/lcd/menu/menu_custom.cpp
@@ -0,0 +1,87 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+//
+// Custom User Menu
+//
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if HAS_LCD_MENU && ENABLED(CUSTOM_USER_MENUS)
+
+#include "menu.h"
+#include "../../gcode/queue.h"
+
+#ifdef USER_SCRIPT_DONE
+ #define _DONE_SCRIPT "\n" USER_SCRIPT_DONE
+#else
+ #define _DONE_SCRIPT ""
+#endif
+
+void _lcd_user_gcode(PGM_P const cmd) {
+ enqueue_and_echo_commands_P(cmd);
+ #if ENABLED(USER_SCRIPT_AUDIBLE_FEEDBACK)
+ lcd_completion_feedback();
+ #endif
+ #if ENABLED(USER_SCRIPT_RETURN)
+ lcd_return_to_status();
+ #endif
+}
+
+#if defined(USER_DESC_1) && defined(USER_GCODE_1)
+ void lcd_user_gcode_1() { _lcd_user_gcode(PSTR(USER_GCODE_1 _DONE_SCRIPT)); }
+#endif
+#if defined(USER_DESC_2) && defined(USER_GCODE_2)
+ void lcd_user_gcode_2() { _lcd_user_gcode(PSTR(USER_GCODE_2 _DONE_SCRIPT)); }
+#endif
+#if defined(USER_DESC_3) && defined(USER_GCODE_3)
+ void lcd_user_gcode_3() { _lcd_user_gcode(PSTR(USER_GCODE_3 _DONE_SCRIPT)); }
+#endif
+#if defined(USER_DESC_4) && defined(USER_GCODE_4)
+ void lcd_user_gcode_4() { _lcd_user_gcode(PSTR(USER_GCODE_4 _DONE_SCRIPT)); }
+#endif
+#if defined(USER_DESC_5) && defined(USER_GCODE_5)
+ void lcd_user_gcode_5() { _lcd_user_gcode(PSTR(USER_GCODE_5 _DONE_SCRIPT)); }
+#endif
+
+void menu_user() {
+ START_MENU();
+ MENU_BACK(MSG_MAIN);
+ #if defined(USER_DESC_1) && defined(USER_GCODE_1)
+ MENU_ITEM(function, USER_DESC_1, lcd_user_gcode_1);
+ #endif
+ #if defined(USER_DESC_2) && defined(USER_GCODE_2)
+ MENU_ITEM(function, USER_DESC_2, lcd_user_gcode_2);
+ #endif
+ #if defined(USER_DESC_3) && defined(USER_GCODE_3)
+ MENU_ITEM(function, USER_DESC_3, lcd_user_gcode_3);
+ #endif
+ #if defined(USER_DESC_4) && defined(USER_GCODE_4)
+ MENU_ITEM(function, USER_DESC_4, lcd_user_gcode_4);
+ #endif
+ #if defined(USER_DESC_5) && defined(USER_GCODE_5)
+ MENU_ITEM(function, USER_DESC_5, lcd_user_gcode_5);
+ #endif
+ END_MENU();
+}
+
+#endif // HAS_LCD_MENU && CUSTOM_USER_MENUS
diff --git a/Marlin/src/lcd/menu/menu_delta_calibrate.cpp b/Marlin/src/lcd/menu/menu_delta_calibrate.cpp
new file mode 100644
index 0000000000..62692f03c5
--- /dev/null
+++ b/Marlin/src/lcd/menu/menu_delta_calibrate.cpp
@@ -0,0 +1,137 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+//
+// Delta Calibrate Menu
+//
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if HAS_LCD_MENU && (ENABLED(DELTA_CALIBRATION_MENU) || ENABLED(DELTA_AUTO_CALIBRATION))
+
+#include "menu.h"
+#include "../../module/delta.h"
+#include "../../module/motion.h"
+
+#if HAS_LEVELING
+ #include "../../feature/bedlevel/bedlevel.h"
+#endif
+
+void _man_probe_pt(const float &rx, const float &ry) {
+ do_blocking_move_to(rx, ry, Z_CLEARANCE_BETWEEN_PROBES);
+ lcd_synchronize();
+ move_menu_scale = MAX(PROBE_MANUALLY_STEP, MIN_STEPS_PER_SEGMENT / float(DEFAULT_XYZ_STEPS_PER_UNIT));
+ lcd_goto_screen(lcd_move_z);
+}
+
+#if ENABLED(DELTA_AUTO_CALIBRATION)
+
+ #include "../../gcode/gcode.h"
+
+ float lcd_probe_pt(const float &rx, const float &ry) {
+ _man_probe_pt(rx, ry);
+ KEEPALIVE_STATE(PAUSED_FOR_USER);
+ defer_return_to_status = true;
+ wait_for_user = true;
+ while (wait_for_user) idle();
+ KEEPALIVE_STATE(IN_HANDLER);
+ lcd_goto_previous_menu_no_defer();
+ return current_position[Z_AXIS];
+ }
+
+#endif
+
+#if ENABLED(DELTA_CALIBRATION_MENU)
+
+ #include "../../gcode/queue.h"
+
+ void _lcd_calibrate_homing() {
+ _lcd_draw_homing();
+ if (all_axes_homed()) lcd_goto_previous_menu();
+ }
+
+ void _lcd_delta_calibrate_home() {
+ enqueue_and_echo_commands_P(PSTR("G28"));
+ lcd_goto_screen(_lcd_calibrate_homing);
+ }
+
+ void _goto_tower_x() { _man_probe_pt(cos(RADIANS(210)) * delta_calibration_radius, sin(RADIANS(210)) * delta_calibration_radius); }
+ void _goto_tower_y() { _man_probe_pt(cos(RADIANS(330)) * delta_calibration_radius, sin(RADIANS(330)) * delta_calibration_radius); }
+ void _goto_tower_z() { _man_probe_pt(cos(RADIANS( 90)) * delta_calibration_radius, sin(RADIANS( 90)) * delta_calibration_radius); }
+ void _goto_center() { _man_probe_pt(0,0); }
+
+#endif
+
+void _recalc_delta_settings() {
+ #if HAS_LEVELING
+ reset_bed_level(); // After changing kinematics bed-level data is no longer valid
+ #endif
+ recalc_delta_settings();
+}
+
+void lcd_delta_settings() {
+ START_MENU();
+ MENU_BACK(MSG_DELTA_CALIBRATE);
+ MENU_ITEM_EDIT_CALLBACK(float52sign, MSG_DELTA_HEIGHT, &delta_height, delta_height - 10, delta_height + 10, _recalc_delta_settings);
+ #define EDIT_ENDSTOP_ADJ(LABEL,N) MENU_ITEM_EDIT_CALLBACK(float43, LABEL, &delta_endstop_adj[_AXIS(N)], -5, 5, _recalc_delta_settings)
+ EDIT_ENDSTOP_ADJ("Ex",A);
+ EDIT_ENDSTOP_ADJ("Ey",B);
+ EDIT_ENDSTOP_ADJ("Ez",C);
+ MENU_ITEM_EDIT_CALLBACK(float52sign, MSG_DELTA_RADIUS, &delta_radius, delta_radius - 5, delta_radius + 5, _recalc_delta_settings);
+ #define EDIT_ANGLE_TRIM(LABEL,N) MENU_ITEM_EDIT_CALLBACK(float43, LABEL, &delta_tower_angle_trim[_AXIS(N)], -5, 5, _recalc_delta_settings)
+ EDIT_ANGLE_TRIM("Tx",A);
+ EDIT_ANGLE_TRIM("Ty",B);
+ EDIT_ANGLE_TRIM("Tz",C);
+ MENU_ITEM_EDIT_CALLBACK(float52sign, MSG_DELTA_DIAG_ROD, &delta_diagonal_rod, delta_diagonal_rod - 5, delta_diagonal_rod + 5, _recalc_delta_settings);
+ END_MENU();
+}
+
+void menu_delta_calibrate() {
+ START_MENU();
+ MENU_BACK(MSG_MAIN);
+
+ #if ENABLED(DELTA_AUTO_CALIBRATION)
+ MENU_ITEM(gcode, MSG_DELTA_AUTO_CALIBRATE, PSTR("G33"));
+ MENU_ITEM(gcode, MSG_DELTA_HEIGHT_CALIBRATE, PSTR("G33 S P1"));
+ MENU_ITEM(gcode, MSG_DELTA_Z_OFFSET_CALIBRATE, PSTR("G33 P-1"));
+ #if ENABLED(EEPROM_SETTINGS)
+ MENU_ITEM(function, MSG_STORE_EEPROM, lcd_store_settings);
+ MENU_ITEM(function, MSG_LOAD_EEPROM, lcd_load_settings);
+ #endif
+ #endif
+
+ MENU_ITEM(submenu, MSG_DELTA_SETTINGS, lcd_delta_settings);
+
+ #if ENABLED(DELTA_CALIBRATION_MENU)
+ MENU_ITEM(submenu, MSG_AUTO_HOME, _lcd_delta_calibrate_home);
+ if (all_axes_homed()) {
+ MENU_ITEM(submenu, MSG_DELTA_CALIBRATE_X, _goto_tower_x);
+ MENU_ITEM(submenu, MSG_DELTA_CALIBRATE_Y, _goto_tower_y);
+ MENU_ITEM(submenu, MSG_DELTA_CALIBRATE_Z, _goto_tower_z);
+ MENU_ITEM(submenu, MSG_DELTA_CALIBRATE_CENTER, _goto_center);
+ }
+ #endif
+
+ END_MENU();
+}
+
+#endif // HAS_LCD_MENU && (DELTA_CALIBRATION_MENU || DELTA_AUTO_CALIBRATION)
diff --git a/Marlin/src/lcd/menu/menu_filament.cpp b/Marlin/src/lcd/menu/menu_filament.cpp
new file mode 100644
index 0000000000..2a46c48309
--- /dev/null
+++ b/Marlin/src/lcd/menu/menu_filament.cpp
@@ -0,0 +1,581 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+//
+// Filament Change Menu
+//
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if HAS_LCD_MENU && ENABLED(ADVANCED_PAUSE_FEATURE)
+
+#include "menu.h"
+#include "../../module/temperature.h"
+#include "../../feature/pause.h"
+
+//
+// Change Filament > Change/Unload/Load Filament
+//
+static AdvancedPauseMode _change_filament_temp_mode; // =ADVANCED_PAUSE_MODE_PAUSE_PRINT
+static int8_t _change_filament_temp_extruder; // =0
+
+static PGM_P _change_filament_temp_command() {
+ switch (_change_filament_temp_mode) {
+ case ADVANCED_PAUSE_MODE_LOAD_FILAMENT:
+ return PSTR("M701 T%d");
+ case ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT:
+ return _change_filament_temp_extruder >= 0 ? PSTR("M702 T%d") : PSTR("M702 ;%d");
+ case ADVANCED_PAUSE_MODE_PAUSE_PRINT:
+ default:
+ return PSTR("M600 B0 T%d");
+ }
+ return PSTR(MSG_FILAMENTCHANGE);
+}
+
+void _change_filament_temp(const uint16_t temperature) {
+ char cmd[11];
+ sprintf_P(cmd, _change_filament_temp_command(), _change_filament_temp_extruder);
+ thermalManager.setTargetHotend(temperature, _change_filament_temp_extruder);
+ lcd_enqueue_command(cmd);
+}
+void _menu_change_filament_temp_1() { _change_filament_temp(PREHEAT_1_TEMP_HOTEND); }
+void _menu_change_filament_temp_2() { _change_filament_temp(PREHEAT_2_TEMP_HOTEND); }
+void _menu_change_filament_temp_custom() { _change_filament_temp(thermalManager.target_temperature[_change_filament_temp_extruder]); }
+
+static PGM_P change_filament_header(const AdvancedPauseMode mode) {
+ switch (mode) {
+ case ADVANCED_PAUSE_MODE_LOAD_FILAMENT:
+ return PSTR(MSG_FILAMENTLOAD);
+ case ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT:
+ return PSTR(MSG_FILAMENTUNLOAD);
+ default: break;
+ }
+ return PSTR(MSG_FILAMENTCHANGE);
+}
+
+void _menu_temp_filament_op(const AdvancedPauseMode mode, const int8_t extruder) {
+ _change_filament_temp_mode = mode;
+ _change_filament_temp_extruder = extruder;
+ START_MENU();
+ if (LCD_HEIGHT >= 4) STATIC_ITEM_P(change_filament_header(mode), true, true);
+ MENU_BACK(MSG_BACK);
+ MENU_ITEM(submenu, MSG_PREHEAT_1, _menu_change_filament_temp_1);
+ MENU_ITEM(submenu, MSG_PREHEAT_2, _menu_change_filament_temp_2);
+ uint16_t max_temp;
+ switch (extruder) {
+ default: max_temp = HEATER_0_MAXTEMP;
+ #if HOTENDS > 1
+ case 1: max_temp = HEATER_1_MAXTEMP; break;
+ #if HOTENDS > 2
+ case 2: max_temp = HEATER_2_MAXTEMP; break;
+ #if HOTENDS > 3
+ case 3: max_temp = HEATER_3_MAXTEMP; break;
+ #if HOTENDS > 4
+ case 4: max_temp = HEATER_4_MAXTEMP; break;
+ #if HOTENDS > 5
+ case 5: max_temp = HEATER_5_MAXTEMP; break;
+ #endif
+ #endif
+ #endif
+ #endif
+ #endif
+ }
+ MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_PREHEAT_CUSTOM, &thermalManager.target_temperature[_change_filament_temp_extruder], EXTRUDE_MINTEMP, max_temp - 15, _menu_change_filament_temp_custom);
+ END_MENU();
+}
+void menu_temp_e0_filament_change() { _menu_temp_filament_op(ADVANCED_PAUSE_MODE_PAUSE_PRINT, 0); }
+void menu_temp_e0_filament_load() { _menu_temp_filament_op(ADVANCED_PAUSE_MODE_LOAD_FILAMENT, 0); }
+void menu_temp_e0_filament_unload() { _menu_temp_filament_op(ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT, 0); }
+#if E_STEPPERS > 1
+ void menu_temp_e1_filament_change() { _menu_temp_filament_op(ADVANCED_PAUSE_MODE_PAUSE_PRINT, 1); }
+ void menu_temp_e1_filament_load() { _menu_temp_filament_op(ADVANCED_PAUSE_MODE_LOAD_FILAMENT, 1); }
+ void menu_temp_e1_filament_unload() { _menu_temp_filament_op(ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT, 1); }
+ #if ENABLED(FILAMENT_UNLOAD_ALL_EXTRUDERS)
+ void menu_unload_filament_all_temp() { _menu_temp_filament_op(ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT, -1); }
+ #endif
+ #if E_STEPPERS > 2
+ void menu_temp_e2_filament_change() { _menu_temp_filament_op(ADVANCED_PAUSE_MODE_PAUSE_PRINT, 2); }
+ void menu_temp_e2_filament_load() { _menu_temp_filament_op(ADVANCED_PAUSE_MODE_LOAD_FILAMENT, 2); }
+ void menu_temp_e2_filament_unload() { _menu_temp_filament_op(ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT, 2); }
+ #if E_STEPPERS > 3
+ void menu_temp_e3_filament_change() { _menu_temp_filament_op(ADVANCED_PAUSE_MODE_PAUSE_PRINT, 3); }
+ void menu_temp_e3_filament_load() { _menu_temp_filament_op(ADVANCED_PAUSE_MODE_LOAD_FILAMENT, 3); }
+ void menu_temp_e3_filament_unload() { _menu_temp_filament_op(ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT, 3); }
+ #if E_STEPPERS > 4
+ void menu_temp_e4_filament_change() { _menu_temp_filament_op(ADVANCED_PAUSE_MODE_PAUSE_PRINT, 4); }
+ void menu_temp_e4_filament_load() { _menu_temp_filament_op(ADVANCED_PAUSE_MODE_LOAD_FILAMENT, 4); }
+ void menu_temp_e4_filament_unload() { _menu_temp_filament_op(ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT, 4); }
+ #endif // E_STEPPERS > 4
+ #endif // E_STEPPERS > 3
+ #endif // E_STEPPERS > 2
+#endif // E_STEPPERS > 1
+
+/**
+ *
+ * "Change Filament" submenu
+ *
+ */
+#if E_STEPPERS > 1 || ENABLED(FILAMENT_LOAD_UNLOAD_GCODES)
+ void menu_change_filament() {
+ START_MENU();
+ MENU_BACK(MSG_MAIN);
+
+ // Change filament
+ #if E_STEPPERS == 1
+ PGM_P msg0 = PSTR(MSG_FILAMENTCHANGE);
+ if (thermalManager.targetTooColdToExtrude(active_extruder))
+ MENU_ITEM_P(submenu, msg0, menu_temp_e0_filament_change);
+ else
+ MENU_ITEM_P(gcode, msg0, PSTR("M600 B0"));
+ #else
+ PGM_P msg0 = PSTR(MSG_FILAMENTCHANGE " " MSG_E1);
+ PGM_P msg1 = PSTR(MSG_FILAMENTCHANGE " " MSG_E2);
+ if (thermalManager.targetTooColdToExtrude(0))
+ MENU_ITEM_P(submenu, msg0, menu_temp_e0_filament_change);
+ else
+ MENU_ITEM_P(gcode, msg0, PSTR("M600 B0 T0"));
+ if (thermalManager.targetTooColdToExtrude(1))
+ MENU_ITEM_P(submenu, msg1, menu_temp_e1_filament_change);
+ else
+ MENU_ITEM_P(gcode, msg1, PSTR("M600 B0 T1"));
+ #if E_STEPPERS > 2
+ PGM_P msg2 = PSTR(MSG_FILAMENTCHANGE " " MSG_E3);
+ if (thermalManager.targetTooColdToExtrude(2))
+ MENU_ITEM_P(submenu, msg2, menu_temp_e2_filament_change);
+ else
+ MENU_ITEM_P(gcode, msg2, PSTR("M600 B0 T2"));
+ #if E_STEPPERS > 3
+ PGM_P msg3 = PSTR(MSG_FILAMENTCHANGE " " MSG_E4);
+ if (thermalManager.targetTooColdToExtrude(3))
+ MENU_ITEM_P(submenu, msg3, menu_temp_e3_filament_change);
+ else
+ MENU_ITEM_P(gcode, msg3, PSTR("M600 B0 T3"));
+ #if E_STEPPERS > 4
+ PGM_P msg4 = PSTR(MSG_FILAMENTCHANGE " " MSG_E5);
+ if (thermalManager.targetTooColdToExtrude(4))
+ MENU_ITEM_P(submenu, msg4, menu_temp_e4_filament_change);
+ else
+ MENU_ITEM_P(gcode, msg4, PSTR("M600 B0 T4"));
+ #if E_STEPPERS > 5
+ PGM_P msg5 = PSTR(MSG_FILAMENTCHANGE " " MSG_E6);
+ if (thermalManager.targetTooColdToExtrude(5))
+ MENU_ITEM_P(submenu, msg5, menu_temp_e5_filament_change);
+ else
+ MENU_ITEM_P(gcode, msg5, PSTR("M600 B0 T5"));
+ #endif // E_STEPPERS > 5
+ #endif // E_STEPPERS > 4
+ #endif // E_STEPPERS > 3
+ #endif // E_STEPPERS > 2
+ #endif // E_STEPPERS == 1
+
+ #if ENABLED(FILAMENT_LOAD_UNLOAD_GCODES)
+ if (!printer_busy()) {
+ // Load filament
+ #if E_STEPPERS == 1
+ PGM_P msg0 = PSTR(MSG_FILAMENTLOAD);
+ if (thermalManager.targetTooColdToExtrude(active_extruder))
+ MENU_ITEM_P(submenu, msg0, menu_temp_e0_filament_load);
+ else
+ MENU_ITEM_P(gcode, msg0, PSTR("M701"));
+ #else
+ PGM_P msg0 = PSTR(MSG_FILAMENTLOAD " " MSG_E1);
+ PGM_P msg1 = PSTR(MSG_FILAMENTLOAD " " MSG_E2);
+ if (thermalManager.targetTooColdToExtrude(0))
+ MENU_ITEM_P(submenu, msg0, menu_temp_e0_filament_load);
+ else
+ MENU_ITEM_P(gcode, msg0, PSTR("M701 T0"));
+ if (thermalManager.targetTooColdToExtrude(1))
+ MENU_ITEM_P(submenu, msg1, menu_temp_e1_filament_load);
+ else
+ MENU_ITEM_P(gcode, msg1, PSTR("M701 T1"));
+ #if E_STEPPERS > 2
+ PGM_P msg2 = PSTR(MSG_FILAMENTLOAD " " MSG_E3);
+ if (thermalManager.targetTooColdToExtrude(2))
+ MENU_ITEM_P(submenu, msg2, menu_temp_e2_filament_load);
+ else
+ MENU_ITEM_P(gcode, msg2, PSTR("M701 T2"));
+ #if E_STEPPERS > 3
+ PGM_P msg3 = PSTR(MSG_FILAMENTLOAD " " MSG_E4);
+ if (thermalManager.targetTooColdToExtrude(3))
+ MENU_ITEM_P(submenu, msg3, menu_temp_e3_filament_load);
+ else
+ MENU_ITEM_P(gcode, msg3, PSTR("M701 T3"));
+ #if E_STEPPERS > 4
+ PGM_P msg4 = PSTR(MSG_FILAMENTLOAD " " MSG_E5);
+ if (thermalManager.targetTooColdToExtrude(4))
+ MENU_ITEM_P(submenu, msg4, menu_temp_e4_filament_load);
+ else
+ MENU_ITEM_P(gcode, msg4, PSTR("M701 T4"));
+ #if E_STEPPERS > 5
+ PGM_P msg5 = PSTR(MSG_FILAMENTLOAD " " MSG_E6);
+ if (thermalManager.targetTooColdToExtrude(5))
+ MENU_ITEM_P(submenu, msg5, menu_temp_e5_filament_load);
+ else
+ MENU_ITEM_P(gcode, msg5, PSTR("M701 T5"));
+ #endif // E_STEPPERS > 5
+ #endif // E_STEPPERS > 4
+ #endif // E_STEPPERS > 3
+ #endif // E_STEPPERS > 2
+ #endif // E_STEPPERS == 1
+
+ // Unload filament
+ #if E_STEPPERS == 1
+ if (thermalManager.targetHotEnoughToExtrude(active_extruder))
+ MENU_ITEM(gcode, MSG_FILAMENTUNLOAD, PSTR("M702"));
+ else
+ MENU_ITEM(submenu, MSG_FILAMENTUNLOAD, menu_temp_e0_filament_unload);
+ #else
+ #if ENABLED(FILAMENT_UNLOAD_ALL_EXTRUDERS)
+ if (thermalManager.targetHotEnoughToExtrude(0)
+ #if E_STEPPERS > 1
+ && thermalManager.targetHotEnoughToExtrude(1)
+ #if E_STEPPERS > 2
+ && thermalManager.targetHotEnoughToExtrude(2)
+ #if E_STEPPERS > 3
+ && thermalManager.targetHotEnoughToExtrude(3)
+ #if E_STEPPERS > 4
+ && thermalManager.targetHotEnoughToExtrude(4)
+ #if E_STEPPERS > 5
+ && thermalManager.targetHotEnoughToExtrude(5)
+ #endif // E_STEPPERS > 5
+ #endif // E_STEPPERS > 4
+ #endif // E_STEPPERS > 3
+ #endif // E_STEPPERS > 2
+ #endif // E_STEPPERS > 1
+ )
+ MENU_ITEM(gcode, MSG_FILAMENTUNLOAD_ALL, PSTR("M702"));
+ else
+ MENU_ITEM(submenu, MSG_FILAMENTUNLOAD_ALL, menu_unload_filament_all_temp);
+ #endif
+ if (thermalManager.targetHotEnoughToExtrude(0))
+ MENU_ITEM(gcode, MSG_FILAMENTUNLOAD " " MSG_E1, PSTR("M702 T0"));
+ else
+ MENU_ITEM(submenu, MSG_FILAMENTUNLOAD " " MSG_E1, menu_temp_e0_filament_unload);
+ if (thermalManager.targetHotEnoughToExtrude(1))
+ MENU_ITEM(gcode, MSG_FILAMENTUNLOAD " " MSG_E2, PSTR("M702 T1"));
+ else
+ MENU_ITEM(submenu, MSG_FILAMENTUNLOAD " " MSG_E2, menu_temp_e1_filament_unload);
+ #if E_STEPPERS > 2
+ if (thermalManager.targetHotEnoughToExtrude(2))
+ MENU_ITEM(gcode, MSG_FILAMENTUNLOAD " " MSG_E3, PSTR("M702 T2"));
+ else
+ MENU_ITEM(submenu, MSG_FILAMENTUNLOAD " " MSG_E3, menu_temp_e2_filament_unload);
+ #if E_STEPPERS > 3
+ if (thermalManager.targetHotEnoughToExtrude(3))
+ MENU_ITEM(gcode, MSG_FILAMENTUNLOAD " " MSG_E4, PSTR("M702 T3"));
+ else
+ MENU_ITEM(submenu, MSG_FILAMENTUNLOAD " " MSG_E4, menu_temp_e3_filament_unload);
+ #if E_STEPPERS > 4
+ if (thermalManager.targetHotEnoughToExtrude(4))
+ MENU_ITEM(gcode, MSG_FILAMENTUNLOAD " " MSG_E5, PSTR("M702 T4"));
+ else
+ MENU_ITEM(submenu, MSG_FILAMENTUNLOAD " " MSG_E5, menu_temp_e4_filament_unload);
+ #if E_STEPPERS > 5
+ if (thermalManager.targetHotEnoughToExtrude(5))
+ MENU_ITEM(gcode, MSG_FILAMENTUNLOAD " " MSG_E6, PSTR("M702 T5"));
+ else
+ MENU_ITEM(submenu, MSG_FILAMENTUNLOAD " " MSG_E6, menu_temp_e5_filament_unload);
+ #endif // E_STEPPERS > 5
+ #endif // E_STEPPERS > 4
+ #endif // E_STEPPERS > 3
+ #endif // E_STEPPERS > 2
+ #endif // E_STEPPERS == 1
+ }
+ #endif
+
+ END_MENU();
+ }
+#endif
+
+static AdvancedPauseMode advanced_pause_mode = ADVANCED_PAUSE_MODE_PAUSE_PRINT;
+static uint8_t hotend_status_extruder = 0;
+
+static PGM_P advanced_pause_header() {
+ switch (advanced_pause_mode) {
+ case ADVANCED_PAUSE_MODE_LOAD_FILAMENT:
+ return PSTR(MSG_FILAMENT_CHANGE_HEADER_LOAD);
+ case ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT:
+ return PSTR(MSG_FILAMENT_CHANGE_HEADER_UNLOAD);
+ default: break;
+ }
+ return PSTR(MSG_FILAMENT_CHANGE_HEADER_PAUSE);
+}
+
+// Portions from STATIC_ITEM...
+#define HOTEND_STATUS_ITEM() do { \
+ if (_menuLineNr == _thisItemNr) { \
+ if (lcdDrawUpdate) { \
+ lcd_implementation_drawmenu_static(_lcdLineNr, PSTR(MSG_FILAMENT_CHANGE_NOZZLE), false, true); \
+ lcd_implementation_hotend_status(_lcdLineNr, hotend_status_extruder); \
+ } \
+ if (_skipStatic && encoderLine <= _thisItemNr) { \
+ encoderPosition += ENCODER_STEPS_PER_MENU_ITEM; \
+ ++encoderLine; \
+ } \
+ lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NEXT; \
+ } \
+ ++_thisItemNr; \
+}while(0)
+
+void lcd_advanced_pause_resume_print() {
+ advanced_pause_menu_response = ADVANCED_PAUSE_RESPONSE_RESUME_PRINT;
+}
+
+void lcd_advanced_pause_extrude_more() {
+ advanced_pause_menu_response = ADVANCED_PAUSE_RESPONSE_EXTRUDE_MORE;
+}
+
+void menu_advanced_pause_option() {
+ START_MENU();
+ #if LCD_HEIGHT > 2
+ STATIC_ITEM(MSG_FILAMENT_CHANGE_OPTION_HEADER, true, false);
+ #endif
+ MENU_ITEM(function, MSG_FILAMENT_CHANGE_OPTION_RESUME, lcd_advanced_pause_resume_print);
+ MENU_ITEM(function, MSG_FILAMENT_CHANGE_OPTION_PURGE, lcd_advanced_pause_extrude_more);
+ END_MENU();
+}
+
+void lcd_advanced_pause_init_message() {
+ START_SCREEN();
+ STATIC_ITEM_P(advanced_pause_header(), true, true);
+ STATIC_ITEM(MSG_FILAMENT_CHANGE_INIT_1);
+ #ifdef MSG_FILAMENT_CHANGE_INIT_2
+ STATIC_ITEM(MSG_FILAMENT_CHANGE_INIT_2);
+ #define __FC_LINES_A 3
+ #else
+ #define __FC_LINES_A 2
+ #endif
+ #ifdef MSG_FILAMENT_CHANGE_INIT_3
+ STATIC_ITEM(MSG_FILAMENT_CHANGE_INIT_3);
+ #define _FC_LINES_A (__FC_LINES_A + 1)
+ #else
+ #define _FC_LINES_A __FC_LINES_A
+ #endif
+ #if LCD_HEIGHT > _FC_LINES_A + 1
+ STATIC_ITEM(" ");
+ #endif
+ HOTEND_STATUS_ITEM();
+ END_SCREEN();
+}
+
+void lcd_advanced_pause_unload_message() {
+ START_SCREEN();
+ STATIC_ITEM_P(advanced_pause_header(), true, true);
+ STATIC_ITEM(MSG_FILAMENT_CHANGE_UNLOAD_1);
+ #ifdef MSG_FILAMENT_CHANGE_UNLOAD_2
+ STATIC_ITEM(MSG_FILAMENT_CHANGE_UNLOAD_2);
+ #define __FC_LINES_B 3
+ #else
+ #define __FC_LINES_B 2
+ #endif
+ #ifdef MSG_FILAMENT_CHANGE_UNLOAD_3
+ STATIC_ITEM(MSG_FILAMENT_CHANGE_UNLOAD_3);
+ #define _FC_LINES_B (__FC_LINES_B + 1)
+ #else
+ #define _FC_LINES_B __FC_LINES_B
+ #endif
+ #if LCD_HEIGHT > _FC_LINES_B + 1
+ STATIC_ITEM(" ");
+ #endif
+ HOTEND_STATUS_ITEM();
+ END_SCREEN();
+}
+
+void lcd_advanced_pause_wait_for_nozzles_to_heat() {
+ START_SCREEN();
+ STATIC_ITEM_P(advanced_pause_header(), true, true);
+ STATIC_ITEM(MSG_FILAMENT_CHANGE_HEATING_1);
+ #ifdef MSG_FILAMENT_CHANGE_HEATING_2
+ STATIC_ITEM(MSG_FILAMENT_CHANGE_HEATING_2);
+ #define _FC_LINES_C 3
+ #else
+ #define _FC_LINES_C 2
+ #endif
+ #if LCD_HEIGHT > _FC_LINES_C + 1
+ STATIC_ITEM(" ");
+ #endif
+ HOTEND_STATUS_ITEM();
+ END_SCREEN();
+}
+
+void lcd_advanced_pause_heat_nozzle() {
+ START_SCREEN();
+ STATIC_ITEM_P(advanced_pause_header(), true, true);
+ STATIC_ITEM(MSG_FILAMENT_CHANGE_HEAT_1);
+ #ifdef MSG_FILAMENT_CHANGE_INSERT_2
+ STATIC_ITEM(MSG_FILAMENT_CHANGE_HEAT_2);
+ #define _FC_LINES_D 3
+ #else
+ #define _FC_LINES_D 2
+ #endif
+ #if LCD_HEIGHT > _FC_LINES_D + 1
+ STATIC_ITEM(" ");
+ #endif
+ HOTEND_STATUS_ITEM();
+ END_SCREEN();
+}
+
+void lcd_advanced_pause_insert_message() {
+ START_SCREEN();
+ STATIC_ITEM_P(advanced_pause_header(), true, true);
+ STATIC_ITEM(MSG_FILAMENT_CHANGE_INSERT_1);
+ #ifdef MSG_FILAMENT_CHANGE_INSERT_2
+ STATIC_ITEM(MSG_FILAMENT_CHANGE_INSERT_2);
+ #define __FC_LINES_E 3
+ #else
+ #define __FC_LINES_E 2
+ #endif
+ #ifdef MSG_FILAMENT_CHANGE_INSERT_3
+ STATIC_ITEM(MSG_FILAMENT_CHANGE_INSERT_3);
+ #define _FC_LINES_E (__FC_LINES_E + 1)
+ #else
+ #define _FC_LINES_E __FC_LINES_E
+ #endif
+ #if LCD_HEIGHT > _FC_LINES_E + 1
+ STATIC_ITEM(" ");
+ #endif
+ HOTEND_STATUS_ITEM();
+ END_SCREEN();
+}
+
+void lcd_advanced_pause_load_message() {
+ START_SCREEN();
+ STATIC_ITEM_P(advanced_pause_header(), true, true);
+ STATIC_ITEM(MSG_FILAMENT_CHANGE_LOAD_1);
+ #ifdef MSG_FILAMENT_CHANGE_LOAD_2
+ STATIC_ITEM(MSG_FILAMENT_CHANGE_LOAD_2);
+ #define __FC_LINES_F 3
+ #else
+ #define __FC_LINES_F 2
+ #endif
+ #ifdef MSG_FILAMENT_CHANGE_LOAD_3
+ STATIC_ITEM(MSG_FILAMENT_CHANGE_LOAD_3);
+ #define _FC_LINES_F (__FC_LINES_F + 1)
+ #else
+ #define _FC_LINES_F __FC_LINES_F
+ #endif
+ #if LCD_HEIGHT > _FC_LINES_F + 1
+ STATIC_ITEM(" ");
+ #endif
+ HOTEND_STATUS_ITEM();
+ END_SCREEN();
+}
+
+void lcd_advanced_pause_purge_message() {
+ START_SCREEN();
+ STATIC_ITEM_P(advanced_pause_header(), true, true);
+ STATIC_ITEM(MSG_FILAMENT_CHANGE_PURGE_1);
+ #ifdef MSG_FILAMENT_CHANGE_PURGE_2
+ STATIC_ITEM(MSG_FILAMENT_CHANGE_PURGE_2);
+ #define __FC_LINES_G 3
+ #else
+ #define __FC_LINES_G 2
+ #endif
+ #ifdef MSG_FILAMENT_CHANGE_PURGE_3
+ STATIC_ITEM(MSG_FILAMENT_CHANGE_PURGE_3);
+ #define _FC_LINES_G (__FC_LINES_G + 1)
+ #else
+ #define _FC_LINES_G __FC_LINES_G
+ #endif
+ #if LCD_HEIGHT > _FC_LINES_G + 1
+ STATIC_ITEM(" ");
+ #endif
+ HOTEND_STATUS_ITEM();
+ END_SCREEN();
+}
+
+#if ENABLED(ADVANCED_PAUSE_CONTINUOUS_PURGE)
+ void menu_advanced_pause_continuous_purge() {
+ START_SCREEN();
+ STATIC_ITEM(MSG_FILAMENT_CHANGE_PURGE_1);
+ #ifdef MSG_FILAMENT_CHANGE_PURGE_2
+ STATIC_ITEM(MSG_FILAMENT_CHANGE_PURGE_2);
+ #define __FC_LINES_G 3
+ #else
+ #define __FC_LINES_G 2
+ #endif
+ #ifdef MSG_FILAMENT_CHANGE_PURGE_3
+ STATIC_ITEM(MSG_FILAMENT_CHANGE_PURGE_3);
+ #define _FC_LINES_G (__FC_LINES_G + 1)
+ #else
+ #define _FC_LINES_G __FC_LINES_G
+ #endif
+ #if LCD_HEIGHT > _FC_LINES_G + 1
+ STATIC_ITEM(" ");
+ #endif
+ HOTEND_STATUS_ITEM();
+ STATIC_ITEM(MSG_USERWAIT);
+ END_SCREEN();
+ }
+#endif
+
+void lcd_advanced_pause_resume_message() {
+ START_SCREEN();
+ STATIC_ITEM_P(advanced_pause_header(), true, true);
+ STATIC_ITEM(MSG_FILAMENT_CHANGE_RESUME_1);
+ #ifdef MSG_FILAMENT_CHANGE_RESUME_2
+ STATIC_ITEM(MSG_FILAMENT_CHANGE_RESUME_2);
+ #endif
+ #ifdef MSG_FILAMENT_CHANGE_RESUME_3
+ STATIC_ITEM(MSG_FILAMENT_CHANGE_RESUME_3);
+ #endif
+ END_SCREEN();
+}
+
+FORCE_INLINE screenFunc_t ap_message_screen(const AdvancedPauseMessage message) {
+ switch (message) {
+ case ADVANCED_PAUSE_MESSAGE_INIT: return lcd_advanced_pause_init_message;
+ case ADVANCED_PAUSE_MESSAGE_UNLOAD: return lcd_advanced_pause_unload_message;
+ case ADVANCED_PAUSE_MESSAGE_INSERT: return lcd_advanced_pause_insert_message;
+ case ADVANCED_PAUSE_MESSAGE_LOAD: return lcd_advanced_pause_load_message;
+ case ADVANCED_PAUSE_MESSAGE_PURGE: return lcd_advanced_pause_purge_message;
+ case ADVANCED_PAUSE_MESSAGE_RESUME: return lcd_advanced_pause_resume_message;
+ case ADVANCED_PAUSE_MESSAGE_CLICK_TO_HEAT_NOZZLE: return lcd_advanced_pause_heat_nozzle;
+ case ADVANCED_PAUSE_MESSAGE_WAIT_FOR_NOZZLES_TO_HEAT: return lcd_advanced_pause_wait_for_nozzles_to_heat;
+ case ADVANCED_PAUSE_MESSAGE_OPTION: advanced_pause_menu_response = ADVANCED_PAUSE_RESPONSE_WAIT_FOR;
+ return menu_advanced_pause_option;
+ #if ENABLED(ADVANCED_PAUSE_CONTINUOUS_PURGE)
+ case ADVANCED_PAUSE_MESSAGE_CONTINUOUS_PURGE: return menu_advanced_pause_continuous_purge;
+ #endif
+ case ADVANCED_PAUSE_MESSAGE_STATUS:
+ default: break;
+ }
+ return NULL;
+}
+
+void lcd_advanced_pause_show_message(
+ const AdvancedPauseMessage message,
+ const AdvancedPauseMode mode/*=ADVANCED_PAUSE_MODE_PAUSE_PRINT*/,
+ const uint8_t extruder/*=active_extruder*/
+) {
+ advanced_pause_mode = mode;
+ hotend_status_extruder = extruder;
+ const screenFunc_t next_screen = ap_message_screen(message);
+ if (next_screen) {
+ defer_return_to_status = true;
+ lcd_goto_screen(next_screen);
+ }
+ else
+ lcd_return_to_status();
+}
+
+#endif // HAS_LCD_MENU && ADVANCED_PAUSE_FEATURE
diff --git a/Marlin/src/lcd/menu/menu_info.cpp b/Marlin/src/lcd/menu/menu_info.cpp
new file mode 100644
index 0000000000..a4860093eb
--- /dev/null
+++ b/Marlin/src/lcd/menu/menu_info.cpp
@@ -0,0 +1,198 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+//
+// Info Menu
+//
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if HAS_LCD_MENU && ENABLED(LCD_INFO_MENU)
+
+#include "menu.h"
+// #include "../../module/motion.h"
+// #include "../../module/planner.h"
+// #include "../../module/temperature.h"
+// #include "../../Marlin.h"
+
+// #if HAS_LEVELING
+// #include "../../feature/bedlevel/bedlevel.h"
+// #endif
+
+
+#if ENABLED(PRINTCOUNTER)
+
+ #include "../../module/printcounter.h"
+
+ //
+ // About Printer > Printer Stats
+ //
+ void menu_info_stats() {
+ if (use_click()) { return lcd_goto_previous_menu(); }
+
+ char buffer[21];
+ printStatistics stats = print_job_timer.getStats();
+
+ START_SCREEN(); // 12345678901234567890
+ STATIC_ITEM(MSG_INFO_PRINT_COUNT ": ", false, false, itostr3left(stats.totalPrints)); // Print Count: 999
+ STATIC_ITEM(MSG_INFO_COMPLETED_PRINTS": ", false, false, itostr3left(stats.finishedPrints)); // Completed : 666
+
+ duration_t elapsed = stats.printTime;
+ elapsed.toString(buffer);
+
+ STATIC_ITEM(MSG_INFO_PRINT_TIME ": ", false, false); // Total print Time:
+ STATIC_ITEM("", false, false, buffer); // 99y 364d 23h 59m 59s
+
+ elapsed = stats.longestPrint;
+ elapsed.toString(buffer);
+
+ STATIC_ITEM(MSG_INFO_PRINT_LONGEST ": ", false, false); // Longest job time:
+ STATIC_ITEM("", false, false, buffer); // 99y 364d 23h 59m 59s
+
+ sprintf_P(buffer, PSTR("%ld.%im"), long(stats.filamentUsed / 1000), int16_t(stats.filamentUsed / 100) % 10);
+ STATIC_ITEM(MSG_INFO_PRINT_FILAMENT ": ", false, false); // Extruded total:
+ STATIC_ITEM("", false, false, buffer); // 125m
+ END_SCREEN();
+ }
+
+#endif
+
+//
+// About Printer > Thermistors
+//
+void menu_info_thermistors() {
+ if (use_click()) { return lcd_goto_previous_menu(); }
+ START_SCREEN();
+ #define THERMISTOR_ID TEMP_SENSOR_0
+ #include "../thermistornames.h"
+ STATIC_ITEM("T0: " THERMISTOR_NAME, false, true);
+ STATIC_ITEM(MSG_INFO_MIN_TEMP ": " STRINGIFY(HEATER_0_MINTEMP), false);
+ STATIC_ITEM(MSG_INFO_MAX_TEMP ": " STRINGIFY(HEATER_0_MAXTEMP), false);
+
+ #if TEMP_SENSOR_1 != 0
+ #undef THERMISTOR_ID
+ #define THERMISTOR_ID TEMP_SENSOR_1
+ #include "../thermistornames.h"
+ STATIC_ITEM("T1: " THERMISTOR_NAME, false, true);
+ STATIC_ITEM(MSG_INFO_MIN_TEMP ": " STRINGIFY(HEATER_1_MINTEMP), false);
+ STATIC_ITEM(MSG_INFO_MAX_TEMP ": " STRINGIFY(HEATER_1_MAXTEMP), false);
+ #endif
+
+ #if TEMP_SENSOR_2 != 0
+ #undef THERMISTOR_ID
+ #define THERMISTOR_ID TEMP_SENSOR_2
+ #include "../thermistornames.h"
+ STATIC_ITEM("T2: " THERMISTOR_NAME, false, true);
+ STATIC_ITEM(MSG_INFO_MIN_TEMP ": " STRINGIFY(HEATER_2_MINTEMP), false);
+ STATIC_ITEM(MSG_INFO_MAX_TEMP ": " STRINGIFY(HEATER_2_MAXTEMP), false);
+ #endif
+
+ #if TEMP_SENSOR_3 != 0
+ #undef THERMISTOR_ID
+ #define THERMISTOR_ID TEMP_SENSOR_3
+ #include "../thermistornames.h"
+ STATIC_ITEM("T3: " THERMISTOR_NAME, false, true);
+ STATIC_ITEM(MSG_INFO_MIN_TEMP ": " STRINGIFY(HEATER_3_MINTEMP), false);
+ STATIC_ITEM(MSG_INFO_MAX_TEMP ": " STRINGIFY(HEATER_3_MAXTEMP), false);
+ #endif
+
+ #if TEMP_SENSOR_4 != 0
+ #undef THERMISTOR_ID
+ #define THERMISTOR_ID TEMP_SENSOR_4
+ #include "../thermistornames.h"
+ STATIC_ITEM("T4: " THERMISTOR_NAME, false, true);
+ STATIC_ITEM(MSG_INFO_MIN_TEMP ": " STRINGIFY(HEATER_4_MINTEMP), false);
+ STATIC_ITEM(MSG_INFO_MAX_TEMP ": " STRINGIFY(HEATER_4_MAXTEMP), false);
+ #endif
+
+ #if HAS_HEATED_BED
+ #undef THERMISTOR_ID
+ #define THERMISTOR_ID TEMP_SENSOR_BED
+ #include "../thermistornames.h"
+ STATIC_ITEM("TBed:" THERMISTOR_NAME, false, true);
+ STATIC_ITEM(MSG_INFO_MIN_TEMP ": " STRINGIFY(BED_MINTEMP), false);
+ STATIC_ITEM(MSG_INFO_MAX_TEMP ": " STRINGIFY(BED_MAXTEMP), false);
+ #endif
+ END_SCREEN();
+}
+
+//
+// About Printer > Board Info
+//
+void menu_info_board() {
+ if (use_click()) { return lcd_goto_previous_menu(); }
+ START_SCREEN();
+ STATIC_ITEM(BOARD_NAME, true, true); // MyPrinterController
+ STATIC_ITEM(MSG_INFO_BAUDRATE ": " STRINGIFY(BAUDRATE), true); // Baud: 250000
+ STATIC_ITEM(MSG_INFO_PROTOCOL ": " PROTOCOL_VERSION, true); // Protocol: 1.0
+ #if POWER_SUPPLY == 0
+ STATIC_ITEM(MSG_INFO_PSU ": Generic", true);
+ #elif POWER_SUPPLY == 1
+ STATIC_ITEM(MSG_INFO_PSU ": ATX", true); // Power Supply: ATX
+ #elif POWER_SUPPLY == 2
+ STATIC_ITEM(MSG_INFO_PSU ": XBox", true); // Power Supply: XBox
+ #endif
+ END_SCREEN();
+}
+
+//
+// About Printer > Printer Info
+//
+void menu_info_printer() {
+ if (use_click()) { return lcd_goto_previous_menu(); }
+ START_SCREEN();
+ STATIC_ITEM(MSG_MARLIN, true, true); // Marlin
+ STATIC_ITEM(SHORT_BUILD_VERSION, true); // x.x.x-Branch
+ STATIC_ITEM(STRING_DISTRIBUTION_DATE, true); // YYYY-MM-DD HH:MM
+ STATIC_ITEM(MACHINE_NAME, true); // My3DPrinter
+ STATIC_ITEM(WEBSITE_URL, true); // www.my3dprinter.com
+ STATIC_ITEM(MSG_INFO_EXTRUDERS ": " STRINGIFY(EXTRUDERS), true); // Extruders: 2
+ #if ENABLED(AUTO_BED_LEVELING_3POINT)
+ STATIC_ITEM(MSG_3POINT_LEVELING, true); // 3-Point Leveling
+ #elif ENABLED(AUTO_BED_LEVELING_LINEAR)
+ STATIC_ITEM(MSG_LINEAR_LEVELING, true); // Linear Leveling
+ #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
+ STATIC_ITEM(MSG_BILINEAR_LEVELING, true); // Bi-linear Leveling
+ #elif ENABLED(AUTO_BED_LEVELING_UBL)
+ STATIC_ITEM(MSG_UBL_LEVELING, true); // Unified Bed Leveling
+ #elif ENABLED(MESH_BED_LEVELING)
+ STATIC_ITEM(MSG_MESH_LEVELING, true); // Mesh Leveling
+ #endif
+ END_SCREEN();
+}
+
+//
+// "About Printer" submenu
+//
+void menu_info() {
+ START_MENU();
+ MENU_BACK(MSG_MAIN);
+ MENU_ITEM(submenu, MSG_INFO_PRINTER_MENU, menu_info_printer); // Printer Info >
+ MENU_ITEM(submenu, MSG_INFO_BOARD_MENU, menu_info_board); // Board Info >
+ MENU_ITEM(submenu, MSG_INFO_THERMISTOR_MENU, menu_info_thermistors); // Thermistors >
+ #if ENABLED(PRINTCOUNTER)
+ MENU_ITEM(submenu, MSG_INFO_STATS_MENU, menu_info_stats); // Printer Stats >
+ #endif
+ END_MENU();
+}
+
+#endif // HAS_LCD_MENU && LCD_INFO_MENU
diff --git a/Marlin/src/lcd/menu/menu_job_recovery.cpp b/Marlin/src/lcd/menu/menu_job_recovery.cpp
new file mode 100644
index 0000000000..51adcaf0d2
--- /dev/null
+++ b/Marlin/src/lcd/menu/menu_job_recovery.cpp
@@ -0,0 +1,106 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+//
+// Job Recovery Menu
+//
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if HAS_LCD_MENU && ENABLED(POWER_LOSS_RECOVERY)
+
+#include "menu.h"
+#include "../../gcode/queue.h"
+#include "../../sd/cardreader.h"
+#include "../../feature/power_loss_recovery.h"
+
+static void lcd_power_loss_recovery_resume() {
+ char cmd[20];
+
+ // Return to status now
+ lcd_return_to_status();
+
+ // Turn leveling off and home
+ enqueue_and_echo_commands_P(PSTR("M420 S0\nG28 R0"
+ #if ENABLED(MARLIN_DEV_MODE)
+ " S"
+ #elif !IS_KINEMATIC
+ " X Y"
+ #endif
+ ));
+
+ #if HAS_HEATED_BED
+ const int16_t bt = job_recovery_info.target_temperature_bed;
+ if (bt) {
+ // Restore the bed temperature
+ sprintf_P(cmd, PSTR("M190 S%i"), bt);
+ enqueue_and_echo_command(cmd);
+ }
+ #endif
+
+ // Restore all hotend temperatures
+ HOTEND_LOOP() {
+ const int16_t et = job_recovery_info.target_temperature[e];
+ if (et) {
+ #if HOTENDS > 1
+ sprintf_P(cmd, PSTR("T%i"), e);
+ enqueue_and_echo_command(cmd);
+ #endif
+ sprintf_P(cmd, PSTR("M109 S%i"), et);
+ enqueue_and_echo_command(cmd);
+ }
+ }
+
+ #if HOTENDS > 1
+ sprintf_P(cmd, PSTR("T%i"), job_recovery_info.active_hotend);
+ enqueue_and_echo_command(cmd);
+ #endif
+
+ // Restore print cooling fan speeds
+ for (uint8_t i = 0; i < FAN_COUNT; i++) {
+ uint8_t f = job_recovery_info.fan_speed[i];
+ if (f) {
+ sprintf_P(cmd, PSTR("M106 P%i S%i"), i, f);
+ enqueue_and_echo_command(cmd);
+ }
+ }
+
+ // Start draining the job recovery command queue
+ job_recovery_phase = JOB_RECOVERY_YES;
+}
+
+static void lcd_power_loss_recovery_cancel() {
+ card.removeJobRecoveryFile();
+ card.autostart_index = 0;
+ lcd_return_to_status();
+}
+
+void menu_job_recovery() {
+ defer_return_to_status = true;
+ START_MENU();
+ STATIC_ITEM(MSG_POWER_LOSS_RECOVERY);
+ MENU_ITEM(function, MSG_RESUME_PRINT, lcd_power_loss_recovery_resume);
+ MENU_ITEM(function, MSG_STOP_PRINT, lcd_power_loss_recovery_cancel);
+ END_MENU();
+}
+
+#endif // HAS_LCD_MENU && POWER_LOSS_RECOVERY
diff --git a/Marlin/src/lcd/menu/menu_led.cpp b/Marlin/src/lcd/menu/menu_led.cpp
new file mode 100644
index 0000000000..d85fe338fb
--- /dev/null
+++ b/Marlin/src/lcd/menu/menu_led.cpp
@@ -0,0 +1,83 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+//
+// LED Menu
+//
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if HAS_LCD_MENU && ENABLED(LED_CONTROL_MENU)
+
+#include "menu.h"
+#include "../../feature/leds/leds.h"
+
+#if ENABLED(LED_COLOR_PRESETS)
+
+ void menu_led_presets() {
+ START_MENU();
+ #if LCD_HEIGHT > 2
+ STATIC_ITEM(MSG_LED_PRESETS, true, true);
+ #endif
+ MENU_BACK(MSG_LED_CONTROL);
+ MENU_ITEM(function, MSG_SET_LEDS_WHITE, leds.set_white);
+ MENU_ITEM(function, MSG_SET_LEDS_RED, leds.set_red);
+ MENU_ITEM(function, MSG_SET_LEDS_ORANGE, leds.set_orange);
+ MENU_ITEM(function, MSG_SET_LEDS_YELLOW,leds.set_yellow);
+ MENU_ITEM(function, MSG_SET_LEDS_GREEN, leds.set_green);
+ MENU_ITEM(function, MSG_SET_LEDS_BLUE, leds.set_blue);
+ MENU_ITEM(function, MSG_SET_LEDS_INDIGO, leds.set_indigo);
+ MENU_ITEM(function, MSG_SET_LEDS_VIOLET, leds.set_violet);
+ END_MENU();
+ }
+
+#endif
+
+void menu_led_custom() {
+ START_MENU();
+ MENU_BACK(MSG_LED_CONTROL);
+ MENU_ITEM_EDIT_CALLBACK(int8, MSG_INTENSITY_R, &leds.color.r, 0, 255, leds.update, true);
+ MENU_ITEM_EDIT_CALLBACK(int8, MSG_INTENSITY_G, &leds.color.g, 0, 255, leds.update, true);
+ MENU_ITEM_EDIT_CALLBACK(int8, MSG_INTENSITY_B, &leds.color.b, 0, 255, leds.update, true);
+ #if ENABLED(RGBW_LED) || ENABLED(NEOPIXEL_LED)
+ MENU_ITEM_EDIT_CALLBACK(int8, MSG_INTENSITY_W, &leds.color.w, 0, 255, leds.update, true);
+ #if ENABLED(NEOPIXEL_LED)
+ MENU_ITEM_EDIT_CALLBACK(int8, MSG_LED_BRIGHTNESS, &leds.color.i, 0, 255, leds.update, true);
+ #endif
+ #endif
+ END_MENU();
+}
+
+void menu_led() {
+ START_MENU();
+ MENU_BACK(MSG_MAIN);
+ bool led_on = leds.lights_on;
+ MENU_ITEM_EDIT_CALLBACK(bool, MSG_LEDS, &led_on, leds.toggle);
+ MENU_ITEM(function, MSG_SET_LEDS_DEFAULT, leds.set_default);
+ #if ENABLED(LED_COLOR_PRESETS)
+ MENU_ITEM(submenu, MSG_LED_PRESETS, menu_led_presets);
+ #endif
+ MENU_ITEM(submenu, MSG_CUSTOM_LEDS, menu_led_custom);
+ END_MENU();
+}
+
+#endif // HAS_LCD_MENU && LED_CONTROL_MENU
diff --git a/Marlin/src/lcd/menu/menu_main.cpp b/Marlin/src/lcd/menu/menu_main.cpp
new file mode 100644
index 0000000000..2d227b34f0
--- /dev/null
+++ b/Marlin/src/lcd/menu/menu_main.cpp
@@ -0,0 +1,166 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+//
+// Main Menu
+//
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if HAS_LCD_MENU
+
+#include "menu.h"
+#include "../../module/temperature.h"
+
+#if ENABLED(SDSUPPORT)
+
+ #include "../../sd/cardreader.h"
+ #include "../../gcode/queue.h"
+ #include "../../module/printcounter.h"
+
+ void lcd_sdcard_pause() {
+ card.pauseSDPrint();
+ print_job_timer.pause();
+ #if ENABLED(PARK_HEAD_ON_PAUSE)
+ enqueue_and_echo_commands_P(PSTR("M125"));
+ #endif
+ lcd_reset_status();
+ }
+
+ void lcd_sdcard_resume() {
+ #if ENABLED(PARK_HEAD_ON_PAUSE)
+ enqueue_and_echo_commands_P(PSTR("M24"));
+ #else
+ card.startFileprint();
+ print_job_timer.start();
+ #endif
+ lcd_reset_status();
+ }
+
+ void lcd_sdcard_stop() {
+ wait_for_heatup = wait_for_user = false;
+ card.abort_sd_printing = true;
+ lcd_setstatusPGM(PSTR(MSG_PRINT_ABORTED), -1);
+ lcd_return_to_status();
+ }
+
+ #if ENABLED(MENU_ADDAUTOSTART)
+
+ void lcd_autostart_sd() { card.beginautostart(); }
+
+ #endif
+
+#endif // SDSUPPORT
+
+void menu_tune();
+void menu_motion();
+void menu_temperature();
+void menu_configuration();
+void menu_user();
+void menu_temp_e0_filament_change();
+void menu_change_filament();
+void menu_info();
+void menu_led();
+
+void menu_main() {
+ START_MENU();
+ MENU_BACK(MSG_WATCH);
+
+ #if ENABLED(SDSUPPORT)
+ if (card.cardOK) {
+ if (card.isFileOpen()) {
+ if (card.sdprinting)
+ MENU_ITEM(function, MSG_PAUSE_PRINT, lcd_sdcard_pause);
+ else
+ MENU_ITEM(function, MSG_RESUME_PRINT, lcd_sdcard_resume);
+ MENU_ITEM(function, MSG_STOP_PRINT, lcd_sdcard_stop);
+ }
+ else {
+ MENU_ITEM(submenu, MSG_CARD_MENU, menu_sdcard);
+ #if !PIN_EXISTS(SD_DETECT)
+ MENU_ITEM(gcode, MSG_CHANGE_SDCARD, PSTR("M21")); // SD-card changed by user
+ #endif
+ }
+ }
+ else {
+ MENU_ITEM(submenu, MSG_NO_CARD, menu_sdcard);
+ #if !PIN_EXISTS(SD_DETECT)
+ MENU_ITEM(gcode, MSG_INIT_SDCARD, PSTR("M21")); // Manually initialize the SD-card via user interface
+ #endif
+ }
+ #endif // SDSUPPORT
+
+ const bool busy = printer_busy();
+ if (busy)
+ MENU_ITEM(submenu, MSG_TUNE, menu_tune);
+ else {
+ MENU_ITEM(submenu, MSG_MOTION, menu_motion);
+ MENU_ITEM(submenu, MSG_TEMPERATURE, menu_temperature);
+ }
+
+ MENU_ITEM(submenu, MSG_CONFIGURATION, menu_configuration);
+
+ #if ENABLED(CUSTOM_USER_MENUS)
+ MENU_ITEM(submenu, MSG_USER_MENU, menu_user);
+ #endif
+
+ #if ENABLED(ADVANCED_PAUSE_FEATURE)
+ #if E_STEPPERS == 1 && DISABLED(FILAMENT_LOAD_UNLOAD_GCODES)
+ if (thermalManager.targetHotEnoughToExtrude(active_extruder))
+ MENU_ITEM(gcode, MSG_FILAMENTCHANGE, PSTR("M600 B0"));
+ else
+ MENU_ITEM(submenu, MSG_FILAMENTCHANGE, menu_temp_e0_filament_change);
+ #else
+ MENU_ITEM(submenu, MSG_FILAMENTCHANGE, menu_change_filament);
+ #endif
+ #endif
+
+ #if ENABLED(LCD_INFO_MENU)
+ MENU_ITEM(submenu, MSG_INFO_MENU, menu_info);
+ #endif
+
+ #if ENABLED(LED_CONTROL_MENU)
+ MENU_ITEM(submenu, MSG_LED_CONTROL, menu_led);
+ #endif
+
+ //
+ // Switch power on/off
+ //
+ #if HAS_POWER_SWITCH
+ if (powersupply_on)
+ MENU_ITEM(gcode, MSG_SWITCH_PS_OFF, PSTR("M81"));
+ else
+ MENU_ITEM(gcode, MSG_SWITCH_PS_ON, PSTR("M80"));
+ #endif
+
+ //
+ // Autostart
+ //
+ #if ENABLED(SDSUPPORT) && ENABLED(MENU_ADDAUTOSTART)
+ if (!busy)
+ MENU_ITEM(function, MSG_AUTOSTART, lcd_autostart_sd);
+ #endif
+
+ END_MENU();
+}
+
+#endif // HAS_LCD_MENU
diff --git a/Marlin/src/lcd/menu/menu_motion.cpp b/Marlin/src/lcd/menu/menu_motion.cpp
new file mode 100644
index 0000000000..5ec938d369
--- /dev/null
+++ b/Marlin/src/lcd/menu/menu_motion.cpp
@@ -0,0 +1,499 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+//
+// Motion Menu
+//
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if HAS_LCD_MENU
+
+#include "menu.h"
+#include "../../module/motion.h"
+
+#if ENABLED(DELTA)
+ #include "../../module/delta.h"
+#endif
+
+#if ENABLED(PREVENT_COLD_EXTRUSION)
+ #include "../../module/temperature.h"
+#endif
+
+#if HAS_LEVELING
+ #include "../../module/planner.h"
+ #include "../../feature/bedlevel/bedlevel.h"
+#endif
+
+extern millis_t manual_move_start_time;
+extern int8_t manual_move_axis;
+#if ENABLED(DUAL_X_CARRIAGE) || E_MANUAL > 1
+ extern int8_t manual_move_e_index;
+#endif
+#if ENABLED(MANUAL_E_MOVES_RELATIVE)
+ float manual_move_e_origin = 0;
+#endif
+#if IS_KINEMATIC
+ extern float manual_move_offset;
+#endif
+
+//
+// Tell lcd_update() to start a move to current_position" after a short delay.
+//
+inline void manual_move_to_current(AxisEnum axis
+ #if E_MANUAL > 1
+ , const int8_t eindex=-1
+ #endif
+) {
+ #if ENABLED(DUAL_X_CARRIAGE) || E_MANUAL > 1
+ #if E_MANUAL > 1
+ if (axis == E_AXIS)
+ #endif
+ manual_move_e_index = eindex >= 0 ? eindex : active_extruder;
+ #endif
+ manual_move_start_time = millis() + (move_menu_scale < 0.99f ? 0UL : 250UL); // delay for bigger moves
+ manual_move_axis = (int8_t)axis;
+}
+
+//
+// "Motion" > "Move Axis" submenu
+//
+
+static void _lcd_move_xyz(PGM_P name, AxisEnum axis) {
+ if (use_click()) { return lcd_goto_previous_menu_no_defer(); }
+ ENCODER_DIRECTION_NORMAL();
+ if (encoderPosition && !processing_manual_move) {
+
+ // Start with no limits to movement
+ float min = current_position[axis] - 1000,
+ max = current_position[axis] + 1000;
+
+ // Limit to software endstops, if enabled
+ #if ENABLED(MIN_SOFTWARE_ENDSTOPS) || ENABLED(MAX_SOFTWARE_ENDSTOPS)
+ if (soft_endstops_enabled) switch (axis) {
+ case X_AXIS:
+ #if ENABLED(MIN_SOFTWARE_ENDSTOP_X)
+ min = soft_endstop_min[X_AXIS];
+ #endif
+ #if ENABLED(MAX_SOFTWARE_ENDSTOP_X)
+ max = soft_endstop_max[X_AXIS];
+ #endif
+ break;
+ case Y_AXIS:
+ #if ENABLED(MIN_SOFTWARE_ENDSTOP_Y)
+ min = soft_endstop_min[Y_AXIS];
+ #endif
+ #if ENABLED(MAX_SOFTWARE_ENDSTOP_Y)
+ max = soft_endstop_max[Y_AXIS];
+ #endif
+ break;
+ case Z_AXIS:
+ #if ENABLED(MIN_SOFTWARE_ENDSTOP_Z)
+ min = soft_endstop_min[Z_AXIS];
+ #endif
+ #if ENABLED(MAX_SOFTWARE_ENDSTOP_Z)
+ max = soft_endstop_max[Z_AXIS];
+ #endif
+ default: break;
+ }
+ #endif // MIN_SOFTWARE_ENDSTOPS || MAX_SOFTWARE_ENDSTOPS
+
+ // Delta limits XY based on the current offset from center
+ // This assumes the center is 0,0
+ #if ENABLED(DELTA)
+ if (axis != Z_AXIS) {
+ max = SQRT(sq((float)(DELTA_PRINTABLE_RADIUS)) - sq(current_position[Y_AXIS - axis])); // (Y_AXIS - axis) == the other axis
+ min = -max;
+ }
+ #endif
+
+ // Get the new position
+ const float diff = float((int32_t)encoderPosition) * move_menu_scale;
+ #if IS_KINEMATIC
+ manual_move_offset += diff;
+ if ((int32_t)encoderPosition < 0)
+ NOLESS(manual_move_offset, min - current_position[axis]);
+ else
+ NOMORE(manual_move_offset, max - current_position[axis]);
+ #else
+ current_position[axis] += diff;
+ if ((int32_t)encoderPosition < 0)
+ NOLESS(current_position[axis], min);
+ else
+ NOMORE(current_position[axis], max);
+ #endif
+
+ manual_move_to_current(axis);
+ lcdDrawUpdate = LCDVIEW_REDRAW_NOW;
+ }
+ encoderPosition = 0;
+ if (lcdDrawUpdate) {
+ const float pos = NATIVE_TO_LOGICAL(processing_manual_move ? destination[axis] : current_position[axis]
+ #if IS_KINEMATIC
+ + manual_move_offset
+ #endif
+ , axis);
+ lcd_implementation_drawedit(name, move_menu_scale >= 0.1f ? ftostr41sign(pos) : ftostr43sign(pos));
+ }
+}
+inline void lcd_move_x() { _lcd_move_xyz(PSTR(MSG_MOVE_X), X_AXIS); }
+inline void lcd_move_y() { _lcd_move_xyz(PSTR(MSG_MOVE_Y), Y_AXIS); }
+inline void lcd_move_z() { _lcd_move_xyz(PSTR(MSG_MOVE_Z), Z_AXIS); }
+static void _lcd_move_e(
+ #if E_MANUAL > 1
+ const int8_t eindex=-1
+ #endif
+) {
+ if (use_click()) { return lcd_goto_previous_menu_no_defer(); }
+ ENCODER_DIRECTION_NORMAL();
+ if (encoderPosition) {
+ if (!processing_manual_move) {
+ const float diff = float((int32_t)encoderPosition) * move_menu_scale;
+ #if IS_KINEMATIC
+ manual_move_offset += diff;
+ #else
+ current_position[E_AXIS] += diff;
+ #endif
+ manual_move_to_current(E_AXIS
+ #if E_MANUAL > 1
+ , eindex
+ #endif
+ );
+ lcdDrawUpdate = LCDVIEW_REDRAW_NOW;
+ }
+ encoderPosition = 0;
+ }
+ if (lcdDrawUpdate) {
+ PGM_P pos_label;
+ #if E_MANUAL == 1
+ pos_label = PSTR(MSG_MOVE_E);
+ #else
+ switch (eindex) {
+ default: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E1); break;
+ case 1: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E2); break;
+ #if E_MANUAL > 2
+ case 2: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E3); break;
+ #if E_MANUAL > 3
+ case 3: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E4); break;
+ #if E_MANUAL > 4
+ case 4: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E5); break;
+ #if E_MANUAL > 5
+ case 5: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E6); break;
+ #endif // E_MANUAL > 5
+ #endif // E_MANUAL > 4
+ #endif // E_MANUAL > 3
+ #endif // E_MANUAL > 2
+ }
+ #endif // E_MANUAL > 1
+
+ lcd_implementation_drawedit(pos_label, ftostr41sign(current_position[E_AXIS]
+ #if IS_KINEMATIC
+ + manual_move_offset
+ #endif
+ #if ENABLED(MANUAL_E_MOVES_RELATIVE)
+ - manual_move_e_origin
+ #endif
+ ));
+ }
+}
+
+inline void lcd_move_e() { _lcd_move_e(); }
+#if E_MANUAL > 1
+ inline void lcd_move_e0() { _lcd_move_e(0); }
+ inline void lcd_move_e1() { _lcd_move_e(1); }
+ #if E_MANUAL > 2
+ inline void lcd_move_e2() { _lcd_move_e(2); }
+ #if E_MANUAL > 3
+ inline void lcd_move_e3() { _lcd_move_e(3); }
+ #if E_MANUAL > 4
+ inline void lcd_move_e4() { _lcd_move_e(4); }
+ #if E_MANUAL > 5
+ inline void lcd_move_e5() { _lcd_move_e(5); }
+ #endif // E_MANUAL > 5
+ #endif // E_MANUAL > 4
+ #endif // E_MANUAL > 3
+ #endif // E_MANUAL > 2
+#endif // E_MANUAL > 1
+
+//
+// "Motion" > "Move Xmm" > "Move XYZ" submenu
+//
+
+screenFunc_t _manual_move_func_ptr;
+
+void _goto_manual_move(const float scale) {
+ defer_return_to_status = true;
+ move_menu_scale = scale;
+ lcd_goto_screen(_manual_move_func_ptr);
+}
+void menu_move_10mm() { _goto_manual_move(10); }
+void menu_move_1mm() { _goto_manual_move( 1); }
+void menu_move_01mm() { _goto_manual_move( 0.1f); }
+
+void _menu_move_distance(const AxisEnum axis, const screenFunc_t func, const int8_t eindex=-1) {
+ _manual_move_func_ptr = func;
+ START_MENU();
+ if (LCD_HEIGHT >= 4) {
+ switch (axis) {
+ case X_AXIS:
+ STATIC_ITEM(MSG_MOVE_X, true, true); break;
+ case Y_AXIS:
+ STATIC_ITEM(MSG_MOVE_Y, true, true); break;
+ case Z_AXIS:
+ STATIC_ITEM(MSG_MOVE_Z, true, true); break;
+ default:
+ #if ENABLED(MANUAL_E_MOVES_RELATIVE)
+ manual_move_e_origin = current_position[E_AXIS];
+ #endif
+ STATIC_ITEM(MSG_MOVE_E, true, true);
+ break;
+ }
+ }
+ #if ENABLED(PREVENT_COLD_EXTRUSION)
+ if (axis == E_AXIS && thermalManager.tooColdToExtrude(eindex >= 0 ? eindex : active_extruder))
+ MENU_BACK(MSG_HOTEND_TOO_COLD);
+ else
+ #endif
+ {
+ MENU_BACK(MSG_MOVE_AXIS);
+ MENU_ITEM(submenu, MSG_MOVE_10MM, menu_move_10mm);
+ MENU_ITEM(submenu, MSG_MOVE_1MM, menu_move_1mm);
+ MENU_ITEM(submenu, MSG_MOVE_01MM, menu_move_01mm);
+ }
+ END_MENU();
+}
+void lcd_move_get_x_amount() { _menu_move_distance(X_AXIS, lcd_move_x); }
+void lcd_move_get_y_amount() { _menu_move_distance(Y_AXIS, lcd_move_y); }
+void lcd_move_get_z_amount() { _menu_move_distance(Z_AXIS, lcd_move_z); }
+void lcd_move_get_e_amount() { _menu_move_distance(E_AXIS, lcd_move_e, -1); }
+#if E_MANUAL > 1
+ void lcd_move_get_e0_amount() { _menu_move_distance(E_AXIS, lcd_move_e0, 0); }
+ void lcd_move_get_e1_amount() { _menu_move_distance(E_AXIS, lcd_move_e1, 1); }
+ #if E_MANUAL > 2
+ void lcd_move_get_e2_amount() { _menu_move_distance(E_AXIS, lcd_move_e2, 2); }
+ #if E_MANUAL > 3
+ void lcd_move_get_e3_amount() { _menu_move_distance(E_AXIS, lcd_move_e3, 3); }
+ #if E_MANUAL > 4
+ void lcd_move_get_e4_amount() { _menu_move_distance(E_AXIS, lcd_move_e4, 4); }
+ #if E_MANUAL > 5
+ void lcd_move_get_e5_amount() { _menu_move_distance(E_AXIS, lcd_move_e5, 5); }
+ #endif // E_MANUAL > 5
+ #endif // E_MANUAL > 4
+ #endif // E_MANUAL > 3
+ #endif // E_MANUAL > 2
+#endif // E_MANUAL > 1
+
+#if ENABLED(DELTA)
+ void lcd_lower_z_to_clip_height() {
+ line_to_z(delta_clip_start_height);
+ lcd_synchronize();
+ }
+#endif
+
+void menu_move() {
+ START_MENU();
+ MENU_BACK(MSG_MOTION);
+
+ #if HAS_SOFTWARE_ENDSTOPS && ENABLED(SOFT_ENDSTOPS_MENU_ITEM)
+ MENU_ITEM_EDIT(bool, MSG_LCD_SOFT_ENDSTOPS, &soft_endstops_enabled);
+ #endif
+
+ if (
+ #if IS_KINEMATIC || ENABLED(NO_MOTION_BEFORE_HOMING)
+ all_axes_homed()
+ #else
+ true
+ #endif
+ ) {
+ if (
+ #if ENABLED(DELTA)
+ current_position[Z_AXIS] <= delta_clip_start_height
+ #else
+ true
+ #endif
+ ) {
+ MENU_ITEM(submenu, MSG_MOVE_X, lcd_move_get_x_amount);
+ MENU_ITEM(submenu, MSG_MOVE_Y, lcd_move_get_y_amount);
+ }
+ #if ENABLED(DELTA)
+ else
+ MENU_ITEM(function, MSG_FREE_XY, lcd_lower_z_to_clip_height);
+ #endif
+
+ MENU_ITEM(submenu, MSG_MOVE_Z, lcd_move_get_z_amount);
+ }
+ else
+ MENU_ITEM(gcode, MSG_AUTO_HOME, PSTR("G28"));
+
+ #if ENABLED(SWITCHING_EXTRUDER) || ENABLED(SWITCHING_NOZZLE)
+
+ #if EXTRUDERS == 6
+ switch (active_extruder) {
+ case 0: MENU_ITEM(gcode, MSG_SELECT " " MSG_E2, PSTR("T1")); break;
+ case 1: MENU_ITEM(gcode, MSG_SELECT " " MSG_E1, PSTR("T0")); break;
+ case 2: MENU_ITEM(gcode, MSG_SELECT " " MSG_E4, PSTR("T3")); break;
+ case 3: MENU_ITEM(gcode, MSG_SELECT " " MSG_E3, PSTR("T2")); break;
+ case 4: MENU_ITEM(gcode, MSG_SELECT " " MSG_E6, PSTR("T5")); break;
+ case 5: MENU_ITEM(gcode, MSG_SELECT " " MSG_E5, PSTR("T4")); break;
+ }
+ #elif EXTRUDERS == 5 || EXTRUDERS == 4
+ switch (active_extruder) {
+ case 0: MENU_ITEM(gcode, MSG_SELECT " " MSG_E2, PSTR("T1")); break;
+ case 1: MENU_ITEM(gcode, MSG_SELECT " " MSG_E1, PSTR("T0")); break;
+ case 2: MENU_ITEM(gcode, MSG_SELECT " " MSG_E4, PSTR("T3")); break;
+ case 3: MENU_ITEM(gcode, MSG_SELECT " " MSG_E3, PSTR("T2")); break;
+ }
+ #elif EXTRUDERS == 3
+ if (active_extruder < 2) {
+ if (active_extruder)
+ MENU_ITEM(gcode, MSG_SELECT " " MSG_E1, PSTR("T0"));
+ else
+ MENU_ITEM(gcode, MSG_SELECT " " MSG_E2, PSTR("T1"));
+ }
+ #else
+ if (active_extruder)
+ MENU_ITEM(gcode, MSG_SELECT " " MSG_E1, PSTR("T0"));
+ else
+ MENU_ITEM(gcode, MSG_SELECT " " MSG_E2, PSTR("T1"));
+ #endif
+
+ #elif ENABLED(DUAL_X_CARRIAGE)
+
+ if (active_extruder)
+ MENU_ITEM(gcode, MSG_SELECT " " MSG_E1, PSTR("T0"));
+ else
+ MENU_ITEM(gcode, MSG_SELECT " " MSG_E2, PSTR("T1"));
+
+ #endif
+
+ #if ENABLED(SWITCHING_EXTRUDER) || ENABLED(SWITCHING_NOZZLE)
+
+ // Only the current...
+ MENU_ITEM(submenu, MSG_MOVE_E, lcd_move_get_e_amount);
+ // ...and the non-switching
+ #if E_MANUAL == 5
+ MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E5, lcd_move_get_e4_amount);
+ #elif E_MANUAL == 3
+ MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E3, lcd_move_get_e2_amount);
+ #endif
+
+ #else
+
+ // Independent extruders with one E-stepper per hotend
+ MENU_ITEM(submenu, MSG_MOVE_E, lcd_move_get_e_amount);
+ #if E_MANUAL > 1
+ MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E1, lcd_move_get_e0_amount);
+ MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E2, lcd_move_get_e1_amount);
+ #if E_MANUAL > 2
+ MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E3, lcd_move_get_e2_amount);
+ #if E_MANUAL > 3
+ MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E4, lcd_move_get_e3_amount);
+ #if E_MANUAL > 4
+ MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E5, lcd_move_get_e4_amount);
+ #if E_MANUAL > 5
+ MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E6, lcd_move_get_e5_amount);
+ #endif // E_MANUAL > 5
+ #endif // E_MANUAL > 4
+ #endif // E_MANUAL > 3
+ #endif // E_MANUAL > 2
+ #endif // E_MANUAL > 1
+
+ #endif
+
+ END_MENU();
+}
+
+void _lcd_ubl_level_bed();
+void menu_bed_leveling();
+
+void menu_motion() {
+ START_MENU();
+
+ //
+ // ^ Main
+ //
+ MENU_BACK(MSG_MAIN);
+
+ //
+ // Move Axis
+ //
+ #if ENABLED(DELTA)
+ if (all_axes_homed())
+ #endif
+ MENU_ITEM(submenu, MSG_MOVE_AXIS, menu_move);
+
+ //
+ // Auto Home
+ //
+ MENU_ITEM(gcode, MSG_AUTO_HOME, PSTR("G28"));
+ #if ENABLED(INDIVIDUAL_AXIS_HOMING_MENU)
+ MENU_ITEM(gcode, MSG_AUTO_HOME_X, PSTR("G28 X"));
+ MENU_ITEM(gcode, MSG_AUTO_HOME_Y, PSTR("G28 Y"));
+ MENU_ITEM(gcode, MSG_AUTO_HOME_Z, PSTR("G28 Z"));
+ #endif
+
+ //
+ // TMC Z Calibration
+ //
+ #if ENABLED(TMC_Z_CALIBRATION)
+ MENU_ITEM(gcode, MSG_TMC_Z_CALIBRATION, PSTR("G28\nM915"));
+ #endif
+
+ //
+ // Level Bed
+ //
+ #if ENABLED(AUTO_BED_LEVELING_UBL)
+
+ MENU_ITEM(submenu, MSG_UBL_LEVEL_BED, _lcd_ubl_level_bed);
+
+ #elif ENABLED(LCD_BED_LEVELING)
+
+ if (!g29_in_progress) MENU_ITEM(submenu, MSG_BED_LEVELING, menu_bed_leveling);
+
+ #elif HAS_LEVELING && DISABLED(SLIM_LCD_MENUS)
+
+ #if DISABLED(PROBE_MANUALLY)
+ MENU_ITEM(gcode, MSG_LEVEL_BED, PSTR("G28\nG29"));
+ #endif
+ if (leveling_is_valid()) {
+ bool new_level_state = planner.leveling_active;
+ MENU_ITEM_EDIT_CALLBACK(bool, MSG_BED_LEVELING, &new_level_state, _lcd_toggle_bed_leveling);
+ }
+ #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
+ MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float3, MSG_Z_FADE_HEIGHT, &lcd_z_fade_height, 0, 100, _lcd_set_z_fade_height);
+ #endif
+
+ #endif
+
+ #if ENABLED(LEVEL_BED_CORNERS) && DISABLED(LCD_BED_LEVELING)
+ MENU_ITEM(function, MSG_LEVEL_CORNERS, _lcd_level_bed_corners);
+ #endif
+
+ //
+ // Disable Steppers
+ //
+ MENU_ITEM(gcode, MSG_DISABLE_STEPPERS, PSTR("M84"));
+
+ END_MENU();
+}
+
+#endif // HAS_LCD_MENU
diff --git a/Marlin/src/lcd/menu/menu_sdcard.cpp b/Marlin/src/lcd/menu/menu_sdcard.cpp
new file mode 100644
index 0000000000..7b7eba8143
--- /dev/null
+++ b/Marlin/src/lcd/menu/menu_sdcard.cpp
@@ -0,0 +1,137 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+//
+// SD Card Menu
+//
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if HAS_LCD_MENU && ENABLED(SDSUPPORT)
+
+#include "menu.h"
+#include "../../sd/cardreader.h"
+
+#if !PIN_EXISTS(SD_DETECT)
+ void lcd_sd_refresh() {
+ card.initsd();
+ encoderTopLine = 0;
+ }
+#endif
+
+void lcd_sd_updir() {
+ encoderPosition = card.updir() ? ENCODER_STEPS_PER_MENU_ITEM : 0;
+ encoderTopLine = 0;
+ screen_changed = true;
+ lcd_refresh();
+}
+
+#if ENABLED(SD_REPRINT_LAST_SELECTED_FILE)
+ uint32_t last_sdfile_encoderPosition = 0xFFFF;
+
+ void lcd_reselect_last_file() {
+ if (last_sdfile_encoderPosition == 0xFFFF) return;
+ #if HAS_GRAPHICAL_LCD
+ // Some of this is a hack to force the screen update to work.
+ // TODO: Fix the real issue that causes this!
+ lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NEXT;
+ lcd_synchronize();
+ safe_delay(50);
+ lcd_synchronize();
+ lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NEXT;
+ drawing_screen = screen_changed = true;
+ #endif
+
+ lcd_goto_screen(menu_sdcard, last_sdfile_encoderPosition);
+ defer_return_to_status = true;
+ last_sdfile_encoderPosition = 0xFFFF;
+
+ #if HAS_GRAPHICAL_LCD
+ lcd_update();
+ #endif
+ }
+#endif
+
+void menu_action_sdfile(CardReader &theCard) {
+ #if ENABLED(SD_REPRINT_LAST_SELECTED_FILE)
+ last_sdfile_encoderPosition = encoderPosition; // Save which file was selected for later use
+ #endif
+ card.openAndPrintFile(theCard.filename);
+ lcd_return_to_status();
+ lcd_reset_status();
+}
+
+void menu_action_sddirectory(CardReader &theCard) {
+ card.chdir(theCard.filename);
+ encoderTopLine = 0;
+ encoderPosition = 2 * ENCODER_STEPS_PER_MENU_ITEM;
+ screen_changed = true;
+ #if HAS_GRAPHICAL_LCD
+ drawing_screen = false;
+ #endif
+ lcd_refresh();
+}
+
+void menu_sdcard() {
+ ENCODER_DIRECTION_MENUS();
+
+ const uint16_t fileCnt = card.get_num_Files();
+
+ START_MENU();
+ MENU_BACK(MSG_MAIN);
+ card.getWorkDirName();
+ if (card.filename[0] == '/') {
+ #if !PIN_EXISTS(SD_DETECT)
+ MENU_ITEM(function, LCD_STR_REFRESH MSG_REFRESH, lcd_sd_refresh);
+ #endif
+ }
+ else {
+ MENU_ITEM(function, LCD_STR_FOLDER "..", lcd_sd_updir);
+ }
+
+ for (uint16_t i = 0; i < fileCnt; i++) {
+ if (_menuLineNr == _thisItemNr) {
+ const uint16_t nr =
+ #if ENABLED(SDCARD_RATHERRECENTFIRST) && DISABLED(SDCARD_SORT_ALPHA)
+ fileCnt - 1 -
+ #endif
+ i;
+
+ #if ENABLED(SDCARD_SORT_ALPHA)
+ card.getfilename_sorted(nr);
+ #else
+ card.getfilename(nr);
+ #endif
+
+ if (card.filenameIsDir)
+ MENU_ITEM(sddirectory, MSG_CARD_MENU, card);
+ else
+ MENU_ITEM(sdfile, MSG_CARD_MENU, card);
+ }
+ else {
+ MENU_ITEM_DUMMY();
+ }
+ }
+ END_MENU();
+}
+
+#endif // HAS_LCD_MENU && SDSUPPORT
diff --git a/Marlin/src/lcd/menu/menu_temperature.cpp b/Marlin/src/lcd/menu/menu_temperature.cpp
new file mode 100644
index 0000000000..b1d09e96cd
--- /dev/null
+++ b/Marlin/src/lcd/menu/menu_temperature.cpp
@@ -0,0 +1,389 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+//
+// Temperature Menu
+//
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if HAS_LCD_MENU
+
+#include "menu.h"
+#include "../../module/temperature.h"
+
+#if FAN_COUNT > 1
+ #include "../../module/motion.h"
+#endif
+
+// Initialized by settings.load()
+int16_t lcd_preheat_hotend_temp[2], lcd_preheat_bed_temp[2];
+uint8_t lcd_preheat_fan_speed[2];
+
+//
+// "Temperature" submenu items
+//
+
+void _lcd_preheat(const int16_t endnum, const int16_t temph, const int16_t tempb, const uint8_t fan) {
+ if (temph > 0) thermalManager.setTargetHotend(MIN(heater_maxtemp[endnum], temph), endnum);
+ #if HAS_HEATED_BED
+ if (tempb >= 0) thermalManager.setTargetBed(tempb);
+ #else
+ UNUSED(tempb);
+ #endif
+ #if FAN_COUNT > 0
+ #if FAN_COUNT > 1
+ fan_speed[active_extruder < FAN_COUNT ? active_extruder : 0] = fan;
+ #else
+ fan_speed[0] = fan;
+ #endif
+ #else
+ UNUSED(fan);
+ #endif
+ lcd_return_to_status();
+}
+
+#if HOTENDS > 1
+
+ void lcd_preheat_m1_e1_only() { _lcd_preheat(1, lcd_preheat_hotend_temp[0], -1, lcd_preheat_fan_speed[0]); }
+ void lcd_preheat_m2_e1_only() { _lcd_preheat(1, lcd_preheat_hotend_temp[1], -1, lcd_preheat_fan_speed[1]); }
+ #if HAS_HEATED_BED
+ void lcd_preheat_m1_e1() { _lcd_preheat(1, lcd_preheat_hotend_temp[0], lcd_preheat_bed_temp[0], lcd_preheat_fan_speed[0]); }
+ void lcd_preheat_m2_e1() { _lcd_preheat(1, lcd_preheat_hotend_temp[1], lcd_preheat_bed_temp[1], lcd_preheat_fan_speed[1]); }
+ #endif
+ #if HOTENDS > 2
+ void lcd_preheat_m1_e2_only() { _lcd_preheat(2, lcd_preheat_hotend_temp[0], -1, lcd_preheat_fan_speed[0]); }
+ void lcd_preheat_m2_e2_only() { _lcd_preheat(2, lcd_preheat_hotend_temp[1], -1, lcd_preheat_fan_speed[1]); }
+ #if HAS_HEATED_BED
+ void lcd_preheat_m1_e2() { _lcd_preheat(2, lcd_preheat_hotend_temp[0], lcd_preheat_bed_temp[0], lcd_preheat_fan_speed[0]); }
+ void lcd_preheat_m2_e2() { _lcd_preheat(2, lcd_preheat_hotend_temp[1], lcd_preheat_bed_temp[1], lcd_preheat_fan_speed[1]); }
+ #endif
+ #if HOTENDS > 3
+ void lcd_preheat_m1_e3_only() { _lcd_preheat(3, lcd_preheat_hotend_temp[0], -1, lcd_preheat_fan_speed[0]); }
+ void lcd_preheat_m2_e3_only() { _lcd_preheat(3, lcd_preheat_hotend_temp[1], -1, lcd_preheat_fan_speed[1]); }
+ #if HAS_HEATED_BED
+ void lcd_preheat_m1_e3() { _lcd_preheat(3, lcd_preheat_hotend_temp[0], lcd_preheat_bed_temp[0], lcd_preheat_fan_speed[0]); }
+ void lcd_preheat_m2_e3() { _lcd_preheat(3, lcd_preheat_hotend_temp[1], lcd_preheat_bed_temp[1], lcd_preheat_fan_speed[1]); }
+ #endif
+ #if HOTENDS > 4
+ void lcd_preheat_m1_e4_only() { _lcd_preheat(4, lcd_preheat_hotend_temp[0], -1, lcd_preheat_fan_speed[0]); }
+ void lcd_preheat_m2_e4_only() { _lcd_preheat(4, lcd_preheat_hotend_temp[1], -1, lcd_preheat_fan_speed[1]); }
+ #if HAS_HEATED_BED
+ void lcd_preheat_m1_e4() { _lcd_preheat(4, lcd_preheat_hotend_temp[0], lcd_preheat_bed_temp[0], lcd_preheat_fan_speed[0]); }
+ void lcd_preheat_m2_e4() { _lcd_preheat(4, lcd_preheat_hotend_temp[1], lcd_preheat_bed_temp[1], lcd_preheat_fan_speed[1]); }
+ #endif
+ #if HOTENDS > 5
+ void lcd_preheat_m1_e5_only() { _lcd_preheat(5, lcd_preheat_hotend_temp[0], -1, lcd_preheat_fan_speed[0]); }
+ void lcd_preheat_m2_e5_only() { _lcd_preheat(5, lcd_preheat_hotend_temp[1], -1, lcd_preheat_fan_speed[1]); }
+ #if HAS_HEATED_BED
+ void lcd_preheat_m1_e5() { _lcd_preheat(5, lcd_preheat_hotend_temp[0], lcd_preheat_bed_temp[0], lcd_preheat_fan_speed[0]); }
+ void lcd_preheat_m2_e5() { _lcd_preheat(5, lcd_preheat_hotend_temp[1], lcd_preheat_bed_temp[1], lcd_preheat_fan_speed[1]); }
+ #endif
+ #endif // HOTENDS > 5
+ #endif // HOTENDS > 4
+ #endif // HOTENDS > 3
+ #endif // HOTENDS > 2
+
+ #if HAS_HEATED_BED
+ void lcd_preheat_m1_e0();
+ void lcd_preheat_m2_e0();
+ #else
+ void lcd_preheat_m1_e0_only();
+ void lcd_preheat_m2_e0_only();
+ #endif
+
+ void lcd_preheat_m1_all() {
+ #if HOTENDS > 1
+ thermalManager.setTargetHotend(lcd_preheat_hotend_temp[0], 1);
+ #if HOTENDS > 2
+ thermalManager.setTargetHotend(lcd_preheat_hotend_temp[0], 2);
+ #if HOTENDS > 3
+ thermalManager.setTargetHotend(lcd_preheat_hotend_temp[0], 3);
+ #if HOTENDS > 4
+ thermalManager.setTargetHotend(lcd_preheat_hotend_temp[0], 4);
+ #if HOTENDS > 5
+ thermalManager.setTargetHotend(lcd_preheat_hotend_temp[0], 5);
+ #endif // HOTENDS > 5
+ #endif // HOTENDS > 4
+ #endif // HOTENDS > 3
+ #endif // HOTENDS > 2
+ #endif // HOTENDS > 1
+ #if HAS_HEATED_BED
+ lcd_preheat_m1_e0();
+ #else
+ lcd_preheat_m1_e0_only();
+ #endif
+ }
+
+ void lcd_preheat_m2_all() {
+ #if HOTENDS > 1
+ thermalManager.setTargetHotend(lcd_preheat_hotend_temp[1], 1);
+ #if HOTENDS > 2
+ thermalManager.setTargetHotend(lcd_preheat_hotend_temp[1], 2);
+ #if HOTENDS > 3
+ thermalManager.setTargetHotend(lcd_preheat_hotend_temp[1], 3);
+ #if HOTENDS > 4
+ thermalManager.setTargetHotend(lcd_preheat_hotend_temp[1], 4);
+ #if HOTENDS > 5
+ thermalManager.setTargetHotend(lcd_preheat_hotend_temp[1], 5);
+ #endif // HOTENDS > 5
+ #endif // HOTENDS > 4
+ #endif // HOTENDS > 3
+ #endif // HOTENDS > 2
+ #endif // HOTENDS > 1
+ #if HAS_HEATED_BED
+ lcd_preheat_m2_e0();
+ #else
+ lcd_preheat_m2_e0_only();
+ #endif
+ }
+
+#endif // HOTENDS > 1
+
+#if HAS_TEMP_HOTEND || HAS_HEATED_BED
+
+ void lcd_preheat_m1_e0_only() { _lcd_preheat(0, lcd_preheat_hotend_temp[0], -1, lcd_preheat_fan_speed[0]); }
+ void lcd_preheat_m2_e0_only() { _lcd_preheat(0, lcd_preheat_hotend_temp[1], -1, lcd_preheat_fan_speed[1]); }
+
+ #if HAS_HEATED_BED
+ void lcd_preheat_m1_e0() { _lcd_preheat(0, lcd_preheat_hotend_temp[0], lcd_preheat_bed_temp[0], lcd_preheat_fan_speed[0]); }
+ void lcd_preheat_m2_e0() { _lcd_preheat(0, lcd_preheat_hotend_temp[1], lcd_preheat_bed_temp[1], lcd_preheat_fan_speed[1]); }
+ void lcd_preheat_m1_bedonly() { _lcd_preheat(0, 0, lcd_preheat_bed_temp[0], lcd_preheat_fan_speed[0]); }
+ void lcd_preheat_m2_bedonly() { _lcd_preheat(0, 0, lcd_preheat_bed_temp[1], lcd_preheat_fan_speed[1]); }
+ #endif
+
+ void menu_preheat_m1() {
+ START_MENU();
+ MENU_BACK(MSG_TEMPERATURE);
+ #if HOTENDS == 1
+ #if HAS_HEATED_BED
+ MENU_ITEM(function, MSG_PREHEAT_1, lcd_preheat_m1_e0);
+ MENU_ITEM(function, MSG_PREHEAT_1_END, lcd_preheat_m1_e0_only);
+ #else
+ MENU_ITEM(function, MSG_PREHEAT_1, lcd_preheat_m1_e0_only);
+ #endif
+ #elif HOTENDS > 1
+ #if HAS_HEATED_BED
+ MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H1, lcd_preheat_m1_e0);
+ MENU_ITEM(function, MSG_PREHEAT_1_END " " MSG_E1, lcd_preheat_m1_e0_only);
+ MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H2, lcd_preheat_m1_e1);
+ MENU_ITEM(function, MSG_PREHEAT_1_END " " MSG_E2, lcd_preheat_m1_e1_only);
+ #else
+ MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H1, lcd_preheat_m1_e0_only);
+ MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H2, lcd_preheat_m1_e1_only);
+ #endif
+ #if HOTENDS > 2
+ #if HAS_HEATED_BED
+ MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H3, lcd_preheat_m1_e2);
+ MENU_ITEM(function, MSG_PREHEAT_1_END " " MSG_E3, lcd_preheat_m1_e2_only);
+ #else
+ MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H3, lcd_preheat_m1_e2_only);
+ #endif
+ #if HOTENDS > 3
+ #if HAS_HEATED_BED
+ MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H4, lcd_preheat_m1_e3);
+ MENU_ITEM(function, MSG_PREHEAT_1_END " " MSG_E4, lcd_preheat_m1_e3_only);
+ #else
+ MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H4, lcd_preheat_m1_e3_only);
+ #endif
+ #if HOTENDS > 4
+ #if HAS_HEATED_BED
+ MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H5, lcd_preheat_m1_e4);
+ MENU_ITEM(function, MSG_PREHEAT_1_END " " MSG_E5, lcd_preheat_m1_e4_only);
+ #else
+ MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H5, lcd_preheat_m1_e4_only);
+ #endif
+ #if HOTENDS > 5
+ #if HAS_HEATED_BED
+ MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H6, lcd_preheat_m1_e5);
+ MENU_ITEM(function, MSG_PREHEAT_1_END " " MSG_E6, lcd_preheat_m1_e5_only);
+ #else
+ MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H6, lcd_preheat_m1_e5_only);
+ #endif
+ #endif // HOTENDS > 5
+ #endif // HOTENDS > 4
+ #endif // HOTENDS > 3
+ #endif // HOTENDS > 2
+ MENU_ITEM(function, MSG_PREHEAT_1_ALL, lcd_preheat_m1_all);
+ #endif // HOTENDS > 1
+ #if HAS_HEATED_BED
+ MENU_ITEM(function, MSG_PREHEAT_1_BEDONLY, lcd_preheat_m1_bedonly);
+ #endif
+ END_MENU();
+ }
+
+ void menu_preheat_m2() {
+ START_MENU();
+ MENU_BACK(MSG_TEMPERATURE);
+ #if HOTENDS == 1
+ #if HAS_HEATED_BED
+ MENU_ITEM(function, MSG_PREHEAT_2, lcd_preheat_m2_e0);
+ MENU_ITEM(function, MSG_PREHEAT_2_END, lcd_preheat_m2_e0_only);
+ #else
+ MENU_ITEM(function, MSG_PREHEAT_2, lcd_preheat_m2_e0_only);
+ #endif
+ #elif HOTENDS > 1
+ #if HAS_HEATED_BED
+ MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H1, lcd_preheat_m2_e0);
+ MENU_ITEM(function, MSG_PREHEAT_2_END " " MSG_E1, lcd_preheat_m2_e0_only);
+ MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H2, lcd_preheat_m2_e1);
+ MENU_ITEM(function, MSG_PREHEAT_2_END " " MSG_E2, lcd_preheat_m2_e1_only);
+ #else
+ MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H1, lcd_preheat_m2_e0_only);
+ MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H2, lcd_preheat_m2_e1_only);
+ #endif
+ #if HOTENDS > 2
+ #if HAS_HEATED_BED
+ MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H3, lcd_preheat_m2_e2);
+ MENU_ITEM(function, MSG_PREHEAT_2_END " " MSG_E3, lcd_preheat_m2_e2_only);
+ #else
+ MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H3, lcd_preheat_m2_e2_only);
+ #endif
+ #if HOTENDS > 3
+ #if HAS_HEATED_BED
+ MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H4, lcd_preheat_m2_e3);
+ MENU_ITEM(function, MSG_PREHEAT_2_END " " MSG_E4, lcd_preheat_m2_e3_only);
+ #else
+ MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H4, lcd_preheat_m2_e3_only);
+ #endif
+ #if HOTENDS > 4
+ #if HAS_HEATED_BED
+ MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H5, lcd_preheat_m2_e4);
+ MENU_ITEM(function, MSG_PREHEAT_2_END " " MSG_E5, lcd_preheat_m2_e4_only);
+ #else
+ MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H5, lcd_preheat_m2_e4_only);
+ #endif
+ #if HOTENDS > 5
+ #if HAS_HEATED_BED
+ MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H6, lcd_preheat_m2_e5);
+ MENU_ITEM(function, MSG_PREHEAT_2_END " " MSG_E6, lcd_preheat_m2_e5_only);
+ #else
+ MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H6, lcd_preheat_m2_e5_only);
+ #endif
+ #endif // HOTENDS > 5
+ #endif // HOTENDS > 4
+ #endif // HOTENDS > 3
+ #endif // HOTENDS > 2
+ MENU_ITEM(function, MSG_PREHEAT_2_ALL, lcd_preheat_m2_all);
+ #endif // HOTENDS > 1
+ #if HAS_HEATED_BED
+ MENU_ITEM(function, MSG_PREHEAT_2_BEDONLY, lcd_preheat_m2_bedonly);
+ #endif
+ END_MENU();
+ }
+
+ void lcd_cooldown() {
+ zero_fan_speeds();
+ thermalManager.disable_all_heaters();
+ lcd_return_to_status();
+ }
+
+#endif // HAS_TEMP_HOTEND || HAS_HEATED_BED
+
+void menu_temperature() {
+ START_MENU();
+ MENU_BACK(MSG_MAIN);
+
+ //
+ // Nozzle:
+ // Nozzle [1-5]:
+ //
+ #if HOTENDS == 1
+ MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE, &thermalManager.target_temperature[0], 0, HEATER_0_MAXTEMP - 15, watch_temp_callback_E0);
+ #else // HOTENDS > 1
+ #define EDIT_TARGET(N,I) MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N##N, &thermalManager.target_temperature[I], 0, HEATER_##I##_MAXTEMP - 15, watch_temp_callback_E##I)
+ EDIT_TARGET(1,0);
+ EDIT_TARGET(2,1);
+ #if HOTENDS > 2
+ EDIT_TARGET(3,2);
+ #if HOTENDS > 3
+ EDIT_TARGET(4,3);
+ #if HOTENDS > 4
+ EDIT_TARGET(5,4);
+ #if HOTENDS > 5
+ EDIT_TARGET(6,5);
+ #endif // HOTENDS > 5
+ #endif // HOTENDS > 4
+ #endif // HOTENDS > 3
+ #endif // HOTENDS > 2
+ #endif // HOTENDS > 1
+
+ //
+ // Bed:
+ //
+ #if HAS_HEATED_BED
+ MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_BED, &thermalManager.target_temperature_bed, 0, BED_MAXTEMP - 15, watch_temp_callback_bed);
+ #endif
+
+ //
+ // Fan Speed:
+ //
+ #if FAN_COUNT > 0
+ #if HAS_FAN0
+ MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_FAN_SPEED FAN_SPEED_1_SUFFIX, &fan_speed[0], 0, 255);
+ #if ENABLED(EXTRA_FAN_SPEED)
+ MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_EXTRA_FAN_SPEED FAN_SPEED_1_SUFFIX, &new_fan_speed[0], 3, 255);
+ #endif
+ #endif
+ #if HAS_FAN1
+ MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_FAN_SPEED " 2", &fan_speed[1], 0, 255);
+ #if ENABLED(EXTRA_FAN_SPEED)
+ MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_EXTRA_FAN_SPEED " 2", &new_fan_speed[1], 3, 255);
+ #endif
+ #endif
+ #if HAS_FAN2
+ MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_FAN_SPEED " 3", &fan_speed[2], 0, 255);
+ #if ENABLED(EXTRA_FAN_SPEED)
+ MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_EXTRA_FAN_SPEED " 3", &new_fan_speed[2], 3, 255);
+ #endif
+ #endif
+ #endif // FAN_COUNT > 0
+
+ #if HAS_TEMP_HOTEND
+
+ //
+ // Cooldown
+ //
+ bool has_heat = false;
+ HOTEND_LOOP() if (thermalManager.target_temperature[HOTEND_INDEX]) { has_heat = true; break; }
+ #if HAS_TEMP_BED
+ if (thermalManager.target_temperature_bed) has_heat = true;
+ #endif
+ if (has_heat) MENU_ITEM(function, MSG_COOLDOWN, lcd_cooldown);
+
+ //
+ // Preheat for Material 1 and 2
+ //
+ #if TEMP_SENSOR_1 != 0 || TEMP_SENSOR_2 != 0 || TEMP_SENSOR_3 != 0 || TEMP_SENSOR_4 != 0 || HAS_HEATED_BED
+ MENU_ITEM(submenu, MSG_PREHEAT_1, menu_preheat_m1);
+ MENU_ITEM(submenu, MSG_PREHEAT_2, menu_preheat_m2);
+ #else
+ MENU_ITEM(function, MSG_PREHEAT_1, lcd_preheat_m1_e0_only);
+ MENU_ITEM(function, MSG_PREHEAT_2, lcd_preheat_m2_e0_only);
+ #endif
+
+ #endif // HAS_TEMP_HOTEND
+
+ END_MENU();
+}
+
+#endif // HAS_LCD_MENU
diff --git a/Marlin/src/lcd/menu/menu_tune.cpp b/Marlin/src/lcd/menu/menu_tune.cpp
new file mode 100644
index 0000000000..97c7d86a7b
--- /dev/null
+++ b/Marlin/src/lcd/menu/menu_tune.cpp
@@ -0,0 +1,206 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+//
+// Tune Menu
+//
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if HAS_LCD_MENU
+
+#include "menu.h"
+#include "../../module/motion.h"
+#include "../../module/planner.h"
+#include "../../module/temperature.h"
+#include "../../Marlin.h"
+
+#if HAS_LEVELING
+ #include "../../feature/bedlevel/bedlevel.h"
+#endif
+
+// Refresh the E factor after changing flow
+void _lcd_refresh_e_factor_0() { planner.refresh_e_factor(0); }
+#if EXTRUDERS > 1
+ void _lcd_refresh_e_factor() { planner.refresh_e_factor(active_extruder); }
+ void _lcd_refresh_e_factor_1() { planner.refresh_e_factor(1); }
+ #if EXTRUDERS > 2
+ void _lcd_refresh_e_factor_2() { planner.refresh_e_factor(2); }
+ #if EXTRUDERS > 3
+ void _lcd_refresh_e_factor_3() { planner.refresh_e_factor(3); }
+ #if EXTRUDERS > 4
+ void _lcd_refresh_e_factor_4() { planner.refresh_e_factor(4); }
+ #if EXTRUDERS > 5
+ void _lcd_refresh_e_factor_5() { planner.refresh_e_factor(5); }
+ #endif // EXTRUDERS > 5
+ #endif // EXTRUDERS > 4
+ #endif // EXTRUDERS > 3
+ #endif // EXTRUDERS > 2
+#endif // EXTRUDERS > 1
+
+#if ENABLED(BABYSTEPPING)
+
+ long babysteps_done = 0;
+
+ void _lcd_babystep(const AxisEnum axis, PGM_P msg) {
+ if (use_click()) { return lcd_goto_previous_menu_no_defer(); }
+ ENCODER_DIRECTION_NORMAL();
+ if (encoderPosition) {
+ const int16_t babystep_increment = (int32_t)encoderPosition * (BABYSTEP_MULTIPLICATOR);
+ encoderPosition = 0;
+ lcdDrawUpdate = LCDVIEW_REDRAW_NOW;
+ thermalManager.babystep_axis(axis, babystep_increment);
+ babysteps_done += babystep_increment;
+ }
+ if (lcdDrawUpdate)
+ lcd_implementation_drawedit(msg, ftostr43sign(planner.steps_to_mm[axis] * babysteps_done));
+ }
+
+ #if ENABLED(BABYSTEP_XY)
+ void _lcd_babystep_x() { _lcd_babystep(X_AXIS, PSTR(MSG_BABYSTEP_X)); }
+ void _lcd_babystep_y() { _lcd_babystep(Y_AXIS, PSTR(MSG_BABYSTEP_Y)); }
+ void lcd_babystep_x() { lcd_goto_screen(_lcd_babystep_x); babysteps_done = 0; defer_return_to_status = true; }
+ void lcd_babystep_y() { lcd_goto_screen(_lcd_babystep_y); babysteps_done = 0; defer_return_to_status = true; }
+ #endif
+
+ #if DISABLED(BABYSTEP_ZPROBE_OFFSET)
+ void _lcd_babystep_z() { _lcd_babystep(Z_AXIS, PSTR(MSG_BABYSTEP_Z)); }
+ void lcd_babystep_z() { lcd_goto_screen(_lcd_babystep_z); babysteps_done = 0; defer_return_to_status = true; }
+ #endif
+
+#endif // BABYSTEPPING
+
+void menu_tune() {
+ START_MENU();
+ MENU_BACK(MSG_MAIN);
+
+ //
+ // Speed:
+ //
+ MENU_ITEM_EDIT(int3, MSG_SPEED, &feedrate_percentage, 10, 999);
+
+ //
+ // Manual bed leveling, Bed Z:
+ //
+ #if ENABLED(MESH_BED_LEVELING) && ENABLED(LCD_BED_LEVELING)
+ MENU_ITEM_EDIT(float43, MSG_BED_Z, &mbl.z_offset, -1, 1);
+ #endif
+
+ //
+ // Nozzle:
+ // Nozzle [1-4]:
+ //
+ #if HOTENDS == 1
+ MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE, &thermalManager.target_temperature[0], 0, HEATER_0_MAXTEMP - 15, watch_temp_callback_E0);
+ #else // HOTENDS > 1
+ MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N1, &thermalManager.target_temperature[0], 0, HEATER_0_MAXTEMP - 15, watch_temp_callback_E0);
+ MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N2, &thermalManager.target_temperature[1], 0, HEATER_1_MAXTEMP - 15, watch_temp_callback_E1);
+ #if HOTENDS > 2
+ MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N3, &thermalManager.target_temperature[2], 0, HEATER_2_MAXTEMP - 15, watch_temp_callback_E2);
+ #if HOTENDS > 3
+ MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N4, &thermalManager.target_temperature[3], 0, HEATER_3_MAXTEMP - 15, watch_temp_callback_E3);
+ #if HOTENDS > 4
+ MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N5, &thermalManager.target_temperature[4], 0, HEATER_4_MAXTEMP - 15, watch_temp_callback_E4);
+ #if HOTENDS > 5
+ MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N6, &thermalManager.target_temperature[5], 0, HEATER_5_MAXTEMP - 15, watch_temp_callback_E5);
+ #endif // HOTENDS > 5
+ #endif // HOTENDS > 4
+ #endif // HOTENDS > 3
+ #endif // HOTENDS > 2
+ #endif // HOTENDS > 1
+
+ //
+ // Bed:
+ //
+ #if HAS_HEATED_BED
+ MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_BED, &thermalManager.target_temperature_bed, 0, BED_MAXTEMP - 15, watch_temp_callback_bed);
+ #endif
+
+ //
+ // Fan Speed:
+ //
+ #if FAN_COUNT > 0
+ #if HAS_FAN0
+ MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_FAN_SPEED FAN_SPEED_1_SUFFIX, &fan_speed[0], 0, 255);
+ #if ENABLED(EXTRA_FAN_SPEED)
+ MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_EXTRA_FAN_SPEED FAN_SPEED_1_SUFFIX, &new_fan_speed[0], 3, 255);
+ #endif
+ #endif
+ #if HAS_FAN1
+ MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_FAN_SPEED " 2", &fan_speed[1], 0, 255);
+ #if ENABLED(EXTRA_FAN_SPEED)
+ MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_EXTRA_FAN_SPEED " 2", &new_fan_speed[1], 3, 255);
+ #endif
+ #endif
+ #if HAS_FAN2
+ MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_FAN_SPEED " 3", &fan_speed[2], 0, 255);
+ #if ENABLED(EXTRA_FAN_SPEED)
+ MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_EXTRA_FAN_SPEED " 3", &new_fan_speed[2], 3, 255);
+ #endif
+ #endif
+ #endif // FAN_COUNT > 0
+
+ //
+ // Flow:
+ // Flow [1-5]:
+ //
+ #if EXTRUDERS == 1
+ MENU_ITEM_EDIT_CALLBACK(int3, MSG_FLOW, &planner.flow_percentage[0], 10, 999, _lcd_refresh_e_factor_0);
+ #else // EXTRUDERS > 1
+ MENU_ITEM_EDIT_CALLBACK(int3, MSG_FLOW, &planner.flow_percentage[active_extruder], 10, 999, _lcd_refresh_e_factor);
+ MENU_ITEM_EDIT_CALLBACK(int3, MSG_FLOW MSG_N1, &planner.flow_percentage[0], 10, 999, _lcd_refresh_e_factor_0);
+ MENU_ITEM_EDIT_CALLBACK(int3, MSG_FLOW MSG_N2, &planner.flow_percentage[1], 10, 999, _lcd_refresh_e_factor_1);
+ #if EXTRUDERS > 2
+ MENU_ITEM_EDIT_CALLBACK(int3, MSG_FLOW MSG_N3, &planner.flow_percentage[2], 10, 999, _lcd_refresh_e_factor_2);
+ #if EXTRUDERS > 3
+ MENU_ITEM_EDIT_CALLBACK(int3, MSG_FLOW MSG_N4, &planner.flow_percentage[3], 10, 999, _lcd_refresh_e_factor_3);
+ #if EXTRUDERS > 4
+ MENU_ITEM_EDIT_CALLBACK(int3, MSG_FLOW MSG_N5, &planner.flow_percentage[4], 10, 999, _lcd_refresh_e_factor_4);
+ #if EXTRUDERS > 5
+ MENU_ITEM_EDIT_CALLBACK(int3, MSG_FLOW MSG_N6, &planner.flow_percentage[5], 10, 999, _lcd_refresh_e_factor_5);
+ #endif // EXTRUDERS > 5
+ #endif // EXTRUDERS > 4
+ #endif // EXTRUDERS > 3
+ #endif // EXTRUDERS > 2
+ #endif // EXTRUDERS > 1
+
+ //
+ // Babystep X:
+ // Babystep Y:
+ // Babystep Z:
+ //
+ #if ENABLED(BABYSTEPPING)
+ #if ENABLED(BABYSTEP_XY)
+ MENU_ITEM(submenu, MSG_BABYSTEP_X, lcd_babystep_x);
+ MENU_ITEM(submenu, MSG_BABYSTEP_Y, lcd_babystep_y);
+ #endif
+ #if ENABLED(BABYSTEP_ZPROBE_OFFSET)
+ MENU_ITEM(submenu, MSG_ZPROBE_ZOFFSET, lcd_babystep_zoffset);
+ #else
+ MENU_ITEM(submenu, MSG_BABYSTEP_Z, lcd_babystep_z);
+ #endif
+ #endif
+
+ END_MENU();
+}
+
+#endif // HAS_LCD_MENU
diff --git a/Marlin/src/lcd/menu/menu_ubl.cpp b/Marlin/src/lcd/menu/menu_ubl.cpp
new file mode 100644
index 0000000000..fdda55812c
--- /dev/null
+++ b/Marlin/src/lcd/menu/menu_ubl.cpp
@@ -0,0 +1,606 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+//
+// Unified Bed Leveling Menus
+//
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if HAS_LCD_MENU && ENABLED(AUTO_BED_LEVELING_UBL)
+
+#include "menu.h"
+#include "../../module/planner.h"
+#include "../../module/configuration_store.h"
+#include "../../feature/bedlevel/bedlevel.h"
+
+static int16_t ubl_storage_slot = 0,
+ custom_hotend_temp = 190,
+ side_points = 3,
+ ubl_fillin_amount = 5,
+ ubl_height_amount = 1,
+ n_edit_pts = 1,
+ x_plot = 0,
+ y_plot = 0;
+
+#if HAS_HEATED_BED
+ static int16_t custom_bed_temp = 50;
+#endif
+
+float mesh_edit_value, mesh_edit_accumulator; // We round mesh_edit_value to 2.5 decimal places. So we keep a
+ // separate value that doesn't lose precision.
+static int16_t ubl_encoderPosition = 0;
+
+static void _lcd_mesh_fine_tune(PGM_P msg) {
+ defer_return_to_status = true;
+ if (ubl.encoder_diff) {
+ ubl_encoderPosition = (ubl.encoder_diff > 0) ? 1 : -1;
+ ubl.encoder_diff = 0;
+
+ mesh_edit_accumulator += float(ubl_encoderPosition) * 0.005f * 0.5f;
+ mesh_edit_value = mesh_edit_accumulator;
+ encoderPosition = 0;
+ lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NEXT;
+
+ const int32_t rounded = (int32_t)(mesh_edit_value * 1000);
+ mesh_edit_value = float(rounded - (rounded % 5L)) / 1000;
+ }
+
+ if (lcdDrawUpdate) {
+ lcd_implementation_drawedit(msg, ftostr43sign(mesh_edit_value));
+ #if ENABLED(MESH_EDIT_GFX_OVERLAY)
+ _lcd_zoffset_overlay_gfx(mesh_edit_value);
+ #endif
+ }
+}
+
+void _lcd_mesh_edit_NOP() {
+ defer_return_to_status = true;
+}
+
+float lcd_mesh_edit() {
+ lcd_goto_screen(_lcd_mesh_edit_NOP);
+ lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NEXT;
+ _lcd_mesh_fine_tune(PSTR("Mesh Editor"));
+ return mesh_edit_value;
+}
+
+void lcd_mesh_edit_setup(const float &initial) {
+ mesh_edit_value = mesh_edit_accumulator = initial;
+ lcd_goto_screen(_lcd_mesh_edit_NOP);
+}
+
+void _lcd_z_offset_edit() {
+ _lcd_mesh_fine_tune(PSTR("Z-Offset: "));
+}
+
+float lcd_z_offset_edit() {
+ lcd_goto_screen(_lcd_z_offset_edit);
+ return mesh_edit_value;
+}
+
+void lcd_z_offset_edit_setup(const float &initial) {
+ mesh_edit_value = mesh_edit_accumulator = initial;
+ lcd_goto_screen(_lcd_z_offset_edit);
+}
+
+/**
+ * UBL Build Custom Mesh Command
+ */
+void _lcd_ubl_build_custom_mesh() {
+ char UBL_LCD_GCODE[20];
+ enqueue_and_echo_commands_P(PSTR("G28"));
+ #if HAS_HEATED_BED
+ sprintf_P(UBL_LCD_GCODE, PSTR("M190 S%i"), custom_bed_temp);
+ lcd_enqueue_command(UBL_LCD_GCODE);
+ #endif
+ sprintf_P(UBL_LCD_GCODE, PSTR("M109 S%i"), custom_hotend_temp);
+ lcd_enqueue_command(UBL_LCD_GCODE);
+ enqueue_and_echo_commands_P(PSTR("G29 P1"));
+}
+
+/**
+ * UBL Custom Mesh submenu
+ *
+ * << Build Mesh
+ * Hotend Temp: ---
+ * Bed Temp: ---
+ * Build Custom Mesh
+ */
+void _lcd_ubl_custom_mesh() {
+ START_MENU();
+ MENU_BACK(MSG_UBL_BUILD_MESH_MENU);
+ MENU_ITEM_EDIT(int3, MSG_UBL_HOTEND_TEMP_CUSTOM, &custom_hotend_temp, EXTRUDE_MINTEMP, (HEATER_0_MAXTEMP - 10));
+ #if HAS_HEATED_BED
+ MENU_ITEM_EDIT(int3, MSG_UBL_BED_TEMP_CUSTOM, &custom_bed_temp, BED_MINTEMP, (BED_MAXTEMP - 15));
+ #endif
+ MENU_ITEM(function, MSG_UBL_BUILD_CUSTOM_MESH, _lcd_ubl_build_custom_mesh);
+ END_MENU();
+}
+
+/**
+ * UBL Adjust Mesh Height Command
+ */
+void _lcd_ubl_adjust_height_cmd() {
+ char UBL_LCD_GCODE[16];
+ const int ind = ubl_height_amount > 0 ? 9 : 10;
+ strcpy_P(UBL_LCD_GCODE, PSTR("G29 P6 C -"));
+ sprintf_P(&UBL_LCD_GCODE[ind], PSTR(".%i"), ABS(ubl_height_amount));
+ lcd_enqueue_command(UBL_LCD_GCODE);
+}
+
+/**
+ * UBL Adjust Mesh Height submenu
+ *
+ * << Edit Mesh
+ * Height Amount: ---
+ * Adjust Mesh Height
+ * << Info Screen
+ */
+void _menu_ubl_height_adjust() {
+ START_MENU();
+ MENU_BACK(MSG_UBL_EDIT_MESH_MENU);
+ MENU_ITEM_EDIT_CALLBACK(int3, MSG_UBL_MESH_HEIGHT_AMOUNT, &ubl_height_amount, -9, 9, _lcd_ubl_adjust_height_cmd);
+ MENU_ITEM(function, MSG_WATCH, lcd_return_to_status);
+ END_MENU();
+}
+
+/**
+ * UBL Edit Mesh submenu
+ *
+ * << UBL Tools
+ * Fine Tune All
+ * Fine Tune Closest
+ * - Adjust Mesh Height >>
+ * << Info Screen
+ */
+void _lcd_ubl_edit_mesh() {
+ START_MENU();
+ MENU_BACK(MSG_UBL_TOOLS);
+ MENU_ITEM(gcode, MSG_UBL_FINE_TUNE_ALL, PSTR("G29 P4 R999 T"));
+ MENU_ITEM(gcode, MSG_UBL_FINE_TUNE_CLOSEST, PSTR("G29 P4 T"));
+ MENU_ITEM(submenu, MSG_UBL_MESH_HEIGHT_ADJUST, _menu_ubl_height_adjust);
+ MENU_ITEM(function, MSG_WATCH, lcd_return_to_status);
+ END_MENU();
+}
+
+/**
+ * UBL Validate Custom Mesh Command
+ */
+void _lcd_ubl_validate_custom_mesh() {
+ char UBL_LCD_GCODE[24];
+ const int temp =
+ #if HAS_HEATED_BED
+ custom_bed_temp
+ #else
+ 0
+ #endif
+ ;
+ sprintf_P(UBL_LCD_GCODE, PSTR("G26 C B%i H%i P"), temp, custom_hotend_temp);
+ lcd_enqueue_commands_P(PSTR("G28"));
+ lcd_enqueue_command(UBL_LCD_GCODE);
+}
+
+/**
+ * UBL Validate Mesh submenu
+ *
+ * << UBL Tools
+ * Mesh Validation with Material 1
+ * Mesh Validation with Material 2
+ * Validate Custom Mesh
+ * << Info Screen
+ */
+void _lcd_ubl_validate_mesh() {
+ START_MENU();
+ MENU_BACK(MSG_UBL_TOOLS);
+ #if HAS_HEATED_BED
+ MENU_ITEM(gcode, MSG_UBL_VALIDATE_MESH_M1, PSTR("G28\nG26 C B" STRINGIFY(PREHEAT_1_TEMP_BED) " H" STRINGIFY(PREHEAT_1_TEMP_HOTEND) " P"));
+ MENU_ITEM(gcode, MSG_UBL_VALIDATE_MESH_M2, PSTR("G28\nG26 C B" STRINGIFY(PREHEAT_2_TEMP_BED) " H" STRINGIFY(PREHEAT_2_TEMP_HOTEND) " P"));
+ #else
+ MENU_ITEM(gcode, MSG_UBL_VALIDATE_MESH_M1, PSTR("G28\nG26 C B0 H" STRINGIFY(PREHEAT_1_TEMP_HOTEND) " P"));
+ MENU_ITEM(gcode, MSG_UBL_VALIDATE_MESH_M2, PSTR("G28\nG26 C B0 H" STRINGIFY(PREHEAT_2_TEMP_HOTEND) " P"));
+ #endif
+ MENU_ITEM(function, MSG_UBL_VALIDATE_CUSTOM_MESH, _lcd_ubl_validate_custom_mesh);
+ MENU_ITEM(function, MSG_WATCH, lcd_return_to_status);
+ END_MENU();
+}
+
+/**
+ * UBL Grid Leveling Command
+ */
+void _lcd_ubl_grid_level_cmd() {
+ char UBL_LCD_GCODE[10];
+ sprintf_P(UBL_LCD_GCODE, PSTR("G29 J%i"), side_points);
+ lcd_enqueue_command(UBL_LCD_GCODE);
+}
+
+/**
+ * UBL Grid Leveling submenu
+ *
+ * << UBL Tools
+ * Side points: ---
+ * Level Mesh
+ */
+void _lcd_ubl_grid_level() {
+ START_MENU();
+ MENU_BACK(MSG_UBL_TOOLS);
+ MENU_ITEM_EDIT(int3, MSG_UBL_SIDE_POINTS, &side_points, 2, 6);
+ MENU_ITEM(function, MSG_UBL_MESH_LEVEL, _lcd_ubl_grid_level_cmd);
+ END_MENU();
+}
+
+/**
+ * UBL Mesh Leveling submenu
+ *
+ * << UBL Tools
+ * 3-Point Mesh Leveling
+ * - Grid Mesh Leveling >>
+ * << Info Screen
+ */
+void _lcd_ubl_mesh_leveling() {
+ START_MENU();
+ MENU_BACK(MSG_UBL_TOOLS);
+ MENU_ITEM(gcode, MSG_UBL_3POINT_MESH_LEVELING, PSTR("G29 J0"));
+ MENU_ITEM(submenu, MSG_UBL_GRID_MESH_LEVELING, _lcd_ubl_grid_level);
+ MENU_ITEM(function, MSG_WATCH, lcd_return_to_status);
+ END_MENU();
+}
+
+/**
+ * UBL Fill-in Amount Mesh Command
+ */
+void _lcd_ubl_fillin_amount_cmd() {
+ char UBL_LCD_GCODE[16];
+ sprintf_P(UBL_LCD_GCODE, PSTR("G29 P3 R C.%i"), ubl_fillin_amount);
+ lcd_enqueue_command(UBL_LCD_GCODE);
+}
+
+/**
+ * UBL Fill-in Mesh submenu
+ *
+ * << Build Mesh
+ * Fill-in Amount: ---
+ * Fill-in Mesh
+ * Smart Fill-in
+ * Manual Fill-in
+ * << Info Screen
+ */
+void _menu_ubl_fillin() {
+ START_MENU();
+ MENU_BACK(MSG_UBL_BUILD_MESH_MENU);
+ MENU_ITEM_EDIT_CALLBACK(int3, MSG_UBL_FILLIN_AMOUNT, &ubl_fillin_amount, 0, 9, _lcd_ubl_fillin_amount_cmd);
+ MENU_ITEM(gcode, MSG_UBL_SMART_FILLIN, PSTR("G29 P3 T0"));
+ MENU_ITEM(gcode, MSG_UBL_MANUAL_FILLIN, PSTR("G29 P2 B T0"));
+ MENU_ITEM(function, MSG_WATCH, lcd_return_to_status);
+ END_MENU();
+}
+
+void _lcd_ubl_invalidate() {
+ ubl.invalidate();
+ SERIAL_PROTOCOLLNPGM("Mesh invalidated.");
+}
+
+/**
+ * UBL Build Mesh submenu
+ *
+ * << UBL Tools
+ * Build Mesh with Material 1
+ * Build Mesh with Material 2
+ * - Build Custom Mesh >>
+ * Build Cold Mesh
+ * - Fill-in Mesh >>
+ * Continue Bed Mesh
+ * Invalidate All
+ * Invalidate Closest
+ * << Info Screen
+ */
+void _lcd_ubl_build_mesh() {
+ START_MENU();
+ MENU_BACK(MSG_UBL_TOOLS);
+ #if HAS_HEATED_BED
+ MENU_ITEM(gcode, MSG_UBL_BUILD_MESH_M1, PSTR(
+ "G28\n"
+ "M190 S" STRINGIFY(PREHEAT_1_TEMP_BED) "\n"
+ "M109 S" STRINGIFY(PREHEAT_1_TEMP_HOTEND) "\n"
+ "G29 P1\n"
+ "M104 S0\n"
+ "M140 S0"
+ ));
+ MENU_ITEM(gcode, MSG_UBL_BUILD_MESH_M2, PSTR(
+ "G28\n"
+ "M190 S" STRINGIFY(PREHEAT_2_TEMP_BED) "\n"
+ "M109 S" STRINGIFY(PREHEAT_2_TEMP_HOTEND) "\n"
+ "G29 P1\n"
+ "M104 S0\n"
+ "M140 S0"
+ ));
+ #else
+ MENU_ITEM(gcode, MSG_UBL_BUILD_MESH_M1, PSTR(
+ "G28\n"
+ "M109 S" STRINGIFY(PREHEAT_1_TEMP_HOTEND) "\n"
+ "G29 P1\n"
+ "M104 S0"
+ ));
+ MENU_ITEM(gcode, MSG_UBL_BUILD_MESH_M2, PSTR(
+ "G28\n"
+ "M109 S" STRINGIFY(PREHEAT_2_TEMP_HOTEND) "\n"
+ "G29 P1\n"
+ "M104 S0"
+ ));
+ #endif
+ MENU_ITEM(submenu, MSG_UBL_BUILD_CUSTOM_MESH, _lcd_ubl_custom_mesh);
+ MENU_ITEM(gcode, MSG_UBL_BUILD_COLD_MESH, PSTR("G28\nG29 P1"));
+ MENU_ITEM(submenu, MSG_UBL_FILLIN_MESH, _menu_ubl_fillin);
+ MENU_ITEM(gcode, MSG_UBL_CONTINUE_MESH, PSTR("G29 P1 C"));
+ MENU_ITEM(function, MSG_UBL_INVALIDATE_ALL, _lcd_ubl_invalidate);
+ MENU_ITEM(gcode, MSG_UBL_INVALIDATE_CLOSEST, PSTR("G29 I"));
+ MENU_ITEM(function, MSG_WATCH, lcd_return_to_status);
+ END_MENU();
+}
+
+/**
+ * UBL Load Mesh Command
+ */
+void _lcd_ubl_load_mesh_cmd() {
+ char UBL_LCD_GCODE[25];
+ sprintf_P(UBL_LCD_GCODE, PSTR("G29 L%i"), ubl_storage_slot);
+ lcd_enqueue_command(UBL_LCD_GCODE);
+ sprintf_P(UBL_LCD_GCODE, PSTR("M117 " MSG_MESH_LOADED), ubl_storage_slot);
+ lcd_enqueue_command(UBL_LCD_GCODE);
+}
+
+/**
+ * UBL Save Mesh Command
+ */
+void _lcd_ubl_save_mesh_cmd() {
+ char UBL_LCD_GCODE[25];
+ sprintf_P(UBL_LCD_GCODE, PSTR("G29 S%i"), ubl_storage_slot);
+ lcd_enqueue_command(UBL_LCD_GCODE);
+ sprintf_P(UBL_LCD_GCODE, PSTR("M117 " MSG_MESH_SAVED), ubl_storage_slot);
+ lcd_enqueue_command(UBL_LCD_GCODE);
+}
+
+/**
+ * UBL Mesh Storage submenu
+ *
+ * << Unified Bed Leveling
+ * Memory Slot: ---
+ * Load Bed Mesh
+ * Save Bed Mesh
+ */
+void _lcd_ubl_storage_mesh() {
+ int16_t a = settings.calc_num_meshes();
+ START_MENU();
+ MENU_BACK(MSG_UBL_LEVEL_BED);
+ if (!WITHIN(ubl_storage_slot, 0, a - 1)) {
+ STATIC_ITEM(MSG_NO_STORAGE);
+ }
+ else {
+ MENU_ITEM_EDIT(int3, MSG_UBL_STORAGE_SLOT, &ubl_storage_slot, 0, a - 1);
+ MENU_ITEM(function, MSG_UBL_LOAD_MESH, _lcd_ubl_load_mesh_cmd);
+ MENU_ITEM(function, MSG_UBL_SAVE_MESH, _lcd_ubl_save_mesh_cmd);
+ }
+ END_MENU();
+}
+
+/**
+ * UBL LCD "radar" map homing
+ */
+void _lcd_ubl_output_map_lcd();
+
+void _lcd_ubl_map_homing() {
+ defer_return_to_status = true;
+ _lcd_draw_homing();
+ if (all_axes_homed()) {
+ ubl.lcd_map_control = true; // Return to the map screen
+ lcd_goto_screen(_lcd_ubl_output_map_lcd);
+ }
+}
+
+/**
+ * UBL LCD "radar" map point editing
+ */
+void _lcd_ubl_map_lcd_edit_cmd() {
+ char UBL_LCD_GCODE[50], str[10], str2[10];
+ dtostrf(pgm_read_float(&ubl._mesh_index_to_xpos[x_plot]), 0, 2, str);
+ dtostrf(pgm_read_float(&ubl._mesh_index_to_ypos[y_plot]), 0, 2, str2);
+ snprintf_P(UBL_LCD_GCODE, sizeof(UBL_LCD_GCODE), PSTR("G29 P4 X%s Y%s R%i"), str, str2, n_edit_pts);
+ lcd_enqueue_command(UBL_LCD_GCODE);
+}
+
+/**
+ * UBL LCD Map Movement
+ */
+void ubl_map_move_to_xy() {
+ current_position[X_AXIS] = pgm_read_float(&ubl._mesh_index_to_xpos[x_plot]);
+ current_position[Y_AXIS] = pgm_read_float(&ubl._mesh_index_to_ypos[y_plot]);
+ planner.buffer_line(current_position, MMM_TO_MMS(XY_PROBE_SPEED), active_extruder);
+}
+
+/**
+ * UBL LCD "radar" map
+ */
+void set_current_from_steppers_for_axis(const AxisEnum axis);
+void sync_plan_position();
+
+void _lcd_do_nothing() {}
+void _lcd_hard_stop() {
+ const screenFunc_t old_screen = currentScreen;
+ currentScreen = _lcd_do_nothing;
+ planner.quick_stop();
+ currentScreen = old_screen;
+ set_current_from_steppers_for_axis(ALL_AXES);
+ sync_plan_position();
+}
+
+void _lcd_ubl_output_map_lcd() {
+ static int16_t step_scaler = 0;
+
+ if (use_click()) return _lcd_ubl_map_lcd_edit_cmd();
+ ENCODER_DIRECTION_NORMAL();
+
+ if (encoderPosition) {
+ step_scaler += (int32_t)encoderPosition;
+ x_plot += step_scaler / (ENCODER_STEPS_PER_MENU_ITEM);
+ if (ABS(step_scaler) >= ENCODER_STEPS_PER_MENU_ITEM) step_scaler = 0;
+ encoderPosition = 0;
+ lcdDrawUpdate = LCDVIEW_REDRAW_NOW;
+ }
+
+ // Encoder to the right (++)
+ if (x_plot >= GRID_MAX_POINTS_X) { x_plot = 0; y_plot++; }
+ if (y_plot >= GRID_MAX_POINTS_Y) y_plot = 0;
+
+ // Encoder to the left (--)
+ if (x_plot <= GRID_MAX_POINTS_X - (GRID_MAX_POINTS_X + 1)) { x_plot = GRID_MAX_POINTS_X - 1; y_plot--; }
+ if (y_plot <= GRID_MAX_POINTS_Y - (GRID_MAX_POINTS_Y + 1)) y_plot = GRID_MAX_POINTS_Y - 1;
+
+ // Prevent underrun/overrun of plot numbers
+ x_plot = constrain(x_plot, GRID_MAX_POINTS_X - (GRID_MAX_POINTS_X + 1), GRID_MAX_POINTS_X + 1);
+ y_plot = constrain(y_plot, GRID_MAX_POINTS_Y - (GRID_MAX_POINTS_Y + 1), GRID_MAX_POINTS_Y + 1);
+
+ // Determine number of points to edit
+ #if IS_KINEMATIC
+ n_edit_pts = 9; //TODO: Delta accessible edit points
+ #else
+ const bool xc = WITHIN(x_plot, 1, GRID_MAX_POINTS_X - 2),
+ yc = WITHIN(y_plot, 1, GRID_MAX_POINTS_Y - 2);
+ n_edit_pts = yc ? (xc ? 9 : 6) : (xc ? 6 : 4); // Corners
+ #endif
+
+ if (lcdDrawUpdate) {
+ lcd_implementation_ubl_plot(x_plot, y_plot);
+
+ if (planner.movesplanned()) // If the nozzle is already moving, cancel the move.
+ _lcd_hard_stop();
+
+ ubl_map_move_to_xy(); // Move to new location
+ }
+}
+
+/**
+ * UBL Homing before LCD map
+ */
+void _lcd_ubl_output_map_lcd_cmd() {
+ if (!all_axes_known()) {
+ axis_homed = 0;
+ enqueue_and_echo_commands_P(PSTR("G28"));
+ }
+ lcd_goto_screen(_lcd_ubl_map_homing);
+}
+
+/**
+ * UBL Output map submenu
+ *
+ * << Unified Bed Leveling
+ * Output for Host
+ * Output for CSV
+ * Off Printer Backup
+ * Output Mesh Map
+ */
+void _lcd_ubl_output_map() {
+ START_MENU();
+ MENU_BACK(MSG_UBL_LEVEL_BED);
+ MENU_ITEM(gcode, MSG_UBL_OUTPUT_MAP_HOST, PSTR("G29 T0"));
+ MENU_ITEM(gcode, MSG_UBL_OUTPUT_MAP_CSV, PSTR("G29 T1"));
+ MENU_ITEM(gcode, MSG_UBL_OUTPUT_MAP_BACKUP, PSTR("G29 S-1"));
+ MENU_ITEM(function, MSG_UBL_OUTPUT_MAP, _lcd_ubl_output_map_lcd_cmd);
+ END_MENU();
+}
+
+/**
+ * UBL Tools submenu
+ *
+ * << Unified Bed Leveling
+ * - Build Mesh >>
+ * - Validate Mesh >>
+ * - Edit Mesh >>
+ * - Mesh Leveling >>
+ */
+void _menu_ubl_tools() {
+ START_MENU();
+ MENU_BACK(MSG_UBL_LEVEL_BED);
+ MENU_ITEM(submenu, MSG_UBL_BUILD_MESH_MENU, _lcd_ubl_build_mesh);
+ MENU_ITEM(gcode, MSG_UBL_MANUAL_MESH, PSTR("G29 I999\nG29 P2 B T0"));
+ MENU_ITEM(submenu, MSG_UBL_VALIDATE_MESH_MENU, _lcd_ubl_validate_mesh);
+ MENU_ITEM(submenu, MSG_UBL_EDIT_MESH_MENU, _lcd_ubl_edit_mesh);
+ MENU_ITEM(submenu, MSG_UBL_MESH_LEVELING, _lcd_ubl_mesh_leveling);
+ END_MENU();
+}
+
+/**
+ * UBL Step-By-Step submenu
+ *
+ * << Unified Bed Leveling
+ * 1 Build Cold Mesh
+ * 2 Smart Fill-in
+ * - 3 Validate Mesh >>
+ * 4 Fine Tune All
+ * - 5 Validate Mesh >>
+ * 6 Fine Tune All
+ * 7 Save Bed Mesh
+ */
+void _lcd_ubl_step_by_step() {
+ START_MENU();
+ MENU_BACK(MSG_UBL_LEVEL_BED);
+ MENU_ITEM(gcode, "1 " MSG_UBL_BUILD_COLD_MESH, PSTR("G28\nG29 P1"));
+ MENU_ITEM(gcode, "2 " MSG_UBL_SMART_FILLIN, PSTR("G29 P3 T0"));
+ MENU_ITEM(submenu, "3 " MSG_UBL_VALIDATE_MESH_MENU, _lcd_ubl_validate_mesh);
+ MENU_ITEM(gcode, "4 " MSG_UBL_FINE_TUNE_ALL, PSTR("G29 P4 R999 T"));
+ MENU_ITEM(submenu, "5 " MSG_UBL_VALIDATE_MESH_MENU, _lcd_ubl_validate_mesh);
+ MENU_ITEM(gcode, "6 " MSG_UBL_FINE_TUNE_ALL, PSTR("G29 P4 R999 T"));
+ MENU_ITEM(function, "7 " MSG_UBL_SAVE_MESH, _lcd_ubl_save_mesh_cmd);
+ END_MENU();
+}
+
+/**
+ * UBL System submenu
+ *
+ * << Motion
+ * - Manually Build Mesh >>
+ * - Activate UBL >>
+ * - Deactivate UBL >>
+ * - Step-By-Step UBL >>
+ * - Mesh Storage >>
+ * - Output Map >>
+ * - UBL Tools >>
+ * - Output UBL Info >>
+ */
+
+void _lcd_ubl_level_bed() {
+ START_MENU();
+ MENU_BACK(MSG_MOTION);
+ MENU_ITEM(gcode, MSG_UBL_ACTIVATE_MESH, PSTR("G29 A"));
+ MENU_ITEM(gcode, MSG_UBL_DEACTIVATE_MESH, PSTR("G29 D"));
+ MENU_ITEM(submenu, MSG_UBL_STEP_BY_STEP_MENU, _lcd_ubl_step_by_step);
+ MENU_ITEM(function, MSG_UBL_MESH_EDIT, _lcd_ubl_output_map_lcd_cmd);
+ MENU_ITEM(submenu, MSG_UBL_STORAGE_MESH_MENU, _lcd_ubl_storage_mesh);
+ MENU_ITEM(submenu, MSG_UBL_OUTPUT_MAP, _lcd_ubl_output_map);
+ MENU_ITEM(submenu, MSG_UBL_TOOLS, _menu_ubl_tools);
+ MENU_ITEM(gcode, MSG_UBL_INFO_UBL, PSTR("G29 W"));
+ #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
+ MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float3, MSG_Z_FADE_HEIGHT, &lcd_z_fade_height, 0, 100, _lcd_set_z_fade_height);
+ #endif
+ END_MENU();
+}
+
+#endif // HAS_LCD_MENU && AUTO_BED_LEVELING_UBL
diff --git a/Marlin/src/lcd/ultralcd.cpp b/Marlin/src/lcd/ultralcd.cpp
index a55e179465..6d67683bcb 100644
--- a/Marlin/src/lcd/ultralcd.cpp
+++ b/Marlin/src/lcd/ultralcd.cpp
@@ -27,6 +27,7 @@
#include
#include "ultralcd.h"
+#include "lcdprint.h"
#include "../sd/cardreader.h"
#include "../module/temperature.h"
@@ -40,7 +41,6 @@
#include "../module/configuration_store.h"
#include "../module/tool_change.h"
-
#include "../Marlin.h"
#if ENABLED(ADVANCED_PAUSE_FEATURE)
@@ -49,6 +49,9 @@
#if ENABLED(POWER_LOSS_RECOVERY)
#include "../feature/power_loss_recovery.h"
+ #if ENABLED(ULTIPANEL)
+ void menu_job_recovery();
+ #endif
#endif
#if ENABLED(PRINTCOUNTER) && ENABLED(LCD_INFO_MENU)
@@ -67,25 +70,24 @@
#include "../feature/bedlevel/bedlevel.h"
#endif
-#if ENABLED(LED_CONTROL_MENU)
- #include "../feature/leds/leds.h"
-#endif
-
-#if ENABLED(FILAMENT_RUNOUT_SENSOR)
- #include "../feature/runout.h"
-#endif
-
#if DISABLED(LCD_USE_I2C_BUZZER)
#include "../libs/buzzer.h"
#endif
+// Buttons
+volatile uint8_t buttons;
+
+#if ENABLED(SDSUPPORT) && PIN_EXISTS(SD_DETECT)
+ uint8_t lcd_sd_status;
+#endif
+
#if ENABLED(STATUS_MESSAGE_SCROLLING)
+ uint8_t status_scroll_offset = 0;
#if LONG_FILENAME_LENGTH > CHARSIZE * 2 * (LCD_WIDTH)
#define MAX_MESSAGE_LENGTH LONG_FILENAME_LENGTH
#else
#define MAX_MESSAGE_LENGTH CHARSIZE * 2 * (LCD_WIDTH)
#endif
- uint8_t status_scroll_offset = 0;
#else
#define MAX_MESSAGE_LENGTH CHARSIZE * (LCD_WIDTH)
#endif
@@ -98,5238 +100,48 @@ uint8_t lcd_status_update_delay = 1, // First update one loop delayed
millis_t previous_lcd_status_ms = 0;
#endif
-#if ENABLED(ULTIPANEL) && ENABLED(SCROLL_LONG_FILENAMES)
- uint8_t filename_scroll_pos, filename_scroll_max, filename_scroll_hash;
+#if ENABLED(SDSUPPORT) && ENABLED(ULTIPANEL) && ENABLED(SCROLL_LONG_FILENAMES)
+ uint8_t filename_scroll_pos, filename_scroll_max;
#endif
#if ENABLED(LCD_SET_PROGRESS_MANUALLY)
uint8_t progress_bar_percent;
#endif
-#if ENABLED(DOGLCD)
- #include "ultralcd_impl_DOGM.h"
+millis_t next_button_update_ms;
+
+#if HAS_GRAPHICAL_LCD
bool drawing_screen, first_page; // = false
-#else
- #include "ultralcd_impl_HD44780.h"
- constexpr bool first_page = true;
#endif
-// The main status screen
+#if ENABLED(ENCODER_RATE_MULTIPLIER)
+ bool encoderRateMultiplierEnabled;
+#endif
+
+#if ENABLED(REVERSE_MENU_DIRECTION)
+ int8_t encoderDirection = 1;
+#endif
+
void lcd_status_screen();
-LCDViewAction lcdDrawUpdate = LCDVIEW_CLEAR_CALL_REDRAW;
-uint16_t max_display_update_time = 0;
-millis_t next_lcd_update_ms;
+#if HAS_LCD_MENU
+ #include "menu/menu.h"
-#if HAS_LCD_CONTRAST
- void set_lcd_contrast(const int16_t value) {
- lcd_contrast = constrain(value, LCD_CONTRAST_MIN, LCD_CONTRAST_MAX);
- u8g.setContrast(lcd_contrast);
- }
-#endif
+ screenFunc_t currentScreen = lcd_status_screen;
-#if ENABLED(ULTIPANEL)
-
- #define DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(_type, _name, _strFunc) \
- inline void lcd_implementation_drawmenu_setting_edit_ ## _name (const bool sel, const uint8_t row, PGM_P pstr, PGM_P pstr2, _type * const data, ...) { \
- UNUSED(pstr2); \
- DRAWMENU_SETTING_EDIT_GENERIC(_strFunc(*(data))); \
- } \
- inline void lcd_implementation_drawmenu_setting_edit_callback_ ## _name (const bool sel, const uint8_t row, PGM_P pstr, PGM_P pstr2, _type * const data, ...) { \
- UNUSED(pstr2); \
- DRAWMENU_SETTING_EDIT_GENERIC(_strFunc(*(data))); \
- } \
- inline void lcd_implementation_drawmenu_setting_edit_accessor_ ## _name (const bool sel, const uint8_t row, PGM_P pstr, PGM_P pstr2, _type (*pget)(), void (*pset)(_type), ...) { \
- UNUSED(pstr2); UNUSED(pset); \
- DRAWMENU_SETTING_EDIT_GENERIC(_strFunc(pget())); \
- } \
- typedef void _name##_void
- DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(int16_t, int3, itostr3);
- DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(int16_t, int4, itostr4sign);
- DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(uint8_t, int8, i8tostr3);
- DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(float, float3, ftostr3);
- DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(float, float52, ftostr52);
- DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(float, float43, ftostr43sign);
- DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(float, float5, ftostr5rj);
- DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(float, float51, ftostr51sign);
- DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(float, float52sign, ftostr52sign);
- DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(float, float62, ftostr62rj);
- DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(uint32_t, long5, ftostr5rj);
- #define lcd_implementation_drawmenu_setting_edit_bool(sel, row, pstr, pstr2, data) DRAW_BOOL_SETTING(sel, row, pstr, data)
- #define lcd_implementation_drawmenu_setting_edit_callback_bool(sel, row, pstr, pstr2, data, callback) DRAW_BOOL_SETTING(sel, row, pstr, data)
- #define lcd_implementation_drawmenu_setting_edit_accessor_bool(sel, row, pstr, pstr2, pget, pset) DRAW_BOOL_SETTING(sel, row, pstr, data)
-
- #ifndef TALL_FONT_CORRECTION
- #define TALL_FONT_CORRECTION 0
- #endif
-
- bool no_reentry = false;
- constexpr int8_t menu_bottom = LCD_HEIGHT - (TALL_FONT_CORRECTION);
-
- // Initialized by settings.load()
- int16_t lcd_preheat_hotend_temp[2], lcd_preheat_bed_temp[2];
- uint8_t lcd_preheat_fan_speed[2];
-
- #if ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(G26_MESH_VALIDATION)
- bool lcd_external_control; // = false
- #endif
-
- #if ENABLED(BABYSTEPPING)
- long babysteps_done = 0;
- #if ENABLED(BABYSTEP_ZPROBE_OFFSET)
- static void lcd_babystep_zoffset();
- #else
- static void lcd_babystep_z();
- #endif
- #endif
-
- #if ENABLED(DAC_STEPPER_CURRENT)
- #include "../feature/dac/stepper_dac.h" //was dac_mcp4728.h MarlinMain uses stepper dac for the m-codes
- uint8_t driverPercent[XYZE];
- #endif
-
- ////////////////////////////////////////////
- ///////////////// Menu Tree ////////////////
- ////////////////////////////////////////////
-
- void lcd_main_menu();
- void lcd_tune_menu();
- void lcd_movement_menu();
- void lcd_move_menu();
- void lcd_configuration_menu();
- void lcd_temperature_menu();
- void lcd_advanced_settings_menu();
-
- #if DISABLED(SLIM_LCD_MENUS)
- void lcd_configuration_temperature_preheat_material1_settings_menu();
- void lcd_configuration_temperature_preheat_material2_settings_menu();
- #endif
-
- #if DISABLED(NO_VOLUMETRICS) || ENABLED(ADVANCED_PAUSE_FEATURE)
- void lcd_advanced_filament_menu();
- #endif
-
- #if ENABLED(LCD_INFO_MENU)
- #if ENABLED(PRINTCOUNTER)
- void lcd_info_stats_menu();
- #endif
- void lcd_info_thermistors_menu();
- void lcd_info_board_menu();
- void lcd_info_menu();
- #endif // LCD_INFO_MENU
-
- #if ENABLED(LED_CONTROL_MENU)
- void lcd_led_menu();
- #endif
-
- #if ENABLED(ADVANCED_PAUSE_FEATURE)
- #if E_STEPPERS > 1 || ENABLED(FILAMENT_LOAD_UNLOAD_GCODES)
- void lcd_change_filament_menu();
- #else
- void lcd_temp_menu_e0_filament_change();
- #endif
- #endif
-
- #if ENABLED(DAC_STEPPER_CURRENT)
- void dac_driver_commit();
- void dac_driver_getValues();
- void lcd_dac_menu();
- void lcd_dac_write_eeprom();
- #endif
-
- #if ENABLED(FWRETRACT)
- #include "../feature/fwretract.h"
- void lcd_config_retract_menu();
- #endif
-
- #if ENABLED(DELTA_CALIBRATION_MENU) || ENABLED(DELTA_AUTO_CALIBRATION)
- void lcd_delta_calibrate_menu();
- #endif
-
- #if ENABLED(MESH_BED_LEVELING) && ENABLED(LCD_BED_LEVELING)
- #include "../feature/bedlevel/mbl/mesh_bed_leveling.h"
- #endif
-
- #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
- static float new_z_fade_height;
- void _lcd_set_z_fade_height() { set_z_fade_height(new_z_fade_height); }
- #endif
-
- ////////////////////////////////////////////
- //////////// Menu System Actions ///////////
- ////////////////////////////////////////////
-
- #define menu_action_back(dummy) _menu_action_back()
- void _menu_action_back();
- void menu_action_submenu(screenFunc_t data);
- void menu_action_gcode(PGM_P pgcode);
- void menu_action_function(menuAction_t data);
-
- #define DECLARE_MENU_EDIT_TYPE(_type, _name) \
- bool _menu_edit_ ## _name(); \
- void menu_edit_ ## _name(); \
- void menu_edit_callback_ ## _name(); \
- void _menu_action_setting_edit_ ## _name(PGM_P const pstr, _type* const ptr, const _type minValue, const _type maxValue); \
- void menu_action_setting_edit_ ## _name(PGM_P const pstr, _type * const ptr, const _type minValue, const _type maxValue); \
- void menu_action_setting_edit_callback_ ## _name(PGM_P const pstr, _type * const ptr, const _type minValue, const _type maxValue, const screenFunc_t callback=NULL, const bool live=false); \
- typedef void _name##_void
-
- DECLARE_MENU_EDIT_TYPE(int16_t, int3);
- DECLARE_MENU_EDIT_TYPE(int16_t, int4);
- DECLARE_MENU_EDIT_TYPE(uint8_t, int8);
- DECLARE_MENU_EDIT_TYPE(float, float3);
- DECLARE_MENU_EDIT_TYPE(float, float52);
- DECLARE_MENU_EDIT_TYPE(float, float43);
- DECLARE_MENU_EDIT_TYPE(float, float5);
- DECLARE_MENU_EDIT_TYPE(float, float51);
- DECLARE_MENU_EDIT_TYPE(float, float52sign);
- DECLARE_MENU_EDIT_TYPE(float, float62);
- DECLARE_MENU_EDIT_TYPE(uint32_t, long5);
-
- void menu_action_setting_edit_bool(PGM_P pstr, bool* ptr);
- void menu_action_setting_edit_callback_bool(PGM_P pstr, bool* ptr, screenFunc_t callbackFunc);
-
- #if ENABLED(SDSUPPORT)
- void lcd_sdcard_menu();
- void menu_action_sdfile(CardReader &theCard);
- void menu_action_sddirectory(CardReader &theCard);
- #endif
-
- ////////////////////////////////////////////
- //////////// Menu System Macros ////////////
- ////////////////////////////////////////////
-
- /**
- * MENU_ITEM generates draw & handler code for a menu item, potentially calling:
- *
- * lcd_implementation_drawmenu_[type](sel, row, label, arg3...)
- * menu_action_[type](arg3...)
- *
- * Examples:
- * MENU_ITEM(back, MSG_WATCH, 0 [dummy parameter] )
- * or
- * MENU_BACK(MSG_WATCH)
- * lcd_implementation_drawmenu_back(sel, row, PSTR(MSG_WATCH))
- * menu_action_back()
- *
- * MENU_ITEM(function, MSG_PAUSE_PRINT, lcd_sdcard_pause)
- * lcd_implementation_drawmenu_function(sel, row, PSTR(MSG_PAUSE_PRINT), lcd_sdcard_pause)
- * menu_action_function(lcd_sdcard_pause)
- *
- * MENU_ITEM_EDIT(int3, MSG_SPEED, &feedrate_percentage, 10, 999)
- * MENU_ITEM(setting_edit_int3, MSG_SPEED, PSTR(MSG_SPEED), &feedrate_percentage, 10, 999)
- * lcd_implementation_drawmenu_setting_edit_int3(sel, row, PSTR(MSG_SPEED), PSTR(MSG_SPEED), &feedrate_percentage, 10, 999)
- * menu_action_setting_edit_int3(PSTR(MSG_SPEED), &feedrate_percentage, 10, 999)
- *
- */
- #define _MENU_ITEM_PART_1(TYPE, ...) \
- if (_menuLineNr == _thisItemNr) { \
- if (encoderLine == _thisItemNr && lcd_clicked) { \
- lcd_clicked = false
-
- #define _MENU_ITEM_PART_2(TYPE, PLABEL, ...) \
- menu_action_ ## TYPE(__VA_ARGS__); \
- if (screen_changed) return; \
- } \
- if (lcdDrawUpdate) \
- lcd_implementation_drawmenu_ ## TYPE(encoderLine == _thisItemNr, _lcdLineNr, PLABEL, ## __VA_ARGS__); \
- } \
- ++_thisItemNr
-
- #define MENU_ITEM_P(TYPE, PLABEL, ...) do { \
- _skipStatic = false; \
- _MENU_ITEM_PART_1(TYPE, ## __VA_ARGS__); \
- _MENU_ITEM_PART_2(TYPE, PLABEL, ## __VA_ARGS__); \
- }while(0)
-
- #define MENU_ITEM(TYPE, LABEL, ...) MENU_ITEM_P(TYPE, PSTR(LABEL), ## __VA_ARGS__)
-
- #define MENU_BACK(LABEL) MENU_ITEM(back, LABEL, 0)
-
- #define MENU_ITEM_ADDON_START(X) \
- if (lcdDrawUpdate && _menuLineNr == _thisItemNr - 1) { \
- SETCURSOR(X, _lcdLineNr)
-
- #define MENU_ITEM_ADDON_END() } (0)
-
- // Used to print static text with no visible cursor.
- // Parameters: label [, bool center [, bool invert [, char *value] ] ]
- #define STATIC_ITEM_P(LABEL, ...) do{ \
- if (_menuLineNr == _thisItemNr) { \
- if (_skipStatic && encoderLine <= _thisItemNr) { \
- encoderPosition += ENCODER_STEPS_PER_MENU_ITEM; \
- ++encoderLine; \
- } \
- if (lcdDrawUpdate) \
- lcd_implementation_drawmenu_static(_lcdLineNr, LABEL, ## __VA_ARGS__); \
- } \
- ++_thisItemNr; } while(0)
-
- #define STATIC_ITEM(LABEL, ...) STATIC_ITEM_P(PSTR(LABEL), ## __VA_ARGS__)
-
- #if ENABLED(ENCODER_RATE_MULTIPLIER)
-
- bool encoderRateMultiplierEnabled;
- #define ENCODER_RATE_MULTIPLY(F) (encoderRateMultiplierEnabled = F)
-
- //#define ENCODER_RATE_MULTIPLIER_DEBUG // If defined, output the encoder steps per second value
-
- /**
- * MENU_MULTIPLIER_ITEM generates drawing and handling code for a multiplier menu item
- */
- #define MENU_MULTIPLIER_ITEM(TYPE, LABEL, ...) do { \
- _MENU_ITEM_PART_1(TYPE, ## __VA_ARGS__); \
- encoderRateMultiplierEnabled = true; \
- lastEncoderMovementMillis = 0; \
- _MENU_ITEM_PART_2(TYPE, PSTR(LABEL), ## __VA_ARGS__); \
- }while(0)
-
- #else // !ENCODER_RATE_MULTIPLIER
- #define ENCODER_RATE_MULTIPLY(F) NOOP
- #endif // !ENCODER_RATE_MULTIPLIER
-
- #define MENU_ITEM_DUMMY() do { _thisItemNr++; }while(0)
- #define MENU_ITEM_EDIT(TYPE, LABEL, ...) MENU_ITEM(_CAT(setting_edit_,TYPE), LABEL, PSTR(LABEL), ## __VA_ARGS__)
- #define MENU_ITEM_EDIT_CALLBACK(TYPE, LABEL, ...) MENU_ITEM(_CAT(setting_edit_callback_,TYPE), LABEL, PSTR(LABEL), ## __VA_ARGS__)
- #if ENABLED(ENCODER_RATE_MULTIPLIER)
- #define MENU_MULTIPLIER_ITEM_EDIT(TYPE, LABEL, ...) MENU_MULTIPLIER_ITEM(_CAT(setting_edit_,TYPE), LABEL, PSTR(LABEL), ## __VA_ARGS__)
- #define MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(TYPE, LABEL, ...) MENU_MULTIPLIER_ITEM(_CAT(setting_edit_callback_,TYPE), LABEL, PSTR(LABEL), ## __VA_ARGS__)
- #else // !ENCODER_RATE_MULTIPLIER
- #define MENU_MULTIPLIER_ITEM_EDIT(TYPE, LABEL, ...) MENU_ITEM(_CAT(setting_edit_,TYPE), LABEL, PSTR(LABEL), ## __VA_ARGS__)
- #define MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(TYPE, LABEL, ...) MENU_ITEM(_CAT(setting_edit_callback_,TYPE), LABEL, PSTR(LABEL), ## __VA_ARGS__)
- #endif // !ENCODER_RATE_MULTIPLIER
-
- #define SCREEN_OR_MENU_LOOP() \
- int8_t _menuLineNr = encoderTopLine, _thisItemNr; \
- for (int8_t _lcdLineNr = 0; _lcdLineNr < menu_bottom; _lcdLineNr++, _menuLineNr++) { \
- _thisItemNr = 0
-
- /**
- * START_SCREEN Opening code for a screen having only static items.
- * Do simplified scrolling of the entire screen.
- *
- * START_MENU Opening code for a screen with menu items.
- * Scroll as-needed to keep the selected line in view.
- */
- #define START_SCREEN() \
- scroll_screen(menu_bottom, false); \
- bool _skipStatic = false; \
- SCREEN_OR_MENU_LOOP()
-
- #define START_MENU() \
- scroll_screen(1, true); \
- bool _skipStatic = true; \
- SCREEN_OR_MENU_LOOP()
-
- #define END_SCREEN() \
- } \
- screen_items = _thisItemNr
-
- #define END_MENU() \
- } \
- screen_items = _thisItemNr; \
- UNUSED(_skipStatic)
-
- ////////////////////////////////////////////
- ///////////// Global Variables /////////////
- ////////////////////////////////////////////
-
- /**
- * REVERSE_MENU_DIRECTION
- *
- * To reverse the menu direction we need a general way to reverse
- * the direction of the encoder everywhere. So encoderDirection is
- * added to allow the encoder to go the other way.
- *
- * This behavior is limited to scrolling Menus and SD card listings,
- * and is disabled in other contexts.
- */
- #if ENABLED(REVERSE_MENU_DIRECTION)
- int8_t encoderDirection = 1;
- #define ENCODER_DIRECTION_NORMAL() (encoderDirection = 1)
- #define ENCODER_DIRECTION_MENUS() (encoderDirection = -1)
- #else
- #define ENCODER_DIRECTION_NORMAL() ;
- #define ENCODER_DIRECTION_MENUS() ;
- #endif
-
- // Encoder Movement
+ // Encoder Handling
volatile int8_t encoderDiff; // Updated in lcd_buttons_update, added to encoderPosition every LCD update
uint32_t encoderPosition;
millis_t lastEncoderMovementMillis = 0;
-
- // Button States
bool lcd_clicked, wait_for_unclick;
- volatile uint8_t buttons;
- millis_t next_button_update_ms;
- #if ENABLED(REPRAPWORLD_KEYPAD)
- volatile uint8_t buttons_reprapworld_keypad;
- #endif
- #if ENABLED(LCD_HAS_SLOW_BUTTONS)
- volatile uint8_t slow_buttons;
- #endif
+ float move_menu_scale;
- // Menu System Navigation
- screenFunc_t currentScreen = lcd_status_screen;
- int8_t encoderTopLine;
- typedef struct {
- screenFunc_t menu_function;
- uint32_t encoder_position;
- } menuPosition;
- menuPosition screen_history[6];
- uint8_t screen_history_depth = 0;
- bool screen_changed, defer_return_to_status;
-
- // Value Editing
- PGM_P editLabel;
- void *editValue;
- int32_t minEditValue, maxEditValue;
- screenFunc_t callbackFunc;
- bool liveEdit;
-
- // Manual Moves
- const float manual_feedrate_mm_m[] = MANUAL_FEEDRATE;
- millis_t manual_move_start_time = 0;
- int8_t manual_move_axis = (int8_t)NO_AXIS;
- #if EXTRUDERS > 1
- int8_t manual_move_e_index = 0;
- #else
- #define manual_move_e_index 0
- #endif
-
- #if ENABLED(MANUAL_E_MOVES_RELATIVE)
- float manual_move_e_origin = 0;
- #endif
-
- #if IS_KINEMATIC
- bool processing_manual_move = false;
- float manual_move_offset = 0;
- #else
- constexpr bool processing_manual_move = false;
- #endif
-
- #if PIN_EXISTS(SD_DETECT)
- uint8_t lcd_sd_status;
- #endif
-
- #if ENABLED(PIDTEMP)
- float raw_Ki, raw_Kd; // place-holders for Ki and Kd edits
- #endif
-
- inline bool use_click() {
+ bool use_click() {
const bool click = lcd_clicked;
lcd_clicked = false;
return click;
}
-
- inline bool printer_busy() { return planner.movesplanned() || IS_SD_PRINTING(); }
-
- void lcd_move_z();
- float move_menu_scale;
-
- /**
- * General function to go directly to a screen
- */
- void lcd_goto_screen(screenFunc_t screen, const uint32_t encoder/*=0*/) {
- if (currentScreen != screen) {
-
- #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
- // Shadow for editing the fade height
- new_z_fade_height = planner.z_fade_height;
- #endif
-
- #if ENABLED(DOUBLECLICK_FOR_Z_BABYSTEPPING) && ENABLED(BABYSTEPPING)
- static millis_t doubleclick_expire_ms = 0;
- // Going to lcd_main_menu from status screen? Remember first click time.
- // Going back to status screen within a very short time? Go to Z babystepping.
- if (screen == lcd_main_menu) {
- if (currentScreen == lcd_status_screen)
- doubleclick_expire_ms = millis() + DOUBLECLICK_MAX_INTERVAL;
- }
- else if (screen == lcd_status_screen && currentScreen == lcd_main_menu && PENDING(millis(), doubleclick_expire_ms)) {
- if (printer_busy()) {
- screen =
- #if ENABLED(BABYSTEP_ZPROBE_OFFSET)
- lcd_babystep_zoffset
- #else
- lcd_babystep_z
- #endif
- ;
- }
- #if ENABLED(MOVE_Z_WHEN_IDLE)
- else {
- move_menu_scale = MOVE_Z_IDLE_MULTIPLICATOR;
- screen = lcd_move_z;
- }
- #endif
- }
- #endif
-
- currentScreen = screen;
- encoderPosition = encoder;
- if (screen == lcd_status_screen) {
- defer_return_to_status = false;
- #if ENABLED(AUTO_BED_LEVELING_UBL)
- ubl.lcd_map_control = false;
- #endif
- screen_history_depth = 0;
- }
- lcd_implementation_clear();
- // Re-initialize custom characters that may be re-used
- #if DISABLED(DOGLCD) && ENABLED(AUTO_BED_LEVELING_UBL)
- if (!ubl.lcd_map_control) {
- lcd_set_custom_characters(
- #if ENABLED(LCD_PROGRESS_BAR)
- screen == lcd_status_screen ? CHARSET_INFO : CHARSET_MENU
- #endif
- );
- }
- #elif ENABLED(LCD_PROGRESS_BAR)
- lcd_set_custom_characters(screen == lcd_status_screen ? CHARSET_INFO : CHARSET_MENU);
- #endif
- lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NEXT;
- screen_changed = true;
- #if ENABLED(DOGLCD)
- drawing_screen = false;
- #endif
- }
- }
-
- /**
- * Show "Moving..." till moves are done, then revert to previous display.
- */
- static const char moving[] PROGMEM = MSG_MOVING;
- static PGM_P sync_message = moving;
-
- //
- // Display the synchronize screen until moves are
- // finished, and don't return to the caller until
- // done. ** This blocks the command queue! **
- //
- void _lcd_synchronize() {
- if (lcdDrawUpdate) lcd_implementation_drawmenu_static(LCD_HEIGHT >= 4 ? 1 : 0, sync_message);
- if (no_reentry) return;
- // Make this the current handler till all moves are done
- no_reentry = true;
- const screenFunc_t old_screen = currentScreen;
- lcd_goto_screen(_lcd_synchronize);
- planner.synchronize(); // idle() is called until moves complete
- no_reentry = false;
- lcd_goto_screen(old_screen);
- }
-
- // Display the synchronize screen with a custom message
- // ** This blocks the command queue! **
- void lcd_synchronize(PGM_P const msg=NULL) {
- sync_message = msg ? msg : moving;
- _lcd_synchronize();
- }
-
- void lcd_return_to_status() { lcd_goto_screen(lcd_status_screen); }
-
- void lcd_save_previous_screen() {
- if (screen_history_depth < COUNT(screen_history)) {
- screen_history[screen_history_depth].menu_function = currentScreen;
- screen_history[screen_history_depth].encoder_position = encoderPosition;
- ++screen_history_depth;
- }
- }
-
- void lcd_goto_previous_menu() {
- if (screen_history_depth > 0) {
- --screen_history_depth;
- lcd_goto_screen(
- screen_history[screen_history_depth].menu_function,
- screen_history[screen_history_depth].encoder_position
- );
- }
- else
- lcd_return_to_status();
- }
-
- void lcd_goto_previous_menu_no_defer() {
- defer_return_to_status = false;
- lcd_goto_previous_menu();
- }
-
- /**
- * Scrolling for menus and other line-based screens
- *
- * encoderLine is the position based on the encoder
- * encoderTopLine is the top menu line to display
- * _lcdLineNr is the index of the LCD line (e.g., 0-3)
- * _menuLineNr is the menu item to draw and process
- * _thisItemNr is the index of each MENU_ITEM or STATIC_ITEM
- * screen_items is the total number of items in the menu (after one call)
- */
- int8_t encoderLine, screen_items;
- void scroll_screen(const uint8_t limit, const bool is_menu) {
- ENCODER_DIRECTION_MENUS();
- ENCODER_RATE_MULTIPLY(false);
- if (encoderPosition > 0x8000) encoderPosition = 0;
- if (first_page) {
- encoderLine = encoderPosition / (ENCODER_STEPS_PER_MENU_ITEM);
- screen_changed = false;
- }
- if (screen_items > 0 && encoderLine >= screen_items - limit) {
- encoderLine = MAX(0, screen_items - limit);
- encoderPosition = encoderLine * (ENCODER_STEPS_PER_MENU_ITEM);
- }
- if (is_menu) {
- NOMORE(encoderTopLine, encoderLine);
- if (encoderLine >= encoderTopLine + menu_bottom)
- encoderTopLine = encoderLine - menu_bottom + 1;
- }
- else
- encoderTopLine = encoderLine;
- }
-
-#endif // ULTIPANEL
-
-/**
- *
- * "Info Screen"
- *
- * This is very display-dependent, so the lcd implementation draws this.
- */
-
-void lcd_status_screen() {
-
- #if ENABLED(ULTIPANEL)
- ENCODER_DIRECTION_NORMAL();
- ENCODER_RATE_MULTIPLY(false);
- #endif
-
- #if ENABLED(LCD_SET_PROGRESS_MANUALLY) && ENABLED(SDSUPPORT) && (ENABLED(LCD_PROGRESS_BAR) || ENABLED(DOGLCD))
- // Progress bar % comes from SD when actively printing
- if (IS_SD_PRINTING())
- progress_bar_percent = card.percentDone();
- #endif
-
- #if ENABLED(LCD_PROGRESS_BAR)
-
- //
- // HD44780 implements the following message blinking and
- // message expiration because Status Line and Progress Bar
- // share the same line on the display.
- //
-
- millis_t ms = millis();
-
- // If the message will blink rather than expire...
- #if DISABLED(PROGRESS_MSG_ONCE)
- if (ELAPSED(ms, progress_bar_ms + PROGRESS_BAR_MSG_TIME + PROGRESS_BAR_BAR_TIME))
- progress_bar_ms = ms;
- #endif
-
- #if PROGRESS_MSG_EXPIRE > 0
-
- // Handle message expire
- if (expire_status_ms > 0) {
-
- #if DISABLED(LCD_SET_PROGRESS_MANUALLY)
- const uint8_t progress_bar_percent = card.percentDone();
- #endif
-
- // Expire the message if a job is active and the bar has ticks
- if (progress_bar_percent > 2 && !print_job_timer.isPaused()) {
- if (ELAPSED(ms, expire_status_ms)) {
- lcd_status_message[0] = '\0';
- expire_status_ms = 0;
- }
- }
- else {
- // Defer message expiration before bar appears
- // and during any pause (not just SD)
- expire_status_ms += LCD_UPDATE_INTERVAL;
- }
- }
-
- #endif // PROGRESS_MSG_EXPIRE
-
- #endif // LCD_PROGRESS_BAR
-
- #if ENABLED(ULTIPANEL)
-
- if (use_click()) {
- #if ENABLED(FILAMENT_LCD_DISPLAY) && ENABLED(SDSUPPORT)
- previous_lcd_status_ms = millis(); // get status message to show up for a while
- #endif
- lcd_implementation_init( // to maybe revive the LCD if static electricity killed it.
- #if ENABLED(LCD_PROGRESS_BAR)
- CHARSET_MENU
- #endif
- );
- lcd_goto_screen(lcd_main_menu);
- return;
- }
-
- #if ENABLED(ULTIPANEL_FEEDMULTIPLY)
- const int16_t new_frm = feedrate_percentage + (int32_t)encoderPosition;
- // Dead zone at 100% feedrate
- if ((feedrate_percentage < 100 && new_frm > 100) || (feedrate_percentage > 100 && new_frm < 100)) {
- feedrate_percentage = 100;
- encoderPosition = 0;
- }
- else if (feedrate_percentage == 100) {
- if ((int32_t)encoderPosition > ENCODER_FEEDRATE_DEADZONE) {
- feedrate_percentage += (int32_t)encoderPosition - (ENCODER_FEEDRATE_DEADZONE);
- encoderPosition = 0;
- }
- else if ((int32_t)encoderPosition < -(ENCODER_FEEDRATE_DEADZONE)) {
- feedrate_percentage += (int32_t)encoderPosition + ENCODER_FEEDRATE_DEADZONE;
- encoderPosition = 0;
- }
- }
- else {
- feedrate_percentage = new_frm;
- encoderPosition = 0;
- }
- #endif // ULTIPANEL_FEEDMULTIPLY
-
- feedrate_percentage = constrain(feedrate_percentage, 10, 999);
-
- #endif // ULTIPANEL
-
- #if LCD_INFO_SCREEN_STYLE == 0
- lcd_impl_status_screen_0();
- #elif LCD_INFO_SCREEN_STYLE == 1
- lcd_impl_status_screen_1();
- #endif
-}
-
-/**
- * Reset the status message
- */
-void lcd_reset_status() {
- static const char paused[] PROGMEM = MSG_PRINT_PAUSED;
- static const char printing[] PROGMEM = MSG_PRINTING;
- static const char welcome[] PROGMEM = WELCOME_MSG;
- PGM_P msg;
- if (print_job_timer.isPaused())
- msg = paused;
- #if ENABLED(SDSUPPORT)
- else if (card.sdprinting)
- return lcd_setstatus(card.longest_filename(), true);
- #endif
- else if (print_job_timer.isRunning())
- msg = printing;
- else
- msg = welcome;
-
- lcd_setstatusPGM(msg, -1);
-}
-
-/**
- *
- * draw the kill screen
- *
- */
-void kill_screen(PGM_P lcd_msg) {
- lcd_init();
- lcd_setalertstatusPGM(lcd_msg);
- lcd_kill_screen();
-}
-
-/**
- *
- * Audio feedback for controller clicks
- *
- */
-void lcd_buzz(const long duration, const uint16_t freq) {
- #if ENABLED(LCD_USE_I2C_BUZZER)
- lcd.buzz(duration, freq);
- #elif PIN_EXISTS(BEEPER)
- buzzer.tone(duration, freq);
- #else
- UNUSED(duration); UNUSED(freq);
- #endif
-}
-
-void lcd_quick_feedback(const bool clear_buttons) {
-
- #if ENABLED(ULTIPANEL)
- lcd_refresh();
- if (clear_buttons) buttons = 0;
- next_button_update_ms = millis() + 500;
- #else
- UNUSED(clear_buttons);
- #endif
-
- // Buzz and wait. The delay is needed for buttons to settle!
- lcd_buzz(LCD_FEEDBACK_FREQUENCY_DURATION_MS, LCD_FEEDBACK_FREQUENCY_HZ);
-
- #if ENABLED(ULTIPANEL)
- #if ENABLED(LCD_USE_I2C_BUZZER)
- delay(10);
- #elif PIN_EXISTS(BEEPER)
- for (int8_t i = 5; i--;) { buzzer.tick(); delay(2); }
- #endif
- #endif
-}
-
-#if ENABLED(ULTIPANEL)
-
- void lcd_completion_feedback(const bool good/*=true*/) {
- if (good) {
- lcd_buzz(100, 659);
- lcd_buzz(100, 698);
- }
- else lcd_buzz(20, 440);
- }
-
- inline void line_to_current_z() {
- planner.buffer_line(current_position, MMM_TO_MMS(manual_feedrate_mm_m[Z_AXIS]), active_extruder);
- }
-
- inline void line_to_z(const float &z) {
- current_position[Z_AXIS] = z;
- line_to_current_z();
- }
-
- #if ENABLED(SDSUPPORT)
-
- void lcd_sdcard_pause() {
- card.pauseSDPrint();
- print_job_timer.pause();
- #if ENABLED(PARK_HEAD_ON_PAUSE)
- enqueue_and_echo_commands_P(PSTR("M125"));
- #endif
- lcd_reset_status();
- }
-
- void lcd_sdcard_resume() {
- #if ENABLED(PARK_HEAD_ON_PAUSE)
- enqueue_and_echo_commands_P(PSTR("M24"));
- #else
- card.startFileprint();
- print_job_timer.start();
- #endif
- lcd_reset_status();
- }
-
- void lcd_sdcard_stop() {
- wait_for_heatup = wait_for_user = false;
- card.abort_sd_printing = true;
- lcd_setstatusPGM(PSTR(MSG_PRINT_ABORTED), -1);
- lcd_return_to_status();
- }
-
- #endif // SDSUPPORT
-
- #if ENABLED(POWER_LOSS_RECOVERY)
-
- static void lcd_power_loss_recovery_resume() {
- char cmd[20];
-
- // Return to status now
- lcd_return_to_status();
-
- // Turn leveling off and home
- enqueue_and_echo_commands_P(PSTR("M420 S0\nG28 R0"
- #if ENABLED(MARLIN_DEV_MODE)
- " S"
- #elif !IS_KINEMATIC
- " X Y"
- #endif
- ));
-
- #if HAS_HEATED_BED
- const int16_t bt = job_recovery_info.target_temperature_bed;
- if (bt) {
- // Restore the bed temperature
- sprintf_P(cmd, PSTR("M190 S%i"), bt);
- enqueue_and_echo_command(cmd);
- }
- #endif
-
- // Restore all hotend temperatures
- HOTEND_LOOP() {
- const int16_t et = job_recovery_info.target_temperature[e];
- if (et) {
- #if HOTENDS > 1
- sprintf_P(cmd, PSTR("T%i"), e);
- enqueue_and_echo_command(cmd);
- #endif
- sprintf_P(cmd, PSTR("M109 S%i"), et);
- enqueue_and_echo_command(cmd);
- }
- }
-
- #if HOTENDS > 1
- sprintf_P(cmd, PSTR("T%i"), job_recovery_info.active_hotend);
- enqueue_and_echo_command(cmd);
- #endif
-
- // Restore print cooling fan speeds
- for (uint8_t i = 0; i < FAN_COUNT; i++) {
- uint8_t f = job_recovery_info.fan_speed[i];
- if (f) {
- sprintf_P(cmd, PSTR("M106 P%i S%i"), i, f);
- enqueue_and_echo_command(cmd);
- }
- }
-
- // Start draining the job recovery command queue
- job_recovery_phase = JOB_RECOVERY_YES;
- }
-
- static void lcd_power_loss_recovery_cancel() {
- card.removeJobRecoveryFile();
- card.autostart_index = 0;
- lcd_return_to_status();
- }
-
- static void lcd_job_recovery_menu() {
- defer_return_to_status = true;
- START_MENU();
- STATIC_ITEM(MSG_POWER_LOSS_RECOVERY);
- MENU_ITEM(function, MSG_RESUME_PRINT, lcd_power_loss_recovery_resume);
- MENU_ITEM(function, MSG_STOP_PRINT, lcd_power_loss_recovery_cancel);
- END_MENU();
- }
-
- #endif // POWER_LOSS_RECOVERY
-
- #if EXTRUDERS > 1
- void tool_change_menu() {
- START_MENU();
- MENU_BACK(MSG_MAIN);
- #if ENABLED(SINGLENOZZLE)
- MENU_ITEM_EDIT(float3, MSG_FILAMENT_SWAP_LENGTH, &toolchange_settings.swap_length, 0, 200);
- MENU_MULTIPLIER_ITEM_EDIT(int4, MSG_SINGLENOZZLE_RETRACT_SPD, &toolchange_settings.retract_speed, 10, 5400);
- MENU_MULTIPLIER_ITEM_EDIT(int4, MSG_SINGLENOZZLE_PRIME_SPD, &toolchange_settings.prime_speed, 10, 5400);
- #endif
- MENU_ITEM_EDIT(float3, MSG_TOOL_CHANGE_ZLIFT, &toolchange_settings.z_raise, 0, 10);
- END_MENU();
- }
- #endif
-
- #if ENABLED(MENU_ITEM_CASE_LIGHT)
-
- #include "../feature/caselight.h"
-
- void case_light_menu() {
- START_MENU();
- MENU_BACK(MSG_MAIN);
- MENU_ITEM_EDIT_CALLBACK(int8, MSG_CASE_LIGHT_BRIGHTNESS, &case_light_brightness, 0, 255, update_case_light, true);
- MENU_ITEM_EDIT_CALLBACK(bool, MSG_CASE_LIGHT, (bool*)&case_light_on, update_case_light);
- END_MENU();
- }
- #endif // MENU_ITEM_CASE_LIGHT
-
- #if ENABLED(BLTOUCH)
-
- /**
- *
- * "BLTouch" submenu
- *
- */
- static void bltouch_menu() {
- START_MENU();
- MENU_BACK(MSG_MAIN);
- MENU_ITEM(gcode, MSG_BLTOUCH_RESET, PSTR("M280 P" STRINGIFY(Z_PROBE_SERVO_NR) " S" STRINGIFY(BLTOUCH_RESET)));
- MENU_ITEM(gcode, MSG_BLTOUCH_SELFTEST, PSTR("M280 P" STRINGIFY(Z_PROBE_SERVO_NR) " S" STRINGIFY(BLTOUCH_SELFTEST)));
- MENU_ITEM(gcode, MSG_BLTOUCH_DEPLOY, PSTR("M280 P" STRINGIFY(Z_PROBE_SERVO_NR) " S" STRINGIFY(BLTOUCH_DEPLOY)));
- MENU_ITEM(gcode, MSG_BLTOUCH_STOW, PSTR("M280 P" STRINGIFY(Z_PROBE_SERVO_NR) " S" STRINGIFY(BLTOUCH_STOW)));
- END_MENU();
- }
-
- #endif // BLTOUCH
-
- #if ENABLED(LCD_PROGRESS_BAR_TEST)
-
- static void progress_bar_test() {
- static int8_t bar_percent = 0;
- if (use_click()) {
- lcd_goto_previous_menu();
- lcd_set_custom_characters(CHARSET_MENU);
- return;
- }
- bar_percent += (int8_t)encoderPosition;
- bar_percent = constrain(bar_percent, 0, 100);
- encoderPosition = 0;
- lcd_implementation_drawmenu_static(0, PSTR(MSG_PROGRESS_BAR_TEST), true, true);
- lcd_moveto((LCD_WIDTH) / 2 - 2, LCD_HEIGHT - 2);
- lcd_put_u8str(int(bar_percent)); lcd_put_wchar('%');
- lcd_moveto(0, LCD_HEIGHT - 1); lcd_draw_progress_bar(bar_percent);
- }
-
- void _progress_bar_test() {
- lcd_goto_screen(progress_bar_test);
- lcd_set_custom_characters();
- }
-
- #endif // LCD_PROGRESS_BAR_TEST
-
- #if HAS_DEBUG_MENU
-
- void lcd_debug_menu() {
- START_MENU();
-
- MENU_BACK(MSG_MAIN);
-
- #if ENABLED(LCD_PROGRESS_BAR_TEST)
- MENU_ITEM(submenu, MSG_PROGRESS_BAR_TEST, _progress_bar_test);
- #endif
-
- END_MENU();
- }
-
- #endif // HAS_DEBUG_MENU
-
- /**
- * IDEX submenu
- */
- #if ENABLED(DUAL_X_CARRIAGE)
- static void _recalc_IDEX_settings() {
- if (active_extruder) { // For the 2nd extruder re-home so the next tool-change gets the new offsets.
- enqueue_and_echo_commands_P(PSTR("G28")); // In future, we can babystep the 2nd extruder (if active), making homing unnecessary.
- active_extruder = 0;
- }
- }
-
- static void IDEX_menu() {
- START_MENU();
- MENU_BACK(MSG_MAIN);
-
- MENU_ITEM(gcode, MSG_IDEX_MODE_AUTOPARK, PSTR("M605 S1\nG28 X\nG1 X100"));
- const bool need_g28 = !(TEST(axis_known_position, Y_AXIS) && TEST(axis_known_position, Z_AXIS));
- MENU_ITEM(gcode, MSG_IDEX_MODE_DUPLICATE, need_g28
- ? PSTR("M605 S1\nT0\nG28\nM605 S2 X200\nG28 X\nG1 X100") // If Y or Z is not homed, do a full G28 first
- : PSTR("M605 S1\nT0\nM605 S2 X200\nG28 X\nG1 X100")
- );
- //MENU_ITEM(gcode, MSG_IDEX_MODE_SCALED_COPY, need_g28
- // ? PSTR("M605 S1\nT0\nG28\nM605 S2 X200\nG28 X\nG1 X100\nM605 S3 X200") // If Y or Z is not homed, do a full G28 first
- // : PSTR("M605 S1\nT0\nM605 S2 X200\nG28 X\nG1 X100\nM605 S3 X200")
- //);
- MENU_ITEM(gcode, MSG_IDEX_MODE_FULL_CTRL, PSTR("M605 S0\nG28 X"));
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float52, MSG_IDEX_X_OFFSET , &hotend_offset[X_AXIS][1], MIN(X2_HOME_POS, X2_MAX_POS) - 25.0, MAX(X2_HOME_POS, X2_MAX_POS) + 25.0, _recalc_IDEX_settings);
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float52, MSG_IDEX_Y_OFFSET , &hotend_offset[Y_AXIS][1], -10.0, 10.0, _recalc_IDEX_settings);
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float52, MSG_IDEX_Z_OFFSET , &hotend_offset[Z_AXIS][1], -10.0, 10.0, _recalc_IDEX_settings);
- MENU_ITEM(gcode, MSG_IDEX_SAVE_OFFSETS, PSTR("M500"));
- END_MENU();
- }
- #endif // DUAL_X_CARRIAGE
-
- #if ENABLED(CUSTOM_USER_MENUS)
-
- #ifdef USER_SCRIPT_DONE
- #define _DONE_SCRIPT "\n" USER_SCRIPT_DONE
- #else
- #define _DONE_SCRIPT ""
- #endif
-
- void _lcd_user_gcode(PGM_P const cmd) {
- enqueue_and_echo_commands_P(cmd);
- #if ENABLED(USER_SCRIPT_AUDIBLE_FEEDBACK)
- lcd_completion_feedback();
- #endif
- #if ENABLED(USER_SCRIPT_RETURN)
- lcd_return_to_status();
- #endif
- }
-
- #if defined(USER_DESC_1) && defined(USER_GCODE_1)
- void lcd_user_gcode_1() { _lcd_user_gcode(PSTR(USER_GCODE_1 _DONE_SCRIPT)); }
- #endif
- #if defined(USER_DESC_2) && defined(USER_GCODE_2)
- void lcd_user_gcode_2() { _lcd_user_gcode(PSTR(USER_GCODE_2 _DONE_SCRIPT)); }
- #endif
- #if defined(USER_DESC_3) && defined(USER_GCODE_3)
- void lcd_user_gcode_3() { _lcd_user_gcode(PSTR(USER_GCODE_3 _DONE_SCRIPT)); }
- #endif
- #if defined(USER_DESC_4) && defined(USER_GCODE_4)
- void lcd_user_gcode_4() { _lcd_user_gcode(PSTR(USER_GCODE_4 _DONE_SCRIPT)); }
- #endif
- #if defined(USER_DESC_5) && defined(USER_GCODE_5)
- void lcd_user_gcode_5() { _lcd_user_gcode(PSTR(USER_GCODE_5 _DONE_SCRIPT)); }
- #endif
-
- void _lcd_user_menu() {
- START_MENU();
- MENU_BACK(MSG_MAIN);
- #if defined(USER_DESC_1) && defined(USER_GCODE_1)
- MENU_ITEM(function, USER_DESC_1, lcd_user_gcode_1);
- #endif
- #if defined(USER_DESC_2) && defined(USER_GCODE_2)
- MENU_ITEM(function, USER_DESC_2, lcd_user_gcode_2);
- #endif
- #if defined(USER_DESC_3) && defined(USER_GCODE_3)
- MENU_ITEM(function, USER_DESC_3, lcd_user_gcode_3);
- #endif
- #if defined(USER_DESC_4) && defined(USER_GCODE_4)
- MENU_ITEM(function, USER_DESC_4, lcd_user_gcode_4);
- #endif
- #if defined(USER_DESC_5) && defined(USER_GCODE_5)
- MENU_ITEM(function, USER_DESC_5, lcd_user_gcode_5);
- #endif
- END_MENU();
- }
-
- #endif
-
- /**
- *
- * "Main" menu
- *
- */
-
- #if ENABLED(SDSUPPORT) && ENABLED(MENU_ADDAUTOSTART)
-
- void lcd_autostart_sd() { card.beginautostart(); }
-
- #endif
-
- void lcd_main_menu() {
- START_MENU();
- MENU_BACK(MSG_WATCH);
-
- #if ENABLED(SDSUPPORT)
- if (card.cardOK) {
- if (card.isFileOpen()) {
- if (card.sdprinting)
- MENU_ITEM(function, MSG_PAUSE_PRINT, lcd_sdcard_pause);
- else
- MENU_ITEM(function, MSG_RESUME_PRINT, lcd_sdcard_resume);
- MENU_ITEM(function, MSG_STOP_PRINT, lcd_sdcard_stop);
- }
- else {
- MENU_ITEM(submenu, MSG_CARD_MENU, lcd_sdcard_menu);
- #if !PIN_EXISTS(SD_DETECT)
- MENU_ITEM(gcode, MSG_CHANGE_SDCARD, PSTR("M21")); // SD-card changed by user
- #endif
- }
- }
- else {
- MENU_ITEM(submenu, MSG_NO_CARD, lcd_sdcard_menu);
- #if !PIN_EXISTS(SD_DETECT)
- MENU_ITEM(gcode, MSG_INIT_SDCARD, PSTR("M21")); // Manually initialize the SD-card via user interface
- #endif
- }
- #endif // SDSUPPORT
-
- const bool busy = printer_busy();
- if (busy)
- MENU_ITEM(submenu, MSG_TUNE, lcd_tune_menu);
- else {
- MENU_ITEM(submenu, MSG_MOTION, lcd_movement_menu);
- MENU_ITEM(submenu, MSG_TEMPERATURE, lcd_temperature_menu);
- }
-
- MENU_ITEM(submenu, MSG_CONFIGURATION, lcd_configuration_menu);
-
- #if ENABLED(CUSTOM_USER_MENUS)
- MENU_ITEM(submenu, MSG_USER_MENU, _lcd_user_menu);
- #endif
-
- #if ENABLED(ADVANCED_PAUSE_FEATURE)
- #if E_STEPPERS == 1 && DISABLED(FILAMENT_LOAD_UNLOAD_GCODES)
- if (thermalManager.targetHotEnoughToExtrude(active_extruder))
- MENU_ITEM(gcode, MSG_FILAMENTCHANGE, PSTR("M600 B0"));
- else
- MENU_ITEM(submenu, MSG_FILAMENTCHANGE, lcd_temp_menu_e0_filament_change);
- #else
- MENU_ITEM(submenu, MSG_FILAMENTCHANGE, lcd_change_filament_menu);
- #endif
- #endif
-
- #if ENABLED(LCD_INFO_MENU)
- MENU_ITEM(submenu, MSG_INFO_MENU, lcd_info_menu);
- #endif
-
- #if ENABLED(LED_CONTROL_MENU)
- MENU_ITEM(submenu, MSG_LED_CONTROL, lcd_led_menu);
- #endif
-
- //
- // Switch power on/off
- //
- #if HAS_POWER_SWITCH
- if (powersupply_on)
- MENU_ITEM(gcode, MSG_SWITCH_PS_OFF, PSTR("M81"));
- else
- MENU_ITEM(gcode, MSG_SWITCH_PS_ON, PSTR("M80"));
- #endif
-
- //
- // Autostart
- //
- #if ENABLED(SDSUPPORT) && ENABLED(MENU_ADDAUTOSTART)
- if (!busy)
- MENU_ITEM(function, MSG_AUTOSTART, lcd_autostart_sd);
- #endif
-
- END_MENU();
- }
-
- /**
- *
- * "Tune" submenu items
- *
- */
-
- #if ENABLED(BABYSTEP_ZPROBE_GFX_OVERLAY) || ENABLED(MESH_EDIT_GFX_OVERLAY)
-
- void _lcd_zoffset_overlay_gfx(const float zvalue) {
- // Determine whether the user is raising or lowering the nozzle.
- static int8_t dir;
- static float old_zvalue;
- if (zvalue != old_zvalue) {
- dir = zvalue ? zvalue < old_zvalue ? -1 : 1 : 0;
- old_zvalue = zvalue;
- }
-
- #if ENABLED(OVERLAY_GFX_REVERSE)
- const unsigned char *rot_up = ccw_bmp, *rot_down = cw_bmp;
- #else
- const unsigned char *rot_up = cw_bmp, *rot_down = ccw_bmp;
- #endif
-
- #if ENABLED(USE_BIG_EDIT_FONT)
- const int left = 0, right = 45, nozzle = 95;
- #else
- const int left = 5, right = 90, nozzle = 60;
- #endif
-
- // Draw a representation of the nozzle
- if (PAGE_CONTAINS(3, 16)) u8g.drawBitmapP(nozzle + 6, 4 - dir, 2, 12, nozzle_bmp);
- if (PAGE_CONTAINS(20, 20)) u8g.drawBitmapP(nozzle + 0, 20, 3, 1, offset_bedline_bmp);
-
- // Draw cw/ccw indicator and up/down arrows.
- if (PAGE_CONTAINS(47, 62)) {
- u8g.drawBitmapP(left + 0, 47, 3, 16, rot_down);
- u8g.drawBitmapP(right + 0, 47, 3, 16, rot_up);
- u8g.drawBitmapP(right + 20, 48 - dir, 2, 13, up_arrow_bmp);
- u8g.drawBitmapP(left + 20, 49 - dir, 2, 13, down_arrow_bmp);
- }
- }
-
- #endif // BABYSTEP_ZPROBE_GFX_OVERLAY || MESH_EDIT_GFX_OVERLAY
-
- #if ENABLED(BABYSTEPPING)
-
- void _lcd_babystep(const AxisEnum axis, PGM_P msg) {
- if (use_click()) { return lcd_goto_previous_menu_no_defer(); }
- ENCODER_DIRECTION_NORMAL();
- if (encoderPosition) {
- const int16_t babystep_increment = (int32_t)encoderPosition * (BABYSTEP_MULTIPLICATOR);
- encoderPosition = 0;
- lcdDrawUpdate = LCDVIEW_REDRAW_NOW;
- thermalManager.babystep_axis(axis, babystep_increment);
- babysteps_done += babystep_increment;
- }
- if (lcdDrawUpdate)
- lcd_implementation_drawedit(msg, ftostr43sign(planner.steps_to_mm[axis] * babysteps_done));
- }
-
- #if ENABLED(BABYSTEP_XY)
- void _lcd_babystep_x() { _lcd_babystep(X_AXIS, PSTR(MSG_BABYSTEP_X)); }
- void _lcd_babystep_y() { _lcd_babystep(Y_AXIS, PSTR(MSG_BABYSTEP_Y)); }
- void lcd_babystep_x() { lcd_goto_screen(_lcd_babystep_x); babysteps_done = 0; defer_return_to_status = true; }
- void lcd_babystep_y() { lcd_goto_screen(_lcd_babystep_y); babysteps_done = 0; defer_return_to_status = true; }
- #endif
-
- #if ENABLED(BABYSTEP_ZPROBE_OFFSET)
-
- void lcd_babystep_zoffset() {
- if (use_click()) { return lcd_goto_previous_menu_no_defer(); }
- defer_return_to_status = true;
- #if ENABLED(BABYSTEP_HOTEND_Z_OFFSET)
- const bool do_probe = (active_extruder == 0);
- #else
- constexpr bool do_probe = true;
- #endif
- ENCODER_DIRECTION_NORMAL();
- if (encoderPosition) {
- const int16_t babystep_increment = (int32_t)encoderPosition * (BABYSTEP_MULTIPLICATOR);
- encoderPosition = 0;
-
- const float diff = planner.steps_to_mm[Z_AXIS] * babystep_increment,
- new_probe_offset = zprobe_zoffset + diff,
- new_offs =
- #if ENABLED(BABYSTEP_HOTEND_Z_OFFSET)
- do_probe ? new_probe_offset : hotend_offset[Z_AXIS][active_extruder] - diff
- #else
- new_probe_offset
- #endif
- ;
- if (WITHIN(new_offs, Z_PROBE_OFFSET_RANGE_MIN, Z_PROBE_OFFSET_RANGE_MAX)) {
-
- thermalManager.babystep_axis(Z_AXIS, babystep_increment);
-
- if (do_probe) zprobe_zoffset = new_offs;
- #if ENABLED(BABYSTEP_HOTEND_Z_OFFSET)
- else hotend_offset[Z_AXIS][active_extruder] = new_offs;
- #endif
-
- lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NEXT;
- }
- }
- if (lcdDrawUpdate) {
- #if ENABLED(BABYSTEP_HOTEND_Z_OFFSET)
- if (!do_probe)
- lcd_implementation_drawedit(PSTR(MSG_IDEX_Z_OFFSET), ftostr43sign(hotend_offset[Z_AXIS][active_extruder]));
- else
- #endif
- lcd_implementation_drawedit(PSTR(MSG_ZPROBE_ZOFFSET), ftostr43sign(zprobe_zoffset));
-
- #if ENABLED(BABYSTEP_ZPROBE_GFX_OVERLAY)
- if (do_probe) _lcd_zoffset_overlay_gfx(zprobe_zoffset);
- #endif
- }
- }
-
- #else // !BABYSTEP_ZPROBE_OFFSET
-
- void _lcd_babystep_z() { _lcd_babystep(Z_AXIS, PSTR(MSG_BABYSTEP_Z)); }
- void lcd_babystep_z() { lcd_goto_screen(_lcd_babystep_z); babysteps_done = 0; defer_return_to_status = true; }
-
- #endif // !BABYSTEP_ZPROBE_OFFSET
-
- #endif // BABYSTEPPING
-
- #if ENABLED(AUTO_BED_LEVELING_UBL)
-
- float mesh_edit_value, mesh_edit_accumulator; // We round mesh_edit_value to 2.5 decimal places. So we keep a
- // separate value that doesn't lose precision.
- static int16_t ubl_encoderPosition = 0;
-
- static void _lcd_mesh_fine_tune(PGM_P msg) {
- defer_return_to_status = true;
- if (ubl.encoder_diff) {
- ubl_encoderPosition = (ubl.encoder_diff > 0) ? 1 : -1;
- ubl.encoder_diff = 0;
-
- mesh_edit_accumulator += float(ubl_encoderPosition) * 0.005f * 0.5f;
- mesh_edit_value = mesh_edit_accumulator;
- encoderPosition = 0;
- lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NEXT;
-
- const int32_t rounded = (int32_t)(mesh_edit_value * 1000);
- mesh_edit_value = float(rounded - (rounded % 5L)) / 1000;
- }
-
- if (lcdDrawUpdate) {
- lcd_implementation_drawedit(msg, ftostr43sign(mesh_edit_value));
- #if ENABLED(MESH_EDIT_GFX_OVERLAY)
- _lcd_zoffset_overlay_gfx(mesh_edit_value);
- #endif
- }
- }
-
- void _lcd_mesh_edit_NOP() {
- defer_return_to_status = true;
- }
-
- float lcd_mesh_edit() {
- lcd_goto_screen(_lcd_mesh_edit_NOP);
- lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NEXT;
- _lcd_mesh_fine_tune(PSTR("Mesh Editor"));
- return mesh_edit_value;
- }
-
- void lcd_mesh_edit_setup(const float &initial) {
- mesh_edit_value = mesh_edit_accumulator = initial;
- lcd_goto_screen(_lcd_mesh_edit_NOP);
- }
-
- void _lcd_z_offset_edit() {
- _lcd_mesh_fine_tune(PSTR("Z-Offset: "));
- }
-
- float lcd_z_offset_edit() {
- lcd_goto_screen(_lcd_z_offset_edit);
- return mesh_edit_value;
- }
-
- void lcd_z_offset_edit_setup(const float &initial) {
- mesh_edit_value = mesh_edit_accumulator = initial;
- lcd_goto_screen(_lcd_z_offset_edit);
- }
-
- #endif // AUTO_BED_LEVELING_UBL
-
-
- /**
- * Watch temperature callbacks
- */
- #if HAS_TEMP_HOTEND
- #if WATCH_HOTENDS
- #define _WATCH_FUNC(N) thermalManager.start_watching_heater(N)
- #else
- #define _WATCH_FUNC(N) NOOP
- #endif
- void watch_temp_callback_E0() { _WATCH_FUNC(0); }
- #if HOTENDS > 1
- void watch_temp_callback_E1() { _WATCH_FUNC(1); }
- #if HOTENDS > 2
- void watch_temp_callback_E2() { _WATCH_FUNC(2); }
- #if HOTENDS > 3
- void watch_temp_callback_E3() { _WATCH_FUNC(3); }
- #if HOTENDS > 4
- void watch_temp_callback_E4() { _WATCH_FUNC(4); }
- #if HOTENDS > 5
- void watch_temp_callback_E5() { _WATCH_FUNC(5); }
- #endif // HOTENDS > 5
- #endif // HOTENDS > 4
- #endif // HOTENDS > 3
- #endif // HOTENDS > 2
- #endif // HOTENDS > 1
- #endif // HAS_TEMP_HOTEND
-
- void watch_temp_callback_bed() {
- #if WATCH_THE_BED
- thermalManager.start_watching_bed();
- #endif
- }
-
- // First Fan Speed title in "Tune" and "Control>Temperature" menus
- #if FAN_COUNT > 0 && HAS_FAN0
- #if FAN_COUNT > 1
- #define FAN_SPEED_1_SUFFIX " 1"
- #else
- #define FAN_SPEED_1_SUFFIX ""
- #endif
- #endif
-
- // Refresh the E factor after changing flow
- inline void _lcd_refresh_e_factor_0() { planner.refresh_e_factor(0); }
- #if EXTRUDERS > 1
- inline void _lcd_refresh_e_factor() { planner.refresh_e_factor(active_extruder); }
- inline void _lcd_refresh_e_factor_1() { planner.refresh_e_factor(1); }
- #if EXTRUDERS > 2
- inline void _lcd_refresh_e_factor_2() { planner.refresh_e_factor(2); }
- #if EXTRUDERS > 3
- inline void _lcd_refresh_e_factor_3() { planner.refresh_e_factor(3); }
- #if EXTRUDERS > 4
- inline void _lcd_refresh_e_factor_4() { planner.refresh_e_factor(4); }
- #if EXTRUDERS > 5
- inline void _lcd_refresh_e_factor_5() { planner.refresh_e_factor(5); }
- #endif // EXTRUDERS > 5
- #endif // EXTRUDERS > 4
- #endif // EXTRUDERS > 3
- #endif // EXTRUDERS > 2
- #endif // EXTRUDERS > 1
-
- /**
- *
- * "Tune" submenu
- *
- */
- void lcd_tune_menu() {
- START_MENU();
- MENU_BACK(MSG_MAIN);
-
- //
- // Speed:
- //
- MENU_ITEM_EDIT(int3, MSG_SPEED, &feedrate_percentage, 10, 999);
-
- //
- // Manual bed leveling, Bed Z:
- //
- #if ENABLED(MESH_BED_LEVELING) && ENABLED(LCD_BED_LEVELING)
- MENU_ITEM_EDIT(float43, MSG_BED_Z, &mbl.z_offset, -1, 1);
- #endif
-
- //
- // Nozzle:
- // Nozzle [1-4]:
- //
- #if HOTENDS == 1
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE, &thermalManager.target_temperature[0], 0, HEATER_0_MAXTEMP - 15, watch_temp_callback_E0);
- #else // HOTENDS > 1
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N1, &thermalManager.target_temperature[0], 0, HEATER_0_MAXTEMP - 15, watch_temp_callback_E0);
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N2, &thermalManager.target_temperature[1], 0, HEATER_1_MAXTEMP - 15, watch_temp_callback_E1);
- #if HOTENDS > 2
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N3, &thermalManager.target_temperature[2], 0, HEATER_2_MAXTEMP - 15, watch_temp_callback_E2);
- #if HOTENDS > 3
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N4, &thermalManager.target_temperature[3], 0, HEATER_3_MAXTEMP - 15, watch_temp_callback_E3);
- #if HOTENDS > 4
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N5, &thermalManager.target_temperature[4], 0, HEATER_4_MAXTEMP - 15, watch_temp_callback_E4);
- #if HOTENDS > 5
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N6, &thermalManager.target_temperature[5], 0, HEATER_5_MAXTEMP - 15, watch_temp_callback_E5);
- #endif // HOTENDS > 5
- #endif // HOTENDS > 4
- #endif // HOTENDS > 3
- #endif // HOTENDS > 2
- #endif // HOTENDS > 1
-
- //
- // Bed:
- //
- #if HAS_HEATED_BED
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_BED, &thermalManager.target_temperature_bed, 0, BED_MAXTEMP - 15, watch_temp_callback_bed);
- #endif
-
- //
- // Fan Speed:
- //
- #if FAN_COUNT > 0
- #if HAS_FAN0
- MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_FAN_SPEED FAN_SPEED_1_SUFFIX, &fan_speed[0], 0, 255);
- #if ENABLED(EXTRA_FAN_SPEED)
- MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_EXTRA_FAN_SPEED FAN_SPEED_1_SUFFIX, &new_fan_speed[0], 3, 255);
- #endif
- #endif
- #if HAS_FAN1
- MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_FAN_SPEED " 2", &fan_speed[1], 0, 255);
- #if ENABLED(EXTRA_FAN_SPEED)
- MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_EXTRA_FAN_SPEED " 2", &new_fan_speed[1], 3, 255);
- #endif
- #endif
- #if HAS_FAN2
- MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_FAN_SPEED " 3", &fan_speed[2], 0, 255);
- #if ENABLED(EXTRA_FAN_SPEED)
- MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_EXTRA_FAN_SPEED " 3", &new_fan_speed[2], 3, 255);
- #endif
- #endif
- #endif // FAN_COUNT > 0
-
- //
- // Flow:
- // Flow [1-5]:
- //
- #if EXTRUDERS == 1
- MENU_ITEM_EDIT_CALLBACK(int3, MSG_FLOW, &planner.flow_percentage[0], 10, 999, _lcd_refresh_e_factor_0);
- #else // EXTRUDERS > 1
- MENU_ITEM_EDIT_CALLBACK(int3, MSG_FLOW, &planner.flow_percentage[active_extruder], 10, 999, _lcd_refresh_e_factor);
- MENU_ITEM_EDIT_CALLBACK(int3, MSG_FLOW MSG_N1, &planner.flow_percentage[0], 10, 999, _lcd_refresh_e_factor_0);
- MENU_ITEM_EDIT_CALLBACK(int3, MSG_FLOW MSG_N2, &planner.flow_percentage[1], 10, 999, _lcd_refresh_e_factor_1);
- #if EXTRUDERS > 2
- MENU_ITEM_EDIT_CALLBACK(int3, MSG_FLOW MSG_N3, &planner.flow_percentage[2], 10, 999, _lcd_refresh_e_factor_2);
- #if EXTRUDERS > 3
- MENU_ITEM_EDIT_CALLBACK(int3, MSG_FLOW MSG_N4, &planner.flow_percentage[3], 10, 999, _lcd_refresh_e_factor_3);
- #if EXTRUDERS > 4
- MENU_ITEM_EDIT_CALLBACK(int3, MSG_FLOW MSG_N5, &planner.flow_percentage[4], 10, 999, _lcd_refresh_e_factor_4);
- #if EXTRUDERS > 5
- MENU_ITEM_EDIT_CALLBACK(int3, MSG_FLOW MSG_N6, &planner.flow_percentage[5], 10, 999, _lcd_refresh_e_factor_5);
- #endif // EXTRUDERS > 5
- #endif // EXTRUDERS > 4
- #endif // EXTRUDERS > 3
- #endif // EXTRUDERS > 2
- #endif // EXTRUDERS > 1
-
- //
- // Babystep X:
- // Babystep Y:
- // Babystep Z:
- //
- #if ENABLED(BABYSTEPPING)
- #if ENABLED(BABYSTEP_XY)
- MENU_ITEM(submenu, MSG_BABYSTEP_X, lcd_babystep_x);
- MENU_ITEM(submenu, MSG_BABYSTEP_Y, lcd_babystep_y);
- #endif
- #if ENABLED(BABYSTEP_ZPROBE_OFFSET)
- MENU_ITEM(submenu, MSG_ZPROBE_ZOFFSET, lcd_babystep_zoffset);
- #else
- MENU_ITEM(submenu, MSG_BABYSTEP_Z, lcd_babystep_z);
- #endif
- #endif
-
- END_MENU();
- }
-
- /**
- *
- * "Driver current control" submenu items
- *
- */
- #if ENABLED(DAC_STEPPER_CURRENT)
-
- void dac_driver_getValues() { LOOP_XYZE(i) driverPercent[i] = dac_current_get_percent((AxisEnum)i); }
-
- void dac_driver_commit() { dac_current_set_percents(driverPercent); }
-
- void dac_driver_eeprom_write() { dac_commit_eeprom(); }
-
- void lcd_dac_menu() {
- dac_driver_getValues();
- START_MENU();
- MENU_BACK(MSG_CONTROL);
- MENU_ITEM_EDIT_CALLBACK(int8, MSG_X " " MSG_DAC_PERCENT, &driverPercent[X_AXIS], 0, 100, dac_driver_commit);
- MENU_ITEM_EDIT_CALLBACK(int8, MSG_Y " " MSG_DAC_PERCENT, &driverPercent[Y_AXIS], 0, 100, dac_driver_commit);
- MENU_ITEM_EDIT_CALLBACK(int8, MSG_Z " " MSG_DAC_PERCENT, &driverPercent[Z_AXIS], 0, 100, dac_driver_commit);
- MENU_ITEM_EDIT_CALLBACK(int8, MSG_E " " MSG_DAC_PERCENT, &driverPercent[E_AXIS], 0, 100, dac_driver_commit);
- MENU_ITEM(function, MSG_DAC_EEPROM_WRITE, dac_driver_eeprom_write);
- END_MENU();
- }
-
- #endif // DAC_STEPPER_CURRENT
-
- #if HAS_MOTOR_CURRENT_PWM
-
- void lcd_pwm_menu() {
- START_MENU();
- MENU_BACK(MSG_CONTROL);
- #if PIN_EXISTS(MOTOR_CURRENT_PWM_XY)
- MENU_ITEM_EDIT_CALLBACK(long5, MSG_X MSG_Y, &stepper.motor_current_setting[0], 100, 2000, Stepper::refresh_motor_power);
- #endif
- #if PIN_EXISTS(MOTOR_CURRENT_PWM_Z)
- MENU_ITEM_EDIT_CALLBACK(long5, MSG_Z, &stepper.motor_current_setting[1], 100, 2000, Stepper::refresh_motor_power);
- #endif
- #if PIN_EXISTS(MOTOR_CURRENT_PWM_E)
- MENU_ITEM_EDIT_CALLBACK(long5, MSG_E, &stepper.motor_current_setting[2], 100, 2000, Stepper::refresh_motor_power);
- #endif
- END_MENU();
- }
-
- #endif // HAS_MOTOR_CURRENT_PWM
-
- constexpr int16_t heater_maxtemp[HOTENDS] = ARRAY_BY_HOTENDS(HEATER_0_MAXTEMP, HEATER_1_MAXTEMP, HEATER_2_MAXTEMP, HEATER_3_MAXTEMP, HEATER_4_MAXTEMP);
-
- /**
- *
- * "Temperature" submenu items
- *
- */
- void _lcd_preheat(const int16_t endnum, const int16_t temph, const int16_t tempb, const uint8_t fan) {
- if (temph > 0) thermalManager.setTargetHotend(MIN(heater_maxtemp[endnum], temph), endnum);
- #if HAS_HEATED_BED
- if (tempb >= 0) thermalManager.setTargetBed(tempb);
- #else
- UNUSED(tempb);
- #endif
- #if FAN_COUNT > 0
- #if FAN_COUNT > 1
- fan_speed[active_extruder < FAN_COUNT ? active_extruder : 0] = fan;
- #else
- fan_speed[0] = fan;
- #endif
- #else
- UNUSED(fan);
- #endif
- lcd_return_to_status();
- }
-
- #if HAS_TEMP_HOTEND
- void lcd_preheat_m1_e0_only() { _lcd_preheat(0, lcd_preheat_hotend_temp[0], -1, lcd_preheat_fan_speed[0]); }
- void lcd_preheat_m2_e0_only() { _lcd_preheat(0, lcd_preheat_hotend_temp[1], -1, lcd_preheat_fan_speed[1]); }
- #if HAS_HEATED_BED
- void lcd_preheat_m1_e0() { _lcd_preheat(0, lcd_preheat_hotend_temp[0], lcd_preheat_bed_temp[0], lcd_preheat_fan_speed[0]); }
- void lcd_preheat_m2_e0() { _lcd_preheat(0, lcd_preheat_hotend_temp[1], lcd_preheat_bed_temp[1], lcd_preheat_fan_speed[1]); }
- #endif
- #endif
-
- #if HOTENDS > 1
- void lcd_preheat_m1_e1_only() { _lcd_preheat(1, lcd_preheat_hotend_temp[0], -1, lcd_preheat_fan_speed[0]); }
- void lcd_preheat_m2_e1_only() { _lcd_preheat(1, lcd_preheat_hotend_temp[1], -1, lcd_preheat_fan_speed[1]); }
- #if HAS_HEATED_BED
- void lcd_preheat_m1_e1() { _lcd_preheat(1, lcd_preheat_hotend_temp[0], lcd_preheat_bed_temp[0], lcd_preheat_fan_speed[0]); }
- void lcd_preheat_m2_e1() { _lcd_preheat(1, lcd_preheat_hotend_temp[1], lcd_preheat_bed_temp[1], lcd_preheat_fan_speed[1]); }
- #endif
- #if HOTENDS > 2
- void lcd_preheat_m1_e2_only() { _lcd_preheat(2, lcd_preheat_hotend_temp[0], -1, lcd_preheat_fan_speed[0]); }
- void lcd_preheat_m2_e2_only() { _lcd_preheat(2, lcd_preheat_hotend_temp[1], -1, lcd_preheat_fan_speed[1]); }
- #if HAS_HEATED_BED
- void lcd_preheat_m1_e2() { _lcd_preheat(2, lcd_preheat_hotend_temp[0], lcd_preheat_bed_temp[0], lcd_preheat_fan_speed[0]); }
- void lcd_preheat_m2_e2() { _lcd_preheat(2, lcd_preheat_hotend_temp[1], lcd_preheat_bed_temp[1], lcd_preheat_fan_speed[1]); }
- #endif
- #if HOTENDS > 3
- void lcd_preheat_m1_e3_only() { _lcd_preheat(3, lcd_preheat_hotend_temp[0], -1, lcd_preheat_fan_speed[0]); }
- void lcd_preheat_m2_e3_only() { _lcd_preheat(3, lcd_preheat_hotend_temp[1], -1, lcd_preheat_fan_speed[1]); }
- #if HAS_HEATED_BED
- void lcd_preheat_m1_e3() { _lcd_preheat(3, lcd_preheat_hotend_temp[0], lcd_preheat_bed_temp[0], lcd_preheat_fan_speed[0]); }
- void lcd_preheat_m2_e3() { _lcd_preheat(3, lcd_preheat_hotend_temp[1], lcd_preheat_bed_temp[1], lcd_preheat_fan_speed[1]); }
- #endif
- #if HOTENDS > 4
- void lcd_preheat_m1_e4_only() { _lcd_preheat(4, lcd_preheat_hotend_temp[0], -1, lcd_preheat_fan_speed[0]); }
- void lcd_preheat_m2_e4_only() { _lcd_preheat(4, lcd_preheat_hotend_temp[1], -1, lcd_preheat_fan_speed[1]); }
- #if HAS_HEATED_BED
- void lcd_preheat_m1_e4() { _lcd_preheat(4, lcd_preheat_hotend_temp[0], lcd_preheat_bed_temp[0], lcd_preheat_fan_speed[0]); }
- void lcd_preheat_m2_e4() { _lcd_preheat(4, lcd_preheat_hotend_temp[1], lcd_preheat_bed_temp[1], lcd_preheat_fan_speed[1]); }
- #endif
- #if HOTENDS > 5
- void lcd_preheat_m1_e5_only() { _lcd_preheat(5, lcd_preheat_hotend_temp[0], -1, lcd_preheat_fan_speed[0]); }
- void lcd_preheat_m2_e5_only() { _lcd_preheat(5, lcd_preheat_hotend_temp[1], -1, lcd_preheat_fan_speed[1]); }
- #if HAS_HEATED_BED
- void lcd_preheat_m1_e5() { _lcd_preheat(5, lcd_preheat_hotend_temp[0], lcd_preheat_bed_temp[0], lcd_preheat_fan_speed[0]); }
- void lcd_preheat_m2_e5() { _lcd_preheat(5, lcd_preheat_hotend_temp[1], lcd_preheat_bed_temp[1], lcd_preheat_fan_speed[1]); }
- #endif
- #endif // HOTENDS > 5
- #endif // HOTENDS > 4
- #endif // HOTENDS > 3
- #endif // HOTENDS > 2
-
- void lcd_preheat_m1_all() {
- #if HOTENDS > 1
- thermalManager.setTargetHotend(lcd_preheat_hotend_temp[0], 1);
- #if HOTENDS > 2
- thermalManager.setTargetHotend(lcd_preheat_hotend_temp[0], 2);
- #if HOTENDS > 3
- thermalManager.setTargetHotend(lcd_preheat_hotend_temp[0], 3);
- #if HOTENDS > 4
- thermalManager.setTargetHotend(lcd_preheat_hotend_temp[0], 4);
- #if HOTENDS > 5
- thermalManager.setTargetHotend(lcd_preheat_hotend_temp[0], 5);
- #endif // HOTENDS > 5
- #endif // HOTENDS > 4
- #endif // HOTENDS > 3
- #endif // HOTENDS > 2
- #endif // HOTENDS > 1
- #if HAS_HEATED_BED
- lcd_preheat_m1_e0();
- #else
- lcd_preheat_m1_e0_only();
- #endif
- }
- void lcd_preheat_m2_all() {
- #if HOTENDS > 1
- thermalManager.setTargetHotend(lcd_preheat_hotend_temp[1], 1);
- #if HOTENDS > 2
- thermalManager.setTargetHotend(lcd_preheat_hotend_temp[1], 2);
- #if HOTENDS > 3
- thermalManager.setTargetHotend(lcd_preheat_hotend_temp[1], 3);
- #if HOTENDS > 4
- thermalManager.setTargetHotend(lcd_preheat_hotend_temp[1], 4);
- #if HOTENDS > 5
- thermalManager.setTargetHotend(lcd_preheat_hotend_temp[1], 5);
- #endif // HOTENDS > 5
- #endif // HOTENDS > 4
- #endif // HOTENDS > 3
- #endif // HOTENDS > 2
- #endif // HOTENDS > 1
- #if HAS_HEATED_BED
- lcd_preheat_m2_e0();
- #else
- lcd_preheat_m2_e0_only();
- #endif
- }
-
- #endif // HOTENDS > 1
-
- #if HAS_HEATED_BED
- void lcd_preheat_m1_bedonly() { _lcd_preheat(0, 0, lcd_preheat_bed_temp[0], lcd_preheat_fan_speed[0]); }
- void lcd_preheat_m2_bedonly() { _lcd_preheat(0, 0, lcd_preheat_bed_temp[1], lcd_preheat_fan_speed[1]); }
- #endif
-
- #if HAS_TEMP_HOTEND || HAS_HEATED_BED
-
- void lcd_preheat_m1_menu() {
- START_MENU();
- MENU_BACK(MSG_TEMPERATURE);
- #if HOTENDS == 1
- #if HAS_HEATED_BED
- MENU_ITEM(function, MSG_PREHEAT_1, lcd_preheat_m1_e0);
- MENU_ITEM(function, MSG_PREHEAT_1_END, lcd_preheat_m1_e0_only);
- #else
- MENU_ITEM(function, MSG_PREHEAT_1, lcd_preheat_m1_e0_only);
- #endif
- #elif HOTENDS > 1
- #if HAS_HEATED_BED
- MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H1, lcd_preheat_m1_e0);
- MENU_ITEM(function, MSG_PREHEAT_1_END " " MSG_E1, lcd_preheat_m1_e0_only);
- MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H2, lcd_preheat_m1_e1);
- MENU_ITEM(function, MSG_PREHEAT_1_END " " MSG_E2, lcd_preheat_m1_e1_only);
- #else
- MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H1, lcd_preheat_m1_e0_only);
- MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H2, lcd_preheat_m1_e1_only);
- #endif
- #if HOTENDS > 2
- #if HAS_HEATED_BED
- MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H3, lcd_preheat_m1_e2);
- MENU_ITEM(function, MSG_PREHEAT_1_END " " MSG_E3, lcd_preheat_m1_e2_only);
- #else
- MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H3, lcd_preheat_m1_e2_only);
- #endif
- #if HOTENDS > 3
- #if HAS_HEATED_BED
- MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H4, lcd_preheat_m1_e3);
- MENU_ITEM(function, MSG_PREHEAT_1_END " " MSG_E4, lcd_preheat_m1_e3_only);
- #else
- MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H4, lcd_preheat_m1_e3_only);
- #endif
- #if HOTENDS > 4
- #if HAS_HEATED_BED
- MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H5, lcd_preheat_m1_e4);
- MENU_ITEM(function, MSG_PREHEAT_1_END " " MSG_E5, lcd_preheat_m1_e4_only);
- #else
- MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H5, lcd_preheat_m1_e4_only);
- #endif
- #if HOTENDS > 5
- #if HAS_HEATED_BED
- MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H6, lcd_preheat_m1_e5);
- MENU_ITEM(function, MSG_PREHEAT_1_END " " MSG_E6, lcd_preheat_m1_e5_only);
- #else
- MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H6, lcd_preheat_m1_e5_only);
- #endif
- #endif // HOTENDS > 5
- #endif // HOTENDS > 4
- #endif // HOTENDS > 3
- #endif // HOTENDS > 2
- MENU_ITEM(function, MSG_PREHEAT_1_ALL, lcd_preheat_m1_all);
- #endif // HOTENDS > 1
- #if HAS_HEATED_BED
- MENU_ITEM(function, MSG_PREHEAT_1_BEDONLY, lcd_preheat_m1_bedonly);
- #endif
- END_MENU();
- }
-
- void lcd_preheat_m2_menu() {
- START_MENU();
- MENU_BACK(MSG_TEMPERATURE);
- #if HOTENDS == 1
- #if HAS_HEATED_BED
- MENU_ITEM(function, MSG_PREHEAT_2, lcd_preheat_m2_e0);
- MENU_ITEM(function, MSG_PREHEAT_2_END, lcd_preheat_m2_e0_only);
- #else
- MENU_ITEM(function, MSG_PREHEAT_2, lcd_preheat_m2_e0_only);
- #endif
- #elif HOTENDS > 1
- #if HAS_HEATED_BED
- MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H1, lcd_preheat_m2_e0);
- MENU_ITEM(function, MSG_PREHEAT_2_END " " MSG_E1, lcd_preheat_m2_e0_only);
- MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H2, lcd_preheat_m2_e1);
- MENU_ITEM(function, MSG_PREHEAT_2_END " " MSG_E2, lcd_preheat_m2_e1_only);
- #else
- MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H1, lcd_preheat_m2_e0_only);
- MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H2, lcd_preheat_m2_e1_only);
- #endif
- #if HOTENDS > 2
- #if HAS_HEATED_BED
- MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H3, lcd_preheat_m2_e2);
- MENU_ITEM(function, MSG_PREHEAT_2_END " " MSG_E3, lcd_preheat_m2_e2_only);
- #else
- MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H3, lcd_preheat_m2_e2_only);
- #endif
- #if HOTENDS > 3
- #if HAS_HEATED_BED
- MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H4, lcd_preheat_m2_e3);
- MENU_ITEM(function, MSG_PREHEAT_2_END " " MSG_E4, lcd_preheat_m2_e3_only);
- #else
- MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H4, lcd_preheat_m2_e3_only);
- #endif
- #if HOTENDS > 4
- #if HAS_HEATED_BED
- MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H5, lcd_preheat_m2_e4);
- MENU_ITEM(function, MSG_PREHEAT_2_END " " MSG_E5, lcd_preheat_m2_e4_only);
- #else
- MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H5, lcd_preheat_m2_e4_only);
- #endif
- #if HOTENDS > 5
- #if HAS_HEATED_BED
- MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H6, lcd_preheat_m2_e5);
- MENU_ITEM(function, MSG_PREHEAT_2_END " " MSG_E6, lcd_preheat_m2_e5_only);
- #else
- MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H6, lcd_preheat_m2_e5_only);
- #endif
- #endif // HOTENDS > 5
- #endif // HOTENDS > 4
- #endif // HOTENDS > 3
- #endif // HOTENDS > 2
- MENU_ITEM(function, MSG_PREHEAT_2_ALL, lcd_preheat_m2_all);
- #endif // HOTENDS > 1
- #if HAS_HEATED_BED
- MENU_ITEM(function, MSG_PREHEAT_2_BEDONLY, lcd_preheat_m2_bedonly);
- #endif
- END_MENU();
- }
-
- #endif // HAS_TEMP_HOTEND || HAS_HEATED_BED
-
- void lcd_cooldown() {
- zero_fan_speeds();
- thermalManager.disable_all_heaters();
- lcd_return_to_status();
- }
-
- #if ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(PID_AUTOTUNE_MENU) || ENABLED(ADVANCED_PAUSE_FEATURE)
-
- /**
- * If the queue is full, the command will fail, so we have to loop
- * with idle() to make sure the command has been enqueued.
- */
- void lcd_enqueue_command(char * const cmd) {
- no_reentry = true;
- enqueue_and_echo_command_now(cmd);
- no_reentry = false;
- }
-
- void lcd_enqueue_commands_P(PGM_P const cmd) {
- no_reentry = true;
- enqueue_and_echo_commands_now_P(cmd);
- no_reentry = false;
- }
-
- #endif
-
- #if ENABLED(EEPROM_SETTINGS)
- static void lcd_store_settings() { lcd_completion_feedback(settings.save()); }
- static void lcd_load_settings() { lcd_completion_feedback(settings.load()); }
- #endif
-
- inline void _lcd_draw_homing() {
- constexpr uint8_t line = (LCD_HEIGHT - 1) / 2;
- if (lcdDrawUpdate) lcd_implementation_drawmenu_static(line, PSTR(MSG_LEVEL_BED_HOMING));
- lcdDrawUpdate = LCDVIEW_CALL_NO_REDRAW;
- }
-
- #if ENABLED(LEVEL_BED_CORNERS)
-
- /**
- * Level corners, starting in the front-left corner.
- */
- static int8_t bed_corner;
- void _lcd_goto_next_corner() {
- line_to_z(4.0);
- switch (bed_corner) {
- case 0:
- current_position[X_AXIS] = X_MIN_BED + LEVEL_CORNERS_INSET;
- current_position[Y_AXIS] = Y_MIN_BED + LEVEL_CORNERS_INSET;
- break;
- case 1:
- current_position[X_AXIS] = X_MAX_BED - LEVEL_CORNERS_INSET;
- break;
- case 2:
- current_position[Y_AXIS] = Y_MAX_BED - LEVEL_CORNERS_INSET;
- break;
- case 3:
- current_position[X_AXIS] = X_MIN_BED + LEVEL_CORNERS_INSET;
- break;
- #if ENABLED(LEVEL_CENTER_TOO)
- case 4:
- current_position[X_AXIS] = X_CENTER;
- current_position[Y_AXIS] = Y_CENTER;
- break;
- #endif
- }
- planner.buffer_line(current_position, MMM_TO_MMS(manual_feedrate_mm_m[X_AXIS]), active_extruder);
- line_to_z(0.0);
- if (++bed_corner > 3
- #if ENABLED(LEVEL_CENTER_TOO)
- + 1
- #endif
- ) bed_corner = 0;
- }
-
- void _lcd_corner_submenu() {
- START_MENU();
- MENU_ITEM(function,
- #if ENABLED(LEVEL_CENTER_TOO)
- MSG_LEVEL_BED_NEXT_POINT
- #else
- MSG_NEXT_CORNER
- #endif
- , _lcd_goto_next_corner);
- MENU_ITEM(function, MSG_BACK, lcd_goto_previous_menu_no_defer);
- END_MENU();
- }
-
- void _lcd_level_bed_corners_homing() {
- _lcd_draw_homing();
- if (all_axes_homed()) {
- bed_corner = 0;
- lcd_goto_screen(_lcd_corner_submenu);
- _lcd_goto_next_corner();
- }
- }
-
- void _lcd_level_bed_corners() {
- defer_return_to_status = true;
- if (!all_axes_known()) {
- axis_homed = 0;
- enqueue_and_echo_commands_P(PSTR("G28"));
- }
- lcd_goto_screen(_lcd_level_bed_corners_homing);
- }
-
- #endif // LEVEL_BED_CORNERS
-
- #if ENABLED(LCD_BED_LEVELING) && (ENABLED(PROBE_MANUALLY) || ENABLED(MESH_BED_LEVELING))
-
- /**
- *
- * "Motion" > "Level Bed" handlers
- *
- */
-
- static uint8_t manual_probe_index;
-
- // LCD probed points are from defaults
- constexpr uint8_t total_probe_points = (
- #if ENABLED(AUTO_BED_LEVELING_3POINT)
- 3
- #elif ABL_GRID || ENABLED(MESH_BED_LEVELING)
- GRID_MAX_POINTS
- #endif
- );
-
- bool lcd_wait_for_move;
-
- //
- // Bed leveling is done. Wait for G29 to complete.
- // A flag is used so that this can release control
- // and allow the command queue to be processed.
- //
- // When G29 finishes the last move:
- // - Raise Z to the "manual probe height"
- // - Don't return until done.
- //
- // ** This blocks the command queue! **
- //
- void _lcd_level_bed_done() {
- if (!lcd_wait_for_move) {
- #if MANUAL_PROBE_HEIGHT > 0 && DISABLED(MESH_BED_LEVELING)
- // Display "Done" screen and wait for moves to complete
- line_to_z(MANUAL_PROBE_HEIGHT);
- lcd_synchronize(PSTR(MSG_LEVEL_BED_DONE));
- #endif
- lcd_goto_previous_menu_no_defer();
- lcd_completion_feedback();
- }
- if (lcdDrawUpdate) lcd_implementation_drawmenu_static(LCD_HEIGHT >= 4 ? 1 : 0, PSTR(MSG_LEVEL_BED_DONE));
- lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NEXT;
- }
-
- void _lcd_level_goto_next_point();
-
- /**
- * Step 7: Get the Z coordinate, click goes to the next point or exits
- */
- void _lcd_level_bed_get_z() {
- ENCODER_DIRECTION_NORMAL();
-
- if (use_click()) {
-
- //
- // Save the current Z position and move
- //
-
- // If done...
- if (++manual_probe_index >= total_probe_points) {
- //
- // The last G29 records the point and enables bed leveling
- //
- lcd_wait_for_move = true;
- lcd_goto_screen(_lcd_level_bed_done);
- #if ENABLED(MESH_BED_LEVELING)
- enqueue_and_echo_commands_P(PSTR("G29 S2"));
- #elif ENABLED(PROBE_MANUALLY)
- enqueue_and_echo_commands_P(PSTR("G29 V1"));
- #endif
- }
- else
- _lcd_level_goto_next_point();
-
- return;
- }
-
- //
- // Encoder knob or keypad buttons adjust the Z position
- //
- if (encoderPosition) {
- const float z = current_position[Z_AXIS] + float((int32_t)encoderPosition) * (MBL_Z_STEP);
- line_to_z(constrain(z, -(LCD_PROBE_Z_RANGE) * 0.5f, (LCD_PROBE_Z_RANGE) * 0.5f));
- lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NEXT;
- encoderPosition = 0;
- }
-
- //
- // Draw on first display, then only on Z change
- //
- if (lcdDrawUpdate) {
- const float v = current_position[Z_AXIS];
- lcd_implementation_drawedit(PSTR(MSG_MOVE_Z), ftostr43sign(v + (v < 0 ? -0.0001f : 0.0001f), '+'));
- }
- }
-
- /**
- * Step 6: Display "Next point: 1 / 9" while waiting for move to finish
- */
- void _lcd_level_bed_moving() {
- if (lcdDrawUpdate) {
- char msg[10];
- sprintf_P(msg, PSTR("%i / %u"), (int)(manual_probe_index + 1), total_probe_points);
- lcd_implementation_drawedit(PSTR(MSG_LEVEL_BED_NEXT_POINT), msg);
- }
- lcdDrawUpdate = LCDVIEW_CALL_NO_REDRAW;
- if (!lcd_wait_for_move) lcd_goto_screen(_lcd_level_bed_get_z);
- }
-
- /**
- * Step 5: Initiate a move to the next point
- */
- void _lcd_level_goto_next_point() {
- lcd_goto_screen(_lcd_level_bed_moving);
-
- // G29 Records Z, moves, and signals when it pauses
- lcd_wait_for_move = true;
- #if ENABLED(MESH_BED_LEVELING)
- enqueue_and_echo_commands_P(manual_probe_index ? PSTR("G29 S2") : PSTR("G29 S1"));
- #elif ENABLED(PROBE_MANUALLY)
- enqueue_and_echo_commands_P(PSTR("G29 V1"));
- #endif
- }
-
- /**
- * Step 4: Display "Click to Begin", wait for click
- * Move to the first probe position
- */
- void _lcd_level_bed_homing_done() {
- if (lcdDrawUpdate) lcd_implementation_drawedit(PSTR(MSG_LEVEL_BED_WAITING));
- if (use_click()) {
- manual_probe_index = 0;
- _lcd_level_goto_next_point();
- }
- }
-
- /**
- * Step 3: Display "Homing XYZ" - Wait for homing to finish
- */
- void _lcd_level_bed_homing() {
- _lcd_draw_homing();
- if (all_axes_homed()) lcd_goto_screen(_lcd_level_bed_homing_done);
- }
-
- #if ENABLED(PROBE_MANUALLY)
- extern bool g29_in_progress;
- #endif
-
- /**
- * Step 2: Continue Bed Leveling...
- */
- void _lcd_level_bed_continue() {
- defer_return_to_status = true;
- axis_homed = 0;
- lcd_goto_screen(_lcd_level_bed_homing);
- enqueue_and_echo_commands_P(PSTR("G28"));
- }
-
- #elif ENABLED(AUTO_BED_LEVELING_UBL)
-
- void _lcd_ubl_level_bed();
-
- static int16_t ubl_storage_slot = 0,
- custom_hotend_temp = 190,
- side_points = 3,
- ubl_fillin_amount = 5,
- ubl_height_amount = 1,
- n_edit_pts = 1,
- x_plot = 0,
- y_plot = 0;
-
- #if HAS_HEATED_BED
- static int16_t custom_bed_temp = 50;
- #endif
-
- /**
- * UBL Build Custom Mesh Command
- */
- void _lcd_ubl_build_custom_mesh() {
- char UBL_LCD_GCODE[20];
- enqueue_and_echo_commands_P(PSTR("G28"));
- #if HAS_HEATED_BED
- sprintf_P(UBL_LCD_GCODE, PSTR("M190 S%i"), custom_bed_temp);
- lcd_enqueue_command(UBL_LCD_GCODE);
- #endif
- sprintf_P(UBL_LCD_GCODE, PSTR("M109 S%i"), custom_hotend_temp);
- lcd_enqueue_command(UBL_LCD_GCODE);
- enqueue_and_echo_commands_P(PSTR("G29 P1"));
- }
-
- /**
- * UBL Custom Mesh submenu
- *
- * << Build Mesh
- * Hotend Temp: ---
- * Bed Temp: ---
- * Build Custom Mesh
- */
- void _lcd_ubl_custom_mesh() {
- START_MENU();
- MENU_BACK(MSG_UBL_BUILD_MESH_MENU);
- MENU_ITEM_EDIT(int3, MSG_UBL_HOTEND_TEMP_CUSTOM, &custom_hotend_temp, EXTRUDE_MINTEMP, (HEATER_0_MAXTEMP - 10));
- #if HAS_HEATED_BED
- MENU_ITEM_EDIT(int3, MSG_UBL_BED_TEMP_CUSTOM, &custom_bed_temp, BED_MINTEMP, (BED_MAXTEMP - 15));
- #endif
- MENU_ITEM(function, MSG_UBL_BUILD_CUSTOM_MESH, _lcd_ubl_build_custom_mesh);
- END_MENU();
- }
-
- /**
- * UBL Adjust Mesh Height Command
- */
- void _lcd_ubl_adjust_height_cmd() {
- char UBL_LCD_GCODE[16];
- const int ind = ubl_height_amount > 0 ? 9 : 10;
- strcpy_P(UBL_LCD_GCODE, PSTR("G29 P6 C -"));
- sprintf_P(&UBL_LCD_GCODE[ind], PSTR(".%i"), ABS(ubl_height_amount));
- lcd_enqueue_command(UBL_LCD_GCODE);
- }
-
- /**
- * UBL Adjust Mesh Height submenu
- *
- * << Edit Mesh
- * Height Amount: ---
- * Adjust Mesh Height
- * << Info Screen
- */
- void _lcd_ubl_height_adjust_menu() {
- START_MENU();
- MENU_BACK(MSG_UBL_EDIT_MESH_MENU);
- MENU_ITEM_EDIT_CALLBACK(int3, MSG_UBL_MESH_HEIGHT_AMOUNT, &ubl_height_amount, -9, 9, _lcd_ubl_adjust_height_cmd);
- MENU_ITEM(function, MSG_WATCH, lcd_return_to_status);
- END_MENU();
- }
-
- /**
- * UBL Edit Mesh submenu
- *
- * << UBL Tools
- * Fine Tune All
- * Fine Tune Closest
- * - Adjust Mesh Height >>
- * << Info Screen
- */
- void _lcd_ubl_edit_mesh() {
- START_MENU();
- MENU_BACK(MSG_UBL_TOOLS);
- MENU_ITEM(gcode, MSG_UBL_FINE_TUNE_ALL, PSTR("G29 P4 R999 T"));
- MENU_ITEM(gcode, MSG_UBL_FINE_TUNE_CLOSEST, PSTR("G29 P4 T"));
- MENU_ITEM(submenu, MSG_UBL_MESH_HEIGHT_ADJUST, _lcd_ubl_height_adjust_menu);
- MENU_ITEM(function, MSG_WATCH, lcd_return_to_status);
- END_MENU();
- }
-
- /**
- * UBL Validate Custom Mesh Command
- */
- void _lcd_ubl_validate_custom_mesh() {
- char UBL_LCD_GCODE[24];
- const int temp =
- #if HAS_HEATED_BED
- custom_bed_temp
- #else
- 0
- #endif
- ;
- sprintf_P(UBL_LCD_GCODE, PSTR("G26 C B%i H%i P"), temp, custom_hotend_temp);
- lcd_enqueue_commands_P(PSTR("G28"));
- lcd_enqueue_command(UBL_LCD_GCODE);
- }
-
- /**
- * UBL Validate Mesh submenu
- *
- * << UBL Tools
- * Mesh Validation with Material 1
- * Mesh Validation with Material 2
- * Validate Custom Mesh
- * << Info Screen
- */
- void _lcd_ubl_validate_mesh() {
- START_MENU();
- MENU_BACK(MSG_UBL_TOOLS);
- #if HAS_HEATED_BED
- MENU_ITEM(gcode, MSG_UBL_VALIDATE_MESH_M1, PSTR("G28\nG26 C B" STRINGIFY(PREHEAT_1_TEMP_BED) " H" STRINGIFY(PREHEAT_1_TEMP_HOTEND) " P"));
- MENU_ITEM(gcode, MSG_UBL_VALIDATE_MESH_M2, PSTR("G28\nG26 C B" STRINGIFY(PREHEAT_2_TEMP_BED) " H" STRINGIFY(PREHEAT_2_TEMP_HOTEND) " P"));
- #else
- MENU_ITEM(gcode, MSG_UBL_VALIDATE_MESH_M1, PSTR("G28\nG26 C B0 H" STRINGIFY(PREHEAT_1_TEMP_HOTEND) " P"));
- MENU_ITEM(gcode, MSG_UBL_VALIDATE_MESH_M2, PSTR("G28\nG26 C B0 H" STRINGIFY(PREHEAT_2_TEMP_HOTEND) " P"));
- #endif
- MENU_ITEM(function, MSG_UBL_VALIDATE_CUSTOM_MESH, _lcd_ubl_validate_custom_mesh);
- MENU_ITEM(function, MSG_WATCH, lcd_return_to_status);
- END_MENU();
- }
-
- /**
- * UBL Grid Leveling Command
- */
- void _lcd_ubl_grid_level_cmd() {
- char UBL_LCD_GCODE[10];
- sprintf_P(UBL_LCD_GCODE, PSTR("G29 J%i"), side_points);
- lcd_enqueue_command(UBL_LCD_GCODE);
- }
-
- /**
- * UBL Grid Leveling submenu
- *
- * << UBL Tools
- * Side points: ---
- * Level Mesh
- */
- void _lcd_ubl_grid_level() {
- START_MENU();
- MENU_BACK(MSG_UBL_TOOLS);
- MENU_ITEM_EDIT(int3, MSG_UBL_SIDE_POINTS, &side_points, 2, 6);
- MENU_ITEM(function, MSG_UBL_MESH_LEVEL, _lcd_ubl_grid_level_cmd);
- END_MENU();
- }
-
- /**
- * UBL Mesh Leveling submenu
- *
- * << UBL Tools
- * 3-Point Mesh Leveling
- * - Grid Mesh Leveling >>
- * << Info Screen
- */
- void _lcd_ubl_mesh_leveling() {
- START_MENU();
- MENU_BACK(MSG_UBL_TOOLS);
- MENU_ITEM(gcode, MSG_UBL_3POINT_MESH_LEVELING, PSTR("G29 J0"));
- MENU_ITEM(submenu, MSG_UBL_GRID_MESH_LEVELING, _lcd_ubl_grid_level);
- MENU_ITEM(function, MSG_WATCH, lcd_return_to_status);
- END_MENU();
- }
-
- /**
- * UBL Fill-in Amount Mesh Command
- */
- void _lcd_ubl_fillin_amount_cmd() {
- char UBL_LCD_GCODE[16];
- sprintf_P(UBL_LCD_GCODE, PSTR("G29 P3 R C.%i"), ubl_fillin_amount);
- lcd_enqueue_command(UBL_LCD_GCODE);
- }
-
- /**
- * UBL Fill-in Mesh submenu
- *
- * << Build Mesh
- * Fill-in Amount: ---
- * Fill-in Mesh
- * Smart Fill-in
- * Manual Fill-in
- * << Info Screen
- */
- void _lcd_ubl_fillin_menu() {
- START_MENU();
- MENU_BACK(MSG_UBL_BUILD_MESH_MENU);
- MENU_ITEM_EDIT_CALLBACK(int3, MSG_UBL_FILLIN_AMOUNT, &ubl_fillin_amount, 0, 9, _lcd_ubl_fillin_amount_cmd);
- MENU_ITEM(gcode, MSG_UBL_SMART_FILLIN, PSTR("G29 P3 T0"));
- MENU_ITEM(gcode, MSG_UBL_MANUAL_FILLIN, PSTR("G29 P2 B T0"));
- MENU_ITEM(function, MSG_WATCH, lcd_return_to_status);
- END_MENU();
- }
-
- void _lcd_ubl_invalidate() {
- ubl.invalidate();
- SERIAL_PROTOCOLLNPGM("Mesh invalidated.");
- }
-
- /**
- * UBL Build Mesh submenu
- *
- * << UBL Tools
- * Build Mesh with Material 1
- * Build Mesh with Material 2
- * - Build Custom Mesh >>
- * Build Cold Mesh
- * - Fill-in Mesh >>
- * Continue Bed Mesh
- * Invalidate All
- * Invalidate Closest
- * << Info Screen
- */
- void _lcd_ubl_build_mesh() {
- START_MENU();
- MENU_BACK(MSG_UBL_TOOLS);
- #if HAS_HEATED_BED
- MENU_ITEM(gcode, MSG_UBL_BUILD_MESH_M1, PSTR(
- "G28\n"
- "M190 S" STRINGIFY(PREHEAT_1_TEMP_BED) "\n"
- "M109 S" STRINGIFY(PREHEAT_1_TEMP_HOTEND) "\n"
- "G29 P1\n"
- "M104 S0\n"
- "M140 S0"
- ));
- MENU_ITEM(gcode, MSG_UBL_BUILD_MESH_M2, PSTR(
- "G28\n"
- "M190 S" STRINGIFY(PREHEAT_2_TEMP_BED) "\n"
- "M109 S" STRINGIFY(PREHEAT_2_TEMP_HOTEND) "\n"
- "G29 P1\n"
- "M104 S0\n"
- "M140 S0"
- ));
- #else
- MENU_ITEM(gcode, MSG_UBL_BUILD_MESH_M1, PSTR(
- "G28\n"
- "M109 S" STRINGIFY(PREHEAT_1_TEMP_HOTEND) "\n"
- "G29 P1\n"
- "M104 S0"
- ));
- MENU_ITEM(gcode, MSG_UBL_BUILD_MESH_M2, PSTR(
- "G28\n"
- "M109 S" STRINGIFY(PREHEAT_2_TEMP_HOTEND) "\n"
- "G29 P1\n"
- "M104 S0"
- ));
- #endif
- MENU_ITEM(submenu, MSG_UBL_BUILD_CUSTOM_MESH, _lcd_ubl_custom_mesh);
- MENU_ITEM(gcode, MSG_UBL_BUILD_COLD_MESH, PSTR("G28\nG29 P1"));
- MENU_ITEM(submenu, MSG_UBL_FILLIN_MESH, _lcd_ubl_fillin_menu);
- MENU_ITEM(gcode, MSG_UBL_CONTINUE_MESH, PSTR("G29 P1 C"));
- MENU_ITEM(function, MSG_UBL_INVALIDATE_ALL, _lcd_ubl_invalidate);
- MENU_ITEM(gcode, MSG_UBL_INVALIDATE_CLOSEST, PSTR("G29 I"));
- MENU_ITEM(function, MSG_WATCH, lcd_return_to_status);
- END_MENU();
- }
-
- /**
- * UBL Load Mesh Command
- */
- void _lcd_ubl_load_mesh_cmd() {
- char UBL_LCD_GCODE[25];
- sprintf_P(UBL_LCD_GCODE, PSTR("G29 L%i"), ubl_storage_slot);
- lcd_enqueue_command(UBL_LCD_GCODE);
- sprintf_P(UBL_LCD_GCODE, PSTR("M117 " MSG_MESH_LOADED), ubl_storage_slot);
- lcd_enqueue_command(UBL_LCD_GCODE);
- }
-
- /**
- * UBL Save Mesh Command
- */
- void _lcd_ubl_save_mesh_cmd() {
- char UBL_LCD_GCODE[25];
- sprintf_P(UBL_LCD_GCODE, PSTR("G29 S%i"), ubl_storage_slot);
- lcd_enqueue_command(UBL_LCD_GCODE);
- sprintf_P(UBL_LCD_GCODE, PSTR("M117 " MSG_MESH_SAVED), ubl_storage_slot);
- lcd_enqueue_command(UBL_LCD_GCODE);
- }
-
- /**
- * UBL Mesh Storage submenu
- *
- * << Unified Bed Leveling
- * Memory Slot: ---
- * Load Bed Mesh
- * Save Bed Mesh
- */
- void _lcd_ubl_storage_mesh() {
- int16_t a = settings.calc_num_meshes();
- START_MENU();
- MENU_BACK(MSG_UBL_LEVEL_BED);
- if (!WITHIN(ubl_storage_slot, 0, a - 1)) {
- STATIC_ITEM(MSG_NO_STORAGE);
- }
- else {
- MENU_ITEM_EDIT(int3, MSG_UBL_STORAGE_SLOT, &ubl_storage_slot, 0, a - 1);
- MENU_ITEM(function, MSG_UBL_LOAD_MESH, _lcd_ubl_load_mesh_cmd);
- MENU_ITEM(function, MSG_UBL_SAVE_MESH, _lcd_ubl_save_mesh_cmd);
- }
- END_MENU();
- }
-
- /**
- * UBL LCD "radar" map homing
- */
- void _lcd_ubl_output_map_lcd();
-
- void _lcd_ubl_map_homing() {
- defer_return_to_status = true;
- _lcd_draw_homing();
- if (all_axes_homed()) {
- ubl.lcd_map_control = true; // Return to the map screen
- lcd_goto_screen(_lcd_ubl_output_map_lcd);
- }
- }
-
- /**
- * UBL LCD "radar" map point editing
- */
- void _lcd_ubl_map_lcd_edit_cmd() {
- char UBL_LCD_GCODE[50], str[10], str2[10];
- dtostrf(pgm_read_float(&ubl._mesh_index_to_xpos[x_plot]), 0, 2, str);
- dtostrf(pgm_read_float(&ubl._mesh_index_to_ypos[y_plot]), 0, 2, str2);
- snprintf_P(UBL_LCD_GCODE, sizeof(UBL_LCD_GCODE), PSTR("G29 P4 X%s Y%s R%i"), str, str2, n_edit_pts);
- lcd_enqueue_command(UBL_LCD_GCODE);
- }
-
- /**
- * UBL LCD Map Movement
- */
- void ubl_map_move_to_xy() {
- current_position[X_AXIS] = pgm_read_float(&ubl._mesh_index_to_xpos[x_plot]);
- current_position[Y_AXIS] = pgm_read_float(&ubl._mesh_index_to_ypos[y_plot]);
- planner.buffer_line(current_position, MMM_TO_MMS(XY_PROBE_SPEED), active_extruder);
- }
-
- /**
- * UBL LCD "radar" map
- */
- void set_current_from_steppers_for_axis(const AxisEnum axis);
- void sync_plan_position();
-
- void _lcd_do_nothing() {}
- void _lcd_hard_stop() {
- const screenFunc_t old_screen = currentScreen;
- currentScreen = _lcd_do_nothing;
- planner.quick_stop();
- currentScreen = old_screen;
- set_current_from_steppers_for_axis(ALL_AXES);
- sync_plan_position();
- }
-
- void _lcd_ubl_output_map_lcd() {
- static int16_t step_scaler = 0;
-
- if (use_click()) return _lcd_ubl_map_lcd_edit_cmd();
- ENCODER_DIRECTION_NORMAL();
-
- if (encoderPosition) {
- step_scaler += (int32_t)encoderPosition;
- x_plot += step_scaler / (ENCODER_STEPS_PER_MENU_ITEM);
- if (ABS(step_scaler) >= ENCODER_STEPS_PER_MENU_ITEM) step_scaler = 0;
- encoderPosition = 0;
- lcdDrawUpdate = LCDVIEW_REDRAW_NOW;
- }
-
- // Encoder to the right (++)
- if (x_plot >= GRID_MAX_POINTS_X) { x_plot = 0; y_plot++; }
- if (y_plot >= GRID_MAX_POINTS_Y) y_plot = 0;
-
- // Encoder to the left (--)
- if (x_plot <= GRID_MAX_POINTS_X - (GRID_MAX_POINTS_X + 1)) { x_plot = GRID_MAX_POINTS_X - 1; y_plot--; }
- if (y_plot <= GRID_MAX_POINTS_Y - (GRID_MAX_POINTS_Y + 1)) y_plot = GRID_MAX_POINTS_Y - 1;
-
- // Prevent underrun/overrun of plot numbers
- x_plot = constrain(x_plot, GRID_MAX_POINTS_X - (GRID_MAX_POINTS_X + 1), GRID_MAX_POINTS_X + 1);
- y_plot = constrain(y_plot, GRID_MAX_POINTS_Y - (GRID_MAX_POINTS_Y + 1), GRID_MAX_POINTS_Y + 1);
-
- // Determine number of points to edit
- #if IS_KINEMATIC
- n_edit_pts = 9; //TODO: Delta accessible edit points
- #else
- const bool xc = WITHIN(x_plot, 1, GRID_MAX_POINTS_X - 2),
- yc = WITHIN(y_plot, 1, GRID_MAX_POINTS_Y - 2);
- n_edit_pts = yc ? (xc ? 9 : 6) : (xc ? 6 : 4); // Corners
- #endif
-
- if (lcdDrawUpdate) {
- lcd_implementation_ubl_plot(x_plot, y_plot);
-
- if (planner.movesplanned()) // If the nozzle is already moving, cancel the move.
- _lcd_hard_stop();
-
- ubl_map_move_to_xy(); // Move to new location
- }
- }
-
- /**
- * UBL Homing before LCD map
- */
- void _lcd_ubl_output_map_lcd_cmd() {
- if (!all_axes_known()) {
- axis_homed = 0;
- enqueue_and_echo_commands_P(PSTR("G28"));
- }
- lcd_goto_screen(_lcd_ubl_map_homing);
- }
-
- /**
- * UBL Output map submenu
- *
- * << Unified Bed Leveling
- * Output for Host
- * Output for CSV
- * Off Printer Backup
- * Output Mesh Map
- */
- void _lcd_ubl_output_map() {
- START_MENU();
- MENU_BACK(MSG_UBL_LEVEL_BED);
- MENU_ITEM(gcode, MSG_UBL_OUTPUT_MAP_HOST, PSTR("G29 T0"));
- MENU_ITEM(gcode, MSG_UBL_OUTPUT_MAP_CSV, PSTR("G29 T1"));
- MENU_ITEM(gcode, MSG_UBL_OUTPUT_MAP_BACKUP, PSTR("G29 S-1"));
- MENU_ITEM(function, MSG_UBL_OUTPUT_MAP, _lcd_ubl_output_map_lcd_cmd);
- END_MENU();
- }
-
- /**
- * UBL Tools submenu
- *
- * << Unified Bed Leveling
- * - Build Mesh >>
- * - Validate Mesh >>
- * - Edit Mesh >>
- * - Mesh Leveling >>
- */
- void _lcd_ubl_tools_menu() {
- START_MENU();
- MENU_BACK(MSG_UBL_LEVEL_BED);
- MENU_ITEM(submenu, MSG_UBL_BUILD_MESH_MENU, _lcd_ubl_build_mesh);
- MENU_ITEM(gcode, MSG_UBL_MANUAL_MESH, PSTR("G29 I999\nG29 P2 B T0"));
- MENU_ITEM(submenu, MSG_UBL_VALIDATE_MESH_MENU, _lcd_ubl_validate_mesh);
- MENU_ITEM(submenu, MSG_UBL_EDIT_MESH_MENU, _lcd_ubl_edit_mesh);
- MENU_ITEM(submenu, MSG_UBL_MESH_LEVELING, _lcd_ubl_mesh_leveling);
- END_MENU();
- }
-
- /**
- * UBL Step-By-Step submenu
- *
- * << Unified Bed Leveling
- * 1 Build Cold Mesh
- * 2 Smart Fill-in
- * - 3 Validate Mesh >>
- * 4 Fine Tune All
- * - 5 Validate Mesh >>
- * 6 Fine Tune All
- * 7 Save Bed Mesh
- */
- void _lcd_ubl_step_by_step() {
- START_MENU();
- MENU_BACK(MSG_UBL_LEVEL_BED);
- MENU_ITEM(gcode, "1 " MSG_UBL_BUILD_COLD_MESH, PSTR("G28\nG29 P1"));
- MENU_ITEM(gcode, "2 " MSG_UBL_SMART_FILLIN, PSTR("G29 P3 T0"));
- MENU_ITEM(submenu, "3 " MSG_UBL_VALIDATE_MESH_MENU, _lcd_ubl_validate_mesh);
- MENU_ITEM(gcode, "4 " MSG_UBL_FINE_TUNE_ALL, PSTR("G29 P4 R999 T"));
- MENU_ITEM(submenu, "5 " MSG_UBL_VALIDATE_MESH_MENU, _lcd_ubl_validate_mesh);
- MENU_ITEM(gcode, "6 " MSG_UBL_FINE_TUNE_ALL, PSTR("G29 P4 R999 T"));
- MENU_ITEM(function, "7 " MSG_UBL_SAVE_MESH, _lcd_ubl_save_mesh_cmd);
- END_MENU();
- }
-
- /**
- * UBL System submenu
- *
- * << Motion
- * - Manually Build Mesh >>
- * - Activate UBL >>
- * - Deactivate UBL >>
- * - Step-By-Step UBL >>
- * - Mesh Storage >>
- * - Output Map >>
- * - UBL Tools >>
- * - Output UBL Info >>
- */
-
- void _lcd_ubl_level_bed() {
- START_MENU();
- MENU_BACK(MSG_MOTION);
- MENU_ITEM(gcode, MSG_UBL_ACTIVATE_MESH, PSTR("G29 A"));
- MENU_ITEM(gcode, MSG_UBL_DEACTIVATE_MESH, PSTR("G29 D"));
- MENU_ITEM(submenu, MSG_UBL_STEP_BY_STEP_MENU, _lcd_ubl_step_by_step);
- MENU_ITEM(function, MSG_UBL_MESH_EDIT, _lcd_ubl_output_map_lcd_cmd);
- MENU_ITEM(submenu, MSG_UBL_STORAGE_MESH_MENU, _lcd_ubl_storage_mesh);
- MENU_ITEM(submenu, MSG_UBL_OUTPUT_MAP, _lcd_ubl_output_map);
- MENU_ITEM(submenu, MSG_UBL_TOOLS, _lcd_ubl_tools_menu);
- MENU_ITEM(gcode, MSG_UBL_INFO_UBL, PSTR("G29 W"));
- #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float3, MSG_Z_FADE_HEIGHT, &new_z_fade_height, 0, 100, _lcd_set_z_fade_height);
- #endif
- END_MENU();
- }
-
- #endif // AUTO_BED_LEVELING_UBL
-
-
- #if ENABLED(LCD_BED_LEVELING) || (HAS_LEVELING && DISABLED(SLIM_LCD_MENUS))
- void _lcd_toggle_bed_leveling() { set_bed_leveling_enabled(!planner.leveling_active); }
- #endif
-
- #if ENABLED(LCD_BED_LEVELING)
-
- /**
- * Step 1: Bed Level entry-point
- *
- * << Motion
- * Auto Home (if homing needed)
- * Leveling On/Off (if data exists, and homed)
- * Fade Height: --- (Req: ENABLE_LEVELING_FADE_HEIGHT)
- * Mesh Z Offset: --- (Req: MESH_BED_LEVELING)
- * Z Probe Offset: --- (Req: HAS_BED_PROBE, Opt: BABYSTEP_ZPROBE_OFFSET)
- * Level Bed >
- * Level Corners > (if homed)
- * Load Settings (Req: EEPROM_SETTINGS)
- * Save Settings (Req: EEPROM_SETTINGS)
- */
- void lcd_bed_leveling_menu() {
- START_MENU();
- MENU_BACK(MSG_MOTION);
-
- const bool is_homed = all_axes_known();
-
- // Auto Home if not using manual probing
- #if DISABLED(PROBE_MANUALLY) && DISABLED(MESH_BED_LEVELING)
- if (!is_homed) MENU_ITEM(gcode, MSG_AUTO_HOME, PSTR("G28"));
- #endif
-
- // Level Bed
- #if ENABLED(PROBE_MANUALLY) || ENABLED(MESH_BED_LEVELING)
- // Manual leveling uses a guided procedure
- MENU_ITEM(submenu, MSG_LEVEL_BED, _lcd_level_bed_continue);
- #else
- // Automatic leveling can just run the G-code
- MENU_ITEM(gcode, MSG_LEVEL_BED, is_homed ? PSTR("G29") : PSTR("G28\nG29"));
- #endif
-
- // Homed and leveling is valid? Then leveling can be toggled.
- if (is_homed && leveling_is_valid()) {
- bool new_level_state = planner.leveling_active;
- MENU_ITEM_EDIT_CALLBACK(bool, MSG_BED_LEVELING, &new_level_state, _lcd_toggle_bed_leveling);
- }
-
- // Z Fade Height
- #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float3, MSG_Z_FADE_HEIGHT, &new_z_fade_height, 0, 100, _lcd_set_z_fade_height);
- #endif
-
- //
- // MBL Z Offset
- //
- #if ENABLED(MESH_BED_LEVELING)
- MENU_ITEM_EDIT(float43, MSG_BED_Z, &mbl.z_offset, -1, 1);
- #endif
-
- #if ENABLED(BABYSTEP_ZPROBE_OFFSET)
- MENU_ITEM(submenu, MSG_ZPROBE_ZOFFSET, lcd_babystep_zoffset);
- #elif HAS_BED_PROBE
- MENU_ITEM_EDIT(float52, MSG_ZPROBE_ZOFFSET, &zprobe_zoffset, Z_PROBE_OFFSET_RANGE_MIN, Z_PROBE_OFFSET_RANGE_MAX);
- #endif
-
- #if ENABLED(LEVEL_BED_CORNERS)
- // Move to the next corner for leveling
- MENU_ITEM(submenu, MSG_LEVEL_CORNERS, _lcd_level_bed_corners);
- #endif
-
- #if ENABLED(EEPROM_SETTINGS)
- MENU_ITEM(function, MSG_LOAD_EEPROM, lcd_load_settings);
- MENU_ITEM(function, MSG_STORE_EEPROM, lcd_store_settings);
- #endif
- END_MENU();
- }
-
- #endif // LCD_BED_LEVELING
-
- /**
- *
- * "Movement" submenu
- *
- */
-
- void lcd_movement_menu() {
- START_MENU();
-
- //
- // ^ Main
- //
- MENU_BACK(MSG_MAIN);
-
- //
- // Move Axis
- //
- #if ENABLED(DELTA)
- if (all_axes_homed())
- #endif
- MENU_ITEM(submenu, MSG_MOVE_AXIS, lcd_move_menu);
-
- //
- // Auto Home
- //
- MENU_ITEM(gcode, MSG_AUTO_HOME, PSTR("G28"));
- #if ENABLED(INDIVIDUAL_AXIS_HOMING_MENU)
- MENU_ITEM(gcode, MSG_AUTO_HOME_X, PSTR("G28 X"));
- MENU_ITEM(gcode, MSG_AUTO_HOME_Y, PSTR("G28 Y"));
- MENU_ITEM(gcode, MSG_AUTO_HOME_Z, PSTR("G28 Z"));
- #endif
-
- //
- // TMC Z Calibration
- //
- #if ENABLED(TMC_Z_CALIBRATION)
- MENU_ITEM(gcode, MSG_TMC_Z_CALIBRATION, PSTR("G28\nM915"));
- #endif
-
- //
- // Level Bed
- //
- #if ENABLED(AUTO_BED_LEVELING_UBL)
-
- MENU_ITEM(submenu, MSG_UBL_LEVEL_BED, _lcd_ubl_level_bed);
-
- #elif ENABLED(LCD_BED_LEVELING)
-
- #if ENABLED(PROBE_MANUALLY)
- if (!g29_in_progress)
- #endif
- MENU_ITEM(submenu, MSG_BED_LEVELING, lcd_bed_leveling_menu);
-
- #elif HAS_LEVELING && DISABLED(SLIM_LCD_MENUS)
-
- #if DISABLED(PROBE_MANUALLY)
- MENU_ITEM(gcode, MSG_LEVEL_BED, PSTR("G28\nG29"));
- #endif
- if (leveling_is_valid()) {
- bool new_level_state = planner.leveling_active;
- MENU_ITEM_EDIT_CALLBACK(bool, MSG_BED_LEVELING, &new_level_state, _lcd_toggle_bed_leveling);
- }
- #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float3, MSG_Z_FADE_HEIGHT, &new_z_fade_height, 0, 100, _lcd_set_z_fade_height);
- #endif
-
- #endif
-
- #if ENABLED(LEVEL_BED_CORNERS) && DISABLED(LCD_BED_LEVELING)
- MENU_ITEM(function, MSG_LEVEL_CORNERS, _lcd_level_bed_corners);
- #endif
-
- //
- // Disable Steppers
- //
- MENU_ITEM(gcode, MSG_DISABLE_STEPPERS, PSTR("M84"));
-
- END_MENU();
- }
-
- #if ENABLED(DELTA_CALIBRATION_MENU) || ENABLED(DELTA_AUTO_CALIBRATION)
-
- void _man_probe_pt(const float &rx, const float &ry) {
- do_blocking_move_to_z(Z_CLEARANCE_BETWEEN_PROBES);
- do_blocking_move_to_xy(rx, ry);
-
- lcd_synchronize();
- move_menu_scale = MAX(PROBE_MANUALLY_STEP, MIN_STEPS_PER_SEGMENT / float(DEFAULT_XYZ_STEPS_PER_UNIT));
- lcd_goto_screen(lcd_move_z);
- }
-
- #endif // DELTA_CALIBRATION_MENU || DELTA_AUTO_CALIBRATION
-
- #if ENABLED(DELTA_AUTO_CALIBRATION)
-
- float lcd_probe_pt(const float &rx, const float &ry) {
- _man_probe_pt(rx, ry);
- KEEPALIVE_STATE(PAUSED_FOR_USER);
- defer_return_to_status = true;
- wait_for_user = true;
- while (wait_for_user) idle();
- KEEPALIVE_STATE(IN_HANDLER);
- lcd_goto_previous_menu_no_defer();
- return current_position[Z_AXIS];
- }
-
- #endif // DELTA_AUTO_CALIBRATION
-
- #if ENABLED(DELTA_CALIBRATION_MENU)
-
- void _lcd_calibrate_homing() {
- _lcd_draw_homing();
- if (all_axes_homed()) lcd_goto_previous_menu();
- }
-
- void _lcd_delta_calibrate_home() {
- enqueue_and_echo_commands_P(PSTR("G28"));
- lcd_goto_screen(_lcd_calibrate_homing);
- }
-
- void _goto_tower_x() { _man_probe_pt(cos(RADIANS(210)) * delta_calibration_radius, sin(RADIANS(210)) * delta_calibration_radius); }
- void _goto_tower_y() { _man_probe_pt(cos(RADIANS(330)) * delta_calibration_radius, sin(RADIANS(330)) * delta_calibration_radius); }
- void _goto_tower_z() { _man_probe_pt(cos(RADIANS( 90)) * delta_calibration_radius, sin(RADIANS( 90)) * delta_calibration_radius); }
- void _goto_center() { _man_probe_pt(0,0); }
-
- #endif // DELTA_CALIBRATION_MENU
-
- #if ENABLED(DELTA_CALIBRATION_MENU) || ENABLED(DELTA_AUTO_CALIBRATION)
-
- void _recalc_delta_settings() {
- #if HAS_LEVELING
- reset_bed_level(); // After changing kinematics bed-level data is no longer valid
- #endif
- recalc_delta_settings();
- }
-
- void lcd_delta_settings() {
- START_MENU();
- MENU_BACK(MSG_DELTA_CALIBRATE);
- MENU_ITEM_EDIT_CALLBACK(float52sign, MSG_DELTA_HEIGHT, &delta_height, delta_height - 10, delta_height + 10, _recalc_delta_settings);
- MENU_ITEM_EDIT_CALLBACK(float43, "Ex", &delta_endstop_adj[A_AXIS], -5, 5, _recalc_delta_settings);
- MENU_ITEM_EDIT_CALLBACK(float43, "Ey", &delta_endstop_adj[B_AXIS], -5, 5, _recalc_delta_settings);
- MENU_ITEM_EDIT_CALLBACK(float43, "Ez", &delta_endstop_adj[C_AXIS], -5, 5, _recalc_delta_settings);
- MENU_ITEM_EDIT_CALLBACK(float52sign, MSG_DELTA_RADIUS, &delta_radius, delta_radius - 5, delta_radius + 5, _recalc_delta_settings);
- MENU_ITEM_EDIT_CALLBACK(float43, "Tx", &delta_tower_angle_trim[A_AXIS], -5, 5, _recalc_delta_settings);
- MENU_ITEM_EDIT_CALLBACK(float43, "Ty", &delta_tower_angle_trim[B_AXIS], -5, 5, _recalc_delta_settings);
- MENU_ITEM_EDIT_CALLBACK(float43, "Tz", &delta_tower_angle_trim[C_AXIS], -5, 5, _recalc_delta_settings);
- MENU_ITEM_EDIT_CALLBACK(float52sign, MSG_DELTA_DIAG_ROD, &delta_diagonal_rod, delta_diagonal_rod - 5, delta_diagonal_rod + 5, _recalc_delta_settings);
- END_MENU();
- }
-
- void lcd_delta_calibrate_menu() {
- START_MENU();
- MENU_BACK(MSG_MAIN);
- #if ENABLED(DELTA_AUTO_CALIBRATION)
- MENU_ITEM(gcode, MSG_DELTA_AUTO_CALIBRATE, PSTR("G33"));
- MENU_ITEM(gcode, MSG_DELTA_HEIGHT_CALIBRATE, PSTR("G33 S P1"));
- MENU_ITEM(gcode, MSG_DELTA_Z_OFFSET_CALIBRATE, PSTR("G33 P-1"));
- #if ENABLED(EEPROM_SETTINGS)
- MENU_ITEM(function, MSG_STORE_EEPROM, lcd_store_settings);
- MENU_ITEM(function, MSG_LOAD_EEPROM, lcd_load_settings);
- #endif
- #endif
- MENU_ITEM(submenu, MSG_DELTA_SETTINGS, lcd_delta_settings);
- #if ENABLED(DELTA_CALIBRATION_MENU)
- MENU_ITEM(submenu, MSG_AUTO_HOME, _lcd_delta_calibrate_home);
- if (all_axes_homed()) {
- MENU_ITEM(submenu, MSG_DELTA_CALIBRATE_X, _goto_tower_x);
- MENU_ITEM(submenu, MSG_DELTA_CALIBRATE_Y, _goto_tower_y);
- MENU_ITEM(submenu, MSG_DELTA_CALIBRATE_Z, _goto_tower_z);
- MENU_ITEM(submenu, MSG_DELTA_CALIBRATE_CENTER, _goto_center);
- }
- #endif
- END_MENU();
- }
-
- #endif // DELTA_CALIBRATION_MENU || DELTA_AUTO_CALIBRATION
-
- /**
- * If the most recent manual move hasn't been fed to the planner yet,
- * and the planner can accept one, send immediately
- */
- inline void manage_manual_move() {
-
- if (processing_manual_move) return;
-
- if (manual_move_axis != (int8_t)NO_AXIS && ELAPSED(millis(), manual_move_start_time) && !planner.is_full()) {
-
- #if IS_KINEMATIC
-
- const float old_feedrate = feedrate_mm_s;
- feedrate_mm_s = MMM_TO_MMS(manual_feedrate_mm_m[manual_move_axis]);
-
- #if EXTRUDERS > 1
- const int8_t old_extruder = active_extruder;
- if (manual_move_axis == E_AXIS) active_extruder = manual_move_e_index;
- #endif
-
- // Set movement on a single axis
- set_destination_from_current();
- destination[manual_move_axis] += manual_move_offset;
-
- // Reset for the next move
- manual_move_offset = 0;
- manual_move_axis = (int8_t)NO_AXIS;
-
- // DELTA and SCARA machines use segmented moves, which could fill the planner during the call to
- // move_to_destination. This will cause idle() to be called, which can then call this function while the
- // previous invocation is being blocked. Modifications to manual_move_offset shouldn't be made while
- // processing_manual_move is true or the planner will get out of sync.
- processing_manual_move = true;
- prepare_move_to_destination(); // will call set_current_from_destination()
- processing_manual_move = false;
-
- feedrate_mm_s = old_feedrate;
- #if EXTRUDERS > 1
- active_extruder = old_extruder;
- #endif
-
- #else
-
- planner.buffer_line(current_position, MMM_TO_MMS(manual_feedrate_mm_m[manual_move_axis]), manual_move_axis == E_AXIS ? manual_move_e_index : active_extruder);
- manual_move_axis = (int8_t)NO_AXIS;
-
- #endif
- }
- }
-
- /**
- * Set a flag that lcd_update() should start a move
- * to "current_position" after a short delay.
- */
- inline void manual_move_to_current(AxisEnum axis
- #if E_MANUAL > 1
- , const int8_t eindex=-1
- #endif
- ) {
- #if ENABLED(DUAL_X_CARRIAGE) || E_MANUAL > 1
- #if E_MANUAL > 1
- if (axis == E_AXIS)
- #endif
- manual_move_e_index = eindex >= 0 ? eindex : active_extruder;
- #endif
- manual_move_start_time = millis() + (move_menu_scale < 0.99f ? 0UL : 250UL); // delay for bigger moves
- manual_move_axis = (int8_t)axis;
- }
-
- /**
- *
- * "Motion" > "Move Axis" submenu
- *
- */
-
- void _lcd_move_xyz(PGM_P name, AxisEnum axis) {
- if (use_click()) { return lcd_goto_previous_menu_no_defer(); }
- ENCODER_DIRECTION_NORMAL();
- if (encoderPosition && !processing_manual_move) {
-
- // Start with no limits to movement
- float min = current_position[axis] - 1000,
- max = current_position[axis] + 1000;
-
- // Limit to software endstops, if enabled
- #if ENABLED(MIN_SOFTWARE_ENDSTOPS) || ENABLED(MAX_SOFTWARE_ENDSTOPS)
- if (soft_endstops_enabled) switch (axis) {
- case X_AXIS:
- #if ENABLED(MIN_SOFTWARE_ENDSTOP_X)
- min = soft_endstop_min[X_AXIS];
- #endif
- #if ENABLED(MAX_SOFTWARE_ENDSTOP_X)
- max = soft_endstop_max[X_AXIS];
- #endif
- break;
- case Y_AXIS:
- #if ENABLED(MIN_SOFTWARE_ENDSTOP_Y)
- min = soft_endstop_min[Y_AXIS];
- #endif
- #if ENABLED(MAX_SOFTWARE_ENDSTOP_Y)
- max = soft_endstop_max[Y_AXIS];
- #endif
- break;
- case Z_AXIS:
- #if ENABLED(MIN_SOFTWARE_ENDSTOP_Z)
- min = soft_endstop_min[Z_AXIS];
- #endif
- #if ENABLED(MAX_SOFTWARE_ENDSTOP_Z)
- max = soft_endstop_max[Z_AXIS];
- #endif
- default: break;
- }
- #endif // MIN_SOFTWARE_ENDSTOPS || MAX_SOFTWARE_ENDSTOPS
-
- // Delta limits XY based on the current offset from center
- // This assumes the center is 0,0
- #if ENABLED(DELTA)
- if (axis != Z_AXIS) {
- max = SQRT(sq((float)(DELTA_PRINTABLE_RADIUS)) - sq(current_position[Y_AXIS - axis])); // (Y_AXIS - axis) == the other axis
- min = -max;
- }
- #endif
-
- // Get the new position
- const float diff = float((int32_t)encoderPosition) * move_menu_scale;
- #if IS_KINEMATIC
- manual_move_offset += diff;
- if ((int32_t)encoderPosition < 0)
- NOLESS(manual_move_offset, min - current_position[axis]);
- else
- NOMORE(manual_move_offset, max - current_position[axis]);
- #else
- current_position[axis] += diff;
- if ((int32_t)encoderPosition < 0)
- NOLESS(current_position[axis], min);
- else
- NOMORE(current_position[axis], max);
- #endif
-
- manual_move_to_current(axis);
- lcdDrawUpdate = LCDVIEW_REDRAW_NOW;
- }
- encoderPosition = 0;
- if (lcdDrawUpdate) {
- const float pos = NATIVE_TO_LOGICAL(processing_manual_move ? destination[axis] : current_position[axis]
- #if IS_KINEMATIC
- + manual_move_offset
- #endif
- , axis);
- lcd_implementation_drawedit(name, move_menu_scale >= 0.1f ? ftostr41sign(pos) : ftostr43sign(pos));
- }
- }
- void lcd_move_x() { _lcd_move_xyz(PSTR(MSG_MOVE_X), X_AXIS); }
- void lcd_move_y() { _lcd_move_xyz(PSTR(MSG_MOVE_Y), Y_AXIS); }
- void lcd_move_z() { _lcd_move_xyz(PSTR(MSG_MOVE_Z), Z_AXIS); }
- void _lcd_move_e(
- #if E_MANUAL > 1
- const int8_t eindex=-1
- #endif
- ) {
- if (use_click()) { return lcd_goto_previous_menu_no_defer(); }
- ENCODER_DIRECTION_NORMAL();
- if (encoderPosition) {
- if (!processing_manual_move) {
- const float diff = float((int32_t)encoderPosition) * move_menu_scale;
- #if IS_KINEMATIC
- manual_move_offset += diff;
- #else
- current_position[E_AXIS] += diff;
- #endif
- manual_move_to_current(E_AXIS
- #if E_MANUAL > 1
- , eindex
- #endif
- );
- lcdDrawUpdate = LCDVIEW_REDRAW_NOW;
- }
- encoderPosition = 0;
- }
- if (lcdDrawUpdate) {
- PGM_P pos_label;
- #if E_MANUAL == 1
- pos_label = PSTR(MSG_MOVE_E);
- #else
- switch (eindex) {
- default: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E1); break;
- case 1: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E2); break;
- #if E_MANUAL > 2
- case 2: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E3); break;
- #if E_MANUAL > 3
- case 3: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E4); break;
- #if E_MANUAL > 4
- case 4: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E5); break;
- #if E_MANUAL > 5
- case 5: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E6); break;
- #endif // E_MANUAL > 5
- #endif // E_MANUAL > 4
- #endif // E_MANUAL > 3
- #endif // E_MANUAL > 2
- }
- #endif // E_MANUAL > 1
- lcd_implementation_drawedit(pos_label, ftostr41sign(current_position[E_AXIS]
- #if IS_KINEMATIC
- + manual_move_offset
- #endif
- #if ENABLED(MANUAL_E_MOVES_RELATIVE)
- - manual_move_e_origin
- #endif
- ));
- }
- }
-
- void lcd_move_e() { _lcd_move_e(); }
- #if E_MANUAL > 1
- void lcd_move_e0() { _lcd_move_e(0); }
- void lcd_move_e1() { _lcd_move_e(1); }
- #if E_MANUAL > 2
- void lcd_move_e2() { _lcd_move_e(2); }
- #if E_MANUAL > 3
- void lcd_move_e3() { _lcd_move_e(3); }
- #if E_MANUAL > 4
- void lcd_move_e4() { _lcd_move_e(4); }
- #if E_MANUAL > 5
- void lcd_move_e5() { _lcd_move_e(5); }
- #endif // E_MANUAL > 5
- #endif // E_MANUAL > 4
- #endif // E_MANUAL > 3
- #endif // E_MANUAL > 2
- #endif // E_MANUAL > 1
-
- /**
- *
- * "Motion" > "Move Xmm" > "Move XYZ" submenu
- *
- */
-
- screenFunc_t _manual_move_func_ptr;
-
- void _goto_manual_move(const float scale) {
- defer_return_to_status = true;
- move_menu_scale = scale;
- lcd_goto_screen(_manual_move_func_ptr);
- }
- void lcd_move_menu_10mm() { _goto_manual_move(10); }
- void lcd_move_menu_1mm() { _goto_manual_move( 1); }
- void lcd_move_menu_01mm() { _goto_manual_move( 0.1f); }
-
- void _lcd_move_distance_menu(const AxisEnum axis, const screenFunc_t func, const int8_t eindex=-1) {
- _manual_move_func_ptr = func;
- START_MENU();
- if (LCD_HEIGHT >= 4) {
- switch (axis) {
- case X_AXIS:
- STATIC_ITEM(MSG_MOVE_X, true, true); break;
- case Y_AXIS:
- STATIC_ITEM(MSG_MOVE_Y, true, true); break;
- case Z_AXIS:
- STATIC_ITEM(MSG_MOVE_Z, true, true); break;
- default:
- #if ENABLED(MANUAL_E_MOVES_RELATIVE)
- manual_move_e_origin = current_position[E_AXIS];
- #endif
- STATIC_ITEM(MSG_MOVE_E, true, true);
- break;
- }
- }
- #if ENABLED(PREVENT_COLD_EXTRUSION)
- if (axis == E_AXIS && thermalManager.tooColdToExtrude(eindex >= 0 ? eindex : active_extruder))
- MENU_BACK(MSG_HOTEND_TOO_COLD);
- else
- #endif
- {
- MENU_BACK(MSG_MOVE_AXIS);
- MENU_ITEM(submenu, MSG_MOVE_10MM, lcd_move_menu_10mm);
- MENU_ITEM(submenu, MSG_MOVE_1MM, lcd_move_menu_1mm);
- MENU_ITEM(submenu, MSG_MOVE_01MM, lcd_move_menu_01mm);
- }
- END_MENU();
- }
- void lcd_move_get_x_amount() { _lcd_move_distance_menu(X_AXIS, lcd_move_x); }
- void lcd_move_get_y_amount() { _lcd_move_distance_menu(Y_AXIS, lcd_move_y); }
- void lcd_move_get_z_amount() { _lcd_move_distance_menu(Z_AXIS, lcd_move_z); }
- void lcd_move_get_e_amount() { _lcd_move_distance_menu(E_AXIS, lcd_move_e, -1); }
- #if E_MANUAL > 1
- void lcd_move_get_e0_amount() { _lcd_move_distance_menu(E_AXIS, lcd_move_e0, 0); }
- void lcd_move_get_e1_amount() { _lcd_move_distance_menu(E_AXIS, lcd_move_e1, 1); }
- #if E_MANUAL > 2
- void lcd_move_get_e2_amount() { _lcd_move_distance_menu(E_AXIS, lcd_move_e2, 2); }
- #if E_MANUAL > 3
- void lcd_move_get_e3_amount() { _lcd_move_distance_menu(E_AXIS, lcd_move_e3, 3); }
- #if E_MANUAL > 4
- void lcd_move_get_e4_amount() { _lcd_move_distance_menu(E_AXIS, lcd_move_e4, 4); }
- #if E_MANUAL > 5
- void lcd_move_get_e5_amount() { _lcd_move_distance_menu(E_AXIS, lcd_move_e5, 5); }
- #endif // E_MANUAL > 5
- #endif // E_MANUAL > 4
- #endif // E_MANUAL > 3
- #endif // E_MANUAL > 2
- #endif // E_MANUAL > 1
-
- /**
- *
- * "Motion" > "Move Axis" submenu
- *
- */
- #if ENABLED(DELTA)
- void lcd_lower_z_to_clip_height() {
- line_to_z(delta_clip_start_height);
- lcd_synchronize();
- }
- #endif
-
- void lcd_move_menu() {
- START_MENU();
- MENU_BACK(MSG_MOTION);
-
- #if HAS_SOFTWARE_ENDSTOPS && ENABLED(SOFT_ENDSTOPS_MENU_ITEM)
- MENU_ITEM_EDIT(bool, MSG_LCD_SOFT_ENDSTOPS, &soft_endstops_enabled);
- #endif
-
- #if IS_KINEMATIC || ENABLED(NO_MOTION_BEFORE_HOMING)
- const bool do_move_xyz = all_axes_homed();
- #else
- constexpr bool do_move_xyz = true;
- #endif
- if (do_move_xyz) {
- #if ENABLED(DELTA)
- const bool do_move_xy = current_position[Z_AXIS] <= delta_clip_start_height;
- #else
- constexpr bool do_move_xy = true;
- #endif
- if (do_move_xy) {
- MENU_ITEM(submenu, MSG_MOVE_X, lcd_move_get_x_amount);
- MENU_ITEM(submenu, MSG_MOVE_Y, lcd_move_get_y_amount);
- }
- #if ENABLED(DELTA)
- else
- MENU_ITEM(function, MSG_FREE_XY, lcd_lower_z_to_clip_height);
- #endif
-
- MENU_ITEM(submenu, MSG_MOVE_Z, lcd_move_get_z_amount);
- }
- else
- MENU_ITEM(gcode, MSG_AUTO_HOME, PSTR("G28"));
-
- #if ENABLED(SWITCHING_EXTRUDER) || ENABLED(SWITCHING_NOZZLE)
-
- #if EXTRUDERS == 6
- switch (active_extruder) {
- case 0: MENU_ITEM(gcode, MSG_SELECT " " MSG_E2, PSTR("T1")); break;
- case 1: MENU_ITEM(gcode, MSG_SELECT " " MSG_E1, PSTR("T0")); break;
- case 2: MENU_ITEM(gcode, MSG_SELECT " " MSG_E4, PSTR("T3")); break;
- case 3: MENU_ITEM(gcode, MSG_SELECT " " MSG_E3, PSTR("T2")); break;
- case 4: MENU_ITEM(gcode, MSG_SELECT " " MSG_E6, PSTR("T5")); break;
- case 5: MENU_ITEM(gcode, MSG_SELECT " " MSG_E5, PSTR("T4")); break;
- }
- #elif EXTRUDERS == 5 || EXTRUDERS == 4
- switch (active_extruder) {
- case 0: MENU_ITEM(gcode, MSG_SELECT " " MSG_E2, PSTR("T1")); break;
- case 1: MENU_ITEM(gcode, MSG_SELECT " " MSG_E1, PSTR("T0")); break;
- case 2: MENU_ITEM(gcode, MSG_SELECT " " MSG_E4, PSTR("T3")); break;
- case 3: MENU_ITEM(gcode, MSG_SELECT " " MSG_E3, PSTR("T2")); break;
- }
- #elif EXTRUDERS == 3
- if (active_extruder < 2) {
- if (active_extruder)
- MENU_ITEM(gcode, MSG_SELECT " " MSG_E1, PSTR("T0"));
- else
- MENU_ITEM(gcode, MSG_SELECT " " MSG_E2, PSTR("T1"));
- }
- #else
- if (active_extruder)
- MENU_ITEM(gcode, MSG_SELECT " " MSG_E1, PSTR("T0"));
- else
- MENU_ITEM(gcode, MSG_SELECT " " MSG_E2, PSTR("T1"));
- #endif
-
- #elif ENABLED(DUAL_X_CARRIAGE)
-
- if (active_extruder)
- MENU_ITEM(gcode, MSG_SELECT " " MSG_E1, PSTR("T0"));
- else
- MENU_ITEM(gcode, MSG_SELECT " " MSG_E2, PSTR("T1"));
-
- #endif
-
- #if ENABLED(SWITCHING_EXTRUDER) || ENABLED(SWITCHING_NOZZLE)
-
- // Only the current...
- MENU_ITEM(submenu, MSG_MOVE_E, lcd_move_get_e_amount);
- // ...and the non-switching
- #if E_MANUAL == 5
- MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E5, lcd_move_get_e4_amount);
- #elif E_MANUAL == 3
- MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E3, lcd_move_get_e2_amount);
- #endif
-
- #else
-
- // Independent extruders with one E-stepper per hotend
- MENU_ITEM(submenu, MSG_MOVE_E, lcd_move_get_e_amount);
- #if E_MANUAL > 1
- MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E1, lcd_move_get_e0_amount);
- MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E2, lcd_move_get_e1_amount);
- #if E_MANUAL > 2
- MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E3, lcd_move_get_e2_amount);
- #if E_MANUAL > 3
- MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E4, lcd_move_get_e3_amount);
- #if E_MANUAL > 4
- MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E5, lcd_move_get_e4_amount);
- #if E_MANUAL > 5
- MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E6, lcd_move_get_e5_amount);
- #endif // E_MANUAL > 5
- #endif // E_MANUAL > 4
- #endif // E_MANUAL > 3
- #endif // E_MANUAL > 2
- #endif // E_MANUAL > 1
-
- #endif
-
- END_MENU();
- }
-
- /**
- *
- * "Configuration" submenu
- *
- */
-
- #if HAS_LCD_CONTRAST
- void lcd_callback_set_contrast() { set_lcd_contrast(lcd_contrast); }
- #endif
-
- static void lcd_factory_settings() {
- settings.reset();
- lcd_completion_feedback();
- }
-
- #if ENABLED(EEPROM_SETTINGS) && DISABLED(SLIM_LCD_MENUS)
-
- static void lcd_init_eeprom() {
- lcd_completion_feedback(settings.init_eeprom());
- lcd_goto_previous_menu();
- }
-
- static void lcd_init_eeprom_confirm() {
- START_MENU();
- MENU_BACK(MSG_ADVANCED_SETTINGS);
- MENU_ITEM(function, MSG_INIT_EEPROM, lcd_init_eeprom);
- END_MENU();
- }
-
- #endif
-
- void lcd_configuration_menu() {
- START_MENU();
- MENU_BACK(MSG_MAIN);
-
- //
- // Debug Menu when certain options are enabled
- //
- #if HAS_DEBUG_MENU
- MENU_ITEM(submenu, MSG_DEBUG_MENU, lcd_debug_menu);
- #endif
-
- MENU_ITEM(submenu, MSG_ADVANCED_SETTINGS, lcd_advanced_settings_menu);
-
- const bool busy = printer_busy();
- if (!busy) {
- //
- // Delta Calibration
- //
- #if ENABLED(DELTA_CALIBRATION_MENU) || ENABLED(DELTA_AUTO_CALIBRATION)
- MENU_ITEM(submenu, MSG_DELTA_CALIBRATE, lcd_delta_calibrate_menu);
- #endif
-
- #if ENABLED(DUAL_X_CARRIAGE)
- MENU_ITEM(submenu, MSG_IDEX_MENU, IDEX_menu);
- #endif
-
- #if ENABLED(BLTOUCH)
- MENU_ITEM(submenu, MSG_BLTOUCH, bltouch_menu);
- #endif
- }
-
- //
- // Set single nozzle filament retract and prime length
- //
- #if EXTRUDERS > 1
- MENU_ITEM(submenu, MSG_TOOL_CHANGE, tool_change_menu);
- #endif
-
- //
- // Set Case light on/off/brightness
- //
- #if ENABLED(MENU_ITEM_CASE_LIGHT)
- if (USEABLE_HARDWARE_PWM(CASE_LIGHT_PIN))
- MENU_ITEM(submenu, MSG_CASE_LIGHT, case_light_menu);
- else
- MENU_ITEM_EDIT_CALLBACK(bool, MSG_CASE_LIGHT, (bool*)&case_light_on, update_case_light);
- #endif
-
- #if HAS_LCD_CONTRAST
- MENU_ITEM_EDIT_CALLBACK(int3, MSG_CONTRAST, &lcd_contrast, LCD_CONTRAST_MIN, LCD_CONTRAST_MAX, lcd_callback_set_contrast, true);
- #endif
- #if ENABLED(FWRETRACT)
- MENU_ITEM(submenu, MSG_RETRACT, lcd_config_retract_menu);
- #endif
- #if ENABLED(DAC_STEPPER_CURRENT)
- MENU_ITEM(submenu, MSG_DRIVE_STRENGTH, lcd_dac_menu);
- #endif
- #if HAS_MOTOR_CURRENT_PWM
- MENU_ITEM(submenu, MSG_DRIVE_STRENGTH, lcd_pwm_menu);
- #endif
-
- #if ENABLED(FILAMENT_RUNOUT_SENSOR)
- MENU_ITEM_EDIT(bool, MSG_RUNOUT_SENSOR_ENABLE, &runout.enabled);
- #endif
-
- #if DISABLED(SLIM_LCD_MENUS)
- // Preheat configurations
- MENU_ITEM(submenu, MSG_PREHEAT_1_SETTINGS, lcd_configuration_temperature_preheat_material1_settings_menu);
- MENU_ITEM(submenu, MSG_PREHEAT_2_SETTINGS, lcd_configuration_temperature_preheat_material2_settings_menu);
- #endif
-
- #if ENABLED(EEPROM_SETTINGS)
- MENU_ITEM(function, MSG_STORE_EEPROM, lcd_store_settings);
- if (!busy)
- MENU_ITEM(function, MSG_LOAD_EEPROM, lcd_load_settings);
- #endif
-
- if (!busy)
- MENU_ITEM(function, MSG_RESTORE_FAILSAFE, lcd_factory_settings);
-
- END_MENU();
- }
-
- /**
- *
- * "Temperature" submenu
- *
- */
-
- #if ENABLED(PID_AUTOTUNE_MENU)
-
- #if ENABLED(PIDTEMP)
- int16_t autotune_temp[HOTENDS] = ARRAY_BY_HOTENDS1(150);
- #endif
-
- #if ENABLED(PIDTEMPBED)
- int16_t autotune_temp_bed = 70;
- #endif
-
- void _lcd_autotune(int16_t e) {
- char cmd[30];
- sprintf_P(cmd, PSTR("M303 U1 E%i S%i"), e,
- #if HAS_PID_FOR_BOTH
- e < 0 ? autotune_temp_bed : autotune_temp[e]
- #elif ENABLED(PIDTEMPBED)
- autotune_temp_bed
- #else
- autotune_temp[e]
- #endif
- );
- lcd_enqueue_command(cmd);
- }
-
- #endif // PID_AUTOTUNE_MENU
-
- #if ENABLED(PIDTEMP)
-
- // Helpers for editing PID Ki & Kd values
- // grab the PID value out of the temp variable; scale it; then update the PID driver
- void copy_and_scalePID_i(int16_t e) {
- #if DISABLED(PID_PARAMS_PER_HOTEND) || HOTENDS == 1
- UNUSED(e);
- #endif
- PID_PARAM(Ki, e) = scalePID_i(raw_Ki);
- thermalManager.updatePID();
- }
- void copy_and_scalePID_d(int16_t e) {
- #if DISABLED(PID_PARAMS_PER_HOTEND) || HOTENDS == 1
- UNUSED(e);
- #endif
- PID_PARAM(Kd, e) = scalePID_d(raw_Kd);
- thermalManager.updatePID();
- }
- #define _DEFINE_PIDTEMP_BASE_FUNCS(N) \
- void copy_and_scalePID_i_E ## N() { copy_and_scalePID_i(N); } \
- void copy_and_scalePID_d_E ## N() { copy_and_scalePID_d(N); }
-
- #if ENABLED(PID_AUTOTUNE_MENU)
- #define DEFINE_PIDTEMP_FUNCS(N) \
- _DEFINE_PIDTEMP_BASE_FUNCS(N); \
- void lcd_autotune_callback_E ## N() { _lcd_autotune(N); } typedef void _pid_##N##_void
- #else
- #define DEFINE_PIDTEMP_FUNCS(N) _DEFINE_PIDTEMP_BASE_FUNCS(N) typedef void _pid_##N##_void
- #endif
-
- DEFINE_PIDTEMP_FUNCS(0);
- #if ENABLED(PID_PARAMS_PER_HOTEND)
- #if HOTENDS > 1
- DEFINE_PIDTEMP_FUNCS(1);
- #if HOTENDS > 2
- DEFINE_PIDTEMP_FUNCS(2);
- #if HOTENDS > 3
- DEFINE_PIDTEMP_FUNCS(3);
- #if HOTENDS > 4
- DEFINE_PIDTEMP_FUNCS(4);
- #if HOTENDS > 5
- DEFINE_PIDTEMP_FUNCS(5);
- #endif // HOTENDS > 5
- #endif // HOTENDS > 4
- #endif // HOTENDS > 3
- #endif // HOTENDS > 2
- #endif // HOTENDS > 1
- #endif // PID_PARAMS_PER_HOTEND
-
- #endif // PIDTEMP
-
- /**
- *
- * "Temperature" submenu
- *
- */
- void lcd_temperature_menu() {
- START_MENU();
- MENU_BACK(MSG_MAIN);
-
- //
- // Nozzle:
- // Nozzle [1-5]:
- //
- #if HOTENDS == 1
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE, &thermalManager.target_temperature[0], 0, HEATER_0_MAXTEMP - 15, watch_temp_callback_E0);
- #else // HOTENDS > 1
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N1, &thermalManager.target_temperature[0], 0, HEATER_0_MAXTEMP - 15, watch_temp_callback_E0);
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N2, &thermalManager.target_temperature[1], 0, HEATER_1_MAXTEMP - 15, watch_temp_callback_E1);
- #if HOTENDS > 2
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N3, &thermalManager.target_temperature[2], 0, HEATER_2_MAXTEMP - 15, watch_temp_callback_E2);
- #if HOTENDS > 3
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N4, &thermalManager.target_temperature[3], 0, HEATER_3_MAXTEMP - 15, watch_temp_callback_E3);
- #if HOTENDS > 4
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N5, &thermalManager.target_temperature[4], 0, HEATER_4_MAXTEMP - 15, watch_temp_callback_E4);
- #if HOTENDS > 5
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N6, &thermalManager.target_temperature[5], 0, HEATER_5_MAXTEMP - 15, watch_temp_callback_E5);
- #endif // HOTENDS > 5
- #endif // HOTENDS > 4
- #endif // HOTENDS > 3
- #endif // HOTENDS > 2
- #endif // HOTENDS > 1
-
- //
- // Bed:
- //
- #if HAS_HEATED_BED
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_BED, &thermalManager.target_temperature_bed, 0, BED_MAXTEMP - 15, watch_temp_callback_bed);
- #endif
-
- //
- // Fan Speed:
- //
- #if FAN_COUNT > 0
- #if HAS_FAN0
- MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_FAN_SPEED FAN_SPEED_1_SUFFIX, &fan_speed[0], 0, 255);
- #if ENABLED(EXTRA_FAN_SPEED)
- MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_EXTRA_FAN_SPEED FAN_SPEED_1_SUFFIX, &new_fan_speed[0], 3, 255);
- #endif
- #endif
- #if HAS_FAN1
- MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_FAN_SPEED " 2", &fan_speed[1], 0, 255);
- #if ENABLED(EXTRA_FAN_SPEED)
- MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_EXTRA_FAN_SPEED " 2", &new_fan_speed[1], 3, 255);
- #endif
- #endif
- #if HAS_FAN2
- MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_FAN_SPEED " 3", &fan_speed[2], 0, 255);
- #if ENABLED(EXTRA_FAN_SPEED)
- MENU_MULTIPLIER_ITEM_EDIT(int8, MSG_EXTRA_FAN_SPEED " 3", &new_fan_speed[2], 3, 255);
- #endif
- #endif
- #endif // FAN_COUNT > 0
-
- #if HAS_TEMP_HOTEND
-
- //
- // Cooldown
- //
- bool has_heat = false;
- HOTEND_LOOP() if (thermalManager.target_temperature[HOTEND_INDEX]) { has_heat = true; break; }
- #if HAS_TEMP_BED
- if (thermalManager.target_temperature_bed) has_heat = true;
- #endif
- if (has_heat) MENU_ITEM(function, MSG_COOLDOWN, lcd_cooldown);
-
- //
- // Preheat for Material 1 and 2
- //
- #if TEMP_SENSOR_1 != 0 || TEMP_SENSOR_2 != 0 || TEMP_SENSOR_3 != 0 || TEMP_SENSOR_4 != 0 || HAS_HEATED_BED
- MENU_ITEM(submenu, MSG_PREHEAT_1, lcd_preheat_m1_menu);
- MENU_ITEM(submenu, MSG_PREHEAT_2, lcd_preheat_m2_menu);
- #else
- MENU_ITEM(function, MSG_PREHEAT_1, lcd_preheat_m1_e0_only);
- MENU_ITEM(function, MSG_PREHEAT_2, lcd_preheat_m2_e0_only);
- #endif
-
- #endif // HAS_TEMP_HOTEND
-
- END_MENU();
- }
-
- /**
- *
- * "Advanced Settings" -> "Temperature" submenu
- *
- */
- void lcd_advanced_temperature_menu() {
- START_MENU();
- MENU_BACK(MSG_ADVANCED_SETTINGS);
- //
- // Autotemp, Min, Max, Fact
- //
- #if ENABLED(AUTOTEMP) && HAS_TEMP_HOTEND
- MENU_ITEM_EDIT(bool, MSG_AUTOTEMP, &planner.autotemp_enabled);
- MENU_ITEM_EDIT(float3, MSG_MIN, &planner.autotemp_min, 0, float(HEATER_0_MAXTEMP) - 15);
- MENU_ITEM_EDIT(float3, MSG_MAX, &planner.autotemp_max, 0, float(HEATER_0_MAXTEMP) - 15);
- MENU_ITEM_EDIT(float52, MSG_FACTOR, &planner.autotemp_factor, 0, 1);
- #endif
-
- //
- // PID-P, PID-I, PID-D, PID-C, PID Autotune
- // PID-P E1, PID-I E1, PID-D E1, PID-C E1, PID Autotune E1
- // PID-P E2, PID-I E2, PID-D E2, PID-C E2, PID Autotune E2
- // PID-P E3, PID-I E3, PID-D E3, PID-C E3, PID Autotune E3
- // PID-P E4, PID-I E4, PID-D E4, PID-C E4, PID Autotune E4
- // PID-P E5, PID-I E5, PID-D E5, PID-C E5, PID Autotune E5
- //
- #if ENABLED(PIDTEMP)
-
- #define _PID_BASE_MENU_ITEMS(ELABEL, eindex) \
- raw_Ki = unscalePID_i(PID_PARAM(Ki, eindex)); \
- raw_Kd = unscalePID_d(PID_PARAM(Kd, eindex)); \
- MENU_ITEM_EDIT(float52sign, MSG_PID_P ELABEL, &PID_PARAM(Kp, eindex), 1, 9990); \
- MENU_ITEM_EDIT_CALLBACK(float52sign, MSG_PID_I ELABEL, &raw_Ki, 0.01f, 9990, copy_and_scalePID_i_E ## eindex); \
- MENU_ITEM_EDIT_CALLBACK(float52sign, MSG_PID_D ELABEL, &raw_Kd, 1, 9990, copy_and_scalePID_d_E ## eindex)
-
- #if ENABLED(PID_EXTRUSION_SCALING)
- #define _PID_MENU_ITEMS(ELABEL, eindex) \
- _PID_BASE_MENU_ITEMS(ELABEL, eindex); \
- MENU_ITEM_EDIT(float3, MSG_PID_C ELABEL, &PID_PARAM(Kc, eindex), 1, 9990)
- #else
- #define _PID_MENU_ITEMS(ELABEL, eindex) _PID_BASE_MENU_ITEMS(ELABEL, eindex)
- #endif
-
- #if ENABLED(PID_AUTOTUNE_MENU)
- #define PID_MENU_ITEMS(ELABEL, eindex) \
- _PID_MENU_ITEMS(ELABEL, eindex); \
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_PID_AUTOTUNE ELABEL, &autotune_temp[eindex], 150, heater_maxtemp[eindex] - 15, lcd_autotune_callback_E ## eindex)
- #else
- #define PID_MENU_ITEMS(ELABEL, eindex) _PID_MENU_ITEMS(ELABEL, eindex)
- #endif
-
- #if ENABLED(PID_PARAMS_PER_HOTEND) && HOTENDS > 1
- PID_MENU_ITEMS(" " MSG_E1, 0);
- PID_MENU_ITEMS(" " MSG_E2, 1);
- #if HOTENDS > 2
- PID_MENU_ITEMS(" " MSG_E3, 2);
- #if HOTENDS > 3
- PID_MENU_ITEMS(" " MSG_E4, 3);
- #if HOTENDS > 4
- PID_MENU_ITEMS(" " MSG_E5, 4);
- #if HOTENDS > 5
- PID_MENU_ITEMS(" " MSG_E6, 5);
- #endif // HOTENDS > 5
- #endif // HOTENDS > 4
- #endif // HOTENDS > 3
- #endif // HOTENDS > 2
- #else // !PID_PARAMS_PER_HOTEND || HOTENDS == 1
- PID_MENU_ITEMS("", 0);
- #endif // !PID_PARAMS_PER_HOTEND || HOTENDS == 1
-
- #endif // PIDTEMP
-
- END_MENU();
- }
-
- #if DISABLED(SLIM_LCD_MENUS)
-
- void _lcd_configuration_temperature_preheat_settings_menu(const uint8_t material) {
- #if HOTENDS > 5
- #define MINTEMP_ALL MIN(HEATER_0_MINTEMP, HEATER_1_MINTEMP, HEATER_2_MINTEMP, HEATER_3_MINTEMP, HEATER_4_MINTEMP, HEATER_5_MINTEMP)
- #define MAXTEMP_ALL MAX(HEATER_0_MAXTEMP, HEATER_1_MAXTEMP, HEATER_2_MAXTEMP, HEATER_3_MAXTEMP, HEATER_4_MAXTEMP, HEATER_5_MAXTEMP)
- #elif HOTENDS > 4
- #define MINTEMP_ALL MIN(HEATER_0_MINTEMP, HEATER_1_MINTEMP, HEATER_2_MINTEMP, HEATER_3_MINTEMP, HEATER_4_MINTEMP)
- #define MAXTEMP_ALL MAX(HEATER_0_MAXTEMP, HEATER_1_MAXTEMP, HEATER_2_MAXTEMP, HEATER_3_MAXTEMP, HEATER_4_MAXTEMP)
- #elif HOTENDS > 3
- #define MINTEMP_ALL MIN(HEATER_0_MINTEMP, HEATER_1_MINTEMP, HEATER_2_MINTEMP, HEATER_3_MINTEMP)
- #define MAXTEMP_ALL MAX(HEATER_0_MAXTEMP, HEATER_1_MAXTEMP, HEATER_2_MAXTEMP, HEATER_3_MAXTEMP)
- #elif HOTENDS > 2
- #define MINTEMP_ALL MIN(HEATER_0_MINTEMP, HEATER_1_MINTEMP, HEATER_2_MINTEMP)
- #define MAXTEMP_ALL MAX(HEATER_0_MAXTEMP, HEATER_1_MAXTEMP, HEATER_2_MAXTEMP)
- #elif HOTENDS > 1
- #define MINTEMP_ALL MIN(HEATER_0_MINTEMP, HEATER_1_MINTEMP)
- #define MAXTEMP_ALL MAX(HEATER_0_MAXTEMP, HEATER_1_MAXTEMP)
- #else
- #define MINTEMP_ALL HEATER_0_MINTEMP
- #define MAXTEMP_ALL HEATER_0_MAXTEMP
- #endif
- START_MENU();
- MENU_BACK(MSG_CONFIGURATION);
- MENU_ITEM_EDIT(int8, MSG_FAN_SPEED, &lcd_preheat_fan_speed[material], 0, 255);
- #if HAS_TEMP_HOTEND
- MENU_ITEM_EDIT(int3, MSG_NOZZLE, &lcd_preheat_hotend_temp[material], MINTEMP_ALL, MAXTEMP_ALL - 15);
- #endif
- #if HAS_HEATED_BED
- MENU_ITEM_EDIT(int3, MSG_BED, &lcd_preheat_bed_temp[material], BED_MINTEMP, BED_MAXTEMP - 15);
- #endif
- #if ENABLED(EEPROM_SETTINGS)
- MENU_ITEM(function, MSG_STORE_EEPROM, lcd_store_settings);
- #endif
- END_MENU();
- }
-
- /**
- *
- * "Temperature" > "Preheat Material 1 conf" submenu
- *
- */
- void lcd_configuration_temperature_preheat_material1_settings_menu() { _lcd_configuration_temperature_preheat_settings_menu(0); }
-
- /**
- *
- * "Temperature" > "Preheat Material 2 conf" submenu
- *
- */
- void lcd_configuration_temperature_preheat_material2_settings_menu() { _lcd_configuration_temperature_preheat_settings_menu(1); }
-
- void _reset_acceleration_rates() { planner.reset_acceleration_rates(); }
- #if ENABLED(DISTINCT_E_FACTORS)
- void _reset_e_acceleration_rate(const uint8_t e) { if (e == active_extruder) _reset_acceleration_rates(); }
- void _reset_e0_acceleration_rate() { _reset_e_acceleration_rate(0); }
- void _reset_e1_acceleration_rate() { _reset_e_acceleration_rate(1); }
- #if E_STEPPERS > 2
- void _reset_e2_acceleration_rate() { _reset_e_acceleration_rate(2); }
- #if E_STEPPERS > 3
- void _reset_e3_acceleration_rate() { _reset_e_acceleration_rate(3); }
- #if E_STEPPERS > 4
- void _reset_e4_acceleration_rate() { _reset_e_acceleration_rate(4); }
- #if E_STEPPERS > 5
- void _reset_e5_acceleration_rate() { _reset_e_acceleration_rate(5); }
- #endif // E_STEPPERS > 5
- #endif // E_STEPPERS > 4
- #endif // E_STEPPERS > 3
- #endif // E_STEPPERS > 2
- #endif
-
- void _planner_refresh_positioning() { planner.refresh_positioning(); }
- #if ENABLED(DISTINCT_E_FACTORS)
- void _planner_refresh_e_positioning(const uint8_t e) {
- if (e == active_extruder)
- _planner_refresh_positioning();
- else
- planner.steps_to_mm[E_AXIS + e] = 1.0f / planner.settings.axis_steps_per_mm[E_AXIS + e];
- }
- void _planner_refresh_e0_positioning() { _planner_refresh_e_positioning(0); }
- void _planner_refresh_e1_positioning() { _planner_refresh_e_positioning(1); }
- #if E_STEPPERS > 2
- void _planner_refresh_e2_positioning() { _planner_refresh_e_positioning(2); }
- #if E_STEPPERS > 3
- void _planner_refresh_e3_positioning() { _planner_refresh_e_positioning(3); }
- #if E_STEPPERS > 4
- void _planner_refresh_e4_positioning() { _planner_refresh_e_positioning(4); }
- #if E_STEPPERS > 5
- void _planner_refresh_e5_positioning() { _planner_refresh_e_positioning(5); }
- #endif // E_STEPPERS > 5
- #endif // E_STEPPERS > 4
- #endif // E_STEPPERS > 3
- #endif // E_STEPPERS > 2
- #endif
-
- // M203 / M205 Velocity options
- void lcd_advanced_velocity_menu() {
- START_MENU();
- MENU_BACK(MSG_ADVANCED_SETTINGS);
-
- // M203 Max Feedrate
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_VMAX MSG_A, &planner.settings.max_feedrate_mm_s[A_AXIS], 1, 999);
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_VMAX MSG_B, &planner.settings.max_feedrate_mm_s[B_AXIS], 1, 999);
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_VMAX MSG_C, &planner.settings.max_feedrate_mm_s[C_AXIS], 1, 999);
-
- #if ENABLED(DISTINCT_E_FACTORS)
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_VMAX MSG_E, &planner.settings.max_feedrate_mm_s[E_AXIS + active_extruder], 1, 999);
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_VMAX MSG_E1, &planner.settings.max_feedrate_mm_s[E_AXIS], 1, 999);
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_VMAX MSG_E2, &planner.settings.max_feedrate_mm_s[E_AXIS + 1], 1, 999);
- #if E_STEPPERS > 2
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_VMAX MSG_E3, &planner.settings.max_feedrate_mm_s[E_AXIS + 2], 1, 999);
- #if E_STEPPERS > 3
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_VMAX MSG_E4, &planner.settings.max_feedrate_mm_s[E_AXIS + 3], 1, 999);
- #if E_STEPPERS > 4
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_VMAX MSG_E5, &planner.settings.max_feedrate_mm_s[E_AXIS + 4], 1, 999);
- #if E_STEPPERS > 5
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_VMAX MSG_E6, &planner.settings.max_feedrate_mm_s[E_AXIS + 5], 1, 999);
- #endif // E_STEPPERS > 5
- #endif // E_STEPPERS > 4
- #endif // E_STEPPERS > 3
- #endif // E_STEPPERS > 2
- #else
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_VMAX MSG_E, &planner.settings.max_feedrate_mm_s[E_AXIS], 1, 999);
- #endif
-
- // M205 S Min Feedrate
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_VMIN, &planner.settings.min_feedrate_mm_s, 0, 999);
-
- // M205 T Min Travel Feedrate
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_VTRAV_MIN, &planner.settings.min_travel_feedrate_mm_s, 0, 999);
-
- END_MENU();
- }
-
- // M201 / M204 Accelerations
- void lcd_advanced_acceleration_menu() {
- START_MENU();
- MENU_BACK(MSG_ADVANCED_SETTINGS);
-
- // M204 P Acceleration
- MENU_MULTIPLIER_ITEM_EDIT(float5, MSG_ACC, &planner.settings.acceleration, 10, 99000);
-
- // M204 R Retract Acceleration
- MENU_MULTIPLIER_ITEM_EDIT(float5, MSG_A_RETRACT, &planner.settings.retract_acceleration, 100, 99000);
-
- // M204 T Travel Acceleration
- MENU_MULTIPLIER_ITEM_EDIT(float5, MSG_A_TRAVEL, &planner.settings.travel_acceleration, 100, 99000);
-
- // M201 settings
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_A, &planner.settings.max_acceleration_mm_per_s2[A_AXIS], 100, 99000, _reset_acceleration_rates);
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_B, &planner.settings.max_acceleration_mm_per_s2[B_AXIS], 100, 99000, _reset_acceleration_rates);
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_C, &planner.settings.max_acceleration_mm_per_s2[C_AXIS], 10, 99000, _reset_acceleration_rates);
-
- #if ENABLED(DISTINCT_E_FACTORS)
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_E, &planner.settings.max_acceleration_mm_per_s2[E_AXIS + active_extruder], 100, 99000, _reset_acceleration_rates);
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_E1, &planner.settings.max_acceleration_mm_per_s2[E_AXIS], 100, 99000, _reset_e0_acceleration_rate);
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_E2, &planner.settings.max_acceleration_mm_per_s2[E_AXIS + 1], 100, 99000, _reset_e1_acceleration_rate);
- #if E_STEPPERS > 2
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_E3, &planner.settings.max_acceleration_mm_per_s2[E_AXIS + 2], 100, 99000, _reset_e2_acceleration_rate);
- #if E_STEPPERS > 3
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_E4, &planner.settings.max_acceleration_mm_per_s2[E_AXIS + 3], 100, 99000, _reset_e3_acceleration_rate);
- #if E_STEPPERS > 4
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_E5, &planner.settings.max_acceleration_mm_per_s2[E_AXIS + 4], 100, 99000, _reset_e4_acceleration_rate);
- #if E_STEPPERS > 5
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_E6, &planner.settings.max_acceleration_mm_per_s2[E_AXIS + 5], 100, 99000, _reset_e5_acceleration_rate);
- #endif // E_STEPPERS > 5
- #endif // E_STEPPERS > 4
- #endif // E_STEPPERS > 3
- #endif // E_STEPPERS > 2
- #else
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_E, &planner.settings.max_acceleration_mm_per_s2[E_AXIS], 100, 99000, _reset_acceleration_rates);
- #endif
-
- END_MENU();
- }
-
- // M205 Jerk
- void lcd_advanced_jerk_menu() {
- START_MENU();
- MENU_BACK(MSG_ADVANCED_SETTINGS);
-
- #if ENABLED(JUNCTION_DEVIATION)
- #if ENABLED(LIN_ADVANCE)
- MENU_ITEM_EDIT_CALLBACK(float43, MSG_JUNCTION_DEVIATION, &planner.junction_deviation_mm, 0.01f, 0.3f, planner.recalculate_max_e_jerk);
- #else
- MENU_ITEM_EDIT(float43, MSG_JUNCTION_DEVIATION, &planner.junction_deviation_mm, 0.01f, 0.3f);
- #endif
- #endif
- #if HAS_CLASSIC_JERK
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_VA_JERK, &planner.max_jerk[A_AXIS], 1, 990);
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_VB_JERK, &planner.max_jerk[B_AXIS], 1, 990);
- #if ENABLED(DELTA)
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_VC_JERK, &planner.max_jerk[C_AXIS], 1, 990);
- #else
- MENU_MULTIPLIER_ITEM_EDIT(float52sign, MSG_VC_JERK, &planner.max_jerk[C_AXIS], 0.1f, 990);
- #endif
- #if DISABLED(JUNCTION_DEVIATION) || DISABLED(LIN_ADVANCE)
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_VE_JERK, &planner.max_jerk[E_AXIS], 1, 990);
- #endif
- #endif
-
- END_MENU();
- }
-
- // M92 Steps-per-mm
- void lcd_advanced_steps_per_mm_menu() {
- START_MENU();
- MENU_BACK(MSG_ADVANCED_SETTINGS);
-
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float62, MSG_ASTEPS, &planner.settings.axis_steps_per_mm[A_AXIS], 5, 9999, _planner_refresh_positioning);
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float62, MSG_BSTEPS, &planner.settings.axis_steps_per_mm[B_AXIS], 5, 9999, _planner_refresh_positioning);
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float62, MSG_CSTEPS, &planner.settings.axis_steps_per_mm[C_AXIS], 5, 9999, _planner_refresh_positioning);
-
- #if ENABLED(DISTINCT_E_FACTORS)
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float62, MSG_ESTEPS, &planner.settings.axis_steps_per_mm[E_AXIS + active_extruder], 5, 9999, _planner_refresh_positioning);
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float62, MSG_E1STEPS, &planner.settings.axis_steps_per_mm[E_AXIS], 5, 9999, _planner_refresh_e0_positioning);
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float62, MSG_E2STEPS, &planner.settings.axis_steps_per_mm[E_AXIS + 1], 5, 9999, _planner_refresh_e1_positioning);
- #if E_STEPPERS > 2
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float62, MSG_E3STEPS, &planner.settings.axis_steps_per_mm[E_AXIS + 2], 5, 9999, _planner_refresh_e2_positioning);
- #if E_STEPPERS > 3
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float62, MSG_E4STEPS, &planner.settings.axis_steps_per_mm[E_AXIS + 3], 5, 9999, _planner_refresh_e3_positioning);
- #if E_STEPPERS > 4
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float62, MSG_E5STEPS, &planner.settings.axis_steps_per_mm[E_AXIS + 4], 5, 9999, _planner_refresh_e4_positioning);
- #if E_STEPPERS > 5
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float62, MSG_E6STEPS, &planner.settings.axis_steps_per_mm[E_AXIS + 5], 5, 9999, _planner_refresh_e5_positioning);
- #endif // E_STEPPERS > 5
- #endif // E_STEPPERS > 4
- #endif // E_STEPPERS > 3
- #endif // E_STEPPERS > 2
- #else
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float62, MSG_ESTEPS, &planner.settings.axis_steps_per_mm[E_AXIS], 5, 9999, _planner_refresh_positioning);
- #endif
-
- END_MENU();
- }
-
- #endif // !SLIM_LCD_MENUS
-
- /**
- *
- * "Advanced Settings" submenu
- *
- */
-
- #if HAS_M206_COMMAND
- /**
- * Set the home offset based on the current_position
- */
- void lcd_set_home_offsets() {
- // M428 Command
- enqueue_and_echo_commands_P(PSTR("M428"));
- lcd_return_to_status();
- }
- #endif
-
- #if ENABLED(SD_FIRMWARE_UPDATE)
- /**
- * Toggle the SD Firmware Update state in EEPROM
- */
- static void _lcd_toggle_sd_update() {
- const bool new_state = !settings.sd_update_status();
- lcd_completion_feedback(settings.set_sd_update_status(new_state));
- lcd_return_to_status();
- if (new_state) LCD_MESSAGEPGM(MSG_RESET_PRINTER); else lcd_reset_status();
- }
- #endif
-
- void lcd_advanced_settings_menu() {
- START_MENU();
- MENU_BACK(MSG_CONFIGURATION);
-
- #if ENABLED(BABYSTEP_ZPROBE_OFFSET)
- MENU_ITEM(submenu, MSG_ZPROBE_ZOFFSET, lcd_babystep_zoffset);
- #elif HAS_BED_PROBE
- MENU_ITEM_EDIT(float52, MSG_ZPROBE_ZOFFSET, &zprobe_zoffset, Z_PROBE_OFFSET_RANGE_MIN, Z_PROBE_OFFSET_RANGE_MAX);
- #endif
-
- #if DISABLED(SLIM_LCD_MENUS)
-
- #if HAS_M206_COMMAND
- //
- // Set Home Offsets
- //
- MENU_ITEM(function, MSG_SET_HOME_OFFSETS, lcd_set_home_offsets);
- #endif
-
- // M203 / M205 - Feedrate items
- MENU_ITEM(submenu, MSG_VELOCITY, lcd_advanced_velocity_menu);
-
- // M201 - Acceleration items
- MENU_ITEM(submenu, MSG_ACCELERATION, lcd_advanced_acceleration_menu);
-
- // M205 - Max Jerk
- MENU_ITEM(submenu, MSG_JERK, lcd_advanced_jerk_menu);
-
- if (!printer_busy()) {
- // M92 - Steps Per mm
- MENU_ITEM(submenu, MSG_STEPS_PER_MM, lcd_advanced_steps_per_mm_menu);
- }
-
- #endif // !SLIM_LCD_MENUS
-
- MENU_ITEM(submenu, MSG_TEMPERATURE, lcd_advanced_temperature_menu);
-
- #if DISABLED(NO_VOLUMETRICS) || ENABLED(ADVANCED_PAUSE_FEATURE)
- MENU_ITEM(submenu, MSG_FILAMENT, lcd_advanced_filament_menu);
- #elif ENABLED(LIN_ADVANCE)
- #if EXTRUDERS == 1
- MENU_ITEM_EDIT(float52, MSG_ADVANCE_K, &planner.extruder_advance_K[0], 0, 999);
- #elif EXTRUDERS > 1
- MENU_ITEM_EDIT(float52, MSG_ADVANCE_K MSG_E1, &planner.extruder_advance_K[0], 0, 999);
- MENU_ITEM_EDIT(float52, MSG_ADVANCE_K MSG_E2, &planner.extruder_advance_K[1], 0, 999);
- #if EXTRUDERS > 2
- MENU_ITEM_EDIT(float52, MSG_ADVANCE_K MSG_E3, &planner.extruder_advance_K[2], 0, 999);
- #if EXTRUDERS > 3
- MENU_ITEM_EDIT(float52, MSG_ADVANCE_K MSG_E4, &planner.extruder_advance_K[3], 0, 999);
- #if EXTRUDERS > 4
- MENU_ITEM_EDIT(float52, MSG_ADVANCE_K MSG_E5, &planner.extruder_advance_K[4], 0, 999);
- #if EXTRUDERS > 5
- MENU_ITEM_EDIT(float52, MSG_ADVANCE_K MSG_E6, &planner.extruder_advance_K[5], 0, 999);
- #endif // EXTRUDERS > 5
- #endif // EXTRUDERS > 4
- #endif // EXTRUDERS > 3
- #endif // EXTRUDERS > 2
- #endif // EXTRUDERS > 1
- #endif
-
- // M540 S - Abort on endstop hit when SD printing
- #if ENABLED(ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED)
- MENU_ITEM_EDIT(bool, MSG_ENDSTOP_ABORT, &planner.abort_on_endstop_hit);
- #endif
-
- //
- // BLTouch Self-Test and Reset
- //
- #if ENABLED(BLTOUCH)
- MENU_ITEM(gcode, MSG_BLTOUCH_SELFTEST, PSTR("M280 P" STRINGIFY(Z_PROBE_SERVO_NR) " S" STRINGIFY(BLTOUCH_SELFTEST)));
- if (!endstops.z_probe_enabled && TEST_BLTOUCH())
- MENU_ITEM(gcode, MSG_BLTOUCH_RESET, PSTR("M280 P" STRINGIFY(Z_PROBE_SERVO_NR) " S" STRINGIFY(BLTOUCH_RESET)));
- #endif
-
- #if ENABLED(SD_FIRMWARE_UPDATE)
- bool sd_update_state = settings.sd_update_status();
- MENU_ITEM_EDIT_CALLBACK(bool, MSG_SD_UPDATE, &sd_update_state, _lcd_toggle_sd_update);
- #endif
-
- #if ENABLED(EEPROM_SETTINGS) && DISABLED(SLIM_LCD_MENUS)
- MENU_ITEM(submenu, MSG_INIT_EEPROM, lcd_init_eeprom_confirm);
- #endif
-
- END_MENU();
- }
-
- #if DISABLED(NO_VOLUMETRICS) || ENABLED(ADVANCED_PAUSE_FEATURE)
- /**
- *
- * "Advanced Settings" > "Filament" submenu
- *
- */
- void lcd_advanced_filament_menu() {
- START_MENU();
- MENU_BACK(MSG_ADVANCED_SETTINGS);
-
- #if ENABLED(LIN_ADVANCE)
- #if EXTRUDERS == 1
- MENU_ITEM_EDIT(float52, MSG_ADVANCE_K, &planner.extruder_advance_K[0], 0, 999);
- #elif EXTRUDERS > 1
- MENU_ITEM_EDIT(float52, MSG_ADVANCE_K MSG_E1, &planner.extruder_advance_K[0], 0, 999);
- MENU_ITEM_EDIT(float52, MSG_ADVANCE_K MSG_E2, &planner.extruder_advance_K[1], 0, 999);
- #if EXTRUDERS > 2
- MENU_ITEM_EDIT(float52, MSG_ADVANCE_K MSG_E3, &planner.extruder_advance_K[2], 0, 999);
- #if EXTRUDERS > 3
- MENU_ITEM_EDIT(float52, MSG_ADVANCE_K MSG_E4, &planner.extruder_advance_K[3], 0, 999);
- #if EXTRUDERS > 4
- MENU_ITEM_EDIT(float52, MSG_ADVANCE_K MSG_E5, &planner.extruder_advance_K[4], 0, 999);
- #if EXTRUDERS > 5
- MENU_ITEM_EDIT(float52, MSG_ADVANCE_K MSG_E6, &planner.extruder_advance_K[5], 0, 999);
- #endif // EXTRUDERS > 5
- #endif // EXTRUDERS > 4
- #endif // EXTRUDERS > 3
- #endif // EXTRUDERS > 2
- #endif // EXTRUDERS > 1
- #endif
-
- #if DISABLED(NO_VOLUMETRICS)
- MENU_ITEM_EDIT_CALLBACK(bool, MSG_VOLUMETRIC_ENABLED, &parser.volumetric_enabled, planner.calculate_volumetric_multipliers);
-
- if (parser.volumetric_enabled) {
- #if EXTRUDERS == 1
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM, &planner.filament_size[0], 1.5f, 3.25f, planner.calculate_volumetric_multipliers);
- #else // EXTRUDERS > 1
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM, &planner.filament_size[active_extruder], 1.5f, 3.25f, planner.calculate_volumetric_multipliers);
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM MSG_DIAM_E1, &planner.filament_size[0], 1.5f, 3.25f, planner.calculate_volumetric_multipliers);
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM MSG_DIAM_E2, &planner.filament_size[1], 1.5f, 3.25f, planner.calculate_volumetric_multipliers);
- #if EXTRUDERS > 2
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM MSG_DIAM_E3, &planner.filament_size[2], 1.5f, 3.25f, planner.calculate_volumetric_multipliers);
- #if EXTRUDERS > 3
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM MSG_DIAM_E4, &planner.filament_size[3], 1.5f, 3.25f, planner.calculate_volumetric_multipliers);
- #if EXTRUDERS > 4
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM MSG_DIAM_E5, &planner.filament_size[4], 1.5f, 3.25f, planner.calculate_volumetric_multipliers);
- #if EXTRUDERS > 5
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM MSG_DIAM_E6, &planner.filament_size[5], 1.5f, 3.25f, planner.calculate_volumetric_multipliers);
- #endif // EXTRUDERS > 5
- #endif // EXTRUDERS > 4
- #endif // EXTRUDERS > 3
- #endif // EXTRUDERS > 2
- #endif // EXTRUDERS > 1
- }
- #endif
-
- #if ENABLED(ADVANCED_PAUSE_FEATURE)
- const float extrude_maxlength =
- #if ENABLED(PREVENT_LENGTHY_EXTRUDE)
- EXTRUDE_MAXLENGTH
- #else
- 999
- #endif
- ;
-
- #if EXTRUDERS == 1
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_UNLOAD, &fc_settings[0].unload_length, 0, extrude_maxlength);
- #else // EXTRUDERS > 1
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_UNLOAD, &fc_settings[active_extruder].unload_length, 0, extrude_maxlength);
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_UNLOAD MSG_DIAM_E1, &fc_settings[0].unload_length, 0, extrude_maxlength);
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_UNLOAD MSG_DIAM_E2, &fc_settings[1].unload_length, 0, extrude_maxlength);
- #if EXTRUDERS > 2
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_UNLOAD MSG_DIAM_E3, &fc_settings[2].unload_length, 0, extrude_maxlength);
- #if EXTRUDERS > 3
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_UNLOAD MSG_DIAM_E4, &fc_settings[3].unload_length, 0, extrude_maxlength);
- #if EXTRUDERS > 4
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_UNLOAD MSG_DIAM_E5, &fc_settings[4].unload_length, 0, extrude_maxlength);
- #if EXTRUDERS > 5
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_UNLOAD MSG_DIAM_E6, &fc_settings[5].unload_length, 0, extrude_maxlength);
- #endif // EXTRUDERS > 5
- #endif // EXTRUDERS > 4
- #endif // EXTRUDERS > 3
- #endif // EXTRUDERS > 2
- #endif // EXTRUDERS > 1
-
- #if EXTRUDERS == 1
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_LOAD, &fc_settings[0].load_length, 0, extrude_maxlength);
- #else // EXTRUDERS > 1
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_LOAD, &fc_settings[active_extruder].load_length, 0, extrude_maxlength);
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_LOAD MSG_DIAM_E1, &fc_settings[0].load_length, 0, extrude_maxlength);
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_LOAD MSG_DIAM_E2, &fc_settings[1].load_length, 0, extrude_maxlength);
- #if EXTRUDERS > 2
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_LOAD MSG_DIAM_E3, &fc_settings[2].load_length, 0, extrude_maxlength);
- #if EXTRUDERS > 3
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_LOAD MSG_DIAM_E4, &fc_settings[3].load_length, 0, extrude_maxlength);
- #if EXTRUDERS > 4
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_LOAD MSG_DIAM_E5, &fc_settings[4].load_length, 0, extrude_maxlength);
- #if EXTRUDERS > 5
- MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_LOAD MSG_DIAM_E6, &fc_settings[5].load_length, 0, extrude_maxlength);
- #endif // EXTRUDERS > 5
- #endif // EXTRUDERS > 4
- #endif // EXTRUDERS > 3
- #endif // EXTRUDERS > 2
- #endif // EXTRUDERS > 1
- #endif
-
- END_MENU();
- }
- #endif // !NO_VOLUMETRICS || ADVANCED_PAUSE_FEATURE
-
- /**
- *
- * "Configuration" > "Retract" submenu
- *
- */
- #if ENABLED(FWRETRACT)
-
- void lcd_config_retract_menu() {
- START_MENU();
- MENU_BACK(MSG_CONTROL);
- #if ENABLED(FWRETRACT_AUTORETRACT)
- MENU_ITEM_EDIT_CALLBACK(bool, MSG_AUTORETRACT, &fwretract.autoretract_enabled, fwretract.refresh_autoretract);
- #endif
- MENU_ITEM_EDIT(float52sign, MSG_CONTROL_RETRACT, &fwretract.settings.retract_length, 0, 100);
- #if EXTRUDERS > 1
- MENU_ITEM_EDIT(float52sign, MSG_CONTROL_RETRACT_SWAP, &fwretract.settings.swap_retract_length, 0, 100);
- #endif
- MENU_ITEM_EDIT(float3, MSG_CONTROL_RETRACTF, &fwretract.settings.retract_feedrate_mm_s, 1, 999);
- MENU_ITEM_EDIT(float52sign, MSG_CONTROL_RETRACT_ZHOP, &fwretract.settings.retract_zraise, 0, 999);
- MENU_ITEM_EDIT(float52sign, MSG_CONTROL_RETRACT_RECOVER, &fwretract.settings.retract_recover_length, -100, 100);
- #if EXTRUDERS > 1
- MENU_ITEM_EDIT(float52sign, MSG_CONTROL_RETRACT_RECOVER_SWAP, &fwretract.settings.swap_retract_recover_length, -100, 100);
- #endif
- MENU_ITEM_EDIT(float3, MSG_CONTROL_RETRACT_RECOVERF, &fwretract.settings.retract_recover_feedrate_mm_s, 1, 999);
- #if EXTRUDERS > 1
- MENU_ITEM_EDIT(float3, MSG_CONTROL_RETRACT_RECOVER_SWAPF, &fwretract.settings.swap_retract_recover_feedrate_mm_s, 1, 999);
- #endif
- END_MENU();
- }
-
- #endif // FWRETRACT
-
- #if ENABLED(SDSUPPORT)
-
- #if !PIN_EXISTS(SD_DETECT)
- void lcd_sd_refresh() {
- card.initsd();
- encoderTopLine = 0;
- }
- #endif
-
- void lcd_sd_updir() {
- encoderPosition = card.updir() ? ENCODER_STEPS_PER_MENU_ITEM : 0;
- encoderTopLine = 0;
- screen_changed = true;
- lcd_refresh();
- }
-
- /**
- *
- * "Print from SD" submenu
- *
- */
-
- #if ENABLED(SD_REPRINT_LAST_SELECTED_FILE)
- uint32_t last_sdfile_encoderPosition = 0xFFFF;
-
- void lcd_reselect_last_file() {
- if (last_sdfile_encoderPosition == 0xFFFF) return;
- #if ENABLED(DOGLCD)
- // Some of this is a hack to force the screen update to work.
- // TODO: Fix the real issue that causes this!
- lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NEXT;
- _lcd_synchronize();
- safe_delay(50);
- _lcd_synchronize();
- lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NEXT;
- drawing_screen = screen_changed = true;
- #endif
-
- lcd_goto_screen(lcd_sdcard_menu, last_sdfile_encoderPosition);
- defer_return_to_status = true;
- last_sdfile_encoderPosition = 0xFFFF;
-
- #if ENABLED(DOGLCD)
- lcd_update();
- #endif
- }
- #endif
-
- void lcd_sdcard_menu() {
- ENCODER_DIRECTION_MENUS();
-
- const uint16_t fileCnt = card.get_num_Files();
-
- START_MENU();
- MENU_BACK(MSG_MAIN);
- card.getWorkDirName();
- if (card.filename[0] == '/') {
- #if !PIN_EXISTS(SD_DETECT)
- MENU_ITEM(function, LCD_STR_REFRESH MSG_REFRESH, lcd_sd_refresh);
- #endif
- }
- else {
- MENU_ITEM(function, LCD_STR_FOLDER "..", lcd_sd_updir);
- }
-
- for (uint16_t i = 0; i < fileCnt; i++) {
- if (_menuLineNr == _thisItemNr) {
- const uint16_t nr =
- #if ENABLED(SDCARD_RATHERRECENTFIRST) && DISABLED(SDCARD_SORT_ALPHA)
- fileCnt - 1 -
- #endif
- i;
-
- #if ENABLED(SDCARD_SORT_ALPHA)
- card.getfilename_sorted(nr);
- #else
- card.getfilename(nr);
- #endif
-
- if (card.filenameIsDir)
- MENU_ITEM(sddirectory, MSG_CARD_MENU, card);
- else
- MENU_ITEM(sdfile, MSG_CARD_MENU, card);
- }
- else {
- MENU_ITEM_DUMMY();
- }
- }
- END_MENU();
- }
-
- #endif // SDSUPPORT
-
- #if ENABLED(LCD_INFO_MENU)
-
- #if ENABLED(PRINTCOUNTER)
- /**
- *
- * About Printer > Statistics submenu
- *
- */
- void lcd_info_stats_menu() {
- if (use_click()) { return lcd_goto_previous_menu(); }
-
- char buffer[21];
- printStatistics stats = print_job_timer.getStats();
-
- START_SCREEN(); // 12345678901234567890
- STATIC_ITEM(MSG_INFO_PRINT_COUNT ": ", false, false, itostr3left(stats.totalPrints)); // Print Count: 999
- STATIC_ITEM(MSG_INFO_COMPLETED_PRINTS": ", false, false, itostr3left(stats.finishedPrints)); // Completed : 666
-
- duration_t elapsed = stats.printTime;
- elapsed.toString(buffer);
-
- STATIC_ITEM(MSG_INFO_PRINT_TIME ": ", false, false); // Total print Time:
- STATIC_ITEM("", false, false, buffer); // 99y 364d 23h 59m 59s
-
- elapsed = stats.longestPrint;
- elapsed.toString(buffer);
-
- STATIC_ITEM(MSG_INFO_PRINT_LONGEST ": ", false, false); // Longest job time:
- STATIC_ITEM("", false, false, buffer); // 99y 364d 23h 59m 59s
-
- sprintf_P(buffer, PSTR("%ld.%im"), long(stats.filamentUsed / 1000), int16_t(stats.filamentUsed / 100) % 10);
- STATIC_ITEM(MSG_INFO_PRINT_FILAMENT ": ", false, false); // Extruded total:
- STATIC_ITEM("", false, false, buffer); // 125m
- END_SCREEN();
- }
- #endif // PRINTCOUNTER
-
- /**
- *
- * About Printer > Thermistors
- *
- */
- void lcd_info_thermistors_menu() {
- if (use_click()) { return lcd_goto_previous_menu(); }
- START_SCREEN();
- #define THERMISTOR_ID TEMP_SENSOR_0
- #include "thermistornames.h"
- STATIC_ITEM("T0: " THERMISTOR_NAME, false, true);
- STATIC_ITEM(MSG_INFO_MIN_TEMP ": " STRINGIFY(HEATER_0_MINTEMP), false);
- STATIC_ITEM(MSG_INFO_MAX_TEMP ": " STRINGIFY(HEATER_0_MAXTEMP), false);
-
- #if TEMP_SENSOR_1 != 0
- #undef THERMISTOR_ID
- #define THERMISTOR_ID TEMP_SENSOR_1
- #include "thermistornames.h"
- STATIC_ITEM("T1: " THERMISTOR_NAME, false, true);
- STATIC_ITEM(MSG_INFO_MIN_TEMP ": " STRINGIFY(HEATER_1_MINTEMP), false);
- STATIC_ITEM(MSG_INFO_MAX_TEMP ": " STRINGIFY(HEATER_1_MAXTEMP), false);
- #endif
-
- #if TEMP_SENSOR_2 != 0
- #undef THERMISTOR_ID
- #define THERMISTOR_ID TEMP_SENSOR_2
- #include "thermistornames.h"
- STATIC_ITEM("T2: " THERMISTOR_NAME, false, true);
- STATIC_ITEM(MSG_INFO_MIN_TEMP ": " STRINGIFY(HEATER_2_MINTEMP), false);
- STATIC_ITEM(MSG_INFO_MAX_TEMP ": " STRINGIFY(HEATER_2_MAXTEMP), false);
- #endif
-
- #if TEMP_SENSOR_3 != 0
- #undef THERMISTOR_ID
- #define THERMISTOR_ID TEMP_SENSOR_3
- #include "thermistornames.h"
- STATIC_ITEM("T3: " THERMISTOR_NAME, false, true);
- STATIC_ITEM(MSG_INFO_MIN_TEMP ": " STRINGIFY(HEATER_3_MINTEMP), false);
- STATIC_ITEM(MSG_INFO_MAX_TEMP ": " STRINGIFY(HEATER_3_MAXTEMP), false);
- #endif
-
- #if TEMP_SENSOR_4 != 0
- #undef THERMISTOR_ID
- #define THERMISTOR_ID TEMP_SENSOR_4
- #include "thermistornames.h"
- STATIC_ITEM("T4: " THERMISTOR_NAME, false, true);
- STATIC_ITEM(MSG_INFO_MIN_TEMP ": " STRINGIFY(HEATER_4_MINTEMP), false);
- STATIC_ITEM(MSG_INFO_MAX_TEMP ": " STRINGIFY(HEATER_4_MAXTEMP), false);
- #endif
-
- #if HAS_HEATED_BED
- #undef THERMISTOR_ID
- #define THERMISTOR_ID TEMP_SENSOR_BED
- #include "thermistornames.h"
- STATIC_ITEM("TBed:" THERMISTOR_NAME, false, true);
- STATIC_ITEM(MSG_INFO_MIN_TEMP ": " STRINGIFY(BED_MINTEMP), false);
- STATIC_ITEM(MSG_INFO_MAX_TEMP ": " STRINGIFY(BED_MAXTEMP), false);
- #endif
- END_SCREEN();
- }
-
- /**
- *
- * About Printer > Board Info
- *
- */
- void lcd_info_board_menu() {
- if (use_click()) { return lcd_goto_previous_menu(); }
- START_SCREEN();
- STATIC_ITEM(BOARD_NAME, true, true); // MyPrinterController
- STATIC_ITEM(MSG_INFO_BAUDRATE ": " STRINGIFY(BAUDRATE), true); // Baud: 250000
- STATIC_ITEM(MSG_INFO_PROTOCOL ": " PROTOCOL_VERSION, true); // Protocol: 1.0
- #if POWER_SUPPLY == 0
- STATIC_ITEM(MSG_INFO_PSU ": Generic", true);
- #elif POWER_SUPPLY == 1
- STATIC_ITEM(MSG_INFO_PSU ": ATX", true); // Power Supply: ATX
- #elif POWER_SUPPLY == 2
- STATIC_ITEM(MSG_INFO_PSU ": XBox", true); // Power Supply: XBox
- #endif
- END_SCREEN();
- }
-
- /**
- *
- * About Printer > Printer Info
- *
- */
- void lcd_info_printer_menu() {
- if (use_click()) { return lcd_goto_previous_menu(); }
- START_SCREEN();
- STATIC_ITEM(MSG_MARLIN, true, true); // Marlin
- STATIC_ITEM(SHORT_BUILD_VERSION, true); // x.x.x-Branch
- STATIC_ITEM(STRING_DISTRIBUTION_DATE, true); // YYYY-MM-DD HH:MM
- STATIC_ITEM(MACHINE_NAME, true); // My3DPrinter
- STATIC_ITEM(WEBSITE_URL, true); // www.my3dprinter.com
- STATIC_ITEM(MSG_INFO_EXTRUDERS ": " STRINGIFY(EXTRUDERS), true); // Extruders: 2
- #if ENABLED(AUTO_BED_LEVELING_3POINT)
- STATIC_ITEM(MSG_3POINT_LEVELING, true); // 3-Point Leveling
- #elif ENABLED(AUTO_BED_LEVELING_LINEAR)
- STATIC_ITEM(MSG_LINEAR_LEVELING, true); // Linear Leveling
- #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
- STATIC_ITEM(MSG_BILINEAR_LEVELING, true); // Bi-linear Leveling
- #elif ENABLED(AUTO_BED_LEVELING_UBL)
- STATIC_ITEM(MSG_UBL_LEVELING, true); // Unified Bed Leveling
- #elif ENABLED(MESH_BED_LEVELING)
- STATIC_ITEM(MSG_MESH_LEVELING, true); // Mesh Leveling
- #endif
- END_SCREEN();
- }
-
- /**
- *
- * "About Printer" submenu
- *
- */
- void lcd_info_menu() {
- START_MENU();
- MENU_BACK(MSG_MAIN);
- MENU_ITEM(submenu, MSG_INFO_PRINTER_MENU, lcd_info_printer_menu); // Printer Info >
- MENU_ITEM(submenu, MSG_INFO_BOARD_MENU, lcd_info_board_menu); // Board Info >
- MENU_ITEM(submenu, MSG_INFO_THERMISTOR_MENU, lcd_info_thermistors_menu); // Thermistors >
- #if ENABLED(PRINTCOUNTER)
- MENU_ITEM(submenu, MSG_INFO_STATS_MENU, lcd_info_stats_menu); // Printer Statistics >
- #endif
- END_MENU();
- }
- #endif // LCD_INFO_MENU
-
- /**
- *
- * LED Menu
- *
- */
-
- #if ENABLED(LED_CONTROL_MENU)
-
- #if ENABLED(LED_COLOR_PRESETS)
-
- void lcd_led_presets_menu() {
- START_MENU();
- #if LCD_HEIGHT > 2
- STATIC_ITEM(MSG_LED_PRESETS, true, true);
- #endif
- MENU_BACK(MSG_LED_CONTROL);
- MENU_ITEM(function, MSG_SET_LEDS_WHITE, leds.set_white);
- MENU_ITEM(function, MSG_SET_LEDS_RED, leds.set_red);
- MENU_ITEM(function, MSG_SET_LEDS_ORANGE, leds.set_orange);
- MENU_ITEM(function, MSG_SET_LEDS_YELLOW,leds.set_yellow);
- MENU_ITEM(function, MSG_SET_LEDS_GREEN, leds.set_green);
- MENU_ITEM(function, MSG_SET_LEDS_BLUE, leds.set_blue);
- MENU_ITEM(function, MSG_SET_LEDS_INDIGO, leds.set_indigo);
- MENU_ITEM(function, MSG_SET_LEDS_VIOLET, leds.set_violet);
- END_MENU();
- }
- #endif // LED_COLOR_PRESETS
-
- void lcd_led_custom_menu() {
- START_MENU();
- MENU_BACK(MSG_LED_CONTROL);
- MENU_ITEM_EDIT_CALLBACK(int8, MSG_INTENSITY_R, &leds.color.r, 0, 255, leds.update, true);
- MENU_ITEM_EDIT_CALLBACK(int8, MSG_INTENSITY_G, &leds.color.g, 0, 255, leds.update, true);
- MENU_ITEM_EDIT_CALLBACK(int8, MSG_INTENSITY_B, &leds.color.b, 0, 255, leds.update, true);
- #if ENABLED(RGBW_LED) || ENABLED(NEOPIXEL_LED)
- MENU_ITEM_EDIT_CALLBACK(int8, MSG_INTENSITY_W, &leds.color.w, 0, 255, leds.update, true);
- #if ENABLED(NEOPIXEL_LED)
- MENU_ITEM_EDIT_CALLBACK(int8, MSG_LED_BRIGHTNESS, &leds.color.i, 0, 255, leds.update, true);
- #endif
- #endif
- END_MENU();
- }
-
- void lcd_led_menu() {
- START_MENU();
- MENU_BACK(MSG_MAIN);
- bool led_on = leds.lights_on;
- MENU_ITEM_EDIT_CALLBACK(bool, MSG_LEDS, &led_on, leds.toggle);
- MENU_ITEM(function, MSG_SET_LEDS_DEFAULT, leds.set_default);
- #if ENABLED(LED_COLOR_PRESETS)
- MENU_ITEM(submenu, MSG_LED_PRESETS, lcd_led_presets_menu);
- #endif
- MENU_ITEM(submenu, MSG_CUSTOM_LEDS, lcd_led_custom_menu);
- END_MENU();
- }
-
- #endif // LED_CONTROL_MENU
-
- /**
- *
- * Filament Change Feature Screens
- *
- */
- #if ENABLED(ADVANCED_PAUSE_FEATURE)
-
- /**
- *
- * "Change Filament" > "Change/Unload/Load Filament" submenu
- *
- */
- static AdvancedPauseMode _change_filament_temp_mode;
- static int8_t _change_filament_temp_extruder;
-
- static PGM_P _change_filament_temp_command() {
- switch (_change_filament_temp_mode) {
- case ADVANCED_PAUSE_MODE_LOAD_FILAMENT:
- return PSTR("M701 T%d");
- case ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT:
- return _change_filament_temp_extruder >= 0 ? PSTR("M702 T%d") : PSTR("M702 ;%d");
- case ADVANCED_PAUSE_MODE_PAUSE_PRINT:
- default:
- return PSTR("M600 B0 T%d");
- }
- return PSTR(MSG_FILAMENTCHANGE);
- }
-
- void _change_filament_temp(const uint16_t temperature) {
- char cmd[11];
- sprintf_P(cmd, _change_filament_temp_command(), _change_filament_temp_extruder);
- thermalManager.setTargetHotend(temperature, _change_filament_temp_extruder);
- lcd_enqueue_command(cmd);
- }
- void _lcd_change_filament_temp_1_menu() { _change_filament_temp(PREHEAT_1_TEMP_HOTEND); }
- void _lcd_change_filament_temp_2_menu() { _change_filament_temp(PREHEAT_2_TEMP_HOTEND); }
- void _lcd_change_filament_temp_custom_menu() { _change_filament_temp(thermalManager.target_temperature[_change_filament_temp_extruder]); }
-
- static PGM_P change_filament_header(const AdvancedPauseMode mode) {
- switch (mode) {
- case ADVANCED_PAUSE_MODE_LOAD_FILAMENT:
- return PSTR(MSG_FILAMENTLOAD);
- case ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT:
- return PSTR(MSG_FILAMENTUNLOAD);
- default: break;
- }
- return PSTR(MSG_FILAMENTCHANGE);
- }
-
- void _lcd_temp_menu_filament_op(const AdvancedPauseMode mode, const int8_t extruder) {
- _change_filament_temp_mode = mode;
- _change_filament_temp_extruder = extruder;
- START_MENU();
- if (LCD_HEIGHT >= 4) STATIC_ITEM_P(change_filament_header(mode), true, true);
- MENU_BACK(MSG_BACK);
- MENU_ITEM(submenu, MSG_PREHEAT_1, _lcd_change_filament_temp_1_menu);
- MENU_ITEM(submenu, MSG_PREHEAT_2, _lcd_change_filament_temp_2_menu);
- uint16_t max_temp;
- switch (extruder) {
- default: max_temp = HEATER_0_MAXTEMP;
- #if HOTENDS > 1
- case 1: max_temp = HEATER_1_MAXTEMP; break;
- #if HOTENDS > 2
- case 2: max_temp = HEATER_2_MAXTEMP; break;
- #if HOTENDS > 3
- case 3: max_temp = HEATER_3_MAXTEMP; break;
- #if HOTENDS > 4
- case 4: max_temp = HEATER_4_MAXTEMP; break;
- #if HOTENDS > 5
- case 5: max_temp = HEATER_5_MAXTEMP; break;
- #endif
- #endif
- #endif
- #endif
- #endif
- }
- MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_PREHEAT_CUSTOM, &thermalManager.target_temperature[_change_filament_temp_extruder], EXTRUDE_MINTEMP, max_temp - 15, _lcd_change_filament_temp_custom_menu);
- END_MENU();
- }
- void lcd_temp_menu_e0_filament_change() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_PAUSE_PRINT, 0); }
- void lcd_temp_menu_e0_filament_load() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_LOAD_FILAMENT, 0); }
- void lcd_temp_menu_e0_filament_unload() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT, 0); }
- #if E_STEPPERS > 1
- void lcd_temp_menu_e1_filament_change() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_PAUSE_PRINT, 1); }
- void lcd_temp_menu_e1_filament_load() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_LOAD_FILAMENT, 1); }
- void lcd_temp_menu_e1_filament_unload() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT, 1); }
- #if ENABLED(FILAMENT_UNLOAD_ALL_EXTRUDERS)
- void lcd_unload_filament_all_temp_menu() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT, -1); }
- #endif
- #if E_STEPPERS > 2
- void lcd_temp_menu_e2_filament_change() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_PAUSE_PRINT, 2); }
- void lcd_temp_menu_e2_filament_load() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_LOAD_FILAMENT, 2); }
- void lcd_temp_menu_e2_filament_unload() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT, 2); }
- #if E_STEPPERS > 3
- void lcd_temp_menu_e3_filament_change() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_PAUSE_PRINT, 3); }
- void lcd_temp_menu_e3_filament_load() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_LOAD_FILAMENT, 3); }
- void lcd_temp_menu_e3_filament_unload() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT, 3); }
- #if E_STEPPERS > 4
- void lcd_temp_menu_e4_filament_change() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_PAUSE_PRINT, 4); }
- void lcd_temp_menu_e4_filament_load() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_LOAD_FILAMENT, 4); }
- void lcd_temp_menu_e4_filament_unload() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT, 4); }
- #endif // E_STEPPERS > 4
- #endif // E_STEPPERS > 3
- #endif // E_STEPPERS > 2
- #endif // E_STEPPERS > 1
-
- /**
- *
- * "Change Filament" submenu
- *
- */
- #if E_STEPPERS > 1 || ENABLED(FILAMENT_LOAD_UNLOAD_GCODES)
- void lcd_change_filament_menu() {
- START_MENU();
- MENU_BACK(MSG_MAIN);
-
- // Change filament
- #if E_STEPPERS == 1
- PGM_P msg0 = PSTR(MSG_FILAMENTCHANGE);
- if (thermalManager.targetTooColdToExtrude(active_extruder))
- MENU_ITEM_P(submenu, msg0, lcd_temp_menu_e0_filament_change);
- else
- MENU_ITEM_P(gcode, msg0, PSTR("M600 B0"));
- #else
- PGM_P msg0 = PSTR(MSG_FILAMENTCHANGE " " MSG_E1);
- PGM_P msg1 = PSTR(MSG_FILAMENTCHANGE " " MSG_E2);
- if (thermalManager.targetTooColdToExtrude(0))
- MENU_ITEM_P(submenu, msg0, lcd_temp_menu_e0_filament_change);
- else
- MENU_ITEM_P(gcode, msg0, PSTR("M600 B0 T0"));
- if (thermalManager.targetTooColdToExtrude(1))
- MENU_ITEM_P(submenu, msg1, lcd_temp_menu_e1_filament_change);
- else
- MENU_ITEM_P(gcode, msg1, PSTR("M600 B0 T1"));
- #if E_STEPPERS > 2
- PGM_P msg2 = PSTR(MSG_FILAMENTCHANGE " " MSG_E3);
- if (thermalManager.targetTooColdToExtrude(2))
- MENU_ITEM_P(submenu, msg2, lcd_temp_menu_e2_filament_change);
- else
- MENU_ITEM_P(gcode, msg2, PSTR("M600 B0 T2"));
- #if E_STEPPERS > 3
- PGM_P msg3 = PSTR(MSG_FILAMENTCHANGE " " MSG_E4);
- if (thermalManager.targetTooColdToExtrude(3))
- MENU_ITEM_P(submenu, msg3, lcd_temp_menu_e3_filament_change);
- else
- MENU_ITEM_P(gcode, msg3, PSTR("M600 B0 T3"));
- #if E_STEPPERS > 4
- PGM_P msg4 = PSTR(MSG_FILAMENTCHANGE " " MSG_E5);
- if (thermalManager.targetTooColdToExtrude(4))
- MENU_ITEM_P(submenu, msg4, lcd_temp_menu_e4_filament_change);
- else
- MENU_ITEM_P(gcode, msg4, PSTR("M600 B0 T4"));
- #if E_STEPPERS > 5
- PGM_P msg5 = PSTR(MSG_FILAMENTCHANGE " " MSG_E6);
- if (thermalManager.targetTooColdToExtrude(5))
- MENU_ITEM_P(submenu, msg5, lcd_temp_menu_e5_filament_change);
- else
- MENU_ITEM_P(gcode, msg5, PSTR("M600 B0 T5"));
- #endif // E_STEPPERS > 5
- #endif // E_STEPPERS > 4
- #endif // E_STEPPERS > 3
- #endif // E_STEPPERS > 2
- #endif // E_STEPPERS == 1
-
- #if ENABLED(FILAMENT_LOAD_UNLOAD_GCODES)
- if (!printer_busy()) {
- // Load filament
- #if E_STEPPERS == 1
- PGM_P msg0 = PSTR(MSG_FILAMENTLOAD);
- if (thermalManager.targetTooColdToExtrude(active_extruder))
- MENU_ITEM_P(submenu, msg0, lcd_temp_menu_e0_filament_load);
- else
- MENU_ITEM_P(gcode, msg0, PSTR("M701"));
- #else
- PGM_P msg0 = PSTR(MSG_FILAMENTLOAD " " MSG_E1);
- PGM_P msg1 = PSTR(MSG_FILAMENTLOAD " " MSG_E2);
- if (thermalManager.targetTooColdToExtrude(0))
- MENU_ITEM_P(submenu, msg0, lcd_temp_menu_e0_filament_load);
- else
- MENU_ITEM_P(gcode, msg0, PSTR("M701 T0"));
- if (thermalManager.targetTooColdToExtrude(1))
- MENU_ITEM_P(submenu, msg1, lcd_temp_menu_e1_filament_load);
- else
- MENU_ITEM_P(gcode, msg1, PSTR("M701 T1"));
- #if E_STEPPERS > 2
- PGM_P msg2 = PSTR(MSG_FILAMENTLOAD " " MSG_E3);
- if (thermalManager.targetTooColdToExtrude(2))
- MENU_ITEM_P(submenu, msg2, lcd_temp_menu_e2_filament_load);
- else
- MENU_ITEM_P(gcode, msg2, PSTR("M701 T2"));
- #if E_STEPPERS > 3
- PGM_P msg3 = PSTR(MSG_FILAMENTLOAD " " MSG_E4);
- if (thermalManager.targetTooColdToExtrude(3))
- MENU_ITEM_P(submenu, msg3, lcd_temp_menu_e3_filament_load);
- else
- MENU_ITEM_P(gcode, msg3, PSTR("M701 T3"));
- #if E_STEPPERS > 4
- PGM_P msg4 = PSTR(MSG_FILAMENTLOAD " " MSG_E5);
- if (thermalManager.targetTooColdToExtrude(4))
- MENU_ITEM_P(submenu, msg4, lcd_temp_menu_e4_filament_load);
- else
- MENU_ITEM_P(gcode, msg4, PSTR("M701 T4"));
- #if E_STEPPERS > 5
- PGM_P msg5 = PSTR(MSG_FILAMENTLOAD " " MSG_E6);
- if (thermalManager.targetTooColdToExtrude(5))
- MENU_ITEM_P(submenu, msg5, lcd_temp_menu_e5_filament_load);
- else
- MENU_ITEM_P(gcode, msg5, PSTR("M701 T5"));
- #endif // E_STEPPERS > 5
- #endif // E_STEPPERS > 4
- #endif // E_STEPPERS > 3
- #endif // E_STEPPERS > 2
- #endif // E_STEPPERS == 1
-
- // Unload filament
- #if E_STEPPERS == 1
- if (thermalManager.targetHotEnoughToExtrude(active_extruder))
- MENU_ITEM(gcode, MSG_FILAMENTUNLOAD, PSTR("M702"));
- else
- MENU_ITEM(submenu, MSG_FILAMENTUNLOAD, lcd_temp_menu_e0_filament_unload);
- #else
- #if ENABLED(FILAMENT_UNLOAD_ALL_EXTRUDERS)
- if (thermalManager.targetHotEnoughToExtrude(0)
- #if E_STEPPERS > 1
- && thermalManager.targetHotEnoughToExtrude(1)
- #if E_STEPPERS > 2
- && thermalManager.targetHotEnoughToExtrude(2)
- #if E_STEPPERS > 3
- && thermalManager.targetHotEnoughToExtrude(3)
- #if E_STEPPERS > 4
- && thermalManager.targetHotEnoughToExtrude(4)
- #if E_STEPPERS > 5
- && thermalManager.targetHotEnoughToExtrude(5)
- #endif // E_STEPPERS > 5
- #endif // E_STEPPERS > 4
- #endif // E_STEPPERS > 3
- #endif // E_STEPPERS > 2
- #endif // E_STEPPERS > 1
- )
- MENU_ITEM(gcode, MSG_FILAMENTUNLOAD_ALL, PSTR("M702"));
- else
- MENU_ITEM(submenu, MSG_FILAMENTUNLOAD_ALL, lcd_unload_filament_all_temp_menu);
- #endif
- if (thermalManager.targetHotEnoughToExtrude(0))
- MENU_ITEM(gcode, MSG_FILAMENTUNLOAD " " MSG_E1, PSTR("M702 T0"));
- else
- MENU_ITEM(submenu, MSG_FILAMENTUNLOAD " " MSG_E1, lcd_temp_menu_e0_filament_unload);
- if (thermalManager.targetHotEnoughToExtrude(1))
- MENU_ITEM(gcode, MSG_FILAMENTUNLOAD " " MSG_E2, PSTR("M702 T1"));
- else
- MENU_ITEM(submenu, MSG_FILAMENTUNLOAD " " MSG_E2, lcd_temp_menu_e1_filament_unload);
- #if E_STEPPERS > 2
- if (thermalManager.targetHotEnoughToExtrude(2))
- MENU_ITEM(gcode, MSG_FILAMENTUNLOAD " " MSG_E3, PSTR("M702 T2"));
- else
- MENU_ITEM(submenu, MSG_FILAMENTUNLOAD " " MSG_E3, lcd_temp_menu_e2_filament_unload);
- #if E_STEPPERS > 3
- if (thermalManager.targetHotEnoughToExtrude(3))
- MENU_ITEM(gcode, MSG_FILAMENTUNLOAD " " MSG_E4, PSTR("M702 T3"));
- else
- MENU_ITEM(submenu, MSG_FILAMENTUNLOAD " " MSG_E4, lcd_temp_menu_e3_filament_unload);
- #if E_STEPPERS > 4
- if (thermalManager.targetHotEnoughToExtrude(4))
- MENU_ITEM(gcode, MSG_FILAMENTUNLOAD " " MSG_E5, PSTR("M702 T4"));
- else
- MENU_ITEM(submenu, MSG_FILAMENTUNLOAD " " MSG_E5, lcd_temp_menu_e4_filament_unload);
- #if E_STEPPERS > 5
- if (thermalManager.targetHotEnoughToExtrude(5))
- MENU_ITEM(gcode, MSG_FILAMENTUNLOAD " " MSG_E6, PSTR("M702 T5"));
- else
- MENU_ITEM(submenu, MSG_FILAMENTUNLOAD " " MSG_E6, lcd_temp_menu_e5_filament_unload);
- #endif // E_STEPPERS > 5
- #endif // E_STEPPERS > 4
- #endif // E_STEPPERS > 3
- #endif // E_STEPPERS > 2
- #endif // E_STEPPERS == 1
- }
- #endif
-
- END_MENU();
- }
- #endif
-
- static AdvancedPauseMode advanced_pause_mode = ADVANCED_PAUSE_MODE_PAUSE_PRINT;
- static uint8_t hotend_status_extruder = 0;
-
- static PGM_P advanced_pause_header() {
- switch (advanced_pause_mode) {
- case ADVANCED_PAUSE_MODE_LOAD_FILAMENT:
- return PSTR(MSG_FILAMENT_CHANGE_HEADER_LOAD);
- case ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT:
- return PSTR(MSG_FILAMENT_CHANGE_HEADER_UNLOAD);
- default: break;
- }
- return PSTR(MSG_FILAMENT_CHANGE_HEADER_PAUSE);
- }
-
- // Portions from STATIC_ITEM...
- #define HOTEND_STATUS_ITEM() do { \
- if (_menuLineNr == _thisItemNr) { \
- if (lcdDrawUpdate) { \
- lcd_implementation_drawmenu_static(_lcdLineNr, PSTR(MSG_FILAMENT_CHANGE_NOZZLE), false, true); \
- lcd_implementation_hotend_status(_lcdLineNr, hotend_status_extruder); \
- } \
- if (_skipStatic && encoderLine <= _thisItemNr) { \
- encoderPosition += ENCODER_STEPS_PER_MENU_ITEM; \
- ++encoderLine; \
- } \
- lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NEXT; \
- } \
- ++_thisItemNr; \
- }while(0)
-
- void lcd_advanced_pause_resume_print() {
- advanced_pause_menu_response = ADVANCED_PAUSE_RESPONSE_RESUME_PRINT;
- }
-
- void lcd_advanced_pause_extrude_more() {
- advanced_pause_menu_response = ADVANCED_PAUSE_RESPONSE_EXTRUDE_MORE;
- }
-
- void lcd_advanced_pause_option_menu() {
- START_MENU();
- #if LCD_HEIGHT > 2
- STATIC_ITEM(MSG_FILAMENT_CHANGE_OPTION_HEADER, true, false);
- #endif
- MENU_ITEM(function, MSG_FILAMENT_CHANGE_OPTION_RESUME, lcd_advanced_pause_resume_print);
- MENU_ITEM(function, MSG_FILAMENT_CHANGE_OPTION_PURGE, lcd_advanced_pause_extrude_more);
- END_MENU();
- }
-
- void lcd_advanced_pause_init_message() {
- START_SCREEN();
- STATIC_ITEM_P(advanced_pause_header(), true, true);
- STATIC_ITEM(MSG_FILAMENT_CHANGE_INIT_1);
- #ifdef MSG_FILAMENT_CHANGE_INIT_2
- STATIC_ITEM(MSG_FILAMENT_CHANGE_INIT_2);
- #define __FC_LINES_A 3
- #else
- #define __FC_LINES_A 2
- #endif
- #ifdef MSG_FILAMENT_CHANGE_INIT_3
- STATIC_ITEM(MSG_FILAMENT_CHANGE_INIT_3);
- #define _FC_LINES_A (__FC_LINES_A + 1)
- #else
- #define _FC_LINES_A __FC_LINES_A
- #endif
- #if LCD_HEIGHT > _FC_LINES_A + 1
- STATIC_ITEM(" ");
- #endif
- HOTEND_STATUS_ITEM();
- END_SCREEN();
- }
-
- void lcd_advanced_pause_unload_message() {
- START_SCREEN();
- STATIC_ITEM_P(advanced_pause_header(), true, true);
- STATIC_ITEM(MSG_FILAMENT_CHANGE_UNLOAD_1);
- #ifdef MSG_FILAMENT_CHANGE_UNLOAD_2
- STATIC_ITEM(MSG_FILAMENT_CHANGE_UNLOAD_2);
- #define __FC_LINES_B 3
- #else
- #define __FC_LINES_B 2
- #endif
- #ifdef MSG_FILAMENT_CHANGE_UNLOAD_3
- STATIC_ITEM(MSG_FILAMENT_CHANGE_UNLOAD_3);
- #define _FC_LINES_B (__FC_LINES_B + 1)
- #else
- #define _FC_LINES_B __FC_LINES_B
- #endif
- #if LCD_HEIGHT > _FC_LINES_B + 1
- STATIC_ITEM(" ");
- #endif
- HOTEND_STATUS_ITEM();
- END_SCREEN();
- }
-
- void lcd_advanced_pause_wait_for_nozzles_to_heat() {
- START_SCREEN();
- STATIC_ITEM_P(advanced_pause_header(), true, true);
- STATIC_ITEM(MSG_FILAMENT_CHANGE_HEATING_1);
- #ifdef MSG_FILAMENT_CHANGE_HEATING_2
- STATIC_ITEM(MSG_FILAMENT_CHANGE_HEATING_2);
- #define _FC_LINES_C 3
- #else
- #define _FC_LINES_C 2
- #endif
- #if LCD_HEIGHT > _FC_LINES_C + 1
- STATIC_ITEM(" ");
- #endif
- HOTEND_STATUS_ITEM();
- END_SCREEN();
- }
-
- void lcd_advanced_pause_heat_nozzle() {
- START_SCREEN();
- STATIC_ITEM_P(advanced_pause_header(), true, true);
- STATIC_ITEM(MSG_FILAMENT_CHANGE_HEAT_1);
- #ifdef MSG_FILAMENT_CHANGE_INSERT_2
- STATIC_ITEM(MSG_FILAMENT_CHANGE_HEAT_2);
- #define _FC_LINES_D 3
- #else
- #define _FC_LINES_D 2
- #endif
- #if LCD_HEIGHT > _FC_LINES_D + 1
- STATIC_ITEM(" ");
- #endif
- HOTEND_STATUS_ITEM();
- END_SCREEN();
- }
-
- void lcd_advanced_pause_insert_message() {
- START_SCREEN();
- STATIC_ITEM_P(advanced_pause_header(), true, true);
- STATIC_ITEM(MSG_FILAMENT_CHANGE_INSERT_1);
- #ifdef MSG_FILAMENT_CHANGE_INSERT_2
- STATIC_ITEM(MSG_FILAMENT_CHANGE_INSERT_2);
- #define __FC_LINES_E 3
- #else
- #define __FC_LINES_E 2
- #endif
- #ifdef MSG_FILAMENT_CHANGE_INSERT_3
- STATIC_ITEM(MSG_FILAMENT_CHANGE_INSERT_3);
- #define _FC_LINES_E (__FC_LINES_E + 1)
- #else
- #define _FC_LINES_E __FC_LINES_E
- #endif
- #if LCD_HEIGHT > _FC_LINES_E + 1
- STATIC_ITEM(" ");
- #endif
- HOTEND_STATUS_ITEM();
- END_SCREEN();
- }
-
- void lcd_advanced_pause_load_message() {
- START_SCREEN();
- STATIC_ITEM_P(advanced_pause_header(), true, true);
- STATIC_ITEM(MSG_FILAMENT_CHANGE_LOAD_1);
- #ifdef MSG_FILAMENT_CHANGE_LOAD_2
- STATIC_ITEM(MSG_FILAMENT_CHANGE_LOAD_2);
- #define __FC_LINES_F 3
- #else
- #define __FC_LINES_F 2
- #endif
- #ifdef MSG_FILAMENT_CHANGE_LOAD_3
- STATIC_ITEM(MSG_FILAMENT_CHANGE_LOAD_3);
- #define _FC_LINES_F (__FC_LINES_F + 1)
- #else
- #define _FC_LINES_F __FC_LINES_F
- #endif
- #if LCD_HEIGHT > _FC_LINES_F + 1
- STATIC_ITEM(" ");
- #endif
- HOTEND_STATUS_ITEM();
- END_SCREEN();
- }
-
- void lcd_advanced_pause_purge_message() {
- START_SCREEN();
- STATIC_ITEM_P(advanced_pause_header(), true, true);
- STATIC_ITEM(MSG_FILAMENT_CHANGE_PURGE_1);
- #ifdef MSG_FILAMENT_CHANGE_PURGE_2
- STATIC_ITEM(MSG_FILAMENT_CHANGE_PURGE_2);
- #define __FC_LINES_G 3
- #else
- #define __FC_LINES_G 2
- #endif
- #ifdef MSG_FILAMENT_CHANGE_PURGE_3
- STATIC_ITEM(MSG_FILAMENT_CHANGE_PURGE_3);
- #define _FC_LINES_G (__FC_LINES_G + 1)
- #else
- #define _FC_LINES_G __FC_LINES_G
- #endif
- #if LCD_HEIGHT > _FC_LINES_G + 1
- STATIC_ITEM(" ");
- #endif
- HOTEND_STATUS_ITEM();
- END_SCREEN();
- }
-
- #if ENABLED(ADVANCED_PAUSE_CONTINUOUS_PURGE)
- void lcd_advanced_pause_continuous_purge_menu() {
- START_SCREEN();
- STATIC_ITEM(MSG_FILAMENT_CHANGE_PURGE_1);
- #ifdef MSG_FILAMENT_CHANGE_PURGE_2
- STATIC_ITEM(MSG_FILAMENT_CHANGE_PURGE_2);
- #define __FC_LINES_G 3
- #else
- #define __FC_LINES_G 2
- #endif
- #ifdef MSG_FILAMENT_CHANGE_PURGE_3
- STATIC_ITEM(MSG_FILAMENT_CHANGE_PURGE_3);
- #define _FC_LINES_G (__FC_LINES_G + 1)
- #else
- #define _FC_LINES_G __FC_LINES_G
- #endif
- #if LCD_HEIGHT > _FC_LINES_G + 1
- STATIC_ITEM(" ");
- #endif
- HOTEND_STATUS_ITEM();
- STATIC_ITEM(MSG_USERWAIT);
- END_SCREEN();
- }
- #endif
-
- void lcd_advanced_pause_resume_message() {
- START_SCREEN();
- STATIC_ITEM_P(advanced_pause_header(), true, true);
- STATIC_ITEM(MSG_FILAMENT_CHANGE_RESUME_1);
- #ifdef MSG_FILAMENT_CHANGE_RESUME_2
- STATIC_ITEM(MSG_FILAMENT_CHANGE_RESUME_2);
- #endif
- #ifdef MSG_FILAMENT_CHANGE_RESUME_3
- STATIC_ITEM(MSG_FILAMENT_CHANGE_RESUME_3);
- #endif
- END_SCREEN();
- }
-
- FORCE_INLINE screenFunc_t ap_message_screen(const AdvancedPauseMessage message) {
- switch (message) {
- case ADVANCED_PAUSE_MESSAGE_INIT: return lcd_advanced_pause_init_message;
- case ADVANCED_PAUSE_MESSAGE_UNLOAD: return lcd_advanced_pause_unload_message;
- case ADVANCED_PAUSE_MESSAGE_INSERT: return lcd_advanced_pause_insert_message;
- case ADVANCED_PAUSE_MESSAGE_LOAD: return lcd_advanced_pause_load_message;
- case ADVANCED_PAUSE_MESSAGE_PURGE: return lcd_advanced_pause_purge_message;
- case ADVANCED_PAUSE_MESSAGE_RESUME: return lcd_advanced_pause_resume_message;
- case ADVANCED_PAUSE_MESSAGE_CLICK_TO_HEAT_NOZZLE: return lcd_advanced_pause_heat_nozzle;
- case ADVANCED_PAUSE_MESSAGE_WAIT_FOR_NOZZLES_TO_HEAT: return lcd_advanced_pause_wait_for_nozzles_to_heat;
- case ADVANCED_PAUSE_MESSAGE_OPTION: advanced_pause_menu_response = ADVANCED_PAUSE_RESPONSE_WAIT_FOR;
- return lcd_advanced_pause_option_menu;
- #if ENABLED(ADVANCED_PAUSE_CONTINUOUS_PURGE)
- case ADVANCED_PAUSE_MESSAGE_CONTINUOUS_PURGE: return lcd_advanced_pause_continuous_purge_menu;
- #endif
- case ADVANCED_PAUSE_MESSAGE_STATUS:
- default: break;
- }
- return NULL;
- }
-
- void lcd_advanced_pause_show_message(
- const AdvancedPauseMessage message,
- const AdvancedPauseMode mode/*=ADVANCED_PAUSE_MODE_PAUSE_PRINT*/,
- const uint8_t extruder/*=active_extruder*/
- ) {
- advanced_pause_mode = mode;
- hotend_status_extruder = extruder;
- const screenFunc_t next_screen = ap_message_screen(message);
- if (next_screen) {
- defer_return_to_status = true;
- lcd_goto_screen(next_screen);
- }
- else
- lcd_return_to_status();
- }
-
- #endif // ADVANCED_PAUSE_FEATURE
-
- /**
- *
- * Functions for editing single values
- *
- * The "DEFINE_MENU_EDIT_TYPE" macro generates the functions needed to edit a numerical value.
- *
- * For example, DEFINE_MENU_EDIT_TYPE(int16_t, int3, itostr3, 1) expands into these functions:
- *
- * bool _menu_edit_int3();
- * void menu_edit_int3(); // edit int16_t (interactively)
- * void menu_edit_callback_int3(); // edit int16_t (interactively) with callback on completion
- * void _menu_action_setting_edit_int3(PGM_P const pstr, int16_t * const ptr, const int16_t minValue, const int16_t maxValue);
- * void menu_action_setting_edit_int3(PGM_P const pstr, int16_t * const ptr, const int16_t minValue, const int16_t maxValue);
- * void menu_action_setting_edit_callback_int3(PGM_P const pstr, int16_t * const ptr, const int16_t minValue, const int16_t maxValue, const screenFunc_t callback, const bool live); // edit int16_t with callback
- *
- * You can then use one of the menu macros to present the edit interface:
- * MENU_ITEM_EDIT(int3, MSG_SPEED, &feedrate_percentage, 10, 999)
- *
- * This expands into a more primitive menu item:
- * MENU_ITEM(setting_edit_int3, MSG_SPEED, PSTR(MSG_SPEED), &feedrate_percentage, 10, 999)
- *
- * ...which calls:
- * menu_action_setting_edit_int3(PSTR(MSG_SPEED), &feedrate_percentage, 10, 999)
- */
- #define DEFINE_MENU_EDIT_TYPE(_type, _name, _strFunc, _scale) \
- bool _menu_edit_ ## _name() { \
- ENCODER_DIRECTION_NORMAL(); \
- if ((int32_t)encoderPosition < 0) encoderPosition = 0; \
- if ((int32_t)encoderPosition > maxEditValue) encoderPosition = maxEditValue; \
- if (lcdDrawUpdate) \
- lcd_implementation_drawedit(editLabel, _strFunc(((_type)((int32_t)encoderPosition + minEditValue)) * (1.0f / _scale))); \
- if (lcd_clicked || (liveEdit && lcdDrawUpdate)) { \
- _type value = ((_type)((int32_t)encoderPosition + minEditValue)) * (1.0f / _scale); \
- if (editValue != NULL) *((_type*)editValue) = value; \
- if (callbackFunc && (liveEdit || lcd_clicked)) (*callbackFunc)(); \
- if (lcd_clicked) lcd_goto_previous_menu(); \
- } \
- return use_click(); \
- } \
- void menu_edit_ ## _name() { _menu_edit_ ## _name(); } \
- void _menu_action_setting_edit_ ## _name(PGM_P const pstr, _type* const ptr, const _type minValue, const _type maxValue) { \
- lcd_save_previous_screen(); \
- lcd_refresh(); \
- \
- editLabel = pstr; \
- editValue = ptr; \
- minEditValue = minValue * _scale; \
- maxEditValue = maxValue * _scale - minEditValue; \
- encoderPosition = (*ptr) * _scale - minEditValue; \
- } \
- void menu_action_setting_edit_callback_ ## _name(PGM_P const pstr, _type * const ptr, const _type minValue, const _type maxValue, const screenFunc_t callback, const bool live) { \
- _menu_action_setting_edit_ ## _name(pstr, ptr, minValue, maxValue); \
- currentScreen = menu_edit_ ## _name; \
- callbackFunc = callback; \
- liveEdit = live; \
- } \
- FORCE_INLINE void menu_action_setting_edit_ ## _name(PGM_P const pstr, _type * const ptr, const _type minValue, const _type maxValue) { \
- menu_action_setting_edit_callback_ ## _name(pstr, ptr, minValue, maxValue); \
- } \
- typedef void _name##_void
-
- DEFINE_MENU_EDIT_TYPE(int16_t, int3, itostr3, 1);
- DEFINE_MENU_EDIT_TYPE(int16_t, int4, itostr4sign, 1);
- DEFINE_MENU_EDIT_TYPE(uint8_t, int8, i8tostr3, 1);
- DEFINE_MENU_EDIT_TYPE(float, float3, ftostr3, 1);
- DEFINE_MENU_EDIT_TYPE(float, float52, ftostr52, 100);
- DEFINE_MENU_EDIT_TYPE(float, float43, ftostr43sign, 1000);
- DEFINE_MENU_EDIT_TYPE(float, float5, ftostr5rj, 0.01f);
- DEFINE_MENU_EDIT_TYPE(float, float51, ftostr51sign, 10);
- DEFINE_MENU_EDIT_TYPE(float, float52sign, ftostr52sign, 100);
- DEFINE_MENU_EDIT_TYPE(float, float62, ftostr62rj, 100);
- DEFINE_MENU_EDIT_TYPE(uint32_t, long5, ftostr5rj, 0.01f);
-
- /**
- *
- * Handlers for Keypad input
- *
- */
- #if ENABLED(ADC_KEYPAD)
-
- inline bool handle_adc_keypad() {
- #define ADC_MIN_KEY_DELAY 100
- if (buttons_reprapworld_keypad) {
- lcdDrawUpdate = LCDVIEW_REDRAW_NOW;
- if (encoderDirection == -1) { // side effect which signals we are inside a menu
- if (buttons_reprapworld_keypad & EN_REPRAPWORLD_KEYPAD_DOWN) encoderPosition -= ENCODER_STEPS_PER_MENU_ITEM;
- else if (buttons_reprapworld_keypad & EN_REPRAPWORLD_KEYPAD_UP) encoderPosition += ENCODER_STEPS_PER_MENU_ITEM;
- else if (buttons_reprapworld_keypad & EN_REPRAPWORLD_KEYPAD_LEFT) { menu_action_back(); lcd_quick_feedback(true); }
- else if (buttons_reprapworld_keypad & EN_REPRAPWORLD_KEYPAD_RIGHT) { lcd_return_to_status(); lcd_quick_feedback(true); }
- }
- else {
- if (buttons_reprapworld_keypad & (EN_REPRAPWORLD_KEYPAD_DOWN|EN_REPRAPWORLD_KEYPAD_UP|EN_REPRAPWORLD_KEYPAD_RIGHT)) {
- if (buttons_reprapworld_keypad & EN_REPRAPWORLD_KEYPAD_DOWN) encoderPosition += ENCODER_PULSES_PER_STEP;
- else if (buttons_reprapworld_keypad & EN_REPRAPWORLD_KEYPAD_UP) encoderPosition -= ENCODER_PULSES_PER_STEP;
- else if (buttons_reprapworld_keypad & EN_REPRAPWORLD_KEYPAD_RIGHT) encoderPosition = 0;
- }
- }
- #if ENABLED(ADC_KEYPAD_DEBUG)
- SERIAL_PROTOCOLLNPAIR("buttons_reprapworld_keypad = ", (uint32_t)buttons_reprapworld_keypad);
- SERIAL_PROTOCOLLNPAIR("encoderPosition = ", (uint32_t)encoderPosition);
- #endif
- next_button_update_ms = millis() + ADC_MIN_KEY_DELAY;
- return true;
- }
-
- return false;
- }
-
- #elif ENABLED(REPRAPWORLD_KEYPAD)
-
- void _reprapworld_keypad_move(const AxisEnum axis, const int16_t dir) {
- move_menu_scale = REPRAPWORLD_KEYPAD_MOVE_STEP;
- encoderPosition = dir;
- switch (axis) {
- case X_AXIS: lcd_move_x(); break;
- case Y_AXIS: lcd_move_y(); break;
- case Z_AXIS: lcd_move_z();
- default: break;
- }
- }
- void reprapworld_keypad_move_z_up() { _reprapworld_keypad_move(Z_AXIS, 1); }
- void reprapworld_keypad_move_z_down() { _reprapworld_keypad_move(Z_AXIS, -1); }
- void reprapworld_keypad_move_x_left() { _reprapworld_keypad_move(X_AXIS, -1); }
- void reprapworld_keypad_move_x_right() { _reprapworld_keypad_move(X_AXIS, 1); }
- void reprapworld_keypad_move_y_up() { _reprapworld_keypad_move(Y_AXIS, -1); }
- void reprapworld_keypad_move_y_down() { _reprapworld_keypad_move(Y_AXIS, 1); }
- void reprapworld_keypad_move_home() { enqueue_and_echo_commands_P(PSTR("G28")); } // move all axes home and wait
- void reprapworld_keypad_move_menu() { lcd_goto_screen(lcd_move_menu); }
-
- inline void handle_reprapworld_keypad() {
-
- static uint8_t keypad_debounce = 0;
-
- if (!REPRAPWORLD_KEYPAD_PRESSED) {
- if (keypad_debounce > 0) keypad_debounce--;
- }
- else if (!keypad_debounce) {
- keypad_debounce = 2;
-
- if (REPRAPWORLD_KEYPAD_MOVE_MENU) reprapworld_keypad_move_menu();
-
- #if DISABLED(DELTA) && Z_HOME_DIR == -1
- if (REPRAPWORLD_KEYPAD_MOVE_Z_UP) reprapworld_keypad_move_z_up();
- #endif
-
- if (all_axes_homed()) {
- #if ENABLED(DELTA) || Z_HOME_DIR != -1
- if (REPRAPWORLD_KEYPAD_MOVE_Z_UP) reprapworld_keypad_move_z_up();
- #endif
- if (REPRAPWORLD_KEYPAD_MOVE_Z_DOWN) reprapworld_keypad_move_z_down();
- if (REPRAPWORLD_KEYPAD_MOVE_X_LEFT) reprapworld_keypad_move_x_left();
- if (REPRAPWORLD_KEYPAD_MOVE_X_RIGHT) reprapworld_keypad_move_x_right();
- if (REPRAPWORLD_KEYPAD_MOVE_Y_DOWN) reprapworld_keypad_move_y_down();
- if (REPRAPWORLD_KEYPAD_MOVE_Y_UP) reprapworld_keypad_move_y_up();
- }
- else {
- if (REPRAPWORLD_KEYPAD_MOVE_HOME) reprapworld_keypad_move_home();
- }
- }
- }
-
- #endif // REPRAPWORLD_KEYPAD
-
- /**
- *
- * Menu actions
- *
- */
- void _menu_action_back() { lcd_goto_previous_menu(); }
- void menu_action_submenu(screenFunc_t func) { lcd_save_previous_screen(); lcd_goto_screen(func); }
- void menu_action_gcode(PGM_P pgcode) { enqueue_and_echo_commands_P(pgcode); }
- void menu_action_function(screenFunc_t func) { (*func)(); }
-
- #if ENABLED(SDSUPPORT)
-
- void menu_action_sdfile(CardReader &theCard) {
- #if ENABLED(SD_REPRINT_LAST_SELECTED_FILE)
- last_sdfile_encoderPosition = encoderPosition; // Save which file was selected for later use
- #endif
- card.openAndPrintFile(theCard.filename);
- lcd_return_to_status();
- lcd_reset_status();
- }
-
- void menu_action_sddirectory(CardReader &theCard) {
- card.chdir(theCard.filename);
- encoderTopLine = 0;
- encoderPosition = 2 * ENCODER_STEPS_PER_MENU_ITEM;
- screen_changed = true;
- #if ENABLED(DOGLCD)
- drawing_screen = false;
- #endif
- lcd_refresh();
- }
-
- #endif // SDSUPPORT
-
- void menu_action_setting_edit_bool(PGM_P pstr, bool* ptr) { UNUSED(pstr); *ptr ^= true; lcd_refresh(); }
- void menu_action_setting_edit_callback_bool(PGM_P pstr, bool* ptr, screenFunc_t callback) {
- menu_action_setting_edit_bool(pstr, ptr);
- (*callback)();
- }
-
-#endif // ULTIPANEL
+#endif
void lcd_init() {
@@ -5406,6 +218,392 @@ bool lcd_blink() {
return blink != 0;
}
+////////////////////////////////////////////
+///////////// Keypad Handling //////////////
+////////////////////////////////////////////
+
+#if ENABLED(REPRAPWORLD_KEYPAD)
+ volatile uint8_t buttons_reprapworld_keypad;
+#endif
+
+#if ENABLED(ADC_KEYPAD)
+
+ #define KEYPAD_HOME EN_REPRAPWORLD_KEYPAD_F1
+ #define KEYPAD_EN_C EN_REPRAPWORLD_KEYPAD_MIDDLE
+
+ inline bool handle_adc_keypad() {
+ #define ADC_MIN_KEY_DELAY 100
+ if (buttons_reprapworld_keypad) {
+ lcdDrawUpdate = LCDVIEW_REDRAW_NOW;
+ if (encoderDirection == -1) { // side effect which signals we are inside a menu
+ if (buttons_reprapworld_keypad & EN_REPRAPWORLD_KEYPAD_DOWN) encoderPosition -= ENCODER_STEPS_PER_MENU_ITEM;
+ else if (buttons_reprapworld_keypad & EN_REPRAPWORLD_KEYPAD_UP) encoderPosition += ENCODER_STEPS_PER_MENU_ITEM;
+ else if (buttons_reprapworld_keypad & EN_REPRAPWORLD_KEYPAD_LEFT) { menu_action_back(); lcd_quick_feedback(true); }
+ else if (buttons_reprapworld_keypad & EN_REPRAPWORLD_KEYPAD_RIGHT) { lcd_return_to_status(); lcd_quick_feedback(true); }
+ }
+ else {
+ if (buttons_reprapworld_keypad & (EN_REPRAPWORLD_KEYPAD_DOWN|EN_REPRAPWORLD_KEYPAD_UP|EN_REPRAPWORLD_KEYPAD_RIGHT)) {
+ if (buttons_reprapworld_keypad & EN_REPRAPWORLD_KEYPAD_DOWN) encoderPosition += ENCODER_PULSES_PER_STEP;
+ else if (buttons_reprapworld_keypad & EN_REPRAPWORLD_KEYPAD_UP) encoderPosition -= ENCODER_PULSES_PER_STEP;
+ else if (buttons_reprapworld_keypad & EN_REPRAPWORLD_KEYPAD_RIGHT) encoderPosition = 0;
+ }
+ }
+ #if ENABLED(ADC_KEYPAD_DEBUG)
+ SERIAL_PROTOCOLLNPAIR("buttons_reprapworld_keypad = ", (uint32_t)buttons_reprapworld_keypad);
+ SERIAL_PROTOCOLLNPAIR("encoderPosition = ", (uint32_t)encoderPosition);
+ #endif
+ next_button_update_ms = millis() + ADC_MIN_KEY_DELAY;
+ return true;
+ }
+
+ return false;
+ }
+
+#elif ENABLED(REPRAPWORLD_KEYPAD)
+
+ #define REPRAPWORLD_BTN_OFFSET 0 // bit offset into buttons for shift register values
+
+ #define BLEN_REPRAPWORLD_KEYPAD_F3 0
+ #define BLEN_REPRAPWORLD_KEYPAD_F2 1
+ #define BLEN_REPRAPWORLD_KEYPAD_F1 2
+ #define BLEN_REPRAPWORLD_KEYPAD_DOWN 3
+ #define BLEN_REPRAPWORLD_KEYPAD_RIGHT 4
+ #define BLEN_REPRAPWORLD_KEYPAD_MIDDLE 5
+ #define BLEN_REPRAPWORLD_KEYPAD_UP 6
+ #define BLEN_REPRAPWORLD_KEYPAD_LEFT 7
+
+ #define EN_REPRAPWORLD_KEYPAD_F3 (_BV(REPRAPWORLD_BTN_OFFSET + BLEN_REPRAPWORLD_KEYPAD_F3))
+ #define EN_REPRAPWORLD_KEYPAD_F2 (_BV(REPRAPWORLD_BTN_OFFSET + BLEN_REPRAPWORLD_KEYPAD_F2))
+ #define EN_REPRAPWORLD_KEYPAD_F1 (_BV(REPRAPWORLD_BTN_OFFSET + BLEN_REPRAPWORLD_KEYPAD_F1))
+ #define EN_REPRAPWORLD_KEYPAD_DOWN (_BV(REPRAPWORLD_BTN_OFFSET + BLEN_REPRAPWORLD_KEYPAD_DOWN))
+ #define EN_REPRAPWORLD_KEYPAD_RIGHT (_BV(REPRAPWORLD_BTN_OFFSET + BLEN_REPRAPWORLD_KEYPAD_RIGHT))
+ #define EN_REPRAPWORLD_KEYPAD_MIDDLE (_BV(REPRAPWORLD_BTN_OFFSET + BLEN_REPRAPWORLD_KEYPAD_MIDDLE))
+ #define EN_REPRAPWORLD_KEYPAD_UP (_BV(REPRAPWORLD_BTN_OFFSET + BLEN_REPRAPWORLD_KEYPAD_UP))
+ #define EN_REPRAPWORLD_KEYPAD_LEFT (_BV(REPRAPWORLD_BTN_OFFSET + BLEN_REPRAPWORLD_KEYPAD_LEFT))
+
+ #define REPRAPWORLD_KEYPAD_MOVE_Z_DOWN (buttons_reprapworld_keypad & EN_REPRAPWORLD_KEYPAD_F3)
+ #define REPRAPWORLD_KEYPAD_MOVE_Z_UP (buttons_reprapworld_keypad & EN_REPRAPWORLD_KEYPAD_F2)
+ #define REPRAPWORLD_KEYPAD_MOVE_Y_DOWN (buttons_reprapworld_keypad & EN_REPRAPWORLD_KEYPAD_DOWN)
+ #define REPRAPWORLD_KEYPAD_MOVE_X_RIGHT (buttons_reprapworld_keypad & EN_REPRAPWORLD_KEYPAD_RIGHT)
+ #define REPRAPWORLD_KEYPAD_MOVE_Y_UP (buttons_reprapworld_keypad & EN_REPRAPWORLD_KEYPAD_UP)
+ #define REPRAPWORLD_KEYPAD_MOVE_X_LEFT (buttons_reprapworld_keypad & EN_REPRAPWORLD_KEYPAD_LEFT)
+
+ #define KEYPAD_HOME EN_REPRAPWORLD_KEYPAD_MIDDLE
+ #define KEYPAD_EN_C EN_REPRAPWORLD_KEYPAD_F1
+ #define REPRAPWORLD_KEYPAD_MOVE_HOME (buttons_reprapworld_keypad & KEYPAD_HOME)
+ #define REPRAPWORLD_KEYPAD_MOVE_MENU (buttons_reprapworld_keypad & KEYPAD_EN_C)
+
+ #define REPRAPWORLD_KEYPAD_PRESSED (buttons_reprapworld_keypad & ( \
+ EN_REPRAPWORLD_KEYPAD_F3 | \
+ EN_REPRAPWORLD_KEYPAD_F2 | \
+ EN_REPRAPWORLD_KEYPAD_F1 | \
+ EN_REPRAPWORLD_KEYPAD_DOWN | \
+ EN_REPRAPWORLD_KEYPAD_RIGHT | \
+ EN_REPRAPWORLD_KEYPAD_MIDDLE | \
+ EN_REPRAPWORLD_KEYPAD_UP | \
+ EN_REPRAPWORLD_KEYPAD_LEFT) \
+ )
+
+ void _reprapworld_keypad_move(const AxisEnum axis, const int16_t dir) {
+ move_menu_scale = REPRAPWORLD_KEYPAD_MOVE_STEP;
+ encoderPosition = dir;
+ switch (axis) {
+ case X_AXIS: lcd_move_x(); break;
+ case Y_AXIS: lcd_move_y(); break;
+ case Z_AXIS: lcd_move_z();
+ default: break;
+ }
+ }
+ inline void reprapworld_keypad_move_z_up() { _reprapworld_keypad_move(Z_AXIS, 1); }
+ inline void reprapworld_keypad_move_z_down() { _reprapworld_keypad_move(Z_AXIS, -1); }
+ inline void reprapworld_keypad_move_x_left() { _reprapworld_keypad_move(X_AXIS, -1); }
+ inline void reprapworld_keypad_move_x_right() { _reprapworld_keypad_move(X_AXIS, 1); }
+ inline void reprapworld_keypad_move_y_up() { _reprapworld_keypad_move(Y_AXIS, -1); }
+ inline void reprapworld_keypad_move_y_down() { _reprapworld_keypad_move(Y_AXIS, 1); }
+ inline void reprapworld_keypad_move_home() { enqueue_and_echo_commands_P(PSTR("G28")); } // move all axes home and wait
+ inline void reprapworld_keypad_move_menu() { lcd_goto_screen(menu_move); }
+
+ inline void handle_reprapworld_keypad() {
+
+ static uint8_t keypad_debounce = 0;
+
+ if (!REPRAPWORLD_KEYPAD_PRESSED) {
+ if (keypad_debounce > 0) keypad_debounce--;
+ }
+ else if (!keypad_debounce) {
+ keypad_debounce = 2;
+
+ if (REPRAPWORLD_KEYPAD_MOVE_MENU) reprapworld_keypad_move_menu();
+
+ #if DISABLED(DELTA) && Z_HOME_DIR == -1
+ if (REPRAPWORLD_KEYPAD_MOVE_Z_UP) reprapworld_keypad_move_z_up();
+ #endif
+
+ if (all_axes_homed()) {
+ #if ENABLED(DELTA) || Z_HOME_DIR != -1
+ if (REPRAPWORLD_KEYPAD_MOVE_Z_UP) reprapworld_keypad_move_z_up();
+ #endif
+ if (REPRAPWORLD_KEYPAD_MOVE_Z_DOWN) reprapworld_keypad_move_z_down();
+ if (REPRAPWORLD_KEYPAD_MOVE_X_LEFT) reprapworld_keypad_move_x_left();
+ if (REPRAPWORLD_KEYPAD_MOVE_X_RIGHT) reprapworld_keypad_move_x_right();
+ if (REPRAPWORLD_KEYPAD_MOVE_Y_DOWN) reprapworld_keypad_move_y_down();
+ if (REPRAPWORLD_KEYPAD_MOVE_Y_UP) reprapworld_keypad_move_y_up();
+ }
+ else {
+ if (REPRAPWORLD_KEYPAD_MOVE_HOME) reprapworld_keypad_move_home();
+ }
+ }
+ }
+
+#endif // REPRAPWORLD_KEYPAD
+
+/**
+ * Status Screen
+ *
+ * This is very display-dependent, so the lcd implementation draws this.
+ */
+
+#if LCD_INFO_SCREEN_STYLE == 0
+ void lcd_impl_status_screen_0();
+#elif LCD_INFO_SCREEN_STYLE == 1
+ void lcd_impl_status_screen_1();
+#endif
+
+void lcd_status_screen() {
+
+ #if ENABLED(ULTIPANEL)
+ ENCODER_DIRECTION_NORMAL();
+ ENCODER_RATE_MULTIPLY(false);
+ #endif
+
+ #if ENABLED(LCD_SET_PROGRESS_MANUALLY) && ENABLED(SDSUPPORT) && (ENABLED(LCD_PROGRESS_BAR) || ENABLED(DOGLCD))
+ // Progress bar % comes from SD when actively printing
+ if (IS_SD_PRINTING())
+ progress_bar_percent = card.percentDone();
+ #endif
+
+ #if ENABLED(LCD_PROGRESS_BAR)
+
+ //
+ // HD44780 implements the following message blinking and
+ // message expiration because Status Line and Progress Bar
+ // share the same line on the display.
+ //
+
+ millis_t ms = millis();
+
+ // If the message will blink rather than expire...
+ #if DISABLED(PROGRESS_MSG_ONCE)
+ if (ELAPSED(ms, progress_bar_ms + PROGRESS_BAR_MSG_TIME + PROGRESS_BAR_BAR_TIME))
+ progress_bar_ms = ms;
+ #endif
+
+ #if PROGRESS_MSG_EXPIRE > 0
+
+ // Handle message expire
+ if (expire_status_ms > 0) {
+
+ #if DISABLED(LCD_SET_PROGRESS_MANUALLY)
+ const uint8_t progress_bar_percent = card.percentDone();
+ #endif
+
+ // Expire the message if a job is active and the bar has ticks
+ if (progress_bar_percent > 2 && !print_job_timer.isPaused()) {
+ if (ELAPSED(ms, expire_status_ms)) {
+ lcd_status_message[0] = '\0';
+ expire_status_ms = 0;
+ }
+ }
+ else {
+ // Defer message expiration before bar appears
+ // and during any pause (not just SD)
+ expire_status_ms += LCD_UPDATE_INTERVAL;
+ }
+ }
+
+ #endif // PROGRESS_MSG_EXPIRE
+
+ #endif // LCD_PROGRESS_BAR
+
+ #if ENABLED(ULTIPANEL)
+
+ if (use_click()) {
+ #if ENABLED(FILAMENT_LCD_DISPLAY) && ENABLED(SDSUPPORT)
+ previous_lcd_status_ms = millis(); // get status message to show up for a while
+ #endif
+ lcd_implementation_init( // to maybe revive the LCD if static electricity killed it.
+ #if ENABLED(LCD_PROGRESS_BAR)
+ CHARSET_MENU
+ #endif
+ );
+ lcd_goto_screen(menu_main);
+ return;
+ }
+
+ #if ENABLED(ULTIPANEL_FEEDMULTIPLY)
+ const int16_t new_frm = feedrate_percentage + (int32_t)encoderPosition;
+ // Dead zone at 100% feedrate
+ if ((feedrate_percentage < 100 && new_frm > 100) || (feedrate_percentage > 100 && new_frm < 100)) {
+ feedrate_percentage = 100;
+ encoderPosition = 0;
+ }
+ else if (feedrate_percentage == 100) {
+ if ((int32_t)encoderPosition > ENCODER_FEEDRATE_DEADZONE) {
+ feedrate_percentage += (int32_t)encoderPosition - (ENCODER_FEEDRATE_DEADZONE);
+ encoderPosition = 0;
+ }
+ else if ((int32_t)encoderPosition < -(ENCODER_FEEDRATE_DEADZONE)) {
+ feedrate_percentage += (int32_t)encoderPosition + ENCODER_FEEDRATE_DEADZONE;
+ encoderPosition = 0;
+ }
+ }
+ else {
+ feedrate_percentage = new_frm;
+ encoderPosition = 0;
+ }
+ #endif // ULTIPANEL_FEEDMULTIPLY
+
+ feedrate_percentage = constrain(feedrate_percentage, 10, 999);
+
+ #endif // ULTIPANEL
+
+ #if LCD_INFO_SCREEN_STYLE == 0
+ lcd_impl_status_screen_0();
+ #elif LCD_INFO_SCREEN_STYLE == 1
+ lcd_impl_status_screen_1();
+ #endif
+}
+
+/**
+ * Reset the status message
+ */
+void lcd_reset_status() {
+ static const char paused[] PROGMEM = MSG_PRINT_PAUSED;
+ static const char printing[] PROGMEM = MSG_PRINTING;
+ static const char welcome[] PROGMEM = WELCOME_MSG;
+ PGM_P msg;
+ if (print_job_timer.isPaused())
+ msg = paused;
+ #if ENABLED(SDSUPPORT)
+ else if (card.sdprinting)
+ return lcd_setstatus(card.longest_filename(), true);
+ #endif
+ else if (print_job_timer.isRunning())
+ msg = printing;
+ else
+ msg = welcome;
+
+ lcd_setstatusPGM(msg, -1);
+}
+
+void kill_screen(PGM_P lcd_msg) {
+ lcd_init();
+ lcd_setalertstatusPGM(lcd_msg);
+ lcd_kill_screen();
+}
+
+#if HAS_BUZZER
+ void lcd_buzz(const long duration, const uint16_t freq) {
+ #if ENABLED(LCD_USE_I2C_BUZZER)
+ lcd.buzz(duration, freq);
+ #elif PIN_EXISTS(BEEPER)
+ buzzer.tone(duration, freq);
+ #endif
+ }
+#endif
+
+void lcd_quick_feedback(const bool clear_buttons) {
+
+ #if ENABLED(ULTIPANEL)
+ lcd_refresh();
+ if (clear_buttons) buttons = 0;
+ next_button_update_ms = millis() + 500;
+ #else
+ UNUSED(clear_buttons);
+ #endif
+
+ // Buzz and wait. The delay is needed for buttons to settle!
+ lcd_buzz(LCD_FEEDBACK_FREQUENCY_DURATION_MS, LCD_FEEDBACK_FREQUENCY_HZ);
+
+ #if ENABLED(ULTIPANEL)
+ #if ENABLED(LCD_USE_I2C_BUZZER)
+ delay(10);
+ #elif PIN_EXISTS(BEEPER)
+ for (int8_t i = 5; i--;) { buzzer.tick(); delay(2); }
+ #endif
+ #endif
+}
+
+#if ENABLED(ULTIPANEL)
+
+ extern bool no_reentry; // Flag to prevent recursion into menu handlers
+
+ int8_t manual_move_axis = (int8_t)NO_AXIS;
+ millis_t manual_move_start_time = 0;
+
+ #if IS_KINEMATIC
+ bool processing_manual_move = false;
+ float manual_move_offset = 0;
+ #endif
+
+ #if !IS_KINEMATIC || (IS_KINEMATIC && EXTRUDERS > 1)
+ int8_t manual_move_e_index = 0;
+ #else
+ constexpr int8_t manual_move_e_index = 0;
+ #endif
+
+ /**
+ * If the most recent manual move hasn't been fed to the planner yet,
+ * and the planner can accept one, send a move immediately.
+ */
+ void manage_manual_move() {
+
+ if (processing_manual_move) return;
+
+ if (manual_move_axis != (int8_t)NO_AXIS && ELAPSED(millis(), manual_move_start_time) && !planner.is_full()) {
+
+ #if IS_KINEMATIC
+
+ const float old_feedrate = feedrate_mm_s;
+ feedrate_mm_s = MMM_TO_MMS(manual_feedrate_mm_m[manual_move_axis]);
+
+ #if EXTRUDERS > 1
+ const int8_t old_extruder = active_extruder;
+ if (manual_move_axis == E_AXIS) active_extruder = manual_move_e_index;
+ #endif
+
+ // Set movement on a single axis
+ set_destination_from_current();
+ destination[manual_move_axis] += manual_move_offset;
+
+ // Reset for the next move
+ manual_move_offset = 0;
+ manual_move_axis = (int8_t)NO_AXIS;
+
+ // DELTA and SCARA machines use segmented moves, which could fill the planner during the call to
+ // move_to_destination. This will cause idle() to be called, which can then call this function while the
+ // previous invocation is being blocked. Modifications to manual_move_offset shouldn't be made while
+ // processing_manual_move is true or the planner will get out of sync.
+ processing_manual_move = true;
+ prepare_move_to_destination(); // will call set_current_from_destination()
+ processing_manual_move = false;
+
+ feedrate_mm_s = old_feedrate;
+ #if EXTRUDERS > 1
+ active_extruder = old_extruder;
+ #endif
+
+ #else
+
+ planner.buffer_line(current_position, MMM_TO_MMS(manual_feedrate_mm_m[manual_move_axis]), manual_move_axis == E_AXIS ? manual_move_e_index : active_extruder);
+ manual_move_axis = (int8_t)NO_AXIS;
+
+ #endif
+ }
+ }
+
+#endif // ULTIPANEL
+
/**
* Update the LCD, read encoder buttons, etc.
* - Read button states
@@ -5436,10 +634,24 @@ bool lcd_blink() {
* - Clear the LCD if lcdDrawUpdate == LCDVIEW_CLEAR_CALL_REDRAW
* - Update lcdDrawUpdate for the next loop (i.e., move one state down, usually)
*
- * No worries. This function is only called from the main thread.
+ * This function is only called from the main thread.
*/
+
+LCDViewAction lcdDrawUpdate = LCDVIEW_CLEAR_CALL_REDRAW;
+
+#if ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(G26_MESH_VALIDATION)
+ bool lcd_external_control; // = false
+#endif
+
+#if ENABLED(LCD_HAS_SLOW_BUTTONS)
+ volatile uint8_t slow_buttons;
+#endif
+
void lcd_update() {
+ static uint16_t max_display_update_time = 0;
+ static millis_t next_lcd_update_ms;
+
#if ENABLED(ULTIPANEL)
static millis_t return_to_status_ms = 0;
@@ -5511,7 +723,7 @@ void lcd_update() {
#if ENABLED(POWER_LOSS_RECOVERY)
if (job_recovery_commands_count && job_recovery_phase == JOB_RECOVERY_IDLE) {
- lcd_goto_screen(lcd_job_recovery_menu);
+ lcd_goto_screen(menu_job_recovery);
job_recovery_phase = JOB_RECOVERY_MAYBE; // Waiting for a response
}
#endif
@@ -5584,10 +796,11 @@ void lcd_update() {
return_to_status_ms = ms + LCD_TIMEOUT_TO_STATUS;
lcdDrawUpdate = LCDVIEW_REDRAW_NOW;
}
+
#endif // ULTIPANEL
- // We arrive here every ~100ms when idling often enough.
- // Instead of tracking the changes simply redraw the Info Screen ~1 time a second.
+ // This runs every ~100ms when idling often enough.
+ // Instead of tracking changes just redraw the Status Screen once per second.
if (
#if ENABLED(ULTIPANEL)
currentScreen == lcd_status_screen &&
@@ -5606,7 +819,7 @@ void lcd_update() {
#if ENABLED(ULTIPANEL) && ENABLED(SCROLL_LONG_FILENAMES)
// If scrolling of long file names is enabled and we are in the sd card menu,
// cause a refresh to occur until all the text has scrolled into view.
- if (currentScreen == lcd_sdcard_menu && filename_scroll_pos < filename_scroll_max && !lcd_status_update_delay--) {
+ if (currentScreen == menu_sdcard && filename_scroll_pos < filename_scroll_max && !lcd_status_update_delay--) {
lcd_status_update_delay = 6;
lcdDrawUpdate = LCDVIEW_REDRAW_NOW;
filename_scroll_pos++;
@@ -5618,15 +831,15 @@ void lcd_update() {
uint16_t bbr2 = planner.block_buffer_runtime() >> 1;
#if ENABLED(DOGLCD)
- #define IS_DRAWING drawing_screen
+ const bool &is_drawing = drawing_screen;
#else
- #define IS_DRAWING false
+ constexpr bool is_drawing = false;
#endif
- if ((lcdDrawUpdate || IS_DRAWING) && (!bbr2 || bbr2 > max_display_update_time)) {
+ if ((lcdDrawUpdate || is_drawing) && (!bbr2 || bbr2 > max_display_update_time)) {
// Change state of drawing flag between screen updates
- if (!IS_DRAWING) switch (lcdDrawUpdate) {
+ if (!is_drawing) switch (lcdDrawUpdate) {
case LCDVIEW_CALL_NO_REDRAW:
lcdDrawUpdate = LCDVIEW_NONE;
break;
@@ -5703,7 +916,7 @@ void lcd_update() {
#endif // ULTIPANEL
// Change state of drawing flag between screen updates
- if (!IS_DRAWING) switch (lcdDrawUpdate) {
+ if (!is_drawing) switch (lcdDrawUpdate) {
case LCDVIEW_CLEAR_CALL_REDRAW:
lcd_implementation_clear(); break;
case LCDVIEW_REDRAW_NOW:
@@ -5817,6 +1030,44 @@ void lcd_setalertstatusPGM(PGM_P const message) {
void lcd_reset_alert_level() { lcd_status_message_level = 0; }
+#if ENABLED(ADC_KEYPAD)
+
+ typedef struct {
+ uint16_t ADCKeyValueMin, ADCKeyValueMax;
+ uint8_t ADCKeyNo;
+ } _stADCKeypadTable_;
+
+ static const _stADCKeypadTable_ stADCKeyTable[] PROGMEM = {
+ // VALUE_MIN, VALUE_MAX, KEY
+ { 4000, 4096, BLEN_REPRAPWORLD_KEYPAD_F1 + 1 }, // F1
+ { 4000, 4096, BLEN_REPRAPWORLD_KEYPAD_F2 + 1 }, // F2
+ { 4000, 4096, BLEN_REPRAPWORLD_KEYPAD_F3 + 1 }, // F3
+ { 300, 500, BLEN_REPRAPWORLD_KEYPAD_LEFT + 1 }, // LEFT
+ { 1900, 2200, BLEN_REPRAPWORLD_KEYPAD_RIGHT + 1 }, // RIGHT
+ { 570, 870, BLEN_REPRAPWORLD_KEYPAD_UP + 1 }, // UP
+ { 2670, 2870, BLEN_REPRAPWORLD_KEYPAD_DOWN + 1 }, // DOWN
+ { 1150, 1450, BLEN_REPRAPWORLD_KEYPAD_MIDDLE + 1 }, // ENTER
+ };
+
+ uint8_t get_ADC_keyValue(void) {
+ if (thermalManager.ADCKey_count >= 16) {
+ const uint16_t currentkpADCValue = thermalManager.current_ADCKey_raw >> 2;
+ #if ENABLED(ADC_KEYPAD_DEBUG)
+ SERIAL_PROTOCOLLN(currentkpADCValue);
+ #endif
+ thermalManager.current_ADCKey_raw = 0;
+ thermalManager.ADCKey_count = 0;
+ if (currentkpADCValue < 4000)
+ for (uint8_t i = 0; i < ADC_KEY_NUM; i++) {
+ const uint16_t lo = pgm_read_word(&stADCKeyTable[i].ADCKeyValueMin),
+ hi = pgm_read_word(&stADCKeyTable[i].ADCKeyValueMax);
+ if (WITHIN(currentkpADCValue, lo, hi)) return pgm_read_byte(&stADCKeyTable[i].ADCKeyNo);
+ }
+ }
+ return 0;
+ }
+#endif
+
#if ENABLED(ULTIPANEL)
/**
@@ -5843,6 +1094,25 @@ void lcd_reset_alert_level() { lcd_status_message_level = 0; }
} \
DST = ~new_##DST; //invert it, because a pressed switch produces a logical 0
+ #if (ENABLED(LCD_I2C_TYPE_MCP23017) || ENABLED(LCD_I2C_TYPE_MCP23008)) && ENABLED(DETECT_DEVICE)
+ bool lcd_detected() { return lcd.LcdDetected() == 1; }
+ #else
+ bool lcd_detected() { return true; }
+ #endif
+
+ #if ENABLED(G26_MESH_VALIDATION)
+ void lcd_chirp() {
+ lcd_buzz(LCD_FEEDBACK_FREQUENCY_DURATION_MS, LCD_FEEDBACK_FREQUENCY_HZ);
+ }
+ #endif
+
+ #if ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(G26_MESH_VALIDATION)
+ bool is_lcd_clicked() { return LCD_CLICKED; }
+ void wait_for_release() {
+ while (is_lcd_clicked()) safe_delay(50);
+ safe_delay(50);
+ }
+ #endif
/**
* Read encoder buttons from the hardware registers
@@ -5982,64 +1252,6 @@ void lcd_reset_alert_level() { lcd_status_message_level = 0; }
}
}
- #if (ENABLED(LCD_I2C_TYPE_MCP23017) || ENABLED(LCD_I2C_TYPE_MCP23008)) && ENABLED(DETECT_DEVICE)
- bool lcd_detected() { return lcd.LcdDetected() == 1; }
- #else
- bool lcd_detected() { return true; }
- #endif
-
- #if ENABLED(G26_MESH_VALIDATION)
- void lcd_chirp() {
- lcd_buzz(LCD_FEEDBACK_FREQUENCY_DURATION_MS, LCD_FEEDBACK_FREQUENCY_HZ);
- }
- #endif
-
- #if ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(G26_MESH_VALIDATION)
- bool is_lcd_clicked() { return LCD_CLICKED; }
- void wait_for_release() {
- while (is_lcd_clicked()) safe_delay(50);
- safe_delay(50);
- }
- #endif
-
#endif // ULTIPANEL
-#if ENABLED(ADC_KEYPAD)
-
- typedef struct {
- uint16_t ADCKeyValueMin, ADCKeyValueMax;
- uint8_t ADCKeyNo;
- } _stADCKeypadTable_;
-
- static const _stADCKeypadTable_ stADCKeyTable[] PROGMEM = {
- // VALUE_MIN, VALUE_MAX, KEY
- { 4000, 4096, BLEN_REPRAPWORLD_KEYPAD_F1 + 1 }, // F1
- { 4000, 4096, BLEN_REPRAPWORLD_KEYPAD_F2 + 1 }, // F2
- { 4000, 4096, BLEN_REPRAPWORLD_KEYPAD_F3 + 1 }, // F3
- { 300, 500, BLEN_REPRAPWORLD_KEYPAD_LEFT + 1 }, // LEFT
- { 1900, 2200, BLEN_REPRAPWORLD_KEYPAD_RIGHT + 1 }, // RIGHT
- { 570, 870, BLEN_REPRAPWORLD_KEYPAD_UP + 1 }, // UP
- { 2670, 2870, BLEN_REPRAPWORLD_KEYPAD_DOWN + 1 }, // DOWN
- { 1150, 1450, BLEN_REPRAPWORLD_KEYPAD_MIDDLE + 1 }, // ENTER
- };
-
- uint8_t get_ADC_keyValue(void) {
- if (thermalManager.ADCKey_count >= 16) {
- const uint16_t currentkpADCValue = thermalManager.current_ADCKey_raw >> 2;
- #if ENABLED(ADC_KEYPAD_DEBUG)
- SERIAL_PROTOCOLLN(currentkpADCValue);
- #endif
- thermalManager.current_ADCKey_raw = 0;
- thermalManager.ADCKey_count = 0;
- if (currentkpADCValue < 4000)
- for (uint8_t i = 0; i < ADC_KEY_NUM; i++) {
- const uint16_t lo = pgm_read_word(&stADCKeyTable[i].ADCKeyValueMin),
- hi = pgm_read_word(&stADCKeyTable[i].ADCKeyValueMax);
- if (WITHIN(currentkpADCValue, lo, hi)) return pgm_read_byte(&stADCKeyTable[i].ADCKeyNo);
- }
- }
- return 0;
- }
-#endif
-
#endif // ULTRA_LCD
diff --git a/Marlin/src/lcd/ultralcd.h b/Marlin/src/lcd/ultralcd.h
index 85f2701ae7..e24673c25c 100644
--- a/Marlin/src/lcd/ultralcd.h
+++ b/Marlin/src/lcd/ultralcd.h
@@ -19,13 +19,165 @@
* along with this program. If not, see .
*
*/
-
-#ifndef ULTRALCD_H
-#define ULTRALCD_H
+#pragma once
#include "../inc/MarlinConfig.h"
-#if ENABLED(ULTRA_LCD) || ENABLED(MALYAN_LCD) || ENABLED(EXTENSIBLE_UI)
+#if HAS_GRAPHICAL_LCD
+
+ #ifndef LCD_PIXEL_WIDTH
+ #define LCD_PIXEL_WIDTH 128
+ #endif
+ #ifndef LCD_PIXEL_HEIGHT
+ #define LCD_PIXEL_HEIGHT 64
+ #endif
+
+ // LCD selection
+ #if ENABLED(REPRAPWORLD_GRAPHICAL_LCD)
+ #define U8G_CLASS U8GLIB_ST7920_128X64_4X
+ #if DISABLED(SDSUPPORT) && (LCD_PINS_D4 == SCK_PIN) && (LCD_PINS_ENABLE == MOSI_PIN)
+ #define U8G_PARAM LCD_PINS_RS
+ #else
+ #define U8G_PARAM LCD_PINS_D4, LCD_PINS_ENABLE, LCD_PINS_RS
+ #endif
+
+ #elif ENABLED(U8GLIB_ST7920)
+ // RepRap Discount Full Graphics Smart Controller
+ #if DISABLED(SDSUPPORT) && (LCD_PINS_D4 == SCK_PIN) && (LCD_PINS_ENABLE == MOSI_PIN)
+ #define U8G_CLASS U8GLIB_ST7920_128X64_4X_HAL
+ #define U8G_PARAM LCD_PINS_RS // 2 stripes, HW SPI (shared with SD card, on AVR does not use standard LCD adapter)
+ #else
+ //#define U8G_CLASS U8GLIB_ST7920_128X64_4X
+ //#define U8G_PARAM LCD_PINS_D4, LCD_PINS_ENABLE, LCD_PINS_RS // Original u8glib device. 2 stripes, SW SPI
+ #define U8G_CLASS U8GLIB_ST7920_128X64_RRD
+ #define U8G_PARAM LCD_PINS_D4, LCD_PINS_ENABLE, LCD_PINS_RS // Number of stripes can be adjusted in ultralcd_st7920_u8glib_rrd.h with PAGE_HEIGHT
+ // AVR version ignores these pin settings
+ // HAL version uses these pin settings
+ #endif
+
+ #elif ENABLED(CARTESIO_UI)
+ // The CartesioUI display
+ //#define U8G_CLASS U8GLIB_DOGM128_2X
+ //#define U8G_PARAM DOGLCD_SCK, DOGLCD_MOSI, DOGLCD_CS, DOGLCD_A0 // 4 stripes
+ #define U8G_CLASS U8GLIB_DOGM128_2X
+ #define U8G_PARAM DOGLCD_CS, DOGLCD_A0 // 4 stripes
+
+ #elif ENABLED(U8GLIB_LM6059_AF)
+ // Based on the Adafruit ST7565 (http://www.adafruit.com/products/250)
+ //#define U8G_CLASS U8GLIB_LM6059
+ //#define U8G_PARAM DOGLCD_CS, DOGLCD_A0 // 8 stripes
+ #define U8G_CLASS U8GLIB_LM6059_2X
+ #define U8G_PARAM DOGLCD_CS, DOGLCD_A0 // 4 stripes
+
+ #elif ENABLED(U8GLIB_ST7565_64128N)
+ // The MaKrPanel, Mini Viki, Viki 2.0 & AZSMZ 12864 ST7565 controller
+ #define SMART_RAMPS (MB(RAMPS_SMART_EFB) || MB(RAMPS_SMART_EEB) || MB(RAMPS_SMART_EFF) || MB(RAMPS_SMART_EEF) || MB(RAMPS_SMART_SF))
+ #if DOGLCD_SCK == SCK_PIN && DOGLCD_MOSI == MOSI_PIN && !SMART_RAMPS
+ #define U8G_CLASS U8GLIB_64128N_2X_HAL
+ #define U8G_PARAM DOGLCD_CS, DOGLCD_A0 // using HW-SPI
+ #else
+ #define U8G_CLASS U8GLIB_64128N_2X_HAL
+ #define U8G_PARAM DOGLCD_SCK, DOGLCD_MOSI, DOGLCD_CS, DOGLCD_A0 // using SW-SPI
+ #endif
+
+ #elif ENABLED(MKS_12864OLED_SSD1306)
+ // MKS 128x64 (SSD1306) OLED I2C LCD
+ #define U8G_CLASS U8GLIB_SSD1306_128X64
+ #define U8G_PARAM DOGLCD_SCK, DOGLCD_MOSI, DOGLCD_CS, DOGLCD_A0 // 8 stripes
+ //#define U8G_CLASS U8GLIB_SSD1306_128X64_2X
+ //#define U8G_PARAM DOGLCD_SCK, DOGLCD_MOSI, DOGLCD_CS, DOGLCD_A0 // 4 stripes
+
+ #elif ENABLED(U8GLIB_SSD1306)
+ // Generic support for SSD1306 OLED I2C LCDs
+ //#define U8G_CLASS U8GLIB_SSD1306_128X64_2X_I2C_2_WIRE
+ //#define U8G_PARAM (U8G_I2C_OPT_NONE | U8G_I2C_OPT_FAST) // 4 stripes
+ #define U8G_CLASS U8GLIB_SSD1306_128X64_2X
+ #define U8G_PARAM (U8G_I2C_OPT_NONE | U8G_I2C_OPT_FAST) // 4 stripes
+
+ #elif ENABLED(MKS_12864OLED)
+ // MKS 128x64 (SH1106) OLED I2C LCD
+ #define U8G_CLASS U8GLIB_SH1106_128X64
+ #define U8G_PARAM DOGLCD_SCK, DOGLCD_MOSI, DOGLCD_CS, DOGLCD_A0 // 8 stripes
+ //#define U8G_CLASS U8GLIB_SH1106_128X64_2X
+ //#define U8G_PARAM DOGLCD_SCK, DOGLCD_MOSI, DOGLCD_CS, DOGLCD_A0 // 4 stripes
+ #elif ENABLED(U8GLIB_SH1106)
+ // Generic support for SH1106 OLED I2C LCDs
+ //#define U8G_CLASS U8GLIB_SH1106_128X64_2X_I2C_2_WIRE
+ //#define U8G_PARAM (U8G_I2C_OPT_NONE | U8G_I2C_OPT_FAST) // 4 stripes
+ #define U8G_CLASS U8GLIB_SH1106_128X64_2X
+ #define U8G_PARAM (U8G_I2C_OPT_NONE | U8G_I2C_OPT_FAST) // 4 stripes
+ #elif ENABLED(U8GLIB_SSD1309)
+ // Generic support for SSD1309 OLED I2C LCDs
+ #define U8G_CLASS U8GLIB_SSD1309_128X64
+ #define U8G_PARAM (U8G_I2C_OPT_NONE | U8G_I2C_OPT_FAST)
+ #elif ENABLED(MINIPANEL)
+ // The MINIPanel display
+ //#define U8G_CLASS U8GLIB_MINI12864
+ //#define U8G_PARAM DOGLCD_CS, DOGLCD_A0 // 8 stripes
+ #define U8G_CLASS U8GLIB_MINI12864_2X
+ #define U8G_PARAM DOGLCD_CS, DOGLCD_A0 // 4 stripes
+ #elif ENABLED(U8GLIB_SH1106_EINSTART)
+ // Connected via motherboard header
+ #define U8G_CLASS U8GLIB_SH1106_128X64
+ #define U8G_PARAM DOGLCD_SCK, DOGLCD_MOSI, DOGLCD_CS, LCD_PINS_DC, LCD_PINS_RS
+ #else
+ // for regular DOGM128 display with HW-SPI
+ //#define U8G_CLASS U8GLIB_DOGM128
+ //#define U8G_PARAM DOGLCD_CS, DOGLCD_A0 // HW-SPI Com: CS, A0 // 8 stripes
+ #define U8G_CLASS U8GLIB_DOGM128_2X
+ #define U8G_PARAM DOGLCD_CS, DOGLCD_A0 // HW-SPI Com: CS, A0 // 4 stripes
+ #endif
+
+ #include
+ #include "dogm/HAL_LCD_class_defines.h"
+ extern U8G_CLASS u8g;
+
+ // DOGM font sizes
+ #define DOG_CHAR_WIDTH 6
+ #define DOG_CHAR_HEIGHT 12
+ #if ENABLED(USE_BIG_EDIT_FONT)
+ #define FONT_MENU_EDIT_NAME u8g_font_9x18
+ #define DOG_CHAR_WIDTH_EDIT 9
+ #define DOG_CHAR_HEIGHT_EDIT 18
+ #else
+ #define FONT_MENU_EDIT_NAME FONT_MENU_NAME
+ #define DOG_CHAR_WIDTH_EDIT DOG_CHAR_WIDTH
+ #define DOG_CHAR_HEIGHT_EDIT DOG_CHAR_HEIGHT
+ #endif
+
+ enum MarlinFont : uint8_t {
+ FONT_STATUSMENU = 1,
+ FONT_SPECIAL,
+ FONT_MENU_EDIT,
+ FONT_MENU,
+ };
+
+ // Only Western languages support big / small fonts
+ #if DISABLED(DISPLAY_CHARSET_ISO10646_1)
+ #undef USE_BIG_EDIT_FONT
+ #undef USE_SMALL_INFOFONT
+ #endif
+
+ #if ENABLED(USE_SMALL_INFOFONT)
+ extern const u8g_fntpgm_uint8_t u8g_font_6x9[];
+ #define INFO_FONT_HEIGHT 7
+ #else
+ #define INFO_FONT_HEIGHT 8
+ #endif
+
+ // For selective rendering within a Y range
+ #define PAGE_UNDER(yb) (u8g.getU8g()->current_page.y0 <= (yb))
+ #define PAGE_CONTAINS(ya, yb) (PAGE_UNDER(yb) && u8g.getU8g()->current_page.y1 >= (ya))
+
+ void lcd_setFont(const MarlinFont font_nr);
+
+ #if ENABLED(LIGHTWEIGHT_UI)
+ void lcd_in_status(const bool inStatus);
+ #endif
+
+#endif // HAS_GRAPHICAL_LCD
+
+#if HAS_SPI_LCD || ENABLED(MALYAN_LCD) || ENABLED(EXTENSIBLE_UI)
void lcd_init();
bool lcd_detected();
void lcd_update();
@@ -38,7 +190,7 @@
inline void lcd_setalertstatusPGM(PGM_P message) { UNUSED(message); }
#endif
-#if ENABLED(ULTRA_LCD)
+#if HAS_SPI_LCD
#include "../Marlin.h"
@@ -71,6 +223,8 @@
#if HAS_BUZZER
void lcd_buzz(const long duration, const uint16_t freq);
+ #else
+ inline void lcd_buzz(const long duration, const uint16_t freq) { UNUSED(duration); UNUSED(freq); }
#endif
void lcd_quick_feedback(const bool clear_buttons); // Audible feedback for a button click - could also be visual
@@ -93,8 +247,8 @@
#endif
#if ENABLED(DOGLCD)
- #define SETCURSOR(col, row) lcd_moveto(col * (DOG_CHAR_WIDTH), (row + 1) * row_height)
- #define SETCURSOR_RJ(len, row) lcd_moveto(LCD_PIXEL_WIDTH - len * (DOG_CHAR_WIDTH), (row + 1) * row_height)
+ #define SETCURSOR(col, row) lcd_moveto(col * (DOG_CHAR_WIDTH), (row + 1) * (DOG_CHAR_HEIGHT))
+ #define SETCURSOR_RJ(len, row) lcd_moveto(LCD_PIXEL_WIDTH - len * (DOG_CHAR_WIDTH), (row + 1) * (DOG_CHAR_HEIGHT))
#else
#define SETCURSOR(col, row) lcd_moveto(col, row)
#define SETCURSOR_RJ(len, row) lcd_moveto(LCD_WIDTH - len, row)
@@ -108,13 +262,14 @@
#define BUTTON_EXISTS(BN) (defined(BTN_## BN) && BTN_## BN >= 0)
#define BUTTON_PRESSED(BN) !READ(BTN_## BN)
- #if ENABLED(ULTIPANEL) // LCD with a click-wheel input
+ #if HAS_LCD_MENU
- extern bool defer_return_to_status;
-
- // Function pointer to menu functions.
typedef void (*screenFunc_t)();
typedef void (*menuAction_t)();
+ extern screenFunc_t currentScreen;
+ void lcd_goto_screen(screenFunc_t screen, const uint32_t encoder=0);
+
+ extern bool lcd_clicked, defer_return_to_status;
extern int16_t lcd_preheat_hotend_temp[2], lcd_preheat_bed_temp[2];
extern uint8_t lcd_preheat_fan_speed[2];
@@ -131,9 +286,14 @@
constexpr bool lcd_wait_for_move = false;
#endif
- void lcd_goto_screen(screenFunc_t screen, const uint32_t encoder=0);
-
- void lcd_completion_feedback(const bool good=true);
+ // Manual Movement
+ constexpr float manual_feedrate_mm_m[XYZE] = MANUAL_FEEDRATE;
+ extern float move_menu_scale;
+ #if IS_KINEMATIC
+ extern bool processing_manual_move;
+ #else
+ constexpr bool processing_manual_move = false;
+ #endif
#if ENABLED(ADVANCED_PAUSE_FEATURE)
void lcd_advanced_pause_show_message(const AdvancedPauseMessage message,
@@ -152,72 +312,29 @@
float lcd_z_offset_edit();
#endif
- #endif
+ #if ENABLED(SCROLL_LONG_FILENAMES)
+ extern uint8_t filename_scroll_pos, filename_scroll_max;
+ #endif
+
+ #endif // ULTIPANEL
#if ENABLED(FILAMENT_LCD_DISPLAY) && ENABLED(SDSUPPORT)
extern millis_t previous_lcd_status_ms;
#endif
- bool lcd_blink();
-
- #if ENABLED(REPRAPWORLD_KEYPAD) // is also ULTIPANEL and NEWPANEL
-
- #define REPRAPWORLD_BTN_OFFSET 0 // bit offset into buttons for shift register values
-
- #define BLEN_REPRAPWORLD_KEYPAD_F3 0
- #define BLEN_REPRAPWORLD_KEYPAD_F2 1
- #define BLEN_REPRAPWORLD_KEYPAD_F1 2
- #define BLEN_REPRAPWORLD_KEYPAD_DOWN 3
- #define BLEN_REPRAPWORLD_KEYPAD_RIGHT 4
- #define BLEN_REPRAPWORLD_KEYPAD_MIDDLE 5
- #define BLEN_REPRAPWORLD_KEYPAD_UP 6
- #define BLEN_REPRAPWORLD_KEYPAD_LEFT 7
-
- #define EN_REPRAPWORLD_KEYPAD_F3 (_BV(REPRAPWORLD_BTN_OFFSET + BLEN_REPRAPWORLD_KEYPAD_F3))
- #define EN_REPRAPWORLD_KEYPAD_F2 (_BV(REPRAPWORLD_BTN_OFFSET + BLEN_REPRAPWORLD_KEYPAD_F2))
- #define EN_REPRAPWORLD_KEYPAD_F1 (_BV(REPRAPWORLD_BTN_OFFSET + BLEN_REPRAPWORLD_KEYPAD_F1))
- #define EN_REPRAPWORLD_KEYPAD_DOWN (_BV(REPRAPWORLD_BTN_OFFSET + BLEN_REPRAPWORLD_KEYPAD_DOWN))
- #define EN_REPRAPWORLD_KEYPAD_RIGHT (_BV(REPRAPWORLD_BTN_OFFSET + BLEN_REPRAPWORLD_KEYPAD_RIGHT))
- #define EN_REPRAPWORLD_KEYPAD_MIDDLE (_BV(REPRAPWORLD_BTN_OFFSET + BLEN_REPRAPWORLD_KEYPAD_MIDDLE))
- #define EN_REPRAPWORLD_KEYPAD_UP (_BV(REPRAPWORLD_BTN_OFFSET + BLEN_REPRAPWORLD_KEYPAD_UP))
- #define EN_REPRAPWORLD_KEYPAD_LEFT (_BV(REPRAPWORLD_BTN_OFFSET + BLEN_REPRAPWORLD_KEYPAD_LEFT))
-
- #define REPRAPWORLD_KEYPAD_MOVE_Z_DOWN (buttons_reprapworld_keypad & EN_REPRAPWORLD_KEYPAD_F3)
- #define REPRAPWORLD_KEYPAD_MOVE_Z_UP (buttons_reprapworld_keypad & EN_REPRAPWORLD_KEYPAD_F2)
- #define REPRAPWORLD_KEYPAD_MOVE_Y_DOWN (buttons_reprapworld_keypad & EN_REPRAPWORLD_KEYPAD_DOWN)
- #define REPRAPWORLD_KEYPAD_MOVE_X_RIGHT (buttons_reprapworld_keypad & EN_REPRAPWORLD_KEYPAD_RIGHT)
- #define REPRAPWORLD_KEYPAD_MOVE_Y_UP (buttons_reprapworld_keypad & EN_REPRAPWORLD_KEYPAD_UP)
- #define REPRAPWORLD_KEYPAD_MOVE_X_LEFT (buttons_reprapworld_keypad & EN_REPRAPWORLD_KEYPAD_LEFT)
-
- #if ENABLED(ADC_KEYPAD)
- #define KEYPAD_HOME EN_REPRAPWORLD_KEYPAD_F1
- #define KEYPAD_EN_C EN_REPRAPWORLD_KEYPAD_MIDDLE
- #else
- #define KEYPAD_HOME EN_REPRAPWORLD_KEYPAD_MIDDLE
- #define KEYPAD_EN_C EN_REPRAPWORLD_KEYPAD_F1
- #endif
- #define REPRAPWORLD_KEYPAD_MOVE_HOME (buttons_reprapworld_keypad & KEYPAD_HOME)
- #define REPRAPWORLD_KEYPAD_MOVE_MENU (buttons_reprapworld_keypad & KEYPAD_EN_C)
-
- #define REPRAPWORLD_KEYPAD_PRESSED (buttons_reprapworld_keypad & ( \
- EN_REPRAPWORLD_KEYPAD_F3 | \
- EN_REPRAPWORLD_KEYPAD_F2 | \
- EN_REPRAPWORLD_KEYPAD_F1 | \
- EN_REPRAPWORLD_KEYPAD_DOWN | \
- EN_REPRAPWORLD_KEYPAD_RIGHT | \
- EN_REPRAPWORLD_KEYPAD_MIDDLE | \
- EN_REPRAPWORLD_KEYPAD_UP | \
- EN_REPRAPWORLD_KEYPAD_LEFT) \
- )
-
+ #if ENABLED(STATUS_MESSAGE_SCROLLING)
+ extern uint8_t status_scroll_offset;
#endif
+ bool lcd_blink();
+
#if ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(G26_MESH_VALIDATION)
bool is_lcd_clicked();
void wait_for_release();
#endif
#elif ENABLED(EXTENSIBLE_UI)
+
// These functions are defined elsewhere
void lcd_setstatus(const char* const message, const bool persist=false);
void lcd_setstatusPGM(const char* const message, const int8_t level=0);
@@ -226,6 +343,7 @@
void lcd_refresh();
void lcd_reset_alert_level();
bool lcd_hasstatus();
+
#else // MALYAN_LCD or no LCD
constexpr bool lcd_wait_for_move = false;
@@ -238,11 +356,11 @@
inline void lcd_reset_alert_level() {}
inline void lcd_reset_status() {}
-#endif // ULTRA_LCD
+#endif
-#if ENABLED(ULTIPANEL)
+#if HAS_LCD_MENU
- #if ENABLED(NEWPANEL) // Uses digital switches, not a shift register
+ #if HAS_DIGITAL_ENCODER
// Wheel spin pins where BA is 00, 10, 11, 01 (1 bit always changes)
#define BLEN_A 0
@@ -273,6 +391,10 @@
#endif
+#if ENABLED(LCD_HAS_SLOW_BUTTONS)
+ extern volatile uint8_t slow_buttons;
+#endif
+
#if ENABLED(REPRAPWORLD_KEYPAD)
#ifdef EN_C
#define LCD_CLICKED ((buttons & EN_C) || REPRAPWORLD_KEYPAD_MOVE_MENU)
@@ -285,6 +407,9 @@
#define LCD_CLICKED false
#endif
+extern uint8_t lcd_status_update_delay;
+extern char lcd_status_message[];
+
#define LCD_MESSAGEPGM(x) lcd_setstatusPGM(PSTR(x))
#define LCD_ALERTMESSAGEPGM(x) lcd_setalertstatusPGM(PSTR(x))
@@ -297,5 +422,22 @@
void lcd_reselect_last_file();
#endif
+// LCD implementations
+void lcd_implementation_clear();
+void lcd_implementation_init();
-#endif // ULTRALCD_H
+#if HAS_GRAPHICAL_LCD
+ extern bool drawing_screen, first_page;
+#elif HAS_SPI_LCD
+ constexpr bool first_page = true;
+#endif
+
+#if HAS_CHARACTER_LCD
+
+ enum HD44780CharSet : uint8_t {
+ CHARSET_MENU,
+ CHARSET_INFO,
+ CHARSET_BOOT
+ };
+
+#endif
diff --git a/Marlin/src/libs/duration_t.h b/Marlin/src/libs/duration_t.h
index f38ab0224d..091bae0e57 100644
--- a/Marlin/src/libs/duration_t.h
+++ b/Marlin/src/libs/duration_t.h
@@ -19,9 +19,9 @@
* along with this program. If not, see .
*
*/
+#pragma once
-#ifndef __DURATION_T__
-#define __DURATION_T__
+#include
struct duration_t {
/**
@@ -163,5 +163,3 @@ struct duration_t {
}
}
};
-
-#endif // __DURATION_T__
diff --git a/Marlin/src/module/motion.h b/Marlin/src/module/motion.h
index 8d8b38d15b..b0e13dd0a4 100644
--- a/Marlin/src/module/motion.h
+++ b/Marlin/src/module/motion.h
@@ -108,7 +108,7 @@ XYZ_DEFS(signed char, home_dir, HOME_DIR);
extern bool soft_endstops_enabled;
void clamp_to_software_endstops(float target[XYZ]);
#else
- #define soft_endstops_enabled false
+ constexpr bool soft_endstops_enabled = false;
#define clamp_to_software_endstops(x) NOOP
#endif
diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp
index 18d30ffe11..6181528c03 100644
--- a/Marlin/src/module/planner.cpp
+++ b/Marlin/src/module/planner.cpp
@@ -141,9 +141,6 @@ float Planner::steps_to_mm[XYZE_N]; // (mm) Millimeters per step
#if ENABLED(DISTINCT_E_FACTORS)
uint8_t Planner::last_extruder = 0; // Respond to extruder change
- #define _EINDEX (E_AXIS + active_extruder)
-#else
- #define _EINDEX E_AXIS
#endif
int16_t Planner::flow_percentage[EXTRUDERS] = ARRAY_BY_EXTRUDERS1(100); // Extrusion factor for each extruder
@@ -2696,7 +2693,7 @@ void Planner::set_machine_position_mm(const float &a, const float &b, const floa
position[A_AXIS] = LROUND(a * settings.axis_steps_per_mm[A_AXIS]);
position[B_AXIS] = LROUND(b * settings.axis_steps_per_mm[B_AXIS]);
position[C_AXIS] = LROUND(c * settings.axis_steps_per_mm[C_AXIS]);
- position[E_AXIS] = LROUND(e * settings.axis_steps_per_mm[_EINDEX]);
+ position[E_AXIS] = LROUND(e * settings.axis_steps_per_mm[E_AXIS_N(active_extruder)]);
#if HAS_POSITION_FLOAT
position_float[A_AXIS] = a;
position_float[B_AXIS] = b;
@@ -2738,11 +2735,9 @@ void Planner::set_position_mm(const float &rx, const float &ry, const float &rz,
* Setters for planner position (also setting stepper position).
*/
void Planner::set_e_position_mm(const float &e) {
+ const uint8_t axis_index = E_AXIS_N(active_extruder);
#if ENABLED(DISTINCT_E_FACTORS)
- const uint8_t axis_index = E_AXIS + active_extruder;
last_extruder = active_extruder;
- #else
- const uint8_t axis_index = E_AXIS;
#endif
#if ENABLED(FWRETRACT)
float e_new = e - fwretract.current_retract[active_extruder];
@@ -2765,7 +2760,7 @@ void Planner::set_e_position_mm(const float &e) {
// Recalculate the steps/s^2 acceleration rates, based on the mm/s^2
void Planner::reset_acceleration_rates() {
#if ENABLED(DISTINCT_E_FACTORS)
- #define AXIS_CONDITION (i < E_AXIS || i == E_AXIS + active_extruder)
+ #define AXIS_CONDITION (i < E_AXIS || i == E_AXIS_N(active_extruder))
#else
#define AXIS_CONDITION true
#endif
diff --git a/buildroot/share/fonts/genallfont.sh b/buildroot/share/fonts/genallfont.sh
index cc0e3f27b8..b4afc4fbb0 100755
--- a/buildroot/share/fonts/genallfont.sh
+++ b/buildroot/share/fonts/genallfont.sh
@@ -64,13 +64,13 @@ for LANG in ${MARLIN_LANGS:=$LANGS_DEFAULT} ; do
${EXEC_WXGGEN} "${FN_FONT}"
sed -i fontutf8-data.h -e 's|fonts//|fonts/|g' -e 's|fonts//|fonts/|g' -e 's|[/0-9a-zA-Z_\-]*buildroot/share/fonts|buildroot/share/fonts|' 2>/dev/null
cd ../
- mv ${DN_WORK}/fontutf8-data.h src/lcd/dogm/language_data_${LANG}.h
+ mv ${DN_WORK}/fontutf8-data.h src/lcd/dogm/fontdata/language_data_${LANG}.h
rm -rf ${DN_WORK}/
done
#
# Generate default ASCII font (char range 0-255):
-# Marlin/src/lcd/dogm/dogm_font_data_ISO10646_1.h
+# Marlin/src/lcd/dogm/fontdata/fontdata_ISO10646_1.h
#
#if [ "${MARLIN_LANGS}" == "${LANGS_DEFAULT}" ]; then
if [ 1 = 1 ]; then
@@ -82,7 +82,7 @@ if [ 1 = 1 ]; then
TMP1=$(cat tmp1.h) ; rm tmp1.h
TMP2=$(cat tmp2.h) ; rm tmp2.h
- cat <../src/lcd/dogm/dogm_font_data_ISO10646_1.h
+ cat <../src/lcd/dogm/fontdata/fontdata_ISO10646_1.h
/**
* Marlin 3D Printer Firmware
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
diff --git a/buildroot/share/tests/megaatmega2560_tests b/buildroot/share/tests/megaatmega2560_tests
index 601c37ce58..baf350b9fc 100755
--- a/buildroot/share/tests/megaatmega2560_tests
+++ b/buildroot/share/tests/megaatmega2560_tests
@@ -30,7 +30,7 @@ opt_set TEMP_SENSOR_BED 1
opt_set POWER_SUPPLY 1
opt_set GRID_MAX_POINTS_X 16
opt_enable PIDTEMPBED FIX_MOUNTED_PROBE Z_SAFE_HOMING \
- REPRAP_DISCOUNT_SMART_CONTROLLER SDSUPPORT EEPROM_SETTINGS PINS_DEBUGGING \
+ REPRAP_DISCOUNT_SMART_CONTROLLER SDSUPPORT LCD_PROGRESS_BAR LCD_PROGRESS_BAR_TEST EEPROM_SETTINGS PINS_DEBUGGING \
BLINKM PCA9632 RGB_LED NEOPIXEL_LED AUTO_POWER_CONTROL \
NOZZLE_PARK_FEATURE FILAMENT_RUNOUT_SENSOR FILAMENT_RUNOUT_DISTANCE_MM \
AUTO_BED_LEVELING_LINEAR Z_MIN_PROBE_REPEATABILITY_TEST DEBUG_LEVELING_FEATURE \