Browse Source

Merge pull request #3822 from wavexx/tm_partial_lock

MK3: TM: Prevent lockout on invalid model values
3d-gussner 1 year ago
parent
commit
0bcb4ab59d
7 changed files with 76 additions and 53 deletions
  1. 15 16
      Firmware/Marlin_main.cpp
  2. 30 24
      Firmware/cmdqueue.cpp
  3. 1 0
      Firmware/messages.cpp
  4. 1 0
      Firmware/messages.h
  5. 1 1
      Firmware/temperature.cpp
  6. 26 11
      Firmware/ultralcd.cpp
  7. 2 1
      Firmware/ultralcd.h

+ 15 - 16
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 <a href="https://reprap.org/wiki/G-code#M603:_Stop_print">M603: Stop print</a>
     */
     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; };

+ 30 - 24
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')) {
-
-			  // 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.
+			  (*cmd_head == 'N')) {
+
+			  // 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

+ 1 - 0
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

+ 1 - 0
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 [];

+ 1 - 1
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);
         }

+ 26 - 11
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();

+ 2 - 1
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