diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index 835cb89b9..1590e2311 100644 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -678,7 +678,7 @@ void crashdet_cancel() saved_printing = false; tmc2130_sg_stop_on_crash = true; if (saved_printing_type == PRINTING_TYPE_SD) { - lcd_print_stop(); + print_stop(); }else if(saved_printing_type == PRINTING_TYPE_USB){ SERIAL_ECHOLNRPGM(MSG_OCTOPRINT_CANCEL); //for Octoprint: works the same as clicking "Abort" button in Octoprint GUI cmdqueue_reset(); @@ -7913,7 +7913,7 @@ Sigma_Exit: ### M603 - Stop print M603: Stop print */ case 603: { - lcd_print_stop(); + print_stop(); } break; @@ -9717,14 +9717,14 @@ void UnconditionalStop() // WARNING: This function is called *continuously* during a thermal failure. // // This either pauses (for thermal model errors) or stops *without recovery* depending on -// "allow_pause". If pause is allowed, this forces a printer-initiated instantanenous pause (just -// like an LCD pause) that bypasses the host pausing functionality. In this state the printer is -// kept in busy state and *must* be recovered from the LCD. -void ThermalStop(bool allow_pause) +// "allow_recovery". If recovery is allowed, this forces a printer-initiated instantanenous pause +// (just like an LCD pause) that bypasses the host pausing functionality. In this state the printer +// is kept in busy state and *must* be recovered from the LCD. +void ThermalStop(bool allow_recovery) { if(Stopped == false) { Stopped = true; - if(allow_pause && (IS_SD_PRINTING || usb_timer.running())) { + if(allow_recovery && (IS_SD_PRINTING || usb_timer.running())) { if (!isPrintPaused) { lcd_setalertstatuspgm(_T(MSG_PAUSED_THERMAL_ERROR), LCD_STATUS_CRITICAL); @@ -9743,10 +9743,7 @@ void ThermalStop(bool allow_pause) } } else { // We got a hard thermal error and/or there is no print going on. Just stop. - lcd_print_stop(); - - // Also prevent further menu entry - menu_set_block(MENU_BLOCK_THERMAL_ERROR); + print_stop(); } // Report the status on the serial, switch to a busy state @@ -9760,13 +9757,15 @@ void ThermalStop(bool allow_pause) // Make a warning sound! We cannot use Sound_MakeCustom as this would stop further moves. // Turn on the speaker here (if not already), and turn it off when back in the main loop. WRITE(BEEPER, HIGH); - } - // Return to the status screen to stop any pending menu action which could have been - // started by the user while stuck in the Stopped state. This also ensures the NEW - // error is immediately shown. - if (menu_menu != lcd_status_screen) + // Always return to the status screen to ensure the NEW error is immediately shown. lcd_return_to_status(); + + if(!allow_recovery) { + // prevent menu access for all fatal errors + menu_set_block(MENU_BLOCK_THERMAL_ERROR); + } + } } bool IsStopped() { return Stopped; }; diff --git a/Firmware/cmdqueue.cpp b/Firmware/cmdqueue.cpp index 31c0cb79c..c2c634bba 100755 --- a/Firmware/cmdqueue.cpp +++ b/Firmware/cmdqueue.cpp @@ -366,22 +366,24 @@ void get_command() comment_mode = false; //for new command return; } - cmdbuffer[bufindw+serial_count+CMDHDRSIZE] = 0; //terminate string + cmdbuffer[bufindw+serial_count+CMDHDRSIZE] = 0; // terminate string + char* cmd_head = cmdbuffer+bufindw+CMDHDRSIZE; // current command pointer + char* cmd_start = cmd_head; // pointer past the line number (if any) + if(!comment_mode){ - - long gcode_N = -1; + long gcode_N = -1; // seen line number // Line numbers must be first in buffer - if ((strstr_P(cmdbuffer+bufindw+CMDHDRSIZE, PSTR("PRUSA")) == NULL) && - (cmdbuffer[bufindw+CMDHDRSIZE] == 'N')) { + (*cmd_head == 'N')) { - // Line number met. When sending a G-code over a serial line, each line may be stamped with its index, - // and Marlin tests, whether the successive lines are stamped with an increasing line number ID - gcode_N = (strtol(cmdbuffer+bufindw+CMDHDRSIZE+1, NULL, 10)); - if(gcode_N != gcode_LastN+1 && (strstr_P(cmdbuffer+bufindw+CMDHDRSIZE, PSTR("M110")) == NULL) ) { - // M110 - set current line number. - // Line numbers not sent in succession. + // Line number met: decode the number, then move cmd_start past all spaces. + gcode_N = (strtol(cmd_head+1, &cmd_start, 10)); + while (*cmd_start == ' ') ++cmd_start; + + // Test whether the successive lines are stamped with an increasing line number ID. + if(gcode_N != gcode_LastN+1 && strncmp_P(cmd_start, PSTR("M110"), 4)) { + // Line numbers not sent in succession and M110 not seen. SERIAL_ERROR_START; SERIAL_ERRORRPGM(_n("Line Number is not Last Line Number+1, Last Line: "));////MSG_ERR_LINE_NO SERIAL_ERRORLN(gcode_LastN); @@ -391,10 +393,10 @@ void get_command() return; } - if((strchr_pointer = strchr(cmdbuffer+bufindw+CMDHDRSIZE, '*')) != NULL) + if((strchr_pointer = strchr(cmd_start, '*')) != NULL) { byte checksum = 0; - char *p = cmdbuffer+bufindw+CMDHDRSIZE; + char *p = cmd_head; while (p != strchr_pointer) checksum = checksum^(*p++); if (code_value_short() != (int16_t)checksum) { @@ -419,12 +421,11 @@ void get_command() } // Don't parse N again with code_seen('N') - cmdbuffer[bufindw + CMDHDRSIZE] = '$'; + *cmd_head = '$'; } // if we don't receive 'N' but still see '*' - if ((cmdbuffer[bufindw + CMDHDRSIZE] != 'N') && (cmdbuffer[bufindw + CMDHDRSIZE] != '$') && (strchr(cmdbuffer+bufindw+CMDHDRSIZE, '*') != NULL)) + if ((*cmd_head != 'N') && (*cmd_head != '$') && (strchr(cmd_start, '*') != NULL)) { - SERIAL_ERROR_START; SERIAL_ERRORRPGM(_n("No Line Number with checksum, Last Line: "));////MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM SERIAL_ERRORLN(gcode_LastN); @@ -432,16 +433,21 @@ void get_command() serial_count = 0; return; } + // Handle KILL early, even when Stopped - if(strcmp(cmdbuffer+bufindw+CMDHDRSIZE, "M112") == 0) + if(strcmp_P(cmd_start, PSTR("M112")) == 0) kill(MSG_M112_KILL, 2); + + // Bypass Stopped for some commands + bool allow_when_stopped = false; + if(strncmp_P(cmd_start, PSTR("M310"), 4) == 0) + allow_when_stopped = true; + // Handle the USB timer - if ((strchr_pointer = strchr(cmdbuffer+bufindw+CMDHDRSIZE, 'G')) != NULL) { - if (!IS_SD_PRINTING) { - usb_timer.start(); - } - } - if (Stopped == true) { + if ((*cmd_start == 'G') && !(IS_SD_PRINTING)) + usb_timer.start(); + + if (allow_when_stopped == false && Stopped == true) { // Stopped can be set either during error states (thermal error: cannot continue), or // when a printer-initiated action is processed. In such case the printer will send to // the host an action, but cannot know if the action has been processed while new diff --git a/Firmware/messages.cpp b/Firmware/messages.cpp index 5fc946ee6..d4acdfa31 100644 --- a/Firmware/messages.cpp +++ b/Firmware/messages.cpp @@ -165,6 +165,7 @@ extern const char MSG_PAUSED_THERMAL_ERROR[] PROGMEM_I1 = ISTR("PAUSED THERMAL E #ifdef TEMP_MODEL extern const char MSG_THERMAL_ANOMALY[] PROGMEM_I1 = ISTR("THERMAL ANOMALY");////MSG_THERMAL_ANOMALY c=20 extern const char MSG_TM_NOT_CAL[] PROGMEM_I1 = ISTR("Temp model not calibrated yet.");////MSG_TM_NOT_CAL c=20 r=4 +extern const char MSG_TM_ACK_ERROR[] PROGMEM_I1 = ISTR("Clear TM error");////MSG_TM_ACK_ERROR c=18 #endif extern const char MSG_NOZZLE_CNG_MENU [] PROGMEM_I1 = ISTR("Nozzle change");////MSG_NOZZLE_CNG_MENU c=18 extern const char MSG_NOZZLE_CNG_READ_HELP [] PROGMEM_I1 = ISTR("For a Nozzle change please read\nprusa.io/nozzle-mk3s");////MSG_NOZZLE_CNG_READ_HELP c=20 r=4 diff --git a/Firmware/messages.h b/Firmware/messages.h index 8197ac6f7..410818b4a 100644 --- a/Firmware/messages.h +++ b/Firmware/messages.h @@ -169,6 +169,7 @@ extern const char MSG_PAUSED_THERMAL_ERROR[]; #ifdef TEMP_MODEL extern const char MSG_THERMAL_ANOMALY[]; extern const char MSG_TM_NOT_CAL[]; +extern const char MSG_TM_ACK_ERROR[]; #endif extern const char MSG_NOZZLE_CNG_MENU []; extern const char MSG_NOZZLE_CNG_READ_HELP []; diff --git a/Firmware/temperature.cpp b/Firmware/temperature.cpp index 1f832aa98..a74acea0d 100755 --- a/Firmware/temperature.cpp +++ b/Firmware/temperature.cpp @@ -1766,7 +1766,6 @@ void handle_temp_error() } else { temp_error_state.v = 0; WRITE(BEEPER, LOW); - menu_unset_block(MENU_BLOCK_THERMAL_ERROR); // hotend error was transitory and disappeared, re-enable bed if (!target_temperature_bed) @@ -2442,6 +2441,7 @@ void handle_warning() lcd_setalertstatuspgm(_T(MSG_THERMAL_ANOMALY), LCD_STATUS_INFO); WRITE(BEEPER, HIGH); } + first = false; } else { if(warn_beep) TOGGLE(BEEPER); } diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp index 2d23d0300..8827ccdf1 100755 --- a/Firmware/ultralcd.cpp +++ b/Firmware/ultralcd.cpp @@ -835,7 +835,7 @@ void lcd_status_screen() // NOT static due to using ins } } -void print_stop(); +void lcd_print_stop_finish(); void lcd_commands() { @@ -853,7 +853,7 @@ void lcd_commands() lcd_setstatuspgm(_T(MSG_PRINT_ABORTED)); lcd_commands_type = LcdCommands::Idle; lcd_commands_step = 0; - print_stop(); + lcd_print_stop_finish(); } } @@ -5623,7 +5623,7 @@ static void lcd_main_menu() if ( moves_planned() || printer_active() ) { MENU_ITEM_SUBMENU_P(_i("Tune"), lcd_tune_menu);////MSG_TUNE c=18 - } else { + } else if (!Stopped) { MENU_ITEM_SUBMENU_P(_i("Preheat"), lcd_preheat_menu);////MSG_PREHEAT c=18 } @@ -5652,6 +5652,11 @@ static void lcd_main_menu() if((IS_SD_PRINTING || usb_timer.running() || isPrintPaused) && (custom_message_type != CustomMsg::MeshBedLeveling)) { MENU_ITEM_SUBMENU_P(_T(MSG_STOP_PRINT), lcd_sdcard_stop); } +#ifdef TEMP_MODEL + else if(Stopped) { + MENU_ITEM_SUBMENU_P(_T(MSG_TM_ACK_ERROR), lcd_print_stop); + } +#endif #ifdef SDSUPPORT //!@todo SDSUPPORT undefined creates several issues in source code if (card.cardOK || lcd_commands_type == LcdCommands::Layer1Cal) { if (!card.isFileOpen()) { @@ -5682,7 +5687,7 @@ static void lcd_main_menu() } } - if ( ! ( IS_SD_PRINTING || usb_timer.running() || (lcd_commands_type == LcdCommands::Layer1Cal) ) ) { + if ( ! ( IS_SD_PRINTING || usb_timer.running() || (lcd_commands_type == LcdCommands::Layer1Cal || Stopped) ) ) { if (mmu_enabled) { MENU_ITEM_SUBMENU_P(_T(MSG_LOAD_FILAMENT), mmu_load_filament_menu); MENU_ITEM_SUBMENU_P(_i("Load to nozzle"), mmu_load_to_nozzle_menu);////MSG_LOAD_TO_NOZZLE c=18 @@ -6050,7 +6055,7 @@ static void lcd_sd_updir() } // continue stopping the print from the main loop after lcd_print_stop() is called -void print_stop() +void lcd_print_stop_finish() { // save printing time stoptime = _millis(); @@ -6082,11 +6087,11 @@ void print_stop() axis_relative_modes = E_AXIS_MASK; //XYZ absolute, E relative } -void lcd_print_stop() +void print_stop(bool interactive) { - // UnconditionalStop() will internally cause planner_abort_hard(), meaning we _cannot_ plan - // any more move in this call! Any further move must happen inside print_stop(), which is called - // by the main loop one iteration later. + // UnconditionalStop() will internally cause planner_abort_hard(), meaning we _cannot_ plan any + // more move in this call! Any further move must happen inside lcd_print_stop_finish(), which is + // called by the main loop one iteration later. UnconditionalStop(); if (!card.sdprinting) { @@ -6101,11 +6106,21 @@ void lcd_print_stop() pause_time = 0; isPrintPaused = false; + if (interactive) { + // acknowledged by the user from the LCD: resume processing USB commands again + Stopped = false; + } + // return to status is required to continue processing in the main loop! lcd_commands_type = LcdCommands::StopPrint; lcd_return_to_status(); } +void lcd_print_stop() +{ + print_stop(true); +} + #ifdef TEMP_MODEL void lcd_temp_model_cal() { @@ -7707,13 +7722,13 @@ void lcd_setalertstatus_(const char* message, uint8_t severity, bool progmem) bool same = !(progmem? strcmp_P(lcd_status_message, message): strcmp(lcd_status_message, message)); - lcd_updatestatus(message, progmem); lcd_status_message_timeout.start(); lcd_status_message_level = severity; custom_message_type = CustomMsg::Status; custom_message_state = 0; if (!same) { // do not kick the user out of the menus if the message is unchanged + lcd_updatestatus(message, progmem); lcd_return_to_status(); } } @@ -7745,7 +7760,7 @@ void menu_lcd_longpress_func(void) // start LCD inactivity timer lcd_timeoutToStatus.start(); backlight_wake(); - if (homing_flag || mesh_bed_leveling_flag || menu_menu == lcd_babystep_z || menu_menu == lcd_move_z || menu_block_mask != MENU_BLOCK_NONE) + if (homing_flag || mesh_bed_leveling_flag || menu_menu == lcd_babystep_z || menu_menu == lcd_move_z || menu_block_mask != MENU_BLOCK_NONE || Stopped) { // disable longpress during re-entry, while homing, calibration or if a serious error lcd_quick_feedback(); diff --git a/Firmware/ultralcd.h b/Firmware/ultralcd.h index 467acb3fc..f45935fc2 100755 --- a/Firmware/ultralcd.h +++ b/Firmware/ultralcd.h @@ -47,7 +47,8 @@ void lcd_sdcard_stop(); void lcd_pause_print(); void lcd_pause_usb_print(); void lcd_resume_print(); -void lcd_print_stop(); +void lcd_print_stop(); // interactive print stop +void print_stop(bool interactive=false); #ifdef TEMP_MODEL void lcd_temp_model_cal(); #endif //TEMP_MODEL