diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp index a261581e5..71c0097f7 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp @@ -630,7 +630,7 @@ #if HAS_LCD_MENU lcd_reset_alert_level(); - lcd_quick_feedback(true); + lcd_quick_feedback(); lcd_reset_status(); lcd_external_control = false; #endif @@ -689,16 +689,14 @@ bool click_and_hold(const clickFunc_t func=NULL) { if (is_lcd_clicked()) { - lcd_quick_feedback(false); // Do NOT clear button status! If cleared, the code - // code can not look for a 'click and hold' + 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(true); + lcd_quick_feedback(); if (func) (*func)(); wait_for_release(); - safe_delay(50); // Debounce the Encoder wheel return true; } } @@ -721,7 +719,7 @@ lcd_external_control = true; #endif - 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 DEPLOY_PROBE(); uint16_t count = GRID_MAX_POINTS; @@ -731,14 +729,13 @@ #if HAS_LCD_MENU if (is_lcd_clicked()) { + lcd_quick_feedback(false); // Preserve button state for click-and-hold SERIAL_PROTOCOLLNPGM("\nMesh only partially populated.\n"); - lcd_quick_feedback(false); STOW_PROBE(); - while (is_lcd_clicked()) idle(); + wait_for_release(); + lcd_quick_feedback(); lcd_external_control = false; restore_ubl_active_state_and_leave(); - lcd_quick_feedback(true); - safe_delay(50); // Debounce the Encoder wheel return; } #endif @@ -843,7 +840,7 @@ do_blocking_move_to_z(Z_CLEARANCE_DEPLOY_PROBE); lcd_external_control = false; KEEPALIVE_STATE(IN_HANDLER); - lcd_quick_feedback(true); + lcd_quick_feedback(); ubl.restore_ubl_active_state_and_leave(); } @@ -910,12 +907,16 @@ } #endif // HAS_LCD_MENU + inline void set_message_with_feedback(PGM_P const msg_P) { + lcd_setstatusPGM(msg_P); + lcd_quick_feedback(); + } + bool unified_bed_leveling::g29_parameter_parsing() { bool err_flag = false; #if HAS_LCD_MENU - LCD_MESSAGEPGM(MSG_UBL_DOING_G29); - lcd_quick_feedback(true); + set_message_with_feedback(PSTR(MSG_UBL_DOING_G29)); #endif g29_constant = 0; @@ -1037,8 +1038,7 @@ if (ubl_state_recursion_chk != 1) { SERIAL_ECHOLNPGM("save_ubl_active_state_and_disabled() called multiple times in a row."); #if HAS_LCD_MENU - LCD_MESSAGEPGM(MSG_UBL_SAVE_ERROR); - lcd_quick_feedback(true); + set_message_with_feedback(PSTR(MSG_UBL_SAVE_ERROR)); #endif return; } @@ -1052,8 +1052,7 @@ if (--ubl_state_recursion_chk) { SERIAL_ECHOLNPGM("restore_ubl_active_state_and_leave() called too many times."); #if HAS_LCD_MENU - LCD_MESSAGEPGM(MSG_UBL_RESTORE_ERROR); - lcd_quick_feedback(true); + set_message_with_feedback(PSTR(MSG_UBL_RESTORE_ERROR)); #endif return; } @@ -1344,8 +1343,7 @@ void abort_fine_tune() { lcd_return_to_status(); do_blocking_move_to_z(Z_CLEARANCE_BETWEEN_PROBES); - LCD_MESSAGEPGM(MSG_EDITING_STOPPED); - lcd_quick_feedback(true); + 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) { diff --git a/Marlin/src/gcode/bedlevel/G26.cpp b/Marlin/src/gcode/bedlevel/G26.cpp index 5bb755655..6deeadb32 100644 --- a/Marlin/src/gcode/bedlevel/G26.cpp +++ b/Marlin/src/gcode/bedlevel/G26.cpp @@ -38,6 +38,7 @@ #include "../../module/planner.h" #include "../../module/stepper.h" #include "../../module/motion.h" +#include "../../module/tool_change.h" #include "../../module/temperature.h" #include "../../lcd/ultralcd.h" @@ -165,18 +166,12 @@ int8_t g26_prime_flag; if (!is_lcd_clicked()) return false; // Return if the button isn't pressed lcd_setstatusPGM(PSTR("Mesh Validation Stopped."), 99); #if HAS_LCD_MENU - lcd_quick_feedback(true); + lcd_quick_feedback(); #endif wait_for_release(); return true; } - bool exit_from_g26() { - lcd_setstatusPGM(PSTR("Leaving G26"), -1); - wait_for_release(); - return G26_ERR; - } - #endif mesh_index_pair find_closest_circle_to_print(const float &X, const float &Y) { @@ -412,58 +407,50 @@ inline bool look_for_lines_to_connect() { * wait for them to get up to temperature. */ inline bool turn_on_heaters() { - millis_t next = millis() + 5000UL; + + SERIAL_ECHOLNPGM("Waiting for heatup."); + #if HAS_HEATED_BED - #if ENABLED(ULTRA_LCD) - if (g26_bed_temp > 25) { + + if (g26_bed_temp > 25) { + #if ENABLED(ULTRA_LCD) lcd_setstatusPGM(PSTR("G26 Heating Bed."), 99); - lcd_quick_feedback(true); + lcd_quick_feedback(); #if HAS_LCD_MENU lcd_external_control = true; #endif - #endif - thermalManager.setTargetBed(g26_bed_temp); - while (ABS(thermalManager.degBed() - g26_bed_temp) > 3) { + #endif + thermalManager.setTargetBed(g26_bed_temp); - #if HAS_LCD_MENU - if (is_lcd_clicked()) return exit_from_g26(); + // Wait for the temperature to stabilize + if (!thermalManager.wait_for_bed(true + #if G26_CLICK_CAN_CANCEL + , true #endif - - if (ELAPSED(millis(), next)) { - next = millis() + 5000UL; - thermalManager.print_heaterstates(); - SERIAL_EOL(); - } - idle(); - SERIAL_FLUSH(); // Prevent host M105 buffer overrun. - } - #if ENABLED(ULTRA_LCD) - } - lcd_setstatusPGM(PSTR("G26 Heating Nozzle."), 99); - lcd_quick_feedback(true); - #endif - #endif - - // Start heating the nozzle and wait for it to reach temperature. - thermalManager.setTargetHotend(g26_hotend_temp, 0); - while (ABS(thermalManager.degHotend(0) - g26_hotend_temp) > 3) { - - #if HAS_LCD_MENU - if (is_lcd_clicked()) return exit_from_g26(); - #endif - - if (ELAPSED(millis(), next)) { - next = millis() + 5000UL; - thermalManager.print_heaterstates(); - SERIAL_EOL(); + ) + ) return G26_ERR; } - idle(); - SERIAL_FLUSH(); // Prevent host M105 buffer overrun. - } + + #endif // HAS_HEATED_BED + + // Start heating the active nozzle + #if ENABLED(ULTRA_LCD) + lcd_setstatusPGM(PSTR("G26 Heating Nozzle."), 99); + lcd_quick_feedback(); + #endif + thermalManager.setTargetHotend(g26_hotend_temp, active_extruder); + + // Wait for the temperature to stabilize + if (!thermalManager.wait_for_hotend(active_extruder, true + #if G26_CLICK_CAN_CANCEL + , true + #endif + ) + ) return G26_ERR; #if ENABLED(ULTRA_LCD) lcd_reset_status(); - lcd_quick_feedback(true); + lcd_quick_feedback(); #endif return G26_OK; @@ -507,7 +494,7 @@ inline bool prime_nozzle() { wait_for_release(); lcd_setstatusPGM(PSTR("Done Priming"), 99); - lcd_quick_feedback(true); + lcd_quick_feedback(); lcd_external_control = false; } else @@ -515,7 +502,7 @@ inline bool prime_nozzle() { { #if ENABLED(ULTRA_LCD) lcd_setstatusPGM(PSTR("Fixed Length Prime."), 99); - lcd_quick_feedback(true); + lcd_quick_feedback(); #endif set_destination_from_current(); destination[E_AXIS] += g26_prime_length; @@ -553,17 +540,21 @@ float valid_trig_angle(float d) { * Q Retraction multiplier * R Repetitions (number of grid points) * S Nozzle Size (diameter) in mm + * T Tool index to change to, if included * U Random deviation (50 if no value given) * X X position * Y Y position */ void GcodeSuite::G26() { - SERIAL_ECHOLNPGM("G26 command started. Waiting for heater(s)."); + SERIAL_ECHOLNPGM("G26 starting..."); // Don't allow Mesh Validation without homing first, // or if the parameter parsing did not go OK, abort if (axis_unhomed_error()) return; + // Change the tool first, if specified + if (parser.seenval('T')) tool_change(parser.value_int()); + g26_extrusion_multiplier = EXTRUSION_MULTIPLIER; g26_retraction_multiplier = RETRACTION_MULTIPLIER; g26_layer_height = MESH_TEST_LAYER_HEIGHT; @@ -891,6 +882,7 @@ void GcodeSuite::G26() { LEAVE: lcd_setstatusPGM(PSTR("Leaving G26"), -1); + wait_for_release(); retract_filament(destination); destination[Z_AXIS] = Z_CLEARANCE_BETWEEN_PROBES; @@ -914,7 +906,7 @@ void GcodeSuite::G26() { #if HAS_HEATED_BED thermalManager.setTargetBed(0); #endif - thermalManager.setTargetHotend(0, 0); + thermalManager.setTargetHotend(active_extruder, 0); } } diff --git a/Marlin/src/lcd/menu/menu.h b/Marlin/src/lcd/menu/menu.h index 8ff59b8b9..2dffc7e1c 100644 --- a/Marlin/src/lcd/menu/menu.h +++ b/Marlin/src/lcd/menu/menu.h @@ -30,7 +30,6 @@ extern bool screen_changed; constexpr int16_t heater_maxtemp[HOTENDS] = ARRAY_BY_HOTENDS(HEATER_0_MAXTEMP, HEATER_1_MAXTEMP, HEATER_2_MAXTEMP, HEATER_3_MAXTEMP, HEATER_4_MAXTEMP); void scroll_screen(const uint8_t limit, const bool is_menu); -bool use_click(); bool printer_busy(); void lcd_completion_feedback(const bool good=true); void lcd_save_previous_screen(); diff --git a/Marlin/src/lcd/ultralcd.cpp b/Marlin/src/lcd/ultralcd.cpp index 7cb7eaec9..14b8e0d1a 100644 --- a/Marlin/src/lcd/ultralcd.cpp +++ b/Marlin/src/lcd/ultralcd.cpp @@ -244,8 +244,8 @@ bool lcd_blink() { #if HAS_LCD_MENU if (RRK(EN_REPRAPWORLD_KEYPAD_DOWN)) encoderPosition -= ENCODER_STEPS_PER_MENU_ITEM; else if (RRK(EN_REPRAPWORLD_KEYPAD_UP)) encoderPosition += ENCODER_STEPS_PER_MENU_ITEM; - else if (RRK(EN_REPRAPWORLD_KEYPAD_LEFT)) { menu_item_back::action(); lcd_quick_feedback(true); } - else if (RRK(EN_REPRAPWORLD_KEYPAD_RIGHT)) { lcd_return_to_status(); lcd_quick_feedback(true); } + else if (RRK(EN_REPRAPWORLD_KEYPAD_LEFT)) { menu_item_back::action(); lcd_quick_feedback(); } + else if (RRK(EN_REPRAPWORLD_KEYPAD_RIGHT)) { lcd_return_to_status(); lcd_quick_feedback(); } #endif } else if (RRK(EN_REPRAPWORLD_KEYPAD_DOWN)) encoderPosition += ENCODER_PULSES_PER_STEP; @@ -484,7 +484,7 @@ void kill_screen(PGM_P lcd_msg) { } #endif -void lcd_quick_feedback(const bool clear_buttons) { +void lcd_quick_feedback(const bool clear_buttons/*=true*/) { #if HAS_LCD_MENU lcd_refresh(); @@ -661,14 +661,14 @@ void lcd_update() { wait_for_unclick = true; // Set debounce flag to ignore continous clicks lcd_clicked = !wait_for_user && !no_reentry; // Keep the click if not waiting for a user-click wait_for_user = false; // Any click clears wait for user - lcd_quick_feedback(true); // Always make a click sound + lcd_quick_feedback(); // Always make a click sound } } else wait_for_unclick = false; #if BUTTON_EXISTS(BACK) if (LCD_BACK_CLICKED) { - lcd_quick_feedback(true); + lcd_quick_feedback(); lcd_goto_previous_menu(); } #endif diff --git a/Marlin/src/lcd/ultralcd.h b/Marlin/src/lcd/ultralcd.h index a8b382690..42f8e82bf 100644 --- a/Marlin/src/lcd/ultralcd.h +++ b/Marlin/src/lcd/ultralcd.h @@ -242,7 +242,7 @@ inline void lcd_buzz(const long duration, const uint16_t freq) { UNUSED(duration); UNUSED(freq); } #endif - void lcd_quick_feedback(const bool clear_buttons); // Audible feedback for a button click - could also be visual + void lcd_quick_feedback(const bool clear_buttons=true); // Audible feedback for a button click - could also be visual #if ENABLED(LCD_PROGRESS_BAR) extern millis_t progress_bar_ms; // Start time for the current progress bar cycle @@ -351,6 +351,8 @@ bool lcd_blink(); + bool use_click(); + #if ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(G26_MESH_VALIDATION) bool is_lcd_clicked(); void wait_for_release(); diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 892379c53..4750b7dcd 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -2441,7 +2441,11 @@ void Temperature::isr() { #define MIN_COOLING_SLOPE_TIME 60 #endif - bool Temperature::wait_for_hotend(const uint8_t target_extruder, const bool no_wait_for_cooling/*=true*/) { + bool Temperature::wait_for_hotend(const uint8_t target_extruder, const bool no_wait_for_cooling/*=true*/ + #if G26_CLICK_CAN_CANCEL + , const bool click_to_cancel/*=false*/ + #endif + ) { #if TEMP_RESIDENCY_TIME > 0 millis_t residency_start_ms = 0; // Loop until the temperature has stabilized @@ -2525,6 +2529,13 @@ void Temperature::isr() { } } + #if G26_CLICK_CAN_CANCEL + if (click_to_cancel && use_click()) { + wait_for_heatup = false; + lcd_quick_feedback(); + } + #endif + } while (wait_for_heatup && TEMP_CONDITIONS); if (wait_for_heatup) { @@ -2552,7 +2563,11 @@ void Temperature::isr() { #define MIN_COOLING_SLOPE_TIME_BED 60 #endif - void Temperature::wait_for_bed(const bool no_wait_for_cooling) { + bool Temperature::wait_for_bed(const bool no_wait_for_cooling + #if G26_CLICK_CAN_CANCEL + , const bool click_to_cancel/*=false*/ + #endif + ) { #if TEMP_BED_RESIDENCY_TIME > 0 millis_t residency_start_ms = 0; // Loop until the temperature has stabilized @@ -2639,6 +2654,13 @@ void Temperature::isr() { } } + #if G26_CLICK_CAN_CANCEL + if (click_to_cancel && use_click()) { + wait_for_heatup = false; + lcd_quick_feedback(); + } + #endif + } while (wait_for_heatup && TEMP_BED_CONDITIONS); if (wait_for_heatup) lcd_reset_status(); @@ -2646,6 +2668,8 @@ void Temperature::isr() { #if DISABLED(BUSY_WHILE_HEATING) && ENABLED(HOST_KEEPALIVE_FEATURE) gcode.busy_state = old_busy_state; #endif + + return wait_for_heatup; } #endif // HAS_HEATED_BED diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h index 7c5610555..c7031fd46 100644 --- a/Marlin/src/module/temperature.h +++ b/Marlin/src/module/temperature.h @@ -138,6 +138,8 @@ enum ADCSensorState : char { #define unscalePID_d(d) ( float(d) * PID_dT ) #endif +#define G26_CLICK_CAN_CANCEL (HAS_LCD_MENU && ENABLED(G26_MESH_VALIDATION)) + class Temperature { public: @@ -426,7 +428,11 @@ class Temperature { } #if HAS_TEMP_HOTEND - static bool wait_for_hotend(const uint8_t target_extruder, const bool no_wait_for_cooling=true); + static bool wait_for_hotend(const uint8_t target_extruder, const bool no_wait_for_cooling=true + #if G26_CLICK_CAN_CANCEL + , const bool click_to_cancel=false + #endif + ); #endif #if HAS_HEATED_BED @@ -459,7 +465,11 @@ class Temperature { static void start_watching_bed(); #endif - static void wait_for_bed(const bool no_wait_for_cooling); + static bool wait_for_bed(const bool no_wait_for_cooling + #if G26_CLICK_CAN_CANCEL + , const bool click_to_cancel=false + #endif + ); #endif // HAS_HEATED_BED