diff --git a/Firmware/mmu2.cpp b/Firmware/mmu2.cpp index a88cfad45..d3fdd3641 100644 --- a/Firmware/mmu2.cpp +++ b/Firmware/mmu2.cpp @@ -91,7 +91,7 @@ MMU2::MMU2() , resume_hotend_temp(0) , logicStepLastStatus(StepStatus::Finished) , state(xState::Stopped) - , mmu_print_saved(false) + , mmu_print_saved(SavedState::None) , loadFilamentStarted(false) , loadingToNozzle(false) { @@ -458,15 +458,14 @@ void MMU2::Home(uint8_t mode){ } void MMU2::SaveAndPark(bool move_axes, bool turn_off_nozzle) { - if (!mmu_print_saved) { // First occurrence. Save current position, park print head, disable nozzle heater. + if (mmu_print_saved == SavedState::None) { // First occurrence. Save current position, park print head, disable nozzle heater. LogEchoEvent("Saving and parking"); st_synchronize(); - - mmu_print_saved = true; - + resume_hotend_temp = degTargetHotend(active_extruder); if (move_axes){ + mmu_print_saved |= SavedState::ParkExtruder; // save current pos for(uint8_t i = 0; i < 3; ++i){ resume_position.xyz[i] = current_position[i]; @@ -487,6 +486,7 @@ void MMU2::SaveAndPark(bool move_axes, bool turn_off_nozzle) { } if (turn_off_nozzle){ + mmu_print_saved |= SavedState::Cooldown; LogEchoEvent("Heater off"); setAllTargetHotends(0); } @@ -496,35 +496,37 @@ void MMU2::SaveAndPark(bool move_axes, bool turn_off_nozzle) { // gcode.reset_stepper_timeout(); } -void MMU2::ResumeAndUnPark(bool move_axes, bool turn_off_nozzle) { - if (mmu_print_saved) { - LogEchoEvent("Resuming print"); +void MMU2::ResumeHotendTemp() { + if ((mmu_print_saved & SavedState::Cooldown) && resume_hotend_temp) { + LogEchoEvent("Resuming Temp"); + MMU2_ECHO_MSG("Restoring hotend temperature "); + SERIAL_ECHOLN(resume_hotend_temp); + setTargetHotend(resume_hotend_temp, active_extruder); + lcd_display_message_fullscreen_P(_i("MMU OK. Resuming temperature...")); // better report the event and let the GUI do its work somewhere else + ReportErrorHookSensorLineRender(); + waitForHotendTargetTemp(1000, []{ + ReportErrorHookDynamicRender(); + }); + LogEchoEvent("Hotend temperature reached"); + lcd_update_enable(true); // temporary hack to stop this locking the printer... + } +} - if (turn_off_nozzle && resume_hotend_temp) { - MMU2_ECHO_MSG("Restoring hotend temperature "); - SERIAL_ECHOLN(resume_hotend_temp); - setTargetHotend(resume_hotend_temp, active_extruder); - waitForHotendTargetTemp(3000, []{ - lcd_display_message_fullscreen_P(_i("MMU OK. Resuming temperature...")); // better report the event and let the GUI do its work somewhere else - }); - LogEchoEvent("Hotend temperature reached"); - lcd_update_enable(true); // temporary hack to stop this locking the printer... - } +void MMU2::ResumeUnpark() +{ + if (mmu_print_saved & SavedState::ParkExtruder) { + LogEchoEvent("Resuming XYZ"); - if (move_axes) { - LogEchoEvent("Resuming XYZ"); - - current_position[X_AXIS] = resume_position.xyz[X_AXIS]; - current_position[Y_AXIS] = resume_position.xyz[Y_AXIS]; - plan_buffer_line_curposXYZE(NOZZLE_PARK_XY_FEEDRATE); - st_synchronize(); - - current_position[Z_AXIS] = resume_position.xyz[Z_AXIS]; - plan_buffer_line_curposXYZE(NOZZLE_PARK_Z_FEEDRATE); - st_synchronize(); - } else { - LogEchoEvent("NOT resuming XYZ"); - } + current_position[X_AXIS] = resume_position.xyz[X_AXIS]; + current_position[Y_AXIS] = resume_position.xyz[Y_AXIS]; + plan_buffer_line_curposXYZE(NOZZLE_PARK_XY_FEEDRATE); + st_synchronize(); + + current_position[Z_AXIS] = resume_position.xyz[Z_AXIS]; + plan_buffer_line_curposXYZE(NOZZLE_PARK_Z_FEEDRATE); + st_synchronize(); + } else { + LogEchoEvent("NOT resuming XYZ"); } } @@ -534,6 +536,7 @@ void MMU2::CheckUserInput(){ case Left: case Middle: case Right: + ResumeHotendTemp(); // Recover the hotend temp before we attempt to do anything else... Button(btn); break; case RestartMMU: @@ -559,7 +562,7 @@ void MMU2::CheckUserInput(){ /// But - in case of an error, the command is not yet finished, but we must react accordingly - move the printhead elsewhere, stop heating, eat a cat or so. /// That's what's being done here... void MMU2::manage_response(const bool move_axes, const bool turn_off_nozzle) { - mmu_print_saved = false; + mmu_print_saved = SavedState::None; KEEPALIVE_STATE(PAUSED_FOR_USER); @@ -577,7 +580,7 @@ void MMU2::manage_response(const bool move_axes, const bool turn_off_nozzle) { case Finished: // command/operation completed, let Marlin continue its work // the E may have some more moves to finish - wait for them - ResumeAndUnPark(move_axes, turn_off_nozzle); // This is needed here otherwise recovery doesn't work. + ResumeUnpark(); // We can now travel back to the tower or wherever we were when we saved. st_synchronize(); return; case VersionMismatch: // this basically means the MMU will be disabled until reconnected @@ -591,7 +594,8 @@ void MMU2::manage_response(const bool move_axes, const bool turn_off_nozzle) { break; case CommunicationRecovered: // @@TODO communication recovered and may be an error recovered as well // may be the logic layer can detect the change of state a respond with one "Recovered" to be handled here - ResumeAndUnPark(move_axes, turn_off_nozzle); + ResumeHotendTemp(); + ResumeUnpark(); break; case Processing: // wait for the MMU to respond default: diff --git a/Firmware/mmu2.h b/Firmware/mmu2.h index 7008ac212..93a5ca3aa 100644 --- a/Firmware/mmu2.h +++ b/Firmware/mmu2.h @@ -58,6 +58,13 @@ public: ResetPin = 1, ///< trigger the reset pin of the MMU CutThePower = 2 ///< power off and power on (that includes +5V and +24V power lines) }; + + /// Saved print state on error. + enum SavedState: uint8_t { + None = 0, // No state saved. + ParkExtruder = 1, // The extruder was parked. + Cooldown = 2, // The extruder was allowed to cool. + }; /// Perform a reset of the MMU /// @param level physical form of the reset @@ -143,7 +150,7 @@ public: bool is_mmu_error_monitor_active; /// Method to read-only mmu_print_saved - bool MMU_PRINT_SAVED() const { return mmu_print_saved; } + bool MMU_PRINT_SAVED() const { return mmu_print_saved != SavedState::None; } private: /// Perform software self-reset of the MMU (sends an X0 command) @@ -193,8 +200,11 @@ private: /// Save print and park the print head void SaveAndPark(bool move_axes, bool turn_off_nozzle); - /// Resume print (unpark, turn on heating etc.) - void ResumeAndUnPark(bool move_axes, bool turn_off_nozzle); + /// Resume hotend temperature, if it was cooled. Safe to call if we aren't saved. + void ResumeHotendTemp(); + + /// Resume position, if the extruder was parked. Safe to all if state was not saved. + void ResumeUnpark(); /// Check for any button/user input coming from the printer's UI void CheckUserInput(); @@ -220,7 +230,7 @@ private: enum xState state; - bool mmu_print_saved; + uint8_t mmu_print_saved; bool loadFilamentStarted; friend struct LoadingToNozzleRAII; diff --git a/Firmware/mmu2_protocol.h b/Firmware/mmu2_protocol.h index 68fde9a1a..21170b131 100644 --- a/Firmware/mmu2_protocol.h +++ b/Firmware/mmu2_protocol.h @@ -37,7 +37,8 @@ enum class ResponseMsgParamCodes : uint8_t { Error = 'E', Finished = 'F', Accepted = 'A', - Rejected = 'R' + Rejected = 'R', + Button = 'B' // the MMU registered a button press and is sending it to the printer for processing }; /// A request message - requests are being sent by the printer into the MMU. diff --git a/Firmware/mmu2_reporting.cpp b/Firmware/mmu2_reporting.cpp index 38a14d108..226ee3ea9 100644 --- a/Firmware/mmu2_reporting.cpp +++ b/Firmware/mmu2_reporting.cpp @@ -27,7 +27,7 @@ void EndReport(CommandInProgress cip, uint16_t ec) { * @brief Renders any characters that will be updated live on the MMU error screen. *Currently, this is FINDA and Filament Sensor status and Extruder temperature. */ -static void ReportErrorHookDynamicRender(void) +extern void ReportErrorHookDynamicRender(void) { lcd_set_cursor(3, 2); lcd_printf_P(PSTR("%d"), mmu2.FindaDetectsFilament()); @@ -78,17 +78,23 @@ static void ReportErrorHookStaticRender(uint8_t ei) { lcd_update_enable(false); lcd_clear(); + ReportErrorHookSensorLineRender(); + // Print title and header lcd_printf_P(PSTR("%.20S\nprusa3d.com/ERR04%hu"), _T(PrusaErrorTitle(ei)), PrusaErrorCode(ei) ); - // Render static characters in third line - lcd_set_cursor(0, 2); - lcd_printf_P(PSTR("FI: FS: > %c %c"), LCD_STR_THERMOMETER[0], LCD_STR_DEGREE[0]); - // Render the choices lcd_show_choices_prompt_P(two_choices ? LCD_LEFT_BUTTON_CHOICE : LCD_MIDDLE_BUTTON_CHOICE, _T(PrusaErrorButtonTitle(button_op_middle)), _T(two_choices ? PrusaErrorButtonMore() : PrusaErrorButtonTitle(button_op_right)), two_choices ? 10 : 7, two_choices ? nullptr : _T(PrusaErrorButtonMore())); } +extern void ReportErrorHookSensorLineRender() +{ + // Render static characters in third line + lcd_set_cursor(0, 2); + lcd_printf_P(PSTR("FI: FS: > %c %c"), LCD_STR_THERMOMETER[0], LCD_STR_DEGREE[0]); +} + + /** * @brief Monitors the LCD button selection without blocking MMU communication * @param[in] ei Error code index diff --git a/Firmware/mmu2_reporting.h b/Firmware/mmu2_reporting.h index fedc6c1d7..8cb531780 100644 --- a/Firmware/mmu2_reporting.h +++ b/Firmware/mmu2_reporting.h @@ -28,6 +28,12 @@ void ReportErrorHook(uint16_t ec); /// Called when the MMU sends operation progress update void ReportProgressHook(CommandInProgress cip, uint16_t ec); +/// Remders the sensor status line. Also used by the "resume temperature" screen. +void ReportErrorHookDynamicRender(); + +/// Renders the static part of the sensor state line. Also used by "resuming temperature screen" +void ReportErrorHookSensorLineRender(); + /// @returns true if the MMU is communicating and available /// can change at runtime bool MMUAvailable();