diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index 21b6698cc..f975c34e6 100644 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -675,7 +675,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(); @@ -7885,7 +7885,7 @@ Sigma_Exit: ### M603 - Stop print M603: Stop print */ case 603: { - lcd_print_stop(); + print_stop(); } break; @@ -9612,14 +9612,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); @@ -9638,10 +9638,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 @@ -9655,13 +9652,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 f41d19671..c0636a76a 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 80254ae62..c50bc36a7 100644 --- a/Firmware/messages.cpp +++ b/Firmware/messages.cpp @@ -169,6 +169,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_LOAD_ALL[] PROGMEM_I1 = ISTR("Load All"); ////MSG_LOAD_ALL c=18 extern const char MSG_NOZZLE_CNG_MENU [] PROGMEM_I1 = ISTR("Nozzle change");////MSG_NOZZLE_CNG_MENU c=18 diff --git a/Firmware/messages.h b/Firmware/messages.h index 497824d80..c5fa61392 100644 --- a/Firmware/messages.h +++ b/Firmware/messages.h @@ -173,6 +173,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_LOAD_ALL[]; extern const char MSG_NOZZLE_CNG_MENU []; diff --git a/Firmware/temperature.cpp b/Firmware/temperature.cpp index 142a30930..2075e7240 100755 --- a/Firmware/temperature.cpp +++ b/Firmware/temperature.cpp @@ -1764,7 +1764,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) @@ -2440,6 +2439,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 5dcc31706..86f1ae4b9 100644 --- a/Firmware/ultralcd.cpp +++ b/Firmware/ultralcd.cpp @@ -819,7 +819,7 @@ void lcd_status_screen() // NOT static due to using ins } } -void print_stop(); +void lcd_print_stop_finish(); void lcd_commands() { @@ -837,7 +837,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(); } } @@ -5456,7 +5456,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 } @@ -5485,6 +5485,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()) { @@ -5515,7 +5520,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 (MMU2::mmu2.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 @@ -5873,7 +5878,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(); @@ -5916,11 +5921,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) { @@ -5935,11 +5940,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() { @@ -7503,13 +7518,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(); } } @@ -7541,7 +7556,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 5c7468cfc..32ea8073b 100755 --- a/Firmware/ultralcd.h +++ b/Firmware/ultralcd.h @@ -46,7 +46,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