@ -40,11 +40,14 @@
extern float destination [ XYZE ] , current_position [ XYZE ] ;
extern float destination [ XYZE ] , current_position [ XYZE ] ;
void lcd_return_to_status ( ) ;
# if ENABLED(NEWPANEL)
void lcd_mesh_edit_setup ( float initial ) ;
void lcd_return_to_status ( ) ;
float lcd_mesh_edit ( ) ;
void lcd_mesh_edit_setup ( float initial ) ;
void lcd_z_offset_edit_setup ( float ) ;
float lcd_mesh_edit ( ) ;
float lcd_z_offset_edit ( ) ;
void lcd_z_offset_edit_setup ( float ) ;
float lcd_z_offset_edit ( ) ;
# endif
extern float meshedit_done ;
extern float meshedit_done ;
extern long babysteps_done ;
extern long babysteps_done ;
extern float probe_pt ( const float & x , const float & y , bool , int ) ;
extern float probe_pt ( const float & x , const float & y , bool , int ) ;
@ -149,9 +152,10 @@
* parameter can be given to prioritize where the command should be trying to measure points .
* parameter can be given to prioritize where the command should be trying to measure points .
* If the X and Y parameters are not specified the current probe position is used .
* If the X and Y parameters are not specified the current probe position is used .
* P1 accepts a ' T ' ( Topology ) parameter so you can observe mesh generation .
* P1 accepts a ' T ' ( Topology ) parameter so you can observe mesh generation .
* P1 also watches for the LCD Panel Encoder Switch to be held down , and will suspend
* P1 also watches for the LCD Panel Encoder Switch to be held down ( assuming you have one ) ,
* generation of the Mesh in that case . ( Note : This check is only done between probe points ,
* and will suspend generation of the Mesh in that case . ( Note : This check is only done
* so you must press and hold the switch until the Phase 1 command detects it . )
* between probe points , so you must press and hold the switch until the Phase 1 command
* detects it . )
*
*
* P2 Phase 2 Probe areas of the Mesh that can ' t be automatically handled . Phase 2 respects an H
* P2 Phase 2 Probe areas of the Mesh that can ' t be automatically handled . Phase 2 respects an H
* parameter to control the height between Mesh points . The default height for movement
* parameter to control the height between Mesh points . The default height for movement
@ -187,6 +191,8 @@
* Phase 2 allows the T ( Map ) parameter to be specified . This helps the user see the progression
* Phase 2 allows the T ( Map ) parameter to be specified . This helps the user see the progression
* of the Mesh being built .
* of the Mesh being built .
*
*
* NOTE : P2 is not available unless you have LCD support enabled !
*
* P3 Phase 3 Fill the unpopulated regions of the Mesh with a fixed value . There are two different paths the
* P3 Phase 3 Fill the unpopulated regions of the Mesh with a fixed value . There are two different paths the
* user can go down . If the user specifies the value using the C parameter , the closest invalid
* user can go down . If the user specifies the value using the C parameter , the closest invalid
* mesh points to the nozzle will be filled . The user can specify a repeat count using the R
* mesh points to the nozzle will be filled . The user can specify a repeat count using the R
@ -204,8 +210,9 @@
* numbers . You should use some scrutiny and caution .
* numbers . You should use some scrutiny and caution .
*
*
* P4 Phase 4 Fine tune the Mesh . The Delta Mesh Compensation System assume the existence of
* P4 Phase 4 Fine tune the Mesh . The Delta Mesh Compensation System assume the existence of
* an LCD Panel . It is possible to fine tune the mesh without the use of an LCD Panel .
* an LCD Panel . It is possible to fine tune the mesh without the use of an LCD Panel using
* ( More work and details on doing this later ! )
* G42 and M421 ; see the UBL documentation for further details .
*
* The System will search for the closest Mesh Point to the nozzle . It will move the
* The System will search for the closest Mesh Point to the nozzle . It will move the
* nozzle to this location . The user can use the LCD Panel to carefully adjust the nozzle
* nozzle to this location . The user can use the LCD Panel to carefully adjust the nozzle
* so it is just barely touching the bed . When the user clicks the control , the System
* so it is just barely touching the bed . When the user clicks the control , the System
@ -228,6 +235,7 @@
* LOWER the Mesh Point at the location . If you did not get good adheasion , you want to
* LOWER the Mesh Point at the location . If you did not get good adheasion , you want to
* RAISE the Mesh Point at that location .
* RAISE the Mesh Point at that location .
*
*
* NOTE : P4 is not available unless you have LCD support enabled !
*
*
* P5 Phase 5 Find Mean Mesh Height and Standard Deviation . Typically , it is easier to use and
* P5 Phase 5 Find Mean Mesh Height and Standard Deviation . Typically , it is easier to use and
* work with the Mesh if it is Mean Adjusted . You can specify a C parameter to
* work with the Mesh if it is Mean Adjusted . You can specify a C parameter to
@ -452,52 +460,57 @@
break ;
break ;
case 2 : {
case 2 : {
//
# if ENABLED(NEWPANEL)
// Manually Probe Mesh in areas that can't be reached by the probe
//
//
// Manually Probe Mesh in areas that can't be reached by the probe
SERIAL_PROTOCOLLNPGM ( " Manually probing unreachable mesh locations. " ) ;
//
do_blocking_move_to_z ( Z_CLEARANCE_BETWEEN_PROBES ) ;
SERIAL_PROTOCOLLNPGM ( " Manually probing unreachable mesh locations. " ) ;
if ( ! g29_x_flag & & ! g29_y_flag ) {
do_blocking_move_to_z ( Z_CLEARANCE_BETWEEN_PROBES ) ;
/**
if ( ! g29_x_flag & & ! g29_y_flag ) {
* Use a good default location for the path .
/**
* The flipped > and < operators in these comparisons is intentional .
* Use a good default location for the path .
* It should cause the probed points to follow a nice path on Cartesian printers .
* The flipped > and < operators in these comparisons is intentional .
* It may make sense to have Delta printers default to the center of the bed .
* It should cause the probed points to follow a nice path on Cartesian printers .
* Until that is decided , this can be forced with the X and Y parameters .
* It may make sense to have Delta printers default to the center of the bed .
*/
* Until that is decided , this can be forced with the X and Y parameters .
# if IS_KINEMATIC
*/
g29_x_pos = X_HOME_POS ;
# if IS_KINEMATIC
g29_y_pos = Y_HOME_POS ;
g29_x_pos = X_HOME_POS ;
# else // cartesian
g29_y_pos = Y_HOME_POS ;
g29_x_pos = X_PROBE_OFFSET_FROM_EXTRUDER > 0 ? X_MAX_POS : X_MIN_POS ;
# else // cartesian
g29_y_pos = Y_PROBE_OFFSET_FROM_EXTRUDER < 0 ? Y_MAX_POS : Y_MIN_POS ;
g29_x_pos = X_PROBE_OFFSET_FROM_EXTRUDER > 0 ? X_MAX_POS : X_MIN_POS ;
# endif
g29_y_pos = Y_PROBE_OFFSET_FROM_EXTRUDER < 0 ? Y_MAX_POS : Y_MIN_POS ;
}
# endif
}
if ( parser . seen ( ' C ' ) ) {
if ( parser . seen ( ' C ' ) ) {
g29_x_pos = current_position [ X_AXIS ] ;
g29_x_pos = current_position [ X_AXIS ] ;
g29_y_pos = current_position [ Y_AXIS ] ;
g29_y_pos = current_position [ Y_AXIS ] ;
}
}
float height = Z_CLEARANCE_BETWEEN_PROBES ;
float height = Z_CLEARANCE_BETWEEN_PROBES ;
if ( parser . seen ( ' B ' ) ) {
if ( parser . seen ( ' B ' ) ) {
g29_card_thickness = parser . has_value ( ) ? parser . value_float ( ) : measure_business_card_thickness ( height ) ;
g29_card_thickness = parser . has_value ( ) ? parser . value_float ( ) : measure_business_card_thickness ( height ) ;
if ( fabs ( g29_card_thickness ) > 1.5 ) {
if ( fabs ( g29_card_thickness ) > 1.5 ) {
SERIAL_PROTOCOLLNPGM ( " ?Error in Business Card measurement. " ) ;
SERIAL_PROTOCOLLNPGM ( " ?Error in Business Card measurement. " ) ;
return ;
return ;
}
}
}
}
if ( parser . seen ( ' H ' ) & & parser . has_value ( ) ) height = parser . value_float ( ) ;
if ( parser . seen ( ' H ' ) & & parser . has_value ( ) ) height = parser . value_float ( ) ;
if ( ! position_is_reachable_xy ( g29_x_pos , g29_y_pos ) ) {
if ( ! position_is_reachable_xy ( g29_x_pos , g29_y_pos ) ) {
SERIAL_PROTOCOLLNPGM ( " XY outside printable radius. " ) ;
SERIAL_PROTOCOLLNPGM ( " XY outside printable radius. " ) ;
return ;
return ;
}
}
manually_probe_remaining_mesh ( g29_x_pos , g29_y_pos , height , g29_card_thickness , parser . seen ( ' T ' ) ) ;
manually_probe_remaining_mesh ( g29_x_pos , g29_y_pos , height , g29_card_thickness , parser . seen ( ' T ' ) ) ;
SERIAL_PROTOCOLLNPGM ( " G29 P2 finished. " ) ;
SERIAL_PROTOCOLLNPGM ( " G29 P2 finished. " ) ;
# else
SERIAL_PROTOCOLLNPGM ( " ?P2 is only available when an LCD is present. " ) ;
return ;
# endif
} break ;
} break ;
case 3 : {
case 3 : {
@ -557,11 +570,13 @@
break ;
break ;
}
}
case 4 :
case 4 : // Fine Tune (i.e., Edit) the Mesh
//
# if ENABLED(NEWPANEL)
// Fine Tune (i.e., Edit) the Mesh
fine_tune_mesh ( g29_x_pos , g29_y_pos , parser . seen ( ' T ' ) ) ;
//
# else
fine_tune_mesh ( g29_x_pos , g29_y_pos , parser . seen ( ' T ' ) ) ;
SERIAL_PROTOCOLLNPGM ( " ?P4 is only available when an LCD is present. " ) ;
return ;
# endif
break ;
break ;
case 5 : find_mean_mesh_height ( ) ; break ;
case 5 : find_mean_mesh_height ( ) ; break ;
@ -716,11 +731,15 @@
LEAVE :
LEAVE :
lcd_reset_alert_level ( ) ;
# if ENABLED(NEWPANEL)
LCD_MESSAGEPGM ( " " ) ;
lcd_reset_alert_level ( ) ;
lcd_quick_feedback ( ) ;
LCD_MESSAGEPGM ( " " ) ;
lcd_quick_feedback ( ) ;
has_control_of_lcd_panel = false ;
has_control_of_lcd_panel = false ;
# endif
return ;
}
}
void unified_bed_leveling : : find_mean_mesh_height ( ) {
void unified_bed_leveling : : find_mean_mesh_height ( ) {
@ -782,16 +801,18 @@
uint16_t max_iterations = GRID_MAX_POINTS ;
uint16_t max_iterations = GRID_MAX_POINTS ;
do {
do {
if ( ubl_lcd_clicked ( ) ) {
# if ENABLED(NEWPANEL)
SERIAL_PROTOCOLLNPGM ( " \n Mesh only partially populated. \n " ) ;
if ( ubl_lcd_clicked ( ) ) {
lcd_quick_feedback ( ) ;
SERIAL_PROTOCOLLNPGM ( " \n Mesh only partially populated. \n " ) ;
STOW_PROBE ( ) ;
lcd_quick_feedback ( ) ;
while ( ubl_lcd_clicked ( ) ) idle ( ) ;
STOW_PROBE ( ) ;
has_control_of_lcd_panel = false ;
while ( ubl_lcd_clicked ( ) ) idle ( ) ;
restore_ubl_active_state_and_leave ( ) ;
has_control_of_lcd_panel = false ;
safe_delay ( 50 ) ; // Debounce the Encoder wheel
restore_ubl_active_state_and_leave ( ) ;
return ;
safe_delay ( 50 ) ; // Debounce the Encoder wheel
}
return ;
}
# endif
location = find_closest_mesh_point_of_type ( INVALID , lx , ly , USE_PROBE_AS_REFERENCE , NULL , close_or_far ) ;
location = find_closest_mesh_point_of_type ( INVALID , lx , ly , USE_PROBE_AS_REFERENCE , NULL , close_or_far ) ;
@ -920,155 +941,165 @@
}
}
}
}
float unified_bed_leveling : : measure_point_with_encoder ( ) {
# if ENABLED(NEWPANEL)
float unified_bed_leveling : : measure_point_with_encoder ( ) {
while ( ubl_lcd_clicked ( ) ) delay ( 50 ) ; // wait for user to release encoder wheel
while ( ubl_lcd_clicked ( ) ) delay ( 50 ) ; // wait for user to release encoder wheel
delay ( 50 ) ; // debounce
delay ( 50 ) ; // debounce
KEEPALIVE_STATE ( PAUSED_FOR_USER ) ;
KEEPALIVE_STATE ( PAUSED_FOR_USER ) ;
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 ( ) ;
idle ( ) ;
if ( encoder_diff ) {
if ( encoder_diff ) {
do_blocking_move_to_z ( current_position [ Z_AXIS ] + 0.01 * float ( encoder_diff ) ) ;
do_blocking_move_to_z ( current_position [ Z_AXIS ] + 0.01 * float ( encoder_diff ) ) ;
encoder_diff = 0 ;
encoder_diff = 0 ;
}
}
}
KEEPALIVE_STATE ( IN_HANDLER ) ;
return current_position [ Z_AXIS ] ;
}
}
KEEPALIVE_STATE ( IN_HANDLER ) ;
return current_position [ Z_AXIS ] ;
}
static void echo_and_take_a_measurement ( ) { SERIAL_PROTOCOLLNPGM ( " and take a measurement. " ) ; }
static void echo_and_take_a_measurement ( ) { SERIAL_PROTOCOLLNPGM ( " and take a measurement. " ) ; }
float unified_bed_leveling : : measure_business_card_thickness ( float & in_height ) {
float unified_bed_leveling : : measure_business_card_thickness ( float & in_height ) {
has_control_of_lcd_panel = true ;
has_control_of_lcd_panel = true ;
save_ubl_active_state_and_disable ( ) ; // Disable bed level correction for probing
save_ubl_active_state_and_disable ( ) ; // Disable bed level correction for probing
do_blocking_move_to_z ( in_height ) ;
do_blocking_move_to_z ( in_height ) ;
do_blocking_move_to_xy ( 0.5 * ( UBL_MESH_MAX_X - ( UBL_MESH_MIN_X ) ) , 0.5 * ( UBL_MESH_MAX_Y - ( UBL_MESH_MIN_Y ) ) ) ;
do_blocking_move_to_xy ( 0.5 * ( UBL_MESH_MAX_X - ( UBL_MESH_MIN_X ) ) , 0.5 * ( UBL_MESH_MAX_Y - ( UBL_MESH_MIN_Y ) ) ) ;
//, min(planner.max_feedrate_mm_s[X_AXIS], planner.max_feedrate_mm_s[Y_AXIS]) / 2.0);
//, min(planner.max_feedrate_mm_s[X_AXIS], planner.max_feedrate_mm_s[Y_AXIS]) / 2.0);
stepper . synchronize ( ) ;
stepper . synchronize ( ) ;
SERIAL_PROTOCOLPGM ( " Place shim under nozzle " ) ;
SERIAL_PROTOCOLPGM ( " Place shim under nozzle " ) ;
LCD_MESSAGEPGM ( " Place shim & measure " ) ; // TODO: Make translatable string
LCD_MESSAGEPGM ( " Place shim & measure " ) ; // TODO: Make translatable string
lcd_return_to_status ( ) ;
lcd_return_to_status ( ) ;
echo_and_take_a_measurement ( ) ;
echo_and_take_a_measurement ( ) ;
const float z1 = measure_point_with_encoder ( ) ;
const float z1 = measure_point_with_encoder ( ) ;
do_blocking_move_to_z ( current_position [ Z_AXIS ] + SIZE_OF_LITTLE_RAISE ) ;
do_blocking_move_to_z ( current_position [ Z_AXIS ] + SIZE_OF_LITTLE_RAISE ) ;
stepper . synchronize ( ) ;
stepper . synchronize ( ) ;
SERIAL_PROTOCOLPGM ( " Remove shim " ) ;
SERIAL_PROTOCOLPGM ( " Remove shim " ) ;
LCD_MESSAGEPGM ( " Remove & measure bed " ) ; // TODO: Make translatable string
LCD_MESSAGEPGM ( " Remove & measure bed " ) ; // TODO: Make translatable string
echo_and_take_a_measurement ( ) ;
echo_and_take_a_measurement ( ) ;
const float z2 = measure_point_with_encoder ( ) ;
const float z2 = measure_point_with_encoder ( ) ;
do_blocking_move_to_z ( current_position [ Z_AXIS ] + Z_CLEARANCE_BETWEEN_PROBES ) ;
do_blocking_move_to_z ( current_position [ Z_AXIS ] + Z_CLEARANCE_BETWEEN_PROBES ) ;
const float thickness = abs ( z1 - z2 ) ;
const float thickness = abs ( z1 - z2 ) ;
if ( g29_verbose_level > 1 ) {
if ( g29_verbose_level > 1 ) {
SERIAL_PROTOCOLPGM ( " Business Card is " ) ;
SERIAL_PROTOCOLPGM ( " Business Card is " ) ;
SERIAL_PROTOCOL_F ( thickness , 4 ) ;
SERIAL_PROTOCOL_F ( thickness , 4 ) ;
SERIAL_PROTOCOLLNPGM ( " mm thick. " ) ;
SERIAL_PROTOCOLLNPGM ( " mm thick. " ) ;
}
}
in_height = current_position [ Z_AXIS ] ; // do manual probing at lower height
in_height = current_position [ Z_AXIS ] ; // do manual probing at lower height
has_control_of_lcd_panel = false ;
has_control_of_lcd_panel = false ;
restore_ubl_active_state_and_leave ( ) ;
restore_ubl_active_state_and_leave ( ) ;
return thickness ;
return thickness ;
}
}
void unified_bed_leveling : : manually_probe_remaining_mesh ( const float & lx , const float & ly , const float & z_clearance , const float & thick , const bool do_ubl_mesh_map ) {
void unified_bed_leveling : : manually_probe_remaining_mesh ( const float & lx , const float & ly , const float & z_clearance , const float & thick , const bool do_ubl_mesh_map ) {
has_control_of_lcd_panel = true ;
has_control_of_lcd_panel = true ;
save_ubl_active_state_and_disable ( ) ; // we don't do bed level correction because we want the raw data when we probe
do_blocking_move_to_z ( Z_CLEARANCE_BETWEEN_PROBES ) ;
do_blocking_move_to_xy ( lx , ly ) ;
lcd_return_to_status ( ) ;
save_ubl_active_state_and_disable ( ) ; // we don't do bed level correction because we want the raw data when we probe
mesh_index_pair location ;
do_blocking_move_to_z ( Z_CLEARANCE_BETWEEN_PROBES ) ;
do {
do_blocking_move_to_xy ( lx , ly ) ;
location = find_closest_mesh_point_of_type ( INVALID , lx , ly , USE_NOZZLE_AS_REFERENCE , NULL , false ) ;
// 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 rawx = mesh_index_to_xpos ( location . x_index ) ,
lcd_return_to_status ( ) ;
rawy = mesh_index_to_ypos ( location . y_index ) ,
xProbe = LOGICAL_X_POSITION ( rawx ) ,
yProbe = LOGICAL_Y_POSITION ( rawy ) ;
if ( ! position_is_reachable_raw_xy ( rawx , rawy ) ) break ; // SHOULD NOT OCCUR (find_closest_mesh_point only returns reachable points)
mesh_index_pair location ;
do {
location = find_closest_mesh_point_of_type ( INVALID , lx , ly , USE_NOZZLE_AS_REFERENCE , NULL , false ) ;
// 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 ;
do_blocking_move_to_z ( Z_CLEARANCE_BETWEEN_PROBES ) ;
const float rawx = mesh_index_to_xpos ( location . x_index ) ,
rawy = mesh_index_to_ypos ( location . y_index ) ,
xProbe = LOGICAL_X_POSITION ( rawx ) ,
yProbe = LOGICAL_Y_POSITION ( rawy ) ;
LCD_MESSAGEPGM ( " Moving to next " ) ; // TODO: Make translatable string
if ( ! position_is_reachable_raw_xy ( rawx , rawy ) ) break ; // SHOULD NOT OCCUR (find_closest_mesh_point only returns reachable points)
do_blocking_move_to_xy ( xProbe , yProbe ) ;
do_blocking_move_to_z ( Z_CLEARANCE_BETWEEN_PROBES ) ;
do_blocking_move_to_z ( z_clearance ) ;
KEEPALIVE_STATE ( PAUSED_FOR_USER ) ;
LCD_MESSAGEPGM ( " Moving to next " ) ; // TODO: Make translatable string
has_control_of_lcd_panel = true ;
do_blocking_move_to_xy ( xProbe , yProbe ) ;
do_blocking_move_to_z ( z_clearance ) ;
if ( do_ubl_mesh_map ) display_map ( g29_map_type ) ; // show user where we're probing
KEEPALIVE_STATE ( PAUSED_FOR_USER ) ;
has_control_of_lcd_panel = true ;
serialprintPGM ( parser . seen ( ' B ' ) ? PSTR ( " Place shim & measure " ) : PSTR ( " Measure " ) ) ; // TODO: Make translatable strings
if ( do_ubl_mesh_map ) display_map ( g29_map_type ) ; // show user where we're probing
const float z_step = 0.01 ; // existing behavior: 0.01mm per click, occasionally step
serialprintPGM ( parser . seen ( ' B ' ) ? PSTR ( " Place shim & measure " ) : PSTR ( " Measure " ) ) ; // TODO: Make translatable strings
//const float z_step = 1.0 / planner.axis_steps_per_mm[Z_AXIS]; // approx one step each click
while ( ubl_lcd_clicked ( ) ) delay ( 50 ) ; // wait for user to release encoder wheel
const float z_step = 0.01 ; // existing behavior: 0.01mm per click, occasionally step
delay ( 50 ) ; // debounce
//const float z_step = 1.0 / planner.axis_steps_per_mm[Z_AXIS]; // approx one step each click
while ( ! ubl_lcd_clicked ( ) ) { // we need the loop to move the nozzle based on the encoder wheel here!
idle ( ) ;
while ( ubl_lcd_clicked ( ) ) delay ( 50 ) ; // wait for user to release encoder wheel
if ( encoder_diff ) {
delay ( 50 ) ; // debounce
do_blocking_move_to_z ( current_position [ Z_AXIS ] + float ( encoder_diff ) * z_step ) ;
while ( ! ubl_lcd_clicked ( ) ) { // we need the loop to move the nozzle based on the encoder wheel here!
encoder_diff = 0 ;
idle ( ) ;
if ( encoder_diff ) {
do_blocking_move_to_z ( current_position [ Z_AXIS ] + float ( encoder_diff ) * z_step ) ;
encoder_diff = 0 ;
}
}
}
}
// this sequence to detect an ubl_lcd_clicked() debounce it and leave if it is
// this sequence to detect an ubl_lcd_clicked() debounce it and leave if it is
// a Press and Hold is repeated in a lot of places (including G26_Mesh_Validation.cpp). This
// a Press and Hold is repeated in a lot of places (including G26_Mesh_Validation.cpp). This
// should be redone and compressed.
// should be redone and compressed.
const millis_t nxt = millis ( ) + 1500L ;
const millis_t nxt = millis ( ) + 1500L ;
while ( ubl_lcd_clicked ( ) ) { // debounce and watch for abort
while ( ubl_lcd_clicked ( ) ) { // debounce and watch for abort
idle ( ) ;
idle ( ) ;
if ( ELAPSED ( millis ( ) , nxt ) ) {
if ( ELAPSED ( millis ( ) , nxt ) ) {
SERIAL_PROTOCOLLNPGM ( " \n Mesh only partially populated. " ) ;
SERIAL_PROTOCOLLNPGM ( " \n Mesh only partially populated. " ) ;
do_blocking_move_to_z ( Z_CLEARANCE_DEPLOY_PROBE ) ;
do_blocking_move_to_z ( Z_CLEARANCE_DEPLOY_PROBE ) ;
lcd_quick_feedback ( ) ;
while ( ubl_lcd_clicked ( ) ) idle ( ) ;
# if ENABLED(NEWPANEL)
has_control_of_lcd_panel = false ;
lcd_quick_feedback ( ) ;
KEEPALIVE_STATE ( IN_HANDLER ) ;
while ( ubl_lcd_clicked ( ) ) idle ( ) ;
restore_ubl_active_state_and_leave ( ) ;
has_control_of_lcd_panel = false ;
return ;
# endif
KEEPALIVE_STATE ( IN_HANDLER ) ;
restore_ubl_active_state_and_leave ( ) ;
return ;
}
}
}
}
z_values [ location . x_index ] [ location . y_index ] = current_position [ Z_AXIS ] - thick ;
z_values [ location . x_index ] [ location . y_index ] = current_position [ Z_AXIS ] - thick ;
if ( g29_verbose_level > 2 ) {
if ( g29_verbose_level > 2 ) {
SERIAL_PROTOCOLPGM ( " Mesh Point Measured at: " ) ;
SERIAL_PROTOCOLPGM ( " Mesh Point Measured at: " ) ;
SERIAL_PROTOCOL_F ( z_values [ location . x_index ] [ location . y_index ] , 6 ) ;
SERIAL_PROTOCOL_F ( z_values [ location . x_index ] [ location . y_index ] , 6 ) ;
SERIAL_EOL ;
SERIAL_EOL ;
}
}
} while ( location . x_index > = 0 & & location . y_index > = 0 ) ;
} while ( location . x_index > = 0 & & location . y_index > = 0 ) ;
if ( do_ubl_mesh_map ) display_map ( g29_map_type ) ;
if ( do_ubl_mesh_map ) display_map ( g29_map_type ) ;
restore_ubl_active_state_and_leave ( ) ;
restore_ubl_active_state_and_leave ( ) ;
KEEPALIVE_STATE ( IN_HANDLER ) ;
KEEPALIVE_STATE ( IN_HANDLER ) ;
do_blocking_move_to_z ( Z_CLEARANCE_DEPLOY_PROBE ) ;
do_blocking_move_to_z ( Z_CLEARANCE_DEPLOY_PROBE ) ;
do_blocking_move_to_xy ( lx , ly ) ;
do_blocking_move_to_xy ( lx , ly ) ;
}
}
# endif
bool unified_bed_leveling : : g29_parameter_parsing ( ) {
bool unified_bed_leveling : : g29_parameter_parsing ( ) {
bool err_flag = false ;
bool err_flag = false ;
LCD_MESSAGEPGM ( " Doing G29 UBL! " ) ; // TODO: Make translatable string
# if ENABLED(NEWPANEL)
lcd_quick_feedback ( ) ;
LCD_MESSAGEPGM ( " Doing G29 UBL! " ) ; // TODO: Make translatable string
lcd_quick_feedback ( ) ;
# endif
g29_constant = 0.0 ;
g29_constant = 0.0 ;
g29_repetition_cnt = 0 ;
g29_repetition_cnt = 0 ;
@ -1174,8 +1205,12 @@
ubl_state_recursion_chk + + ;
ubl_state_recursion_chk + + ;
if ( ubl_state_recursion_chk ! = 1 ) {
if ( ubl_state_recursion_chk ! = 1 ) {
SERIAL_ECHOLNPGM ( " save_ubl_active_state_and_disabled() called multiple times in a row. " ) ;
SERIAL_ECHOLNPGM ( " save_ubl_active_state_and_disabled() called multiple times in a row. " ) ;
LCD_MESSAGEPGM ( " save_UBL_active() error " ) ; // TODO: Make translatable string
lcd_quick_feedback ( ) ;
# if ENABLED(NEWPANEL)
LCD_MESSAGEPGM ( " save_UBL_active() error " ) ; // TODO: Make translatable string
lcd_quick_feedback ( ) ;
# endif
return ;
return ;
}
}
ubl_state_at_invocation = state . active ;
ubl_state_at_invocation = state . active ;
@ -1185,8 +1220,12 @@
void unified_bed_leveling : : restore_ubl_active_state_and_leave ( ) {
void unified_bed_leveling : : restore_ubl_active_state_and_leave ( ) {
if ( - - ubl_state_recursion_chk ) {
if ( - - ubl_state_recursion_chk ) {
SERIAL_ECHOLNPGM ( " restore_ubl_active_state_and_leave() called too many times. " ) ;
SERIAL_ECHOLNPGM ( " restore_ubl_active_state_and_leave() called too many times. " ) ;
LCD_MESSAGEPGM ( " restore_UBL_active() error " ) ; // TODO: Make translatable string
lcd_quick_feedback ( ) ;
# if ENABLED(NEWPANEL)
LCD_MESSAGEPGM ( " restore_UBL_active() error " ) ; // TODO: Make translatable string
lcd_quick_feedback ( ) ;
# endif
return ;
return ;
}
}
set_bed_leveling_enabled ( ubl_state_at_invocation ) ;
set_bed_leveling_enabled ( ubl_state_at_invocation ) ;
@ -1420,114 +1459,116 @@
return out_mesh ;
return out_mesh ;
}
}
void unified_bed_leveling : : fine_tune_mesh ( const float & lx , const float & ly , const bool do_ubl_mesh_map ) {
# if ENABLED(NEWPANEL)
if ( ! parser . seen ( ' R ' ) ) // fine_tune_mesh() is special. If no repetition count flag is specified
void unified_bed_leveling : : fine_tune_mesh ( const float & lx , const float & ly , const bool do_ubl_mesh_map ) {
g29_repetition_cnt = 1 ; // do exactly one mesh location. Otherwise use what the parser decided.
if ( ! parser . seen ( ' R ' ) ) // fine_tune_mesh() is special. If no repetition count flag is specified
g29_repetition_cnt = 1 ; // do exactly one mesh location. Otherwise use what the parser decided.
mesh_index_pair location ;
mesh_index_pair location ;
uint16_t not_done [ 16 ] ;
uint16_t not_done [ 16 ] ;
if ( ! position_is_reachable_xy ( lx , ly ) ) {
if ( ! position_is_reachable_xy ( lx , ly ) ) {
SERIAL_PROTOCOLLNPGM ( " (X,Y) outside printable radius. " ) ;
SERIAL_PROTOCOLLNPGM ( " (X,Y) outside printable radius. " ) ;
return ;
return ;
}
}
save_ubl_active_state_and_disable ( ) ;
save_ubl_active_state_and_disable ( ) ;
memset ( not_done , 0xFF , sizeof ( not_done ) ) ;
memset ( not_done , 0xFF , sizeof ( not_done ) ) ;
LCD_MESSAGEPGM ( " Fine Tuning Mesh " ) ; // TODO: Make translatable string
LCD_MESSAGEPGM ( " Fine Tuning Mesh " ) ; // TODO: Make translatable string
do_blocking_move_to_z ( Z_CLEARANCE_BETWEEN_PROBES ) ;
do_blocking_move_to_z ( Z_CLEARANCE_BETWEEN_PROBES ) ;
do_blocking_move_to_xy ( lx , ly ) ;
do_blocking_move_to_xy ( lx , ly ) ;
do {
do {
location = find_closest_mesh_point_of_type ( SET_IN_BITMAP , lx , ly , USE_NOZZLE_AS_REFERENCE , not_done , false ) ;
location = find_closest_mesh_point_of_type ( SET_IN_BITMAP , lx , ly , USE_NOZZLE_AS_REFERENCE , not_done , false ) ;
if ( location . x_index < 0 ) break ; // stop when we can't find any more reachable points.
if ( location . x_index < 0 ) break ; // stop when we can't find any more reachable points.
bit_clear ( not_done , location . x_index , location . y_index ) ; // Mark this location as 'adjusted' so we will find a
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
// different location the next time through the loop
const float rawx = mesh_index_to_xpos ( location . x_index ) ,
const float rawx = mesh_index_to_xpos ( location . x_index ) ,
rawy = mesh_index_to_ypos ( location . y_index ) ;
rawy = mesh_index_to_ypos ( location . y_index ) ;
if ( ! position_is_reachable_raw_xy ( rawx , rawy ) ) // SHOULD NOT OCCUR because find_closest_mesh_point_of_type will only return reachable
if ( ! position_is_reachable_raw_xy ( rawx , rawy ) ) // SHOULD NOT OCCUR because find_closest_mesh_point_of_type will only return reachable
break ;
break ;
float new_z = z_values [ location . x_index ] [ location . y_index ] ;
float new_z = z_values [ location . x_index ] [ location . y_index ] ;
if ( isnan ( new_z ) ) // if the mesh point is invalid, set it to 0.0 so it can be edited
if ( isnan ( new_z ) ) // if the mesh point is invalid, set it to 0.0 so it can be edited
new_z = 0.0 ;
new_z = 0.0 ;
do_blocking_move_to_z ( Z_CLEARANCE_BETWEEN_PROBES ) ; // Move the nozzle to where we are going to edit
do_blocking_move_to_z ( Z_CLEARANCE_BETWEEN_PROBES ) ; // Move the nozzle to where we are going to edit
do_blocking_move_to_xy ( LOGICAL_X_POSITION ( rawx ) , LOGICAL_Y_POSITION ( rawy ) ) ;
do_blocking_move_to_xy ( LOGICAL_X_POSITION ( rawx ) , LOGICAL_Y_POSITION ( rawy ) ) ;
new_z = floor ( new_z * 1000.0 ) * 0.001 ; // Chop off digits after the 1000ths place
new_z = floor ( new_z * 1000.0 ) * 0.001 ; // Chop off digits after the 1000ths place
KEEPALIVE_STATE ( PAUSED_FOR_USER ) ;
KEEPALIVE_STATE ( PAUSED_FOR_USER ) ;
has_control_of_lcd_panel = true ;
has_control_of_lcd_panel = true ;
if ( do_ubl_mesh_map ) display_map ( g29_map_type ) ; // show the user which point is being adjusted
if ( do_ubl_mesh_map ) display_map ( g29_map_type ) ; // show the user which point is being adjusted
lcd_refresh ( ) ;
lcd_refresh ( ) ;
lcd_mesh_edit_setup ( new_z ) ;
lcd_mesh_edit_setup ( new_z ) ;
do {
do {
new_z = lcd_mesh_edit ( ) ;
new_z = lcd_mesh_edit ( ) ;
# ifdef UBL_MESH_EDIT_MOVES_Z
# ifdef UBL_MESH_EDIT_MOVES_Z
do_blocking_move_to_z ( Z_CLEARANCE_BETWEEN_PROBES + new_z ) ; // Move the nozzle as the point is edited
do_blocking_move_to_z ( Z_CLEARANCE_BETWEEN_PROBES + new_z ) ; // Move the nozzle as the point is edited
# endif
# endif
idle ( ) ;
idle ( ) ;
} while ( ! ubl_lcd_clicked ( ) ) ;
} while ( ! ubl_lcd_clicked ( ) ) ;
lcd_return_to_status ( ) ;
lcd_return_to_status ( ) ;
// The technique used here generates a race condition for the encoder click.
// The technique used here generates a race condition for the encoder click.
// It could get detected in lcd_mesh_edit (actually _lcd_mesh_fine_tune) or here.
// It could get detected in lcd_mesh_edit (actually _lcd_mesh_fine_tune) or here.
// Let's work on specifying a proper API for the LCD ASAP, OK?
// Let's work on specifying a proper API for the LCD ASAP, OK?
has_control_of_lcd_panel = true ;
has_control_of_lcd_panel = true ;
// this sequence to detect an ubl_lcd_clicked() debounce it and leave if it is
// this sequence to detect an ubl_lcd_clicked() debounce it and leave if it is
// a Press and Hold is repeated in a lot of places (including G26_Mesh_Validation.cpp). This
// a Press and Hold is repeated in a lot of places (including G26_Mesh_Validation.cpp). This
// should be redone and compressed.
// should be redone and compressed.
const millis_t nxt = millis ( ) + 1500UL ;
const millis_t nxt = millis ( ) + 1500UL ;
while ( ubl_lcd_clicked ( ) ) { // debounce and watch for abort
while ( ubl_lcd_clicked ( ) ) { // debounce and watch for abort
idle ( ) ;
idle ( ) ;
if ( ELAPSED ( millis ( ) , nxt ) ) {
if ( ELAPSED ( millis ( ) , nxt ) ) {
lcd_return_to_status ( ) ;
lcd_return_to_status ( ) ;
//SERIAL_PROTOCOLLNPGM("\nFine Tuning of Mesh Stopped.");
//SERIAL_PROTOCOLLNPGM("\nFine Tuning of Mesh Stopped.");
do_blocking_move_to_z ( Z_CLEARANCE_BETWEEN_PROBES ) ;
do_blocking_move_to_z ( Z_CLEARANCE_BETWEEN_PROBES ) ;
LCD_MESSAGEPGM ( " Mesh Editing Stopped " ) ; // TODO: Make translatable string
LCD_MESSAGEPGM ( " Mesh Editing Stopped " ) ; // TODO: Make translatable string
while ( ubl_lcd_clicked ( ) ) idle ( ) ;
while ( ubl_lcd_clicked ( ) ) idle ( ) ;
goto FINE_TUNE_EXIT ;
goto FINE_TUNE_EXIT ;
}
}
}
}
safe_delay ( 20 ) ; // We don't want any switch noise.
safe_delay ( 20 ) ; // We don't want any switch noise.
z_values [ location . x_index ] [ location . y_index ] = new_z ;
z_values [ location . x_index ] [ location . y_index ] = new_z ;
lcd_refresh ( ) ;
lcd_refresh ( ) ;
} while ( location . x_index > = 0 & & - - g29_repetition_cnt > 0 ) ;
} while ( location . x_index > = 0 & & - - g29_repetition_cnt > 0 ) ;
FINE_TUNE_EXIT :
FINE_TUNE_EXIT :
has_control_of_lcd_panel = false ;
has_control_of_lcd_panel = false ;
KEEPALIVE_STATE ( IN_HANDLER ) ;
KEEPALIVE_STATE ( IN_HANDLER ) ;
if ( do_ubl_mesh_map ) display_map ( g29_map_type ) ;
if ( do_ubl_mesh_map ) display_map ( g29_map_type ) ;
restore_ubl_active_state_and_leave ( ) ;
restore_ubl_active_state_and_leave ( ) ;
do_blocking_move_to_z ( Z_CLEARANCE_BETWEEN_PROBES ) ;
do_blocking_move_to_z ( Z_CLEARANCE_BETWEEN_PROBES ) ;
do_blocking_move_to_xy ( lx , ly ) ;
do_blocking_move_to_xy ( lx , ly ) ;
LCD_MESSAGEPGM ( " Done Editing Mesh " ) ; // TODO: Make translatable string
LCD_MESSAGEPGM ( " Done Editing Mesh " ) ; // TODO: Make translatable string
SERIAL_ECHOLNPGM ( " Done Editing Mesh " ) ;
SERIAL_ECHOLNPGM ( " Done Editing Mesh " ) ;
}
}
# endif
/**
/**
* ' Smart Fill ' : Scan from the outward edges of the mesh towards the center .
* ' Smart Fill ' : Scan from the outward edges of the mesh towards the center .