From b05a75655a202518e1cdac412d6af076c943420b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Br=C3=A1zio?= <jbrazio@gmail.com>
Date: Thu, 16 Jun 2016 05:18:44 +0100
Subject: [PATCH 1/4] Implements a nozzle cleaning pattern generator (G12)

---
 .travis.yml            |   6 +++
 Marlin/Configuration.h |  38 ++++++++++++++
 Marlin/Marlin_main.cpp |  47 +++++++++++------
 Marlin/SanityCheck.h   |   7 +++
 Marlin/clean_nozzle.h  | 112 +++++++++++++++++++++++++++++++++++++++++
 Marlin/point_t.h       |  33 ++++++++++++
 6 files changed, 228 insertions(+), 15 deletions(-)
 create mode 100644 Marlin/clean_nozzle.h
 create mode 100644 Marlin/point_t.h

diff --git a/.travis.yml b/.travis.yml
index eb471fd11e..4d003a95df 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -211,6 +211,12 @@ script:
   - opt_enable PRINTCOUNTER
   - build_marlin
   #
+  # Test CLEAN_NOZZLE_FEATURE
+  #
+  - restore_configs
+  - opt_enable AUTO_BED_LEVELING_FEATURE CLEAN_NOZZLE_FEATURE FIX_MOUNTED_PROBE
+  - build_marlin
+  #
   #
   ######## STANDARD LCD/PANELS ##############
   #
diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h
index 94c1d32e9e..6c170ccf33 100644
--- a/Marlin/Configuration.h
+++ b/Marlin/Configuration.h
@@ -787,6 +787,44 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l
 #define PREHEAT_2_TEMP_BED    110
 #define PREHEAT_2_FAN_SPEED     0 // Value from 0 to 255
 
+//
+// Clean Nozzle Feature -- EXPERIMENTAL
+//
+// When enabled allows the user to send G12 to start the nozzle cleaning
+// process, the G-Code accepts two parameters:
+//   "P" for pattern selection
+//   "S" for defining the number of strokes/repetitions
+//
+// Available list of patterns:
+//   P0: This is the default pattern, this process requires a sponge type
+//       material at a fixed bed location, the cleaning process is based on
+//       "strokes" i.e. back-and-forth movements between the starting and end
+//       points.
+//
+//   P1: This starts a zig-zag pattern between (Xs, Ys) and (Xe, Ye), "S"
+//       defines the number of zig-zag triangles to be done. Each "side"
+//       cannot be less than 5mm. As an example "G12 P1 S3" will execute:
+//
+//                                                /|   /|   /| (Xe, Ye)
+//                                               / |  / |  / |
+//                                              /  | /  | /  |
+//                                    (Xs, Ys) /   |/   |/   |
+//
+//
+// Caveats: End point Z should use the same value as Start point Z.
+//
+// Attention: This is an EXPERIMENTAL feature, in the future the G-code arguments
+// may change to add new functionality like different wipe patterns.
+//
+//#define CLEAN_NOZZLE_FEATURE
+
+#if ENABLED(CLEAN_NOZZLE_FEATURE)
+  #define CLEAN_NOZZLE_STROKES  12
+  #define CLEAN_NOZZLE_START_PT { 30, 30, (Z_MIN_POS + 1), 0}
+  #define CLEAN_NOZZLE_END_PT   {100, 60, (Z_MIN_POS + 1), 0}
+  //                            {  X,  Y,               Z, E}
+#endif
+
 //
 // Print job timer
 //
diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp
index 95b8a5c764..ac7c5f19ee 100644
--- a/Marlin/Marlin_main.cpp
+++ b/Marlin/Marlin_main.cpp
@@ -106,8 +106,9 @@
  * G3  - CCW ARC
  * G4  - Dwell S<seconds> or P<milliseconds>
  * G5  - Cubic B-spline with XYZE destination and IJPQ offsets
- * G10 - retract filament according to settings of M207
- * G11 - retract recover filament according to settings of M208
+ * G10 - Retract filament according to settings of M207
+ * G11 - Retract recover filament according to settings of M208
+ * G12 - Clean tool
  * G20 - Set input units to inches
  * G21 - Set input units to millimeters
  * G28 - Home one or more axes
@@ -1703,6 +1704,10 @@ static void clean_up_after_endstop_or_probe_move() {
     do_blocking_move_to(x, current_position[Y_AXIS], current_position[Z_AXIS], feed_rate);
   }
 
+  inline void do_blocking_move_to_y(float y) {
+    do_blocking_move_to(current_position[X_AXIS], y, current_position[Z_AXIS]);
+  }
+
   inline void do_blocking_move_to_z(float z, float feed_rate = 0.0) {
     do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], z, feed_rate);
   }
@@ -2712,6 +2717,23 @@ inline void gcode_G4() {
 
 #endif //FWRETRACT
 
+#if ENABLED(CLEAN_NOZZLE_FEATURE) && ENABLED(AUTO_BED_LEVELING_FEATURE)
+  #include "clean_nozzle.h"
+
+  inline void gcode_G12() {
+    // Don't allow nozzle cleaning without homing first
+    if (!axis_homed[X_AXIS] || !axis_homed[Y_AXIS] || !axis_homed[Z_AXIS]) {
+      axis_unhomed_error(true);
+      return;
+    }
+
+    uint8_t const pattern = code_seen('P') ? code_value_ushort() : 0;
+    uint8_t const strokes = code_seen('S') ? code_value_ushort() : CLEAN_NOZZLE_STROKES;
+
+    CleanNozzle::start(pattern, strokes);
+  }
+#endif
+
 #if ENABLED(INCH_MODE_SUPPORT)
   /**
    * G20: Set input mode to inches
@@ -6748,12 +6770,10 @@ void process_next_command() {
 
       // G2, G3
       #if ENABLED(ARC_SUPPORT) && DISABLED(SCARA)
-
         case 2: // G2  - CW ARC
         case 3: // G3  - CCW ARC
           gcode_G2_G3(codenum == 2);
           break;
-
       #endif
 
       // G4 Dwell
@@ -6762,23 +6782,25 @@ void process_next_command() {
         break;
 
       #if ENABLED(BEZIER_CURVE_SUPPORT)
-
         // G5
         case 5: // G5  - Cubic B_spline
           gcode_G5();
           break;
-
       #endif // BEZIER_CURVE_SUPPORT
 
       #if ENABLED(FWRETRACT)
-
         case 10: // G10: retract
         case 11: // G11: retract_recover
           gcode_G10_G11(codenum == 10);
           break;
-
       #endif // FWRETRACT
 
+      #if ENABLED(CLEAN_NOZZLE_FEATURE) && ENABLED(AUTO_BED_LEVELING_FEATURE)
+        case 12:
+          gcode_G12(); // G12: Clean Nozzle
+          break;
+      #endif // CLEAN_NOZZLE_FEATURE
+
       #if ENABLED(INCH_MODE_SUPPORT)
         case 20: //G20: Inch Mode
           gcode_G20();
@@ -6787,7 +6809,7 @@ void process_next_command() {
         case 21: //G21: MM Mode
           gcode_G21();
           break;
-      #endif
+      #endif // INCH_MODE_SUPPORT
 
       case 28: // G28: Home all axes, one at a time
         gcode_G28();
@@ -6797,7 +6819,7 @@ void process_next_command() {
         case 29: // G29 Detailed Z probe, probes the bed at 3 or more points.
           gcode_G29();
           break;
-      #endif
+      #endif // AUTO_BED_LEVELING_FEATURE
 
       #if HAS_BED_PROBE
 
@@ -6816,7 +6838,6 @@ void process_next_command() {
               break;
 
         #endif // Z_PROBE_SLED
-
       #endif // HAS_BED_PROBE
 
       case 90: // G90
@@ -6845,7 +6866,6 @@ void process_next_command() {
         break;
 
       #if ENABLED(SDSUPPORT)
-
         case 20: // M20 - list SD card
           gcode_M20(); break;
         case 21: // M21 - init SD card
@@ -6878,7 +6898,6 @@ void process_next_command() {
 
         case 928: //M928 - Start SD write
           gcode_M928(); break;
-
       #endif //SDSUPPORT
 
       case 31: //M31 take time since the start of the SD print or an M109 command
@@ -6948,11 +6967,9 @@ void process_next_command() {
       #endif
 
       #if ENABLED(HOST_KEEPALIVE_FEATURE)
-
         case 113: // M113: Set Host Keepalive interval
           gcode_M113();
           break;
-
       #endif
 
       case 140: // M140: Set bed temp
diff --git a/Marlin/SanityCheck.h b/Marlin/SanityCheck.h
index 3dc330885e..8120500662 100644
--- a/Marlin/SanityCheck.h
+++ b/Marlin/SanityCheck.h
@@ -646,4 +646,11 @@
   #error "ABS_PREHEAT_FAN_SPEED is now PREHEAT_2_FAN_SPEED. Please update your configuration."
 #endif
 
+/**
+ * Nozzle cleaning
+ */
+#if ENABLED(CLEAN_NOZZLE_FEATURE) && DISABLED(AUTO_BED_LEVELING_FEATURE)
+  #error You must enable AUTO_BED_LEVELING_FEATURE for CLEAN_NOZZLE_FEATURE to work
+#endif
+
 #endif //SANITYCHECK_H
diff --git a/Marlin/clean_nozzle.h b/Marlin/clean_nozzle.h
new file mode 100644
index 0000000000..9670605b0c
--- /dev/null
+++ b/Marlin/clean_nozzle.h
@@ -0,0 +1,112 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __CLEAN_NOZZLE_H__
+#define __CLEAN_NOZZLE_H__
+
+#include "Marlin.h"
+#include "point_t.h"
+
+/**
+ * @brief CleanNozzle class
+ *
+ * @todo: Do not ignore the end.z value and allow XYZ movements
+ * @todo: Currently this feature needs AUTO_BED_LEVELING_FEATURE to be active
+ *  due to the do_blocking_move_to*() functions.
+ */
+class CleanNozzle {
+  private:
+    /**
+     * @brief Stroke clean pattern
+     * @details Wipes the nozzle back and forth in a linear movement
+     *
+     * @param start point_t defining the starting point
+     * @param end point_t defining the ending point
+     * @param strokes number of strokes to execute
+     */
+    static void stroke(point_t const &start, point_t const &end, uint8_t const &strokes)
+    __attribute__ ((optimize ("Os"))) {
+      // Move to the starting point
+      do_blocking_move_to_xy(start.x, start.y);
+      do_blocking_move_to_z(start.z);
+
+      // Start the stroke pattern
+      for (uint8_t i = 0; i < (strokes >>1); i++) {
+        do_blocking_move_to_xy(end.x, end.y);
+        do_blocking_move_to_xy(start.x, start.y);
+      }
+    }
+
+    /**
+     * @brief Zig-zag clean pattern
+     * @details Apply a zig-zag cleanning pattern
+     *
+     * @param start point_t defining the starting point
+     * @param end point_t defining the ending point
+     * @param triangles number of triangles to execute
+     */
+    static void zigzag(point_t const &start, point_t const &end, uint8_t const &triangles)
+    __attribute__ ((optimize ("Os"))) {
+      // Move to the starting point
+      do_blocking_move_to_xy(start.x, start.y);
+      do_blocking_move_to_z(start.z);
+
+      // Calculate the triangle side
+      float const a = fabs(end.x - start.x) / triangles;
+
+      // Don't allow the sides (a, b) to be smaller than 5mm
+      if (a < 5 || fabs(end.y - start.y) < 5) return;
+
+      // Start the zig-zag pattern
+      for (uint8_t i = 0; i < triangles; i++) {
+        float const x = start.x + (a * (i + 1));
+        do_blocking_move_to_xy(x, end.y);
+        do_blocking_move_to_y(start.y);
+      }
+    }
+
+  public:
+    /**
+     * @brief Clean the nozzle
+     * @details Starts the selected clean procedure pattern
+     *
+     * @param pattern one of the available patterns
+     * @param argument depends on the cleaning pattern
+     */
+    static void start(uint8_t const &pattern, uint8_t const &argument)
+    __attribute__ ((optimize ("Os"))) {
+      switch (pattern) {
+        case 1:
+          CleanNozzle::zigzag(
+            CLEAN_NOZZLE_START_PT,
+            CLEAN_NOZZLE_END_PT, argument);
+          break;
+
+        default:
+          CleanNozzle::stroke(
+            CLEAN_NOZZLE_START_PT,
+            CLEAN_NOZZLE_END_PT, argument);
+      }
+    }
+};
+
+#endif
diff --git a/Marlin/point_t.h b/Marlin/point_t.h
new file mode 100644
index 0000000000..18dfe09c8f
--- /dev/null
+++ b/Marlin/point_t.h
@@ -0,0 +1,33 @@
+/**
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __POINT_T__
+#define __POINT_T__
+
+struct point_t {
+  float x;
+  float y;
+  float z;
+  float e;
+};
+
+#endif

From 021544f5721442ba62ac339d91451f6caf2e7c5f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Br=C3=A1zio?= <jbrazio@gmail.com>
Date: Thu, 23 Jun 2016 00:23:55 +0100
Subject: [PATCH 2/4] Improves G12 zig-zag pattern

---
 Marlin/Configuration.h              | 25 +++++++-----
 Marlin/Marlin_main.cpp              |  5 ++-
 Marlin/{clean_nozzle.h => nozzle.h} | 63 +++++++++++++++++++----------
 3 files changed, 60 insertions(+), 33 deletions(-)
 rename Marlin/{clean_nozzle.h => nozzle.h} (61%)

diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h
index 6c170ccf33..c455c50a67 100644
--- a/Marlin/Configuration.h
+++ b/Marlin/Configuration.h
@@ -801,15 +801,20 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l
 //       "strokes" i.e. back-and-forth movements between the starting and end
 //       points.
 //
-//   P1: This starts a zig-zag pattern between (Xs, Ys) and (Xe, Ye), "S"
-//       defines the number of zig-zag triangles to be done. Each "side"
-//       cannot be less than 5mm. As an example "G12 P1 S3" will execute:
-//
-//                                                /|   /|   /| (Xe, Ye)
-//                                               / |  / |  / |
-//                                              /  | /  | /  |
-//                                    (Xs, Ys) /   |/   |/   |
+//   P1: This starts a zig-zag pattern between (X0, Y0) and (X1, Y1), "T"
+//       defines the number of zig-zag triangles to be done. "S" defines the
+//       number of strokes aka one back-and-forth movement. As an example
+//       sending "G12 P1 S1 T3" will execute:
 //
+//          --
+//         |  (X0, Y1) |     /\        /\        /\     | (X1, Y1)
+//         |           |    /  \      /  \      /  \    |
+//       A |           |   /    \    /    \    /    \   |
+//         |           |  /      \  /      \  /      \  |
+//         |  (X0, Y0) | /        \/        \/        \ | (X1, Y0)
+//          --         +--------------------------------+
+//                       |________|_________|_________|
+//                           T1        T2        T3
 //
 // Caveats: End point Z should use the same value as Start point Z.
 //
@@ -820,8 +825,8 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l
 
 #if ENABLED(CLEAN_NOZZLE_FEATURE)
   #define CLEAN_NOZZLE_STROKES  12
-  #define CLEAN_NOZZLE_START_PT { 30, 30, (Z_MIN_POS + 1), 0}
-  #define CLEAN_NOZZLE_END_PT   {100, 60, (Z_MIN_POS + 1), 0}
+  #define CLEAN_NOZZLE_START_PT { 30, 30, (Z_MIN_POS + 5), 0}
+  #define CLEAN_NOZZLE_END_PT   {100, 60, (Z_MIN_POS + 5), 0}
   //                            {  X,  Y,               Z, E}
 #endif
 
diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp
index ac7c5f19ee..835b20fcd4 100644
--- a/Marlin/Marlin_main.cpp
+++ b/Marlin/Marlin_main.cpp
@@ -2718,7 +2718,7 @@ inline void gcode_G4() {
 #endif //FWRETRACT
 
 #if ENABLED(CLEAN_NOZZLE_FEATURE) && ENABLED(AUTO_BED_LEVELING_FEATURE)
-  #include "clean_nozzle.h"
+  #include "nozzle.h"
 
   inline void gcode_G12() {
     // Don't allow nozzle cleaning without homing first
@@ -2729,8 +2729,9 @@ inline void gcode_G4() {
 
     uint8_t const pattern = code_seen('P') ? code_value_ushort() : 0;
     uint8_t const strokes = code_seen('S') ? code_value_ushort() : CLEAN_NOZZLE_STROKES;
+    uint8_t const objects = code_seen('T') ? code_value_ushort() : 3;
 
-    CleanNozzle::start(pattern, strokes);
+    Nozzle::clean(pattern, strokes, objects);
   }
 #endif
 
diff --git a/Marlin/clean_nozzle.h b/Marlin/nozzle.h
similarity index 61%
rename from Marlin/clean_nozzle.h
rename to Marlin/nozzle.h
index 9670605b0c..796d18b349 100644
--- a/Marlin/clean_nozzle.h
+++ b/Marlin/nozzle.h
@@ -27,13 +27,13 @@
 #include "point_t.h"
 
 /**
- * @brief CleanNozzle class
+ * @brief Nozzle class
  *
  * @todo: Do not ignore the end.z value and allow XYZ movements
  * @todo: Currently this feature needs AUTO_BED_LEVELING_FEATURE to be active
  *  due to the do_blocking_move_to*() functions.
  */
-class CleanNozzle {
+class Nozzle {
   private:
     /**
      * @brief Stroke clean pattern
@@ -62,26 +62,46 @@ class CleanNozzle {
      *
      * @param start point_t defining the starting point
      * @param end point_t defining the ending point
-     * @param triangles number of triangles to execute
+     * @param strokes number of strokes to execute
+     * @param objects number of objects to create
      */
-    static void zigzag(point_t const &start, point_t const &end, uint8_t const &triangles)
+    static void zigzag(point_t const &start,
+      point_t const &end, uint8_t const &strokes, uint8_t const &objects)
     __attribute__ ((optimize ("Os"))) {
-      // Move to the starting point
-      do_blocking_move_to_xy(start.x, start.y);
-      do_blocking_move_to_z(start.z);
+      float A = fabs(end.y - start.y); // [twice the] Amplitude
+      float P = fabs(end.x - start.x) / (objects << 1); // Period
 
-      // Calculate the triangle side
-      float const a = fabs(end.x - start.x) / triangles;
+      // Don't allow impossible triangles
+      if (A <= 0.0f || P <= 0.0f ) return;
 
-      // Don't allow the sides (a, b) to be smaller than 5mm
-      if (a < 5 || fabs(end.y - start.y) < 5) return;
+      // Store the current coords
+      point_t const home = {
+        current_position[X_AXIS],
+        current_position[Y_AXIS],
+        current_position[Z_AXIS],
+        current_position[E_AXIS]
+      };
 
-      // Start the zig-zag pattern
-      for (uint8_t i = 0; i < triangles; i++) {
-        float const x = start.x + (a * (i + 1));
-        do_blocking_move_to_xy(x, end.y);
-        do_blocking_move_to_y(start.y);
+      for (uint8_t j = 0; j < strokes; j++) {
+        for (uint8_t i = 0; i < (objects << 1); i++) {
+          float const x = start.x + i * P;
+          float const y = start.y + (A/P) * (P - fabs(fmod((i*P), (2*P)) - P));
+
+          do_blocking_move_to_xy(x, y);
+          if (i == 0) do_blocking_move_to_z(start.z);
+        }
+
+        for (int i = (objects << 1); i > -1; i--) {
+          float const x = start.x + i * P;
+          float const y = start.y + (A/P) * (P - fabs(fmod((i*P), (2*P)) - P));
+
+          do_blocking_move_to_xy(x, y);
+        }
       }
+
+      // Move to home/start position
+      do_blocking_move_to_z(home.z);
+      do_blocking_move_to_xy(home.x, home.y);
     }
 
   public:
@@ -92,19 +112,20 @@ class CleanNozzle {
      * @param pattern one of the available patterns
      * @param argument depends on the cleaning pattern
      */
-    static void start(uint8_t const &pattern, uint8_t const &argument)
+    static void clean(uint8_t const &pattern,
+      uint8_t const &strokes, uint8_t const &objects = 0)
     __attribute__ ((optimize ("Os"))) {
       switch (pattern) {
         case 1:
-          CleanNozzle::zigzag(
+          Nozzle::zigzag(
             CLEAN_NOZZLE_START_PT,
-            CLEAN_NOZZLE_END_PT, argument);
+            CLEAN_NOZZLE_END_PT, strokes, objects);
           break;
 
         default:
-          CleanNozzle::stroke(
+          Nozzle::stroke(
             CLEAN_NOZZLE_START_PT,
-            CLEAN_NOZZLE_END_PT, argument);
+            CLEAN_NOZZLE_END_PT, strokes);
       }
     }
 };

From 4937f9ada4b2441cc2d2f84e3acd7f60e35f23f8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Br=C3=A1zio?= <jbrazio@gmail.com>
Date: Thu, 14 Jul 2016 00:07:36 +0100
Subject: [PATCH 3/4] Minor G12 tweaks and point_t struct extension

---
 Marlin/Marlin_main.cpp | 13 ++++------
 Marlin/SanityCheck.h   |  4 +--
 Marlin/nozzle.h        | 55 +++++++++++++++++++++++++++++-------------
 Marlin/point_t.h       | 13 ++++++++++
 4 files changed, 58 insertions(+), 27 deletions(-)

diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp
index 835b20fcd4..523f8cf326 100644
--- a/Marlin/Marlin_main.cpp
+++ b/Marlin/Marlin_main.cpp
@@ -2717,18 +2717,15 @@ inline void gcode_G4() {
 
 #endif //FWRETRACT
 
-#if ENABLED(CLEAN_NOZZLE_FEATURE) && ENABLED(AUTO_BED_LEVELING_FEATURE)
+#if ENABLED(NOZZLE_CLEAN_FEATURE) && ENABLED(AUTO_BED_LEVELING_FEATURE)
   #include "nozzle.h"
 
   inline void gcode_G12() {
     // Don't allow nozzle cleaning without homing first
-    if (!axis_homed[X_AXIS] || !axis_homed[Y_AXIS] || !axis_homed[Z_AXIS]) {
-      axis_unhomed_error(true);
-      return;
-    }
+    if (axis_unhomed_error(true, true, true)) { return; }
 
     uint8_t const pattern = code_seen('P') ? code_value_ushort() : 0;
-    uint8_t const strokes = code_seen('S') ? code_value_ushort() : CLEAN_NOZZLE_STROKES;
+    uint8_t const strokes = code_seen('S') ? code_value_ushort() : NOZZLE_CLEAN_STROKES;
     uint8_t const objects = code_seen('T') ? code_value_ushort() : 3;
 
     Nozzle::clean(pattern, strokes, objects);
@@ -6796,11 +6793,11 @@ void process_next_command() {
           break;
       #endif // FWRETRACT
 
-      #if ENABLED(CLEAN_NOZZLE_FEATURE) && ENABLED(AUTO_BED_LEVELING_FEATURE)
+      #if ENABLED(NOZZLE_CLEAN_FEATURE) && HAS_BED_PROBE
         case 12:
           gcode_G12(); // G12: Clean Nozzle
           break;
-      #endif // CLEAN_NOZZLE_FEATURE
+      #endif // NOZZLE_CLEAN_FEATURE
 
       #if ENABLED(INCH_MODE_SUPPORT)
         case 20: //G20: Inch Mode
diff --git a/Marlin/SanityCheck.h b/Marlin/SanityCheck.h
index 8120500662..8334b12893 100644
--- a/Marlin/SanityCheck.h
+++ b/Marlin/SanityCheck.h
@@ -649,8 +649,8 @@
 /**
  * Nozzle cleaning
  */
-#if ENABLED(CLEAN_NOZZLE_FEATURE) && DISABLED(AUTO_BED_LEVELING_FEATURE)
-  #error You must enable AUTO_BED_LEVELING_FEATURE for CLEAN_NOZZLE_FEATURE to work
+#if ENABLED(NOZZLE_CLEAN_FEATURE) && !HAS_BED_PROBE
+  #error Due to internal dependencies you must have a bed probe for NOZZLE_CLEAN_FEATURE to work
 #endif
 
 #endif //SANITYCHECK_H
diff --git a/Marlin/nozzle.h b/Marlin/nozzle.h
index 796d18b349..02771a5164 100644
--- a/Marlin/nozzle.h
+++ b/Marlin/nozzle.h
@@ -20,8 +20,8 @@
  *
  */
 
-#ifndef __CLEAN_NOZZLE_H__
-#define __CLEAN_NOZZLE_H__
+#ifndef __NOZZLE_H__
+#define __NOZZLE_H__
 
 #include "Marlin.h"
 #include "point_t.h"
@@ -30,7 +30,7 @@
  * @brief Nozzle class
  *
  * @todo: Do not ignore the end.z value and allow XYZ movements
- * @todo: Currently this feature needs AUTO_BED_LEVELING_FEATURE to be active
+ * @todo: Currently this feature needs HAS_BED_PROBE to be active
  *  due to the do_blocking_move_to*() functions.
  */
 class Nozzle {
@@ -45,6 +45,17 @@ class Nozzle {
      */
     static void stroke(point_t const &start, point_t const &end, uint8_t const &strokes)
     __attribute__ ((optimize ("Os"))) {
+
+      #if ENABLED(NOZZLE_CLEAN_PARK)
+        // Store the current coords
+        point_t const initial = {
+          current_position[X_AXIS],
+          current_position[Y_AXIS],
+          current_position[Z_AXIS],
+          current_position[E_AXIS]
+        };
+      #endif
+
       // Move to the starting point
       do_blocking_move_to_xy(start.x, start.y);
       do_blocking_move_to_z(start.z);
@@ -54,6 +65,12 @@ class Nozzle {
         do_blocking_move_to_xy(end.x, end.y);
         do_blocking_move_to_xy(start.x, start.y);
       }
+
+      #if ENABLED(NOZZLE_CLEAN_PARK)
+        // Move the nozzle to the initial point
+        do_blocking_move_to_z(initial.z);
+        do_blocking_move_to_xy(initial.x, initial.y);
+      #endif
     }
 
     /**
@@ -74,13 +91,15 @@ class Nozzle {
       // Don't allow impossible triangles
       if (A <= 0.0f || P <= 0.0f ) return;
 
-      // Store the current coords
-      point_t const home = {
-        current_position[X_AXIS],
-        current_position[Y_AXIS],
-        current_position[Z_AXIS],
-        current_position[E_AXIS]
-      };
+      #if ENABLED(NOZZLE_CLEAN_PARK)
+        // Store the current coords
+        point_t const initial = {
+          current_position[X_AXIS],
+          current_position[Y_AXIS],
+          current_position[Z_AXIS],
+          current_position[E_AXIS]
+        };
+      #endif
 
       for (uint8_t j = 0; j < strokes; j++) {
         for (uint8_t i = 0; i < (objects << 1); i++) {
@@ -99,9 +118,11 @@ class Nozzle {
         }
       }
 
-      // Move to home/start position
-      do_blocking_move_to_z(home.z);
-      do_blocking_move_to_xy(home.x, home.y);
+      #if ENABLED(NOZZLE_CLEAN_PARK)
+        // Move the nozzle to the initial point
+        do_blocking_move_to_z(initial.z);
+        do_blocking_move_to_xy(initial.x, initial.y);
+      #endif
     }
 
   public:
@@ -118,14 +139,14 @@ class Nozzle {
       switch (pattern) {
         case 1:
           Nozzle::zigzag(
-            CLEAN_NOZZLE_START_PT,
-            CLEAN_NOZZLE_END_PT, strokes, objects);
+            NOZZLE_CLEAN_START_PT,
+            NOZZLE_CLEAN_END_PT, strokes, objects);
           break;
 
         default:
           Nozzle::stroke(
-            CLEAN_NOZZLE_START_PT,
-            CLEAN_NOZZLE_END_PT, strokes);
+            NOZZLE_CLEAN_START_PT,
+            NOZZLE_CLEAN_END_PT, strokes);
       }
     }
 };
diff --git a/Marlin/point_t.h b/Marlin/point_t.h
index 18dfe09c8f..dbad668581 100644
--- a/Marlin/point_t.h
+++ b/Marlin/point_t.h
@@ -28,6 +28,19 @@ struct point_t {
   float y;
   float z;
   float e;
+
+  point_t(float const x, float const y)
+    : point_t(x, y, NAN, NAN) {}
+
+  point_t(float const x, float const y, float const z)
+    : point_t(x, y, z, NAN) {}
+
+  point_t(float const x, float const y, float const z, float const e) {
+    this->x = x;
+    this->y = y;
+    this->z = z;
+    this->e = e;
+  }
 };
 
 #endif

From 68c343a09a85183aba7c3e47a4b1eecf2cc61236 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Br=C3=A1zio?= <jbrazio@gmail.com>
Date: Thu, 14 Jul 2016 00:38:42 +0100
Subject: [PATCH 4/4] Added G12 configuration options to all configs

---
 Marlin/Configuration.h                        | 17 +++---
 .../Cartesio/Configuration.h                  | 54 +++++++++++++++++--
 .../Felix/Configuration.h                     | 48 +++++++++++++++++
 .../Felix/DUAL/Configuration.h                | 48 +++++++++++++++++
 .../Hephestos/Configuration.h                 | 48 +++++++++++++++++
 .../Hephestos_2/Configuration.h               | 48 +++++++++++++++++
 .../K8200/Configuration.h                     | 48 +++++++++++++++++
 .../K8400/Configuration.h                     | 48 +++++++++++++++++
 .../{Dual Heads => Dual-head}/Configuration.h | 48 +++++++++++++++++
 .../RepRapWorld/Megatronics/Configuration.h   | 48 +++++++++++++++++
 .../RigidBot/Configuration.h                  | 48 +++++++++++++++++
 .../SCARA/Configuration.h                     | 48 +++++++++++++++++
 .../TAZ4/Configuration.h                      | 48 +++++++++++++++++
 .../WITBOX/Configuration.h                    | 48 +++++++++++++++++
 .../adafruit/ST7565/Configuration.h           | 48 +++++++++++++++++
 .../delta/biv2.5/Configuration.h              | 48 +++++++++++++++++
 .../delta/generic/Configuration.h             | 48 +++++++++++++++++
 .../delta/kossel_mini/Configuration.h         | 48 +++++++++++++++++
 .../delta/kossel_pro/Configuration.h          | 48 +++++++++++++++++
 .../delta/kossel_xl/Configuration.h           | 48 +++++++++++++++++
 .../makibox/Configuration.h                   | 48 +++++++++++++++++
 .../tvrrug/Round2/Configuration.h             | 48 +++++++++++++++++
 22 files changed, 1022 insertions(+), 9 deletions(-)
 rename Marlin/example_configurations/K8400/{Dual Heads => Dual-head}/Configuration.h (96%)

diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h
index c455c50a67..96cb580689 100644
--- a/Marlin/Configuration.h
+++ b/Marlin/Configuration.h
@@ -821,13 +821,18 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l
 // Attention: This is an EXPERIMENTAL feature, in the future the G-code arguments
 // may change to add new functionality like different wipe patterns.
 //
-//#define CLEAN_NOZZLE_FEATURE
+//#define NOZZLE_CLEAN_FEATURE
 
-#if ENABLED(CLEAN_NOZZLE_FEATURE)
-  #define CLEAN_NOZZLE_STROKES  12
-  #define CLEAN_NOZZLE_START_PT { 30, 30, (Z_MIN_POS + 5), 0}
-  #define CLEAN_NOZZLE_END_PT   {100, 60, (Z_MIN_POS + 5), 0}
-  //                            {  X,  Y,               Z, E}
+#if ENABLED(NOZZLE_CLEAN_FEATURE)
+  // Number of pattern repetitions
+  #define NOZZLE_CLEAN_STROKES  12
+
+  //                            {  X,  Y,               Z}
+  #define NOZZLE_CLEAN_START_PT { 30, 30, (Z_MIN_POS + 5)}
+  #define NOZZLE_CLEAN_END_PT   {100, 60, (Z_MIN_POS + 5)}
+
+  // Moves the nozzle to the parked position
+  #define NOZZLE_CLEAN_PARK
 #endif
 
 //
diff --git a/Marlin/example_configurations/Cartesio/Configuration.h b/Marlin/example_configurations/Cartesio/Configuration.h
index a875ecce66..b4d1f08523 100644
--- a/Marlin/example_configurations/Cartesio/Configuration.h
+++ b/Marlin/example_configurations/Cartesio/Configuration.h
@@ -268,12 +268,12 @@
     #define  DEFAULT_Kp 18
     #define  DEFAULT_Ki 1
     #define  DEFAULT_Kd 100
-    
+
     // Cartesio extruderV6 40W Volcano
     //#define  DEFAULT_Kp 50
     //#define  DEFAULT_Ki 9
     //#define  DEFAULT_Kd 70
-    
+
     // Cartesio extruderV6 40W Cyclops
     //#define  DEFAULT_Kp 18
     //#define  DEFAULT_Ki 1
@@ -313,7 +313,7 @@
     #define  DEFAULT_bedKp 390
     #define  DEFAULT_bedKi 70
     #define  DEFAULT_bedKd 546
-   
+
     //24V 250W silicone heater on to 4mm glass CartesioM
     //#define  DEFAULT_bedKp 303
     //#define  DEFAULT_bedKi 42
@@ -786,6 +786,54 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l
 #define PREHEAT_2_TEMP_BED    110
 #define PREHEAT_2_FAN_SPEED     0 // Value from 0 to 255
 
+//
+// Clean Nozzle Feature -- EXPERIMENTAL
+//
+// When enabled allows the user to send G12 to start the nozzle cleaning
+// process, the G-Code accepts two parameters:
+//   "P" for pattern selection
+//   "S" for defining the number of strokes/repetitions
+//
+// Available list of patterns:
+//   P0: This is the default pattern, this process requires a sponge type
+//       material at a fixed bed location, the cleaning process is based on
+//       "strokes" i.e. back-and-forth movements between the starting and end
+//       points.
+//
+//   P1: This starts a zig-zag pattern between (X0, Y0) and (X1, Y1), "T"
+//       defines the number of zig-zag triangles to be done. "S" defines the
+//       number of strokes aka one back-and-forth movement. As an example
+//       sending "G12 P1 S1 T3" will execute:
+//
+//          --
+//         |  (X0, Y1) |     /\        /\        /\     | (X1, Y1)
+//         |           |    /  \      /  \      /  \    |
+//       A |           |   /    \    /    \    /    \   |
+//         |           |  /      \  /      \  /      \  |
+//         |  (X0, Y0) | /        \/        \/        \ | (X1, Y0)
+//          --         +--------------------------------+
+//                       |________|_________|_________|
+//                           T1        T2        T3
+//
+// Caveats: End point Z should use the same value as Start point Z.
+//
+// Attention: This is an EXPERIMENTAL feature, in the future the G-code arguments
+// may change to add new functionality like different wipe patterns.
+//
+//#define NOZZLE_CLEAN_FEATURE
+
+#if ENABLED(NOZZLE_CLEAN_FEATURE)
+  // Number of pattern repetitions
+  #define NOZZLE_CLEAN_STROKES  12
+
+  //                            {  X,  Y,               Z}
+  #define NOZZLE_CLEAN_START_PT { 30, 30, (Z_MIN_POS + 5)}
+  #define NOZZLE_CLEAN_END_PT   {100, 60, (Z_MIN_POS + 5)}
+
+  // Moves the nozzle to the parked position
+  #define NOZZLE_CLEAN_PARK
+#endif
+
 //
 // Print job timer
 //
diff --git a/Marlin/example_configurations/Felix/Configuration.h b/Marlin/example_configurations/Felix/Configuration.h
index d3543127f8..50ace1c2d5 100644
--- a/Marlin/example_configurations/Felix/Configuration.h
+++ b/Marlin/example_configurations/Felix/Configuration.h
@@ -770,6 +770,54 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l
 #define PREHEAT_2_TEMP_BED    100
 #define PREHEAT_2_FAN_SPEED   255 // Value from 0 to 255
 
+//
+// Clean Nozzle Feature -- EXPERIMENTAL
+//
+// When enabled allows the user to send G12 to start the nozzle cleaning
+// process, the G-Code accepts two parameters:
+//   "P" for pattern selection
+//   "S" for defining the number of strokes/repetitions
+//
+// Available list of patterns:
+//   P0: This is the default pattern, this process requires a sponge type
+//       material at a fixed bed location, the cleaning process is based on
+//       "strokes" i.e. back-and-forth movements between the starting and end
+//       points.
+//
+//   P1: This starts a zig-zag pattern between (X0, Y0) and (X1, Y1), "T"
+//       defines the number of zig-zag triangles to be done. "S" defines the
+//       number of strokes aka one back-and-forth movement. As an example
+//       sending "G12 P1 S1 T3" will execute:
+//
+//          --
+//         |  (X0, Y1) |     /\        /\        /\     | (X1, Y1)
+//         |           |    /  \      /  \      /  \    |
+//       A |           |   /    \    /    \    /    \   |
+//         |           |  /      \  /      \  /      \  |
+//         |  (X0, Y0) | /        \/        \/        \ | (X1, Y0)
+//          --         +--------------------------------+
+//                       |________|_________|_________|
+//                           T1        T2        T3
+//
+// Caveats: End point Z should use the same value as Start point Z.
+//
+// Attention: This is an EXPERIMENTAL feature, in the future the G-code arguments
+// may change to add new functionality like different wipe patterns.
+//
+//#define NOZZLE_CLEAN_FEATURE
+
+#if ENABLED(NOZZLE_CLEAN_FEATURE)
+  // Number of pattern repetitions
+  #define NOZZLE_CLEAN_STROKES  12
+
+  //                            {  X,  Y,               Z}
+  #define NOZZLE_CLEAN_START_PT { 30, 30, (Z_MIN_POS + 5)}
+  #define NOZZLE_CLEAN_END_PT   {100, 60, (Z_MIN_POS + 5)}
+
+  // Moves the nozzle to the parked position
+  #define NOZZLE_CLEAN_PARK
+#endif
+
 //
 // Print job timer
 //
diff --git a/Marlin/example_configurations/Felix/DUAL/Configuration.h b/Marlin/example_configurations/Felix/DUAL/Configuration.h
index 097c1e2ee8..3c2be5a228 100644
--- a/Marlin/example_configurations/Felix/DUAL/Configuration.h
+++ b/Marlin/example_configurations/Felix/DUAL/Configuration.h
@@ -768,6 +768,54 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l
 #define PREHEAT_2_TEMP_BED    100
 #define PREHEAT_2_FAN_SPEED   255 // Value from 0 to 255
 
+//
+// Clean Nozzle Feature -- EXPERIMENTAL
+//
+// When enabled allows the user to send G12 to start the nozzle cleaning
+// process, the G-Code accepts two parameters:
+//   "P" for pattern selection
+//   "S" for defining the number of strokes/repetitions
+//
+// Available list of patterns:
+//   P0: This is the default pattern, this process requires a sponge type
+//       material at a fixed bed location, the cleaning process is based on
+//       "strokes" i.e. back-and-forth movements between the starting and end
+//       points.
+//
+//   P1: This starts a zig-zag pattern between (X0, Y0) and (X1, Y1), "T"
+//       defines the number of zig-zag triangles to be done. "S" defines the
+//       number of strokes aka one back-and-forth movement. As an example
+//       sending "G12 P1 S1 T3" will execute:
+//
+//          --
+//         |  (X0, Y1) |     /\        /\        /\     | (X1, Y1)
+//         |           |    /  \      /  \      /  \    |
+//       A |           |   /    \    /    \    /    \   |
+//         |           |  /      \  /      \  /      \  |
+//         |  (X0, Y0) | /        \/        \/        \ | (X1, Y0)
+//          --         +--------------------------------+
+//                       |________|_________|_________|
+//                           T1        T2        T3
+//
+// Caveats: End point Z should use the same value as Start point Z.
+//
+// Attention: This is an EXPERIMENTAL feature, in the future the G-code arguments
+// may change to add new functionality like different wipe patterns.
+//
+//#define NOZZLE_CLEAN_FEATURE
+
+#if ENABLED(NOZZLE_CLEAN_FEATURE)
+  // Number of pattern repetitions
+  #define NOZZLE_CLEAN_STROKES  12
+
+  //                            {  X,  Y,               Z}
+  #define NOZZLE_CLEAN_START_PT { 30, 30, (Z_MIN_POS + 5)}
+  #define NOZZLE_CLEAN_END_PT   {100, 60, (Z_MIN_POS + 5)}
+
+  // Moves the nozzle to the parked position
+  #define NOZZLE_CLEAN_PARK
+#endif
+
 //
 // Print job timer
 //
diff --git a/Marlin/example_configurations/Hephestos/Configuration.h b/Marlin/example_configurations/Hephestos/Configuration.h
index ad3d59088a..31ac6728fb 100644
--- a/Marlin/example_configurations/Hephestos/Configuration.h
+++ b/Marlin/example_configurations/Hephestos/Configuration.h
@@ -779,6 +779,54 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = true; // set to true to invert the lo
 #define PREHEAT_2_TEMP_BED    100
 #define PREHEAT_2_FAN_SPEED   255 // Value from 0 to 255
 
+//
+// Clean Nozzle Feature -- EXPERIMENTAL
+//
+// When enabled allows the user to send G12 to start the nozzle cleaning
+// process, the G-Code accepts two parameters:
+//   "P" for pattern selection
+//   "S" for defining the number of strokes/repetitions
+//
+// Available list of patterns:
+//   P0: This is the default pattern, this process requires a sponge type
+//       material at a fixed bed location, the cleaning process is based on
+//       "strokes" i.e. back-and-forth movements between the starting and end
+//       points.
+//
+//   P1: This starts a zig-zag pattern between (X0, Y0) and (X1, Y1), "T"
+//       defines the number of zig-zag triangles to be done. "S" defines the
+//       number of strokes aka one back-and-forth movement. As an example
+//       sending "G12 P1 S1 T3" will execute:
+//
+//          --
+//         |  (X0, Y1) |     /\        /\        /\     | (X1, Y1)
+//         |           |    /  \      /  \      /  \    |
+//       A |           |   /    \    /    \    /    \   |
+//         |           |  /      \  /      \  /      \  |
+//         |  (X0, Y0) | /        \/        \/        \ | (X1, Y0)
+//          --         +--------------------------------+
+//                       |________|_________|_________|
+//                           T1        T2        T3
+//
+// Caveats: End point Z should use the same value as Start point Z.
+//
+// Attention: This is an EXPERIMENTAL feature, in the future the G-code arguments
+// may change to add new functionality like different wipe patterns.
+//
+//#define NOZZLE_CLEAN_FEATURE
+
+#if ENABLED(NOZZLE_CLEAN_FEATURE)
+  // Number of pattern repetitions
+  #define NOZZLE_CLEAN_STROKES  12
+
+  //                            {  X,  Y,               Z}
+  #define NOZZLE_CLEAN_START_PT { 30, 30, (Z_MIN_POS + 5)}
+  #define NOZZLE_CLEAN_END_PT   {100, 60, (Z_MIN_POS + 5)}
+
+  // Moves the nozzle to the parked position
+  #define NOZZLE_CLEAN_PARK
+#endif
+
 //
 // Print job timer
 //
diff --git a/Marlin/example_configurations/Hephestos_2/Configuration.h b/Marlin/example_configurations/Hephestos_2/Configuration.h
index 0d6252eabd..5e31b0e99d 100644
--- a/Marlin/example_configurations/Hephestos_2/Configuration.h
+++ b/Marlin/example_configurations/Hephestos_2/Configuration.h
@@ -781,6 +781,54 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l
 #define PREHEAT_2_TEMP_BED    110
 #define PREHEAT_2_FAN_SPEED     0 // Value from 0 to 255
 
+//
+// Clean Nozzle Feature -- EXPERIMENTAL
+//
+// When enabled allows the user to send G12 to start the nozzle cleaning
+// process, the G-Code accepts two parameters:
+//   "P" for pattern selection
+//   "S" for defining the number of strokes/repetitions
+//
+// Available list of patterns:
+//   P0: This is the default pattern, this process requires a sponge type
+//       material at a fixed bed location, the cleaning process is based on
+//       "strokes" i.e. back-and-forth movements between the starting and end
+//       points.
+//
+//   P1: This starts a zig-zag pattern between (X0, Y0) and (X1, Y1), "T"
+//       defines the number of zig-zag triangles to be done. "S" defines the
+//       number of strokes aka one back-and-forth movement. As an example
+//       sending "G12 P1 S1 T3" will execute:
+//
+//          --
+//         |  (X0, Y1) |     /\        /\        /\     | (X1, Y1)
+//         |           |    /  \      /  \      /  \    |
+//       A |           |   /    \    /    \    /    \   |
+//         |           |  /      \  /      \  /      \  |
+//         |  (X0, Y0) | /        \/        \/        \ | (X1, Y0)
+//          --         +--------------------------------+
+//                       |________|_________|_________|
+//                           T1        T2        T3
+//
+// Caveats: End point Z should use the same value as Start point Z.
+//
+// Attention: This is an EXPERIMENTAL feature, in the future the G-code arguments
+// may change to add new functionality like different wipe patterns.
+//
+//#define NOZZLE_CLEAN_FEATURE
+
+#if ENABLED(NOZZLE_CLEAN_FEATURE)
+  // Number of pattern repetitions
+  #define NOZZLE_CLEAN_STROKES  12
+
+  //                            {  X,  Y,               Z}
+  #define NOZZLE_CLEAN_START_PT { 30, 30, (Z_MIN_POS + 5)}
+  #define NOZZLE_CLEAN_END_PT   {100, 60, (Z_MIN_POS + 5)}
+
+  // Moves the nozzle to the parked position
+  #define NOZZLE_CLEAN_PARK
+#endif
+
 //
 // Print job timer
 //
diff --git a/Marlin/example_configurations/K8200/Configuration.h b/Marlin/example_configurations/K8200/Configuration.h
index 2a1ed29817..37fe86722f 100644
--- a/Marlin/example_configurations/K8200/Configuration.h
+++ b/Marlin/example_configurations/K8200/Configuration.h
@@ -804,6 +804,54 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l
 #define PREHEAT_2_TEMP_BED     60 // K8200: set back to 110 if you have an upgraded heatbed power supply
 #define PREHEAT_2_FAN_SPEED     0 // Value from 0 to 255
 
+//
+// Clean Nozzle Feature -- EXPERIMENTAL
+//
+// When enabled allows the user to send G12 to start the nozzle cleaning
+// process, the G-Code accepts two parameters:
+//   "P" for pattern selection
+//   "S" for defining the number of strokes/repetitions
+//
+// Available list of patterns:
+//   P0: This is the default pattern, this process requires a sponge type
+//       material at a fixed bed location, the cleaning process is based on
+//       "strokes" i.e. back-and-forth movements between the starting and end
+//       points.
+//
+//   P1: This starts a zig-zag pattern between (X0, Y0) and (X1, Y1), "T"
+//       defines the number of zig-zag triangles to be done. "S" defines the
+//       number of strokes aka one back-and-forth movement. As an example
+//       sending "G12 P1 S1 T3" will execute:
+//
+//          --
+//         |  (X0, Y1) |     /\        /\        /\     | (X1, Y1)
+//         |           |    /  \      /  \      /  \    |
+//       A |           |   /    \    /    \    /    \   |
+//         |           |  /      \  /      \  /      \  |
+//         |  (X0, Y0) | /        \/        \/        \ | (X1, Y0)
+//          --         +--------------------------------+
+//                       |________|_________|_________|
+//                           T1        T2        T3
+//
+// Caveats: End point Z should use the same value as Start point Z.
+//
+// Attention: This is an EXPERIMENTAL feature, in the future the G-code arguments
+// may change to add new functionality like different wipe patterns.
+//
+//#define NOZZLE_CLEAN_FEATURE
+
+#if ENABLED(NOZZLE_CLEAN_FEATURE)
+  // Number of pattern repetitions
+  #define NOZZLE_CLEAN_STROKES  12
+
+  //                            {  X,  Y,               Z}
+  #define NOZZLE_CLEAN_START_PT { 30, 30, (Z_MIN_POS + 5)}
+  #define NOZZLE_CLEAN_END_PT   {100, 60, (Z_MIN_POS + 5)}
+
+  // Moves the nozzle to the parked position
+  #define NOZZLE_CLEAN_PARK
+#endif
+
 //
 // Print job timer
 //
diff --git a/Marlin/example_configurations/K8400/Configuration.h b/Marlin/example_configurations/K8400/Configuration.h
index 6cec00cb21..c900fc263f 100644
--- a/Marlin/example_configurations/K8400/Configuration.h
+++ b/Marlin/example_configurations/K8400/Configuration.h
@@ -787,6 +787,54 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = true; // set to true to invert the lo
 #define PREHEAT_2_TEMP_BED      0
 #define PREHEAT_2_FAN_SPEED   165 // Value from 0 to 255
 
+//
+// Clean Nozzle Feature -- EXPERIMENTAL
+//
+// When enabled allows the user to send G12 to start the nozzle cleaning
+// process, the G-Code accepts two parameters:
+//   "P" for pattern selection
+//   "S" for defining the number of strokes/repetitions
+//
+// Available list of patterns:
+//   P0: This is the default pattern, this process requires a sponge type
+//       material at a fixed bed location, the cleaning process is based on
+//       "strokes" i.e. back-and-forth movements between the starting and end
+//       points.
+//
+//   P1: This starts a zig-zag pattern between (X0, Y0) and (X1, Y1), "T"
+//       defines the number of zig-zag triangles to be done. "S" defines the
+//       number of strokes aka one back-and-forth movement. As an example
+//       sending "G12 P1 S1 T3" will execute:
+//
+//          --
+//         |  (X0, Y1) |     /\        /\        /\     | (X1, Y1)
+//         |           |    /  \      /  \      /  \    |
+//       A |           |   /    \    /    \    /    \   |
+//         |           |  /      \  /      \  /      \  |
+//         |  (X0, Y0) | /        \/        \/        \ | (X1, Y0)
+//          --         +--------------------------------+
+//                       |________|_________|_________|
+//                           T1        T2        T3
+//
+// Caveats: End point Z should use the same value as Start point Z.
+//
+// Attention: This is an EXPERIMENTAL feature, in the future the G-code arguments
+// may change to add new functionality like different wipe patterns.
+//
+//#define NOZZLE_CLEAN_FEATURE
+
+#if ENABLED(NOZZLE_CLEAN_FEATURE)
+  // Number of pattern repetitions
+  #define NOZZLE_CLEAN_STROKES  12
+
+  //                            {  X,  Y,               Z}
+  #define NOZZLE_CLEAN_START_PT { 30, 30, (Z_MIN_POS + 5)}
+  #define NOZZLE_CLEAN_END_PT   {100, 60, (Z_MIN_POS + 5)}
+
+  // Moves the nozzle to the parked position
+  #define NOZZLE_CLEAN_PARK
+#endif
+
 //
 // Print job timer
 //
diff --git a/Marlin/example_configurations/K8400/Dual Heads/Configuration.h b/Marlin/example_configurations/K8400/Dual-head/Configuration.h
similarity index 96%
rename from Marlin/example_configurations/K8400/Dual Heads/Configuration.h
rename to Marlin/example_configurations/K8400/Dual-head/Configuration.h
index 2dc75368a7..d69c5bdfe3 100644
--- a/Marlin/example_configurations/K8400/Dual Heads/Configuration.h	
+++ b/Marlin/example_configurations/K8400/Dual-head/Configuration.h
@@ -787,6 +787,54 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = true; // set to true to invert the lo
 #define PREHEAT_2_TEMP_BED      0
 #define PREHEAT_2_FAN_SPEED   165 // Value from 0 to 255
 
+//
+// Clean Nozzle Feature -- EXPERIMENTAL
+//
+// When enabled allows the user to send G12 to start the nozzle cleaning
+// process, the G-Code accepts two parameters:
+//   "P" for pattern selection
+//   "S" for defining the number of strokes/repetitions
+//
+// Available list of patterns:
+//   P0: This is the default pattern, this process requires a sponge type
+//       material at a fixed bed location, the cleaning process is based on
+//       "strokes" i.e. back-and-forth movements between the starting and end
+//       points.
+//
+//   P1: This starts a zig-zag pattern between (X0, Y0) and (X1, Y1), "T"
+//       defines the number of zig-zag triangles to be done. "S" defines the
+//       number of strokes aka one back-and-forth movement. As an example
+//       sending "G12 P1 S1 T3" will execute:
+//
+//          --
+//         |  (X0, Y1) |     /\        /\        /\     | (X1, Y1)
+//         |           |    /  \      /  \      /  \    |
+//       A |           |   /    \    /    \    /    \   |
+//         |           |  /      \  /      \  /      \  |
+//         |  (X0, Y0) | /        \/        \/        \ | (X1, Y0)
+//          --         +--------------------------------+
+//                       |________|_________|_________|
+//                           T1        T2        T3
+//
+// Caveats: End point Z should use the same value as Start point Z.
+//
+// Attention: This is an EXPERIMENTAL feature, in the future the G-code arguments
+// may change to add new functionality like different wipe patterns.
+//
+//#define NOZZLE_CLEAN_FEATURE
+
+#if ENABLED(NOZZLE_CLEAN_FEATURE)
+  // Number of pattern repetitions
+  #define NOZZLE_CLEAN_STROKES  12
+
+  //                            {  X,  Y,               Z}
+  #define NOZZLE_CLEAN_START_PT { 30, 30, (Z_MIN_POS + 5)}
+  #define NOZZLE_CLEAN_END_PT   {100, 60, (Z_MIN_POS + 5)}
+
+  // Moves the nozzle to the parked position
+  #define NOZZLE_CLEAN_PARK
+#endif
+
 //
 // Print job timer
 //
diff --git a/Marlin/example_configurations/RepRapWorld/Megatronics/Configuration.h b/Marlin/example_configurations/RepRapWorld/Megatronics/Configuration.h
index ab6c8dcd91..315010fe8f 100644
--- a/Marlin/example_configurations/RepRapWorld/Megatronics/Configuration.h
+++ b/Marlin/example_configurations/RepRapWorld/Megatronics/Configuration.h
@@ -787,6 +787,54 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l
 #define PREHEAT_2_TEMP_BED    110
 #define PREHEAT_2_FAN_SPEED     0 // Value from 0 to 255
 
+//
+// Clean Nozzle Feature -- EXPERIMENTAL
+//
+// When enabled allows the user to send G12 to start the nozzle cleaning
+// process, the G-Code accepts two parameters:
+//   "P" for pattern selection
+//   "S" for defining the number of strokes/repetitions
+//
+// Available list of patterns:
+//   P0: This is the default pattern, this process requires a sponge type
+//       material at a fixed bed location, the cleaning process is based on
+//       "strokes" i.e. back-and-forth movements between the starting and end
+//       points.
+//
+//   P1: This starts a zig-zag pattern between (X0, Y0) and (X1, Y1), "T"
+//       defines the number of zig-zag triangles to be done. "S" defines the
+//       number of strokes aka one back-and-forth movement. As an example
+//       sending "G12 P1 S1 T3" will execute:
+//
+//          --
+//         |  (X0, Y1) |     /\        /\        /\     | (X1, Y1)
+//         |           |    /  \      /  \      /  \    |
+//       A |           |   /    \    /    \    /    \   |
+//         |           |  /      \  /      \  /      \  |
+//         |  (X0, Y0) | /        \/        \/        \ | (X1, Y0)
+//          --         +--------------------------------+
+//                       |________|_________|_________|
+//                           T1        T2        T3
+//
+// Caveats: End point Z should use the same value as Start point Z.
+//
+// Attention: This is an EXPERIMENTAL feature, in the future the G-code arguments
+// may change to add new functionality like different wipe patterns.
+//
+//#define NOZZLE_CLEAN_FEATURE
+
+#if ENABLED(NOZZLE_CLEAN_FEATURE)
+  // Number of pattern repetitions
+  #define NOZZLE_CLEAN_STROKES  12
+
+  //                            {  X,  Y,               Z}
+  #define NOZZLE_CLEAN_START_PT { 30, 30, (Z_MIN_POS + 5)}
+  #define NOZZLE_CLEAN_END_PT   {100, 60, (Z_MIN_POS + 5)}
+
+  // Moves the nozzle to the parked position
+  #define NOZZLE_CLEAN_PARK
+#endif
+
 //
 // Print job timer
 //
diff --git a/Marlin/example_configurations/RigidBot/Configuration.h b/Marlin/example_configurations/RigidBot/Configuration.h
index f24a4ea076..829c8d8a54 100644
--- a/Marlin/example_configurations/RigidBot/Configuration.h
+++ b/Marlin/example_configurations/RigidBot/Configuration.h
@@ -785,6 +785,54 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l
 #define PREHEAT_2_TEMP_BED    110
 #define PREHEAT_2_FAN_SPEED   255 // Value from 0 to 255
 
+//
+// Clean Nozzle Feature -- EXPERIMENTAL
+//
+// When enabled allows the user to send G12 to start the nozzle cleaning
+// process, the G-Code accepts two parameters:
+//   "P" for pattern selection
+//   "S" for defining the number of strokes/repetitions
+//
+// Available list of patterns:
+//   P0: This is the default pattern, this process requires a sponge type
+//       material at a fixed bed location, the cleaning process is based on
+//       "strokes" i.e. back-and-forth movements between the starting and end
+//       points.
+//
+//   P1: This starts a zig-zag pattern between (X0, Y0) and (X1, Y1), "T"
+//       defines the number of zig-zag triangles to be done. "S" defines the
+//       number of strokes aka one back-and-forth movement. As an example
+//       sending "G12 P1 S1 T3" will execute:
+//
+//          --
+//         |  (X0, Y1) |     /\        /\        /\     | (X1, Y1)
+//         |           |    /  \      /  \      /  \    |
+//       A |           |   /    \    /    \    /    \   |
+//         |           |  /      \  /      \  /      \  |
+//         |  (X0, Y0) | /        \/        \/        \ | (X1, Y0)
+//          --         +--------------------------------+
+//                       |________|_________|_________|
+//                           T1        T2        T3
+//
+// Caveats: End point Z should use the same value as Start point Z.
+//
+// Attention: This is an EXPERIMENTAL feature, in the future the G-code arguments
+// may change to add new functionality like different wipe patterns.
+//
+//#define NOZZLE_CLEAN_FEATURE
+
+#if ENABLED(NOZZLE_CLEAN_FEATURE)
+  // Number of pattern repetitions
+  #define NOZZLE_CLEAN_STROKES  12
+
+  //                            {  X,  Y,               Z}
+  #define NOZZLE_CLEAN_START_PT { 30, 30, (Z_MIN_POS + 5)}
+  #define NOZZLE_CLEAN_END_PT   {100, 60, (Z_MIN_POS + 5)}
+
+  // Moves the nozzle to the parked position
+  #define NOZZLE_CLEAN_PARK
+#endif
+
 //
 // Print job timer
 //
diff --git a/Marlin/example_configurations/SCARA/Configuration.h b/Marlin/example_configurations/SCARA/Configuration.h
index b8addb2871..4d32f85a76 100644
--- a/Marlin/example_configurations/SCARA/Configuration.h
+++ b/Marlin/example_configurations/SCARA/Configuration.h
@@ -795,6 +795,54 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l
 #define PREHEAT_2_TEMP_BED    100
 #define PREHEAT_2_FAN_SPEED   255 // Value from 0 to 255
 
+//
+// Clean Nozzle Feature -- EXPERIMENTAL
+//
+// When enabled allows the user to send G12 to start the nozzle cleaning
+// process, the G-Code accepts two parameters:
+//   "P" for pattern selection
+//   "S" for defining the number of strokes/repetitions
+//
+// Available list of patterns:
+//   P0: This is the default pattern, this process requires a sponge type
+//       material at a fixed bed location, the cleaning process is based on
+//       "strokes" i.e. back-and-forth movements between the starting and end
+//       points.
+//
+//   P1: This starts a zig-zag pattern between (X0, Y0) and (X1, Y1), "T"
+//       defines the number of zig-zag triangles to be done. "S" defines the
+//       number of strokes aka one back-and-forth movement. As an example
+//       sending "G12 P1 S1 T3" will execute:
+//
+//          --
+//         |  (X0, Y1) |     /\        /\        /\     | (X1, Y1)
+//         |           |    /  \      /  \      /  \    |
+//       A |           |   /    \    /    \    /    \   |
+//         |           |  /      \  /      \  /      \  |
+//         |  (X0, Y0) | /        \/        \/        \ | (X1, Y0)
+//          --         +--------------------------------+
+//                       |________|_________|_________|
+//                           T1        T2        T3
+//
+// Caveats: End point Z should use the same value as Start point Z.
+//
+// Attention: This is an EXPERIMENTAL feature, in the future the G-code arguments
+// may change to add new functionality like different wipe patterns.
+//
+//#define NOZZLE_CLEAN_FEATURE
+
+#if ENABLED(NOZZLE_CLEAN_FEATURE)
+  // Number of pattern repetitions
+  #define NOZZLE_CLEAN_STROKES  12
+
+  //                            {  X,  Y,               Z}
+  #define NOZZLE_CLEAN_START_PT { 30, 30, (Z_MIN_POS + 5)}
+  #define NOZZLE_CLEAN_END_PT   {100, 60, (Z_MIN_POS + 5)}
+
+  // Moves the nozzle to the parked position
+  #define NOZZLE_CLEAN_PARK
+#endif
+
 //
 // Print job timer
 //
diff --git a/Marlin/example_configurations/TAZ4/Configuration.h b/Marlin/example_configurations/TAZ4/Configuration.h
index e2782de05e..f8f49db47b 100644
--- a/Marlin/example_configurations/TAZ4/Configuration.h
+++ b/Marlin/example_configurations/TAZ4/Configuration.h
@@ -808,6 +808,54 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l
 #define PREHEAT_2_TEMP_BED    110
 #define PREHEAT_2_FAN_SPEED     0 // Value from 0 to 255
 
+//
+// Clean Nozzle Feature -- EXPERIMENTAL
+//
+// When enabled allows the user to send G12 to start the nozzle cleaning
+// process, the G-Code accepts two parameters:
+//   "P" for pattern selection
+//   "S" for defining the number of strokes/repetitions
+//
+// Available list of patterns:
+//   P0: This is the default pattern, this process requires a sponge type
+//       material at a fixed bed location, the cleaning process is based on
+//       "strokes" i.e. back-and-forth movements between the starting and end
+//       points.
+//
+//   P1: This starts a zig-zag pattern between (X0, Y0) and (X1, Y1), "T"
+//       defines the number of zig-zag triangles to be done. "S" defines the
+//       number of strokes aka one back-and-forth movement. As an example
+//       sending "G12 P1 S1 T3" will execute:
+//
+//          --
+//         |  (X0, Y1) |     /\        /\        /\     | (X1, Y1)
+//         |           |    /  \      /  \      /  \    |
+//       A |           |   /    \    /    \    /    \   |
+//         |           |  /      \  /      \  /      \  |
+//         |  (X0, Y0) | /        \/        \/        \ | (X1, Y0)
+//          --         +--------------------------------+
+//                       |________|_________|_________|
+//                           T1        T2        T3
+//
+// Caveats: End point Z should use the same value as Start point Z.
+//
+// Attention: This is an EXPERIMENTAL feature, in the future the G-code arguments
+// may change to add new functionality like different wipe patterns.
+//
+//#define NOZZLE_CLEAN_FEATURE
+
+#if ENABLED(NOZZLE_CLEAN_FEATURE)
+  // Number of pattern repetitions
+  #define NOZZLE_CLEAN_STROKES  12
+
+  //                            {  X,  Y,               Z}
+  #define NOZZLE_CLEAN_START_PT { 30, 30, (Z_MIN_POS + 5)}
+  #define NOZZLE_CLEAN_END_PT   {100, 60, (Z_MIN_POS + 5)}
+
+  // Moves the nozzle to the parked position
+  #define NOZZLE_CLEAN_PARK
+#endif
+
 //
 // Print job timer
 //
diff --git a/Marlin/example_configurations/WITBOX/Configuration.h b/Marlin/example_configurations/WITBOX/Configuration.h
index 06a5ae8fb9..d4102ef995 100644
--- a/Marlin/example_configurations/WITBOX/Configuration.h
+++ b/Marlin/example_configurations/WITBOX/Configuration.h
@@ -779,6 +779,54 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = true; // set to true to invert the lo
 #define PREHEAT_2_TEMP_BED    100
 #define PREHEAT_2_FAN_SPEED   255 // Value from 0 to 255
 
+//
+// Clean Nozzle Feature -- EXPERIMENTAL
+//
+// When enabled allows the user to send G12 to start the nozzle cleaning
+// process, the G-Code accepts two parameters:
+//   "P" for pattern selection
+//   "S" for defining the number of strokes/repetitions
+//
+// Available list of patterns:
+//   P0: This is the default pattern, this process requires a sponge type
+//       material at a fixed bed location, the cleaning process is based on
+//       "strokes" i.e. back-and-forth movements between the starting and end
+//       points.
+//
+//   P1: This starts a zig-zag pattern between (X0, Y0) and (X1, Y1), "T"
+//       defines the number of zig-zag triangles to be done. "S" defines the
+//       number of strokes aka one back-and-forth movement. As an example
+//       sending "G12 P1 S1 T3" will execute:
+//
+//          --
+//         |  (X0, Y1) |     /\        /\        /\     | (X1, Y1)
+//         |           |    /  \      /  \      /  \    |
+//       A |           |   /    \    /    \    /    \   |
+//         |           |  /      \  /      \  /      \  |
+//         |  (X0, Y0) | /        \/        \/        \ | (X1, Y0)
+//          --         +--------------------------------+
+//                       |________|_________|_________|
+//                           T1        T2        T3
+//
+// Caveats: End point Z should use the same value as Start point Z.
+//
+// Attention: This is an EXPERIMENTAL feature, in the future the G-code arguments
+// may change to add new functionality like different wipe patterns.
+//
+//#define NOZZLE_CLEAN_FEATURE
+
+#if ENABLED(NOZZLE_CLEAN_FEATURE)
+  // Number of pattern repetitions
+  #define NOZZLE_CLEAN_STROKES  12
+
+  //                            {  X,  Y,               Z}
+  #define NOZZLE_CLEAN_START_PT { 30, 30, (Z_MIN_POS + 5)}
+  #define NOZZLE_CLEAN_END_PT   {100, 60, (Z_MIN_POS + 5)}
+
+  // Moves the nozzle to the parked position
+  #define NOZZLE_CLEAN_PARK
+#endif
+
 //
 // Print job timer
 //
diff --git a/Marlin/example_configurations/adafruit/ST7565/Configuration.h b/Marlin/example_configurations/adafruit/ST7565/Configuration.h
index be81a9a2e7..2bb90a191a 100644
--- a/Marlin/example_configurations/adafruit/ST7565/Configuration.h
+++ b/Marlin/example_configurations/adafruit/ST7565/Configuration.h
@@ -787,6 +787,54 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l
 #define PREHEAT_2_TEMP_BED    110
 #define PREHEAT_2_FAN_SPEED     0 // Value from 0 to 255
 
+//
+// Clean Nozzle Feature -- EXPERIMENTAL
+//
+// When enabled allows the user to send G12 to start the nozzle cleaning
+// process, the G-Code accepts two parameters:
+//   "P" for pattern selection
+//   "S" for defining the number of strokes/repetitions
+//
+// Available list of patterns:
+//   P0: This is the default pattern, this process requires a sponge type
+//       material at a fixed bed location, the cleaning process is based on
+//       "strokes" i.e. back-and-forth movements between the starting and end
+//       points.
+//
+//   P1: This starts a zig-zag pattern between (X0, Y0) and (X1, Y1), "T"
+//       defines the number of zig-zag triangles to be done. "S" defines the
+//       number of strokes aka one back-and-forth movement. As an example
+//       sending "G12 P1 S1 T3" will execute:
+//
+//          --
+//         |  (X0, Y1) |     /\        /\        /\     | (X1, Y1)
+//         |           |    /  \      /  \      /  \    |
+//       A |           |   /    \    /    \    /    \   |
+//         |           |  /      \  /      \  /      \  |
+//         |  (X0, Y0) | /        \/        \/        \ | (X1, Y0)
+//          --         +--------------------------------+
+//                       |________|_________|_________|
+//                           T1        T2        T3
+//
+// Caveats: End point Z should use the same value as Start point Z.
+//
+// Attention: This is an EXPERIMENTAL feature, in the future the G-code arguments
+// may change to add new functionality like different wipe patterns.
+//
+//#define NOZZLE_CLEAN_FEATURE
+
+#if ENABLED(NOZZLE_CLEAN_FEATURE)
+  // Number of pattern repetitions
+  #define NOZZLE_CLEAN_STROKES  12
+
+  //                            {  X,  Y,               Z}
+  #define NOZZLE_CLEAN_START_PT { 30, 30, (Z_MIN_POS + 5)}
+  #define NOZZLE_CLEAN_END_PT   {100, 60, (Z_MIN_POS + 5)}
+
+  // Moves the nozzle to the parked position
+  #define NOZZLE_CLEAN_PARK
+#endif
+
 //
 // Print job timer
 //
diff --git a/Marlin/example_configurations/delta/biv2.5/Configuration.h b/Marlin/example_configurations/delta/biv2.5/Configuration.h
index 5cc2ed9d18..981ae59dd7 100644
--- a/Marlin/example_configurations/delta/biv2.5/Configuration.h
+++ b/Marlin/example_configurations/delta/biv2.5/Configuration.h
@@ -882,6 +882,54 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = true; // set to true to invert the lo
 #define PREHEAT_2_TEMP_BED    100
 #define PREHEAT_2_FAN_SPEED   255 // Value from 0 to 255
 
+//
+// Clean Nozzle Feature -- EXPERIMENTAL
+//
+// When enabled allows the user to send G12 to start the nozzle cleaning
+// process, the G-Code accepts two parameters:
+//   "P" for pattern selection
+//   "S" for defining the number of strokes/repetitions
+//
+// Available list of patterns:
+//   P0: This is the default pattern, this process requires a sponge type
+//       material at a fixed bed location, the cleaning process is based on
+//       "strokes" i.e. back-and-forth movements between the starting and end
+//       points.
+//
+//   P1: This starts a zig-zag pattern between (X0, Y0) and (X1, Y1), "T"
+//       defines the number of zig-zag triangles to be done. "S" defines the
+//       number of strokes aka one back-and-forth movement. As an example
+//       sending "G12 P1 S1 T3" will execute:
+//
+//          --
+//         |  (X0, Y1) |     /\        /\        /\     | (X1, Y1)
+//         |           |    /  \      /  \      /  \    |
+//       A |           |   /    \    /    \    /    \   |
+//         |           |  /      \  /      \  /      \  |
+//         |  (X0, Y0) | /        \/        \/        \ | (X1, Y0)
+//          --         +--------------------------------+
+//                       |________|_________|_________|
+//                           T1        T2        T3
+//
+// Caveats: End point Z should use the same value as Start point Z.
+//
+// Attention: This is an EXPERIMENTAL feature, in the future the G-code arguments
+// may change to add new functionality like different wipe patterns.
+//
+//#define NOZZLE_CLEAN_FEATURE
+
+#if ENABLED(NOZZLE_CLEAN_FEATURE)
+  // Number of pattern repetitions
+  #define NOZZLE_CLEAN_STROKES  12
+
+  //                            {  X,  Y,               Z}
+  #define NOZZLE_CLEAN_START_PT { 30, 30, (Z_MIN_POS + 5)}
+  #define NOZZLE_CLEAN_END_PT   {100, 60, (Z_MIN_POS + 5)}
+
+  // Moves the nozzle to the parked position
+  #define NOZZLE_CLEAN_PARK
+#endif
+
 //
 // Print job timer
 //
diff --git a/Marlin/example_configurations/delta/generic/Configuration.h b/Marlin/example_configurations/delta/generic/Configuration.h
index 31d6b3551f..2fed91a1a6 100644
--- a/Marlin/example_configurations/delta/generic/Configuration.h
+++ b/Marlin/example_configurations/delta/generic/Configuration.h
@@ -876,6 +876,54 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = true; // set to true to invert the lo
 #define PREHEAT_2_TEMP_BED    100
 #define PREHEAT_2_FAN_SPEED   255 // Value from 0 to 255
 
+//
+// Clean Nozzle Feature -- EXPERIMENTAL
+//
+// When enabled allows the user to send G12 to start the nozzle cleaning
+// process, the G-Code accepts two parameters:
+//   "P" for pattern selection
+//   "S" for defining the number of strokes/repetitions
+//
+// Available list of patterns:
+//   P0: This is the default pattern, this process requires a sponge type
+//       material at a fixed bed location, the cleaning process is based on
+//       "strokes" i.e. back-and-forth movements between the starting and end
+//       points.
+//
+//   P1: This starts a zig-zag pattern between (X0, Y0) and (X1, Y1), "T"
+//       defines the number of zig-zag triangles to be done. "S" defines the
+//       number of strokes aka one back-and-forth movement. As an example
+//       sending "G12 P1 S1 T3" will execute:
+//
+//          --
+//         |  (X0, Y1) |     /\        /\        /\     | (X1, Y1)
+//         |           |    /  \      /  \      /  \    |
+//       A |           |   /    \    /    \    /    \   |
+//         |           |  /      \  /      \  /      \  |
+//         |  (X0, Y0) | /        \/        \/        \ | (X1, Y0)
+//          --         +--------------------------------+
+//                       |________|_________|_________|
+//                           T1        T2        T3
+//
+// Caveats: End point Z should use the same value as Start point Z.
+//
+// Attention: This is an EXPERIMENTAL feature, in the future the G-code arguments
+// may change to add new functionality like different wipe patterns.
+//
+//#define NOZZLE_CLEAN_FEATURE
+
+#if ENABLED(NOZZLE_CLEAN_FEATURE)
+  // Number of pattern repetitions
+  #define NOZZLE_CLEAN_STROKES  12
+
+  //                            {  X,  Y,               Z}
+  #define NOZZLE_CLEAN_START_PT { 30, 30, (Z_MIN_POS + 5)}
+  #define NOZZLE_CLEAN_END_PT   {100, 60, (Z_MIN_POS + 5)}
+
+  // Moves the nozzle to the parked position
+  #define NOZZLE_CLEAN_PARK
+#endif
+
 //
 // Print job timer
 //
diff --git a/Marlin/example_configurations/delta/kossel_mini/Configuration.h b/Marlin/example_configurations/delta/kossel_mini/Configuration.h
index 2699a97f45..9e97af3c32 100644
--- a/Marlin/example_configurations/delta/kossel_mini/Configuration.h
+++ b/Marlin/example_configurations/delta/kossel_mini/Configuration.h
@@ -879,6 +879,54 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l
 #define PREHEAT_2_TEMP_BED    100
 #define PREHEAT_2_FAN_SPEED   255 // Value from 0 to 255
 
+//
+// Clean Nozzle Feature -- EXPERIMENTAL
+//
+// When enabled allows the user to send G12 to start the nozzle cleaning
+// process, the G-Code accepts two parameters:
+//   "P" for pattern selection
+//   "S" for defining the number of strokes/repetitions
+//
+// Available list of patterns:
+//   P0: This is the default pattern, this process requires a sponge type
+//       material at a fixed bed location, the cleaning process is based on
+//       "strokes" i.e. back-and-forth movements between the starting and end
+//       points.
+//
+//   P1: This starts a zig-zag pattern between (X0, Y0) and (X1, Y1), "T"
+//       defines the number of zig-zag triangles to be done. "S" defines the
+//       number of strokes aka one back-and-forth movement. As an example
+//       sending "G12 P1 S1 T3" will execute:
+//
+//          --
+//         |  (X0, Y1) |     /\        /\        /\     | (X1, Y1)
+//         |           |    /  \      /  \      /  \    |
+//       A |           |   /    \    /    \    /    \   |
+//         |           |  /      \  /      \  /      \  |
+//         |  (X0, Y0) | /        \/        \/        \ | (X1, Y0)
+//          --         +--------------------------------+
+//                       |________|_________|_________|
+//                           T1        T2        T3
+//
+// Caveats: End point Z should use the same value as Start point Z.
+//
+// Attention: This is an EXPERIMENTAL feature, in the future the G-code arguments
+// may change to add new functionality like different wipe patterns.
+//
+//#define NOZZLE_CLEAN_FEATURE
+
+#if ENABLED(NOZZLE_CLEAN_FEATURE)
+  // Number of pattern repetitions
+  #define NOZZLE_CLEAN_STROKES  12
+
+  //                            {  X,  Y,               Z}
+  #define NOZZLE_CLEAN_START_PT { 30, 30, (Z_MIN_POS + 5)}
+  #define NOZZLE_CLEAN_END_PT   {100, 60, (Z_MIN_POS + 5)}
+
+  // Moves the nozzle to the parked position
+  #define NOZZLE_CLEAN_PARK
+#endif
+
 //
 // Print job timer
 //
diff --git a/Marlin/example_configurations/delta/kossel_pro/Configuration.h b/Marlin/example_configurations/delta/kossel_pro/Configuration.h
index dddb9c4357..2b49bd039b 100644
--- a/Marlin/example_configurations/delta/kossel_pro/Configuration.h
+++ b/Marlin/example_configurations/delta/kossel_pro/Configuration.h
@@ -879,6 +879,54 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l
 #define PREHEAT_2_TEMP_BED    100
 #define PREHEAT_2_FAN_SPEED   255 // Value from 0 to 255
 
+//
+// Clean Nozzle Feature -- EXPERIMENTAL
+//
+// When enabled allows the user to send G12 to start the nozzle cleaning
+// process, the G-Code accepts two parameters:
+//   "P" for pattern selection
+//   "S" for defining the number of strokes/repetitions
+//
+// Available list of patterns:
+//   P0: This is the default pattern, this process requires a sponge type
+//       material at a fixed bed location, the cleaning process is based on
+//       "strokes" i.e. back-and-forth movements between the starting and end
+//       points.
+//
+//   P1: This starts a zig-zag pattern between (X0, Y0) and (X1, Y1), "T"
+//       defines the number of zig-zag triangles to be done. "S" defines the
+//       number of strokes aka one back-and-forth movement. As an example
+//       sending "G12 P1 S1 T3" will execute:
+//
+//          --
+//         |  (X0, Y1) |     /\        /\        /\     | (X1, Y1)
+//         |           |    /  \      /  \      /  \    |
+//       A |           |   /    \    /    \    /    \   |
+//         |           |  /      \  /      \  /      \  |
+//         |  (X0, Y0) | /        \/        \/        \ | (X1, Y0)
+//          --         +--------------------------------+
+//                       |________|_________|_________|
+//                           T1        T2        T3
+//
+// Caveats: End point Z should use the same value as Start point Z.
+//
+// Attention: This is an EXPERIMENTAL feature, in the future the G-code arguments
+// may change to add new functionality like different wipe patterns.
+//
+//#define NOZZLE_CLEAN_FEATURE
+
+#if ENABLED(NOZZLE_CLEAN_FEATURE)
+  // Number of pattern repetitions
+  #define NOZZLE_CLEAN_STROKES  12
+
+  //                            {  X,  Y,               Z}
+  #define NOZZLE_CLEAN_START_PT { 30, 30, (Z_MIN_POS + 5)}
+  #define NOZZLE_CLEAN_END_PT   {100, 60, (Z_MIN_POS + 5)}
+
+  // Moves the nozzle to the parked position
+  #define NOZZLE_CLEAN_PARK
+#endif
+
 //
 // Print job timer
 //
diff --git a/Marlin/example_configurations/delta/kossel_xl/Configuration.h b/Marlin/example_configurations/delta/kossel_xl/Configuration.h
index 58b1626357..258ba72c9b 100644
--- a/Marlin/example_configurations/delta/kossel_xl/Configuration.h
+++ b/Marlin/example_configurations/delta/kossel_xl/Configuration.h
@@ -881,6 +881,54 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l
 #define PREHEAT_2_TEMP_BED    100
 #define PREHEAT_2_FAN_SPEED   255 // Value from 0 to 255
 
+//
+// Clean Nozzle Feature -- EXPERIMENTAL
+//
+// When enabled allows the user to send G12 to start the nozzle cleaning
+// process, the G-Code accepts two parameters:
+//   "P" for pattern selection
+//   "S" for defining the number of strokes/repetitions
+//
+// Available list of patterns:
+//   P0: This is the default pattern, this process requires a sponge type
+//       material at a fixed bed location, the cleaning process is based on
+//       "strokes" i.e. back-and-forth movements between the starting and end
+//       points.
+//
+//   P1: This starts a zig-zag pattern between (X0, Y0) and (X1, Y1), "T"
+//       defines the number of zig-zag triangles to be done. "S" defines the
+//       number of strokes aka one back-and-forth movement. As an example
+//       sending "G12 P1 S1 T3" will execute:
+//
+//          --
+//         |  (X0, Y1) |     /\        /\        /\     | (X1, Y1)
+//         |           |    /  \      /  \      /  \    |
+//       A |           |   /    \    /    \    /    \   |
+//         |           |  /      \  /      \  /      \  |
+//         |  (X0, Y0) | /        \/        \/        \ | (X1, Y0)
+//          --         +--------------------------------+
+//                       |________|_________|_________|
+//                           T1        T2        T3
+//
+// Caveats: End point Z should use the same value as Start point Z.
+//
+// Attention: This is an EXPERIMENTAL feature, in the future the G-code arguments
+// may change to add new functionality like different wipe patterns.
+//
+//#define NOZZLE_CLEAN_FEATURE
+
+#if ENABLED(NOZZLE_CLEAN_FEATURE)
+  // Number of pattern repetitions
+  #define NOZZLE_CLEAN_STROKES  12
+
+  //                            {  X,  Y,               Z}
+  #define NOZZLE_CLEAN_START_PT { 30, 30, (Z_MIN_POS + 5)}
+  #define NOZZLE_CLEAN_END_PT   {100, 60, (Z_MIN_POS + 5)}
+
+  // Moves the nozzle to the parked position
+  #define NOZZLE_CLEAN_PARK
+#endif
+
 //
 // Print job timer
 //
diff --git a/Marlin/example_configurations/makibox/Configuration.h b/Marlin/example_configurations/makibox/Configuration.h
index 9a4be404e4..c51d75d36f 100644
--- a/Marlin/example_configurations/makibox/Configuration.h
+++ b/Marlin/example_configurations/makibox/Configuration.h
@@ -790,6 +790,54 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l
 #define PREHEAT_2_TEMP_BED    100
 #define PREHEAT_2_FAN_SPEED   255 // Value from 0 to 255
 
+//
+// Clean Nozzle Feature -- EXPERIMENTAL
+//
+// When enabled allows the user to send G12 to start the nozzle cleaning
+// process, the G-Code accepts two parameters:
+//   "P" for pattern selection
+//   "S" for defining the number of strokes/repetitions
+//
+// Available list of patterns:
+//   P0: This is the default pattern, this process requires a sponge type
+//       material at a fixed bed location, the cleaning process is based on
+//       "strokes" i.e. back-and-forth movements between the starting and end
+//       points.
+//
+//   P1: This starts a zig-zag pattern between (X0, Y0) and (X1, Y1), "T"
+//       defines the number of zig-zag triangles to be done. "S" defines the
+//       number of strokes aka one back-and-forth movement. As an example
+//       sending "G12 P1 S1 T3" will execute:
+//
+//          --
+//         |  (X0, Y1) |     /\        /\        /\     | (X1, Y1)
+//         |           |    /  \      /  \      /  \    |
+//       A |           |   /    \    /    \    /    \   |
+//         |           |  /      \  /      \  /      \  |
+//         |  (X0, Y0) | /        \/        \/        \ | (X1, Y0)
+//          --         +--------------------------------+
+//                       |________|_________|_________|
+//                           T1        T2        T3
+//
+// Caveats: End point Z should use the same value as Start point Z.
+//
+// Attention: This is an EXPERIMENTAL feature, in the future the G-code arguments
+// may change to add new functionality like different wipe patterns.
+//
+//#define NOZZLE_CLEAN_FEATURE
+
+#if ENABLED(NOZZLE_CLEAN_FEATURE)
+  // Number of pattern repetitions
+  #define NOZZLE_CLEAN_STROKES  12
+
+  //                            {  X,  Y,               Z}
+  #define NOZZLE_CLEAN_START_PT { 30, 30, (Z_MIN_POS + 5)}
+  #define NOZZLE_CLEAN_END_PT   {100, 60, (Z_MIN_POS + 5)}
+
+  // Moves the nozzle to the parked position
+  #define NOZZLE_CLEAN_PARK
+#endif
+
 //
 // Print job timer
 //
diff --git a/Marlin/example_configurations/tvrrug/Round2/Configuration.h b/Marlin/example_configurations/tvrrug/Round2/Configuration.h
index a135d4d7b8..eeee653041 100644
--- a/Marlin/example_configurations/tvrrug/Round2/Configuration.h
+++ b/Marlin/example_configurations/tvrrug/Round2/Configuration.h
@@ -781,6 +781,54 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = true; // set to true to invert the lo
 #define PREHEAT_2_TEMP_BED    100
 #define PREHEAT_2_FAN_SPEED   255 // Value from 0 to 255
 
+//
+// Clean Nozzle Feature -- EXPERIMENTAL
+//
+// When enabled allows the user to send G12 to start the nozzle cleaning
+// process, the G-Code accepts two parameters:
+//   "P" for pattern selection
+//   "S" for defining the number of strokes/repetitions
+//
+// Available list of patterns:
+//   P0: This is the default pattern, this process requires a sponge type
+//       material at a fixed bed location, the cleaning process is based on
+//       "strokes" i.e. back-and-forth movements between the starting and end
+//       points.
+//
+//   P1: This starts a zig-zag pattern between (X0, Y0) and (X1, Y1), "T"
+//       defines the number of zig-zag triangles to be done. "S" defines the
+//       number of strokes aka one back-and-forth movement. As an example
+//       sending "G12 P1 S1 T3" will execute:
+//
+//          --
+//         |  (X0, Y1) |     /\        /\        /\     | (X1, Y1)
+//         |           |    /  \      /  \      /  \    |
+//       A |           |   /    \    /    \    /    \   |
+//         |           |  /      \  /      \  /      \  |
+//         |  (X0, Y0) | /        \/        \/        \ | (X1, Y0)
+//          --         +--------------------------------+
+//                       |________|_________|_________|
+//                           T1        T2        T3
+//
+// Caveats: End point Z should use the same value as Start point Z.
+//
+// Attention: This is an EXPERIMENTAL feature, in the future the G-code arguments
+// may change to add new functionality like different wipe patterns.
+//
+//#define NOZZLE_CLEAN_FEATURE
+
+#if ENABLED(NOZZLE_CLEAN_FEATURE)
+  // Number of pattern repetitions
+  #define NOZZLE_CLEAN_STROKES  12
+
+  //                            {  X,  Y,               Z}
+  #define NOZZLE_CLEAN_START_PT { 30, 30, (Z_MIN_POS + 5)}
+  #define NOZZLE_CLEAN_END_PT   {100, 60, (Z_MIN_POS + 5)}
+
+  // Moves the nozzle to the parked position
+  #define NOZZLE_CLEAN_PARK
+#endif
+
 //
 // Print job timer
 //