|  |  |  | @ -111,9 +111,6 @@ static void lcd_status_screen(); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   #if ENABLED(MANUAL_BED_LEVELING) | 
			
		
	
		
			
				
					|  |  |  |  |     #include "mesh_bed_leveling.h" | 
			
		
	
		
			
				
					|  |  |  |  |     static void _lcd_level_bed(); | 
			
		
	
		
			
				
					|  |  |  |  |     static void _lcd_level_bed_homing(); | 
			
		
	
		
			
				
					|  |  |  |  |     static void lcd_level_bed(); | 
			
		
	
		
			
				
					|  |  |  |  |   #endif | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   /* Different types of actions that can be used in menu items. */ | 
			
		
	
	
		
			
				
					|  |  |  | @ -464,6 +461,15 @@ static void lcd_status_screen() { | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | #if ENABLED(ULTIPANEL) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | inline void line_to_current(AxisEnum axis) { | 
			
		
	
		
			
				
					|  |  |  |  |   #if ENABLED(DELTA) | 
			
		
	
		
			
				
					|  |  |  |  |     calculate_delta(current_position); | 
			
		
	
		
			
				
					|  |  |  |  |     plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], current_position[E_AXIS], manual_feedrate[axis]/60, active_extruder); | 
			
		
	
		
			
				
					|  |  |  |  |   #else | 
			
		
	
		
			
				
					|  |  |  |  |     plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], manual_feedrate[axis]/60, active_extruder); | 
			
		
	
		
			
				
					|  |  |  |  |   #endif | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | #if ENABLED(SDSUPPORT) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   static void lcd_sdcard_pause() { card.pauseSDPrint(); } | 
			
		
	
	
		
			
				
					|  |  |  | @ -852,6 +858,147 @@ void lcd_cooldown() { | 
			
		
	
		
			
				
					|  |  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | #endif | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | #if ENABLED(MANUAL_BED_LEVELING) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   /**
 | 
			
		
	
		
			
				
					|  |  |  |  |    * | 
			
		
	
		
			
				
					|  |  |  |  |    * "Prepare" > "Bed Leveling" handlers | 
			
		
	
		
			
				
					|  |  |  |  |    * | 
			
		
	
		
			
				
					|  |  |  |  |    */ | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   static int _lcd_level_bed_position; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   /**
 | 
			
		
	
		
			
				
					|  |  |  |  |    * MBL Wait for controller movement and clicks: | 
			
		
	
		
			
				
					|  |  |  |  |    *   - Movement adjusts the Z axis | 
			
		
	
		
			
				
					|  |  |  |  |    *   - Click saves the Z and goes to the next mesh point | 
			
		
	
		
			
				
					|  |  |  |  |    */ | 
			
		
	
		
			
				
					|  |  |  |  |   static void _lcd_level_bed_procedure() { | 
			
		
	
		
			
				
					|  |  |  |  |     static bool mbl_wait_for_move = false; | 
			
		
	
		
			
				
					|  |  |  |  |     // Menu handlers may be called in a re-entrant fashion
 | 
			
		
	
		
			
				
					|  |  |  |  |     // if they call st_synchronize or plan_buffer_line. So
 | 
			
		
	
		
			
				
					|  |  |  |  |     // while waiting for a move we just ignore new input.
 | 
			
		
	
		
			
				
					|  |  |  |  |     if (mbl_wait_for_move) { | 
			
		
	
		
			
				
					|  |  |  |  |       lcdDrawUpdate = LCD_DRAW_UPDATE_CALL_NO_REDRAW; | 
			
		
	
		
			
				
					|  |  |  |  |       return; | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     ENCODER_DIRECTION_NORMAL(); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     // Encoder wheel adjusts the Z position
 | 
			
		
	
		
			
				
					|  |  |  |  |     if (encoderPosition != 0 && movesplanned() <= 3) { | 
			
		
	
		
			
				
					|  |  |  |  |       refresh_cmd_timeout(); | 
			
		
	
		
			
				
					|  |  |  |  |       current_position[Z_AXIS] += float((int)encoderPosition) * (MBL_Z_STEP); | 
			
		
	
		
			
				
					|  |  |  |  |       if (min_software_endstops) NOLESS(current_position[Z_AXIS], Z_MIN_POS); | 
			
		
	
		
			
				
					|  |  |  |  |       if (max_software_endstops) NOMORE(current_position[Z_AXIS], Z_MAX_POS); | 
			
		
	
		
			
				
					|  |  |  |  |       encoderPosition = 0; | 
			
		
	
		
			
				
					|  |  |  |  |       line_to_current(Z_AXIS); | 
			
		
	
		
			
				
					|  |  |  |  |       lcdDrawUpdate = LCD_DRAW_UPDATE_CALL_NO_REDRAW; | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     // Update on first display, then only on updates to Z position
 | 
			
		
	
		
			
				
					|  |  |  |  |     if (lcdDrawUpdate) { | 
			
		
	
		
			
				
					|  |  |  |  |       float v = current_position[Z_AXIS] - MESH_HOME_SEARCH_Z; | 
			
		
	
		
			
				
					|  |  |  |  |       lcd_implementation_drawedit(PSTR(MSG_MOVE_Z), ftostr43(v + (v < 0 ? -0.0001 : 0.0001), '+')); | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     // We want subsequent calls, but don't force redraw
 | 
			
		
	
		
			
				
					|  |  |  |  |     // Set here so it can be overridden by lcd_return_to_status below
 | 
			
		
	
		
			
				
					|  |  |  |  |     lcdDrawUpdate = LCD_DRAW_UPDATE_CALL_NO_REDRAW; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     // Click sets the current Z and moves to the next position
 | 
			
		
	
		
			
				
					|  |  |  |  |     static bool debounce_click = false; | 
			
		
	
		
			
				
					|  |  |  |  |     if (LCD_CLICKED) { | 
			
		
	
		
			
				
					|  |  |  |  |       if (!debounce_click) { | 
			
		
	
		
			
				
					|  |  |  |  |         debounce_click = true; // ignore multiple "clicks" in a row
 | 
			
		
	
		
			
				
					|  |  |  |  |         int ix = _lcd_level_bed_position % (MESH_NUM_X_POINTS), | 
			
		
	
		
			
				
					|  |  |  |  |             iy = _lcd_level_bed_position / (MESH_NUM_X_POINTS); | 
			
		
	
		
			
				
					|  |  |  |  |         if (iy & 1) ix = (MESH_NUM_X_POINTS - 1) - ix; // Zig zag
 | 
			
		
	
		
			
				
					|  |  |  |  |         mbl.set_z(ix, iy, current_position[Z_AXIS]); | 
			
		
	
		
			
				
					|  |  |  |  |         _lcd_level_bed_position++; | 
			
		
	
		
			
				
					|  |  |  |  |         if (_lcd_level_bed_position == (MESH_NUM_X_POINTS) * (MESH_NUM_Y_POINTS)) { | 
			
		
	
		
			
				
					|  |  |  |  |           current_position[Z_AXIS] = MESH_HOME_SEARCH_Z; | 
			
		
	
		
			
				
					|  |  |  |  |           mbl_wait_for_move = true; | 
			
		
	
		
			
				
					|  |  |  |  |           line_to_current(Z_AXIS); | 
			
		
	
		
			
				
					|  |  |  |  |           st_synchronize(); | 
			
		
	
		
			
				
					|  |  |  |  |           mbl.active = 1; | 
			
		
	
		
			
				
					|  |  |  |  |           enqueue_and_echo_commands_P(PSTR("G28")); | 
			
		
	
		
			
				
					|  |  |  |  |           mbl_wait_for_move = false; | 
			
		
	
		
			
				
					|  |  |  |  |           lcd_return_to_status(); | 
			
		
	
		
			
				
					|  |  |  |  |           #if ENABLED(NEWPANEL) | 
			
		
	
		
			
				
					|  |  |  |  |             lcd_quick_feedback(); | 
			
		
	
		
			
				
					|  |  |  |  |           #endif | 
			
		
	
		
			
				
					|  |  |  |  |           LCD_ALERTMESSAGEPGM(MSG_LEVEL_BED_DONE); | 
			
		
	
		
			
				
					|  |  |  |  |           #if HAS_BUZZER | 
			
		
	
		
			
				
					|  |  |  |  |             buzz(200, 659); | 
			
		
	
		
			
				
					|  |  |  |  |             buzz(200, 698); | 
			
		
	
		
			
				
					|  |  |  |  |           #endif | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |         else { | 
			
		
	
		
			
				
					|  |  |  |  |           current_position[Z_AXIS] = MESH_HOME_SEARCH_Z; | 
			
		
	
		
			
				
					|  |  |  |  |           line_to_current(Z_AXIS); | 
			
		
	
		
			
				
					|  |  |  |  |           ix = _lcd_level_bed_position % (MESH_NUM_X_POINTS); | 
			
		
	
		
			
				
					|  |  |  |  |           iy = _lcd_level_bed_position / (MESH_NUM_X_POINTS); | 
			
		
	
		
			
				
					|  |  |  |  |           if (iy & 1) ix = (MESH_NUM_X_POINTS - 1) - ix; // Zig zag
 | 
			
		
	
		
			
				
					|  |  |  |  |           current_position[X_AXIS] = mbl.get_x(ix); | 
			
		
	
		
			
				
					|  |  |  |  |           current_position[Y_AXIS] = mbl.get_y(iy); | 
			
		
	
		
			
				
					|  |  |  |  |           line_to_current(manual_feedrate[X_AXIS] <= manual_feedrate[Y_AXIS] ? X_AXIS : Y_AXIS); | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |       } | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  |     else { | 
			
		
	
		
			
				
					|  |  |  |  |       debounce_click = false; | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   static void _lcd_level_bed_homing_done() { | 
			
		
	
		
			
				
					|  |  |  |  |     if (lcdDrawUpdate) lcd_implementation_drawedit(PSTR(MSG_LEVEL_BED_WAITING), NULL); | 
			
		
	
		
			
				
					|  |  |  |  |     lcdDrawUpdate = LCD_DRAW_UPDATE_CALL_NO_REDRAW; | 
			
		
	
		
			
				
					|  |  |  |  |     if (LCD_CLICKED) { | 
			
		
	
		
			
				
					|  |  |  |  |       current_position[Z_AXIS] = MESH_HOME_SEARCH_Z; | 
			
		
	
		
			
				
					|  |  |  |  |       plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); | 
			
		
	
		
			
				
					|  |  |  |  |       current_position[X_AXIS] = MESH_MIN_X; | 
			
		
	
		
			
				
					|  |  |  |  |       current_position[Y_AXIS] = MESH_MIN_Y; | 
			
		
	
		
			
				
					|  |  |  |  |       line_to_current(manual_feedrate[X_AXIS] <= manual_feedrate[Y_AXIS] ? X_AXIS : Y_AXIS); | 
			
		
	
		
			
				
					|  |  |  |  |       _lcd_level_bed_position = 0; | 
			
		
	
		
			
				
					|  |  |  |  |       lcd_goto_menu(_lcd_level_bed_procedure, true); | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   /**
 | 
			
		
	
		
			
				
					|  |  |  |  |    * MBL Move to mesh starting point | 
			
		
	
		
			
				
					|  |  |  |  |    */ | 
			
		
	
		
			
				
					|  |  |  |  |   static void _lcd_level_bed_homing() { | 
			
		
	
		
			
				
					|  |  |  |  |     if (lcdDrawUpdate) lcd_implementation_drawedit(PSTR(MSG_LEVEL_BED_HOMING), NULL); | 
			
		
	
		
			
				
					|  |  |  |  |     lcdDrawUpdate = LCD_DRAW_UPDATE_CALL_NO_REDRAW; | 
			
		
	
		
			
				
					|  |  |  |  |     if (axis_known_position[X_AXIS] && axis_known_position[Y_AXIS] && axis_known_position[Z_AXIS]) | 
			
		
	
		
			
				
					|  |  |  |  |       lcd_goto_menu(_lcd_level_bed_homing_done); | 
			
		
	
		
			
				
					|  |  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   /**
 | 
			
		
	
		
			
				
					|  |  |  |  |    * MBL Continue Bed Leveling... | 
			
		
	
		
			
				
					|  |  |  |  |    */ | 
			
		
	
		
			
				
					|  |  |  |  |   static void _lcd_level_bed_continue() { | 
			
		
	
		
			
				
					|  |  |  |  |     defer_return_to_status = true; | 
			
		
	
		
			
				
					|  |  |  |  |     axis_known_position[X_AXIS] = axis_known_position[Y_AXIS] = axis_known_position[Z_AXIS] = false; | 
			
		
	
		
			
				
					|  |  |  |  |     mbl.reset(); | 
			
		
	
		
			
				
					|  |  |  |  |     enqueue_and_echo_commands_P(PSTR("G28")); | 
			
		
	
		
			
				
					|  |  |  |  |     lcd_goto_menu(_lcd_level_bed_homing, true); | 
			
		
	
		
			
				
					|  |  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   /**
 | 
			
		
	
		
			
				
					|  |  |  |  |    * MBL entry-point | 
			
		
	
		
			
				
					|  |  |  |  |    */ | 
			
		
	
		
			
				
					|  |  |  |  |   static void lcd_level_bed() { | 
			
		
	
		
			
				
					|  |  |  |  |     START_MENU(); | 
			
		
	
		
			
				
					|  |  |  |  |     MENU_ITEM(back, MSG_LEVEL_BED_CANCEL); | 
			
		
	
		
			
				
					|  |  |  |  |     MENU_ITEM(submenu, MSG_LEVEL_BED, _lcd_level_bed_continue); | 
			
		
	
		
			
				
					|  |  |  |  |     END_MENU(); | 
			
		
	
		
			
				
					|  |  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | #endif  // MANUAL_BED_LEVELING
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | /**
 | 
			
		
	
		
			
				
					|  |  |  |  |  * | 
			
		
	
		
			
				
					|  |  |  |  |  * "Prepare" submenu | 
			
		
	
	
		
			
				
					|  |  |  | @ -951,15 +1098,6 @@ static void lcd_prepare_menu() { | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | #endif // DELTA_CALIBRATION_MENU
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | inline void line_to_current(AxisEnum axis) { | 
			
		
	
		
			
				
					|  |  |  |  |   #if ENABLED(DELTA) | 
			
		
	
		
			
				
					|  |  |  |  |     calculate_delta(current_position); | 
			
		
	
		
			
				
					|  |  |  |  |     plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], current_position[E_AXIS], manual_feedrate[axis]/60, active_extruder); | 
			
		
	
		
			
				
					|  |  |  |  |   #else | 
			
		
	
		
			
				
					|  |  |  |  |     plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], manual_feedrate[axis]/60, active_extruder); | 
			
		
	
		
			
				
					|  |  |  |  |   #endif | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | /**
 | 
			
		
	
		
			
				
					|  |  |  |  |  * | 
			
		
	
		
			
				
					|  |  |  |  |  * "Prepare" > "Move Axis" submenu | 
			
		
	
	
		
			
				
					|  |  |  | @ -2495,138 +2633,4 @@ char* ftostr52(const float& x) { | 
			
		
	
		
			
				
					|  |  |  |  |   return conv; | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | #if ENABLED(MANUAL_BED_LEVELING) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   static int _lcd_level_bed_position; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   /**
 | 
			
		
	
		
			
				
					|  |  |  |  |    * MBL Wait for controller movement and clicks: | 
			
		
	
		
			
				
					|  |  |  |  |    *   - Movement adjusts the Z axis | 
			
		
	
		
			
				
					|  |  |  |  |    *   - Click saves the Z and goes to the next mesh point | 
			
		
	
		
			
				
					|  |  |  |  |    */ | 
			
		
	
		
			
				
					|  |  |  |  |   static void _lcd_level_bed_procedure() { | 
			
		
	
		
			
				
					|  |  |  |  |     static bool mbl_wait_for_move = false; | 
			
		
	
		
			
				
					|  |  |  |  |     // Menu handlers may be called in a re-entrant fashion
 | 
			
		
	
		
			
				
					|  |  |  |  |     // if they call st_synchronize or plan_buffer_line. So
 | 
			
		
	
		
			
				
					|  |  |  |  |     // while waiting for a move we just ignore new input.
 | 
			
		
	
		
			
				
					|  |  |  |  |     if (mbl_wait_for_move) { | 
			
		
	
		
			
				
					|  |  |  |  |       lcdDrawUpdate = LCD_DRAW_UPDATE_CALL_NO_REDRAW; | 
			
		
	
		
			
				
					|  |  |  |  |       return; | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     ENCODER_DIRECTION_NORMAL(); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     // Encoder wheel adjusts the Z position
 | 
			
		
	
		
			
				
					|  |  |  |  |     if (encoderPosition != 0 && movesplanned() <= 3) { | 
			
		
	
		
			
				
					|  |  |  |  |       refresh_cmd_timeout(); | 
			
		
	
		
			
				
					|  |  |  |  |       current_position[Z_AXIS] += float((int)encoderPosition) * (MBL_Z_STEP); | 
			
		
	
		
			
				
					|  |  |  |  |       if (min_software_endstops) NOLESS(current_position[Z_AXIS], Z_MIN_POS); | 
			
		
	
		
			
				
					|  |  |  |  |       if (max_software_endstops) NOMORE(current_position[Z_AXIS], Z_MAX_POS); | 
			
		
	
		
			
				
					|  |  |  |  |       encoderPosition = 0; | 
			
		
	
		
			
				
					|  |  |  |  |       line_to_current(Z_AXIS); | 
			
		
	
		
			
				
					|  |  |  |  |       lcdDrawUpdate = LCD_DRAW_UPDATE_CALL_NO_REDRAW; | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     // Update on first display, then only on updates to Z position
 | 
			
		
	
		
			
				
					|  |  |  |  |     if (lcdDrawUpdate) { | 
			
		
	
		
			
				
					|  |  |  |  |       float v = current_position[Z_AXIS] - MESH_HOME_SEARCH_Z; | 
			
		
	
		
			
				
					|  |  |  |  |       lcd_implementation_drawedit(PSTR(MSG_MOVE_Z), ftostr43(v + (v < 0 ? -0.0001 : 0.0001), '+')); | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     // We want subsequent calls, but don't force redraw
 | 
			
		
	
		
			
				
					|  |  |  |  |     // Set here so it can be overridden by lcd_return_to_status below
 | 
			
		
	
		
			
				
					|  |  |  |  |     lcdDrawUpdate = LCD_DRAW_UPDATE_CALL_NO_REDRAW; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     // Click sets the current Z and moves to the next position
 | 
			
		
	
		
			
				
					|  |  |  |  |     static bool debounce_click = false; | 
			
		
	
		
			
				
					|  |  |  |  |     if (LCD_CLICKED) { | 
			
		
	
		
			
				
					|  |  |  |  |       if (!debounce_click) { | 
			
		
	
		
			
				
					|  |  |  |  |         debounce_click = true; // ignore multiple "clicks" in a row
 | 
			
		
	
		
			
				
					|  |  |  |  |         int ix = _lcd_level_bed_position % (MESH_NUM_X_POINTS), | 
			
		
	
		
			
				
					|  |  |  |  |             iy = _lcd_level_bed_position / (MESH_NUM_X_POINTS); | 
			
		
	
		
			
				
					|  |  |  |  |         if (iy & 1) ix = (MESH_NUM_X_POINTS - 1) - ix; // Zig zag
 | 
			
		
	
		
			
				
					|  |  |  |  |         mbl.set_z(ix, iy, current_position[Z_AXIS]); | 
			
		
	
		
			
				
					|  |  |  |  |         _lcd_level_bed_position++; | 
			
		
	
		
			
				
					|  |  |  |  |         if (_lcd_level_bed_position == (MESH_NUM_X_POINTS) * (MESH_NUM_Y_POINTS)) { | 
			
		
	
		
			
				
					|  |  |  |  |           current_position[Z_AXIS] = MESH_HOME_SEARCH_Z; | 
			
		
	
		
			
				
					|  |  |  |  |           mbl_wait_for_move = true; | 
			
		
	
		
			
				
					|  |  |  |  |           line_to_current(Z_AXIS); | 
			
		
	
		
			
				
					|  |  |  |  |           st_synchronize(); | 
			
		
	
		
			
				
					|  |  |  |  |           mbl.active = 1; | 
			
		
	
		
			
				
					|  |  |  |  |           enqueue_and_echo_commands_P(PSTR("G28")); | 
			
		
	
		
			
				
					|  |  |  |  |           mbl_wait_for_move = false; | 
			
		
	
		
			
				
					|  |  |  |  |           lcd_return_to_status(); | 
			
		
	
		
			
				
					|  |  |  |  |           #if ENABLED(NEWPANEL) | 
			
		
	
		
			
				
					|  |  |  |  |             lcd_quick_feedback(); | 
			
		
	
		
			
				
					|  |  |  |  |           #endif | 
			
		
	
		
			
				
					|  |  |  |  |           LCD_ALERTMESSAGEPGM(MSG_LEVEL_BED_DONE); | 
			
		
	
		
			
				
					|  |  |  |  |           #if HAS_BUZZER | 
			
		
	
		
			
				
					|  |  |  |  |             buzz(200, 659); | 
			
		
	
		
			
				
					|  |  |  |  |             buzz(200, 698); | 
			
		
	
		
			
				
					|  |  |  |  |           #endif | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |         else { | 
			
		
	
		
			
				
					|  |  |  |  |           current_position[Z_AXIS] = MESH_HOME_SEARCH_Z; | 
			
		
	
		
			
				
					|  |  |  |  |           line_to_current(Z_AXIS); | 
			
		
	
		
			
				
					|  |  |  |  |           ix = _lcd_level_bed_position % (MESH_NUM_X_POINTS); | 
			
		
	
		
			
				
					|  |  |  |  |           iy = _lcd_level_bed_position / (MESH_NUM_X_POINTS); | 
			
		
	
		
			
				
					|  |  |  |  |           if (iy & 1) ix = (MESH_NUM_X_POINTS - 1) - ix; // Zig zag
 | 
			
		
	
		
			
				
					|  |  |  |  |           current_position[X_AXIS] = mbl.get_x(ix); | 
			
		
	
		
			
				
					|  |  |  |  |           current_position[Y_AXIS] = mbl.get_y(iy); | 
			
		
	
		
			
				
					|  |  |  |  |           line_to_current(manual_feedrate[X_AXIS] <= manual_feedrate[Y_AXIS] ? X_AXIS : Y_AXIS); | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |       } | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  |     else { | 
			
		
	
		
			
				
					|  |  |  |  |       debounce_click = false; | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   static void _lcd_level_bed_homing_done() { | 
			
		
	
		
			
				
					|  |  |  |  |     if (lcdDrawUpdate) lcd_implementation_drawedit(PSTR(MSG_LEVEL_BED_WAITING), NULL); | 
			
		
	
		
			
				
					|  |  |  |  |     lcdDrawUpdate = LCD_DRAW_UPDATE_CALL_NO_REDRAW; | 
			
		
	
		
			
				
					|  |  |  |  |     if (LCD_CLICKED) { | 
			
		
	
		
			
				
					|  |  |  |  |       current_position[Z_AXIS] = MESH_HOME_SEARCH_Z; | 
			
		
	
		
			
				
					|  |  |  |  |       plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); | 
			
		
	
		
			
				
					|  |  |  |  |       current_position[X_AXIS] = MESH_MIN_X; | 
			
		
	
		
			
				
					|  |  |  |  |       current_position[Y_AXIS] = MESH_MIN_Y; | 
			
		
	
		
			
				
					|  |  |  |  |       line_to_current(manual_feedrate[X_AXIS] <= manual_feedrate[Y_AXIS] ? X_AXIS : Y_AXIS); | 
			
		
	
		
			
				
					|  |  |  |  |       _lcd_level_bed_position = 0; | 
			
		
	
		
			
				
					|  |  |  |  |       lcd_goto_menu(_lcd_level_bed_procedure, true); | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   /**
 | 
			
		
	
		
			
				
					|  |  |  |  |    * MBL Move to mesh starting point | 
			
		
	
		
			
				
					|  |  |  |  |    */ | 
			
		
	
		
			
				
					|  |  |  |  |   static void _lcd_level_bed_homing() { | 
			
		
	
		
			
				
					|  |  |  |  |     if (lcdDrawUpdate) lcd_implementation_drawedit(PSTR(MSG_LEVEL_BED_HOMING), NULL); | 
			
		
	
		
			
				
					|  |  |  |  |     lcdDrawUpdate = LCD_DRAW_UPDATE_CALL_NO_REDRAW; | 
			
		
	
		
			
				
					|  |  |  |  |     if (axis_known_position[X_AXIS] && axis_known_position[Y_AXIS] && axis_known_position[Z_AXIS]) | 
			
		
	
		
			
				
					|  |  |  |  |       lcd_goto_menu(_lcd_level_bed_homing_done); | 
			
		
	
		
			
				
					|  |  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   /**
 | 
			
		
	
		
			
				
					|  |  |  |  |    * MBL Continue Bed Leveling... | 
			
		
	
		
			
				
					|  |  |  |  |    */ | 
			
		
	
		
			
				
					|  |  |  |  |   static void _lcd_level_bed_continue() { | 
			
		
	
		
			
				
					|  |  |  |  |     defer_return_to_status = true; | 
			
		
	
		
			
				
					|  |  |  |  |     axis_known_position[X_AXIS] = axis_known_position[Y_AXIS] = axis_known_position[Z_AXIS] = false; | 
			
		
	
		
			
				
					|  |  |  |  |     mbl.reset(); | 
			
		
	
		
			
				
					|  |  |  |  |     enqueue_and_echo_commands_P(PSTR("G28")); | 
			
		
	
		
			
				
					|  |  |  |  |     lcd_goto_menu(_lcd_level_bed_homing, true); | 
			
		
	
		
			
				
					|  |  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   /**
 | 
			
		
	
		
			
				
					|  |  |  |  |    * MBL entry-point | 
			
		
	
		
			
				
					|  |  |  |  |    */ | 
			
		
	
		
			
				
					|  |  |  |  |   static void lcd_level_bed() { | 
			
		
	
		
			
				
					|  |  |  |  |     START_MENU(); | 
			
		
	
		
			
				
					|  |  |  |  |     MENU_ITEM(back, MSG_LEVEL_BED_CANCEL); | 
			
		
	
		
			
				
					|  |  |  |  |     MENU_ITEM(submenu, MSG_LEVEL_BED, _lcd_level_bed_continue); | 
			
		
	
		
			
				
					|  |  |  |  |     END_MENU(); | 
			
		
	
		
			
				
					|  |  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | #endif  // MANUAL_BED_LEVELING
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | #endif // ULTRA_LCD
 | 
			
		
	
	
		
			
				
					|  |  |  | 
 |