From 3b431f2f726960b912462b8d1943b16d9a68d6b0 Mon Sep 17 00:00:00 2001
From: Scott Lahteine <github@thinkyhead.com>
Date: Thu, 23 Nov 2017 18:13:17 -0600
Subject: [PATCH] Arrange G26 functions in dependency order

---
 Marlin/G26_Mesh_Validation_Tool.cpp | 1050 +++++++++++++--------------
 Marlin/ubl.h                        |    1 -
 Marlin/ubl_G29.cpp                  |   28 +-
 Marlin/ultralcd.cpp                 |    9 +-
 Marlin/ultralcd.h                   |    7 +
 5 files changed, 536 insertions(+), 559 deletions(-)

diff --git a/Marlin/G26_Mesh_Validation_Tool.cpp b/Marlin/G26_Mesh_Validation_Tool.cpp
index 6d3e94970da..23dc19faf85 100644
--- a/Marlin/G26_Mesh_Validation_Tool.cpp
+++ b/Marlin/G26_Mesh_Validation_Tool.cpp
@@ -55,7 +55,7 @@
   #endif
 
   #define G26_OK false
-  #define G26_ERROR true
+  #define G26_ERR true
 
   /**
    *   G26 Mesh Validation Tool
@@ -142,10 +142,6 @@
   void prepare_move_to_destination();
   inline void sync_plan_position_e() { planner.set_e_position_mm(current_position[E_AXIS]); }
   inline void set_current_from_destination() { COPY(current_position, destination); }
-  #if ENABLED(NEWPANEL)
-    void lcd_setstatusPGM(const char* const message, const int8_t level);
-    void chirp_at_user();
-  #endif
 
   // Private functions
 
@@ -155,49 +151,24 @@
 
   static bool g26_retracted = false; // Track the retracted state of the nozzle so mismatched
                                      // retracts/recovers won't result in a bad state.
-  float valid_trig_angle(float);
 
-  void G26_line_to_destination(const float &feed_rate) {
-    const float save_feedrate = feedrate_mm_s;
-    feedrate_mm_s = feed_rate;      // use specified feed rate
-    prepare_move_to_destination();  // will ultimately call ubl.line_to_destination_cartesian for UBL or ubl.prepare_linear_move_to for UBL_DELTA
-    feedrate_mm_s = save_feedrate;  // restore global feed rate
-  }
-  static bool exit_from_g26();
-  static bool parse_G26_parameters();
-  static mesh_index_pair find_closest_circle_to_print(const float&, const float&);
-  static bool look_for_lines_to_connect();
-  static bool turn_on_heaters();
-  static bool prime_nozzle();
-  static void retract_filament(const float where[XYZE]);
-  static void recover_filament(const float where[XYZE]);
-  static void print_line_from_here_to_there(const float&, const float&, const float&, const float&, const float&, const float&);
-  static void move_to(const float&, const float&, const float&, const float&);
-  #if ENABLED(NEWPANEL)
-    extern bool ubl_lcd_clicked();
-  #endif
-  static void move_to(const float where[XYZE], const float &de) { move_to(where[X_AXIS], where[Y_AXIS], where[Z_AXIS], de); }
+  static float g26_extrusion_multiplier,
+               g26_retraction_multiplier,
+               g26_layer_height,
+               g26_prime_length,
+               g26_x_pos, g26_y_pos;
 
-  static float   g26_extrusion_multiplier,
-                 g26_retraction_multiplier,
-                 g26_nozzle,
-                 g26_filament_diameter,
-                 g26_prime_length,
-                 g26_x_pos, g26_y_pos,
-                 g26_ooze_amount,
-                 g26_layer_height;
   static int16_t g26_bed_temp,
-                 g26_hotend_temp,
-                 g26_repeats;
-  static int8_t  g26_prime_flag;
-  static bool    g26_continue_with_closest, g26_keep_heaters_on;
+                 g26_hotend_temp;
+
+  static int8_t g26_prime_flag;
 
   #if ENABLED(NEWPANEL)
     /**
-     * Detect ubl_lcd_clicked, debounce it, and return true for cancel
+     * Detect is_lcd_clicked, debounce it, and return true for cancel
      */
     bool user_canceled() {
-      if (!ubl_lcd_clicked()) return false;
+      if (!is_lcd_clicked()) return false;
       safe_delay(10);                       // Wait for click to settle
 
       #if ENABLED(ULTRA_LCD)
@@ -205,18 +176,385 @@
         lcd_quick_feedback();
       #endif
 
-      while (!ubl_lcd_clicked()) idle();    // Wait for button release
+      while (!is_lcd_clicked()) idle();    // Wait for button release
 
       // If the button is suddenly pressed again,
       // ask the user to resolve the issue
       lcd_setstatusPGM(PSTR("Release button"), 99); // will never appear...
-      while (ubl_lcd_clicked()) idle();             // unless this loop happens
+      while (is_lcd_clicked()) idle();             // unless this loop happens
       lcd_reset_status();
 
       return true;
     }
   #endif
 
+  #if ENABLED(NEWPANEL)
+    bool exit_from_g26() {
+      lcd_setstatusPGM(PSTR("Leaving G26"), -1);
+      while (is_lcd_clicked()) idle();
+      return G26_ERR;
+    }
+  #endif
+
+  void G26_line_to_destination(const float &feed_rate) {
+    const float save_feedrate = feedrate_mm_s;
+    feedrate_mm_s = feed_rate;      // use specified feed rate
+    prepare_move_to_destination();  // will ultimately call ubl.line_to_destination_cartesian for UBL or ubl.prepare_linear_move_to for UBL_DELTA
+    feedrate_mm_s = save_feedrate;  // restore global feed rate
+  }
+
+  void move_to(const float &x, const float &y, const float &z, const float &e_delta) {
+    float feed_value;
+    static float last_z = -999.99;
+
+    bool has_xy_component = (x != current_position[X_AXIS] || y != current_position[Y_AXIS]); // Check if X or Y is involved in the movement.
+
+    if (z != last_z) {
+      last_z = z;
+      feed_value = planner.max_feedrate_mm_s[Z_AXIS]/(3.0);  // Base the feed rate off of the configured Z_AXIS feed rate
+
+      destination[X_AXIS] = current_position[X_AXIS];
+      destination[Y_AXIS] = current_position[Y_AXIS];
+      destination[Z_AXIS] = z;                          // We know the last_z==z or we wouldn't be in this block of code.
+      destination[E_AXIS] = current_position[E_AXIS];
+
+      G26_line_to_destination(feed_value);
+
+      stepper.synchronize();
+      set_destination_from_current();
+    }
+
+    // Check if X or Y is involved in the movement.
+    // Yes: a 'normal' movement. No: a retract() or recover()
+    feed_value = has_xy_component ? PLANNER_XY_FEEDRATE() / 10.0 : planner.max_feedrate_mm_s[E_AXIS] / 1.5;
+
+    if (g26_debug_flag) SERIAL_ECHOLNPAIR("in move_to() feed_value for XY:", feed_value);
+
+    destination[X_AXIS] = x;
+    destination[Y_AXIS] = y;
+    destination[E_AXIS] += e_delta;
+
+    G26_line_to_destination(feed_value);
+
+    stepper.synchronize();
+    set_destination_from_current();
+  }
+
+  FORCE_INLINE void move_to(const float where[XYZE], const float &de) { move_to(where[X_AXIS], where[Y_AXIS], where[Z_AXIS], de); }
+
+  void retract_filament(const float where[XYZE]) {
+    if (!g26_retracted) { // Only retract if we are not already retracted!
+      g26_retracted = true;
+      move_to(where, -1.0 * g26_retraction_multiplier);
+    }
+  }
+
+  void recover_filament(const float where[XYZE]) {
+    if (g26_retracted) { // Only un-retract if we are retracted.
+      move_to(where, 1.2 * g26_retraction_multiplier);
+      g26_retracted = false;
+    }
+  }
+
+  /**
+   * Prime the nozzle if needed. Return true on error.
+   */
+  inline bool prime_nozzle() {
+
+    #if ENABLED(NEWPANEL)
+      float Total_Prime = 0.0;
+
+      if (g26_prime_flag == -1) {  // The user wants to control how much filament gets purged
+
+        lcd_external_control = true;
+        lcd_setstatusPGM(PSTR("User-Controlled Prime"), 99);
+        lcd_chirp();
+
+        set_destination_from_current();
+
+        recover_filament(destination); // Make sure G26 doesn't think the filament is retracted().
+
+        while (!is_lcd_clicked()) {
+          lcd_chirp();
+          destination[E_AXIS] += 0.25;
+          #ifdef PREVENT_LENGTHY_EXTRUDE
+            Total_Prime += 0.25;
+            if (Total_Prime >= EXTRUDE_MAXLENGTH) return G26_ERR;
+          #endif
+          G26_line_to_destination(planner.max_feedrate_mm_s[E_AXIS] / 15.0);
+
+          stepper.synchronize();    // Without this synchronize, the purge is more consistent,
+                                    // but because the planner has a buffer, we won't be able
+                                    // to stop as quickly. So we put up with the less smooth
+                                    // action to give the user a more responsive 'Stop'.
+          set_destination_from_current();
+          idle();
+        }
+
+        while (is_lcd_clicked()) idle();           // Debounce Encoder Wheel
+
+        #if ENABLED(ULTRA_LCD)
+          strcpy_P(lcd_status_message, PSTR("Done Priming")); // We can't do lcd_setstatusPGM() without having it continue;
+                                                              // So... We cheat to get a message up.
+          lcd_setstatusPGM(PSTR("Done Priming"), 99);
+          lcd_quick_feedback();
+          lcd_external_control = false;
+        #endif
+      }
+      else
+    #endif
+    {
+      #if ENABLED(ULTRA_LCD)
+        lcd_setstatusPGM(PSTR("Fixed Length Prime."), 99);
+        lcd_quick_feedback();
+      #endif
+      set_destination_from_current();
+      destination[E_AXIS] += g26_prime_length;
+      G26_line_to_destination(planner.max_feedrate_mm_s[E_AXIS] / 15.0);
+      stepper.synchronize();
+      set_destination_from_current();
+      retract_filament(destination);
+    }
+
+    return G26_OK;
+  }
+
+  mesh_index_pair find_closest_circle_to_print(const float &X, const float &Y) {
+    float closest = 99999.99;
+    mesh_index_pair return_val;
+
+    return_val.x_index = return_val.y_index = -1;
+
+    for (uint8_t i = 0; i < GRID_MAX_POINTS_X; i++) {
+      for (uint8_t j = 0; j < GRID_MAX_POINTS_Y; j++) {
+        if (!is_bit_set(circle_flags, i, j)) {
+          const float mx = _GET_MESH_X(i),  // We found a circle that needs to be printed
+                      my = _GET_MESH_Y(j);
+
+          // Get the distance to this intersection
+          float f = HYPOT(X - mx, Y - my);
+
+          // It is possible that we are being called with the values
+          // to let us find the closest circle to the start position.
+          // But if this is not the case, add a small weighting to the
+          // distance calculation to help it choose a better place to continue.
+          f += HYPOT(g26_x_pos - mx, g26_y_pos - my) / 15.0;
+
+          // Add in the specified amount of Random Noise to our search
+          if (random_deviation > 1.0)
+            f += random(0.0, random_deviation);
+
+          if (f < closest) {
+            closest = f;              // We found a closer location that is still
+            return_val.x_index = i;   // un-printed  --- save the data for it
+            return_val.y_index = j;
+            return_val.distance = closest;
+          }
+        }
+      }
+    }
+    bit_set(circle_flags, return_val.x_index, return_val.y_index);   // Mark this location as done.
+    return return_val;
+  }
+
+  /**
+   * print_line_from_here_to_there() takes two cartesian coordinates and draws a line from one
+   * to the other. But there are really three sets of coordinates involved. The first coordinate
+   * is the present location of the nozzle. We don't necessarily want to print from this location.
+   * We first need to move the nozzle to the start of line segment where we want to print. Once
+   * there, we can use the two coordinates supplied to draw the line.
+   *
+   * Note:  Although we assume the first set of coordinates is the start of the line and the second
+   * set of coordinates is the end of the line, it does not always work out that way. This function
+   * optimizes the movement to minimize the travel distance before it can start printing. This saves
+   * a lot of time and eliminates a lot of nonsensical movement of the nozzle. However, it does
+   * cause a lot of very little short retracement of th nozzle when it draws the very first line
+   * segment of a 'circle'. The time this requires is very short and is easily saved by the other
+   * cases where the optimization comes into play.
+   */
+  void print_line_from_here_to_there(const float &sx, const float &sy, const float &sz, const float &ex, const float &ey, const float &ez) {
+    const float dx_s = current_position[X_AXIS] - sx,   // find our distance from the start of the actual line segment
+                dy_s = current_position[Y_AXIS] - sy,
+                dist_start = HYPOT2(dx_s, dy_s),        // We don't need to do a sqrt(), we can compare the distance^2
+                                                        // to save computation time
+                dx_e = current_position[X_AXIS] - ex,   // find our distance from the end of the actual line segment
+                dy_e = current_position[Y_AXIS] - ey,
+                dist_end = HYPOT2(dx_e, dy_e),
+
+                line_length = HYPOT(ex - sx, ey - sy);
+
+    // If the end point of the line is closer to the nozzle, flip the direction,
+    // moving from the end to the start. On very small lines the optimization isn't worth it.
+    if (dist_end < dist_start && (SIZE_OF_INTERSECTION_CIRCLES) < FABS(line_length))
+      return print_line_from_here_to_there(ex, ey, ez, sx, sy, sz);
+
+    // Decide whether to retract & bump
+
+    if (dist_start > 2.0) {
+      retract_filament(destination);
+      //todo:  parameterize the bump height with a define
+      move_to(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] + 0.500, 0.0);  // Z bump to minimize scraping
+      move_to(sx, sy, sz + 0.500, 0.0); // Get to the starting point with no extrusion while bumped
+    }
+
+    move_to(sx, sy, sz, 0.0); // Get to the starting point with no extrusion / un-Z bump
+
+    const float e_pos_delta = line_length * g26_e_axis_feedrate * g26_extrusion_multiplier;
+
+    recover_filament(destination);
+    move_to(ex, ey, ez, e_pos_delta);  // Get to the ending point with an appropriate amount of extrusion
+  }
+
+  inline bool look_for_lines_to_connect() {
+    float sx, sy, ex, ey;
+
+    for (uint8_t i = 0; i < GRID_MAX_POINTS_X; i++) {
+      for (uint8_t j = 0; j < GRID_MAX_POINTS_Y; j++) {
+
+        #if ENABLED(NEWPANEL)
+          if (user_canceled()) return true;     // Check if the user wants to stop the Mesh Validation
+        #endif
+
+        if (i < GRID_MAX_POINTS_X) { // We can't connect to anything to the right than GRID_MAX_POINTS_X.
+                                     // This is already a half circle because we are at the edge of the bed.
+
+          if (is_bit_set(circle_flags, i, j) && is_bit_set(circle_flags, i + 1, j)) { // check if we can do a line to the left
+            if (!is_bit_set(horizontal_mesh_line_flags, i, j)) {
+
+              //
+              // We found two circles that need a horizontal line to connect them
+              // Print it!
+              //
+              sx = _GET_MESH_X(  i  ) + (SIZE_OF_INTERSECTION_CIRCLES - (SIZE_OF_CROSSHAIRS)); // right edge
+              ex = _GET_MESH_X(i + 1) - (SIZE_OF_INTERSECTION_CIRCLES - (SIZE_OF_CROSSHAIRS)); // left edge
+
+              sx = constrain(sx, X_MIN_POS + 1, X_MAX_POS - 1);
+              sy = ey = constrain(_GET_MESH_Y(j), Y_MIN_POS + 1, Y_MAX_POS - 1);
+              ex = constrain(ex, X_MIN_POS + 1, X_MAX_POS - 1);
+
+              if (position_is_reachable(sx, sy) && position_is_reachable(ex, ey)) {
+
+                if (g26_debug_flag) {
+                  SERIAL_ECHOPAIR(" Connecting with horizontal line (sx=", sx);
+                  SERIAL_ECHOPAIR(", sy=", sy);
+                  SERIAL_ECHOPAIR(") -> (ex=", ex);
+                  SERIAL_ECHOPAIR(", ey=", ey);
+                  SERIAL_CHAR(')');
+                  SERIAL_EOL();
+                  //debug_current_and_destination(PSTR("Connecting horizontal line."));
+                }
+                print_line_from_here_to_there(sx, sy, g26_layer_height, ex, ey, g26_layer_height);
+              }
+              bit_set(horizontal_mesh_line_flags, i, j);   // Mark it as done so we don't do it again, even if we skipped it
+            }
+          }
+
+          if (j < GRID_MAX_POINTS_Y) { // We can't connect to anything further back than GRID_MAX_POINTS_Y.
+                                           // This is already a half circle because we are at the edge  of the bed.
+
+            if (is_bit_set(circle_flags, i, j) && is_bit_set(circle_flags, i, j + 1)) { // check if we can do a line straight down
+              if (!is_bit_set( vertical_mesh_line_flags, i, j)) {
+                //
+                // We found two circles that need a vertical line to connect them
+                // Print it!
+                //
+                sy = _GET_MESH_Y(  j  ) + (SIZE_OF_INTERSECTION_CIRCLES - (SIZE_OF_CROSSHAIRS)); // top edge
+                ey = _GET_MESH_Y(j + 1) - (SIZE_OF_INTERSECTION_CIRCLES - (SIZE_OF_CROSSHAIRS)); // bottom edge
+
+                sx = ex = constrain(_GET_MESH_X(i), X_MIN_POS + 1, X_MAX_POS - 1);
+                sy = constrain(sy, Y_MIN_POS + 1, Y_MAX_POS - 1);
+                ey = constrain(ey, Y_MIN_POS + 1, Y_MAX_POS - 1);
+
+                if (position_is_reachable(sx, sy) && position_is_reachable(ex, ey)) {
+
+                  if (g26_debug_flag) {
+                    SERIAL_ECHOPAIR(" Connecting with vertical line (sx=", sx);
+                    SERIAL_ECHOPAIR(", sy=", sy);
+                    SERIAL_ECHOPAIR(") -> (ex=", ex);
+                    SERIAL_ECHOPAIR(", ey=", ey);
+                    SERIAL_CHAR(')');
+                    SERIAL_EOL();
+
+                    #if ENABLED(AUTO_BED_LEVELING_UBL)
+                      debug_current_and_destination(PSTR("Connecting vertical line."));
+                    #endif
+                  }
+                  print_line_from_here_to_there(sx, sy, g26_layer_height, ex, ey, g26_layer_height);
+                }
+                bit_set(vertical_mesh_line_flags, i, j);   // Mark it as done so we don't do it again, even if skipped
+              }
+            }
+          }
+        }
+      }
+    }
+    return false;
+  }
+
+  float valid_trig_angle(float d) {
+    while (d > 360.0) d -= 360.0;
+    while (d < 0.0) d += 360.0;
+    return d;
+  }
+
+  /**
+   * Turn on the bed and nozzle heat and
+   * wait for them to get up to temperature.
+   */
+  bool turn_on_heaters() {
+    millis_t next = millis() + 5000UL;
+    #if HAS_TEMP_BED
+      #if ENABLED(ULTRA_LCD)
+        if (g26_bed_temp > 25) {
+          lcd_setstatusPGM(PSTR("G26 Heating Bed."), 99);
+          lcd_quick_feedback();
+          lcd_external_control = true;
+      #endif
+          thermalManager.setTargetBed(g26_bed_temp);
+          while (abs(thermalManager.degBed() - g26_bed_temp) > 3) {
+
+            #if ENABLED(NEWPANEL)
+              if (is_lcd_clicked()) return exit_from_g26();
+            #endif
+
+            if (ELAPSED(millis(), next)) {
+              next = millis() + 5000UL;
+              print_heaterstates();
+              SERIAL_EOL();
+            }
+            idle();
+          }
+      #if ENABLED(ULTRA_LCD)
+        }
+        lcd_setstatusPGM(PSTR("G26 Heating Nozzle."), 99);
+        lcd_quick_feedback();
+      #endif
+    #endif
+
+    // Start heating the nozzle and wait for it to reach temperature.
+    thermalManager.setTargetHotend(g26_hotend_temp, 0);
+    while (abs(thermalManager.degHotend(0) - g26_hotend_temp) > 3) {
+
+      #if ENABLED(NEWPANEL)
+        if (is_lcd_clicked()) return exit_from_g26();
+      #endif
+
+      if (ELAPSED(millis(), next)) {
+        next = millis() + 5000UL;
+        print_heaterstates();
+        SERIAL_EOL();
+      }
+      idle();
+    }
+
+    #if ENABLED(ULTRA_LCD)
+      lcd_reset_status();
+      lcd_quick_feedback();
+    #endif
+
+    return G26_OK;
+  }
+
   /**
    * G26: Mesh Validation Pattern generation.
    *
@@ -231,7 +569,134 @@
 
     // Don't allow Mesh Validation without homing first,
     // or if the parameter parsing did not go OK, abort
-    if (axis_unhomed_error() || parse_G26_parameters()) return;
+    if (axis_unhomed_error()) return;
+
+    g26_extrusion_multiplier    = EXTRUSION_MULTIPLIER;
+    g26_retraction_multiplier   = RETRACTION_MULTIPLIER;
+    g26_layer_height            = MESH_TEST_LAYER_HEIGHT;
+    g26_prime_length            = PRIME_LENGTH;
+    g26_bed_temp                = MESH_TEST_BED_TEMP;
+    g26_hotend_temp             = MESH_TEST_HOTEND_TEMP;
+    g26_prime_flag              = 0;
+
+    float g26_nozzle            = MESH_TEST_NOZZLE_SIZE,
+          g26_filament_diameter = DEFAULT_NOMINAL_FILAMENT_DIA,
+          g26_ooze_amount       = parser.linearval('O', OOZE_AMOUNT);
+
+    bool g26_continue_with_closest = parser.boolval('C'),
+         g26_keep_heaters_on       = parser.boolval('K');
+
+    if (parser.seenval('B')) {
+      g26_bed_temp = parser.value_celsius();
+      if (!WITHIN(g26_bed_temp, 15, 140)) {
+        SERIAL_PROTOCOLLNPGM("?Specified bed temperature not plausible.");
+        return G26_ERR;
+      }
+    }
+
+    if (parser.seenval('L')) {
+      g26_layer_height = parser.value_linear_units();
+      if (!WITHIN(g26_layer_height, 0.0, 2.0)) {
+        SERIAL_PROTOCOLLNPGM("?Specified layer height not plausible.");
+        return G26_ERR;
+      }
+    }
+
+    if (parser.seen('Q')) {
+      if (parser.has_value()) {
+        g26_retraction_multiplier = parser.value_float();
+        if (!WITHIN(g26_retraction_multiplier, 0.05, 15.0)) {
+          SERIAL_PROTOCOLLNPGM("?Specified Retraction Multiplier not plausible.");
+          return G26_ERR;
+        }
+      }
+      else {
+        SERIAL_PROTOCOLLNPGM("?Retraction Multiplier must be specified.");
+        return G26_ERR;
+      }
+    }
+
+    if (parser.seenval('S')) {
+      g26_nozzle = parser.value_float();
+      if (!WITHIN(g26_nozzle, 0.1, 1.0)) {
+        SERIAL_PROTOCOLLNPGM("?Specified nozzle size not plausible.");
+        return G26_ERR;
+      }
+    }
+
+    if (parser.seen('P')) {
+      if (!parser.has_value()) {
+        #if ENABLED(NEWPANEL)
+          g26_prime_flag = -1;
+        #else
+          SERIAL_PROTOCOLLNPGM("?Prime length must be specified when not using an LCD.");
+          return G26_ERR;
+        #endif
+      }
+      else {
+        g26_prime_flag++;
+        g26_prime_length = parser.value_linear_units();
+        if (!WITHIN(g26_prime_length, 0.0, 25.0)) {
+          SERIAL_PROTOCOLLNPGM("?Specified prime length not plausible.");
+          return G26_ERR;
+        }
+      }
+    }
+
+    if (parser.seenval('F')) {
+      g26_filament_diameter = parser.value_linear_units();
+      if (!WITHIN(g26_filament_diameter, 1.0, 4.0)) {
+        SERIAL_PROTOCOLLNPGM("?Specified filament size not plausible.");
+        return G26_ERR;
+      }
+    }
+    g26_extrusion_multiplier *= sq(1.75) / sq(g26_filament_diameter); // If we aren't using 1.75mm filament, we need to
+                                                                      // scale up or down the length needed to get the
+                                                                      // same volume of filament
+
+    g26_extrusion_multiplier *= g26_filament_diameter * sq(g26_nozzle) / sq(0.3); // Scale up by nozzle size
+
+    if (parser.seenval('H')) {
+      g26_hotend_temp = parser.value_celsius();
+      if (!WITHIN(g26_hotend_temp, 165, 280)) {
+        SERIAL_PROTOCOLLNPGM("?Specified nozzle temperature not plausible.");
+        return G26_ERR;
+      }
+    }
+
+    if (parser.seen('U')) {
+      randomSeed(millis());
+      // This setting will persist for the next G26
+      random_deviation = parser.has_value() ? parser.value_float() : 50.0;
+    }
+
+    int16_t g26_repeats;
+    #if ENABLED(NEWPANEL)
+      g26_repeats = parser.intval('R', GRID_MAX_POINTS + 1);
+    #else
+      if (!parser.seen('R')) {
+        SERIAL_PROTOCOLLNPGM("?(R)epeat must be specified when not using an LCD.");
+        return G26_ERR;
+      }
+      else
+        g26_repeats = parser.has_value() ? parser.value_int() : GRID_MAX_POINTS + 1;
+    #endif
+    if (g26_repeats < 1) {
+      SERIAL_PROTOCOLLNPGM("?(R)epeat value not plausible; must be at least 1.");
+      return G26_ERR;
+    }
+
+    g26_x_pos = parser.seenval('X') ? RAW_X_POSITION(parser.value_linear_units()) : current_position[X_AXIS];
+    g26_y_pos = parser.seenval('Y') ? RAW_Y_POSITION(parser.value_linear_units()) : current_position[Y_AXIS];
+    if (!position_is_reachable(g26_x_pos, g26_y_pos)) {
+      SERIAL_PROTOCOLLNPGM("?Specified X,Y coordinate out of bounds.");
+      return G26_ERR;
+    }
+
+    /**
+     * Wait until all parameters are verified before altering the state!
+     */
+    set_bed_leveling_enabled(!parser.seen('D'));
 
     if (current_position[Z_AXIS] < Z_CLEARANCE_BETWEEN_PROBES) {
       do_blocking_move_to_z(Z_CLEARANCE_BETWEEN_PROBES);
@@ -385,9 +850,9 @@
     move_to(destination, 0); // Raise the nozzle
     //debug_current_and_destination(PSTR("done doing Z-Raise."));
 
-    destination[X_AXIS] = g26_x_pos;                                               // Move back to the starting position
+    destination[X_AXIS] = g26_x_pos;                               // Move back to the starting position
     destination[Y_AXIS] = g26_y_pos;
-    //destination[Z_AXIS] = Z_CLEARANCE_BETWEEN_PROBES;                        // Keep the nozzle where it is
+    //destination[Z_AXIS] = Z_CLEARANCE_BETWEEN_PROBES;            // Keep the nozzle where it is
 
     move_to(destination, 0); // Move back to the starting position
     //debug_current_and_destination(PSTR("done doing X/Y move."));
@@ -404,499 +869,4 @@
     }
   }
 
-  float valid_trig_angle(float d) {
-    while (d > 360.0) d -= 360.0;
-    while (d < 0.0) d += 360.0;
-    return d;
-  }
-
-  mesh_index_pair find_closest_circle_to_print(const float &X, const float &Y) {
-    float closest = 99999.99;
-    mesh_index_pair return_val;
-
-    return_val.x_index = return_val.y_index = -1;
-
-    for (uint8_t i = 0; i < GRID_MAX_POINTS_X; i++) {
-      for (uint8_t j = 0; j < GRID_MAX_POINTS_Y; j++) {
-        if (!is_bit_set(circle_flags, i, j)) {
-          const float mx = _GET_MESH_X(i),  // We found a circle that needs to be printed
-                      my = _GET_MESH_Y(j);
-
-          // Get the distance to this intersection
-          float f = HYPOT(X - mx, Y - my);
-
-          // It is possible that we are being called with the values
-          // to let us find the closest circle to the start position.
-          // But if this is not the case, add a small weighting to the
-          // distance calculation to help it choose a better place to continue.
-          f += HYPOT(g26_x_pos - mx, g26_y_pos - my) / 15.0;
-
-          // Add in the specified amount of Random Noise to our search
-          if (random_deviation > 1.0)
-            f += random(0.0, random_deviation);
-
-          if (f < closest) {
-            closest = f;              // We found a closer location that is still
-            return_val.x_index = i;   // un-printed  --- save the data for it
-            return_val.y_index = j;
-            return_val.distance = closest;
-          }
-        }
-      }
-    }
-    bit_set(circle_flags, return_val.x_index, return_val.y_index);   // Mark this location as done.
-    return return_val;
-  }
-
-  bool look_for_lines_to_connect() {
-    float sx, sy, ex, ey;
-
-    for (uint8_t i = 0; i < GRID_MAX_POINTS_X; i++) {
-      for (uint8_t j = 0; j < GRID_MAX_POINTS_Y; j++) {
-
-        #if ENABLED(NEWPANEL)
-          if (user_canceled()) return true;     // Check if the user wants to stop the Mesh Validation
-        #endif
-
-        if (i < GRID_MAX_POINTS_X) { // We can't connect to anything to the right than GRID_MAX_POINTS_X.
-                                     // This is already a half circle because we are at the edge of the bed.
-
-          if (is_bit_set(circle_flags, i, j) && is_bit_set(circle_flags, i + 1, j)) { // check if we can do a line to the left
-            if (!is_bit_set(horizontal_mesh_line_flags, i, j)) {
-
-              //
-              // We found two circles that need a horizontal line to connect them
-              // Print it!
-              //
-              sx = _GET_MESH_X(  i  ) + (SIZE_OF_INTERSECTION_CIRCLES - (SIZE_OF_CROSSHAIRS)); // right edge
-              ex = _GET_MESH_X(i + 1) - (SIZE_OF_INTERSECTION_CIRCLES - (SIZE_OF_CROSSHAIRS)); // left edge
-
-              sx = constrain(sx, X_MIN_POS + 1, X_MAX_POS - 1);
-              sy = ey = constrain(_GET_MESH_Y(j), Y_MIN_POS + 1, Y_MAX_POS - 1);
-              ex = constrain(ex, X_MIN_POS + 1, X_MAX_POS - 1);
-
-              if (position_is_reachable(sx, sy) && position_is_reachable(ex, ey)) {
-
-                if (g26_debug_flag) {
-                  SERIAL_ECHOPAIR(" Connecting with horizontal line (sx=", sx);
-                  SERIAL_ECHOPAIR(", sy=", sy);
-                  SERIAL_ECHOPAIR(") -> (ex=", ex);
-                  SERIAL_ECHOPAIR(", ey=", ey);
-                  SERIAL_CHAR(')');
-                  SERIAL_EOL();
-                  //debug_current_and_destination(PSTR("Connecting horizontal line."));
-                }
-                print_line_from_here_to_there(sx, sy, g26_layer_height, ex, ey, g26_layer_height);
-              }
-              bit_set(horizontal_mesh_line_flags, i, j);   // Mark it as done so we don't do it again, even if we skipped it
-            }
-          }
-
-          if (j < GRID_MAX_POINTS_Y) { // We can't connect to anything further back than GRID_MAX_POINTS_Y.
-                                           // This is already a half circle because we are at the edge  of the bed.
-
-            if (is_bit_set(circle_flags, i, j) && is_bit_set(circle_flags, i, j + 1)) { // check if we can do a line straight down
-              if (!is_bit_set( vertical_mesh_line_flags, i, j)) {
-                //
-                // We found two circles that need a vertical line to connect them
-                // Print it!
-                //
-                sy = _GET_MESH_Y(  j  ) + (SIZE_OF_INTERSECTION_CIRCLES - (SIZE_OF_CROSSHAIRS)); // top edge
-                ey = _GET_MESH_Y(j + 1) - (SIZE_OF_INTERSECTION_CIRCLES - (SIZE_OF_CROSSHAIRS)); // bottom edge
-
-                sx = ex = constrain(_GET_MESH_X(i), X_MIN_POS + 1, X_MAX_POS - 1);
-                sy = constrain(sy, Y_MIN_POS + 1, Y_MAX_POS - 1);
-                ey = constrain(ey, Y_MIN_POS + 1, Y_MAX_POS - 1);
-
-                if (position_is_reachable(sx, sy) && position_is_reachable(ex, ey)) {
-
-                  if (g26_debug_flag) {
-                    SERIAL_ECHOPAIR(" Connecting with vertical line (sx=", sx);
-                    SERIAL_ECHOPAIR(", sy=", sy);
-                    SERIAL_ECHOPAIR(") -> (ex=", ex);
-                    SERIAL_ECHOPAIR(", ey=", ey);
-                    SERIAL_CHAR(')');
-                    SERIAL_EOL();
-
-                    #if ENABLED(AUTO_BED_LEVELING_UBL)
-                      debug_current_and_destination(PSTR("Connecting vertical line."));
-                    #endif
-                  }
-                  print_line_from_here_to_there(sx, sy, g26_layer_height, ex, ey, g26_layer_height);
-                }
-                bit_set(vertical_mesh_line_flags, i, j);   // Mark it as done so we don't do it again, even if skipped
-              }
-            }
-          }
-        }
-      }
-    }
-    return false;
-  }
-
-  void move_to(const float &x, const float &y, const float &z, const float &e_delta) {
-    float feed_value;
-    static float last_z = -999.99;
-
-    bool has_xy_component = (x != current_position[X_AXIS] || y != current_position[Y_AXIS]); // Check if X or Y is involved in the movement.
-
-    if (z != last_z) {
-      last_z = z;
-      feed_value = planner.max_feedrate_mm_s[Z_AXIS]/(3.0);  // Base the feed rate off of the configured Z_AXIS feed rate
-
-      destination[X_AXIS] = current_position[X_AXIS];
-      destination[Y_AXIS] = current_position[Y_AXIS];
-      destination[Z_AXIS] = z;                          // We know the last_z==z or we wouldn't be in this block of code.
-      destination[E_AXIS] = current_position[E_AXIS];
-
-      G26_line_to_destination(feed_value);
-
-      stepper.synchronize();
-      set_destination_from_current();
-    }
-
-    // Check if X or Y is involved in the movement.
-    // Yes: a 'normal' movement. No: a retract() or recover()
-    feed_value = has_xy_component ? PLANNER_XY_FEEDRATE() / 10.0 : planner.max_feedrate_mm_s[E_AXIS] / 1.5;
-
-    if (g26_debug_flag) SERIAL_ECHOLNPAIR("in move_to() feed_value for XY:", feed_value);
-
-    destination[X_AXIS] = x;
-    destination[Y_AXIS] = y;
-    destination[E_AXIS] += e_delta;
-
-    G26_line_to_destination(feed_value);
-
-    stepper.synchronize();
-    set_destination_from_current();
-
-  }
-
-  void retract_filament(const float where[XYZE]) {
-    if (!g26_retracted) { // Only retract if we are not already retracted!
-      g26_retracted = true;
-      move_to(where, -1.0 * g26_retraction_multiplier);
-    }
-  }
-
-  void recover_filament(const float where[XYZE]) {
-    if (g26_retracted) { // Only un-retract if we are retracted.
-      move_to(where, 1.2 * g26_retraction_multiplier);
-      g26_retracted = false;
-    }
-  }
-
-  /**
-   * print_line_from_here_to_there() takes two cartesian coordinates and draws a line from one
-   * to the other. But there are really three sets of coordinates involved. The first coordinate
-   * is the present location of the nozzle. We don't necessarily want to print from this location.
-   * We first need to move the nozzle to the start of line segment where we want to print. Once
-   * there, we can use the two coordinates supplied to draw the line.
-   *
-   * Note:  Although we assume the first set of coordinates is the start of the line and the second
-   * set of coordinates is the end of the line, it does not always work out that way. This function
-   * optimizes the movement to minimize the travel distance before it can start printing. This saves
-   * a lot of time and eliminates a lot of nonsensical movement of the nozzle. However, it does
-   * cause a lot of very little short retracement of th nozzle when it draws the very first line
-   * segment of a 'circle'. The time this requires is very short and is easily saved by the other
-   * cases where the optimization comes into play.
-   */
-  void print_line_from_here_to_there(const float &sx, const float &sy, const float &sz, const float &ex, const float &ey, const float &ez) {
-    const float dx_s = current_position[X_AXIS] - sx,   // find our distance from the start of the actual line segment
-                dy_s = current_position[Y_AXIS] - sy,
-                dist_start = HYPOT2(dx_s, dy_s),        // We don't need to do a sqrt(), we can compare the distance^2
-                                                        // to save computation time
-                dx_e = current_position[X_AXIS] - ex,   // find our distance from the end of the actual line segment
-                dy_e = current_position[Y_AXIS] - ey,
-                dist_end = HYPOT2(dx_e, dy_e),
-
-                line_length = HYPOT(ex - sx, ey - sy);
-
-    // If the end point of the line is closer to the nozzle, flip the direction,
-    // moving from the end to the start. On very small lines the optimization isn't worth it.
-    if (dist_end < dist_start && (SIZE_OF_INTERSECTION_CIRCLES) < FABS(line_length))
-      return print_line_from_here_to_there(ex, ey, ez, sx, sy, sz);
-
-    // Decide whether to retract & bump
-
-    if (dist_start > 2.0) {
-      retract_filament(destination);
-      //todo:  parameterize the bump height with a define
-      move_to(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] + 0.500, 0.0);  // Z bump to minimize scraping
-      move_to(sx, sy, sz + 0.500, 0.0); // Get to the starting point with no extrusion while bumped
-    }
-
-    move_to(sx, sy, sz, 0.0); // Get to the starting point with no extrusion / un-Z bump
-
-    const float e_pos_delta = line_length * g26_e_axis_feedrate * g26_extrusion_multiplier;
-
-    recover_filament(destination);
-    move_to(ex, ey, ez, e_pos_delta);  // Get to the ending point with an appropriate amount of extrusion
-  }
-
-  /**
-   * This function used to be inline code in G26. But there are so many
-   * parameters it made sense to turn them into static globals and get
-   * this code out of sight of the main routine.
-   */
-  bool parse_G26_parameters() {
-
-    g26_extrusion_multiplier  = EXTRUSION_MULTIPLIER;
-    g26_retraction_multiplier = RETRACTION_MULTIPLIER;
-    g26_nozzle                = MESH_TEST_NOZZLE_SIZE;
-    g26_filament_diameter     = DEFAULT_NOMINAL_FILAMENT_DIA;
-    g26_layer_height          = MESH_TEST_LAYER_HEIGHT;
-    g26_prime_length          = PRIME_LENGTH;
-    g26_bed_temp              = MESH_TEST_BED_TEMP;
-    g26_hotend_temp           = MESH_TEST_HOTEND_TEMP;
-    g26_prime_flag            = 0;
-
-    g26_ooze_amount           = parser.linearval('O', OOZE_AMOUNT);
-    g26_keep_heaters_on       = parser.boolval('K');
-    g26_continue_with_closest = parser.boolval('C');
-
-    if (parser.seenval('B')) {
-      g26_bed_temp = parser.value_celsius();
-      if (!WITHIN(g26_bed_temp, 15, 140)) {
-        SERIAL_PROTOCOLLNPGM("?Specified bed temperature not plausible.");
-        return G26_ERROR;
-      }
-    }
-
-    if (parser.seenval('L')) {
-      g26_layer_height = parser.value_linear_units();
-      if (!WITHIN(g26_layer_height, 0.0, 2.0)) {
-        SERIAL_PROTOCOLLNPGM("?Specified layer height not plausible.");
-        return G26_ERROR;
-      }
-    }
-
-    if (parser.seen('Q')) {
-      if (parser.has_value()) {
-        g26_retraction_multiplier = parser.value_float();
-        if (!WITHIN(g26_retraction_multiplier, 0.05, 15.0)) {
-          SERIAL_PROTOCOLLNPGM("?Specified Retraction Multiplier not plausible.");
-          return G26_ERROR;
-        }
-      }
-      else {
-        SERIAL_PROTOCOLLNPGM("?Retraction Multiplier must be specified.");
-        return G26_ERROR;
-      }
-    }
-
-    if (parser.seenval('S')) {
-      g26_nozzle = parser.value_float();
-      if (!WITHIN(g26_nozzle, 0.1, 1.0)) {
-        SERIAL_PROTOCOLLNPGM("?Specified nozzle size not plausible.");
-        return G26_ERROR;
-      }
-    }
-
-    if (parser.seen('P')) {
-      if (!parser.has_value()) {
-        #if ENABLED(NEWPANEL)
-          g26_prime_flag = -1;
-        #else
-          SERIAL_PROTOCOLLNPGM("?Prime length must be specified when not using an LCD.");
-          return G26_ERROR;
-        #endif
-      }
-      else {
-        g26_prime_flag++;
-        g26_prime_length = parser.value_linear_units();
-        if (!WITHIN(g26_prime_length, 0.0, 25.0)) {
-          SERIAL_PROTOCOLLNPGM("?Specified prime length not plausible.");
-          return G26_ERROR;
-        }
-      }
-    }
-
-    if (parser.seenval('F')) {
-      g26_filament_diameter = parser.value_linear_units();
-      if (!WITHIN(g26_filament_diameter, 1.0, 4.0)) {
-        SERIAL_PROTOCOLLNPGM("?Specified filament size not plausible.");
-        return G26_ERROR;
-      }
-    }
-    g26_extrusion_multiplier *= sq(1.75) / sq(g26_filament_diameter); // If we aren't using 1.75mm filament, we need to
-                                                                      // scale up or down the length needed to get the
-                                                                      // same volume of filament
-
-    g26_extrusion_multiplier *= g26_filament_diameter * sq(g26_nozzle) / sq(0.3); // Scale up by nozzle size
-
-    if (parser.seenval('H')) {
-      g26_hotend_temp = parser.value_celsius();
-      if (!WITHIN(g26_hotend_temp, 165, 280)) {
-        SERIAL_PROTOCOLLNPGM("?Specified nozzle temperature not plausible.");
-        return G26_ERROR;
-      }
-    }
-
-    if (parser.seen('U')) {
-      randomSeed(millis());
-      // This setting will persist for the next G26
-      random_deviation = parser.has_value() ? parser.value_float() : 50.0;
-    }
-
-    #if ENABLED(NEWPANEL)
-      g26_repeats = parser.intval('R', GRID_MAX_POINTS + 1);
-    #else
-      if (!parser.seen('R')) {
-        SERIAL_PROTOCOLLNPGM("?(R)epeat must be specified when not using an LCD.");
-        return G26_ERROR;
-      }
-      else
-        g26_repeats = parser.has_value() ? parser.value_int() : GRID_MAX_POINTS + 1;
-    #endif
-    if (g26_repeats < 1) {
-      SERIAL_PROTOCOLLNPGM("?(R)epeat value not plausible; must be at least 1.");
-      return G26_ERROR;
-    }
-
-    g26_x_pos = parser.seenval('X') ? RAW_X_POSITION(parser.value_linear_units()) : current_position[X_AXIS];
-    g26_y_pos = parser.seenval('Y') ? RAW_Y_POSITION(parser.value_linear_units()) : current_position[Y_AXIS];
-    if (!position_is_reachable(g26_x_pos, g26_y_pos)) {
-      SERIAL_PROTOCOLLNPGM("?Specified X,Y coordinate out of bounds.");
-      return G26_ERROR;
-    }
-
-    /**
-     * Wait until all parameters are verified before altering the state!
-     */
-    set_bed_leveling_enabled(!parser.seen('D'));
-
-    return G26_OK;
-  }
-
-  #if ENABLED(NEWPANEL)
-    bool exit_from_g26() {
-      lcd_setstatusPGM(PSTR("Leaving G26"), -1);
-      while (ubl_lcd_clicked()) idle();
-      return G26_ERROR;
-    }
-  #endif
-
-  /**
-   * Turn on the bed and nozzle heat and
-   * wait for them to get up to temperature.
-   */
-  bool turn_on_heaters() {
-    millis_t next = millis() + 5000UL;
-    #if HAS_TEMP_BED
-      #if ENABLED(ULTRA_LCD)
-        if (g26_bed_temp > 25) {
-          lcd_setstatusPGM(PSTR("G26 Heating Bed."), 99);
-          lcd_quick_feedback();
-          lcd_external_control = true;
-      #endif
-          thermalManager.setTargetBed(g26_bed_temp);
-          while (abs(thermalManager.degBed() - g26_bed_temp) > 3) {
-
-            #if ENABLED(NEWPANEL)
-              if (ubl_lcd_clicked()) return exit_from_g26();
-            #endif
-
-            if (ELAPSED(millis(), next)) {
-              next = millis() + 5000UL;
-              print_heaterstates();
-              SERIAL_EOL();
-            }
-            idle();
-          }
-      #if ENABLED(ULTRA_LCD)
-        }
-        lcd_setstatusPGM(PSTR("G26 Heating Nozzle."), 99);
-        lcd_quick_feedback();
-      #endif
-    #endif
-
-    // Start heating the nozzle and wait for it to reach temperature.
-    thermalManager.setTargetHotend(g26_hotend_temp, 0);
-    while (abs(thermalManager.degHotend(0) - g26_hotend_temp) > 3) {
-
-      #if ENABLED(NEWPANEL)
-        if (ubl_lcd_clicked()) return exit_from_g26();
-      #endif
-
-      if (ELAPSED(millis(), next)) {
-        next = millis() + 5000UL;
-        print_heaterstates();
-        SERIAL_EOL();
-      }
-      idle();
-    }
-
-    #if ENABLED(ULTRA_LCD)
-      lcd_reset_status();
-      lcd_quick_feedback();
-    #endif
-
-    return G26_OK;
-  }
-
-  /**
-   * Prime the nozzle if needed. Return true on error.
-   */
-  bool prime_nozzle() {
-
-    #if ENABLED(NEWPANEL)
-      float Total_Prime = 0.0;
-
-      if (g26_prime_flag == -1) {  // The user wants to control how much filament gets purged
-
-        lcd_external_control = true;
-        lcd_setstatusPGM(PSTR("User-Controlled Prime"), 99);
-        chirp_at_user();
-
-        set_destination_from_current();
-
-        recover_filament(destination); // Make sure G26 doesn't think the filament is retracted().
-
-        while (!ubl_lcd_clicked()) {
-          chirp_at_user();
-          destination[E_AXIS] += 0.25;
-          #ifdef PREVENT_LENGTHY_EXTRUDE
-            Total_Prime += 0.25;
-            if (Total_Prime >= EXTRUDE_MAXLENGTH) return G26_ERROR;
-          #endif
-          G26_line_to_destination(planner.max_feedrate_mm_s[E_AXIS] / 15.0);
-
-          stepper.synchronize();    // Without this synchronize, the purge is more consistent,
-                                    // but because the planner has a buffer, we won't be able
-                                    // to stop as quickly. So we put up with the less smooth
-                                    // action to give the user a more responsive 'Stop'.
-          set_destination_from_current();
-          idle();
-        }
-
-        while (ubl_lcd_clicked()) idle();           // Debounce Encoder Wheel
-
-        #if ENABLED(ULTRA_LCD)
-          strcpy_P(lcd_status_message, PSTR("Done Priming")); // We can't do lcd_setstatusPGM() without having it continue;
-                                                              // So... We cheat to get a message up.
-          lcd_setstatusPGM(PSTR("Done Priming"), 99);
-          lcd_quick_feedback();
-          lcd_external_control = false;
-        #endif
-      }
-      else {
-    #else
-    {
-    #endif
-      #if ENABLED(ULTRA_LCD)
-        lcd_setstatusPGM(PSTR("Fixed Length Prime."), 99);
-        lcd_quick_feedback();
-      #endif
-      set_destination_from_current();
-      destination[E_AXIS] += g26_prime_length;
-      G26_line_to_destination(planner.max_feedrate_mm_s[E_AXIS] / 15.0);
-      stepper.synchronize();
-      set_destination_from_current();
-      retract_filament(destination);
-    }
-
-    return G26_OK;
-  }
-
 #endif // G26_MESH_VALIDATION
diff --git a/Marlin/ubl.h b/Marlin/ubl.h
index 24bcfb0a8e0..2b73d3cfdd9 100644
--- a/Marlin/ubl.h
+++ b/Marlin/ubl.h
@@ -50,7 +50,6 @@
   // External references
 
   char *ftostr43sign(const float&, char);
-  bool ubl_lcd_clicked();
   void home_all_axes();
 
   extern uint8_t ubl_cnt;
diff --git a/Marlin/ubl_G29.cpp b/Marlin/ubl_G29.cpp
index 43c187ca3da..93066593154 100644
--- a/Marlin/ubl_G29.cpp
+++ b/Marlin/ubl_G29.cpp
@@ -47,7 +47,6 @@
     float lcd_mesh_edit();
     void lcd_z_offset_edit_setup(float);
     extern void _lcd_ubl_output_map_lcd();
-    extern bool ubl_lcd_clicked();
     float lcd_z_offset_edit();
   #endif
 
@@ -750,11 +749,11 @@
         if (do_ubl_mesh_map) display_map(g29_map_type);
 
         #if ENABLED(NEWPANEL)
-          if (ubl_lcd_clicked()) {
+          if (is_lcd_clicked()) {
             SERIAL_PROTOCOLLNPGM("\nMesh only partially populated.\n");
             lcd_quick_feedback();
             STOW_PROBE();
-            while (ubl_lcd_clicked()) idle();
+            while (is_lcd_clicked()) idle();
             lcd_external_control = false;
             restore_ubl_active_state_and_leave();
             safe_delay(50);  // Debounce the Encoder wheel
@@ -893,13 +892,14 @@
   #endif // HAS_BED_PROBE
 
   #if ENABLED(NEWPANEL)
+
     float unified_bed_leveling::measure_point_with_encoder() {
 
-      while (ubl_lcd_clicked()) delay(50);  // wait for user to release encoder wheel
+      while (is_lcd_clicked()) delay(50);  // wait for user to release encoder wheel
       delay(50);  // debounce
 
       KEEPALIVE_STATE(PAUSED_FOR_USER);
-      while (!ubl_lcd_clicked()) {     // we need the loop to move the nozzle based on the encoder wheel here!
+      while (!is_lcd_clicked()) {     // we need the loop to move the nozzle based on the encoder wheel here!
         idle();
         if (encoder_diff) {
           do_blocking_move_to_z(current_position[Z_AXIS] + 0.01 * float(encoder_diff));
@@ -989,9 +989,9 @@
         const float z_step = 0.01;                                        // existing behavior: 0.01mm per click, occasionally step
         //const float z_step = 1.0 / planner.axis_steps_per_mm[Z_AXIS];   // approx one step each click
 
-        while (ubl_lcd_clicked()) delay(50);             // wait for user to release encoder wheel
+        while (is_lcd_clicked()) delay(50);             // wait for user to release encoder wheel
         delay(50);                                       // debounce
-        while (!ubl_lcd_clicked()) {                     // we need the loop to move the nozzle based on the encoder wheel here!
+        while (!is_lcd_clicked()) {                     // we need the loop to move the nozzle based on the encoder wheel here!
           idle();
           if (encoder_diff) {
             do_blocking_move_to_z(current_position[Z_AXIS] + float(encoder_diff) * z_step);
@@ -999,11 +999,11 @@
           }
         }
 
-        // this sequence to detect an ubl_lcd_clicked() debounce it and leave if it is
+        // this sequence to detect an is_lcd_clicked() debounce it and leave if it is
         // a Press and Hold is repeated in a lot of places (including G26_Mesh_Validation.cpp).   This
         // should be redone and compressed.
         const millis_t nxt = millis() + 1500L;
-        while (ubl_lcd_clicked()) {     // debounce and watch for abort
+        while (is_lcd_clicked()) {     // debounce and watch for abort
           idle();
           if (ELAPSED(millis(), nxt)) {
             SERIAL_PROTOCOLLNPGM("\nMesh only partially populated.");
@@ -1011,7 +1011,7 @@
 
             #if ENABLED(NEWPANEL)
               lcd_quick_feedback();
-              while (ubl_lcd_clicked()) idle();
+              while (is_lcd_clicked()) idle();
               lcd_external_control = false;
             #endif
 
@@ -1528,7 +1528,7 @@
             do_blocking_move_to_z(h_offset + new_z); // Move the nozzle as the point is edited
           #endif
           idle();
-        } while (!ubl_lcd_clicked());
+        } while (!is_lcd_clicked());
 
         if (!lcd_map_control) lcd_return_to_status();
 
@@ -1537,18 +1537,18 @@
         // Let's work on specifying a proper API for the LCD ASAP, OK?
         lcd_external_control = true;
 
-        // this sequence to detect an ubl_lcd_clicked() debounce it and leave if it is
+        // this sequence to detect an is_lcd_clicked() debounce it and leave if it is
         // a Press and Hold is repeated in a lot of places (including G26_Mesh_Validation.cpp).   This
         // should be redone and compressed.
         const millis_t nxt = millis() + 1500UL;
-        while (ubl_lcd_clicked()) { // debounce and watch for abort
+        while (is_lcd_clicked()) { // debounce and watch for abort
           idle();
           if (ELAPSED(millis(), nxt)) {
             lcd_return_to_status();
             do_blocking_move_to_z(Z_CLEARANCE_BETWEEN_PROBES);
             LCD_MESSAGEPGM(MSG_EDITING_STOPPED);
 
-            while (ubl_lcd_clicked()) idle();
+            while (is_lcd_clicked()) idle();
 
             goto FINE_TUNE_EXIT;
           }
diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp
index ed03be7ecc0..f16796be2a1 100644
--- a/Marlin/ultralcd.cpp
+++ b/Marlin/ultralcd.cpp
@@ -5091,17 +5091,18 @@ void lcd_reset_alert_level() { lcd_status_message_level = 0; }
     bool lcd_detected() { return true; }
   #endif
 
-  #if ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(G26_MESH_VALIDATION)
-    void chirp_at_user() {
+  #if ENABLED(G26_MESH_VALIDATION)
+    void lcd_chirp() {
       #if ENABLED(LCD_USE_I2C_BUZZER)
         lcd.buzz(LCD_FEEDBACK_FREQUENCY_DURATION_MS, LCD_FEEDBACK_FREQUENCY_HZ);
       #elif PIN_EXISTS(BEEPER)
         buzzer.tone(LCD_FEEDBACK_FREQUENCY_DURATION_MS, LCD_FEEDBACK_FREQUENCY_HZ);
       #endif
     }
+  #endif
 
-    bool ubl_lcd_clicked() { return LCD_CLICKED; }
-
+  #if ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(G26_MESH_VALIDATION)
+    bool is_lcd_clicked() { return LCD_CLICKED; }
   #endif
 
 #endif // ULTIPANEL
diff --git a/Marlin/ultralcd.h b/Marlin/ultralcd.h
index 3281b5e5a78..69a536a8fc7 100644
--- a/Marlin/ultralcd.h
+++ b/Marlin/ultralcd.h
@@ -29,6 +29,9 @@
 
   #if ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(G26_MESH_VALIDATION)
     extern bool lcd_external_control;
+    #if ENABLED(G26_MESH_VALIDATION)
+      void lcd_chirp();
+    #endif
   #endif
 
   #define BUTTON_EXISTS(BN) (defined(BTN_## BN) && BTN_## BN >= 0)
@@ -171,6 +174,10 @@
     #define LCD_CLICKED false
   #endif
 
+  #if ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(G26_MESH_VALIDATION)
+    bool is_lcd_clicked();
+  #endif
+
   #if ENABLED(LCD_SET_PROGRESS_MANUALLY) && (ENABLED(LCD_PROGRESS_BAR) || ENABLED(DOGLCD))
     extern uint8_t progress_bar_percent;
   #endif