diff --git a/Firmware/Marlin.h b/Firmware/Marlin.h index 582cea348a..0f2eda2a64 100755 --- a/Firmware/Marlin.h +++ b/Firmware/Marlin.h @@ -514,7 +514,7 @@ void proc_commands(); void M600_load_filament(); void M600_load_filament_movements(); -void M600_wait_for_user(float HotendTempBckp); +bool M600_wait_for_user(float HotendTempBckp); void M600_check_state(float nozzle_temp); void load_filament_final_feed(); void marlin_wait_for_click(); diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index 5279776d5f..df7b317333 100755 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -3037,8 +3037,9 @@ static void gcode_M600(bool automatic, float x_position, float y_position, float st_synchronize(); //Beep, manage nozzle heater and wait for user to start unload filament - if(!mmu_enabled) M600_wait_for_user(HotendTempBckp); - + if (mmu_enabled || M600_wait_for_user(HotendTempBckp)) + { + lcd_change_fil_state = 0; // Unload filament @@ -3085,6 +3086,8 @@ static void gcode_M600(bool automatic, float x_position, float y_position, float M600_load_filament(); if (!automatic) M600_check_state(HotendTempBckp); + + } // if (mmu_enabled || M600_wait_for_user(HotendTempBckp)) lcd_update_enable(true); @@ -10320,44 +10323,76 @@ void M600_check_state(float nozzle_temp) //! If times out, active extruder temperature is set to 0. //! //! @param HotendTempBckp Temperature to be restored for active extruder, after user resolves MMU problem. -void M600_wait_for_user(float HotendTempBckp) { +bool M600_wait_for_user(float HotendTempBckp) { KEEPALIVE_STATE(PAUSED_FOR_USER); - int counterBeep = 0; unsigned long waiting_start_time = _millis(); + unsigned long beep_start_time = 0; uint8_t wait_for_user_state = 0; - lcd_display_message_fullscreen_P(_T(MSG_PRESS_TO_UNLOAD)); + + // Ask the user if he actually wants to reload + // filament. They may have changed their mind; or they + // might want to use the M600 as a comfortable pause + // for whatever reason (works well with the layer + // change feature of PrusaSlicer). + + // 0 = no (skip unload) + // 1 = yes (do unload) + // -1 = timeout (last selection was NO) + // -2 = timeout (last selection was YES) + int8_t yesno = -2; + bool bFirst=true; - while (!(wait_for_user_state == 0 && lcd_clicked())){ - manage_heater(); - manage_inactivity(true); + unsigned long mill; + while (wait_for_user_state != 0 || yesno < 0){ + + manage_heater(); + manage_inactivity(true); + + mill = _millis(); + #if BEEPER > 0 - if (counterBeep == 500) { - counterBeep = 0; - } SET_OUTPUT(BEEPER); - if (counterBeep == 0) { - if((eSoundMode==e_SOUND_MODE_BLIND)|| (eSoundMode==e_SOUND_MODE_LOUD)||((eSoundMode==e_SOUND_MODE_ONCE)&&bFirst)) - { - bFirst=false; - WRITE(BEEPER, HIGH); - } + if (beep_start_time == 0 && + wait_for_user_state != 2 && + ((eSoundMode==e_SOUND_MODE_BLIND) || + (eSoundMode==e_SOUND_MODE_LOUD) || + ((eSoundMode==e_SOUND_MODE_ONCE) && bFirst))) { + // Start a beep + bFirst=false; + WRITE(BEEPER, HIGH); + beep_start_time = mill; } - if (counterBeep == 20) { - WRITE(BEEPER, LOW); - } - - counterBeep++; - #endif //BEEPER > 0 + #endif //BEEPER > 0 + if (wait_for_user_state == 0) { + // this takes 1000ms + yesno = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Unload filament now?"), 1000, yesno); + if (yesno >= 0) { + break; + } + } + + #if BEEPER > 0 + if (mill - beep_start_time > 900) { + // Turn off beeper after 0.9s, which should be safely after the 1 second prompt timeout. + WRITE(BEEPER, LOW); + } + if (mill - beep_start_time > 5000) { + // Next beep after 5s + beep_start_time = 0; + } + #endif //BEEPER > 0 + + switch (wait_for_user_state) { case 0: //nozzle is hot, waiting for user to press the knob to unload filament delay_keep_alive(4); - if (_millis() > waiting_start_time + (unsigned long)M600_TIMEOUT * 1000) { + if (mill > waiting_start_time + (unsigned long)M600_TIMEOUT * 1000) { lcd_display_message_fullscreen_P(_i("Press knob to preheat nozzle and continue."));////MSG_PRESS_TO_PREHEAT c=20 r=4 wait_for_user_state = 1; setAllTargetHotends(0); @@ -10378,14 +10413,11 @@ void M600_wait_for_user(float HotendTempBckp) { } break; case 2: //waiting for nozzle to reach target temperature - if (abs(degTargetHotend(active_extruder) - degHotend(active_extruder)) < 1) { - lcd_display_message_fullscreen_P(_T(MSG_PRESS_TO_UNLOAD)); - waiting_start_time = _millis(); + waiting_start_time = mill; wait_for_user_state = 0; } else { - counterBeep = 20; //beeper will be inactive during waiting for nozzle preheat lcd_set_cursor(1, 4); lcd_print(ftostr3(degHotend(active_extruder))); } @@ -10394,7 +10426,10 @@ void M600_wait_for_user(float HotendTempBckp) { } } + WRITE(BEEPER, LOW); + + return (yesno == 1 ? true : false); } void M600_load_filament_movements() diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp index e601fd7557..0dbcabc867 100755 --- a/Firmware/ultralcd.cpp +++ b/Firmware/ultralcd.cpp @@ -3725,40 +3725,39 @@ int8_t lcd_show_multiscreen_message_two_choices_and_wait_P(const char *msg, bool //! @brief Show single screen message with yes and no possible choices and wait with possible timeout //! @param msg Message to show -//! @param allow_timeouting if true, allows time outing of the screen -//! @param default_yes if true, yes choice is selected by default, otherwise no choice is preselected +//! @param allow_timeouting if true, allows time outing of the screen with a default timeout. If any other +//! number != 0, then allows timeout with that number of milliseconds +//! @param default_yes if true or -2, then yes choice is selected by default, otherwise no choice is preselected. +//! If return_immediately is true, then this should be the value of the previous call. //! @retval 1 yes choice selected by user //! @retval 0 no choice selected by user -//! @retval -1 screen timed out -int8_t lcd_show_fullscreen_message_yes_no_and_wait_P(const char *msg, bool allow_timeouting, bool default_yes) +//! @retval -1 screen timed out and the cursor was on NO +//! @retval -2 screen timed out and the cursor was on YES +int8_t lcd_show_fullscreen_message_yes_no_and_wait_P(const char *msg, unsigned long allow_timeouting, int8_t default_yes) { lcd_display_message_fullscreen_P(msg); - - if (default_yes) { - lcd_set_cursor(0, 2); - lcd_puts_P(PSTR(">")); - lcd_puts_P(_T(MSG_YES)); - lcd_set_cursor(1, 3); - lcd_puts_P(_T(MSG_NO)); - } - else { - lcd_set_cursor(1, 2); - lcd_puts_P(_T(MSG_YES)); - lcd_set_cursor(0, 3); - lcd_puts_P(PSTR(">")); - lcd_puts_P(_T(MSG_NO)); - } - bool yes = default_yes ? true : false; + + bool yes = (default_yes == true) || (default_yes == -2); + + lcd_set_cursor(1, 2); + lcd_puts_P(_T(MSG_YES)); + lcd_set_cursor(1, 3); + lcd_puts_P(_T(MSG_NO)); + + lcd_set_cursor(0, yes ? 2 : 3); + lcd_puts_P(PSTR(">")); // Wait for user confirmation or a timeout. unsigned long previous_millis_cmd = _millis(); + unsigned long timeout = allow_timeouting == true ? LCD_TIMEOUT_TO_STATUS : allow_timeouting; int8_t enc_dif = lcd_encoder_diff; lcd_consume_click(); KEEPALIVE_STATE(PAUSED_FOR_USER); for (;;) { - if (allow_timeouting && _millis() - previous_millis_cmd > LCD_TIMEOUT_TO_STATUS) - return -1; + if (allow_timeouting && _millis() - previous_millis_cmd > timeout) + return yes ? -2 : -1; + manage_heater(); manage_inactivity(true); if (abs(enc_dif - lcd_encoder_diff) > 4) { diff --git a/Firmware/ultralcd.h b/Firmware/ultralcd.h index f414a1cc12..856b7dc67f 100755 --- a/Firmware/ultralcd.h +++ b/Firmware/ultralcd.h @@ -66,8 +66,8 @@ extern void lcd_return_to_status(); extern void lcd_wait_for_click(); extern bool lcd_wait_for_click_delay(uint16_t nDelay); extern void lcd_show_fullscreen_message_and_wait_P(const char *msg); -// 0: no, 1: yes, -1: timeouted -extern int8_t lcd_show_fullscreen_message_yes_no_and_wait_P(const char *msg, bool allow_timeouting = true, bool default_yes = false); +// 0: no, 1: yes, -1: timeouted (cursor on NO), -2: timeouted (cursor on YES) +extern int8_t lcd_show_fullscreen_message_yes_no_and_wait_P(const char *msg, unsigned long allow_timeouting = true, int8_t default_yes = false); extern int8_t lcd_show_multiscreen_message_two_choices_and_wait_P(const char *msg, bool allow_timeouting, bool default_yes, const char *first_choice, const char *second_choice); extern int8_t lcd_show_multiscreen_message_yes_no_and_wait_P(const char *msg, bool allow_timeouting = true, bool default_yes = false);