@ -158,7 +158,7 @@
 
			
		
	
		
			
				
					   *                     only  done  between  probe  points .  You  will  need  to  press  and  hold  the  switch  until  the 
 
			
		
	
		
			
				
					   *                     Phase  1  command  can  detect  it . ) 
 
			
		
	
		
			
				
					   * 
 
			
		
	
		
			
				
					   *    P2     Phase  2     Probe  areas  of  the  Mesh  that  can  no  t be  automatically  handled .  Phase  2  respects  an  H 
 
			
		
	
		
			
				
					   *    P2     Phase  2     Probe  areas  of  the  Mesh  that  can ' be  automatically  handled .  Phase  2  respects  an  H 
 
			
		
	
		
			
				
					   *                     parameter  to  control  the  height  between  Mesh  points .  The  default  height  for  movement 
 
			
		
	
		
			
				
					   *                     between  Mesh  points  is  5 mm .  A  smaller  number  can  be  used  to  make  this  part  of  the 
 
			
		
	
		
			
				
					   *                     calibration  less  time  consuming .  You  will  be  running  the  nozzle  down  until  it  just  barely 
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -303,25 +303,17 @@
 
			
		
	
		
			
				
					  volatile  int8_t  ubl_encoderDiff  =  0 ;  // Volatile because it's changed by Temperature ISR button update
 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  // The simple parameter flags and values are 'static' so parameter parsing can be in a support routine.
 
 
			
		
	
		
			
				
					  static  int  g29_verbose_level  =  0  ,  phase_value  =  - 1 ,  repetition_cnt  =  1  , 
 
			
		
	
		
			
				
					             storage_slot  =  0 ,  map_type  =  0 ,  test_pattern  =  0 ,  unlevel_value  =  - 1 ;  
 
			
		
	
		
			
				
					  static  bool  repeat_flag  =  UBL_OK  ,  c_flag  =  false  ,  x_flag  =  UBL_OK  ,  y_flag  =  UBL_OK ,  statistics_flag  =  UBL_OK ,  business_card_mode  =  false  ; 
 
			
		
	
		
			
				
					  static  float  x_pos  =  0.0  ,  y_pos  =  0.0 ,  height_value  =  5.0  ,  measured_z ,  card_thickness  =  0.0 ,  =  0.0 ; 
 
			
		
	
		
			
				
					  static  int  g29_verbose_level ,  phase_value  =  - 1 ,  repetition_cnt , 
 
			
		
	
		
			
				
					             storage_slot  =  0 ,  map_type ;  //unlevel_value = -1;
 
 
			
		
	
		
			
				
					  static  bool  repeat_flag ,  c_flag ,  x_flag ,  y_flag ; 
 
			
		
	
		
			
				
					  static  float  x_pos ,  y_pos ,  measured_z ,  card_thickness  =  0.0 ,  ubl_ constant =  0.0 ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  # if ENABLED(ULTRA_LCD) 
 
			
		
	
		
			
				
					    void  lcd_setstatus ( const  char *  message ,  bool  persist ) ; 
 
			
		
	
		
			
				
					  # endif 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  void  gcode_G29 ( )  { 
 
			
		
	
		
			
				
					    float  Z1 ,  Z2 ,  Z3 ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    g29_verbose_level  =  0 ;   // These may change, but let's get some reasonable values into them.
 
 
			
		
	
		
			
				
					    repeat_flag        =  UBL_OK ; 
 
			
		
	
		
			
				
					    repetition_cnt     =  1 ; 
 
			
		
	
		
			
				
					    c_flag             =  false ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    SERIAL_PROTOCOLLNPAIR ( " ubl_eeprom_start= " ,  ubl_eeprom_start ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    if  ( ubl_eeprom_start  <  0 )  { 
 
			
		
	
		
			
				
					      SERIAL_PROTOCOLLNPGM ( " ?You need to enable your EEPROM and initialize it " ) ; 
 
			
		
	
		
			
				
					      SERIAL_PROTOCOLLNPGM ( " with M502, M500, M501 in that order. \n " ) ; 
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -350,53 +342,46 @@
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    if  ( code_seen ( ' Q ' ) )  { 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      if  ( code_has_value ( ) )  test_pattern  =  code_value_int ( ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      if  ( test_pattern  <  0  | |  test_pattern  >  4 )  { 
 
			
		
	
		
			
				
					        SERIAL_PROTOCOLLNPGM ( " Invalid test_pattern value. (0-4) \n " ) ; 
 
			
		
	
		
			
				
					      const  int  test_pattern  =  code_has_value ( )  ?  code_value_int ( )  :  - 1 ; 
 
			
		
	
		
			
				
					      if  ( test_pattern  <  0  | |  test_pattern  >  2 )  { 
 
			
		
	
		
			
				
					        SERIAL_PROTOCOLLNPGM ( " Invalid test_pattern value. (0-2) \n " ) ; 
 
			
		
	
		
			
				
					        return ; 
 
			
		
	
		
			
				
					      } 
 
			
		
	
		
			
				
					      SERIAL_PROTOCOLLNPGM ( " Loading test_pattern values. \n " ) ; 
 
			
		
	
		
			
				
					      switch  ( test_pattern )  { 
 
			
		
	
		
			
				
					        case  0 : 
 
			
		
	
		
			
				
					          for  ( uint8_t  x  =  0 ;  x  <  UBL_MESH_NUM_X_POINTS ;  x + + )  {          // Create a bowl shape. This is  
 
			
		
	
		
			
				
					            for  ( uint8_t  y  =  0 ;  y  <  UBL_MESH_NUM_Y_POINTS ;  y + + )  {        // similar to what a user would see with  
 
			
		
	
		
			
				
					              Z =  0.5  *  ( UBL_MESH_NUM_X_POINTS )  -  x ;                   // a poorly calibrated Delta.
  
 
			
		
	
		
			
				
					              Z =  0.5  *  ( UBL_MESH_NUM_Y_POINTS )  -  y ; 
 
			
		
	
		
			
				
					              z_values [ x ] [ y ]  + =  2.0  *  HYPOT ( Z1,  Z  2) ; 
 
			
		
	
		
			
				
					          for  ( uint8_t  x  =  0 ;  x  <  UBL_MESH_NUM_X_POINTS ;  x + + )  {    // Create a bowl shape - similar to 
 
			
		
	
		
			
				
					            for  ( uint8_t  y  =  0 ;  y  <  UBL_MESH_NUM_Y_POINTS ;  y + + )  {  // a poorly calibrated Delta. 
 
			
		
	
		
			
				
					              const  float  p =  0.5  *  ( UBL_MESH_NUM_X_POINTS )  -  x , 
 
			
		
	
		
			
				
					                          p  2 =  0.5  *  ( UBL_MESH_NUM_Y_POINTS )  -  y ; 
 
			
		
	
		
			
				
					              z_values [ x ] [ y ]  + =  2.0  *  HYPOT ( p1,  p  2) ; 
 
			
		
	
		
			
				
					            } 
 
			
		
	
		
			
				
					          } 
 
			
		
	
		
			
				
					        break ; 
 
			
		
	
		
			
				
					           break ; 
 
			
		
	
		
			
				
					        case  1 : 
 
			
		
	
		
			
				
					          for  ( uint8_t  x  =  0 ;  x  <  UBL_MESH_NUM_X_POINTS ;  x + + )  {   // Create a diagonal line several Mesh
 
 
			
		
	
		
			
				
					            z_values [ x ] [ x ]  + =  9.999 ;                              // cells thick that is raised
 
 
			
		
	
		
			
				
					            if  ( x  <  UBL_MESH_NUM_Y_POINTS  -  1 ) 
 
			
		
	
		
			
				
					              z_values [ x ] [ x  +  1 ]  + =  9.999 ;                        // We want the altered line several mesh points thick
 
 
			
		
	
		
			
				
					            if  ( x  >  0 ) 
 
			
		
	
		
			
				
					              z_values [ x ] [ x  -  1 ]  + =  9.999 ;                        // We want the altered line several mesh points thick
 
 
			
		
	
		
			
				
					          for  ( uint8_t  x  =  0 ;  x  <  UBL_MESH_NUM_X_POINTS ;  x + + )  {   // Create a diagonal line several Mesh cells thick that is raised
 
 
			
		
	
		
			
				
					            z_values [ x ] [ x ]  + =  9.999 ; 
 
			
		
	
		
			
				
					            z_values [ x ] [ x  +  ( x  <  UBL_MESH_NUM_Y_POINTS  -  1 )  ?  1  :  - 1 ]  + =  9.999 ;  // We want the altered line several mesh points thick
 
 
			
		
	
		
			
				
					          } 
 
			
		
	
		
			
				
					          break ; 
 
			
		
	
		
			
				
					        case  2 : 
 
			
		
	
		
			
				
					          // Allow the user to specify the height because 10mm is
 
 
			
		
	
		
			
				
					          // a little bit extreme in some cases.
 
 
			
		
	
		
			
				
					          // Allow the user to specify the height because 10mm is a little extreme in some cases.
 
 
			
		
	
		
			
				
					          for  ( uint8_t  x  =  ( UBL_MESH_NUM_X_POINTS )  /  3 ;  x  <  2  *  ( UBL_MESH_NUM_X_POINTS )  /  3 ;  x + + )    // Create a rectangular raised area in
 
 
			
		
	
		
			
				
					            for  ( uint8_t  y  =  ( UBL_MESH_NUM_Y_POINTS )  /  3 ;  y  <  2  *  ( UBL_MESH_NUM_Y_POINTS )  /  3 ;  y + + )  // the center of the bed
 
 
			
		
	
		
			
				
					              z_values [ x ] [ y ]  + =  code_seen ( ' C ' )  ?  constant  :  9.99 ; 
 
			
		
	
		
			
				
					          break ; 
 
			
		
	
		
			
				
					        case  3 : 
 
			
		
	
		
			
				
					              z_values [ x ] [ y ]  + =  code_seen ( ' C ' )  ?  ubl_constant  :  9.99 ; 
 
			
		
	
		
			
				
					          break ; 
 
			
		
	
		
			
				
					      } 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					/*
  
			
		
	
		
			
				
					     /*
  
			
		
	
		
			
				
					    if  ( code_seen ( ' U ' ) )  { 
 
			
		
	
		
			
				
					      unlevel_value  =  code_value_int ( ) ; 
 
			
		
	
		
			
				
					//      
			
		
	
		
			
				
					//      
			
		
	
		
			
				
					//      
			
		
	
		
			
				
					//      
			
		
	
		
			
				
					      //  if (unlevel_value < 0 || unlevel_value > 7) {
 
			
		
	
		
			
				
					      //    SERIAL_PROTOCOLLNPGM("Invalid Unlevel value. (0-4)\n");
 
			
		
	
		
			
				
					      //    return;
 
			
		
	
		
			
				
					      //  }
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					*/  
			
		
	
		
			
				
					    //*/
   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    if  ( code_seen ( ' P ' ) )  { 
 
			
		
	
		
			
				
					      phase_value  =  code_value_int ( ) ; 
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -430,9 +415,9 @@
 
			
		
	
		
			
				
					                            code_seen ( ' O ' )  | |  code_seen ( ' M ' ) ,  code_seen ( ' E ' ) ,  code_seen ( ' U ' ) ) ; 
 
			
		
	
		
			
				
					          break ; 
 
			
		
	
		
			
				
					        //
 
 
			
		
	
		
			
				
					        // Manually Probe Mesh in areas that can  no t be reached by the probe
 
			
		
	
		
			
				
					        // Manually Probe Mesh in areas that can ' t be reached by the probe
 
			
		
	
		
			
				
					        //
 
 
			
		
	
		
			
				
					        case  2 : 
 
			
		
	
		
			
				
					        case  2 :  {  
 
			
		
	
		
			
				
					          SERIAL_PROTOCOLLNPGM ( " Manually probing unreachable mesh locations. \n " ) ; 
 
			
		
	
		
			
				
					          do_blocking_move_to_z ( Z_CLEARANCE_BETWEEN_PROBES ) ; 
 
			
		
	
		
			
				
					          if  ( ! x_flag  & &  ! y_flag )  {       // use a good default location for the path
 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -451,32 +436,34 @@
 
			
		
	
		
			
				
					            y_pos  =  current_position [ Y_AXIS ] ; 
 
			
		
	
		
			
				
					          } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					          height _value  =  code_seen ( ' H ' )  & &  code_has_value ( )  ?  code_value_float ( )  :  Z_CLEARANCE_BETWEEN_PROBES ; 
 
			
		
	
		
			
				
					          const  float  height  =  code_seen ( ' H ' )  & &  code_has_value ( )  ?  code_value_float ( )  :  Z_CLEARANCE_BETWEEN_PROBES ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					          if  ( ( business_card_mode  =  code_seen ( ' B ' ) ) )  { 
 
			
		
	
		
			
				
					            card_thickness  =  code_has_value ( )  ?  code_value_float ( )  :  measure_business_card_thickness ( height _value ) ; 
 
			
		
	
		
			
				
					          if  ( code_seen ( ' B ' ) )  { 
 
			
		
	
		
			
				
					            card_thickness  =  code_has_value ( )  ?  code_value_float ( )  :  measure_business_card_thickness ( height ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					            if  ( fabs ( card_thickness )  >  1.5 )  { 
 
			
		
	
		
			
				
					              SERIAL_PROTOCOLLNPGM ( " ?Error in Business Card measur ment.\n " ) ; 
 
			
		
	
		
			
				
					              SERIAL_PROTOCOLLNPGM ( " ?Error in Business Card measur e ment.\n " ) ; 
 
			
		
	
		
			
				
					              return ; 
 
			
		
	
		
			
				
					            } 
 
			
		
	
		
			
				
					          } 
 
			
		
	
		
			
				
					          manually_probe_remaining_mesh ( x_pos ,  y_pos ,  height_value ,  card_thickness ,  code_seen ( ' O ' )  | |  code_seen ( ' M ' ) ) ; 
 
			
		
	
		
			
				
					          break ; 
 
			
		
	
		
			
				
					          manually_probe_remaining_mesh ( x_pos ,  y_pos ,  height ,  card_thickness ,  code_seen ( ' O ' )  | |  code_seen ( ' M ' ) ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        }  break ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        //
 
 
			
		
	
		
			
				
					        // Populate invalid Mesh areas with a constant
 
 
			
		
	
		
			
				
					        //
 
 
			
		
	
		
			
				
					        case  3 : 
 
			
		
	
		
			
				
					          height_value  =  0.0 ;  // Assume 0.0 until proven otherwise
 
 
			
		
	
		
			
				
					          if  ( code_seen ( ' C ' ) )  height_value  =  constant ; 
 
			
		
	
		
			
				
					        case  3 :  { 
 
			
		
	
		
			
				
					          const  float  height  =  code_seen ( ' C ' )  ?  ubl_constant  :  0.0 ; 
 
			
		
	
		
			
				
					          // If no repetition is specified, do the whole Mesh
 
 
			
		
	
		
			
				
					          if  ( ! repeat_flag )  repetition_cnt  =  9999 ; 
 
			
		
	
		
			
				
					          while  ( repetition_cnt - - )  { 
 
			
		
	
		
			
				
					            const  mesh_index_pair  location  =  find_closest_mesh_point_of_type ( INVALID ,  x_pos ,  y_pos ,  0 ,  NULL ,  false ) ;  // The '0' says we want to use the nozzle's position
 
 
			
		
	
		
			
				
					            if  ( location . x_index  <  0 )  break ;  // No more invalid Mesh Points to populate
 
 
			
		
	
		
			
				
					            z_values [ location . x_index ] [ location . y_index ]  =  height _value ; 
 
			
		
	
		
			
				
					            z_values [ location . x_index ] [ location . y_index ]  =  height ; 
 
			
		
	
		
			
				
					          } 
 
			
		
	
		
			
				
					          break ; 
 
			
		
	
		
			
				
					        }  break ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        //
 
 
			
		
	
		
			
				
					        // Fine Tune (Or Edit) the Mesh
 
 
			
		
	
		
			
				
					        //
 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -491,36 +478,56 @@
 
			
		
	
		
			
				
					          break ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        case  10 : 
 
			
		
	
		
			
				
					          // Debug code... Pay no attention to this stuff
 
 
			
		
	
		
			
				
					          // it can be removed soon.
 
 
			
		
	
		
			
				
					          // [DEBUG] Pay no attention to this stuff. It can be removed soon.
 
 
			
		
	
		
			
				
					          SERIAL_ECHO_START ; 
 
			
		
	
		
			
				
					          SERIAL_ECHOLNPGM ( " Checking G29 has control of LCD Panel: " ) ; 
 
			
		
	
		
			
				
					          wait_for_user  =  true ; 
 
			
		
	
		
			
				
					          KEEPALIVE_STATE ( PAUSED_FOR_USER ) ; 
 
			
		
	
		
			
				
					          ubl_has_control_of_lcd_panel + + ; 
 
			
		
	
		
			
				
					          while  ( ! ubl_lcd_clicked ( ) )  { 
 
			
		
	
		
			
				
					            safe_delay ( 250 ) ; 
 
			
		
	
		
			
				
					            SERIAL_ECHO ( ( int ) ubl_encoderDiff ) ; 
 
			
		
	
		
			
				
					            ubl_encoderDiff  =  0 ; 
 
			
		
	
		
			
				
					            SERIAL_EOL ; 
 
			
		
	
		
			
				
					            if  ( ubl_encoderDiff )  { 
 
			
		
	
		
			
				
					              SERIAL_ECHOLN ( ( int ) ubl_encoderDiff ) ; 
 
			
		
	
		
			
				
					              ubl_encoderDiff  =  0 ; 
 
			
		
	
		
			
				
					            } 
 
			
		
	
		
			
				
					          } 
 
			
		
	
		
			
				
					          SERIAL_ECHOLNPGM ( " G29 giving back control of LCD Panel. " ) ; 
 
			
		
	
		
			
				
					          ubl_has_control_of_lcd_panel  =  false ; 
 
			
		
	
		
			
				
					          KEEPALIVE_STATE ( IN_HANDLER ) ; 
 
			
		
	
		
			
				
					          break ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        case  11 : 
 
			
		
	
		
			
				
					          // [DEBUG] wait_for_user code. Pay no attention to this stuff. It can be removed soon.
 
 
			
		
	
		
			
				
					          SERIAL_ECHO_START ; 
 
			
		
	
		
			
				
					          SERIAL_ECHOLNPGM ( " Checking G29 has control of LCD Panel: " ) ; 
 
			
		
	
		
			
				
					          KEEPALIVE_STATE ( PAUSED_FOR_USER ) ; 
 
			
		
	
		
			
				
					          wait_for_user  =  true ; 
 
			
		
	
		
			
				
					          while  ( wait_for_user )  { 
 
			
		
	
		
			
				
					            safe_delay ( 250 ) ; 
 
			
		
	
		
			
				
					            if  ( ubl_encoderDiff )  { 
 
			
		
	
		
			
				
					              SERIAL_ECHOLN ( ( int ) ubl_encoderDiff ) ; 
 
			
		
	
		
			
				
					              ubl_encoderDiff  =  0 ; 
 
			
		
	
		
			
				
					            } 
 
			
		
	
		
			
				
					          } 
 
			
		
	
		
			
				
					          SERIAL_ECHOLNPGM ( " G29 giving back control of LCD Panel. " ) ; 
 
			
		
	
		
			
				
					          KEEPALIVE_STATE ( IN_HANDLER ) ; 
 
			
		
	
		
			
				
					          break ; 
 
			
		
	
		
			
				
					      } 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    if  ( code_seen ( ' T ' ) )  { 
 
			
		
	
		
			
				
					      Z1  =  probe_pt ( ubl_3_point_1_X ,  ubl_3_point_1_Y ,  false  /*Stow Flag*/ ,  g29_verbose_level )  +  zprobe_zoffset ; 
 
			
		
	
		
			
				
					      Z2  =  probe_pt ( ubl_3_point_2_X ,  ubl_3_point_2_Y ,  false  /*Stow Flag*/ ,  g29_verbose_level )  +  zprobe_zoffset ; 
 
			
		
	
		
			
				
					      Z3  =  probe_pt ( ubl_3_point_3_X ,  ubl_3_point_3_Y ,  true   /*Stow Flag*/ ,  g29_verbose_level )  +  zprobe_zoffset ; 
 
			
		
	
		
			
				
					      float  z =  probe_pt ( ubl_3_point_1_X ,  ubl_3_point_1_Y ,  false  /*Stow Flag*/ ,  g29_verbose_level )  +  zprobe_zoffset , 
 
			
		
	
		
			
				
					            z  2 =  probe_pt ( ubl_3_point_2_X ,  ubl_3_point_2_Y ,  false  /*Stow Flag*/ ,  g29_verbose_level )  +  zprobe_zoffset , 
 
			
		
	
		
			
				
					            z  3 =  probe_pt ( ubl_3_point_3_X ,  ubl_3_point_3_Y ,  true   /*Stow Flag*/ ,  g29_verbose_level )  +  zprobe_zoffset ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      //  We need to adjust Z1, Z2, Z3 by the Mesh Height at these points. Just because they are non-zero doesn't mean
 
 
			
		
	
		
			
				
					      //  We need to adjust  z1, z2, z 3 by the Mesh Height at these points. Just because they are non-zero doesn't mean
 
			
		
	
		
			
				
					      //  the Mesh is tilted!  (We need to compensate each probe point by what the Mesh says that location's height is)
 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      Z1  - =  ubl . get_z_correction ( ubl_3_point_1_X ,  ubl_3_point_1_Y ) ; 
 
			
		
	
		
			
				
					      Z2  - =  ubl . get_z_correction ( ubl_3_point_2_X ,  ubl_3_point_2_Y ) ; 
 
			
		
	
		
			
				
					      Z3  - =  ubl . get_z_correction ( ubl_3_point_3_X ,  ubl_3_point_3_Y ) ; 
 
			
		
	
		
			
				
					      z 1 - =  ubl . get_z_correction ( ubl_3_point_1_X ,  ubl_3_point_1_Y ) ; 
 
			
		
	
		
			
				
					      z 2 - =  ubl . get_z_correction ( ubl_3_point_2_X ,  ubl_3_point_2_Y ) ; 
 
			
		
	
		
			
				
					      z 3 - =  ubl . get_z_correction ( ubl_3_point_3_X ,  ubl_3_point_3_Y ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      do_blocking_move_to_xy ( ( X_MAX_POS  -  ( X_MIN_POS ) )  /  2.0 ,  ( Y_MAX_POS  -  ( Y_MIN_POS ) )  /  2.0 ) ; 
 
			
		
	
		
			
				
					      tilt_mesh_based_on_3pts ( Z1,  Z2 ,  Z  3) ; 
 
			
		
	
		
			
				
					      tilt_mesh_based_on_3pts ( z1,  z2 ,  z  3) ; 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    //
 
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -610,13 +617,16 @@
 
			
		
	
		
			
				
					        save_ubl_active_state_and_disable ( ) ; 
 
			
		
	
		
			
				
					        //measured_z = probe_pt(x_pos + X_PROBE_OFFSET_FROM_EXTRUDER, y_pos + Y_PROBE_OFFSET_FROM_EXTRUDER, ProbeDeployAndStow, g29_verbose_level);
 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        ubl_has_control_of_lcd_panel  =  true ;  // Grab the LCD Hardware
 
 
			
		
	
		
			
				
					        ubl_has_control_of_lcd_panel + + ;      // Grab the LCD Hardware
 
 
			
		
	
		
			
				
					        measured_z  =  1.5 ; 
 
			
		
	
		
			
				
					        do_blocking_move_to_z ( measured_z ) ;   // Get close to the bed, but leave some space so we don't damage anything
 
 
			
		
	
		
			
				
					                                            // The user is not going to be locking in a new Z-Offset very often so
 
 
			
		
	
		
			
				
					                                            // it won't be that painful to spin the Encoder Wheel for 1.5mm
 
 
			
		
	
		
			
				
					        lcd_implementation_clear ( ) ; 
 
			
		
	
		
			
				
					        lcd_z_offset_edit_setup ( measured_z ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        KEEPALIVE_STATE ( PAUSED_FOR_USER ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        do  { 
 
			
		
	
		
			
				
					          measured_z  =  lcd_z_offset_edit ( ) ; 
 
			
		
	
		
			
				
					          idle ( ) ; 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -628,6 +638,8 @@
 
			
		
	
		
			
				
					                                          // or here. So, until we are done looking for a long Encoder Wheel Press,
 
 
			
		
	
		
			
				
					                                          // we need to take control of the panel
 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        KEEPALIVE_STATE ( IN_HANDLER ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        lcd_return_to_status ( ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        const  millis_t  nxt  =  millis ( )  +  1500UL ; 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -637,7 +649,6 @@
 
			
		
	
		
			
				
					            SERIAL_PROTOCOLLNPGM ( " \n Z-Offset Adjustment Stopped. " ) ; 
 
			
		
	
		
			
				
					            do_blocking_move_to_z ( Z_CLEARANCE_DEPLOY_PROBE ) ; 
 
			
		
	
		
			
				
					            lcd_setstatus ( " Z-Offset Stopped " ,  true ) ; 
 
			
		
	
		
			
				
					            ubl_has_control_of_lcd_panel  =  false ; 
 
			
		
	
		
			
				
					            restore_ubl_active_state_and_leave ( ) ; 
 
			
		
	
		
			
				
					            goto  LEAVE ; 
 
			
		
	
		
			
				
					          } 
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -702,14 +713,14 @@
 
			
		
	
		
			
				
					      for  ( x  =  0 ;  x  <  UBL_MESH_NUM_X_POINTS ;  x + + ) 
 
			
		
	
		
			
				
					        for  ( y  =  0 ;  y  <  UBL_MESH_NUM_Y_POINTS ;  y + + ) 
 
			
		
	
		
			
				
					          if  ( ! isnan ( z_values [ x ] [ y ] ) ) 
 
			
		
	
		
			
				
					            z_values [ x ] [ y ]  - =  mean  +  ; 
 
			
		
	
		
			
				
					            z_values [ x ] [ y ]  - =  mean  +  ubl_ constant; 
 
			
		
	
		
			
				
					  } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  void  shift_mesh_height ( )  { 
 
			
		
	
		
			
				
					    for  ( uint8_t  x  =  0 ;  x  <  UBL_MESH_NUM_X_POINTS ;  x + + ) 
 
			
		
	
		
			
				
					      for  ( uint8_t  y  =  0 ;  y  <  UBL_MESH_NUM_Y_POINTS ;  y + + ) 
 
			
		
	
		
			
				
					        if  ( ! isnan ( z_values [ x ] [ y ] ) ) 
 
			
		
	
		
			
				
					          z_values [ x ] [ y ]  + =  ; 
 
			
		
	
		
			
				
					          z_values [ x ] [ y ]  + =  ubl_ constant; 
 
			
		
	
		
			
				
					  } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  /**
 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -728,9 +739,7 @@
 
			
		
	
		
			
				
					        SERIAL_PROTOCOLLNPGM ( " \n Mesh only partially populated. \n " ) ; 
 
			
		
	
		
			
				
					        lcd_quick_feedback ( ) ; 
 
			
		
	
		
			
				
					        STOW_PROBE ( ) ; 
 
			
		
	
		
			
				
					        while  ( ubl_lcd_clicked ( )  )  { 
 
			
		
	
		
			
				
					          idle ( ) ; 
 
			
		
	
		
			
				
					        } 
 
			
		
	
		
			
				
					        while  ( ubl_lcd_clicked ( ) )  idle ( ) ; 
 
			
		
	
		
			
				
					        ubl_has_control_of_lcd_panel  =  false ; 
 
			
		
	
		
			
				
					        restore_ubl_active_state_and_leave ( ) ; 
 
			
		
	
		
			
				
					        safe_delay ( 50 ) ;   // Debounce the Encoder wheel
 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -739,14 +748,18 @@
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      location  =  find_closest_mesh_point_of_type ( INVALID ,  lx ,  ly ,  1 ,  NULL ,  do_furthest  ) ;   // the '1' says we want the location to be relative to the probe
 
 
			
		
	
		
			
				
					      if  ( location . x_index  > =  0  & &  location . y_index  > =  0 )  { 
 
			
		
	
		
			
				
					        const  float  xProbe  =  ubl . map_x_index_to_bed_location ( location . x_index ) , 
 
			
		
	
		
			
				
					                    yProbe  =  ubl . map_y_index_to_bed_location ( location . y_index ) ; 
 
			
		
	
		
			
				
					        if  ( xProbe  <  MIN_PROBE_X  | |  xProbe  >  MAX_PROBE_X  | |  yProbe  <  MIN_PROBE_Y  | |  yProbe  >  MAX_PROBE_Y )  { 
 
			
		
	
		
			
				
					          SERIAL_PROTOCOLLNPGM ( " ?Error: Attempt to probe off the bed. " ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        const  float  rawx  =  ubl . map_x_index_to_bed_location ( location . x_index ) , 
 
			
		
	
		
			
				
					                    rawy  =  ubl . map_y_index_to_bed_location ( location . y_index ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        // TODO: Change to use `position_is_reachable` (for SCARA-compatibility)
 
 
			
		
	
		
			
				
					        if  ( rawx  <  ( MIN_PROBE_X )  | |  rawx  >  ( MAX_PROBE_X )  | |  rawy  <  ( MIN_PROBE_Y )  | |  rawy  >  ( MAX_PROBE_Y ) )  { 
 
			
		
	
		
			
				
					          SERIAL_ERROR_START ; 
 
			
		
	
		
			
				
					          SERIAL_ERRORLNPGM ( " Attempt to probe off the bed. " ) ; 
 
			
		
	
		
			
				
					          ubl_has_control_of_lcd_panel  =  false ; 
 
			
		
	
		
			
				
					          goto  LEAVE ; 
 
			
		
	
		
			
				
					        } 
 
			
		
	
		
			
				
					        const  float  measured_z  =  probe_pt ( xProbe ,  yProbe ,  stow_probe ,  g29_verbose_level ) ; 
 
			
		
	
		
			
				
					        const  float  measured_z  =  probe_pt ( LOGICAL_X_POSITION( rawx ) ,  LOGICAL_Y_POSITION ( rawy )  ,  stow_probe ,  g29_verbose_level ) ; 
 
			
		
	
		
			
				
					        z_values [ location . x_index ] [ location . y_index ]  =  measured_z  +  zprobe_zoffset ; 
 
			
		
	
		
			
				
					      } 
 
			
		
	
		
			
				
					
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -831,6 +844,7 @@
 
			
		
	
		
			
				
					  } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  float  use_encoder_wheel_to_measure_point ( )  { 
 
			
		
	
		
			
				
					    KEEPALIVE_STATE ( PAUSED_FOR_USER ) ; 
 
			
		
	
		
			
				
					    while  ( ! ubl_lcd_clicked ( ) )  {      // we need the loop to move the nozzle based on the encoder wheel here!
 
 
			
		
	
		
			
				
					      idle ( ) ; 
 
			
		
	
		
			
				
					      if  ( ubl_encoderDiff )  { 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -838,34 +852,35 @@
 
			
		
	
		
			
				
					        ubl_encoderDiff  =  0 ; 
 
			
		
	
		
			
				
					      } 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					    KEEPALIVE_STATE ( IN_HANDLER ) ; 
 
			
		
	
		
			
				
					    return  current_position [ Z_AXIS ] ; 
 
			
		
	
		
			
				
					  } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  float  measure_business_card_thickness ( const  float  & _value )  { 
 
			
		
	
		
			
				
					  float  measure_business_card_thickness ( const  float  & in_ height)  { 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    ubl_has_control_of_lcd_panel + + ; 
 
			
		
	
		
			
				
					    save_ubl_active_state_and_disable ( ) ;    // we don't do bed level correction because we want the raw data when we probe
 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    SERIAL_PROTOCOLLNPGM ( " Place Shim Under Nozzle and Perform Measurement. " ) ; 
 
			
		
	
		
			
				
					    do_blocking_move_to_z ( _value ) ; 
 
			
		
	
		
			
				
					    do_blocking_move_to_z ( in_ height) ; 
 
			
		
	
		
			
				
					    do_blocking_move_to_xy ( ( float ( X_MAX_POS )  -  float ( X_MIN_POS ) )  /  2.0 ,  ( float ( Y_MAX_POS )  -  float ( Y_MIN_POS ) )  /  2.0 ) ; 
 
			
		
	
		
			
				
					      //, min( planner.max_feedrate_mm_s[X_AXIS], planner.max_feedrate_mm_s[Y_AXIS])/2.0);
 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    const  float  Z 1 =  use_encoder_wheel_to_measure_point ( ) ; 
 
			
		
	
		
			
				
					    const  float  z 1 =  use_encoder_wheel_to_measure_point ( ) ; 
 
			
		
	
		
			
				
					    do_blocking_move_to_z ( current_position [ Z_AXIS ]  +  SIZE_OF_LITTLE_RAISE ) ; 
 
			
		
	
		
			
				
					    ubl_has_control_of_lcd_panel  =  false ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    SERIAL_PROTOCOLLNPGM ( " Remove Shim and Measure Bed Height. " ) ; 
 
			
		
	
		
			
				
					    const  float  Z 2 =  use_encoder_wheel_to_measure_point ( ) ; 
 
			
		
	
		
			
				
					    const  float  z 2 =  use_encoder_wheel_to_measure_point ( ) ; 
 
			
		
	
		
			
				
					    do_blocking_move_to_z ( current_position [ Z_AXIS ]  +  SIZE_OF_LITTLE_RAISE ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    if  ( g29_verbose_level  >  1 )  { 
 
			
		
	
		
			
				
					      SERIAL_PROTOCOLPGM ( " Business Card is:  " ) ; 
 
			
		
	
		
			
				
					      SERIAL_PROTOCOL_F ( abs ( Z1 -  Z  2) ,  6 ) ; 
 
			
		
	
		
			
				
					      SERIAL_PROTOCOL_F ( abs ( z1 -  z  2) ,  6 ) ; 
 
			
		
	
		
			
				
					      SERIAL_PROTOCOLLNPGM ( " mm thick. " ) ; 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					    restore_ubl_active_state_and_leave ( ) ; 
 
			
		
	
		
			
				
					    return  abs ( Z1 -  Z  2) ; 
 
			
		
	
		
			
				
					    return  abs ( z1 -  z  2) ; 
 
			
		
	
		
			
				
					  } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  void  manually_probe_remaining_mesh ( const  float  & lx ,  const  float  & ly ,  const  float  & z_clearance ,  const  float  & card_thickness ,  const  bool  do_ubl_mesh_map )  { 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -881,21 +896,23 @@
 
			
		
	
		
			
				
					      if  ( do_ubl_mesh_map )  ubl . display_map ( map_type ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      location  =  find_closest_mesh_point_of_type ( INVALID ,  lx ,  ly ,  0 ,  NULL ,  false ) ;  // The '0' says we want to use the nozzle's position
 
 
			
		
	
		
			
				
					      // It doesn't matter if the probe can not reach the
 
 
			
		
	
		
			
				
					      // NAN location. This is a manual probe.
 
 
			
		
	
		
			
				
					      // It doesn't matter if the probe can't reach the NAN location. This is a manual probe.
 
 
			
		
	
		
			
				
					      if  ( location . x_index  <  0  & &  location . y_index  <  0 )  continue ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      const  float  xProbe  =  ubl . map_x_index_to_bed_location ( location . x_index ) , 
 
			
		
	
		
			
				
					                  yProbe  =  ubl . map_y_index_to_bed_location ( location . y_index ) ; 
 
			
		
	
		
			
				
					      const  float  rawx  =  ubl . map_x_index_to_bed_location ( location . x_index ) , 
 
			
		
	
		
			
				
					                  rawy  =  ubl . map_y_index_to_bed_location ( location . y_index ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      // Modify to use if (position_is_reachable(pos[XYZ]))
 
 
			
		
	
		
			
				
					      if  ( xProbe  <  ( X_MIN_POS )  | |  xProbe  >  ( X_MAX_POS )  | |  yProbe  <  ( Y_MIN_POS )  | |  yProbe  >  ( Y_MAX_POS ) )  { 
 
			
		
	
		
			
				
					        SERIAL_PROTOCOLLNPGM ( " ?Error: Attempt to probe off the bed. " ) ; 
 
			
		
	
		
			
				
					      // TODO: Change to use `position_is_reachable` (for SCARA-compatibility)
 
 
			
		
	
		
			
				
					      if  ( rawx  <  ( X_MIN_POS )  | |  rawx  >  ( X_MAX_POS )  | |  rawy  <  ( Y_MIN_POS )  | |  rawy  >  ( Y_MAX_POS ) )  { 
 
			
		
	
		
			
				
					        SERIAL_ERROR_START ; 
 
			
		
	
		
			
				
					        SERIAL_ERRORLNPGM ( " Attempt to probe off the bed. " ) ; 
 
			
		
	
		
			
				
					        ubl_has_control_of_lcd_panel  =  false ; 
 
			
		
	
		
			
				
					        goto  LEAVE ; 
 
			
		
	
		
			
				
					      } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      const  float  dx  =  xProbe  -  last_x , 
 
			
		
	
		
			
				
					      const  float  xProbe  =  LOGICAL_X_POSITION ( rawx ) , 
 
			
		
	
		
			
				
					                  yProbe  =  LOGICAL_Y_POSITION ( rawy ) , 
 
			
		
	
		
			
				
					                  dx  =  xProbe  -  last_x , 
 
			
		
	
		
			
				
					                  dy  =  yProbe  -  last_y ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      if  ( HYPOT ( dx ,  dy )  <  BIG_RAISE_NOT_NEEDED ) 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -908,8 +925,10 @@
 
			
		
	
		
			
				
					      last_x  =  xProbe ; 
 
			
		
	
		
			
				
					      last_y  =  yProbe ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      KEEPALIVE_STATE ( PAUSED_FOR_USER ) ; 
 
			
		
	
		
			
				
					      ubl_has_control_of_lcd_panel  =  true ; 
 
			
		
	
		
			
				
					      while  ( ! ubl_lcd_clicked )  {      // we need the loop to move the nozzle based on the encoder wheel here!
 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      while  ( ! ubl_lcd_clicked ( ) )  {      // we need the loop to move the nozzle based on the encoder wheel here!
 
 
			
		
	
		
			
				
					        idle ( ) ; 
 
			
		
	
		
			
				
					        if  ( ubl_encoderDiff )  { 
 
			
		
	
		
			
				
					          do_blocking_move_to_z ( current_position [ Z_AXIS ]  +  float ( ubl_encoderDiff )  /  100.0 ) ; 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -926,6 +945,7 @@
 
			
		
	
		
			
				
					          lcd_quick_feedback ( ) ; 
 
			
		
	
		
			
				
					          while  ( ubl_lcd_clicked ( ) )  idle ( ) ; 
 
			
		
	
		
			
				
					          ubl_has_control_of_lcd_panel  =  false ; 
 
			
		
	
		
			
				
					          KEEPALIVE_STATE ( IN_HANDLER ) ; 
 
			
		
	
		
			
				
					          restore_ubl_active_state_and_leave ( ) ; 
 
			
		
	
		
			
				
					          return ; 
 
			
		
	
		
			
				
					        } 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -933,7 +953,7 @@
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      z_values [ location . x_index ] [ location . y_index ]  =  current_position [ Z_AXIS ]  -  card_thickness ; 
 
			
		
	
		
			
				
					      if  ( g29_verbose_level  >  2 )  { 
 
			
		
	
		
			
				
					        SERIAL_PROTOCOL ( " Mesh Point Measured at:  " ) ; 
 
			
		
	
		
			
				
					        SERIAL_PROTOCOL PGM ( " Mesh Point Measured at:  " ) ; 
 
			
		
	
		
			
				
					        SERIAL_PROTOCOL_F ( z_values [ location . x_index ] [ location . y_index ] ,  6 ) ; 
 
			
		
	
		
			
				
					        SERIAL_EOL ; 
 
			
		
	
		
			
				
					      } 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -943,52 +963,40 @@
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    LEAVE : 
 
			
		
	
		
			
				
					    restore_ubl_active_state_and_leave ( ) ; 
 
			
		
	
		
			
				
					    KEEPALIVE_STATE ( IN_HANDLER ) ; 
 
			
		
	
		
			
				
					    do_blocking_move_to_z ( Z_CLEARANCE_DEPLOY_PROBE ) ; 
 
			
		
	
		
			
				
					    do_blocking_move_to_xy ( lx ,  ly ) ; 
 
			
		
	
		
			
				
					  } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  bool  g29_parameter_parsing ( )  { 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # if ENABLED(ULTRA_LCD) 
 
			
		
	
		
			
				
					      lcd_setstatus ( " Doing G29 UBL ! " ,  true ) ; 
 
			
		
	
		
			
				
					      lcd_quick_feedback ( ) ; 
 
			
		
	
		
			
				
					    # endif 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    x_pos  =  current_position [ X_AXIS ] ; 
 
			
		
	
		
			
				
					    y_pos  =  current_position [ Y_AXIS ] ; 
 
			
		
	
		
			
				
					    x_flag  =  y_flag  =  repeat_flag  =  false ; 
 
			
		
	
		
			
				
					    map_type  =  0 ; 
 
			
		
	
		
			
				
					    constant  =  0.0 ; 
 
			
		
	
		
			
				
					    repetition_cnt  =  1 ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    if  ( ( x_flag  =  code_seen ( ' X ' ) ) )  { 
 
			
		
	
		
			
				
					      x_pos  =  code_value_float ( ) ; 
 
			
		
	
		
			
				
					      if  ( x_pos  <  X_MIN_POS  | |  x_pos  >  X_MAX_POS )  { 
 
			
		
	
		
			
				
					        SERIAL_PROTOCOLLNPGM ( " Invalid X location specified. \n " ) ; 
 
			
		
	
		
			
				
					        return  UBL_ERR ; 
 
			
		
	
		
			
				
					      } 
 
			
		
	
		
			
				
					    g29_verbose_level  =  code_seen ( ' V ' )  ?  code_value_int ( )  :  0 ; 
 
			
		
	
		
			
				
					    if  ( g29_verbose_level  <  0  | |  g29_verbose_level  >  4 )  { 
 
			
		
	
		
			
				
					      SERIAL_PROTOCOLLNPGM ( " Invalid Verbose Level specified. (0-4) \n " ) ; 
 
			
		
	
		
			
				
					      return  UBL_ERR ; 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    if  ( ( y_flag  =  code_seen ( ' Y ' ) ) )  { 
 
			
		
	
		
			
				
					      y_pos  =  code_value_float ( ) ; 
 
			
		
	
		
			
				
					      if  ( y_pos  <  Y_MIN_POS  | |  y_pos  >  Y_MAX_POS )  { 
 
			
		
	
		
			
				
					        SERIAL_PROTOCOLLNPGM ( " Invalid Y location specified. \n " ) ; 
 
			
		
	
		
			
				
					        return  UBL_ERR ; 
 
			
		
	
		
			
				
					      } 
 
			
		
	
		
			
				
					    x_flag  =  code_seen ( ' X ' )  & &  code_has_value ( ) ; 
 
			
		
	
		
			
				
					    x_pos  =  x_flag  ?  code_value_float ( )  :  current_position [ X_AXIS ] ; 
 
			
		
	
		
			
				
					    if  ( x_pos  <  LOGICAL_X_POSITION ( X_MIN_POS )  | |  x_pos  >  LOGICAL_X_POSITION ( X_MAX_POS ) )  { 
 
			
		
	
		
			
				
					      SERIAL_PROTOCOLLNPGM ( " Invalid X location specified. \n " ) ; 
 
			
		
	
		
			
				
					      return  UBL_ERR ; 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    if  ( x_flag  ! =  y_flag )  { 
 
			
		
	
		
			
				
					      SERIAL_PROTOCOLLNPGM ( " Both X & Y locations must be specified. \n " ) ; 
 
			
		
	
		
			
				
					    y_flag  =  code_seen ( ' Y ' )  & &  code_has_value ( ) ; 
 
			
		
	
		
			
				
					    y_pos  =  y_flag  ?  code_value_float ( )  :  current_position [ Y_AXIS ] ; 
 
			
		
	
		
			
				
					    if  ( y_pos  <  LOGICAL_Y_POSITION ( Y_MIN_POS )  | |  y_pos  >  LOGICAL_Y_POSITION ( Y_MAX_POS ) )  { 
 
			
		
	
		
			
				
					      SERIAL_PROTOCOLLNPGM ( " Invalid Y location specified. \n " ) ; 
 
			
		
	
		
			
				
					      return  UBL_ERR ; 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    g29_verbose_level  =  0 ; 
 
			
		
	
		
			
				
					    if  ( code_seen ( ' V ' ) )  { 
 
			
		
	
		
			
				
					      g29_verbose_level  =  code_value_int ( ) ; 
 
			
		
	
		
			
				
					      if  ( g29_verbose_level  <  0  | |  g29_verbose_level  >  4 )  { 
 
			
		
	
		
			
				
					        SERIAL_PROTOCOLLNPGM ( " Invalid Verbose Level specified. (0-4) \n " ) ; 
 
			
		
	
		
			
				
					        return  UBL_ERR ; 
 
			
		
	
		
			
				
					      } 
 
			
		
	
		
			
				
					    if  ( x_flag  ! =  y_flag )  { 
 
			
		
	
		
			
				
					      SERIAL_PROTOCOLLNPGM ( " Both X & Y locations must be specified. \n " ) ; 
 
			
		
	
		
			
				
					      return  UBL_ERR ; 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    if  ( code_seen ( ' A ' ) )  {      // Activate the Unified Bed Leveling System
 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -997,8 +1005,8 @@
 
			
		
	
		
			
				
					      ubl . store_state ( ) ; 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    if  ( ( c_flag  =  code_seen ( ' C ' )  & &  code_has_value ( ) ))  
 
			
		
	
		
			
				
					       =  c ode_value_float( ) ; 
 
			
		
	
		
			
				
					    c_flag  =  code_seen ( ' C ' )  & &  code_has_value ( ) ; 
 
			
		
	
		
			
				
					    ubl_ constant =  c _flag ?  c  ode_value_float( )  :  0.0  ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    if  ( code_seen ( ' D ' ) )  {      // Disable the Unified Bed Leveling System
 
 
			
		
	
		
			
				
					      ubl . state . active  =  0 ; 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -1018,29 +1026,28 @@
 
			
		
	
		
			
				
					      } 
 
			
		
	
		
			
				
					    # endif 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    if  ( ( repeat_flag  =  code_seen ( ' R ' ) ) )  { 
 
			
		
	
		
			
				
					      repetition_cnt  =  code_has_value ( )  ?  code_value_int ( )  :  9999 ; 
 
			
		
	
		
			
				
					      if  ( repetition_cnt  <  1 )  { 
 
			
		
	
		
			
				
					        SERIAL_PROTOCOLLNPGM ( " Invalid Repetition count. \n " ) ; 
 
			
		
	
		
			
				
					        return  UBL_ERR ; 
 
			
		
	
		
			
				
					      } 
 
			
		
	
		
			
				
					    repeat_flag  =  code_seen ( ' R ' ) ; 
 
			
		
	
		
			
				
					    repetition_cnt  =  repeat_flag  ?  ( code_has_value ( )  ?  code_value_int ( )  :  9999 )  :  1 ; 
 
			
		
	
		
			
				
					    if  ( repetition_cnt  <  1 )  { 
 
			
		
	
		
			
				
					      SERIAL_PROTOCOLLNPGM ( " Invalid Repetition count. \n " ) ; 
 
			
		
	
		
			
				
					      return  UBL_ERR ; 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    if  ( code_seen ( ' O ' ) )  {      // Check if a map type was specified
 
 
			
		
	
		
			
				
					      map_type  =  code_value_int ( )  ?  code_has_value ( )  :  0 ;  
 
			
		
	
		
			
				
					      if  (  map_type < 0  | |  map_type > 1 )  { 
 
			
		
	
		
			
				
					        SERIAL_PROTOCOLLNPGM ( " Invalid map type. \n " ) ; 
 
			
		
	
		
			
				
					        return  UBL_ERR ; 
 
			
		
	
		
			
				
					      } 
 
			
		
	
		
			
				
					    map_type  =  code_seen ( ' O ' )  & &  code_has_value ( )  ?  code_value_int ( )  :  0 ; 
 
			
		
	
		
			
				
					    if  ( map_type  <  0  | |  map_type  >  1 )  { 
 
			
		
	
		
			
				
					      SERIAL_PROTOCOLLNPGM ( " Invalid map type. \n " ) ; 
 
			
		
	
		
			
				
					      return  UBL_ERR ; 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    /*
 
 
			
		
	
		
			
				
					    if  ( code_seen ( ' M ' ) )  {      // Check if a map type was specified
 
 
			
		
	
		
			
				
					      map_type  =  code_ value_int ( )  ?  code_ has_ value( )  :  0 ;  
 
			
		
	
		
			
				
					      if  (   map_type < 0  | |  map_type > 1 )  { 
 
			
		
	
		
			
				
					      map_type  =  code_ has_ value( )  ?  code_ value_int ( )  :  0 ;  
 
			
		
	
		
			
				
					      if  ( map_type   <   0  | |  map_type   >   1 )  { 
 
			
		
	
		
			
				
					        SERIAL_PROTOCOLLNPGM ( " Invalid map type. \n " ) ; 
 
			
		
	
		
			
				
					        return  UBL_ERR ; 
 
			
		
	
		
			
				
					      } 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					    //*/
 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    return  UBL_OK ; 
 
			
		
	
		
			
				
					  } 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -1054,20 +1061,15 @@
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    SERIAL_PROTOCOL ( str ) ; 
 
			
		
	
		
			
				
					    SERIAL_PROTOCOL_F ( f ,  8 ) ; 
 
			
		
	
		
			
				
					    SERIAL_PROTOCOL ( "    " ) ; 
 
			
		
	
		
			
				
					    SERIAL_PROTOCOL PGM ( "    " ) ; 
 
			
		
	
		
			
				
					    ptr  =  ( char * ) & f ; 
 
			
		
	
		
			
				
					    for  ( uint8_t  i  =  0 ;  i  <  4 ;  i + + )  { 
 
			
		
	
		
			
				
					      SERIAL_PROTOCOL ( "    " ) ; 
 
			
		
	
		
			
				
					      prt_hex_byte ( * ptr + + ) ; 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					    SERIAL_PROTOCOL ( "   isnan()= " ) ; 
 
			
		
	
		
			
				
					    SERIAL_PROTOCOL ( isnan ( f ) ) ; 
 
			
		
	
		
			
				
					    SERIAL_PROTOCOL ( "   isinf()= " ) ; 
 
			
		
	
		
			
				
					    SERIAL_PROTOCOL ( isinf ( f ) ) ; 
 
			
		
	
		
			
				
					    for  ( uint8_t  i  =  0 ;  i  <  4 ;  i + + ) 
 
			
		
	
		
			
				
					      SERIAL_PROTOCOLPAIR ( "    " ,  hex_byte ( * ptr + + ) ) ; 
 
			
		
	
		
			
				
					    SERIAL_PROTOCOLPAIR ( "   isnan()= " ,  isnan ( f ) ) ; 
 
			
		
	
		
			
				
					    SERIAL_PROTOCOLPAIR ( "   isinf()= " ,  isinf ( f ) ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    constexpr  float  g  =  INFINITY ; 
 
			
		
	
		
			
				
					    if  ( f  = =  - g ) 
 
			
		
	
		
			
				
					      SERIAL_PROTOCOL ( "   Minus Infinity detected. " ) ; 
 
			
		
	
		
			
				
					    if  ( f  = =  - INFINITY ) 
 
			
		
	
		
			
				
					      SERIAL_PROTOCOLPGM ( "   Minus Infinity detected. " ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    SERIAL_EOL ; 
 
			
		
	
		
			
				
					  } 
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -1104,7 +1106,6 @@
 
			
		
	
		
			
				
					   */ 
 
			
		
	
		
			
				
					  void  g29_what_command ( )  { 
 
			
		
	
		
			
				
					    const  uint16_t  k  =  E2END  -  ubl_eeprom_start ; 
 
			
		
	
		
			
				
					    statistics_flag + + ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    SERIAL_PROTOCOLPGM ( " Unified Bed Leveling System Version 1.00  " ) ; 
 
			
		
	
		
			
				
					    if  ( ubl . state . active )   
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -1117,8 +1118,7 @@
 
			
		
	
		
			
				
					    if  ( ubl . state . eeprom_storage_slot  = =  - 1 ) 
 
			
		
	
		
			
				
					      SERIAL_PROTOCOLPGM ( " No Mesh Loaded. " ) ; 
 
			
		
	
		
			
				
					    else  { 
 
			
		
	
		
			
				
					      SERIAL_PROTOCOLPGM ( " Mesh:  " ) ; 
 
			
		
	
		
			
				
					      prt_hex_word ( ubl . state . eeprom_storage_slot ) ; 
 
			
		
	
		
			
				
					      SERIAL_PROTOCOLPAIR ( " Mesh  " ,  ubl . state . eeprom_storage_slot ) ; 
 
			
		
	
		
			
				
					      SERIAL_PROTOCOLPGM ( "  Loaded. " ) ; 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					    SERIAL_EOL ; 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -1136,7 +1136,7 @@
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    SERIAL_PROTOCOLPGM ( " X-Axis Mesh Points at:  " ) ; 
 
			
		
	
		
			
				
					    for  ( uint8_t  i  =  0 ;  i  <  UBL_MESH_NUM_X_POINTS ;  i + + )  { 
 
			
		
	
		
			
				
					      SERIAL_PROTOCOL_F (   ubl . map_x_index_to_bed_location ( i ) ,  1 ) ; 
 
			
		
	
		
			
				
					      SERIAL_PROTOCOL_F ( LOGICAL_X_POSITION ( ubl . map_x_index_to_bed_location ( i ) ) ,  1 ) ; 
 
			
		
	
		
			
				
					      SERIAL_PROTOCOLPGM ( "    " ) ; 
 
			
		
	
		
			
				
					      safe_delay ( 50 ) ; 
 
			
		
	
		
			
				
					    } 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -1144,7 +1144,7 @@
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    SERIAL_PROTOCOLPGM ( " Y-Axis Mesh Points at:  " ) ; 
 
			
		
	
		
			
				
					    for  ( uint8_t  i  =  0 ;  i  <  UBL_MESH_NUM_Y_POINTS ;  i + + )  { 
 
			
		
	
		
			
				
					      SERIAL_PROTOCOL_F (   ubl . map_y_index_to_bed_location ( i ) ,  1 ) ; 
 
			
		
	
		
			
				
					      SERIAL_PROTOCOL_F ( LOGICAL_Y_POSITION ( ubl . map_y_index_to_bed_location ( i ) ) ,  1 ) ; 
 
			
		
	
		
			
				
					      SERIAL_PROTOCOLPGM ( "    " ) ; 
 
			
		
	
		
			
				
					      safe_delay ( 50 ) ; 
 
			
		
	
		
			
				
					    } 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -1162,13 +1162,9 @@
 
			
		
	
		
			
				
					    SERIAL_PROTOCOLLNPAIR ( " ubl_state_recursion_chk : " ,  ubl_state_recursion_chk ) ; 
 
			
		
	
		
			
				
					    SERIAL_EOL ; 
 
			
		
	
		
			
				
					    safe_delay ( 50 ) ; 
 
			
		
	
		
			
				
					    SERIAL_PROTOCOLPGM ( " Free EEPROM space starts at: 0x " ) ; 
 
			
		
	
		
			
				
					    prt_hex_word ( ubl_eeprom_start ) ; 
 
			
		
	
		
			
				
					    SERIAL_EOL ; 
 
			
		
	
		
			
				
					    SERIAL_PROTOCOLLNPAIR ( " Free EEPROM space starts at: 0x " ,  hex_word ( ubl_eeprom_start ) ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    SERIAL_PROTOCOLPGM ( " end of EEPROM              :  " ) ; 
 
			
		
	
		
			
				
					    prt_hex_word ( E2END ) ; 
 
			
		
	
		
			
				
					    SERIAL_EOL ; 
 
			
		
	
		
			
				
					    SERIAL_PROTOCOLLNPAIR ( " end of EEPROM              :  " ,  hex_word ( E2END ) ) ; 
 
			
		
	
		
			
				
					    safe_delay ( 50 ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    SERIAL_PROTOCOLLNPAIR ( " sizeof(ubl) :   " ,  ( int ) sizeof ( ubl ) ) ; 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -1177,18 +1173,14 @@
 
			
		
	
		
			
				
					    SERIAL_EOL ; 
 
			
		
	
		
			
				
					    safe_delay ( 50 ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    SERIAL_PROTOCOLPGM ( " EEPROM free for UBL: 0x " ) ; 
 
			
		
	
		
			
				
					    prt_hex_word ( k ) ; 
 
			
		
	
		
			
				
					    SERIAL_EOL ; 
 
			
		
	
		
			
				
					    SERIAL_PROTOCOLLNPAIR ( " EEPROM free for UBL: 0x " ,  hex_word ( k ) ) ; 
 
			
		
	
		
			
				
					    safe_delay ( 50 ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    SERIAL_PROTOCOLPGM ( " EEPROM can hold 0x " ) ; 
 
			
		
	
		
			
				
					    prt_hex_word ( k  /  sizeof ( z_values ) ) ; 
 
			
		
	
		
			
				
					    SERIAL_PROTOCOLPAIR ( " EEPROM can hold  " ,  k  /  sizeof ( z_values ) ) ; 
 
			
		
	
		
			
				
					    SERIAL_PROTOCOLLNPGM ( "  meshes. \n " ) ; 
 
			
		
	
		
			
				
					    safe_delay ( 50 ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    SERIAL_PROTOCOLPGM ( " sizeof(ubl.state) : " ) ; 
 
			
		
	
		
			
				
					    prt_hex_word ( sizeof ( ubl . state ) ) ; 
 
			
		
	
		
			
				
					    SERIAL_PROTOCOLPAIR ( " sizeof(ubl.state) :  " ,  ( int ) sizeof ( ubl . state ) ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    SERIAL_PROTOCOLPAIR ( " \n UBL_MESH_NUM_X_POINTS   " ,  UBL_MESH_NUM_X_POINTS ) ; 
 
			
		
	
		
			
				
					    SERIAL_PROTOCOLPAIR ( " \n UBL_MESH_NUM_Y_POINTS   " ,  UBL_MESH_NUM_Y_POINTS ) ; 
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -1222,12 +1214,12 @@
 
			
		
	
		
			
				
					    SERIAL_ECHOLNPGM ( " EEPROM Dump: " ) ; 
 
			
		
	
		
			
				
					    for  ( uint16_t  i  =  0 ;  i  <  E2END  +  1 ;  i  + =  16 )  { 
 
			
		
	
		
			
				
					      if  ( ! ( i  &  0x3 ) )  idle ( ) ; 
 
			
		
	
		
			
				
					      pr t_hex_word( i ) ; 
 
			
		
	
		
			
				
					      pr in t_hex_word( i ) ; 
 
			
		
	
		
			
				
					      SERIAL_ECHOPGM ( " :  " ) ; 
 
			
		
	
		
			
				
					      for  ( uint16_t  j  =  0 ;  j  <  16 ;  j + + )  { 
 
			
		
	
		
			
				
					        kkkk  =  i  +  j ; 
 
			
		
	
		
			
				
					        eeprom_read_block ( & cccc ,  ( void  * ) kkkk ,  1 ) ; 
 
			
		
	
		
			
				
					        pr t_hex_byte( cccc ) ; 
 
			
		
	
		
			
				
					        pr in t_hex_byte( cccc ) ; 
 
			
		
	
		
			
				
					        SERIAL_ECHO ( '   ' ) ; 
 
			
		
	
		
			
				
					      } 
 
			
		
	
		
			
				
					      SERIAL_EOL ; 
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -1259,9 +1251,8 @@
 
			
		
	
		
			
				
					    eeprom_read_block ( ( void  * ) & tmp_z_values ,  ( void  * ) j ,  sizeof ( tmp_z_values ) ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    SERIAL_ECHOPAIR ( " Subtracting Mesh  " ,  storage_slot ) ; 
 
			
		
	
		
			
				
					    SERIAL_PROTOCOLPGM ( "  loaded from EEPROM address  " ) ;    // Soon, we can remove the extra clutter of printing
 
 
			
		
	
		
			
				
					    prt_hex_word ( j ) ;             // the address in the EEPROM where the Mesh is stored.
 
 
			
		
	
		
			
				
					    SERIAL_EOL ; 
 
			
		
	
		
			
				
					    SERIAL_PROTOCOLLNPAIR ( "  loaded from EEPROM address  " ,  hex_word ( j ) ) ;  // Soon, we can remove the extra clutter of printing
 
 
			
		
	
		
			
				
					                                                                        // the address in the EEPROM where the Mesh is stored.
 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    for  ( uint8_t  x  =  0 ;  x  <  UBL_MESH_NUM_X_POINTS ;  x + + ) 
 
			
		
	
		
			
				
					      for  ( uint8_t  y  =  0 ;  y  <  UBL_MESH_NUM_Y_POINTS ;  y + + ) 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -1269,7 +1260,6 @@
 
			
		
	
		
			
				
					  } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  mesh_index_pair  find_closest_mesh_point_of_type ( const  MeshPointType  type ,  const  float  & lx ,  const  float  & ly ,  const  bool  probe_as_reference ,  unsigned  int  bits [ 16 ] ,  bool  far_flag )  { 
 
			
		
	
		
			
				
					    int  i ,  j ,  k ,  l ; 
 
			
		
	
		
			
				
					    float  distance ,  closest  =  far_flag  ?  - 99999.99  :  99999.99 ; 
 
			
		
	
		
			
				
					    mesh_index_pair  return_val ; 
 
			
		
	
		
			
				
					
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -1282,8 +1272,8 @@
 
			
		
	
		
			
				
					    const  float  px  =  lx  -  ( probe_as_reference  ?  X_PROBE_OFFSET_FROM_EXTRUDER  :  0 ) , 
 
			
		
	
		
			
				
					                py  =  ly  -  ( probe_as_reference  ?  Y_PROBE_OFFSET_FROM_EXTRUDER  :  0 ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    for  ( i  =  0 ;  i  <  UBL_MESH_NUM_X_POINTS ;  i + + )  { 
 
			
		
	
		
			
				
					      for  ( j  =  0 ;  j  <  UBL_MESH_NUM_Y_POINTS ;  j + + )  { 
 
			
		
	
		
			
				
					    for  ( uint8_t  i  =  0 ;  i  <  UBL_MESH_NUM_X_POINTS ;  i + + )  { 
 
			
		
	
		
			
				
					      for  ( uint8_t  j  =  0 ;  j  <  UBL_MESH_NUM_Y_POINTS ;  j + + )  { 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        if  (  ( type  = =  INVALID  & &  isnan ( z_values [ i ] [ j ] ) )   // Check to see if this location holds the right thing
 
 
			
		
	
		
			
				
					          | |  ( type  = =  REAL  & &  ! isnan ( z_values [ i ] [ j ] ) ) 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -1292,42 +1282,45 @@
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					          // We only get here if we found a Mesh Point of the specified type
 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					          const  float  mx =  LOGICAL_X_POSITION (  ubl . map_x_index_to_bed_location ( i ) ) ,  // Check if we can probe this mesh location
 
 
			
		
	
		
			
				
					                      my =  LOGICAL_Y_POSITION (  ubl . map_y_index_to_bed_location ( j ) ) ; 
 
			
		
	
		
			
				
					          const  float  rawx =   ubl . map_x_index_to_bed_location ( i ) ,  // Check if we can probe this mesh location
 
 
			
		
	
		
			
				
					                      rawy =   ubl . map_y_index_to_bed_location ( j ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					          // If we are using the probe as the reference there are some locations we can't get to.
 
 
			
		
	
		
			
				
					          // We prune these out of the list and ignore them until the next Phase where we do the
 
 
			
		
	
		
			
				
					          // manual nozzle probing.
 
 
			
		
	
		
			
				
					          // If using the probe as the reference there are some unreachable locations.
 
 
			
		
	
		
			
				
					          // Prune them from the list and ignore them till the next Phase (manual nozzle probing).
 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					          if  ( probe_as_reference  & & 
 
			
		
	
		
			
				
					            ( mx <  ( MIN_PROBE_X )  | |  mx  >  ( MAX_PROBE_X )  | |  my  <  ( MIN_PROBE_Y )  | |  m  y >  ( MAX_PROBE_Y ) ) 
 
			
		
	
		
			
				
					            ( rawx <  ( MIN_PROBE_X )  | |  rawx  >  ( MAX_PROBE_X )  | |  rawy  <  ( MIN_PROBE_Y )  | |  raw  y >  ( MAX_PROBE_Y ) ) 
 
			
		
	
		
			
				
					          )  continue ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					          //  We can get to it. Let's see if it i s the closest location to the nozzle.
 
			
		
	
		
			
				
					          //  Unreachable. Check if it' s the closest location to the nozzle.
 
			
		
	
		
			
				
					          // Add in a weighting factor that considers the current location of the nozzle.
 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					          const  float  mx  =  LOGICAL_X_POSITION ( rawx ) ,  // Check if we can probe this mesh location
 
 
			
		
	
		
			
				
					                      my  =  LOGICAL_Y_POSITION ( rawy ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					          distance  =  HYPOT ( px  -  mx ,  py  -  my )  +  HYPOT ( current_x  -  mx ,  current_y  -  my )  *  0.1 ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
						  if  ( far_flag )  {                                     // If doing the far_flag action, we want to be as far as possible
 
 
			
		
	
		
			
				
					            for  ( k  =  0 ;  k  <  UBL_MESH_NUM_X_POINTS ;  k + + )  {      // from the starting point and from any other probed points.  We
 
 
			
		
	
		
			
				
					              for  ( l  =  0 ;  l  <  UBL_MESH_NUM_Y_POINTS ;  l + + )  {    // want the next point spread out and filling in any blank spaces
 
 
			
		
	
		
			
				
					                if  (   ! isnan ( z_values [ k ] [ l ] ) )  {                // in the mesh.     So we add in some of the distance to every probed  
 
			
		
	
		
			
				
					                  distance  + =  ( i - k ) * ( i - k ) * MESH_X_DIST * .05 ; // point we can find.
 
 
			
		
	
		
			
				
					                  distance  + =  ( j - l ) * ( j - l ) * MESH_Y_DIST * .05 ; 
 
			
		
	
		
			
				
							 }  
			
		
	
		
			
				
					           if  ( far_flag )  {                                             // If doing the far_flag action, we want to be as far as possible
  
			
		
	
		
			
				
					            for  ( uint8_t  k  =  0 ;  k  <  UBL_MESH_NUM_X_POINTS ;  k + + )  {    // from the starting point and from any other probed points.  We
 
 
			
		
	
		
			
				
					              for  ( uint8_t  l  =  0 ;  l  <  UBL_MESH_NUM_Y_POINTS ;  l + + )  {  // want the next point spread out and filling in any blank spaces
 
 
			
		
	
		
			
				
					                if  ( ! isnan ( z_values [ k ] [ l ] ) )  {                          // in the mesh.  So we add in some of the distance to every probed
 
			
		
	
		
			
				
					                  distance  + =  sq ( i  -  k )  *  ( MESH_X_DIST )  *  .05     // point we can find.
 
 
			
		
	
		
			
				
					                            +  sq ( j  -  l )  *  ( MESH_Y_DIST )  *   .05 ; 
 
			
		
	
		
			
				
					                 }  
			
		
	
		
			
				
					              } 
 
			
		
	
		
			
				
						     }  
			
		
	
		
			
				
						   }  
			
		
	
		
			
				
					             }  
			
		
	
		
			
				
					           }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					          if  (  ( ! far_flag & & ( distance  <  closest ) )  | |  ( far_flag & & ( distance  >  closest ) )  )  {   // if far_flag, look for furthest away   point
 
			
		
	
		
			
				
					            closest  =  distance ;        // We found a closer  location with
 
			
		
	
		
			
				
					          if  ( far_flag  = =  ( distance  >  closest )  & &  distance  ! =  closest )  {   // if far_flag, look for farthest 
 
			
		
	
		
			
				
					            closest  =  distance ;        // We found a closer /farther  location with
 
			
		
	
		
			
				
					            return_val . x_index  =  i ;    // the specified type of mesh value.
 
 
			
		
	
		
			
				
					            return_val . y_index  =  j ; 
 
			
		
	
		
			
				
					            return_val . distance  =  closest ; 
 
			
		
	
		
			
				
					          } 
 
			
		
	
		
			
				
					        } 
 
			
		
	
		
			
				
					      } 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					      }  // for j
 
 
			
		
	
		
			
				
					    }  // for i
 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    return  return_val ; 
 
			
		
	
		
			
				
					  } 
 
			
		
	
		
			
				
					
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -1356,27 +1349,30 @@
 
			
		
	
		
			
				
					      bit_clear ( not_done ,  location . x_index ,  location . y_index ) ;   // Mark this location as 'adjusted' so we will find a
 
 
			
		
	
		
			
				
					                                                                // different location the next time through the loop
 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      const  float  xProbe  =  ubl . map_x_index_to_bed_location ( location . x_index ) , 
 
			
		
	
		
			
				
					                  yProbe  =  ubl . map_y_index_to_bed_location ( location . y_index ) ; 
 
			
		
	
		
			
				
					      if  ( xProbe  <  X_MIN_POS  | |  xProbe  >  X_MAX_POS  | |  yProbe  <  Y_MIN_POS  | |  yProbe  >  Y_MAX_POS )  {  // In theory, we don't need this check.
 
 
			
		
	
		
			
				
					        SERIAL_PROTOCOLLNPGM ( " ?Error: Attempt to edit off the bed. " ) ;                              // This really can't happen, but for now,
 
 
			
		
	
		
			
				
					        ubl_has_control_of_lcd_panel  =  false ;                                                          // Let's do the check.
 
 
			
		
	
		
			
				
					      const  float  rawx  =  ubl . map_x_index_to_bed_location ( location . x_index ) , 
 
			
		
	
		
			
				
					                  rawy  =  ubl . map_y_index_to_bed_location ( location . y_index ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      // TODO: Change to use `position_is_reachable` (for SCARA-compatibility)
 
 
			
		
	
		
			
				
					      if  ( rawx  <  ( X_MIN_POS )  | |  rawx  >  ( X_MAX_POS )  | |  rawy  <  ( Y_MIN_POS )  | |  rawy  >  ( Y_MAX_POS ) )  {  // In theory, we don't need this check.
 
 
			
		
	
		
			
				
					        SERIAL_ERROR_START ; 
 
			
		
	
		
			
				
					        SERIAL_ERRORLNPGM ( " Attempt to edit off the bed. " ) ;  // This really can't happen, but do the check for now
 
 
			
		
	
		
			
				
					        ubl_has_control_of_lcd_panel  =  false ; 
 
			
		
	
		
			
				
					        goto  FINE_TUNE_EXIT ; 
 
			
		
	
		
			
				
					      } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      do_blocking_move_to_z ( Z_CLEARANCE_DEPLOY_PROBE ) ;     // Move the nozzle to where we are going to edit
 
 
			
		
	
		
			
				
					      do_blocking_move_to_xy ( xProbe,  yProbe  ) ; 
 
			
		
	
		
			
				
					      do_blocking_move_to_xy ( LOGICAL_X_POSITION( rawx ) ,  LOGICAL_Y_POSITION ( rawy )  ) ; 
 
			
		
	
		
			
				
					      float  new_z  =  z_values [ location . x_index ] [ location . y_index ] ; 
 
			
		
	
		
			
				
					      
 
			
		
	
		
			
				
					      round_off  =  ( int32_t ) ( new_z  *  1000.0 ) ;     // we chop off the last digits just to be clean. We are rounding to the
 
 
			
		
	
		
			
				
					      new_z  =  float ( round_off )  /  1000.0 ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      KEEPALIVE_STATE ( PAUSED_FOR_USER ) ; 
 
			
		
	
		
			
				
					      ubl_has_control_of_lcd_panel  =  true ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      lcd_implementation_clear ( ) ; 
 
			
		
	
		
			
				
					      lcd_mesh_edit_setup ( new_z ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      wait_for_user  =  true ; 
 
			
		
	
		
			
				
					      do  { 
 
			
		
	
		
			
				
					        new_z  =  lcd_mesh_edit ( ) ; 
 
			
		
	
		
			
				
					        idle ( ) ; 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -1393,13 +1389,12 @@
 
			
		
	
		
			
				
					        idle ( ) ; 
 
			
		
	
		
			
				
					        if  ( ELAPSED ( millis ( ) ,  nxt ) )  { 
 
			
		
	
		
			
				
					          lcd_return_to_status ( ) ; 
 
			
		
	
		
			
				
					//          
			
		
	
		
			
				
					          //  SERIAL_PROTOCOLLNPGM("\nFine Tuning of Mesh Stopped.");
 
			
		
	
		
			
				
					          do_blocking_move_to_z ( Z_CLEARANCE_DEPLOY_PROBE ) ; 
 
			
		
	
		
			
				
					          lcd_setstatus ( " Mesh Editing Stopped " ,  true ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					          while  ( ubl_lcd_clicked ( ) )  idle ( ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					          ubl_has_control_of_lcd_panel  =  false ; 
 
			
		
	
		
			
				
					          goto  FINE_TUNE_EXIT ; 
 
			
		
	
		
			
				
					        } 
 
			
		
	
		
			
				
					      } 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -1415,6 +1410,7 @@
 
			
		
	
		
			
				
					    FINE_TUNE_EXIT : 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    ubl_has_control_of_lcd_panel  =  false ; 
 
			
		
	
		
			
				
					    KEEPALIVE_STATE ( IN_HANDLER ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    if  ( do_ubl_mesh_map )  ubl . display_map ( map_type ) ; 
 
			
		
	
		
			
				
					    restore_ubl_active_state_and_leave ( ) ;