Browse Source

Merge pull request #990 from PavelSindler/snmm_v2

Snmm v2: M600, communication timeouts with mmu
PavelSindler 6 years ago
parent
commit
d363bd071d

+ 10 - 4
Firmware/Marlin.h

@@ -354,6 +354,9 @@ extern char dir_names[3][9];
 // save/restore printing
 extern bool saved_printing;
 
+//save/restore printing in case that mmu is not responding
+extern bool mmu_print_saved;
+
 //estimated time to end of the print
 extern uint8_t print_percent_done_normal;
 extern uint16_t print_time_remaining_normal;
@@ -361,7 +364,7 @@ extern uint8_t print_percent_done_silent;
 extern uint16_t print_time_remaining_silent;
 #define PRINT_TIME_REMAINING_INIT 65535
 #define PRINT_PERCENT_DONE_INIT 255
-#define PRINTER_ACTIVE (IS_SD_PRINTING || is_usb_printing || isPrintPaused || (custom_message_type == 4) || saved_printing || (lcd_commands_type == LCD_COMMAND_V2_CAL) || card.paused)
+#define PRINTER_ACTIVE (IS_SD_PRINTING || is_usb_printing || isPrintPaused || (custom_message_type == 4) || saved_printing || (lcd_commands_type == LCD_COMMAND_V2_CAL) || card.paused || mmu_print_saved)
 
 extern void calculate_extruder_multipliers();
 
@@ -464,9 +467,12 @@ void gcode_M701();
 
 void proc_commands();
 
-bool mmu_get_reponse(bool timeout);
+void manage_response();
+bool mmu_get_response(bool timeout);
 void mmu_not_responding();
 void mmu_load_to_nozzle();
 void M600_load_filament();
-void mmu_M600_load_filament();
-void M600_load_filament_movements();
+void mmu_M600_load_filament(bool automatic);
+void M600_load_filament_movements();
+void M600_wait_for_user();
+void M600_check_state();

+ 341 - 365
Firmware/Marlin_main.cpp

@@ -319,7 +319,7 @@ unsigned long kicktime = millis()+100000;
 
 unsigned int  usb_printing_counter;
 
-int lcd_change_fil_state = 0;
+int8_t lcd_change_fil_state = 0;
 
 int feedmultiplyBckp = 100;
 float HotendTempBckp = 0;
@@ -462,6 +462,9 @@ uint8_t saved_filament_type;
 // save/restore printing
 bool saved_printing = false;
 
+// save/restore printing in case that mmu was not responding 
+bool mmu_print_saved = false;
+
 // storing estimated time to end of print counted by slicer
 uint8_t print_percent_done_normal = PRINT_PERCENT_DONE_INIT;
 uint16_t print_time_remaining_normal = PRINT_TIME_REMAINING_INIT; //estimated remaining print time in minutes
@@ -3073,6 +3076,112 @@ void gcode_M114()
 	SERIAL_PROTOCOLLN("");
 }
 
+void gcode_M600(bool automatic, float x_position, float y_position, float z_shift, float e_shift, float e_shift_late) {
+		st_synchronize();
+		float lastpos[4];
+
+		if (farm_mode)
+		{
+			prusa_statistics(22);
+		}
+
+		//First backup current position and settings
+        feedmultiplyBckp=feedmultiply;
+        float HotendTempBckp = degTargetHotend(active_extruder);
+		int fanSpeedBckp = fanSpeed;
+        lastpos[X_AXIS]=current_position[X_AXIS];
+        lastpos[Y_AXIS]=current_position[Y_AXIS];
+        lastpos[Z_AXIS]=current_position[Z_AXIS];
+        lastpos[E_AXIS]=current_position[E_AXIS];
+
+		//Retract E
+        current_position[E_AXIS]+= e_shift;
+        plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], FILAMENTCHANGE_RFEED, active_extruder);
+		st_synchronize();
+
+        //Lift Z
+        current_position[Z_AXIS]+= z_shift;
+        plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], FILAMENTCHANGE_ZFEED, active_extruder);
+		st_synchronize();
+        
+		//Move XY to side
+        current_position[X_AXIS]= x_position;
+        current_position[Y_AXIS]= y_position;
+        plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], FILAMENTCHANGE_XYFEED, active_extruder);
+		st_synchronize();
+		
+		//Beep, manage nozzle heater and wait for user to start unload filament
+		if(!automatic) M600_wait_for_user();
+		
+		lcd_change_fil_state = 0;
+		
+		// Unload filament
+#if defined (SNMM) || defined (SNMM_V2) 
+		extr_unload(); //unload just current filament
+#else
+		unload_filament(); //unload filament fopr single material (used also in M702)
+#endif 
+		//finish moves
+		st_synchronize();
+
+			
+#if !defined(SNMM_V2) && !defined(SNMM)
+			KEEPALIVE_STATE(PAUSED_FOR_USER);
+			lcd_change_fil_state = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Was filament unload successful?"), false, true);////MSG_UNLOAD_SUCCESSFUL c=20 r=2
+			if (lcd_change_fil_state == 0) lcd_show_fullscreen_message_and_wait_P(_i("Please open idler and remove filament manually."));////MSG_CHECK_IDLER c=20 r=4
+			
+			lcd_update_enable(true);
+		}
+#endif
+
+#ifdef SNMM_V2
+		mmu_M600_load_filament(automatic);
+#else		
+		M600_load_filament();
+#endif    
+
+		if(!automatic) M600_check_state();
+
+      //Not let's go back to print
+	  fanSpeed = fanSpeedBckp;
+
+      //Feed a little of filament to stabilize pressure
+	  if (!automatic) {
+		  current_position[E_AXIS] += FILAMENTCHANGE_RECFEED;
+		  plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], FILAMENTCHANGE_EXFEED, active_extruder);
+	  }
+      
+      //Move XY back
+      plan_buffer_line(lastpos[X_AXIS], lastpos[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], FILAMENTCHANGE_XYFEED, active_extruder);
+      st_synchronize();
+      //Move Z back
+      plan_buffer_line(lastpos[X_AXIS], lastpos[Y_AXIS], lastpos[Z_AXIS], current_position[E_AXIS], FILAMENTCHANGE_ZFEED, active_extruder);
+      st_synchronize();  
+      
+	  //Unretract
+      current_position[E_AXIS]= current_position[E_AXIS] - FILAMENTCHANGE_FIRSTRETRACT;
+      plan_buffer_line(lastpos[X_AXIS], lastpos[Y_AXIS], lastpos[Z_AXIS], current_position[E_AXIS], FILAMENTCHANGE_RFEED, active_extruder);
+	  st_synchronize();
+
+      //Set E position to original  
+      plan_set_e_position(lastpos[E_AXIS]);
+
+	  memcpy(current_position, lastpos, sizeof(lastpos));
+	  memcpy(destination, current_position, sizeof(current_position));
+       
+      //Recover feed rate 
+      feedmultiply=feedmultiplyBckp;
+      char cmd[9];
+      sprintf_P(cmd, PSTR("M220 S%i"), feedmultiplyBckp);
+      enquecommand(cmd);
+      
+	  lcd_setstatuspgm(_T(WELCOME_MSG));
+	  custom_message = false;
+	  custom_message_type = 0;
+        
+}
+
+
 void gcode_M701()
 {
 	printf_P(PSTR("gcode_M701 begin\n"));
@@ -6253,359 +6362,83 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 
     #ifdef FILAMENTCHANGEENABLE
     case 600: //Pause for filament change X[pos] Y[pos] Z[relative lift] E[initial retract] L[later retract distance for removal]
-    {
-
+	{
 		st_synchronize();
-		float lastpos[4];
-
-        if (farm_mode)
-            
-        {
-            
-            prusa_statistics(22);
-            
-        }
-        
-        feedmultiplyBckp=feedmultiply;
 
-		float HotendTempBckp = degTargetHotend(active_extruder);
-		int fanSpeedBckp = fanSpeed;
-        lastpos[X_AXIS]=current_position[X_AXIS];
-        lastpos[Y_AXIS]=current_position[Y_AXIS];
-        lastpos[Z_AXIS]=current_position[Z_AXIS];
-        lastpos[E_AXIS]=current_position[E_AXIS];
-
-        //Restract extruder
+		float x_position = current_position[X_AXIS];
+		float y_position = current_position[Y_AXIS];
+		float z_shift = 0;
+		float e_shift_init = 0;
+		float e_shift_late = 0;
+		bool automatic = false;
+		
+        //Retract extruder
         if(code_seen('E'))
         {
-          current_position[E_AXIS]+= code_value();
+          e_shift_init = code_value();
         }
         else
         {
           #ifdef FILAMENTCHANGE_FIRSTRETRACT
-            current_position[E_AXIS]+= FILAMENTCHANGE_FIRSTRETRACT ;
+            e_shift_init = FILAMENTCHANGE_FIRSTRETRACT ;
           #endif
         }
-        plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], FILAMENTCHANGE_RFEED, active_extruder);
+
+		//currently don't work as we are using the same unload sequence as in M702, needs re-work 
+		if (code_seen('L'))
+		{
+			e_shift_late = code_value();
+		}
+		else
+		{
+		  #ifdef FILAMENTCHANGE_FINALRETRACT
+			e_shift_late = FILAMENTCHANGE_FINALRETRACT;
+		  #endif	
+		}
 
         //Lift Z
         if(code_seen('Z'))
         {
-          current_position[Z_AXIS]+= code_value();
+          z_shift = code_value();
         }
         else
         {
           #ifdef FILAMENTCHANGE_ZADD
-            current_position[Z_AXIS]+= FILAMENTCHANGE_ZADD ;
-            if(current_position[Z_AXIS] < 10){
-              current_position[Z_AXIS]+= 10 ;
-            }
+            z_shift= FILAMENTCHANGE_ZADD ;
+            if(current_position[Z_AXIS] < 25) z_shift+= 25 ;
           #endif
-     
-          
         }
-        plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], FILAMENTCHANGE_ZFEED, active_extruder);
-
-        //Move XY to side
+		//Move XY to side
         if(code_seen('X'))
         {
-          current_position[X_AXIS]+= code_value();
+          x_position = code_value();
         }
         else
         {
           #ifdef FILAMENTCHANGE_XPOS
-            current_position[X_AXIS]= FILAMENTCHANGE_XPOS ;
+			x_position = FILAMENTCHANGE_XPOS;
           #endif
         }
         if(code_seen('Y'))
         {
-          current_position[Y_AXIS]= code_value();
+          y_position = code_value();
         }
         else
         {
           #ifdef FILAMENTCHANGE_YPOS
-            current_position[Y_AXIS]= FILAMENTCHANGE_YPOS ;
+            y_position = FILAMENTCHANGE_YPOS ;
           #endif
         }
-        plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], FILAMENTCHANGE_XYFEED, active_extruder);
-		st_synchronize();
-		KEEPALIVE_STATE(PAUSED_FOR_USER);
-
-		int counterBeep = 0;	
-		fanSpeed = 0;
-		unsigned long waiting_start_time = millis();
-		uint8_t wait_for_user_state = 0;
-		lcd_display_message_fullscreen_P(_T(MSG_PRESS_TO_UNLOAD));
-          bool bFirst=true;
-		while (!(wait_for_user_state == 0 && lcd_clicked())){
-
-			manage_heater();
-			manage_inactivity(true);
-
-#if BEEPER > 0
-				if (counterBeep == 500) {
-					counterBeep = 0;
-				}
-				SET_OUTPUT(BEEPER);
-				if (counterBeep == 0) {
-                         if((eSoundMode==e_SOUND_MODE_LOUD)||((eSoundMode==e_SOUND_MODE_ONCE)&&bFirst)) {
-                              bFirst=false;
-					     WRITE(BEEPER, HIGH);
-                         }
-				}
-				if (counterBeep == 20) {
-					WRITE(BEEPER, LOW);
-				}
-				
-				counterBeep++;
-#endif
-			
-			switch (wait_for_user_state) {
-			case 0: 
-				delay_keep_alive(4);
-
-				if (millis() > 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);
-					st_synchronize();
-					disable_e0();
-					disable_e1();
-					disable_e2();
-				}
-				break;
-			case 1:
-				delay_keep_alive(4);
-		
-				if (lcd_clicked()) {
-					setTargetHotend(HotendTempBckp, active_extruder);
-					lcd_wait_for_heater();
 
-					wait_for_user_state = 2;
-				}
-				break;
-			case 2:
-
-				if (abs(degTargetHotend(active_extruder) - degHotend(active_extruder)) < 1) {
-					lcd_display_message_fullscreen_P(_T(MSG_PRESS_TO_UNLOAD));
-					waiting_start_time = millis();
-					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)));
-				}
-				break;
-
-			}
-
-		}
-		WRITE(BEEPER, LOW);
-		
-		lcd_change_fil_state = 0;
-		
-
-		// Unload filament
-			lcd_display_message_fullscreen_P(_T(MSG_UNLOADING_FILAMENT));
-			KEEPALIVE_STATE(IN_HANDLER);
-			custom_message = true;
-			lcd_setstatuspgm(_T(MSG_UNLOADING_FILAMENT));
-
-			if (code_seen('L'))
-			{
-				current_position[E_AXIS] += code_value();
-			}
-			else
-			{
-#ifdef SNMM
-
-#else
-#ifdef FILAMENTCHANGE_FINALRETRACT
-				current_position[E_AXIS] += FILAMENTCHANGE_FINALRETRACT;
-#endif
-#endif // SNMM
-			}
-
-#ifdef SNMM
-			current_position[E_AXIS] += 12;
-			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3500, active_extruder);
-			current_position[E_AXIS] += 6;
-			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 5000, active_extruder);
-			current_position[E_AXIS] += (FIL_LOAD_LENGTH * -1);
-			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 5000, active_extruder);
-			st_synchronize();
-			current_position[E_AXIS] += (FIL_COOLING);
-			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 50, active_extruder);
-			current_position[E_AXIS] += (FIL_COOLING*-1);
-			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 50, active_extruder);
-			current_position[E_AXIS] += (bowden_length[snmm_extruder] * -1);
-			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000, active_extruder);
-			st_synchronize();
-
-#else
-			//		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], FILAMENTCHANGE_RFEED, active_extruder);
-			//plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3500 / 60, active_extruder);
-            
-            current_position[E_AXIS] -= FILAMENTCHANGE_FINALRETRACT;
-            st_synchronize();
-#ifdef TMC2130
-            uint8_t tmc2130_current_r_bckp = tmc2130_current_r[E_AXIS];
-            tmc2130_set_current_r(E_AXIS, TMC2130_UNLOAD_CURRENT_R);
-#else 
-
-			st_current_set(2, 200); //set lower E motor current for unload to protect filament sensor and ptfe tube
-			float tmp_motor[3] = DEFAULT_PWM_MOTOR_CURRENT;
-			float tmp_motor_loud[3] = DEFAULT_PWM_MOTOR_CURRENT_LOUD;
-
-#endif //TMC2130
-
-            current_position[E_AXIS] -= 45;
-            plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 5200 / 60, active_extruder);
-            st_synchronize();
-            current_position[E_AXIS] -= 15;
-            plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 1000 / 60, active_extruder);
-            st_synchronize();
-            current_position[E_AXIS] -= 20;
-            plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 1000 / 60, active_extruder);
-            st_synchronize();
-
-#ifdef TMC2130            
-            tmc2130_set_current_r(E_AXIS, tmc2130_current_r_bckp);
-#else
-			uint8_t silentMode = eeprom_read_byte((uint8_t*)EEPROM_SILENT);
-			if(silentMode != SILENT_MODE_POWER) st_current_set(2, tmp_motor[2]); //set E back to normal operation currents
-			else st_current_set(2, tmp_motor_loud[2]);		
-#endif //TMC2130
-
-#endif // SNMM
-
-
-			//finish moves
-			st_synchronize();
-
-			//disable extruder steppers so filament can be removed
-			disable_e0();
-			disable_e1();
-			disable_e2();
-			delay(100);
-
-#ifdef SNMM_V2
-			fprintf_P(uart2io, PSTR("U0\n"));
-
-			// get response
-			bool response = mmu_get_reponse(false);
-			if (!response) mmu_not_responding();
-#else
-			lcd_display_message_fullscreen_P(_T(MSG_PULL_OUT_FILAMENT));
-			
-
-			 
-			
-if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
-			WRITE(BEEPER, HIGH);
-			counterBeep = 0;
-			while(!lcd_clicked() && (counterBeep < 50)) {
-				if(counterBeep > 5) WRITE(BEEPER, LOW);
-				delay_keep_alive(100);
-				counterBeep++;
-			}
-			WRITE(BEEPER, LOW);
-#endif
-
-			KEEPALIVE_STATE(PAUSED_FOR_USER);
-			lcd_change_fil_state = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Was filament unload successful?"), false, true);////MSG_UNLOAD_SUCCESSFUL c=20 r=2
-			if (lcd_change_fil_state == 0) lcd_show_fullscreen_message_and_wait_P(_i("Please open idler and remove filament manually."));////MSG_CHECK_IDLER c=20 r=4
-			//lcd_return_to_status();
-			lcd_update_enable(true);
-		
-
-#ifdef SNMM_V2
-		mmu_M600_load_filament();
-#else		
-		M600_load_filament();
-#endif    
-
-		//Wait for user to check the state
-        lcd_change_fil_state = 0;
-		
-		while ((lcd_change_fil_state == 0)||(lcd_change_fil_state != 1)){
-          lcd_change_fil_state = 0;
-		  KEEPALIVE_STATE(PAUSED_FOR_USER);
-          lcd_alright();
-		  KEEPALIVE_STATE(IN_HANDLER);
-          switch(lcd_change_fil_state){
-            
-             // Filament failed to load so load it again
-             case 2:
 #ifdef SNMM_V2
-                     mmu_M600_load_filament(); //change to "wrong filament loaded" option?
-#else
-                     M600_load_filament_movements();
-#endif
-                     break;
-
-             // Filament loaded properly but color is not clear
-             case 3:
-                     current_position[E_AXIS]+= FILAMENTCHANGE_FINALFEED ;
-                     plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2, active_extruder); 
-                     lcd_loading_color();
-                     break;
-                 
-             // Everything good             
-             default:
-                     lcd_change_success();
-					 lcd_update_enable(true);
-                     break;
-          }
-          
-        }
-        
-
-      //Not let's go back to print
-	  fanSpeed = fanSpeedBckp;
-
-      //Feed a little of filament to stabilize pressure
-      current_position[E_AXIS]+= FILAMENTCHANGE_RECFEED;
-      plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], FILAMENTCHANGE_EXFEED, active_extruder);
-        
-      //Retract
-      current_position[E_AXIS]+= FILAMENTCHANGE_FIRSTRETRACT;
-      plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], FILAMENTCHANGE_RFEED, active_extruder);
-        
-
-        
-      //plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 70, active_extruder); //should do nothing
-      
-      //Move XY back
-      plan_buffer_line(lastpos[X_AXIS], lastpos[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], FILAMENTCHANGE_XYFEED, active_extruder);
-      
-      //Move Z back
-      plan_buffer_line(lastpos[X_AXIS], lastpos[Y_AXIS], lastpos[Z_AXIS], current_position[E_AXIS], FILAMENTCHANGE_ZFEED, active_extruder);
-        
-        
-      current_position[E_AXIS]= current_position[E_AXIS] - FILAMENTCHANGE_FIRSTRETRACT;
-        
-      //Unretract       
-      plan_buffer_line(lastpos[X_AXIS], lastpos[Y_AXIS], lastpos[Z_AXIS], current_position[E_AXIS], FILAMENTCHANGE_RFEED, active_extruder);
-        
-      //Set E position to original  
-      plan_set_e_position(lastpos[E_AXIS]);
+		if (code_seen("AUTO")) {
+			automatic = true;
+		}
+#endif //SNMM_V2
 
-	  memcpy(current_position, lastpos, sizeof(lastpos));
-	  memcpy(destination, current_position, sizeof(current_position));
-       
-      //Recover feed rate 
-      feedmultiply=feedmultiplyBckp;
-      char cmd[9];
-      sprintf_P(cmd, PSTR("M220 S%i"), feedmultiplyBckp);
-      enquecommand(cmd);
-      
-	  lcd_setstatuspgm(_T(WELCOME_MSG));
-	  custom_message = false;
-	  custom_message_type = 0;
-        
-    }
+		gcode_M600(automatic, x_position, y_position, z_shift, e_shift_init, e_shift_late);
+	
+	}
     break;
     #endif //FILAMENTCHANGEENABLE
 	case 601: {
@@ -6926,47 +6759,10 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 			extr_unload(); //unload just current filament 
 		}
 		else {
-			  extr_unload_all(); //unload all filaments
+			extr_unload_all(); //unload all filaments
 		}
 #else
-		custom_message = true;
-		custom_message_type = 2;
-		lcd_setstatuspgm(_T(MSG_UNLOADING_FILAMENT)); 
-
-//		extr_unload2();
-		
-		current_position[E_AXIS] -= 45;
-		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 5200 / 60, active_extruder);
-        st_synchronize();
-        current_position[E_AXIS] -= 15;
-        plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 1000 / 60, active_extruder);
-        st_synchronize();
-        current_position[E_AXIS] -= 20;
-        plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 1000 / 60, active_extruder);
-		st_synchronize();
-
-		lcd_display_message_fullscreen_P(_T(MSG_PULL_OUT_FILAMENT));
-
-		//disable extruder steppers so filament can be removed
-		disable_e0();
-		disable_e1();
-		disable_e2();
-		delay(100);
-
-          Sound_MakeSound(e_SOUND_CLASS_Prompt,e_SOUND_TYPE_StandardPrompt);
-          uint8_t counterBeep = 0;
-          while (!lcd_clicked() && (counterBeep < 50)) {
-	         delay_keep_alive(100);
-	         counterBeep++;
-          }
-		st_synchronize();	
-		while (lcd_clicked()) delay_keep_alive(100);
-
-		lcd_update_enable(true);
-	
-		lcd_setstatuspgm(_T(WELCOME_MSG));
-		custom_message = false;
-		custom_message_type = 0;
+		unload_filament();
 #endif	
 	}
 	break;
@@ -7007,8 +6803,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 		  printf_P(PSTR("T code: %d \n"), tmp_extruder);
 		  fprintf_P(uart2io, PSTR("T%d\n"), tmp_extruder);
 
-		  bool response = mmu_get_reponse(false);
-		  if (!response) mmu_not_responding();
+		  manage_response();
 
     	  snmm_extruder = tmp_extruder; //filament change is finished
 
@@ -9043,7 +8838,7 @@ static void print_time_remaining_init() {
 	print_percent_done_silent = PRINT_PERCENT_DONE_INIT;
 }
 
-bool mmu_get_reponse(bool timeout) {
+bool mmu_get_response(bool timeout) {
 	bool response = true;
 	LongTimer mmu_get_reponse_timeout;
     uart2_rx_clr();
@@ -9052,7 +8847,7 @@ bool mmu_get_reponse(bool timeout) {
 	while (!uart2_rx_ok())
     {
       delay_keep_alive(100);
-	  if (timeout && mmu_get_reponse_timeout.expired(180 * 1000ul)) { //3 minutes timeout
+	  if (timeout && mmu_get_reponse_timeout.expired(5 * 60 * 1000ul)) { //5 minutes timeout
 			response = false;
 			break;
 	  }
@@ -9060,8 +8855,66 @@ bool mmu_get_reponse(bool timeout) {
 	return response;
 }
 
-void mmu_not_responding() {
-	printf_P(PSTR("MMU not responding"));
+
+void manage_response() {
+	bool response = false;
+	mmu_print_saved = false;
+	bool lcd_update_was_enabled = false;
+	float hotend_temp_bckp;
+	float z_position_bckp, x_position_bckp, y_position_bckp;
+	while(!response) {
+		  response = mmu_get_response(true);
+		  if (!response) {
+			  if (!mmu_print_saved) { //first occurence
+				  if (lcd_update_enabled) {
+					  lcd_update_was_enabled = true;
+					  lcd_update_enable(false);
+				  }
+				  st_synchronize();
+				  mmu_print_saved = true;
+				  
+				  hotend_temp_bckp = degTargetHotend(active_extruder);
+				  z_position_bckp = current_position[Z_AXIS];
+				  x_position_bckp = current_position[X_AXIS];
+				  y_position_bckp = current_position[Y_AXIS];
+
+				  //lift z
+				  current_position[Z_AXIS] += Z_PAUSE_LIFT;
+				  if (current_position[Z_AXIS] > Z_MAX_POS) current_position[Z_AXIS] = Z_MAX_POS;
+				  plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 15, active_extruder);
+				  st_synchronize();
+				  //set nozzle target temperature to 0
+				  setAllTargetHotends(0);
+
+				  //Move XY to side
+				  current_position[X_AXIS] = X_PAUSE_POS;
+				  current_position[Y_AXIS] = Y_PAUSE_POS;
+				  plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 50, active_extruder);
+				  st_synchronize();
+			  }
+			  printf_P(PSTR("MMU not responding\n"));
+			  lcd_show_fullscreen_message_and_wait_P(_i("MMU needs user attention. Please press knob to resume nozzle target temperature."));
+			  setTargetHotend(hotend_temp_bckp, active_extruder);
+			  while ((degTargetHotend(active_extruder) - degHotend(active_extruder)) > 5) {
+				  delay_keep_alive(1000);
+				  lcd_wait_for_heater();
+			  }			
+			  lcd_display_message_fullscreen_P(_i("Now check MMU. Fix the issue and then press knob on MMU unit."));
+		  }
+		  else if (mmu_print_saved) {
+			  printf_P(PSTR("MMU start responding\n"));
+			  lcd_clear();
+			  lcd_display_message_fullscreen_P(_i("MMU OK. Resuming..."));
+			  current_position[X_AXIS] = x_position_bckp;
+			  current_position[Y_AXIS] = y_position_bckp;
+			  plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 50, active_extruder);
+			  st_synchronize();
+			  current_position[Z_AXIS] = z_position_bckp;
+			  plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 15, active_extruder);
+			  st_synchronize();			  
+		  }
+	}
+	if (lcd_update_was_enabled) lcd_update_enable(true);
 }
 
 void mmu_load_to_nozzle() {
@@ -9103,21 +8956,144 @@ void mmu_switch_extruder(uint8_t extruder) {
 
 }
 
-void mmu_M600_load_filament() {
+void M600_check_state() {
+		//Wait for user to check the state
+		lcd_change_fil_state = 0;
+		
+		while ((lcd_change_fil_state == 0)||(lcd_change_fil_state != 1)){
+			lcd_change_fil_state = 0;
+			KEEPALIVE_STATE(PAUSED_FOR_USER);
+			lcd_alright();
+			KEEPALIVE_STATE(IN_HANDLER);
+			switch(lcd_change_fil_state){
+				// Filament failed to load so load it again
+				case 2:
+					#ifdef SNMM_V2
+					mmu_M600_load_filament(false); //nonautomatic load; change to "wrong filament loaded" option?
+					#else
+					M600_load_filament_movements();
+					#endif
+					break;
+
+				// Filament loaded properly but color is not clear
+				case 3:
+					current_position[E_AXIS]+= FILAMENTCHANGE_FINALFEED ;
+					plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2, active_extruder); 
+					lcd_loading_color();
+					break;
+                 
+				// Everything good             
+				default:
+					lcd_change_success();
+					lcd_update_enable(true);
+					break;
+			}
+	}
+}
+
+void M600_wait_for_user() {
+		KEEPALIVE_STATE(PAUSED_FOR_USER);
+
+		int counterBeep = 0;	
+
+		unsigned long waiting_start_time = millis();
+		uint8_t wait_for_user_state = 0;
+		lcd_display_message_fullscreen_P(_T(MSG_PRESS_TO_UNLOAD));
+		//-//
+		bool bFirst=true;
+
+
+			while (!(wait_for_user_state == 0 && lcd_clicked())){
+
+			manage_heater();
+			manage_inactivity(true);
+
+				#if BEEPER > 0
+				if (counterBeep == 500) {
+					counterBeep = 0;
+				}
+				SET_OUTPUT(BEEPER);
+				if (counterBeep == 0) {
+					//-//
+					//if(eSoundMode==e_SOUND_MODE_LOUD)
+					if((eSoundMode==e_SOUND_MODE_LOUD)||((eSoundMode==e_SOUND_MODE_ONCE)&&bFirst))
+					{
+						bFirst=false;
+						WRITE(BEEPER, HIGH);
+					}
+				}
+				if (counterBeep == 20) {
+					WRITE(BEEPER, LOW);
+				}
+				
+				counterBeep++;
+#endif
+			
+			switch (wait_for_user_state) {
+			case 0: 
+				delay_keep_alive(4);
+
+				if (millis() > 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;
+					setTargetHotend(0, 0);
+					setTargetHotend(0, 1);
+					setTargetHotend(0, 2);
+					st_synchronize();
+					disable_e0();
+					disable_e1();
+					disable_e2();
+				}
+				break;
+			case 1:
+				delay_keep_alive(4);
+		
+				if (lcd_clicked()) {
+					setTargetHotend(HotendTempBckp, active_extruder);
+					lcd_wait_for_heater();
+
+					wait_for_user_state = 2;
+				}
+				break;
+			case 2:
+
+				if (abs(degTargetHotend(active_extruder) - degHotend(active_extruder)) < 1) {
+					lcd_display_message_fullscreen_P(_T(MSG_PRESS_TO_UNLOAD));
+					waiting_start_time = millis();
+					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)));
+				}
+				break;
+
+			}
+
+		}
+		WRITE(BEEPER, LOW);
+}
+
+void mmu_M600_load_filament(bool automatic) {
 #ifdef SNMM_V2
 		  bool response = false;
-		  tmp_extruder = choose_extruder_menu();
+		  if (!automatic) {
+			  tmp_extruder = choose_extruder_menu();
+		  }
+		  else {
+			  tmp_extruder = (tmp_extruder+1)%5;
+		  }
 		  lcd_update_enable(false);
 		  lcd_clear();
 		  lcd_set_cursor(0, 1); lcd_puts_P(_T(MSG_LOADING_FILAMENT));
 		  lcd_print(" ");
-		  lcd_print(snmm_extruder + 1);
+		  lcd_print(tmp_extruder + 1);
 		  snmm_filaments_used |= (1 << tmp_extruder); //for stop print
 		  printf_P(PSTR("T code: %d \n"), tmp_extruder);
 		  fprintf_P(uart2io, PSTR("T%d\n"), tmp_extruder);
-		  response = mmu_get_reponse(false);
-		  if (!response) mmu_not_responding();
 
+		  manage_response();
     	  snmm_extruder = tmp_extruder; //filament change is finished
 
 		  mmu_load_to_nozzle();

+ 45 - 5
Firmware/ultralcd.cpp

@@ -5308,8 +5308,8 @@ void extr_adj(int extruder) //loading filament for SNMM
 	lcd_print(snmm_extruder + 1);
 
 	// get response
-	bool response = mmu_get_reponse(false);
-	if (!response) mmu_not_responding();
+	manage_response();
+
 	lcd_update_enable(true);
 	
 	
@@ -5381,8 +5381,7 @@ void extr_unload() { //unloads filament
 		fprintf_P(uart2io, PSTR("U0\n"));
 
 		// get response
-		bool response = mmu_get_reponse(false);
-		if (!response) mmu_not_responding();
+		manage_response();
 
 		lcd_update_enable(true);
 		#else //SNMM_V2
@@ -5552,7 +5551,6 @@ void extr_unload_all() {
 }
 
 //unloading just used filament (for snmm)
-
 void extr_unload_used() {
 	if (degHotend0() > EXTRUDE_MINTEMP) {
 		for (int i = 0; i < 4; i++) {
@@ -5598,6 +5596,48 @@ static void extr_unload_4() {
 	extr_unload();
 }
 
+//unload filament for single material printer (used in M702 gcode)
+void unload_filament() {
+	custom_message = true;
+	custom_message_type = 2;
+	lcd_setstatuspgm(_T(MSG_UNLOADING_FILAMENT));
+
+	//		extr_unload2();
+
+	current_position[E_AXIS] -= 45;
+	plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 5200 / 60, active_extruder);
+	st_synchronize();
+	current_position[E_AXIS] -= 15;
+	plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 1000 / 60, active_extruder);
+	st_synchronize();
+	current_position[E_AXIS] -= 20;
+	plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 1000 / 60, active_extruder);
+	st_synchronize();
+
+	lcd_display_message_fullscreen_P(_T(MSG_PULL_OUT_FILAMENT));
+
+	//disable extruder steppers so filament can be removed
+	disable_e0();
+	disable_e1();
+	disable_e2();
+	delay(100);
+
+	Sound_MakeSound(e_SOUND_CLASS_Prompt, e_SOUND_TYPE_StandardPrompt);
+	uint8_t counterBeep = 0;
+	while (!lcd_clicked() && (counterBeep < 50)) {
+		delay_keep_alive(100);
+		counterBeep++;
+	}
+	st_synchronize();
+	while (lcd_clicked()) delay_keep_alive(100);
+
+	lcd_update_enable(true);
+
+	lcd_setstatuspgm(_T(WELCOME_MSG));
+	custom_message = false;
+	custom_message_type = 0;
+
+}
 
 static void fil_load_menu()
 {

+ 2 - 0
Firmware/ultralcd.h

@@ -120,6 +120,8 @@ void extr_unload_all();
 void extr_unload_used();
 void extr_unload();
 
+void unload_filament();
+
 void stack_error();
 void lcd_printer_connected();
 void lcd_ping();

+ 1 - 1
Firmware/variants/1_75mm_MK3-MMU-EINSy10a-E3Dv6full.h

@@ -134,7 +134,7 @@
 
 // Filament sensor
 #define PAT9125
-#define FILAMENT_SENSOR
+//#define FILAMENT_SENSOR
 
 // Backlash - 
 //#define BACKLASH_X