@ -195,7 +195,7 @@
 
			
		
	
		
			
				
					 *  M502  -  Revert  to  the  default  " factory settings " .  * *  Does  not  write  them  to  EEPROM !  * * 
 
			
		
	
		
			
				
					 *  M503  -  Print  the  current  settings  ( in  memory ) :  " M503 S<verbose> " .  S0  specifies  compact  output . 
 
			
		
	
		
			
				
					 *  M540  -  Enable / disable  SD  card  abort  on  endstop  hit :  " M540 S<state> " .  ( Requires  ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED ) 
 
			
		
	
		
			
				
					 *  M600  -  Pause  for  filament  change :  " M600 X<pos> Y<pos> Z<raise> E<first_retract> L<later_retract> " .  ( Requires  FILAMENT_CHANG E_FEATURE) 
 
			
		
	
		
			
				
					 *  M600  -  Pause  for  filament  change :  " M600 X<pos> Y<pos> Z<raise> E<first_retract> L<later_retract> " .  ( Requires  ADVANCED_PAUS E_FEATURE) 
 
			
		
	
		
			
				
					 *  M665  -  Set  delta  configurations :  " M665 L<diagonal rod> R<delta radius> S<segments/s> A<rod A trim mm> B<rod B trim mm> C<rod C trim mm> I<tower A trim angle> J<tower B trim angle> K<tower C trim angle> "  ( Requires  DELTA ) 
 
			
		
	
		
			
				
					 *  M666  -  Set  delta  endstop  adjustment .  ( Requires  DELTA ) 
 
			
		
	
		
			
				
					 *  M605  -  Set  dual  x - carriage  movement  mode :  " M605 S<mode> [X<x_offset>] [R<temp_offset>] " .  ( Requires  DUAL_X_CARRIAGE ) 
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -627,8 +627,8 @@ float cartes[XYZ] = { 0 };
 
			
		
	
		
			
				
					  static  bool  filament_ran_out  =  false ; 
 
			
		
	
		
			
				
					# endif  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					# if ENABLED( FILAMENT_CHANG E_FEATURE) 
			
		
	
		
			
				
					  FilamentChangeMenuResponse filament_chang  e_menu_response; 
 
			
		
	
		
			
				
					# if ENABLED( ADVANCED_PAUS E_FEATURE) 
			
		
	
		
			
				
					  AdvancedPauseMenuResponse advanced_paus  e_menu_response; 
 
			
		
	
		
			
				
					# endif  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					# if ENABLED(MIXING_EXTRUDER)  
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -5738,14 +5738,244 @@ inline void gcode_M17() {
 
			
		
	
		
			
				
					  # define RUNPLAN(RATE_MM_S) line_to_destination(RATE_MM_S) 
 
			
		
	
		
			
				
					# endif  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					# if ENABLED(PARK_HEAD_ON_PAUSE)  
			
		
	
		
			
				
					# if ENABLED(ADVANCED_PAUSE_FEATURE)  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  static  float  resume_position [ XYZE ] ; 
 
			
		
	
		
			
				
					  static  bool  move_away_flag  =  false ; 
 
			
		
	
		
			
				
					  # if ENABLED(SDSUPPORT) 
 
			
		
	
		
			
				
					    static  bool  sd_print_paused  =  false ; 
 
			
		
	
		
			
				
					  # endif 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  static  void  filament_change_beep ( const  int  max_beep_count ,  const  bool  init = false )  { 
 
			
		
	
		
			
				
					    static  millis_t  next_buzz  =  0 ; 
 
			
		
	
		
			
				
					    static  uint16_t  runout_beep  =  0 ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    if  ( init )  next_buzz  =  runout_beep  =  0 ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    const  millis_t  ms  =  millis ( ) ; 
 
			
		
	
		
			
				
					    if  ( ELAPSED ( ms ,  next_buzz ) )  { 
 
			
		
	
		
			
				
					      if  ( max_beep_count  <  0  | |  runout_beep  <  max_beep_count  +  5 )  {  // Only beep as long as we're supposed to
 
 
			
		
	
		
			
				
					        next_buzz  =  ms  +  ( ( max_beep_count  <  0  | |  runout_beep  <  max_beep_count )  ?  2500  :  400 ) ; 
 
			
		
	
		
			
				
					        BUZZ ( 300 ,  2000 ) ; 
 
			
		
	
		
			
				
					        runout_beep + + ; 
 
			
		
	
		
			
				
					      } 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					  } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  static  bool  pause_print ( const  float &  retract ,  const  float &  z_lift ,  const  float &  x_pos ,  const  float &  y_pos , 
 
			
		
	
		
			
				
					                          const  float &  unload_length  =  0  ,  int  max_beep_count  =  0 ,  bool  show_lcd  =  false )  { 
 
			
		
	
		
			
				
					    if  ( move_away_flag )  return  false ;  // already paused
 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    if  ( ! DEBUGGING ( DRYRUN )  & &  thermalManager . tooColdToExtrude ( active_extruder )  & &  unload_length  >  0 )  { 
 
			
		
	
		
			
				
					      SERIAL_ERROR_START ; 
 
			
		
	
		
			
				
					      SERIAL_ERRORLNPGM ( MSG_TOO_COLD_FOR_M600 ) ; 
 
			
		
	
		
			
				
					      return  false ; 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    const  bool  job_running  =  print_job_timer . isRunning ( ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // Indicate that the printer is paused
 
 
			
		
	
		
			
				
					    move_away_flag  =  true ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // Pause the print job and timer
 
 
			
		
	
		
			
				
					    # if ENABLED(SDSUPPORT) 
 
			
		
	
		
			
				
					      if  ( card . sdprinting )  { 
 
			
		
	
		
			
				
					        card . pauseSDPrint ( ) ; 
 
			
		
	
		
			
				
					        sd_print_paused  =  true ; 
 
			
		
	
		
			
				
					      } 
 
			
		
	
		
			
				
					    # endif 
 
			
		
	
		
			
				
					    print_job_timer . pause ( ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // Show initial message and wait for synchronize steppers
 
 
			
		
	
		
			
				
					    if  ( show_lcd )  { 
 
			
		
	
		
			
				
					      # if ENABLED(ULTIPANEL) 
 
			
		
	
		
			
				
					        lcd_advanced_pause_show_message ( ADVANCED_PAUSE_MESSAGE_INIT ) ; 
 
			
		
	
		
			
				
					      # endif 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					    stepper . synchronize ( ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // Save current position
 
 
			
		
	
		
			
				
					    COPY ( resume_position ,  current_position ) ; 
 
			
		
	
		
			
				
					    set_destination_to_current ( ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // Initial retract before move to filament change position
 
 
			
		
	
		
			
				
					    destination [ E_AXIS ]  + =  retract ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    RUNPLAN ( PAUSE_PARK_RETRACT_FEEDRATE ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // Lift Z axis
 
 
			
		
	
		
			
				
					    if  ( z_lift  >  0 )  { 
 
			
		
	
		
			
				
					      destination [ Z_AXIS ]  + =  z_lift ; 
 
			
		
	
		
			
				
					      NOMORE ( destination [ Z_AXIS ] ,  Z_MAX_POS ) ; 
 
			
		
	
		
			
				
					      RUNPLAN ( PAUSE_PARK_Z_FEEDRATE ) ; 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // Move XY axes to filament exchange position
 
 
			
		
	
		
			
				
					    destination [ X_AXIS ]  =  x_pos ; 
 
			
		
	
		
			
				
					    destination [ Y_AXIS ]  =  y_pos ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    clamp_to_software_endstops ( destination ) ; 
 
			
		
	
		
			
				
					    RUNPLAN ( PAUSE_PARK_XY_FEEDRATE ) ; 
 
			
		
	
		
			
				
					    stepper . synchronize ( ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    if  ( unload_length  ! =  0 )  { 
 
			
		
	
		
			
				
					      if  ( show_lcd )  { 
 
			
		
	
		
			
				
					        # if ENABLED(ULTIPANEL) 
 
			
		
	
		
			
				
					          lcd_advanced_pause_show_message ( ADVANCED_PAUSE_MESSAGE_UNLOAD ) ; 
 
			
		
	
		
			
				
					          idle ( ) ; 
 
			
		
	
		
			
				
					        # endif 
 
			
		
	
		
			
				
					      } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      // Unload filament
 
 
			
		
	
		
			
				
					      destination [ E_AXIS ]  + =  unload_length ; 
 
			
		
	
		
			
				
					      RUNPLAN ( FILAMENT_CHANGE_UNLOAD_FEEDRATE ) ; 
 
			
		
	
		
			
				
					      stepper . synchronize ( ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      if  ( show_lcd )  { 
 
			
		
	
		
			
				
					        # if ENABLED(ULTIPANEL) 
 
			
		
	
		
			
				
					          lcd_advanced_pause_show_message ( ADVANCED_PAUSE_MESSAGE_INSERT ) ; 
 
			
		
	
		
			
				
					        # endif 
 
			
		
	
		
			
				
					      } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      # if HAS_BUZZER 
 
			
		
	
		
			
				
					        filament_change_beep ( max_beep_count ,  true ) ; 
 
			
		
	
		
			
				
					      # endif 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      idle ( ) ; 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // Disable extruders steppers for manual filament changing
 
 
			
		
	
		
			
				
					    disable_e_steppers ( ) ; 
 
			
		
	
		
			
				
					    safe_delay ( 100 ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // Start the heater idle timers
 
 
			
		
	
		
			
				
					    const  millis_t  nozzle_timeout  =  ( millis_t ) ( PAUSE_PARK_NOZZLE_TIMEOUT )  *  1000UL ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    HOTEND_LOOP ( ) 
 
			
		
	
		
			
				
					      thermalManager . start_heater_idle_timer ( e ,  nozzle_timeout ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    return  true ; 
 
			
		
	
		
			
				
					  } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  static  void  wait_for_filament_reload ( int  max_beep_count  =  0 )  { 
 
			
		
	
		
			
				
					    bool  nozzle_timed_out  =  false ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // Wait for filament insert by user and press button
 
 
			
		
	
		
			
				
					    KEEPALIVE_STATE ( PAUSED_FOR_USER ) ; 
 
			
		
	
		
			
				
					    wait_for_user  =  true ;     // LCD click or M108 will clear this
 
 
			
		
	
		
			
				
					    while  ( wait_for_user )  { 
 
			
		
	
		
			
				
					      # if HAS_BUZZER 
 
			
		
	
		
			
				
					        filament_change_beep ( max_beep_count ) ; 
 
			
		
	
		
			
				
					      # endif 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  float  resume_position [ XYZE ] ; 
 
			
		
	
		
			
				
					  bool  move_away_flag  =  false ; 
 
			
		
	
		
			
				
					      if  ( ! nozzle_timed_out ) 
 
			
		
	
		
			
				
					        HOTEND_LOOP ( ) 
 
			
		
	
		
			
				
					          nozzle_timed_out  | =  thermalManager . is_heater_idle ( e ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      # if ENABLED(ULTIPANEL) 
 
			
		
	
		
			
				
					        if  ( nozzle_timed_out ) 
 
			
		
	
		
			
				
					          lcd_advanced_pause_show_message ( ADVANCED_PAUSE_MESSAGE_CLICK_TO_HEAT_NOZZLE ) ; 
 
			
		
	
		
			
				
					      # endif 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      idle ( true ) ; 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					    KEEPALIVE_STATE ( IN_HANDLER ) ; 
 
			
		
	
		
			
				
					  } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  static  void  resume_print ( const  float &  load_length  =  0 ,  const  float &  initial_extrude_length  =  0 ,  int  max_beep_count  =  0 )  { 
 
			
		
	
		
			
				
					    bool  nozzle_timed_out  =  false ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  inline  void  move_back_on_resume ( )  { 
 
			
		
	
		
			
				
					    if  ( ! move_away_flag )  return ; 
 
			
		
	
		
			
				
					    move_away_flag  =  false ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // Re-enable the heaters if they timed out
 
 
			
		
	
		
			
				
					    HOTEND_LOOP ( )  { 
 
			
		
	
		
			
				
					      nozzle_timed_out  | =  thermalManager . is_heater_idle ( e ) ; 
 
			
		
	
		
			
				
					      thermalManager . reset_heater_idle_timer ( e ) ; 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # if ENABLED(ULTIPANEL) 
 
			
		
	
		
			
				
					      // Show "wait for heating"
 
 
			
		
	
		
			
				
					      lcd_advanced_pause_show_message ( ADVANCED_PAUSE_MESSAGE_WAIT_FOR_NOZZLES_TO_HEAT ) ; 
 
			
		
	
		
			
				
					    # endif 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    wait_for_heatup  =  true ; 
 
			
		
	
		
			
				
					    while  ( wait_for_heatup )  { 
 
			
		
	
		
			
				
					      idle ( ) ; 
 
			
		
	
		
			
				
					      wait_for_heatup  =  false ; 
 
			
		
	
		
			
				
					      HOTEND_LOOP ( )  { 
 
			
		
	
		
			
				
					        if  ( abs ( thermalManager . degHotend ( e )  -  thermalManager . degTargetHotend ( e ) )  >  3 )  { 
 
			
		
	
		
			
				
					          wait_for_heatup  =  true ; 
 
			
		
	
		
			
				
					          break ; 
 
			
		
	
		
			
				
					        } 
 
			
		
	
		
			
				
					      } 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # if HAS_BUZZER 
 
			
		
	
		
			
				
					      filament_change_beep ( max_beep_count ,  true ) ; 
 
			
		
	
		
			
				
					    # endif 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    if  ( load_length  ! =  0 )  { 
 
			
		
	
		
			
				
					      # if ENABLED(ULTIPANEL) 
 
			
		
	
		
			
				
					        // Show "insert filament"
 
 
			
		
	
		
			
				
					        if  ( nozzle_timed_out ) 
 
			
		
	
		
			
				
					          lcd_advanced_pause_show_message ( ADVANCED_PAUSE_MESSAGE_INSERT ) ; 
 
			
		
	
		
			
				
					      # endif 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      KEEPALIVE_STATE ( PAUSED_FOR_USER ) ; 
 
			
		
	
		
			
				
					      wait_for_user  =  true ;     // LCD click or M108 will clear this
 
 
			
		
	
		
			
				
					      while  ( wait_for_user  & &  nozzle_timed_out )  { 
 
			
		
	
		
			
				
					        # if HAS_BUZZER 
 
			
		
	
		
			
				
					          filament_change_beep ( max_beep_count ) ; 
 
			
		
	
		
			
				
					        # endif 
 
			
		
	
		
			
				
					        idle ( true ) ; 
 
			
		
	
		
			
				
					      } 
 
			
		
	
		
			
				
					      KEEPALIVE_STATE ( IN_HANDLER ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      # if ENABLED(ULTIPANEL) 
 
			
		
	
		
			
				
					        // Show "load" message
 
 
			
		
	
		
			
				
					        lcd_advanced_pause_show_message ( ADVANCED_PAUSE_MESSAGE_LOAD ) ; 
 
			
		
	
		
			
				
					      # endif 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      // Load filament
 
 
			
		
	
		
			
				
					      destination [ E_AXIS ]  + =  load_length ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      RUNPLAN ( FILAMENT_CHANGE_LOAD_FEEDRATE ) ; 
 
			
		
	
		
			
				
					      stepper . synchronize ( ) ; 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # if ENABLED(ULTIPANEL) && defined(ADVANCED_PAUSE_EXTRUDE_LENGTH) && ADVANCED_PAUSE_EXTRUDE_LENGTH > 0 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      float  extrude_length  =  initial_extrude_length ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      do  { 
 
			
		
	
		
			
				
					        if  ( extrude_length  >  0 )  { 
 
			
		
	
		
			
				
					          // "Wait for filament extrude"
 
 
			
		
	
		
			
				
					          lcd_advanced_pause_show_message ( ADVANCED_PAUSE_MESSAGE_EXTRUDE ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					          // Extrude filament to get into hotend
 
 
			
		
	
		
			
				
					          destination [ E_AXIS ]  + =  extrude_length ; 
 
			
		
	
		
			
				
					          RUNPLAN ( ADVANCED_PAUSE_EXTRUDE_FEEDRATE ) ; 
 
			
		
	
		
			
				
					          stepper . synchronize ( ) ; 
 
			
		
	
		
			
				
					        } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        // Show "Extrude More" / "Resume" menu and wait for reply
 
 
			
		
	
		
			
				
					        KEEPALIVE_STATE ( PAUSED_FOR_USER ) ; 
 
			
		
	
		
			
				
					        wait_for_user  =  false ; 
 
			
		
	
		
			
				
					        lcd_advanced_pause_show_message ( ADVANCED_PAUSE_MESSAGE_OPTION ) ; 
 
			
		
	
		
			
				
					        while  ( advanced_pause_menu_response  = =  ADVANCED_PAUSE_RESPONSE_WAIT_FOR )  idle ( true ) ; 
 
			
		
	
		
			
				
					        KEEPALIVE_STATE ( IN_HANDLER ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        extrude_length  =  ADVANCED_PAUSE_EXTRUDE_LENGTH ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        // Keep looping if "Extrude More" was selected
 
 
			
		
	
		
			
				
					      }  while  ( advanced_pause_menu_response  = =  ADVANCED_PAUSE_RESPONSE_EXTRUDE_MORE ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # endif 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # if ENABLED(ULTIPANEL) 
 
			
		
	
		
			
				
					      // "Wait for print to resume"
 
 
			
		
	
		
			
				
					      lcd_advanced_pause_show_message ( ADVANCED_PAUSE_MESSAGE_RESUME ) ; 
 
			
		
	
		
			
				
					    # endif 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // Set extruder to saved position
 
 
			
		
	
		
			
				
					    destination [ E_AXIS ]  =  current_position [ E_AXIS ]  =  resume_position [ E_AXIS ] ; 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -5753,24 +5983,38 @@ inline void gcode_M17() {
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # if IS_KINEMATIC 
 
			
		
	
		
			
				
					      // Move XYZ to starting position
 
 
			
		
	
		
			
				
					      planner . buffer_line_kinematic ( lastpos ,  FILAMENT_CHANGE _XY_FEEDRATE,  active_extruder ) ; 
 
			
		
	
		
			
				
					      planner . buffer_line_kinematic ( lastpos ,  PAUSE_PARK _XY_FEEDRATE,  active_extruder ) ; 
 
			
		
	
		
			
				
					    # else 
 
			
		
	
		
			
				
					      // Move XY to starting position, then Z
 
 
			
		
	
		
			
				
					      destination [ X_AXIS ]  =  resume_position [ X_AXIS ] ; 
 
			
		
	
		
			
				
					      destination [ Y_AXIS ]  =  resume_position [ Y_AXIS ] ; 
 
			
		
	
		
			
				
					      RUNPLAN ( FILAMENT_CHANGE _XY_FEEDRATE) ; 
 
			
		
	
		
			
				
					      RUNPLAN ( PAUSE_PARK _XY_FEEDRATE) ; 
 
			
		
	
		
			
				
					      destination [ Z_AXIS ]  =  resume_position [ Z_AXIS ] ; 
 
			
		
	
		
			
				
					      RUNPLAN ( FILAMENT_CHANGE _Z_FEEDRATE) ; 
 
			
		
	
		
			
				
					      RUNPLAN ( PAUSE_PARK _Z_FEEDRATE) ; 
 
			
		
	
		
			
				
					    # endif 
 
			
		
	
		
			
				
					    stepper . synchronize ( ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # if ENABLED(FILAMENT_RUNOUT_SENSOR) 
 
			
		
	
		
			
				
					      filament_ran_out  =  false ; 
 
			
		
	
		
			
				
					    # endif 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    set_current_to_destination ( ) ; 
 
			
		
	
		
			
				
					  } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					# endif  // PARK_HEAD_ON_PAUSE
  
			
		
	
		
			
				
					    # if ENABLED(ULTIPANEL) 
 
			
		
	
		
			
				
					      // Show status screen
 
 
			
		
	
		
			
				
					      lcd_advanced_pause_show_message ( ADVANCED_PAUSE_MESSAGE_STATUS ) ; 
 
			
		
	
		
			
				
					    # endif 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # if ENABLED(SDSUPPORT) 
 
			
		
	
		
			
				
					      if  ( sd_print_paused )  { 
 
			
		
	
		
			
				
					        card . startFileprint ( ) ; 
 
			
		
	
		
			
				
					        sd_print_paused  =  false ; 
 
			
		
	
		
			
				
					      } 
 
			
		
	
		
			
				
					    # endif 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    move_away_flag  =  false ; 
 
			
		
	
		
			
				
					  } 
 
			
		
	
		
			
				
					# endif  // ADVANCED_PAUSE_FEATURE
  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					# if ENABLED(SDSUPPORT)  
			
		
	
		
			
				
					
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -5803,7 +6047,7 @@ inline void gcode_M17() {
 
			
		
	
		
			
				
					   */ 
 
			
		
	
		
			
				
					  inline  void  gcode_M24 ( )  { 
 
			
		
	
		
			
				
					    # if ENABLED(PARK_HEAD_ON_PAUSE) 
 
			
		
	
		
			
				
					      move_back_on_ resume( ) ; 
 
			
		
	
		
			
				
					      _print ( ) ; 
 
			
		
	
		
			
				
					    # endif 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    card . startFileprint ( ) ; 
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -7462,89 +7706,55 @@ inline void gcode_M121() { endstops.enable_globally(false); }
 
			
		
	
		
			
				
					   *     Z  =  override  Z  raise 
 
			
		
	
		
			
				
					   */ 
 
			
		
	
		
			
				
					  inline  void  gcode_M125 ( )  { 
 
			
		
	
		
			
				
					    if  ( move_away_flag )  return ;  // already paused
 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    const  bool  job_running  =  print_job_timer . isRunning ( ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // there are blocks after this one, or sd printing
 
 
			
		
	
		
			
				
					    move_away_flag  =  job_running  | |  planner . blocks_queued ( ) 
 
			
		
	
		
			
				
					      # if ENABLED(SDSUPPORT) 
 
			
		
	
		
			
				
					        | |  card . sdprinting 
 
			
		
	
		
			
				
					      # endif 
 
			
		
	
		
			
				
					    ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    if  ( ! move_away_flag )  return ;  // nothing to pause
 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // M125 can be used to pause a print too
 
 
			
		
	
		
			
				
					    # if ENABLED(SDSUPPORT) 
 
			
		
	
		
			
				
					      card . pauseSDPrint ( ) ; 
 
			
		
	
		
			
				
					    # endif 
 
			
		
	
		
			
				
					    print_job_timer . pause ( ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // Save current position
 
 
			
		
	
		
			
				
					    COPY ( resume_position ,  current_position ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    set_destination_to_current ( ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // Initial retract before move to filament change position
 
 
			
		
	
		
			
				
					    destination [ E_AXIS ]  + =  parser . seen ( ' L ' )  ?  parser . value_axis_units ( E_AXIS )  :  0 
 
			
		
	
		
			
				
					      # if defined( FILAMENT_CHANGE_RETRACT_LENGTH) && FILAMENT_CHANGE _RETRACT_LENGTH > 0
 
			
		
	
		
			
				
					        -  ( FILAMENT_CHANGE _RETRACT_LENGTH) 
 
			
		
	
		
			
				
					    const  float  retract  =  parser . seen ( ' L ' )  ?  parser . value_axis_units ( E_AXIS )  :  0 
 
			
		
	
		
			
				
					      # if defined(PAUSE_PARK_RETRACT_LENGTH) && PAUSE_PARK_RETRACT_LENGTH > 0 
 
			
		
	
		
			
				
					        -  ( PAUSE_PARK_RETRACT_LENGTH ) 
 
			
		
	
		
			
				
					      # endif 
 
			
		
	
		
			
				
					    ; 
 
			
		
	
		
			
				
					    RUNPLAN ( FILAMENT_CHANGE_RETRACT_FEEDRATE ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // Lift Z axis
 
 
			
		
	
		
			
				
					    const  float  z_lift  =  parser . seen ( ' Z ' )  ?  parser . value_linear_units ( )  : 
 
			
		
	
		
			
				
					      # if defined( FILAMENT_CHANGE_Z_ADD) && FILAMENT_CHANGE _Z_ADD > 0
 
			
		
	
		
			
				
					        FILAMENT_CHANGE _Z_ADD
 
			
		
	
		
			
				
					      # if defined(PAUSE_PARK_Z_ADD) && PAUSE_PARK_Z_ADD > 0 
 
			
		
	
		
			
				
					        PAUSE_PARK_Z_ADD 
 
			
		
	
		
			
				
					      # else 
 
			
		
	
		
			
				
					        0 
 
			
		
	
		
			
				
					      # endif 
 
			
		
	
		
			
				
					    ; 
 
			
		
	
		
			
				
					    if  ( z_lift  >  0 )  { 
 
			
		
	
		
			
				
					      destination [ Z_AXIS ]  + =  z_lift ; 
 
			
		
	
		
			
				
					      NOMORE ( destination [ Z_AXIS ] ,  Z_MAX_POS ) ; 
 
			
		
	
		
			
				
					      RUNPLAN ( FILAMENT_CHANGE_Z_FEEDRATE ) ; 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // Move XY axes to filament change position or given position
 
 
			
		
	
		
			
				
					    destination [ X_AXIS ] =  parser . seen ( ' X ' )  ?  parser . value_linear_units ( )  :  0 
 
			
		
	
		
			
				
					      # ifdef  FILAMENT_CHANGE _X_POS
 
			
		
	
		
			
				
					        +  FILAMENT_CHANGE _X_POS
 
			
		
	
		
			
				
					    const  float  x_pos  =  parser . seen ( ' X ' )  ?  parser . value_linear_units ( )  :  0 
 
			
		
	
		
			
				
					      # ifdef PAUSE_PARK_X_POS 
 
			
		
	
		
			
				
					        +  PAUSE_PARK_X_POS 
 
			
		
	
		
			
				
					      # endif 
 
			
		
	
		
			
				
					    ; 
 
			
		
	
		
			
				
					    destination [ Y_AXIS ] =  parser . seen ( ' Y ' )  ?  parser . value_linear_units ( )  :  0 
 
			
		
	
		
			
				
					      # ifdef  FILAMENT_CHANGE _Y_POS
 
			
		
	
		
			
				
					        +  FILAMENT_CHANGE _Y_POS
 
			
		
	
		
			
				
					    const  float  y_pos =  parser . seen ( ' Y ' )  ?  parser . value_linear_units ( )  :  0 
 
			
		
	
		
			
				
					      # ifdef  PAUSE_PARK _Y_POS
 
			
		
	
		
			
				
					        +  PAUSE_PARK _Y_POS
 
			
		
	
		
			
				
					      # endif 
 
			
		
	
		
			
				
					    ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # if HOTENDS > 1 && DISABLED(DUAL_X_CARRIAGE) 
 
			
		
	
		
			
				
					      if  ( active_extruder  >  0 )  { 
 
			
		
	
		
			
				
					        if  ( ! parser . seen ( ' X ' ) )  destination[ X_AXIS ]   + =  hotend_offset [ X_AXIS ] [ active_extruder ] ; 
 
			
		
	
		
			
				
					        if  ( ! parser . seen ( ' Y ' ) )  destination[ Y_AXIS ]   + =  hotend_offset [ Y_AXIS ] [ active_extruder ] ; 
 
			
		
	
		
			
				
					        if  ( ! parser . seen ( ' X ' ) )  x_pos  + =  hotend_offset [ X_AXIS ] [ active_extruder ] ; 
 
			
		
	
		
			
				
					        if  ( ! parser . seen ( ' Y ' ) )  y_pos  + =  hotend_offset [ Y_AXIS ] [ active_extruder ] ; 
 
			
		
	
		
			
				
					      } 
 
			
		
	
		
			
				
					    # endif 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    clamp_to_software_endstops ( destination ) ; 
 
			
		
	
		
			
				
					    RUNPLAN ( FILAMENT_CHANGE_XY_FEEDRATE ) ; 
 
			
		
	
		
			
				
					    set_current_to_destination ( ) ; 
 
			
		
	
		
			
				
					    stepper . synchronize ( ) ; 
 
			
		
	
		
			
				
					    disable_e_steppers ( ) ; 
 
			
		
	
		
			
				
					    const  bool  job_running  =  print_job_timer . isRunning ( ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # if DISABLED(SDSUPPORT) 
 
			
		
	
		
			
				
					      // Wait for lcd click or M108
 
 
			
		
	
		
			
				
					      KEEPALIVE_STATE ( PAUSED_FOR_USER ) ; 
 
			
		
	
		
			
				
					      wait_for_user  =  true ; 
 
			
		
	
		
			
				
					      while  ( wait_for_user )  idle ( ) ; 
 
			
		
	
		
			
				
					      KEEPALIVE_STATE ( IN_HANDLER ) ; 
 
			
		
	
		
			
				
					    if  ( pause_print ( retract ,  z_lift ,  x_pos ,  y_pos ) )  { 
 
			
		
	
		
			
				
					      # if DISABLED(SDSUPPORT) 
 
			
		
	
		
			
				
					        // Wait for lcd click or M108
 
 
			
		
	
		
			
				
					        wait_for_filament_reload ( ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      // Return to print position and continue
 
 
			
		
	
		
			
				
					      move_back_on_resume ( ) ; 
 
			
		
	
		
			
				
					      if  ( job_running )  print_job_timer . start ( ) ; 
 
			
		
	
		
			
				
					      move_away_flag  =  false ; 
 
			
		
	
		
			
				
					    # endif 
 
			
		
	
		
			
				
					        // Return to print position and continue
 
 
			
		
	
		
			
				
					        resume_print ( ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        if  ( job_running )  print_job_timer . start ( ) ; 
 
			
		
	
		
			
				
					      # endif 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					  } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					# endif  // PARK_HEAD_ON_PAUSE
  
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -8812,25 +9022,7 @@ inline void gcode_M503() {
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					# endif  // HAS_BED_PROBE
  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					# if ENABLED(FILAMENT_CHANGE_FEATURE)  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  void  filament_change_beep ( const  bool  init = false )  { 
 
			
		
	
		
			
				
					    static  millis_t  next_buzz  =  0 ; 
 
			
		
	
		
			
				
					    static  uint16_t  runout_beep  =  0 ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    if  ( init )  next_buzz  =  runout_beep  =  0 ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    const  millis_t  ms  =  millis ( ) ; 
 
			
		
	
		
			
				
					    if  ( ELAPSED ( ms ,  next_buzz ) )  { 
 
			
		
	
		
			
				
					      if  ( runout_beep  < =  FILAMENT_CHANGE_NUMBER_OF_ALERT_BEEPS  +  5 )  {  // Only beep as long as we're supposed to
 
 
			
		
	
		
			
				
					        next_buzz  =  ms  +  ( runout_beep  < =  FILAMENT_CHANGE_NUMBER_OF_ALERT_BEEPS  ?  2500  :  400 ) ; 
 
			
		
	
		
			
				
					        BUZZ ( 300 ,  2000 ) ; 
 
			
		
	
		
			
				
					        runout_beep + + ; 
 
			
		
	
		
			
				
					      } 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					  } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  static  bool  busy_doing_M600  =  false ; 
 
			
		
	
		
			
				
					# if ENABLED(ADVANCED_PAUSE_FEATURE)  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  /**
 
 
			
		
	
		
			
				
					   *  M600 :  Pause  for  filament  change 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -8839,231 +9031,77 @@ inline void gcode_M503() {
 
			
		
	
		
			
				
					   *   Z [ distance ]  -  Move  the  Z  axis  by  this  distance 
 
			
		
	
		
			
				
					   *   X [ position ]  -  Move  to  this  X  position ,  with  Y 
 
			
		
	
		
			
				
					   *   Y [ position ]  -  Move  to  this  Y  position ,  with  X 
 
			
		
	
		
			
				
					   *   L [ distance ]  -  Retract  distance  for  removal  ( manual  reload ) 
 
			
		
	
		
			
				
					   *   U [ distance ]  -  Retract  distance  for  removal  ( negative  value )  ( manual  reload ) 
 
			
		
	
		
			
				
					   *   L [ distance ]  -  Extrude  distance  for  insertion  ( positive  value )  ( manual  reload ) 
 
			
		
	
		
			
				
					   *   B [ count ]     -  Number  of  times  to  beep ,  - 1  for  indefinite  ( if  equipped  with  a  buzzer ) 
 
			
		
	
		
			
				
					   * 
 
			
		
	
		
			
				
					   *   Default  values  are  used  for  omitted  arguments . 
 
			
		
	
		
			
				
					   * 
 
			
		
	
		
			
				
					   */ 
 
			
		
	
		
			
				
					  inline  void  gcode_M600 ( )  { 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    if  ( ! DEBUGGING ( DRYRUN )  & &  thermalManager . tooColdToExtrude ( active_extruder ) )  { 
 
			
		
	
		
			
				
					      SERIAL_ERROR_START ; 
 
			
		
	
		
			
				
					      SERIAL_ERRORLNPGM ( MSG_TOO_COLD_FOR_M600 ) ; 
 
			
		
	
		
			
				
					      return ; 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    busy_doing_M600  =  true ;   // Stepper Motors can't timeout when this is set
 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // Pause the print job timer
 
 
			
		
	
		
			
				
					    const  bool  job_running  =  print_job_timer . isRunning ( ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    print_job_timer . pause ( ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // Show initial message and wait for synchronize steppers
 
 
			
		
	
		
			
				
					    lcd_filament_change_show_message ( FILAMENT_CHANGE_MESSAGE_INIT ) ; 
 
			
		
	
		
			
				
					    stepper . synchronize ( ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // Save current position of all axes
 
 
			
		
	
		
			
				
					    float  lastpos [ XYZE ] ; 
 
			
		
	
		
			
				
					    COPY ( lastpos ,  current_position ) ; 
 
			
		
	
		
			
				
					    set_destination_to_current ( ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // Initial retract before move to filament change position
 
 
			
		
	
		
			
				
					    destination [ E_AXIS ]  + =  parser . seen ( ' E ' )  ?  parser . value_axis_units ( E_AXIS )  :  0 
 
			
		
	
		
			
				
					      # if defined( FILAMENT_CHANGE_RETRACT_LENGTH) && FILAMENT_CHANGE _RETRACT_LENGTH > 0
 
			
		
	
		
			
				
					        -  ( FILAMENT_CHANGE _RETRACT_LENGTH) 
 
			
		
	
		
			
				
					    const  float  retract  =  parser . seen ( ' E ' )  ?  parser . value_axis_units ( E_AXIS )  :  0 
 
			
		
	
		
			
				
					      # if defined(PAUSE_PARK_RETRACT_LENGTH) && PAUSE_PARK_RETRACT_LENGTH > 0 
 
			
		
	
		
			
				
					        -  ( PAUSE_PARK_RETRACT_LENGTH ) 
 
			
		
	
		
			
				
					      # endif 
 
			
		
	
		
			
				
					    ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    RUNPLAN ( FILAMENT_CHANGE_RETRACT_FEEDRATE ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // Lift Z axis
 
 
			
		
	
		
			
				
					    float  z_lift  =  parser . seen ( ' Z ' )  ?  parser . value_linear_units ( )  : 
 
			
		
	
		
			
				
					      # if defined( FILAMENT_CHANGE_Z_ADD) && FILAMENT_CHANGE _Z_ADD > 0
 
			
		
	
		
			
				
					        FILAMENT_CHANGE _Z_ADD
 
			
		
	
		
			
				
					    const  float  z_lift  =  parser . seen ( ' Z ' )  ?  parser . value_linear_units ( )  : 
 
			
		
	
		
			
				
					      # if defined(PAUSE_PARK_Z_ADD) && PAUSE_PARK_Z_ADD > 0 
 
			
		
	
		
			
				
					        PAUSE_PARK_Z_ADD 
 
			
		
	
		
			
				
					      # else 
 
			
		
	
		
			
				
					        0 
 
			
		
	
		
			
				
					      # endif 
 
			
		
	
		
			
				
					    ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    if  ( z_lift  >  0 )  { 
 
			
		
	
		
			
				
					      destination [ Z_AXIS ]  + =  z_lift ; 
 
			
		
	
		
			
				
					      NOMORE ( destination [ Z_AXIS ] ,  Z_MAX_POS ) ; 
 
			
		
	
		
			
				
					      RUNPLAN ( FILAMENT_CHANGE_Z_FEEDRATE ) ; 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // Move XY axes to filament exchange position
 
 
			
		
	
		
			
				
					    if  ( parser . seen ( ' X ' ) )  destination [ X_AXIS ]  =  parser . value_linear_units ( ) ; 
 
			
		
	
		
			
				
					    # ifdef FILAMENT_CHANGE_X_POS 
 
			
		
	
		
			
				
					      else  destination [ X_AXIS ]  =  FILAMENT_CHANGE_X_POS ; 
 
			
		
	
		
			
				
					    # endif 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    if  ( parser . seen ( ' Y ' ) )  destination [ Y_AXIS ]  =  parser . value_linear_units ( ) ; 
 
			
		
	
		
			
				
					    # ifdef FILAMENT_CHANGE_Y_POS 
 
			
		
	
		
			
				
					      else  destination [ Y_AXIS ]  =  FILAMENT_CHANGE_Y_POS ; 
 
			
		
	
		
			
				
					    # endif 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    RUNPLAN ( FILAMENT_CHANGE_XY_FEEDRATE ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    stepper . synchronize ( ) ; 
 
			
		
	
		
			
				
					    lcd_filament_change_show_message ( FILAMENT_CHANGE_MESSAGE_UNLOAD ) ; 
 
			
		
	
		
			
				
					    idle ( ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // Unload filament
 
 
			
		
	
		
			
				
					    destination [ E_AXIS ]  + =  parser . seen ( ' L ' )  ?  parser . value_axis_units ( E_AXIS )  :  0 
 
			
		
	
		
			
				
					      # if FILAMENT_CHANGE_UNLOAD_LENGTH > 0 
 
			
		
	
		
			
				
					        -  ( FILAMENT_CHANGE_UNLOAD_LENGTH ) 
 
			
		
	
		
			
				
					    const  float  x_pos  =  parser . seen ( ' X ' )  ?  parser . value_linear_units ( )  :  0 
 
			
		
	
		
			
				
					      # ifdef PAUSE_PARK_X_POS 
 
			
		
	
		
			
				
					        +  PAUSE_PARK_X_POS 
 
			
		
	
		
			
				
					      # endif 
 
			
		
	
		
			
				
					    ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    RUNPLAN ( FILAMENT_CHANGE_UNLOAD_FEEDRATE ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // Synchronize steppers and then disable extruders steppers for manual filament changing
 
 
			
		
	
		
			
				
					    stepper . synchronize ( ) ; 
 
			
		
	
		
			
				
					    disable_e_steppers ( ) ; 
 
			
		
	
		
			
				
					    safe_delay ( 100 ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    const  millis_t  nozzle_timeout  =  millis ( )  +  ( millis_t ) ( FILAMENT_CHANGE_NOZZLE_TIMEOUT )  *  1000UL ; 
 
			
		
	
		
			
				
					    bool  nozzle_timed_out  =  false ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // Wait for filament insert by user and press button
 
 
			
		
	
		
			
				
					    lcd_filament_change_show_message ( FILAMENT_CHANGE_MESSAGE_INSERT ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # if HAS_BUZZER 
 
			
		
	
		
			
				
					      filament_change_beep ( true ) ; 
 
			
		
	
		
			
				
					    # endif 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    idle ( ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    int16_t  temps [ HOTENDS ] ; 
 
			
		
	
		
			
				
					    HOTEND_LOOP ( )  temps [ e ]  =  thermalManager . target_temperature [ e ] ;  // Save nozzle temps
 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    KEEPALIVE_STATE ( PAUSED_FOR_USER ) ; 
 
			
		
	
		
			
				
					    wait_for_user  =  true ;     // LCD click or M108 will clear this
 
 
			
		
	
		
			
				
					    while  ( wait_for_user )  { 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      if  ( nozzle_timed_out ) 
 
			
		
	
		
			
				
					        lcd_filament_change_show_message ( FILAMENT_CHANGE_MESSAGE_CLICK_TO_HEAT_NOZZLE ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      # if HAS_BUZZER 
 
			
		
	
		
			
				
					        filament_change_beep ( ) ; 
 
			
		
	
		
			
				
					    const  float  y_pos  =  parser . seen ( ' Y ' )  ?  parser . value_linear_units ( )  :  0 
 
			
		
	
		
			
				
					      # ifdef PAUSE_PARK_Y_POS 
 
			
		
	
		
			
				
					        +  PAUSE_PARK_Y_POS 
 
			
		
	
		
			
				
					      # endif 
 
			
		
	
		
			
				
					    ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      if  ( ! nozzle_timed_out  & &  ELAPSED ( millis ( ) ,  nozzle_timeout ) )  { 
 
			
		
	
		
			
				
					        nozzle_timed_out  =  true ;  // on nozzle timeout remember the nozzles need to be reheated
 
 
			
		
	
		
			
				
					        HOTEND_LOOP ( )  thermalManager . setTargetHotend ( 0 ,  e ) ;  // Turn off all the nozzles
 
 
			
		
	
		
			
				
					        lcd_filament_change_show_message ( FILAMENT_CHANGE_MESSAGE_CLICK_TO_HEAT_NOZZLE ) ; 
 
			
		
	
		
			
				
					      } 
 
			
		
	
		
			
				
					      idle ( true ) ; 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					    KEEPALIVE_STATE ( IN_HANDLER ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    if  ( nozzle_timed_out )       // Turn nozzles back on if they were turned off
 
 
			
		
	
		
			
				
					      HOTEND_LOOP ( )  thermalManager . setTargetHotend ( temps [ e ] ,  e ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // Show "wait for heating"
 
 
			
		
	
		
			
				
					    lcd_filament_change_show_message ( FILAMENT_CHANGE_MESSAGE_WAIT_FOR_NOZZLES_TO_HEAT ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    wait_for_heatup  =  true ; 
 
			
		
	
		
			
				
					    while  ( wait_for_heatup )  { 
 
			
		
	
		
			
				
					      idle ( ) ; 
 
			
		
	
		
			
				
					      wait_for_heatup  =  false ; 
 
			
		
	
		
			
				
					      HOTEND_LOOP ( )  { 
 
			
		
	
		
			
				
					        if  ( abs ( thermalManager . degHotend ( e )  -  temps [ e ] )  >  3 )  { 
 
			
		
	
		
			
				
					          wait_for_heatup  =  true ; 
 
			
		
	
		
			
				
					          break ; 
 
			
		
	
		
			
				
					        } 
 
			
		
	
		
			
				
					      } 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // Show "insert filament"
 
 
			
		
	
		
			
				
					    if  ( nozzle_timed_out ) 
 
			
		
	
		
			
				
					      lcd_filament_change_show_message ( FILAMENT_CHANGE_MESSAGE_INSERT ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # if HAS_BUZZER 
 
			
		
	
		
			
				
					      filament_change_beep ( true ) ; 
 
			
		
	
		
			
				
					    # endif 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    KEEPALIVE_STATE ( PAUSED_FOR_USER ) ; 
 
			
		
	
		
			
				
					    wait_for_user  =  true ;     // LCD click or M108 will clear this
 
 
			
		
	
		
			
				
					    while  ( wait_for_user  & &  nozzle_timed_out )  { 
 
			
		
	
		
			
				
					      # if HAS_BUZZER 
 
			
		
	
		
			
				
					        filament_change_beep ( ) ; 
 
			
		
	
		
			
				
					    // Unload filament
 
 
			
		
	
		
			
				
					    const  float  unload_length  =  parser . seen ( ' U ' )  ?  parser . value_axis_units ( E_AXIS )  :  0 
 
			
		
	
		
			
				
					      # if defined(FILAMENT_CHANGE_UNLOAD_LENGTH) && FILAMENT_CHANGE_UNLOAD_LENGTH > 0 
 
			
		
	
		
			
				
					        -  ( FILAMENT_CHANGE_UNLOAD_LENGTH ) 
 
			
		
	
		
			
				
					      # endif 
 
			
		
	
		
			
				
					      idle ( true ) ; 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					    KEEPALIVE_STATE ( IN_HANDLER ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // Show "load" message
 
 
			
		
	
		
			
				
					    lcd_filament_change_show_message ( FILAMENT_CHANGE_MESSAGE_LOAD ) ; 
 
			
		
	
		
			
				
					    ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // Load filament
 
 
			
		
	
		
			
				
					    destination [ E_AXIS ]  + =  parser . seen ( ' L ' )  ?  - parser . value_axis_units ( E_AXIS )  :  0 
 
			
		
	
		
			
				
					      # if  FILAMENT_CHANGE_LOAD_LENGTH > 0 
 
			
		
	
		
			
				
					    const  float  load_length  =  parser . seen ( ' L ' )  ?  parser . value_axis_units ( E_AXIS )  :  0 
 
			
		
	
		
			
				
					      # ifdef FILAMENT_CHANGE_LOAD_LENGTH 
 
			
		
	
		
			
				
					        +  FILAMENT_CHANGE_LOAD_LENGTH 
 
			
		
	
		
			
				
					      # endif 
 
			
		
	
		
			
				
					    ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    RUNPLAN ( FILAMENT_CHANGE_LOAD_FEEDRATE ) ; 
 
			
		
	
		
			
				
					    stepper . synchronize ( ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # if defined(FILAMENT_CHANGE_EXTRUDE_LENGTH) && FILAMENT_CHANGE_EXTRUDE_LENGTH > 0 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      do  { 
 
			
		
	
		
			
				
					        // "Wait for filament extrude"
 
 
			
		
	
		
			
				
					        lcd_filament_change_show_message ( FILAMENT_CHANGE_MESSAGE_EXTRUDE ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        // Extrude filament to get into hotend
 
 
			
		
	
		
			
				
					        destination [ E_AXIS ]  + =  FILAMENT_CHANGE_EXTRUDE_LENGTH ; 
 
			
		
	
		
			
				
					        RUNPLAN ( FILAMENT_CHANGE_EXTRUDE_FEEDRATE ) ; 
 
			
		
	
		
			
				
					        stepper . synchronize ( ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        // Show "Extrude More" / "Resume" menu and wait for reply
 
 
			
		
	
		
			
				
					        KEEPALIVE_STATE ( PAUSED_FOR_USER ) ; 
 
			
		
	
		
			
				
					        wait_for_user  =  false ; 
 
			
		
	
		
			
				
					        lcd_filament_change_show_message ( FILAMENT_CHANGE_MESSAGE_OPTION ) ; 
 
			
		
	
		
			
				
					        while  ( filament_change_menu_response  = =  FILAMENT_CHANGE_RESPONSE_WAIT_FOR )  idle ( true ) ; 
 
			
		
	
		
			
				
					        KEEPALIVE_STATE ( IN_HANDLER ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        // Keep looping if "Extrude More" was selected
 
 
			
		
	
		
			
				
					      }  while  ( filament_change_menu_response  = =  FILAMENT_CHANGE_RESPONSE_EXTRUDE_MORE ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # endif 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // "Wait for print to resume"
 
 
			
		
	
		
			
				
					    lcd_filament_change_show_message ( FILAMENT_CHANGE_MESSAGE_RESUME ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // Set extruder to saved position
 
 
			
		
	
		
			
				
					    destination [ E_AXIS ]  =  current_position [ E_AXIS ]  =  lastpos [ E_AXIS ] ; 
 
			
		
	
		
			
				
					    planner . set_e_position_mm ( current_position [ E_AXIS ] ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # if IS_KINEMATIC 
 
			
		
	
		
			
				
					      // Move XYZ to starting position
 
 
			
		
	
		
			
				
					      planner . buffer_line_kinematic ( lastpos ,  FILAMENT_CHANGE_XY_FEEDRATE ,  active_extruder ) ; 
 
			
		
	
		
			
				
					    # else 
 
			
		
	
		
			
				
					      // Move XY to starting position, then Z
 
 
			
		
	
		
			
				
					      destination [ X_AXIS ]  =  lastpos [ X_AXIS ] ; 
 
			
		
	
		
			
				
					      destination [ Y_AXIS ]  =  lastpos [ Y_AXIS ] ; 
 
			
		
	
		
			
				
					      RUNPLAN ( FILAMENT_CHANGE_XY_FEEDRATE ) ; 
 
			
		
	
		
			
				
					      destination [ Z_AXIS ]  =  lastpos [ Z_AXIS ] ; 
 
			
		
	
		
			
				
					      RUNPLAN ( FILAMENT_CHANGE_Z_FEEDRATE ) ; 
 
			
		
	
		
			
				
					    # endif 
 
			
		
	
		
			
				
					    stepper . synchronize ( ) ; 
 
			
		
	
		
			
				
					    const  int  beep_count  =  parser . seen ( ' B ' )  ?  parser . value_int ( )  : 
 
			
		
	
		
			
				
					      # ifdef FILAMENT_CHANGE_NUMBER_OF_ALERT_BEEPS 
 
			
		
	
		
			
				
					        FILAMENT_CHANGE_NUMBER_OF_ALERT_BEEPS 
 
			
		
	
		
			
				
					      # else 
 
			
		
	
		
			
				
					        - 1 
 
			
		
	
		
			
				
					      # endif 
 
			
		
	
		
			
				
					    ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # if ENABLED(FILAMENT_RUNOUT_SENSOR) 
 
			
		
	
		
			
				
					      filament_ran_out  =  false ; 
 
			
		
	
		
			
				
					    # endif 
 
			
		
	
		
			
				
					    const  bool  job_running  =  print_job_timer . isRunning ( ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // Show status screen
 
 
			
		
	
		
			
				
					    lcd_filament_change_show_message ( FILAMENT_CHANGE_MESSAGE_STATUS ) ; 
 
			
		
	
		
			
				
					    if  ( pause_print ( retract ,  z_lift ,  x_pos ,  y_pos ,  unload_length ,  beep_count ,  true ) )  { 
 
			
		
	
		
			
				
					      wait_for_filament_reload ( beep_count ) ; 
 
			
		
	
		
			
				
					      resume_print ( load_length ,  ADVANCED_PAUSE_EXTRUDE_LENGTH ,  beep_count ) ; 
 
			
		
	
		
			
				
					    } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    // Resume the print job timer if it was running
 
 
			
		
	
		
			
				
					    if  ( job_running )  print_job_timer . start ( ) ; 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    busy_doing_M600  =  false ;   // Allow Stepper Motors to be turned off during inactivity
 
 
			
		
	
		
			
				
					  } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					# endif  //  FILAMENT_CHANG E_FEATURE
 
			
		
	
		
			
				
					# endif  // ADVANCED_PAUSE_FEATURE
  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					# if ENABLED(DUAL_X_CARRIAGE)  
			
		
	
		
			
				
					
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -10569,11 +10607,11 @@ void process_next_command() {
 
			
		
	
		
			
				
					          break ; 
 
			
		
	
		
			
				
					      # endif  // HAS_BED_PROBE
 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      # if ENABLED( FILAMENT_CHANG E_FEATURE)
 
			
		
	
		
			
				
					      # if ENABLED( ADVANCED_PAUS E_FEATURE)
 
			
		
	
		
			
				
					        case  600 :  // M600: Pause for filament change
 
 
			
		
	
		
			
				
					          gcode_M600 ( ) ; 
 
			
		
	
		
			
				
					          break ; 
 
			
		
	
		
			
				
					      # endif  //  FILAMENT_CHANG E_FEATURE
 
			
		
	
		
			
				
					      # endif  //  ADVANCED_PAUS E_FEATURE
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      # if ENABLED(DUAL_X_CARRIAGE) || ENABLED(DUAL_NOZZLE_DUPLICATION_MODE) 
 
			
		
	
		
			
				
					        case  605 :  // M605: Set Dual X Carriage movement mode
 
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -12064,13 +12102,13 @@ void manage_inactivity(bool ignore_stepper_queue/*=false*/) {
 
			
		
	
		
			
				
					  } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  // Prevent steppers timing-out in the middle of M600
 
 
			
		
	
		
			
				
					  # if ENABLED( FILAMENT_CHANGE_FEATURE) && ENABLED(FILAMENT_CHANGE _NO_STEPPER_TIMEOUT)
 
			
		
	
		
			
				
					    # define M 600_TEST !busy_doing_M600 
 
			
		
	
		
			
				
					  # if ENABLED( ADVANCED_PAUSE_FEATURE) && ENABLED(PAUSE_PARK _NO_STEPPER_TIMEOUT)
 
			
		
	
		
			
				
					    # define M OVE_AWAY_TEST !move_away_flag 
 
			
		
	
		
			
				
					  # else 
 
			
		
	
		
			
				
					    # define M 600 _TEST true
 
			
		
	
		
			
				
					    # define M OVE_AWAY _TEST true
 
			
		
	
		
			
				
					  # endif 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  if  ( M 600 _TEST & &  stepper_inactive_time  & &  ELAPSED ( ms ,  previous_cmd_ms  +  stepper_inactive_time ) 
 
			
		
	
		
			
				
					  if  ( M OVE_AWAY _TEST & &  stepper_inactive_time  & &  ELAPSED ( ms ,  previous_cmd_ms  +  stepper_inactive_time ) 
 
			
		
	
		
			
				
					      & &  ! ignore_stepper_queue  & &  ! planner . blocks_queued ( ) )  { 
 
			
		
	
		
			
				
					    # if ENABLED(DISABLE_INACTIVE_X) 
 
			
		
	
		
			
				
					      disable_X ( ) ; 
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -12216,7 +12254,7 @@ void manage_inactivity(bool ignore_stepper_queue/*=false*/) {
 
			
		
	
		
			
				
					 *  Standard  idle  routine  keeps  the  machine  alive 
 
			
		
	
		
			
				
					 */ 
 
			
		
	
		
			
				
					void  idle (  
			
		
	
		
			
				
					  # if ENABLED( FILAMENT_CHANG E_FEATURE)
 
			
		
	
		
			
				
					  # if ENABLED( ADVANCED_PAUS E_FEATURE)
 
			
		
	
		
			
				
					    bool  no_stepper_sleep /*=false*/ 
 
			
		
	
		
			
				
					  # endif 
 
			
		
	
		
			
				
					)  {  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -12229,7 +12267,7 @@ void idle(
 
			
		
	
		
			
				
					  # endif 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  manage_inactivity ( 
 
			
		
	
		
			
				
					    # if ENABLED( FILAMENT_CHANG E_FEATURE)
 
			
		
	
		
			
				
					    # if ENABLED( ADVANCED_PAUS E_FEATURE)
 
			
		
	
		
			
				
					      no_stepper_sleep 
 
			
		
	
		
			
				
					    # endif 
 
			
		
	
		
			
				
					  ) ;