@ -53,7 +53,6 @@
extern float destination [ XYZE ] , current_position [ XYZE ] ;
# if HAS_LCD_MENU
void lcd_return_to_status ( ) ;
void _lcd_ubl_output_map_lcd ( ) ;
# endif
@ -345,9 +344,13 @@
}
SERIAL_PROTOCOLLNPGM ( " Loading test_pattern values. \n " ) ;
switch ( test_pattern ) {
case - 1 :
g29_eeprom_dump ( ) ;
break ;
# if ENABLED(UBL_DEVEL_DEBUGGING)
case - 1 :
g29_eeprom_dump ( ) ;
break ;
# endif
case 0 :
for ( uint8_t x = 0 ; x < GRID_MAX_POINTS_X ; x + + ) { // Create a bowl shape - similar to
for ( uint8_t y = 0 ; y < GRID_MAX_POINTS_Y ; y + + ) { // a poorly calibrated Delta.
@ -357,12 +360,14 @@
}
}
break ;
case 1 :
for ( uint8_t x = 0 ; x < GRID_MAX_POINTS_X ; x + + ) { // Create a diagonal line several Mesh cells thick that is raised
z_values [ x ] [ x ] + = 9.999f ;
z_values [ x ] [ x + ( x < GRID_MAX_POINTS_Y - 1 ) ? 1 : - 1 ] + = 9.999f ; // We want the altered line several mesh points thick
}
break ;
case 2 :
// Allow the user to specify the height because 10mm is a little extreme in some cases.
for ( uint8_t x = ( GRID_MAX_POINTS_X ) / 3 ; x < 2 * ( GRID_MAX_POINTS_X ) / 3 ; x + + ) // Create a rectangular raised area in
@ -554,19 +559,24 @@
}
}
//
// Much of the 'What?' command can be eliminated. But until we are fully debugged, it is
// good to have the extra information. Soon... we prune this to just a few items
//
if ( parser . seen ( ' W ' ) ) g29_what_command ( ) ;
# if ENABLED(UBL_DEVEL_DEBUGGING)
//
// When we are fully debugged, this may go away. But there are some valid
// use cases for the users. So we can wait and see what to do with it.
//
//
// Much of the 'What?' command can be eliminated. But until we are fully debugged, it is
// good to have the extra information. Soon... we prune this to just a few items
//
if ( parser . seen ( ' W ' ) ) g29_what_command ( ) ;
//
// When we are fully debugged, this may go away. But there are some valid
// use cases for the users. So we can wait and see what to do with it.
//
if ( parser . seen ( ' K ' ) ) // Kompare Current Mesh Data to Specified Stored Mesh
g29_compare_current_mesh_to_stored_mesh ( ) ;
# endif // UBL_DEVEL_DEBUGGING
if ( parser . seen ( ' K ' ) ) // Kompare Current Mesh Data to Specified Stored Mesh
g29_compare_current_mesh_to_stored_mesh ( ) ;
//
// Load a Mesh from the EEPROM
@ -629,10 +639,10 @@
LEAVE :
# if HAS_LCD_MENU
lcd_ reset_alert_level( ) ;
lcd_ quick_feedback( ) ;
lcd_ reset_status( ) ;
lcd_external_control = false ;
ui . reset_alert_level ( ) ;
ui . quick_feedback ( ) ;
ui . reset_status ( ) ;
ui . release ( ) ;
# endif
return ;
@ -683,30 +693,6 @@
z_values [ x ] [ y ] + = g29_constant ;
}
# if HAS_LCD_MENU
typedef void ( * clickFunc_t ) ( ) ;
bool click_and_hold ( const clickFunc_t func = NULL ) {
if ( is_lcd_clicked ( ) ) {
lcd_quick_feedback ( false ) ; // Preserve button state for click-and-hold
const millis_t nxt = millis ( ) + 1500UL ;
while ( is_lcd_clicked ( ) ) { // Loop while the encoder is pressed. Uses hardware flag!
idle ( ) ; // idle, of course
if ( ELAPSED ( millis ( ) , nxt ) ) { // After 1.5 seconds
lcd_quick_feedback ( ) ;
if ( func ) ( * func ) ( ) ;
wait_for_release ( ) ;
return true ;
}
}
}
safe_delay ( 15 ) ;
return false ;
}
# endif // HAS_LCD_MENU
# if HAS_BED_PROBE
/**
* Probe all invalidated locations of the mesh that can be reached by the probe .
@ -716,10 +702,10 @@
mesh_index_pair location ;
# if HAS_LCD_MENU
lcd_external_control = true ;
ui . capture ( ) ;
# endif
save_ubl_active_state_and_disable ( ) ; // No bed level correction so only raw data is obtained
save_ubl_active_state_and_disable ( ) ; // No bed level correction so only raw data is obtained
DEPLOY_PROBE ( ) ;
uint16_t count = GRID_MAX_POINTS ;
@ -728,13 +714,13 @@
if ( do_ubl_mesh_map ) display_map ( g29_map_type ) ;
# if HAS_LCD_MENU
if ( is_lcd_click ed( ) ) {
lcd_ quick_feedback( false ) ; // Preserve button state for click-and-hold
if ( ui . button_press ed( ) ) {
ui . quick_feedback ( false ) ; // Preserve button state for click-and-hold
SERIAL_PROTOCOLLNPGM ( " \n Mesh only partially populated. \n " ) ;
STOW_PROBE ( ) ;
wait_for_release ( ) ;
lcd_ quick_feedback( ) ;
lcd_external_control = false ;
ui . wait_for_release ( ) ;
ui . quick_feedback ( ) ;
ui . release ( ) ;
restore_ubl_active_state_and_leave ( ) ;
return ;
}
@ -769,14 +755,33 @@
) ;
}
# endif // HAS_BED_PROBE
# if HAS_LCD_MENU
typedef void ( * clickFunc_t ) ( ) ;
bool click_and_hold ( const clickFunc_t func = NULL ) {
if ( ui . button_pressed ( ) ) {
ui . quick_feedback ( false ) ; // Preserve button state for click-and-hold
const millis_t nxt = millis ( ) + 1500UL ;
while ( ui . button_pressed ( ) ) { // Loop while the encoder is pressed. Uses hardware flag!
idle ( ) ; // idle, of course
if ( ELAPSED ( millis ( ) , nxt ) ) { // After 1.5 seconds
ui . quick_feedback ( ) ;
if ( func ) ( * func ) ( ) ;
ui . wait_for_release ( ) ;
return true ;
}
}
}
safe_delay ( 15 ) ;
return false ;
}
void unified_bed_leveling : : move_z_with_encoder ( const float & multiplier ) {
wait_for_release ( ) ;
while ( ! is_lcd_clicked ( ) ) {
ui . wait_for_release ( ) ;
while ( ! ui . button_press ed( ) ) {
idle ( ) ;
gcode . reset_stepper_timeout ( ) ; // Keep steppers powered
if ( encoder_diff ) {
@ -796,7 +801,7 @@
static void echo_and_take_a_measurement ( ) { SERIAL_PROTOCOLLNPGM ( " and take a measurement. " ) ; }
float unified_bed_leveling : : measure_business_card_thickness ( float in_height ) {
lcd_external_control = true ;
ui . capture ( ) ;
save_ubl_active_state_and_disable ( ) ; // Disable bed level correction for probing
do_blocking_move_to ( 0.5f * ( MESH_MAX_X - ( MESH_MIN_X ) ) , 0.5f * ( MESH_MAX_Y - ( MESH_MIN_Y ) ) , in_height ) ;
@ -805,7 +810,7 @@
SERIAL_PROTOCOLPGM ( " Place shim under nozzle " ) ;
LCD_MESSAGEPGM ( MSG_UBL_BC_INSERT ) ;
lcd_ return_to_status( ) ;
ui . return_to_status ( ) ;
echo_and_take_a_measurement ( ) ;
const float z1 = measure_point_with_encoder ( ) ;
@ -828,7 +833,7 @@
SERIAL_PROTOCOLLNPGM ( " mm thick. " ) ;
}
lcd_external_control = false ;
ui . release ( ) ;
restore_ubl_active_state_and_leave ( ) ;
@ -838,20 +843,20 @@
void abort_manual_probe_remaining_mesh ( ) {
SERIAL_PROTOCOLLNPGM ( " \n Mesh only partially populated. " ) ;
do_blocking_move_to_z ( Z_CLEARANCE_DEPLOY_PROBE ) ;
lcd_external_control = false ;
ui . release ( ) ;
KEEPALIVE_STATE ( IN_HANDLER ) ;
lcd_ quick_feedback( ) ;
ui . quick_feedback ( ) ;
ubl . restore_ubl_active_state_and_leave ( ) ;
}
void unified_bed_leveling : : manually_probe_remaining_mesh ( const float & rx , const float & ry , const float & z_clearance , const float & thick , const bool do_ubl_mesh_map ) {
lcd_external_control = true ;
ui . capture ( ) ;
save_ubl_active_state_and_disable ( ) ; // we don't do bed level correction because we want the raw data when we probe
save_ubl_active_state_and_disable ( ) ; // No bed level correction so only raw data is obtained
do_blocking_move_to ( current_position [ X_AXIS ] , current_position [ Y_AXIS ] , z_clearance ) ;
lcd_ return_to_status( ) ;
ui . return_to_status ( ) ;
mesh_index_pair location ;
do {
@ -870,7 +875,7 @@
do_blocking_move_to_z ( z_clearance ) ;
KEEPALIVE_STATE ( PAUSED_FOR_USER ) ;
lcd_external_control = true ;
ui . capture ( ) ;
if ( do_ubl_mesh_map ) display_map ( g29_map_type ) ; // show user where we're probing
@ -884,7 +889,7 @@
if ( click_and_hold ( ) ) {
SERIAL_PROTOCOLLNPGM ( " \n Mesh only partially populated. " ) ;
do_blocking_move_to_z ( Z_CLEARANCE_DEPLOY_PROBE ) ;
lcd_external_control = false ;
ui . release ( ) ;
KEEPALIVE_STATE ( IN_HANDLER ) ;
restore_ubl_active_state_and_leave ( ) ;
return ;
@ -905,12 +910,121 @@
KEEPALIVE_STATE ( IN_HANDLER ) ;
do_blocking_move_to ( rx , ry , Z_CLEARANCE_DEPLOY_PROBE ) ;
}
# endif // HAS_LCD_MENU
inline void set_message_with_feedback ( PGM_P const msg_P ) {
lcd_setstatusPGM ( msg_P ) ;
lcd_quick_feedback ( ) ;
}
inline void set_message_with_feedback ( PGM_P const msg_P ) {
ui . setstatusPGM ( msg_P ) ;
ui . quick_feedback ( ) ;
}
void abort_fine_tune ( ) {
ui . return_to_status ( ) ;
do_blocking_move_to_z ( Z_CLEARANCE_BETWEEN_PROBES ) ;
set_message_with_feedback ( PSTR ( MSG_EDITING_STOPPED ) ) ;
}
void unified_bed_leveling : : fine_tune_mesh ( const float & rx , const float & ry , const bool do_ubl_mesh_map ) {
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.
# if ENABLED(UBL_MESH_EDIT_MOVES_Z)
const float h_offset = parser . seenval ( ' H ' ) ? parser . value_linear_units ( ) : 0 ;
if ( ! WITHIN ( h_offset , 0 , 10 ) ) {
SERIAL_PROTOCOLLNPGM ( " Offset out of bounds. (0 to 10mm) \n " ) ;
return ;
}
# endif
mesh_index_pair location ;
if ( ! position_is_reachable ( rx , ry ) ) {
SERIAL_PROTOCOLLNPGM ( " (X,Y) outside printable radius. " ) ;
return ;
}
save_ubl_active_state_and_disable ( ) ;
LCD_MESSAGEPGM ( MSG_UBL_FINE_TUNE_MESH ) ;
ui . capture ( ) ; // Take over control of the LCD encoder
do_blocking_move_to ( rx , ry , Z_CLEARANCE_BETWEEN_PROBES ) ; // Move to the given XY with probe clearance
# if ENABLED(UBL_MESH_EDIT_MOVES_Z)
do_blocking_move_to_z ( h_offset ) ; // Move Z to the given 'H' offset
# endif
uint16_t not_done [ 16 ] ;
memset ( not_done , 0xFF , sizeof ( not_done ) ) ;
do {
location = find_closest_mesh_point_of_type ( SET_IN_BITMAP , rx , ry , USE_NOZZLE_AS_REFERENCE , not_done ) ;
if ( location . x_index < 0 ) break ; // Stop when there are no more reachable points
bitmap_clear ( not_done , location . x_index , location . y_index ) ; // Mark this location as 'adjusted' so a new
// location is used on the next loop
const float rawx = mesh_index_to_xpos ( location . x_index ) ,
rawy = mesh_index_to_ypos ( location . y_index ) ;
if ( ! position_is_reachable ( rawx , rawy ) ) break ; // SHOULD NOT OCCUR because find_closest_mesh_point_of_type will only return reachable
do_blocking_move_to ( rawx , rawy , Z_CLEARANCE_BETWEEN_PROBES ) ; // Move the nozzle to the edit point with probe clearance
# if ENABLED(UBL_MESH_EDIT_MOVES_Z)
do_blocking_move_to_z ( h_offset ) ; // Move Z to the given 'H' offset before editing
# endif
KEEPALIVE_STATE ( PAUSED_FOR_USER ) ;
if ( do_ubl_mesh_map ) display_map ( g29_map_type ) ; // Display the current point
ui . refresh ( ) ;
float new_z = z_values [ location . x_index ] [ location . y_index ] ;
if ( isnan ( new_z ) ) new_z = 0 ; // Invalid points begin at 0
new_z = FLOOR ( new_z * 1000 ) * 0.001f ; // Chop off digits after the 1000ths place
lcd_mesh_edit_setup ( new_z ) ;
do {
new_z = lcd_mesh_edit ( ) ;
# if ENABLED(UBL_MESH_EDIT_MOVES_Z)
do_blocking_move_to_z ( h_offset + new_z ) ; // Move the nozzle as the point is edited
# endif
idle ( ) ;
SERIAL_FLUSH ( ) ; // Prevent host M105 buffer overrun.
} while ( ! ui . button_pressed ( ) ) ;
if ( ! lcd_map_control ) ui . return_to_status ( ) ; // Just editing a single point? Return to status
if ( click_and_hold ( abort_fine_tune ) ) goto FINE_TUNE_EXIT ; // If the click is held down, abort editing
z_values [ location . x_index ] [ location . y_index ] = new_z ; // Save the updated Z value
safe_delay ( 20 ) ; // No switch noise
ui . refresh ( ) ;
} while ( location . x_index > = 0 & & - - g29_repetition_cnt > 0 ) ;
FINE_TUNE_EXIT :
ui . release ( ) ;
KEEPALIVE_STATE ( IN_HANDLER ) ;
if ( do_ubl_mesh_map ) display_map ( g29_map_type ) ;
restore_ubl_active_state_and_leave ( ) ;
do_blocking_move_to ( rx , ry , Z_CLEARANCE_BETWEEN_PROBES ) ;
LCD_MESSAGEPGM ( MSG_UBL_DONE_EDITING_MESH ) ;
SERIAL_ECHOLNPGM ( " Done Editing Mesh " ) ;
if ( lcd_map_control )
ui . goto_screen ( _lcd_ubl_output_map_lcd ) ;
else
ui . return_to_status ( ) ;
}
# endif // HAS_LCD_MENU
bool unified_bed_leveling : : g29_parameter_parsing ( ) {
bool err_flag = false ;
@ -1060,170 +1174,6 @@
set_bed_leveling_enabled ( ubl_state_at_invocation ) ;
}
/**
* Much of the ' What ? ' command can be eliminated . But until we are fully debugged , it is
* good to have the extra information . Soon . . . we prune this to just a few items
*/
void unified_bed_leveling : : g29_what_command ( ) {
report_state ( ) ;
if ( storage_slot = = - 1 )
SERIAL_PROTOCOLPGM ( " No Mesh Loaded. " ) ;
else {
SERIAL_PROTOCOLPAIR ( " Mesh " , storage_slot ) ;
SERIAL_PROTOCOLPGM ( " Loaded. " ) ;
}
SERIAL_EOL ( ) ;
safe_delay ( 50 ) ;
SERIAL_PROTOCOLLNPAIR ( " UBL object count: " , ( int ) ubl_cnt ) ;
# if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
SERIAL_PROTOCOLPGM ( " planner.z_fade_height : " ) ;
SERIAL_PROTOCOL_F ( planner . z_fade_height , 4 ) ;
SERIAL_EOL ( ) ;
# endif
adjust_mesh_to_mean ( g29_c_flag , g29_constant ) ;
# if HAS_BED_PROBE
SERIAL_PROTOCOLPGM ( " zprobe_zoffset: " ) ;
SERIAL_PROTOCOL_F ( zprobe_zoffset , 7 ) ;
SERIAL_EOL ( ) ;
# endif
SERIAL_ECHOLNPAIR ( " MESH_MIN_X " STRINGIFY ( MESH_MIN_X ) " = " , MESH_MIN_X ) ;
safe_delay ( 50 ) ;
SERIAL_ECHOLNPAIR ( " MESH_MIN_Y " STRINGIFY ( MESH_MIN_Y ) " = " , MESH_MIN_Y ) ;
safe_delay ( 50 ) ;
SERIAL_ECHOLNPAIR ( " MESH_MAX_X " STRINGIFY ( MESH_MAX_X ) " = " , MESH_MAX_X ) ;
safe_delay ( 50 ) ;
SERIAL_ECHOLNPAIR ( " MESH_MAX_Y " STRINGIFY ( MESH_MAX_Y ) " = " , MESH_MAX_Y ) ;
safe_delay ( 50 ) ;
SERIAL_ECHOLNPAIR ( " GRID_MAX_POINTS_X " , GRID_MAX_POINTS_X ) ;
safe_delay ( 50 ) ;
SERIAL_ECHOLNPAIR ( " GRID_MAX_POINTS_Y " , GRID_MAX_POINTS_Y ) ;
safe_delay ( 50 ) ;
SERIAL_ECHOLNPAIR ( " MESH_X_DIST " , MESH_X_DIST ) ;
SERIAL_ECHOLNPAIR ( " MESH_Y_DIST " , MESH_Y_DIST ) ;
safe_delay ( 50 ) ;
SERIAL_PROTOCOLPGM ( " X-Axis Mesh Points at: " ) ;
for ( uint8_t i = 0 ; i < GRID_MAX_POINTS_X ; i + + ) {
SERIAL_PROTOCOL_F ( LOGICAL_X_POSITION ( mesh_index_to_xpos ( i ) ) , 3 ) ;
SERIAL_PROTOCOLPGM ( " " ) ;
safe_delay ( 25 ) ;
}
SERIAL_EOL ( ) ;
SERIAL_PROTOCOLPGM ( " Y-Axis Mesh Points at: " ) ;
for ( uint8_t i = 0 ; i < GRID_MAX_POINTS_Y ; i + + ) {
SERIAL_PROTOCOL_F ( LOGICAL_Y_POSITION ( mesh_index_to_ypos ( i ) ) , 3 ) ;
SERIAL_PROTOCOLPGM ( " " ) ;
safe_delay ( 25 ) ;
}
SERIAL_EOL ( ) ;
# if HAS_KILL
SERIAL_PROTOCOLPAIR ( " Kill pin on : " , KILL_PIN ) ;
SERIAL_PROTOCOLLNPAIR ( " state: " , READ ( KILL_PIN ) ) ;
# endif
SERIAL_EOL ( ) ;
safe_delay ( 50 ) ;
# if ENABLED(UBL_DEVEL_DEBUGGING)
SERIAL_PROTOCOLLNPAIR ( " ubl_state_at_invocation : " , ubl_state_at_invocation ) ;
SERIAL_EOL ( ) ;
SERIAL_PROTOCOLLNPAIR ( " ubl_state_recursion_chk : " , ubl_state_recursion_chk ) ;
SERIAL_EOL ( ) ;
safe_delay ( 50 ) ;
SERIAL_PROTOCOLPAIR ( " Meshes go from " , hex_address ( ( void * ) settings . meshes_start_index ( ) ) ) ;
SERIAL_PROTOCOLLNPAIR ( " to " , hex_address ( ( void * ) settings . meshes_end_index ( ) ) ) ;
safe_delay ( 50 ) ;
SERIAL_PROTOCOLLNPAIR ( " sizeof(ubl) : " , ( int ) sizeof ( ubl ) ) ;
SERIAL_EOL ( ) ;
SERIAL_PROTOCOLLNPAIR ( " z_value[][] size: " , ( int ) sizeof ( z_values ) ) ;
SERIAL_EOL ( ) ;
safe_delay ( 25 ) ;
SERIAL_PROTOCOLLNPAIR ( " EEPROM free for UBL: " , hex_address ( ( void * ) ( settings . meshes_end_index ( ) - settings . meshes_start_index ( ) ) ) ) ;
safe_delay ( 50 ) ;
SERIAL_PROTOCOLPAIR ( " EEPROM can hold " , settings . calc_num_meshes ( ) ) ;
SERIAL_PROTOCOLLNPGM ( " meshes. \n " ) ;
safe_delay ( 25 ) ;
# endif // UBL_DEVEL_DEBUGGING
if ( ! sanity_check ( ) ) {
echo_name ( ) ;
SERIAL_PROTOCOLLNPGM ( " sanity checks passed. " ) ;
}
}
/**
* When we are fully debugged , the EEPROM dump command will get deleted also . But
* right now , it is good to have the extra information . Soon . . . we prune this .
*/
void unified_bed_leveling : : g29_eeprom_dump ( ) {
uint8_t cccc ;
SERIAL_ECHO_START ( ) ;
SERIAL_ECHOLNPGM ( " EEPROM Dump: " ) ;
persistentStore . access_start ( ) ;
for ( uint16_t i = 0 ; i < persistentStore . capacity ( ) ; i + = 16 ) {
if ( ! ( i & 0x3 ) ) idle ( ) ;
print_hex_word ( i ) ;
SERIAL_ECHOPGM ( " : " ) ;
for ( uint16_t j = 0 ; j < 16 ; j + + ) {
persistentStore . read_data ( i + j , & cccc , sizeof ( uint8_t ) ) ;
print_hex_byte ( cccc ) ;
SERIAL_ECHO ( ' ' ) ;
}
SERIAL_EOL ( ) ;
}
SERIAL_EOL ( ) ;
persistentStore . access_finish ( ) ;
}
/**
* When we are fully debugged , this may go away . But there are some valid
* use cases for the users . So we can wait and see what to do with it .
*/
void unified_bed_leveling : : g29_compare_current_mesh_to_stored_mesh ( ) {
int16_t a = settings . calc_num_meshes ( ) ;
if ( ! a ) {
SERIAL_PROTOCOLLNPGM ( " ?EEPROM storage not available. " ) ;
return ;
}
if ( ! parser . has_value ( ) ) {
SERIAL_PROTOCOLLNPGM ( " ?Storage slot # required. " ) ;
SERIAL_PROTOCOLLNPAIR ( " ?Use 0 to " , a - 1 ) ;
return ;
}
g29_storage_slot = parser . value_int ( ) ;
if ( ! WITHIN ( g29_storage_slot , 0 , a - 1 ) ) {
SERIAL_PROTOCOLLNPGM ( " ?Invalid storage slot. " ) ;
SERIAL_PROTOCOLLNPAIR ( " ?Use 0 to " , a - 1 ) ;
return ;
}
float tmp_z_values [ GRID_MAX_POINTS_X ] [ GRID_MAX_POINTS_Y ] ;
settings . load_mesh ( g29_storage_slot , & tmp_z_values ) ;
SERIAL_PROTOCOLPAIR ( " Subtracting mesh in slot " , g29_storage_slot ) ;
SERIAL_PROTOCOLLNPGM ( " from current mesh. " ) ;
for ( uint8_t x = 0 ; x < GRID_MAX_POINTS_X ; x + + )
for ( uint8_t y = 0 ; y < GRID_MAX_POINTS_Y ; y + + )
z_values [ x ] [ y ] - = tmp_z_values [ x ] [ y ] ;
}
mesh_index_pair unified_bed_leveling : : find_furthest_invalid_mesh_point ( ) {
bool found_a_NAN = false , found_a_real = false ;
@ -1338,118 +1288,6 @@
return out_mesh ;
}
# if HAS_LCD_MENU
void abort_fine_tune ( ) {
lcd_return_to_status ( ) ;
do_blocking_move_to_z ( Z_CLEARANCE_BETWEEN_PROBES ) ;
set_message_with_feedback ( PSTR ( MSG_EDITING_STOPPED ) ) ;
}
void unified_bed_leveling : : fine_tune_mesh ( const float & rx , const float & ry , const bool do_ubl_mesh_map ) {
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.
# if ENABLED(UBL_MESH_EDIT_MOVES_Z)
const float h_offset = parser . seenval ( ' H ' ) ? parser . value_linear_units ( ) : 0 ;
if ( ! WITHIN ( h_offset , 0 , 10 ) ) {
SERIAL_PROTOCOLLNPGM ( " Offset out of bounds. (0 to 10mm) \n " ) ;
return ;
}
# endif
mesh_index_pair location ;
if ( ! position_is_reachable ( rx , ry ) ) {
SERIAL_PROTOCOLLNPGM ( " (X,Y) outside printable radius. " ) ;
return ;
}
save_ubl_active_state_and_disable ( ) ;
LCD_MESSAGEPGM ( MSG_UBL_FINE_TUNE_MESH ) ;
lcd_external_control = true ; // Take over control of the LCD encoder
do_blocking_move_to ( rx , ry , Z_CLEARANCE_BETWEEN_PROBES ) ; // Move to the given XY with probe clearance
# if ENABLED(UBL_MESH_EDIT_MOVES_Z)
do_blocking_move_to_z ( h_offset ) ; // Move Z to the given 'H' offset
# endif
uint16_t not_done [ 16 ] ;
memset ( not_done , 0xFF , sizeof ( not_done ) ) ;
do {
location = find_closest_mesh_point_of_type ( SET_IN_BITMAP , rx , ry , USE_NOZZLE_AS_REFERENCE , not_done ) ;
if ( location . x_index < 0 ) break ; // Stop when there are no more reachable points
bitmap_clear ( not_done , location . x_index , location . y_index ) ; // Mark this location as 'adjusted' so a new
// location is used on the next loop
const float rawx = mesh_index_to_xpos ( location . x_index ) ,
rawy = mesh_index_to_ypos ( location . y_index ) ;
if ( ! position_is_reachable ( rawx , rawy ) ) break ; // SHOULD NOT OCCUR because find_closest_mesh_point_of_type will only return reachable
do_blocking_move_to ( rawx , rawy , Z_CLEARANCE_BETWEEN_PROBES ) ; // Move the nozzle to the edit point with probe clearance
# if ENABLED(UBL_MESH_EDIT_MOVES_Z)
do_blocking_move_to_z ( h_offset ) ; // Move Z to the given 'H' offset before editing
# endif
KEEPALIVE_STATE ( PAUSED_FOR_USER ) ;
if ( do_ubl_mesh_map ) display_map ( g29_map_type ) ; // Display the current point
lcd_refresh ( ) ;
float new_z = z_values [ location . x_index ] [ location . y_index ] ;
if ( isnan ( new_z ) ) new_z = 0 ; // Invalid points begin at 0
new_z = FLOOR ( new_z * 1000 ) * 0.001f ; // Chop off digits after the 1000ths place
lcd_mesh_edit_setup ( new_z ) ;
do {
new_z = lcd_mesh_edit ( ) ;
# if ENABLED(UBL_MESH_EDIT_MOVES_Z)
do_blocking_move_to_z ( h_offset + new_z ) ; // Move the nozzle as the point is edited
# endif
idle ( ) ;
SERIAL_FLUSH ( ) ; // Prevent host M105 buffer overrun.
} while ( ! is_lcd_clicked ( ) ) ;
if ( ! lcd_map_control ) lcd_return_to_status ( ) ; // Just editing a single point? Return to status
if ( click_and_hold ( abort_fine_tune ) ) goto FINE_TUNE_EXIT ; // If the click is held down, abort editing
z_values [ location . x_index ] [ location . y_index ] = new_z ; // Save the updated Z value
safe_delay ( 20 ) ; // No switch noise
lcd_refresh ( ) ;
} while ( location . x_index > = 0 & & - - g29_repetition_cnt > 0 ) ;
FINE_TUNE_EXIT :
lcd_external_control = false ;
KEEPALIVE_STATE ( IN_HANDLER ) ;
if ( do_ubl_mesh_map ) display_map ( g29_map_type ) ;
restore_ubl_active_state_and_leave ( ) ;
do_blocking_move_to ( rx , ry , Z_CLEARANCE_BETWEEN_PROBES ) ;
LCD_MESSAGEPGM ( MSG_UBL_DONE_EDITING_MESH ) ;
SERIAL_ECHOLNPGM ( " Done Editing Mesh " ) ;
if ( lcd_map_control )
lcd_goto_screen ( _lcd_ubl_output_map_lcd ) ;
else
lcd_return_to_status ( ) ;
}
# endif // HAS_LCD_MENU
/**
* ' Smart Fill ' : Scan from the outward edges of the mesh towards the center .
* If an invalid location is found , use the next two points ( if valid ) to
@ -1823,4 +1661,158 @@
}
# endif // UBL_G29_P31
# if ENABLED(UBL_DEVEL_DEBUGGING)
/**
* Much of the ' What ? ' command can be eliminated . But until we are fully debugged , it is
* good to have the extra information . Soon . . . we prune this to just a few items
*/
void unified_bed_leveling : : g29_what_command ( ) {
report_state ( ) ;
if ( storage_slot = = - 1 )
SERIAL_PROTOCOLPGM ( " No Mesh Loaded. " ) ;
else {
SERIAL_PROTOCOLPAIR ( " Mesh " , storage_slot ) ;
SERIAL_PROTOCOLPGM ( " Loaded. " ) ;
}
SERIAL_EOL ( ) ;
safe_delay ( 50 ) ;
# if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
SERIAL_PROTOCOLPGM ( " planner.z_fade_height : " ) ;
SERIAL_PROTOCOL_F ( planner . z_fade_height , 4 ) ;
SERIAL_EOL ( ) ;
# endif
adjust_mesh_to_mean ( g29_c_flag , g29_constant ) ;
# if HAS_BED_PROBE
SERIAL_PROTOCOLPGM ( " zprobe_zoffset: " ) ;
SERIAL_PROTOCOL_F ( zprobe_zoffset , 7 ) ;
SERIAL_EOL ( ) ;
# endif
SERIAL_ECHOLNPAIR ( " MESH_MIN_X " STRINGIFY ( MESH_MIN_X ) " = " , MESH_MIN_X ) ; safe_delay ( 50 ) ;
SERIAL_ECHOLNPAIR ( " MESH_MIN_Y " STRINGIFY ( MESH_MIN_Y ) " = " , MESH_MIN_Y ) ; safe_delay ( 50 ) ;
SERIAL_ECHOLNPAIR ( " MESH_MAX_X " STRINGIFY ( MESH_MAX_X ) " = " , MESH_MAX_X ) ; safe_delay ( 50 ) ;
SERIAL_ECHOLNPAIR ( " MESH_MAX_Y " STRINGIFY ( MESH_MAX_Y ) " = " , MESH_MAX_Y ) ; safe_delay ( 50 ) ;
SERIAL_ECHOLNPAIR ( " GRID_MAX_POINTS_X " , GRID_MAX_POINTS_X ) ; safe_delay ( 50 ) ;
SERIAL_ECHOLNPAIR ( " GRID_MAX_POINTS_Y " , GRID_MAX_POINTS_Y ) ; safe_delay ( 50 ) ;
SERIAL_ECHOLNPAIR ( " MESH_X_DIST " , MESH_X_DIST ) ;
SERIAL_ECHOLNPAIR ( " MESH_Y_DIST " , MESH_Y_DIST ) ; safe_delay ( 50 ) ;
SERIAL_PROTOCOLPGM ( " X-Axis Mesh Points at: " ) ;
for ( uint8_t i = 0 ; i < GRID_MAX_POINTS_X ; i + + ) {
SERIAL_PROTOCOL_F ( LOGICAL_X_POSITION ( mesh_index_to_xpos ( i ) ) , 3 ) ;
SERIAL_PROTOCOLPGM ( " " ) ;
safe_delay ( 25 ) ;
}
SERIAL_EOL ( ) ;
SERIAL_PROTOCOLPGM ( " Y-Axis Mesh Points at: " ) ;
for ( uint8_t i = 0 ; i < GRID_MAX_POINTS_Y ; i + + ) {
SERIAL_PROTOCOL_F ( LOGICAL_Y_POSITION ( mesh_index_to_ypos ( i ) ) , 3 ) ;
SERIAL_PROTOCOLPGM ( " " ) ;
safe_delay ( 25 ) ;
}
SERIAL_EOL ( ) ;
# if HAS_KILL
SERIAL_PROTOCOLPAIR ( " Kill pin on : " , KILL_PIN ) ;
SERIAL_PROTOCOLLNPAIR ( " state: " , READ ( KILL_PIN ) ) ;
# endif
SERIAL_EOL ( ) ;
safe_delay ( 50 ) ;
# if ENABLED(UBL_DEVEL_DEBUGGING)
SERIAL_PROTOCOLLNPAIR ( " ubl_state_at_invocation : " , ubl_state_at_invocation ) ; SERIAL_EOL ( ) ;
SERIAL_PROTOCOLLNPAIR ( " ubl_state_recursion_chk : " , ubl_state_recursion_chk ) ; SERIAL_EOL ( ) ;
safe_delay ( 50 ) ;
SERIAL_PROTOCOLPAIR ( " Meshes go from " , hex_address ( ( void * ) settings . meshes_start_index ( ) ) ) ;
SERIAL_PROTOCOLLNPAIR ( " to " , hex_address ( ( void * ) settings . meshes_end_index ( ) ) ) ;
safe_delay ( 50 ) ;
SERIAL_PROTOCOLLNPAIR ( " sizeof(ubl) : " , ( int ) sizeof ( ubl ) ) ; SERIAL_EOL ( ) ;
SERIAL_PROTOCOLLNPAIR ( " z_value[][] size: " , ( int ) sizeof ( z_values ) ) ; SERIAL_EOL ( ) ;
safe_delay ( 25 ) ;
SERIAL_PROTOCOLLNPAIR ( " EEPROM free for UBL: " , hex_address ( ( void * ) ( settings . meshes_end_index ( ) - settings . meshes_start_index ( ) ) ) ) ;
safe_delay ( 50 ) ;
SERIAL_PROTOCOLPAIR ( " EEPROM can hold " , settings . calc_num_meshes ( ) ) ;
SERIAL_PROTOCOLLNPGM ( " meshes. \n " ) ;
safe_delay ( 25 ) ;
# endif // UBL_DEVEL_DEBUGGING
if ( ! sanity_check ( ) ) {
echo_name ( ) ;
SERIAL_PROTOCOLLNPGM ( " sanity checks passed. " ) ;
}
}
/**
* When we are fully debugged , the EEPROM dump command will get deleted also . But
* right now , it is good to have the extra information . Soon . . . we prune this .
*/
void unified_bed_leveling : : g29_eeprom_dump ( ) {
uint8_t cccc ;
SERIAL_ECHO_START ( ) ;
SERIAL_ECHOLNPGM ( " EEPROM Dump: " ) ;
persistentStore . access_start ( ) ;
for ( uint16_t i = 0 ; i < persistentStore . capacity ( ) ; i + = 16 ) {
if ( ! ( i & 0x3 ) ) idle ( ) ;
print_hex_word ( i ) ;
SERIAL_ECHOPGM ( " : " ) ;
for ( uint16_t j = 0 ; j < 16 ; j + + ) {
persistentStore . read_data ( i + j , & cccc , sizeof ( uint8_t ) ) ;
print_hex_byte ( cccc ) ;
SERIAL_ECHO ( ' ' ) ;
}
SERIAL_EOL ( ) ;
}
SERIAL_EOL ( ) ;
persistentStore . access_finish ( ) ;
}
/**
* When we are fully debugged , this may go away . But there are some valid
* use cases for the users . So we can wait and see what to do with it .
*/
void unified_bed_leveling : : g29_compare_current_mesh_to_stored_mesh ( ) {
int16_t a = settings . calc_num_meshes ( ) ;
if ( ! a ) {
SERIAL_PROTOCOLLNPGM ( " ?EEPROM storage not available. " ) ;
return ;
}
if ( ! parser . has_value ( ) ) {
SERIAL_PROTOCOLLNPGM ( " ?Storage slot # required. " ) ;
SERIAL_PROTOCOLLNPAIR ( " ?Use 0 to " , a - 1 ) ;
return ;
}
g29_storage_slot = parser . value_int ( ) ;
if ( ! WITHIN ( g29_storage_slot , 0 , a - 1 ) ) {
SERIAL_PROTOCOLLNPGM ( " ?Invalid storage slot. " ) ;
SERIAL_PROTOCOLLNPAIR ( " ?Use 0 to " , a - 1 ) ;
return ;
}
float tmp_z_values [ GRID_MAX_POINTS_X ] [ GRID_MAX_POINTS_Y ] ;
settings . load_mesh ( g29_storage_slot , & tmp_z_values ) ;
SERIAL_PROTOCOLPAIR ( " Subtracting mesh in slot " , g29_storage_slot ) ;
SERIAL_PROTOCOLLNPGM ( " from current mesh. " ) ;
for ( uint8_t x = 0 ; x < GRID_MAX_POINTS_X ; x + + )
for ( uint8_t y = 0 ; y < GRID_MAX_POINTS_Y ; y + + )
z_values [ x ] [ y ] - = tmp_z_values [ x ] [ y ] ;
}
# endif // UBL_DEVEL_DEBUGGING
# endif // AUTO_BED_LEVELING_UBL