| 
					
				 | 
			
			
				@@ -112,6 +112,7 @@ MMU2::MMU2() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     , loadFilamentStarted(false) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     , unloadFilamentStarted(false) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     , loadingToNozzle(false) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    , inAutoRetry(false) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     ResetRetryAttempts(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -230,11 +231,14 @@ bool MMU2::RetryIfPossible(uint16_t ec){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         SetButtonResponse(ButtonOperations::Retry); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         // check, that Retry is actually allowed on that operation 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if( ButtonAvailable(ec) != NoButton ){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            inAutoRetry = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             SERIAL_ECHOLNPGM("RetryButtonPressed"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            --retryAttempts; // "used" one retry attempt 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // We don't decrement until the button is acknowledged by the MMU. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            //--retryAttempts; // "used" one retry attempt 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    inAutoRetry = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -243,6 +247,14 @@ void MMU2::ResetRetryAttempts(){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     retryAttempts = 3; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+void MMU2::DecrementRetryAttempts(){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (inAutoRetry && retryAttempts) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        SERIAL_ECHOLNPGM("DecrementRetryAttempts"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        retryAttempts--; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 bool MMU2::tool_change(uint8_t index) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if( ! WaitForMMUReady()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         return false; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -607,7 +619,8 @@ void MMU2::CheckUserInput(){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     case Left: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     case Middle: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     case Right: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        SERIAL_ECHOLNPGM("CheckUserInput-btnLMR"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        SERIAL_ECHOPGM("CheckUserInput-btnLMR "); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        SERIAL_ECHOLN(btn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         ResumeHotendTemp(); // Recover the hotend temp before we attempt to do anything else... 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         Button(btn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         break; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -655,7 +668,7 @@ void MMU2::manage_response(const bool move_axes, const bool turn_off_nozzle) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if (!nozzleTimeout.running()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 nozzleTimeout.start(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                LogEchoEvent(" Cooling Timeout started"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                LogEchoEvent("Cooling Timeout started"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             }  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             else if (nozzleTimeout.expired(DEFAULT_SAFETYTIMER_TIME_MINS*60*1000ul)) // mins->msec. TODO: do we use the global or have our own independent timeout 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -676,13 +689,20 @@ void MMU2::manage_response(const bool move_axes, const bool turn_off_nozzle) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             // command/operation completed, let Marlin continue its work 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             // the E may have some more moves to finish - wait for them 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             ResumeUnpark(); // We can now travel back to the tower or wherever we were when we saved. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ResetRetryAttempts(); // Reset the retry counter. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             st_synchronize();  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         case VersionMismatch: // this basically means the MMU will be disabled until reconnected 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             CheckUserInput(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        case CommunicationTimeout: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         case CommandError: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Don't proceed to the park/save if we are doing an autoretry. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (inAutoRetry) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            /* FALLTHRU */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case CommunicationTimeout: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         case ProtocolError: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             SaveAndPark(move_axes, turn_off_nozzle); // and wait for the user to resolve the problem 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             CheckUserInput(); 
			 |