SMUFF (MMU2 clone) support (#19912)
This commit is contained in:
		
				
					committed by
					
						
						Scott Lahteine
					
				
			
			
				
	
			
			
			
						parent
						
							b6d2671260
						
					
				
				
					commit
					bd38e59479
				
			@@ -158,33 +158,19 @@
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Průša MK2 Single Nozzle Multi-Material Multiplexer, and variants.
 | 
			
		||||
 * Multi-Material Unit
 | 
			
		||||
 * Set to one of these predefined models:
 | 
			
		||||
 *
 | 
			
		||||
 * This device allows one stepper driver on a control board to drive
 | 
			
		||||
 * two to eight stepper motors, one at a time, in a manner suitable
 | 
			
		||||
 * for extruders.
 | 
			
		||||
 *
 | 
			
		||||
 * This option only allows the multiplexer to switch on tool-change.
 | 
			
		||||
 * Additional options to configure custom E moves are pending.
 | 
			
		||||
 */
 | 
			
		||||
//#define MK2_MULTIPLEXER
 | 
			
		||||
#if ENABLED(MK2_MULTIPLEXER)
 | 
			
		||||
  // Override the default DIO selector pins here, if needed.
 | 
			
		||||
  // Some pins files may provide defaults for these pins.
 | 
			
		||||
  //#define E_MUX0_PIN 40  // Always Required
 | 
			
		||||
  //#define E_MUX1_PIN 42  // Needed for 3 to 8 inputs
 | 
			
		||||
  //#define E_MUX2_PIN 44  // Needed for 5 to 8 inputs
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Průša Multi-Material Unit v2
 | 
			
		||||
 *   PRUSA_MMU1      : Průša MMU1 (The "multiplexer" version)
 | 
			
		||||
 *   PRUSA_MMU2      : Průša MMU2
 | 
			
		||||
 *   PRUSA_MMU2S     : Průša MMU2S (Requires MK3S extruder with motion sensor, EXTRUDERS = 5)
 | 
			
		||||
 *   SMUFF_EMU_MMU2  : Technik Gegg SMUFF (Průša MMU2 emulation mode)
 | 
			
		||||
 *   SMUFF_EMU_MMU2S : Technik Gegg SMUFF (Průša MMU2S emulation mode)
 | 
			
		||||
 *
 | 
			
		||||
 * Requires NOZZLE_PARK_FEATURE to park print head in case MMU unit fails.
 | 
			
		||||
 * Requires EXTRUDERS = 5
 | 
			
		||||
 *
 | 
			
		||||
 * For additional configuration see Configuration_adv.h
 | 
			
		||||
 * See additional options in Configuration_adv.h.
 | 
			
		||||
 */
 | 
			
		||||
//#define PRUSA_MMU2
 | 
			
		||||
//#define MMU_MODEL PRUSA_MMU2
 | 
			
		||||
 | 
			
		||||
// A dual extruder that uses a single stepper motor
 | 
			
		||||
//#define SWITCHING_EXTRUDER
 | 
			
		||||
 
 | 
			
		||||
@@ -3532,11 +3532,24 @@
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Průša Multi-Material Unit v2
 | 
			
		||||
 * Průša Multi-Material Unit (MMU)
 | 
			
		||||
 * Enable in Configuration.h
 | 
			
		||||
 *
 | 
			
		||||
 * These devices allow a single stepper driver on the board to drive
 | 
			
		||||
 * multi-material feeders with any number of stepper motors.
 | 
			
		||||
 */
 | 
			
		||||
#if ENABLED(PRUSA_MMU2)
 | 
			
		||||
 | 
			
		||||
#if HAS_PRUSA_MMU1
 | 
			
		||||
  /**
 | 
			
		||||
   * This option only allows the multiplexer to switch on tool-change.
 | 
			
		||||
   * Additional options to configure custom E moves are pending.
 | 
			
		||||
   *
 | 
			
		||||
   * Override the default DIO selector pins here, if needed.
 | 
			
		||||
   * Some pins files may provide defaults for these pins.
 | 
			
		||||
   */
 | 
			
		||||
  //#define E_MUX0_PIN 40  // Always Required
 | 
			
		||||
  //#define E_MUX1_PIN 42  // Needed for 3 to 8 inputs
 | 
			
		||||
  //#define E_MUX2_PIN 44  // Needed for 5 to 8 inputs
 | 
			
		||||
#elif HAS_PRUSA_MMU2
 | 
			
		||||
  // Serial port used for communication with MMU2.
 | 
			
		||||
  // For AVR enable the UART port used for the MMU. (e.g., mmuSerial)
 | 
			
		||||
  // For 32-bit boards check your HAL for available serial ports. (e.g., Serial2)
 | 
			
		||||
@@ -3554,7 +3567,7 @@
 | 
			
		||||
 | 
			
		||||
  // Add an LCD menu for MMU2
 | 
			
		||||
  //#define MMU2_MENUS
 | 
			
		||||
  #if ENABLED(MMU2_MENUS)
 | 
			
		||||
  #if EITHER(MMU2_MENUS, HAS_PRUSA_MMU2S)
 | 
			
		||||
    // Settings for filament load / unload from the LCD menu.
 | 
			
		||||
    // This is for Průša MK3-style extruders. Customize for your hardware.
 | 
			
		||||
    #define MMU2_FILAMENTCHANGE_EJECT_FEED 80.0
 | 
			
		||||
@@ -3579,29 +3592,12 @@
 | 
			
		||||
      { -50.0, 2000 }
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * MMU Extruder Sensor
 | 
			
		||||
   *
 | 
			
		||||
   * Support for a Průša (or other) IR Sensor to detect filament near the extruder
 | 
			
		||||
   * and make loading more reliable. Suitable for an extruder equipped with a filament
 | 
			
		||||
   * sensor less than 38mm from the gears.
 | 
			
		||||
   *
 | 
			
		||||
   * During loading the extruder will stop when the sensor is triggered, then do a last
 | 
			
		||||
   * move up to the gears. If no filament is detected, the MMU2 can make some more attempts.
 | 
			
		||||
   * If all attempts fail, a filament runout will be triggered.
 | 
			
		||||
   */
 | 
			
		||||
  //#define MMU_EXTRUDER_SENSOR
 | 
			
		||||
  #if ENABLED(MMU_EXTRUDER_SENSOR)
 | 
			
		||||
    #define MMU_LOADING_ATTEMPTS_NR 5 // max. number of attempts to load filament if first load fail
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Using a sensor like the MMU2S
 | 
			
		||||
   * This mode requires a MK3S extruder with a sensor at the extruder idler, like the MMU2S.
 | 
			
		||||
   * See https://help.prusa3d.com/en/guide/3b-mk3s-mk2-5s-extruder-upgrade_41560, step 11
 | 
			
		||||
   */
 | 
			
		||||
  //#define PRUSA_MMU2_S_MODE
 | 
			
		||||
  #if ENABLED(PRUSA_MMU2_S_MODE)
 | 
			
		||||
  #if HAS_PRUSA_MMU2S
 | 
			
		||||
    #define MMU2_C0_RETRY   5             // Number of retries (total time = timeout*retries)
 | 
			
		||||
 | 
			
		||||
    #define MMU2_CAN_LOAD_FEEDRATE 800    // (mm/min)
 | 
			
		||||
@@ -3617,11 +3613,29 @@
 | 
			
		||||
    #define MMU2_CAN_LOAD_INCREMENT_SEQUENCE \
 | 
			
		||||
      { -MMU2_CAN_LOAD_INCREMENT, MMU2_CAN_LOAD_FEEDRATE }
 | 
			
		||||
 | 
			
		||||
  #else
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * MMU1 Extruder Sensor
 | 
			
		||||
     *
 | 
			
		||||
     * Support for a Průša (or other) IR Sensor to detect filament near the extruder
 | 
			
		||||
     * and make loading more reliable. Suitable for an extruder equipped with a filament
 | 
			
		||||
     * sensor less than 38mm from the gears.
 | 
			
		||||
     *
 | 
			
		||||
     * During loading the extruder will stop when the sensor is triggered, then do a last
 | 
			
		||||
     * move up to the gears. If no filament is detected, the MMU2 can make some more attempts.
 | 
			
		||||
     * If all attempts fail, a filament runout will be triggered.
 | 
			
		||||
     */
 | 
			
		||||
    //#define MMU_EXTRUDER_SENSOR
 | 
			
		||||
    #if ENABLED(MMU_EXTRUDER_SENSOR)
 | 
			
		||||
      #define MMU_LOADING_ATTEMPTS_NR 5 // max. number of attempts to load filament if first load fail
 | 
			
		||||
    #endif
 | 
			
		||||
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
  //#define MMU2_DEBUG  // Write debug info to serial output
 | 
			
		||||
 | 
			
		||||
#endif // PRUSA_MMU2
 | 
			
		||||
#endif // HAS_PRUSA_MMU2
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Advanced Print Counter settings
 | 
			
		||||
 
 | 
			
		||||
@@ -97,8 +97,8 @@ static_assert(DISABLED(BAUD_RATE_GCODE), "BAUD_RATE_GCODE is not yet supported o
 | 
			
		||||
  #define IS_RX0(P) (P == P0_03)
 | 
			
		||||
  #if IS_TX0(TMC_SW_MISO) || IS_RX0(TMC_SW_MOSI)
 | 
			
		||||
    #error "Serial port pins (0) conflict with Trinamic SPI pins!"
 | 
			
		||||
  #elif ENABLED(MK2_MULTIPLEXER) && (IS_TX0(E_MUX1_PIN) || IS_RX0(E_MUX0_PIN))
 | 
			
		||||
    #error "Serial port pins (0) conflict with MK2 multiplexer pins!"
 | 
			
		||||
  #elif HAS_PRUSA_MMU1 && (IS_TX0(E_MUX1_PIN) || IS_RX0(E_MUX0_PIN))
 | 
			
		||||
    #error "Serial port pins (0) conflict with Multi-Material-Unit multiplexer pins!"
 | 
			
		||||
  #elif (AXIS_HAS_SPI(X) && IS_TX0(X_CS_PIN)) || (AXIS_HAS_SPI(Y) && IS_RX0(Y_CS_PIN))
 | 
			
		||||
    #error "Serial port pins (0) conflict with X/Y axis SPI pins!"
 | 
			
		||||
  #endif
 | 
			
		||||
 
 | 
			
		||||
@@ -213,8 +213,8 @@
 | 
			
		||||
  #include "feature/controllerfan.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if ENABLED(PRUSA_MMU2)
 | 
			
		||||
  #include "feature/mmu2/mmu2.h"
 | 
			
		||||
#if HAS_PRUSA_MMU2
 | 
			
		||||
  #include "feature/mmu/mmu2.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if HAS_L64XX
 | 
			
		||||
@@ -713,9 +713,7 @@ void idle(TERN_(ADVANCED_PAUSE_FEATURE, bool no_stepper_sleep/*=false*/)) {
 | 
			
		||||
  TERN_(HAS_FILAMENT_SENSOR, runout.run());
 | 
			
		||||
 | 
			
		||||
  // Run HAL idle tasks
 | 
			
		||||
  #ifdef HAL_IDLETASK
 | 
			
		||||
    HAL_idletask();
 | 
			
		||||
  #endif
 | 
			
		||||
  TERN_(HAL_IDLETASK, HAL_idletask());
 | 
			
		||||
 | 
			
		||||
  // Check network connection
 | 
			
		||||
  TERN_(HAS_ETHERNET, ethernet.check());
 | 
			
		||||
@@ -772,7 +770,7 @@ void idle(TERN_(ADVANCED_PAUSE_FEATURE, bool no_stepper_sleep/*=false*/)) {
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
  // Update the Průša MMU2
 | 
			
		||||
  TERN_(PRUSA_MMU2, mmu2.mmu_loop());
 | 
			
		||||
  TERN_(HAS_PRUSA_MMU2, mmu2.mmu_loop());
 | 
			
		||||
 | 
			
		||||
  // Handle Joystick jogging
 | 
			
		||||
  TERN_(POLL_JOG, joystick.inject_jog_moves());
 | 
			
		||||
@@ -780,9 +778,8 @@ void idle(TERN_(ADVANCED_PAUSE_FEATURE, bool no_stepper_sleep/*=false*/)) {
 | 
			
		||||
  // Direct Stepping
 | 
			
		||||
  TERN_(DIRECT_STEPPING, page_manager.write_responses());
 | 
			
		||||
 | 
			
		||||
  #if HAS_TFT_LVGL_UI
 | 
			
		||||
    LV_TASK_HANDLER();
 | 
			
		||||
  #endif
 | 
			
		||||
  // Update the LVGL interface
 | 
			
		||||
  TERN_(HAS_TFT_LVGL_UI, LV_TASK_HANDLER());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -1187,8 +1184,8 @@ void setup() {
 | 
			
		||||
    SETUP_RUN(caselight.update_brightness());
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
  #if ENABLED(MK2_MULTIPLEXER)
 | 
			
		||||
    SETUP_LOG("MK2_MULTIPLEXER");
 | 
			
		||||
  #if HAS_PRUSA_MMU1
 | 
			
		||||
    SETUP_LOG("Prusa MMU1");
 | 
			
		||||
    SET_OUTPUT(E_MUX0_PIN);
 | 
			
		||||
    SET_OUTPUT(E_MUX1_PIN);
 | 
			
		||||
    SET_OUTPUT(E_MUX2_PIN);
 | 
			
		||||
@@ -1268,7 +1265,7 @@ void setup() {
 | 
			
		||||
    SETUP_RUN(test_tmc_connection(true, true, true, true));
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
  #if ENABLED(PRUSA_MMU2)
 | 
			
		||||
  #if HAS_PRUSA_MMU2
 | 
			
		||||
    SETUP_RUN(mmu2.init());
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@
 | 
			
		||||
 | 
			
		||||
#include "../inc/MarlinConfig.h"
 | 
			
		||||
 | 
			
		||||
#if ENABLED(MK2_MULTIPLEXER)
 | 
			
		||||
#if HAS_PRUSA_MMU1
 | 
			
		||||
 | 
			
		||||
#include "../module/stepper.h"
 | 
			
		||||
 | 
			
		||||
@@ -35,4 +35,4 @@ void select_multiplexed_stepper(const uint8_t e) {
 | 
			
		||||
  safe_delay(100);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif // MK2_MULTIPLEXER
 | 
			
		||||
#endif // HAS_PRUSA_MMU1
 | 
			
		||||
@@ -22,7 +22,7 @@
 | 
			
		||||
 | 
			
		||||
#include "../../inc/MarlinConfig.h"
 | 
			
		||||
 | 
			
		||||
#if ENABLED(PRUSA_MMU2)
 | 
			
		||||
#if HAS_PRUSA_MMU2
 | 
			
		||||
 | 
			
		||||
#include "mmu2.h"
 | 
			
		||||
#include "../../lcd/menu/menu_mmu2.h"
 | 
			
		||||
@@ -94,7 +94,7 @@ MMU2 mmu2;
 | 
			
		||||
#define mmuSerial   MMU2_SERIAL
 | 
			
		||||
 | 
			
		||||
bool MMU2::enabled, MMU2::ready, MMU2::mmu_print_saved;
 | 
			
		||||
#if ENABLED(PRUSA_MMU2_S_MODE)
 | 
			
		||||
#if HAS_PRUSA_MMU2S
 | 
			
		||||
  bool MMU2::mmu2s_triggered;
 | 
			
		||||
#endif
 | 
			
		||||
uint8_t MMU2::cmd, MMU2::cmd_arg, MMU2::last_cmd, MMU2::extruder;
 | 
			
		||||
@@ -105,23 +105,19 @@ int16_t MMU2::version = -1, MMU2::buildnr = -1;
 | 
			
		||||
millis_t MMU2::prev_request, MMU2::prev_P0_request;
 | 
			
		||||
char MMU2::rx_buffer[MMU_RX_SIZE], MMU2::tx_buffer[MMU_TX_SIZE];
 | 
			
		||||
 | 
			
		||||
#if BOTH(HAS_LCD_MENU, MMU2_MENUS)
 | 
			
		||||
struct E_Step {
 | 
			
		||||
  float extrude;        //!< extrude distance in mm
 | 
			
		||||
  feedRate_t feedRate;  //!< feed rate in mm/s
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
  struct E_Step {
 | 
			
		||||
    float extrude;        //!< extrude distance in mm
 | 
			
		||||
    feedRate_t feedRate;  //!< feed rate in mm/s
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  static constexpr E_Step
 | 
			
		||||
      ramming_sequence[] PROGMEM = { MMU2_RAMMING_SEQUENCE }
 | 
			
		||||
    , load_to_nozzle_sequence[] PROGMEM = { MMU2_LOAD_TO_NOZZLE_SEQUENCE }
 | 
			
		||||
    #if ENABLED(PRUSA_MMU2_S_MODE)
 | 
			
		||||
      , can_load_sequence[] PROGMEM = { MMU2_CAN_LOAD_SEQUENCE }
 | 
			
		||||
      , can_load_increment_sequence[] PROGMEM = { MMU2_CAN_LOAD_INCREMENT_SEQUENCE }
 | 
			
		||||
    #endif
 | 
			
		||||
  ;
 | 
			
		||||
 | 
			
		||||
#endif // MMU2_MENUS
 | 
			
		||||
static constexpr E_Step
 | 
			
		||||
    ramming_sequence[] PROGMEM = { MMU2_RAMMING_SEQUENCE }
 | 
			
		||||
  , load_to_nozzle_sequence[] PROGMEM = { MMU2_LOAD_TO_NOZZLE_SEQUENCE }
 | 
			
		||||
  #if HAS_PRUSA_MMU2S
 | 
			
		||||
    , can_load_sequence[] PROGMEM = { MMU2_CAN_LOAD_SEQUENCE }
 | 
			
		||||
    , can_load_increment_sequence[] PROGMEM = { MMU2_CAN_LOAD_INCREMENT_SEQUENCE }
 | 
			
		||||
  #endif
 | 
			
		||||
;
 | 
			
		||||
 | 
			
		||||
MMU2::MMU2() {
 | 
			
		||||
  rx_buffer[0] = '\0';
 | 
			
		||||
@@ -162,7 +158,7 @@ uint8_t MMU2::get_current_tool() {
 | 
			
		||||
  return extruder == MMU2_NO_TOOL ? -1 : extruder;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if EITHER(PRUSA_MMU2_S_MODE, MMU_EXTRUDER_SENSOR)
 | 
			
		||||
#if EITHER(HAS_PRUSA_MMU2S, MMU_EXTRUDER_SENSOR)
 | 
			
		||||
  #define FILAMENT_PRESENT() (READ(FIL_RUNOUT1_PIN) != FIL_RUNOUT1_STATE)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@@ -188,7 +184,7 @@ void MMU2::mmu_loop() {
 | 
			
		||||
 | 
			
		||||
    case -2:
 | 
			
		||||
      if (rx_ok()) {
 | 
			
		||||
        sscanf(rx_buffer, "%uok\n", &version);
 | 
			
		||||
        sscanf(rx_buffer, "%huok\n", &version);
 | 
			
		||||
 | 
			
		||||
        DEBUG_ECHOLNPAIR("MMU => ", version, "\nMMU <= 'S2'");
 | 
			
		||||
 | 
			
		||||
@@ -199,7 +195,7 @@ void MMU2::mmu_loop() {
 | 
			
		||||
 | 
			
		||||
    case -3:
 | 
			
		||||
      if (rx_ok()) {
 | 
			
		||||
        sscanf(rx_buffer, "%uok\n", &buildnr);
 | 
			
		||||
        sscanf(rx_buffer, "%huok\n", &buildnr);
 | 
			
		||||
 | 
			
		||||
        DEBUG_ECHOLNPAIR("MMU => ", buildnr);
 | 
			
		||||
 | 
			
		||||
@@ -242,7 +238,7 @@ void MMU2::mmu_loop() {
 | 
			
		||||
 | 
			
		||||
        enabled = true;
 | 
			
		||||
        state = 1;
 | 
			
		||||
        TERN_(PRUSA_MMU2_S_MODE, mmu2s_triggered = false);
 | 
			
		||||
        TERN_(HAS_PRUSA_MMU2S, mmu2s_triggered = false);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
@@ -307,7 +303,7 @@ void MMU2::mmu_loop() {
 | 
			
		||||
        state = 2; // wait for response
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      TERN_(PRUSA_MMU2_S_MODE, check_filament());
 | 
			
		||||
      TERN_(HAS_PRUSA_MMU2S, check_filament());
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case 2:   // response to command P0
 | 
			
		||||
@@ -324,7 +320,7 @@ void MMU2::mmu_loop() {
 | 
			
		||||
      else if (ELAPSED(millis(), prev_request + MMU_P0_TIMEOUT)) // Resend request after timeout (3s)
 | 
			
		||||
        state = 1;
 | 
			
		||||
 | 
			
		||||
      TERN_(PRUSA_MMU2_S_MODE, check_filament());
 | 
			
		||||
      TERN_(HAS_PRUSA_MMU2S, check_filament());
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case 3:   // response to mmu commands
 | 
			
		||||
@@ -340,9 +336,9 @@ void MMU2::mmu_loop() {
 | 
			
		||||
      #endif
 | 
			
		||||
 | 
			
		||||
      if (rx_ok()) {
 | 
			
		||||
        // Response to C0 mmu command in PRUSA_MMU2_S_MODE
 | 
			
		||||
        // Response to C0 mmu command in MMU2S model
 | 
			
		||||
        bool can_reset = true;
 | 
			
		||||
        #if ENABLED(PRUSA_MMU2_S_MODE)
 | 
			
		||||
        #if HAS_PRUSA_MMU2S
 | 
			
		||||
          if (!mmu2s_triggered && last_cmd == MMU_CMD_C0) {
 | 
			
		||||
            can_reset = false;
 | 
			
		||||
            // MMU ok received but filament sensor not triggered, retrying...
 | 
			
		||||
@@ -367,7 +363,7 @@ void MMU2::mmu_loop() {
 | 
			
		||||
        }
 | 
			
		||||
        state = 1;
 | 
			
		||||
      }
 | 
			
		||||
      TERN_(PRUSA_MMU2_S_MODE, check_filament());
 | 
			
		||||
      TERN_(HAS_PRUSA_MMU2S, check_filament());
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -487,7 +483,7 @@ static void mmu2_not_responding() {
 | 
			
		||||
  BUZZ(100, 659);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if ENABLED(PRUSA_MMU2_S_MODE)
 | 
			
		||||
#if HAS_PRUSA_MMU2S
 | 
			
		||||
 | 
			
		||||
  bool MMU2::load_to_gears() {
 | 
			
		||||
    command(MMU_CMD_C0);
 | 
			
		||||
@@ -541,33 +537,38 @@ static void mmu2_not_responding() {
 | 
			
		||||
   * Tc Load to nozzle after filament was prepared by Tx and extruder nozzle is already heated.
 | 
			
		||||
   */
 | 
			
		||||
  void MMU2::tool_change(const char* special) {
 | 
			
		||||
 | 
			
		||||
    if (!enabled) return;
 | 
			
		||||
 | 
			
		||||
    #if ENABLED(MMU2_MENUS)
 | 
			
		||||
      if (!enabled) return;
 | 
			
		||||
 | 
			
		||||
      set_runout_valid(false);
 | 
			
		||||
 | 
			
		||||
      switch (*special) {
 | 
			
		||||
        case '?': {
 | 
			
		||||
          uint8_t index = mmu2_choose_filament();
 | 
			
		||||
          while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100);
 | 
			
		||||
          load_filament_to_nozzle(index);
 | 
			
		||||
          #if ENABLED(MMU2_MENUS)
 | 
			
		||||
            const uint8_t index = mmu2_choose_filament();
 | 
			
		||||
            while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100);
 | 
			
		||||
            load_filament_to_nozzle(index);
 | 
			
		||||
          #else
 | 
			
		||||
            BUZZ(400, 40);
 | 
			
		||||
          #endif
 | 
			
		||||
        } break;
 | 
			
		||||
 | 
			
		||||
        case 'x': {
 | 
			
		||||
          planner.synchronize();
 | 
			
		||||
          uint8_t index = mmu2_choose_filament();
 | 
			
		||||
          DISABLE_AXIS_E0();
 | 
			
		||||
          command(MMU_CMD_T0 + index);
 | 
			
		||||
          manage_response(true, true);
 | 
			
		||||
          #if ENABLED(MMU2_MENUS)
 | 
			
		||||
            planner.synchronize();
 | 
			
		||||
            const uint8_t index = mmu2_choose_filament();
 | 
			
		||||
            DISABLE_AXIS_E0();
 | 
			
		||||
            command(MMU_CMD_T0 + index);
 | 
			
		||||
            manage_response(true, true);
 | 
			
		||||
 | 
			
		||||
          if (load_to_gears()) {
 | 
			
		||||
            mmu_loop();
 | 
			
		||||
            ENABLE_AXIS_E0();
 | 
			
		||||
            extruder = index;
 | 
			
		||||
            active_extruder = 0;
 | 
			
		||||
          }
 | 
			
		||||
            if (load_to_gears()) {
 | 
			
		||||
              mmu_loop();
 | 
			
		||||
              ENABLE_AXIS_E0();
 | 
			
		||||
              extruder = index;
 | 
			
		||||
              active_extruder = 0;
 | 
			
		||||
            }
 | 
			
		||||
          #else
 | 
			
		||||
            BUZZ(400, 40);
 | 
			
		||||
          #endif
 | 
			
		||||
        } break;
 | 
			
		||||
 | 
			
		||||
        case 'c': {
 | 
			
		||||
@@ -577,8 +578,6 @@ static void mmu2_not_responding() {
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      set_runout_valid(true);
 | 
			
		||||
 | 
			
		||||
    #endif // MMU2_MENUS
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
#elif ENABLED(MMU_EXTRUDER_SENSOR)
 | 
			
		||||
@@ -628,20 +627,23 @@ static void mmu2_not_responding() {
 | 
			
		||||
  void MMU2::tool_change(const char* special) {
 | 
			
		||||
    if (!enabled) return;
 | 
			
		||||
 | 
			
		||||
    #if ENABLED(MMU2_MENUS)
 | 
			
		||||
    set_runout_valid(false);
 | 
			
		||||
 | 
			
		||||
      set_runout_valid(false);
 | 
			
		||||
 | 
			
		||||
      switch (*special) {
 | 
			
		||||
        case '?': {
 | 
			
		||||
          DEBUG_ECHOLNPGM("case ?\n");
 | 
			
		||||
    switch (*special) {
 | 
			
		||||
      case '?': {
 | 
			
		||||
        DEBUG_ECHOLNPGM("case ?\n");
 | 
			
		||||
        #if ENABLED(MMU2_MENUS)
 | 
			
		||||
          uint8_t index = mmu2_choose_filament();
 | 
			
		||||
          while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100);
 | 
			
		||||
          load_filament_to_nozzle(index);
 | 
			
		||||
        } break;
 | 
			
		||||
        #else
 | 
			
		||||
          BUZZ(400, 40);
 | 
			
		||||
        #endif
 | 
			
		||||
      } break;
 | 
			
		||||
 | 
			
		||||
        case 'x': {
 | 
			
		||||
          DEBUG_ECHOLNPGM("case x\n");
 | 
			
		||||
      case 'x': {
 | 
			
		||||
        DEBUG_ECHOLNPGM("case x\n");
 | 
			
		||||
        #if ENABLED(MMU2_MENUS)
 | 
			
		||||
          planner.synchronize();
 | 
			
		||||
          uint8_t index = mmu2_choose_filament();
 | 
			
		||||
          DISABLE_AXIS_E0();
 | 
			
		||||
@@ -654,18 +656,19 @@ static void mmu2_not_responding() {
 | 
			
		||||
          ENABLE_AXIS_E0();
 | 
			
		||||
          extruder = index;
 | 
			
		||||
          active_extruder = 0;
 | 
			
		||||
        } break;
 | 
			
		||||
        #else
 | 
			
		||||
          BUZZ(400, 40);
 | 
			
		||||
        #endif
 | 
			
		||||
      } break;
 | 
			
		||||
 | 
			
		||||
        case 'c': {
 | 
			
		||||
          DEBUG_ECHOLNPGM("case c\n");
 | 
			
		||||
          while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100);
 | 
			
		||||
          execute_extruder_sequence((const E_Step *)load_to_nozzle_sequence, COUNT(load_to_nozzle_sequence));
 | 
			
		||||
        } break;
 | 
			
		||||
      }
 | 
			
		||||
      case 'c': {
 | 
			
		||||
        DEBUG_ECHOLNPGM("case c\n");
 | 
			
		||||
        while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100);
 | 
			
		||||
        execute_extruder_sequence((const E_Step *)load_to_nozzle_sequence, COUNT(load_to_nozzle_sequence));
 | 
			
		||||
      } break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
      set_runout_valid(true);
 | 
			
		||||
 | 
			
		||||
    #endif // MMU2_MENUS
 | 
			
		||||
    set_runout_valid(true);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void MMU2::mmu_continue_loading() {
 | 
			
		||||
@@ -682,68 +685,74 @@ static void mmu2_not_responding() {
 | 
			
		||||
    mmu_idl_sens = 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
#elif DISABLED(MMU_EXTRUDER_SENSOR) && DISABLED(PRUSA_MMU2_S_MODE)
 | 
			
		||||
#else // !HAS_PRUSA_MMU2S && !MMU_EXTRUDER_SENSOR
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handle tool change
 | 
			
		||||
 */
 | 
			
		||||
void MMU2::tool_change(const uint8_t index) {
 | 
			
		||||
  if (!enabled) return;
 | 
			
		||||
  /**
 | 
			
		||||
   * Handle tool change
 | 
			
		||||
   */
 | 
			
		||||
  void MMU2::tool_change(const uint8_t index) {
 | 
			
		||||
    if (!enabled) return;
 | 
			
		||||
 | 
			
		||||
  set_runout_valid(false);
 | 
			
		||||
    set_runout_valid(false);
 | 
			
		||||
 | 
			
		||||
  if (index != extruder) {
 | 
			
		||||
    DISABLE_AXIS_E0();
 | 
			
		||||
    ui.status_printf_P(0, GET_TEXT(MSG_MMU2_LOADING_FILAMENT), int(index + 1));
 | 
			
		||||
    command(MMU_CMD_T0 + index);
 | 
			
		||||
    manage_response(true, true);
 | 
			
		||||
    command(MMU_CMD_C0);
 | 
			
		||||
    extruder = index; //filament change is finished
 | 
			
		||||
    active_extruder = 0;
 | 
			
		||||
    ENABLE_AXIS_E0();
 | 
			
		||||
    SERIAL_ECHO_START();
 | 
			
		||||
    SERIAL_ECHOLNPAIR(STR_ACTIVE_EXTRUDER, int(extruder));
 | 
			
		||||
    ui.reset_status();
 | 
			
		||||
    if (index != extruder) {
 | 
			
		||||
      DISABLE_AXIS_E0();
 | 
			
		||||
      ui.status_printf_P(0, GET_TEXT(MSG_MMU2_LOADING_FILAMENT), int(index + 1));
 | 
			
		||||
      command(MMU_CMD_T0 + index);
 | 
			
		||||
      manage_response(true, true);
 | 
			
		||||
      command(MMU_CMD_C0);
 | 
			
		||||
      extruder = index; //filament change is finished
 | 
			
		||||
      active_extruder = 0;
 | 
			
		||||
      ENABLE_AXIS_E0();
 | 
			
		||||
      SERIAL_ECHO_START();
 | 
			
		||||
      SERIAL_ECHOLNPAIR(STR_ACTIVE_EXTRUDER, int(extruder));
 | 
			
		||||
      ui.reset_status();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    set_runout_valid(true);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  set_runout_valid(true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handle special T?/Tx/Tc commands
 | 
			
		||||
 *
 | 
			
		||||
 * T? Gcode to extrude shouldn't have to follow, load to extruder wheels is done automatically
 | 
			
		||||
 * Tx Same as T?, except nozzle doesn't have to be preheated. Tc must be placed after extruder nozzle is preheated to finish filament load.
 | 
			
		||||
 * Tc Load to nozzle after filament was prepared by Tx and extruder nozzle is already heated.
 | 
			
		||||
 */
 | 
			
		||||
void MMU2::tool_change(const char* special) {
 | 
			
		||||
  if (!enabled) return;
 | 
			
		||||
 | 
			
		||||
  #if ENABLED(MMU2_MENUS)
 | 
			
		||||
  /**
 | 
			
		||||
   * Handle special T?/Tx/Tc commands
 | 
			
		||||
   *
 | 
			
		||||
   * T? Gcode to extrude shouldn't have to follow, load to extruder wheels is done automatically
 | 
			
		||||
   * Tx Same as T?, except nozzle doesn't have to be preheated. Tc must be placed after extruder nozzle is preheated to finish filament load.
 | 
			
		||||
   * Tc Load to nozzle after filament was prepared by Tx and extruder nozzle is already heated.
 | 
			
		||||
   */
 | 
			
		||||
  void MMU2::tool_change(const char* special) {
 | 
			
		||||
    if (!enabled) return;
 | 
			
		||||
 | 
			
		||||
    set_runout_valid(false);
 | 
			
		||||
 | 
			
		||||
    switch (*special) {
 | 
			
		||||
      case '?': {
 | 
			
		||||
        DEBUG_ECHOLNPGM("case ?\n");
 | 
			
		||||
        uint8_t index = mmu2_choose_filament();
 | 
			
		||||
        while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100);
 | 
			
		||||
        load_filament_to_nozzle(index);
 | 
			
		||||
        #if ENABLED(MMU2_MENUS)
 | 
			
		||||
          uint8_t index = mmu2_choose_filament();
 | 
			
		||||
          while (!thermalManager.wait_for_hotend(active_extruder, false)) safe_delay(100);
 | 
			
		||||
          load_filament_to_nozzle(index);
 | 
			
		||||
        #else
 | 
			
		||||
          BUZZ(400, 40);
 | 
			
		||||
        #endif
 | 
			
		||||
      } break;
 | 
			
		||||
 | 
			
		||||
      case 'x': {
 | 
			
		||||
        DEBUG_ECHOLNPGM("case x\n");
 | 
			
		||||
        planner.synchronize();
 | 
			
		||||
        uint8_t index = mmu2_choose_filament();
 | 
			
		||||
        DISABLE_AXIS_E0();
 | 
			
		||||
        command(MMU_CMD_T0 + index);
 | 
			
		||||
        manage_response(true, true);
 | 
			
		||||
        command(MMU_CMD_C0);
 | 
			
		||||
        mmu_loop();
 | 
			
		||||
        #if ENABLED(MMU2_MENUS)
 | 
			
		||||
          planner.synchronize();
 | 
			
		||||
          uint8_t index = mmu2_choose_filament();
 | 
			
		||||
          DISABLE_AXIS_E0();
 | 
			
		||||
          command(MMU_CMD_T0 + index);
 | 
			
		||||
          manage_response(true, true);
 | 
			
		||||
          command(MMU_CMD_C0);
 | 
			
		||||
          mmu_loop();
 | 
			
		||||
 | 
			
		||||
        ENABLE_AXIS_E0();
 | 
			
		||||
        extruder = index;
 | 
			
		||||
        active_extruder = 0;
 | 
			
		||||
          ENABLE_AXIS_E0();
 | 
			
		||||
          extruder = index;
 | 
			
		||||
          active_extruder = 0;
 | 
			
		||||
        #else
 | 
			
		||||
          BUZZ(400, 40);
 | 
			
		||||
        #endif
 | 
			
		||||
      } break;
 | 
			
		||||
 | 
			
		||||
      case 'c': {
 | 
			
		||||
@@ -754,11 +763,9 @@ void MMU2::tool_change(const char* special) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    set_runout_valid(true);
 | 
			
		||||
 | 
			
		||||
  #endif
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
#endif // MMU_EXTRUDER_SENSOR
 | 
			
		||||
#endif // HAS_PRUSA_MMU2S
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Set next command
 | 
			
		||||
@@ -866,7 +873,7 @@ void MMU2::filament_runout() {
 | 
			
		||||
  planner.synchronize();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if ENABLED(PRUSA_MMU2_S_MODE)
 | 
			
		||||
#if HAS_PRUSA_MMU2S
 | 
			
		||||
 | 
			
		||||
  void MMU2::check_filament() {
 | 
			
		||||
    const bool present = FILAMENT_PRESENT();
 | 
			
		||||
@@ -907,162 +914,159 @@ void MMU2::filament_runout() {
 | 
			
		||||
    DEBUG_ECHOLNPGM(" succeeded.");
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if BOTH(HAS_LCD_MENU, MMU2_MENUS)
 | 
			
		||||
// Load filament into MMU2
 | 
			
		||||
void MMU2::load_filament(const uint8_t index) {
 | 
			
		||||
  if (!enabled) return;
 | 
			
		||||
  command(MMU_CMD_L0 + index);
 | 
			
		||||
  manage_response(false, false);
 | 
			
		||||
  BUZZ(200, 404);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
  // Load filament into MMU2
 | 
			
		||||
  void MMU2::load_filament(const uint8_t index) {
 | 
			
		||||
    if (!enabled) return;
 | 
			
		||||
    command(MMU_CMD_L0 + index);
 | 
			
		||||
/**
 | 
			
		||||
 * Switch material and load to nozzle
 | 
			
		||||
 */
 | 
			
		||||
bool MMU2::load_filament_to_nozzle(const uint8_t index) {
 | 
			
		||||
 | 
			
		||||
  if (!enabled) return false;
 | 
			
		||||
 | 
			
		||||
  if (thermalManager.tooColdToExtrude(active_extruder)) {
 | 
			
		||||
    BUZZ(200, 404);
 | 
			
		||||
    LCD_ALERTMESSAGEPGM(MSG_HOTEND_TOO_COLD);
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  command(MMU_CMD_T0 + index);
 | 
			
		||||
  manage_response(true, true);
 | 
			
		||||
 | 
			
		||||
  const bool success = load_to_gears();
 | 
			
		||||
  if (success) {
 | 
			
		||||
    mmu_loop();
 | 
			
		||||
    extruder = index;
 | 
			
		||||
    active_extruder = 0;
 | 
			
		||||
    load_to_nozzle();
 | 
			
		||||
    BUZZ(200, 404);
 | 
			
		||||
  }
 | 
			
		||||
  return success;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Load filament to nozzle of multimaterial printer
 | 
			
		||||
 *
 | 
			
		||||
 * This function is used only only after T? (user select filament) and M600 (change filament).
 | 
			
		||||
 * It is not used after T0 .. T4 command (select filament), in such case, gcode is responsible for loading
 | 
			
		||||
 * filament to nozzle.
 | 
			
		||||
 */
 | 
			
		||||
void MMU2::load_to_nozzle() {
 | 
			
		||||
  if (!enabled) return;
 | 
			
		||||
  execute_extruder_sequence((const E_Step *)load_to_nozzle_sequence, COUNT(load_to_nozzle_sequence));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MMU2::eject_filament(const uint8_t index, const bool recover) {
 | 
			
		||||
 | 
			
		||||
  if (!enabled) return false;
 | 
			
		||||
 | 
			
		||||
  if (thermalManager.tooColdToExtrude(active_extruder)) {
 | 
			
		||||
    BUZZ(200, 404);
 | 
			
		||||
    LCD_ALERTMESSAGEPGM(MSG_HOTEND_TOO_COLD);
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  LCD_MESSAGEPGM(MSG_MMU2_EJECTING_FILAMENT);
 | 
			
		||||
 | 
			
		||||
  ENABLE_AXIS_E0();
 | 
			
		||||
  current_position.e -= MMU2_FILAMENTCHANGE_EJECT_FEED;
 | 
			
		||||
  line_to_current_position(MMM_TO_MMS(2500));
 | 
			
		||||
  planner.synchronize();
 | 
			
		||||
  command(MMU_CMD_E0 + index);
 | 
			
		||||
  manage_response(false, false);
 | 
			
		||||
 | 
			
		||||
  if (recover)  {
 | 
			
		||||
    LCD_MESSAGEPGM(MSG_MMU2_EJECT_RECOVER);
 | 
			
		||||
    BUZZ(200, 404);
 | 
			
		||||
    TERN_(HOST_PROMPT_SUPPORT, host_prompt_do(PROMPT_USER_CONTINUE, PSTR("MMU2 Eject Recover"), CONTINUE_STR));
 | 
			
		||||
    TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired_P(PSTR("MMU2 Eject Recover")));
 | 
			
		||||
    wait_for_user_response();
 | 
			
		||||
    BUZZ(200, 404);
 | 
			
		||||
    BUZZ(200, 404);
 | 
			
		||||
 | 
			
		||||
    command(MMU_CMD_R0);
 | 
			
		||||
    manage_response(false, false);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ui.reset_status();
 | 
			
		||||
 | 
			
		||||
  // no active tool
 | 
			
		||||
  extruder = MMU2_NO_TOOL;
 | 
			
		||||
 | 
			
		||||
  set_runout_valid(false);
 | 
			
		||||
 | 
			
		||||
  BUZZ(200, 404);
 | 
			
		||||
 | 
			
		||||
  DISABLE_AXIS_E0();
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Unload from hotend and retract to MMU
 | 
			
		||||
 */
 | 
			
		||||
bool MMU2::unload() {
 | 
			
		||||
 | 
			
		||||
  if (!enabled) return false;
 | 
			
		||||
 | 
			
		||||
  if (thermalManager.tooColdToExtrude(active_extruder)) {
 | 
			
		||||
    BUZZ(200, 404);
 | 
			
		||||
    LCD_ALERTMESSAGEPGM(MSG_HOTEND_TOO_COLD);
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Switch material and load to nozzle
 | 
			
		||||
   */
 | 
			
		||||
  bool MMU2::load_filament_to_nozzle(const uint8_t index) {
 | 
			
		||||
  filament_ramming();
 | 
			
		||||
 | 
			
		||||
    if (!enabled) return false;
 | 
			
		||||
  command(MMU_CMD_U0);
 | 
			
		||||
  manage_response(false, true);
 | 
			
		||||
 | 
			
		||||
    if (thermalManager.tooColdToExtrude(active_extruder)) {
 | 
			
		||||
      BUZZ(200, 404);
 | 
			
		||||
      LCD_ALERTMESSAGEPGM(MSG_HOTEND_TOO_COLD);
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
  BUZZ(200, 404);
 | 
			
		||||
 | 
			
		||||
    command(MMU_CMD_T0 + index);
 | 
			
		||||
    manage_response(true, true);
 | 
			
		||||
  // no active tool
 | 
			
		||||
  extruder = MMU2_NO_TOOL;
 | 
			
		||||
 | 
			
		||||
    const bool success = load_to_gears();
 | 
			
		||||
    if (success) {
 | 
			
		||||
      mmu_loop();
 | 
			
		||||
      extruder = index;
 | 
			
		||||
      active_extruder = 0;
 | 
			
		||||
      load_to_nozzle();
 | 
			
		||||
      BUZZ(200, 404);
 | 
			
		||||
    }
 | 
			
		||||
    return success;
 | 
			
		||||
  }
 | 
			
		||||
  set_runout_valid(false);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Load filament to nozzle of multimaterial printer
 | 
			
		||||
   *
 | 
			
		||||
   * This function is used only only after T? (user select filament) and M600 (change filament).
 | 
			
		||||
   * It is not used after T0 .. T4 command (select filament), in such case, gcode is responsible for loading
 | 
			
		||||
   * filament to nozzle.
 | 
			
		||||
   */
 | 
			
		||||
  void MMU2::load_to_nozzle() {
 | 
			
		||||
    if (!enabled) return;
 | 
			
		||||
    execute_extruder_sequence((const E_Step *)load_to_nozzle_sequence, COUNT(load_to_nozzle_sequence));
 | 
			
		||||
  }
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
  bool MMU2::eject_filament(const uint8_t index, const bool recover) {
 | 
			
		||||
/**
 | 
			
		||||
 * Unload sequence to optimize shape of the tip of the unloaded filament
 | 
			
		||||
 */
 | 
			
		||||
void MMU2::filament_ramming() {
 | 
			
		||||
  execute_extruder_sequence((const E_Step *)ramming_sequence, sizeof(ramming_sequence) / sizeof(E_Step));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    if (!enabled) return false;
 | 
			
		||||
void MMU2::execute_extruder_sequence(const E_Step * sequence, int steps) {
 | 
			
		||||
 | 
			
		||||
    if (thermalManager.tooColdToExtrude(active_extruder)) {
 | 
			
		||||
      BUZZ(200, 404);
 | 
			
		||||
      LCD_ALERTMESSAGEPGM(MSG_HOTEND_TOO_COLD);
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
  planner.synchronize();
 | 
			
		||||
  ENABLE_AXIS_E0();
 | 
			
		||||
 | 
			
		||||
    LCD_MESSAGEPGM(MSG_MMU2_EJECTING_FILAMENT);
 | 
			
		||||
  const E_Step* step = sequence;
 | 
			
		||||
 | 
			
		||||
    ENABLE_AXIS_E0();
 | 
			
		||||
    current_position.e -= MMU2_FILAMENTCHANGE_EJECT_FEED;
 | 
			
		||||
    line_to_current_position(2500 / 60);
 | 
			
		||||
  LOOP_L_N(i, steps) {
 | 
			
		||||
    const float es = pgm_read_float(&(step->extrude));
 | 
			
		||||
    const feedRate_t fr_mm_m = pgm_read_float(&(step->feedRate));
 | 
			
		||||
 | 
			
		||||
    DEBUG_ECHO_START();
 | 
			
		||||
    DEBUG_ECHOLNPAIR("E step ", es, "/", fr_mm_m);
 | 
			
		||||
 | 
			
		||||
    current_position.e += es;
 | 
			
		||||
    line_to_current_position(MMM_TO_MMS(fr_mm_m));
 | 
			
		||||
    planner.synchronize();
 | 
			
		||||
    command(MMU_CMD_E0 + index);
 | 
			
		||||
    manage_response(false, false);
 | 
			
		||||
 | 
			
		||||
    if (recover)  {
 | 
			
		||||
      LCD_MESSAGEPGM(MSG_MMU2_EJECT_RECOVER);
 | 
			
		||||
      BUZZ(200, 404);
 | 
			
		||||
      TERN_(HOST_PROMPT_SUPPORT, host_prompt_do(PROMPT_USER_CONTINUE, PSTR("MMU2 Eject Recover"), CONTINUE_STR));
 | 
			
		||||
      TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired_P(PSTR("MMU2 Eject Recover")));
 | 
			
		||||
      wait_for_user_response();
 | 
			
		||||
      BUZZ(200, 404);
 | 
			
		||||
      BUZZ(200, 404);
 | 
			
		||||
 | 
			
		||||
      command(MMU_CMD_R0);
 | 
			
		||||
      manage_response(false, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ui.reset_status();
 | 
			
		||||
 | 
			
		||||
    // no active tool
 | 
			
		||||
    extruder = MMU2_NO_TOOL;
 | 
			
		||||
 | 
			
		||||
    set_runout_valid(false);
 | 
			
		||||
 | 
			
		||||
    BUZZ(200, 404);
 | 
			
		||||
 | 
			
		||||
    DISABLE_AXIS_E0();
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
    step++;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Unload from hotend and retract to MMU
 | 
			
		||||
   */
 | 
			
		||||
  bool MMU2::unload() {
 | 
			
		||||
  DISABLE_AXIS_E0();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    if (!enabled) return false;
 | 
			
		||||
 | 
			
		||||
    if (thermalManager.tooColdToExtrude(active_extruder)) {
 | 
			
		||||
      BUZZ(200, 404);
 | 
			
		||||
      LCD_ALERTMESSAGEPGM(MSG_HOTEND_TOO_COLD);
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    filament_ramming();
 | 
			
		||||
 | 
			
		||||
    command(MMU_CMD_U0);
 | 
			
		||||
    manage_response(false, true);
 | 
			
		||||
 | 
			
		||||
    BUZZ(200, 404);
 | 
			
		||||
 | 
			
		||||
    // no active tool
 | 
			
		||||
    extruder = MMU2_NO_TOOL;
 | 
			
		||||
 | 
			
		||||
    set_runout_valid(false);
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Unload sequence to optimize shape of the tip of the unloaded filament
 | 
			
		||||
   */
 | 
			
		||||
  void MMU2::filament_ramming() {
 | 
			
		||||
    execute_extruder_sequence((const E_Step *)ramming_sequence, sizeof(ramming_sequence) / sizeof(E_Step));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void MMU2::execute_extruder_sequence(const E_Step * sequence, int steps) {
 | 
			
		||||
 | 
			
		||||
    planner.synchronize();
 | 
			
		||||
    ENABLE_AXIS_E0();
 | 
			
		||||
 | 
			
		||||
    const E_Step* step = sequence;
 | 
			
		||||
 | 
			
		||||
    LOOP_L_N(i, steps) {
 | 
			
		||||
      const float es = pgm_read_float(&(step->extrude));
 | 
			
		||||
      const feedRate_t fr_mm_m = pgm_read_float(&(step->feedRate));
 | 
			
		||||
 | 
			
		||||
      DEBUG_ECHO_START();
 | 
			
		||||
      DEBUG_ECHOLNPAIR("E step ", es, "/", fr_mm_m);
 | 
			
		||||
 | 
			
		||||
      current_position.e += es;
 | 
			
		||||
      line_to_current_position(MMM_TO_MMS(fr_mm_m));
 | 
			
		||||
      planner.synchronize();
 | 
			
		||||
 | 
			
		||||
      step++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    DISABLE_AXIS_E0();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
#endif // HAS_LCD_MENU && MMU2_MENUS
 | 
			
		||||
 | 
			
		||||
#endif // PRUSA_MMU2
 | 
			
		||||
#endif // HAS_PRUSA_MMU2
 | 
			
		||||
@@ -49,13 +49,11 @@ public:
 | 
			
		||||
  static uint8_t get_current_tool();
 | 
			
		||||
  static void set_filament_type(const uint8_t index, const uint8_t type);
 | 
			
		||||
 | 
			
		||||
  #if BOTH(HAS_LCD_MENU, MMU2_MENUS)
 | 
			
		||||
    static bool unload();
 | 
			
		||||
    static void load_filament(uint8_t);
 | 
			
		||||
    static void load_all();
 | 
			
		||||
    static bool load_filament_to_nozzle(const uint8_t index);
 | 
			
		||||
    static bool eject_filament(const uint8_t index, const bool recover);
 | 
			
		||||
  #endif
 | 
			
		||||
  static bool unload();
 | 
			
		||||
  static void load_filament(uint8_t);
 | 
			
		||||
  static void load_all();
 | 
			
		||||
  static bool load_filament_to_nozzle(const uint8_t index);
 | 
			
		||||
  static bool eject_filament(const uint8_t index, const bool recover);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
  static bool rx_str_P(const char* str);
 | 
			
		||||
@@ -72,15 +70,13 @@ private:
 | 
			
		||||
  static bool get_response();
 | 
			
		||||
  static void manage_response(const bool move_axes, const bool turn_off_nozzle);
 | 
			
		||||
 | 
			
		||||
  #if BOTH(HAS_LCD_MENU, MMU2_MENUS)
 | 
			
		||||
    static void load_to_nozzle();
 | 
			
		||||
    static void filament_ramming();
 | 
			
		||||
    static void execute_extruder_sequence(const E_Step * sequence, int steps);
 | 
			
		||||
  #endif
 | 
			
		||||
  static void load_to_nozzle();
 | 
			
		||||
  static void filament_ramming();
 | 
			
		||||
  static void execute_extruder_sequence(const E_Step * sequence, int steps);
 | 
			
		||||
 | 
			
		||||
  static void filament_runout();
 | 
			
		||||
 | 
			
		||||
  #if ENABLED(PRUSA_MMU2_S_MODE)
 | 
			
		||||
  #if HAS_PRUSA_MMU2S
 | 
			
		||||
    static bool mmu2s_triggered;
 | 
			
		||||
    static void check_filament();
 | 
			
		||||
    static bool can_load();
 | 
			
		||||
@@ -31,13 +31,13 @@
 | 
			
		||||
 *
 | 
			
		||||
 * Report the current speed percentage factor if no parameter is specified
 | 
			
		||||
 *
 | 
			
		||||
 * With PRUSA_MMU2...
 | 
			
		||||
 * For MMU2 and MMU2S devices...
 | 
			
		||||
 *   B : Flag to back up the current factor
 | 
			
		||||
 *   R : Flag to restore the last-saved factor
 | 
			
		||||
 */
 | 
			
		||||
void GcodeSuite::M220() {
 | 
			
		||||
 | 
			
		||||
  #if ENABLED(PRUSA_MMU2)
 | 
			
		||||
  #if HAS_PRUSA_MMU2
 | 
			
		||||
    static int16_t backup_feedrate_percentage = 100;
 | 
			
		||||
    if (parser.seen('B')) backup_feedrate_percentage = feedrate_percentage;
 | 
			
		||||
    if (parser.seen('R')) feedrate_percentage = backup_feedrate_percentage;
 | 
			
		||||
 
 | 
			
		||||
@@ -27,8 +27,8 @@
 | 
			
		||||
  #include "../../module/motion.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if ENABLED(PRUSA_MMU2)
 | 
			
		||||
  #include "../../feature/mmu2/mmu2.h"
 | 
			
		||||
#if HAS_PRUSA_MMU2
 | 
			
		||||
  #include "../../feature/mmu/mmu2.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define DEBUG_OUT ENABLED(DEBUG_LEVELING_FEATURE)
 | 
			
		||||
@@ -40,7 +40,7 @@
 | 
			
		||||
 *   F[units/min] Set the movement feedrate
 | 
			
		||||
 *   S1           Don't move the tool in XY after change
 | 
			
		||||
 *
 | 
			
		||||
 * For PRUSA_MMU2:
 | 
			
		||||
 * For PRUSA_MMU2(S) and SMUFF_EMU_MMU2(S)
 | 
			
		||||
 *   T[n] Gcode to extrude at least 38.10 mm at feedrate 19.02 mm/s must follow immediately to load to extruder wheels.
 | 
			
		||||
 *   T?   Gcode to extrude shouldn't have to follow. Load to extruder wheels is done automatically.
 | 
			
		||||
 *   Tx   Same as T?, but nozzle doesn't have to be preheated. Tc requires a preheated nozzle to finish filament load.
 | 
			
		||||
@@ -54,7 +54,7 @@ void GcodeSuite::T(const int8_t tool_index) {
 | 
			
		||||
  // Count this command as movement / activity
 | 
			
		||||
  reset_stepper_timeout();
 | 
			
		||||
 | 
			
		||||
  #if ENABLED(PRUSA_MMU2)
 | 
			
		||||
  #if HAS_PRUSA_MMU2
 | 
			
		||||
    if (parser.string_arg) {
 | 
			
		||||
      mmu2.tool_change(parser.string_arg);   // Special commands T?/Tx/Tc
 | 
			
		||||
      return;
 | 
			
		||||
 
 | 
			
		||||
@@ -38,8 +38,8 @@
 | 
			
		||||
  #include "../../../lcd/marlinui.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if ENABLED(PRUSA_MMU2)
 | 
			
		||||
  #include "../../../feature/mmu2/mmu2.h"
 | 
			
		||||
#if HAS_PRUSA_MMU2
 | 
			
		||||
  #include "../../../feature/mmu/mmu2.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if ENABLED(MIXING_EXTRUDER)
 | 
			
		||||
@@ -86,7 +86,7 @@ void GcodeSuite::M701() {
 | 
			
		||||
  // Show initial "wait for load" message
 | 
			
		||||
  TERN_(HAS_LCD_MENU, lcd_pause_show_message(PAUSE_MESSAGE_LOAD, PAUSE_MODE_LOAD_FILAMENT, target_extruder));
 | 
			
		||||
 | 
			
		||||
  #if HAS_MULTI_EXTRUDER && DISABLED(PRUSA_MMU2)
 | 
			
		||||
  #if HAS_MULTI_EXTRUDER && (HAS_PRUSA_MMU1 || !HAS_MMU)
 | 
			
		||||
    // Change toolhead if specified
 | 
			
		||||
    uint8_t active_extruder_before_filament_change = active_extruder;
 | 
			
		||||
    if (active_extruder != target_extruder)
 | 
			
		||||
@@ -98,7 +98,7 @@ void GcodeSuite::M701() {
 | 
			
		||||
    do_blocking_move_to_z(_MIN(current_position.z + park_point.z, Z_MAX_POS), feedRate_t(NOZZLE_PARK_Z_FEEDRATE));
 | 
			
		||||
 | 
			
		||||
  // Load filament
 | 
			
		||||
  #if ENABLED(PRUSA_MMU2)
 | 
			
		||||
  #if HAS_PRUSA_MMU2
 | 
			
		||||
    mmu2.load_filament_to_nozzle(target_extruder);
 | 
			
		||||
  #else
 | 
			
		||||
    constexpr float     purge_length = ADVANCED_PAUSE_PURGE_LENGTH,
 | 
			
		||||
@@ -121,7 +121,7 @@ void GcodeSuite::M701() {
 | 
			
		||||
  if (park_point.z > 0)
 | 
			
		||||
    do_blocking_move_to_z(_MAX(current_position.z - park_point.z, 0), feedRate_t(NOZZLE_PARK_Z_FEEDRATE));
 | 
			
		||||
 | 
			
		||||
  #if HAS_MULTI_EXTRUDER && DISABLED(PRUSA_MMU2)
 | 
			
		||||
  #if HAS_MULTI_EXTRUDER && (HAS_PRUSA_MMU1 || !HAS_MMU)
 | 
			
		||||
    // Restore toolhead if it was changed
 | 
			
		||||
    if (active_extruder_before_filament_change != active_extruder)
 | 
			
		||||
      tool_change(active_extruder_before_filament_change, false);
 | 
			
		||||
@@ -186,7 +186,7 @@ void GcodeSuite::M702() {
 | 
			
		||||
  // Show initial "wait for unload" message
 | 
			
		||||
  TERN_(HAS_LCD_MENU, lcd_pause_show_message(PAUSE_MESSAGE_UNLOAD, PAUSE_MODE_UNLOAD_FILAMENT, target_extruder));
 | 
			
		||||
 | 
			
		||||
  #if HAS_MULTI_EXTRUDER && DISABLED(PRUSA_MMU2)
 | 
			
		||||
  #if HAS_MULTI_EXTRUDER && (HAS_PRUSA_MMU1 || !HAS_MMU)
 | 
			
		||||
    // Change toolhead if specified
 | 
			
		||||
    uint8_t active_extruder_before_filament_change = active_extruder;
 | 
			
		||||
    if (active_extruder != target_extruder)
 | 
			
		||||
@@ -198,7 +198,7 @@ void GcodeSuite::M702() {
 | 
			
		||||
    do_blocking_move_to_z(_MIN(current_position.z + park_point.z, Z_MAX_POS), feedRate_t(NOZZLE_PARK_Z_FEEDRATE));
 | 
			
		||||
 | 
			
		||||
  // Unload filament
 | 
			
		||||
  #if ENABLED(PRUSA_MMU2)
 | 
			
		||||
  #if HAS_PRUSA_MMU2
 | 
			
		||||
    mmu2.unload();
 | 
			
		||||
  #else
 | 
			
		||||
    #if BOTH(HAS_MULTI_EXTRUDER, FILAMENT_UNLOAD_ALL_EXTRUDERS)
 | 
			
		||||
@@ -227,7 +227,7 @@ void GcodeSuite::M702() {
 | 
			
		||||
  if (park_point.z > 0)
 | 
			
		||||
    do_blocking_move_to_z(_MAX(current_position.z - park_point.z, 0), feedRate_t(NOZZLE_PARK_Z_FEEDRATE));
 | 
			
		||||
 | 
			
		||||
  #if HAS_MULTI_EXTRUDER && DISABLED(PRUSA_MMU2)
 | 
			
		||||
  #if HAS_MULTI_EXTRUDER && (HAS_PRUSA_MMU1 || !HAS_MMU)
 | 
			
		||||
    // Restore toolhead if it was changed
 | 
			
		||||
    if (active_extruder_before_filament_change != active_extruder)
 | 
			
		||||
      tool_change(active_extruder_before_filament_change, false);
 | 
			
		||||
 
 | 
			
		||||
@@ -22,10 +22,10 @@
 | 
			
		||||
 | 
			
		||||
#include "../../../inc/MarlinConfigPre.h"
 | 
			
		||||
 | 
			
		||||
#if ENABLED(PRUSA_MMU2)
 | 
			
		||||
#if HAS_PRUSA_MMU2
 | 
			
		||||
 | 
			
		||||
#include "../../gcode.h"
 | 
			
		||||
#include "../../../feature/mmu2/mmu2.h"
 | 
			
		||||
#include "../../../feature/mmu/mmu2.h"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * M403: Set filament type for MMU2
 | 
			
		||||
@@ -46,4 +46,4 @@ void GcodeSuite::M403() {
 | 
			
		||||
    SERIAL_ECHO_MSG("M403 - bad arguments.");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif // PRUSA_MMU2
 | 
			
		||||
#endif // HAS_PRUSA_MMU2
 | 
			
		||||
 
 | 
			
		||||
@@ -702,7 +702,7 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
 | 
			
		||||
        case 402: M402(); break;                                  // M402: Stow probe
 | 
			
		||||
      #endif
 | 
			
		||||
 | 
			
		||||
      #if ENABLED(PRUSA_MMU2)
 | 
			
		||||
      #if HAS_PRUSA_MMU2
 | 
			
		||||
        case 403: M403(); break;
 | 
			
		||||
      #endif
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -181,7 +181,7 @@
 | 
			
		||||
 * M217 - Set filament swap parameters: "M217 S<length> P<feedrate> R<feedrate>". (Requires SINGLENOZZLE)
 | 
			
		||||
 * M218 - Set/get a tool offset: "M218 T<index> X<offset> Y<offset>". (Requires 2 or more extruders)
 | 
			
		||||
 * M220 - Set Feedrate Percentage: "M220 S<percent>" (i.e., "FR" on the LCD)
 | 
			
		||||
 *        Use "M220 B" to back up the Feedrate Percentage and "M220 R" to restore it. (Requires PRUSA_MMU2)
 | 
			
		||||
 *        Use "M220 B" to back up the Feedrate Percentage and "M220 R" to restore it. (Requires an MMU_MODEL version 2 or 2S)
 | 
			
		||||
 * M221 - Set Flow Percentage: "M221 S<percent>"
 | 
			
		||||
 * M226 - Wait until a pin is in a given state: "M226 P<pin> S<state>" (Requires DIRECT_PIN_CONTROL)
 | 
			
		||||
 * M240 - Trigger a camera to take a photograph. (Requires PHOTO_GCODE)
 | 
			
		||||
@@ -735,7 +735,7 @@ private:
 | 
			
		||||
    static void M402();
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
  TERN_(PRUSA_MMU2, static void M403());
 | 
			
		||||
  TERN_(HAS_PRUSA_MMU2, static void M403());
 | 
			
		||||
 | 
			
		||||
  #if ENABLED(FILAMENT_WIDTH_SENSOR)
 | 
			
		||||
    static void M404();
 | 
			
		||||
 
 | 
			
		||||
@@ -155,7 +155,7 @@ void GCodeParser::parse(char *p) {
 | 
			
		||||
      // Skip spaces to get the numeric part
 | 
			
		||||
      while (*p == ' ') p++;
 | 
			
		||||
 | 
			
		||||
      #if ENABLED(PRUSA_MMU2)
 | 
			
		||||
      #if HAS_PRUSA_MMU2
 | 
			
		||||
        if (letter == 'T') {
 | 
			
		||||
          // check for special MMU2 T?/Tx/Tc commands
 | 
			
		||||
          if (*p == '?' || *p == 'x' || *p == 'c') {
 | 
			
		||||
 
 | 
			
		||||
@@ -495,6 +495,36 @@
 | 
			
		||||
  #endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Multi-Material-Unit supported models
 | 
			
		||||
 */
 | 
			
		||||
#define PRUSA_MMU1      1
 | 
			
		||||
#define PRUSA_MMU2      2
 | 
			
		||||
#define PRUSA_MMU2S     3
 | 
			
		||||
#define SMUFF_EMU_MMU2  12
 | 
			
		||||
#define SMUFF_EMU_MMU2S 13
 | 
			
		||||
 | 
			
		||||
#ifdef MMU_MODEL
 | 
			
		||||
  #define HAS_MMU 1
 | 
			
		||||
  #if MMU_MODEL == PRUSA_MMU1
 | 
			
		||||
    #define HAS_PRUSA_MMU1 1
 | 
			
		||||
  #elif MMU_MODEL % 10 == PRUSA_MMU2
 | 
			
		||||
    #define HAS_PRUSA_MMU2 1
 | 
			
		||||
  #elif MMU_MODEL % 10 == PRUSA_MMU2S
 | 
			
		||||
    #define HAS_PRUSA_MMU2 1
 | 
			
		||||
    #define HAS_PRUSA_MMU2S 1
 | 
			
		||||
  #endif
 | 
			
		||||
  #if MMU_MODEL >= SMUFF_EMU_MMU2
 | 
			
		||||
    #define HAS_SMUFF 1
 | 
			
		||||
  #endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#undef PRUSA_MMU1
 | 
			
		||||
#undef PRUSA_MMU2
 | 
			
		||||
#undef PRUSA_MMU2S
 | 
			
		||||
#undef SMUFF_EMU_MMU2
 | 
			
		||||
#undef SMUFF_EMU_MMU2S
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Extruders have some combination of stepper motors and hotends
 | 
			
		||||
 * so we separate these concepts into the defines:
 | 
			
		||||
@@ -512,8 +542,6 @@
 | 
			
		||||
  #undef SWITCHING_EXTRUDER
 | 
			
		||||
  #undef SWITCHING_NOZZLE
 | 
			
		||||
  #undef MIXING_EXTRUDER
 | 
			
		||||
  #undef MK2_MULTIPLEXER
 | 
			
		||||
  #undef PRUSA_MMU2
 | 
			
		||||
  #undef HOTEND_IDLE_TIMEOUT
 | 
			
		||||
#elif EXTRUDERS > 1
 | 
			
		||||
  #define HAS_MULTI_EXTRUDER 1
 | 
			
		||||
@@ -539,17 +567,17 @@
 | 
			
		||||
#elif ENABLED(SWITCHING_TOOLHEAD)
 | 
			
		||||
  #define E_STEPPERS      EXTRUDERS
 | 
			
		||||
  #define E_MANUAL        EXTRUDERS
 | 
			
		||||
#elif ENABLED(PRUSA_MMU2)
 | 
			
		||||
#elif HAS_PRUSA_MMU2
 | 
			
		||||
  #define E_STEPPERS 1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// No inactive extruders with MK2_MULTIPLEXER or SWITCHING_NOZZLE
 | 
			
		||||
#if EITHER(MK2_MULTIPLEXER, SWITCHING_NOZZLE)
 | 
			
		||||
// No inactive extruders with SWITCHING_NOZZLE or Průša MMU1
 | 
			
		||||
#if ENABLED(SWITCHING_NOZZLE) || HAS_PRUSA_MMU1
 | 
			
		||||
  #undef DISABLE_INACTIVE_EXTRUDER
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// Průša MK2 Multiplexer and MMU 2.0 force SINGLENOZZLE
 | 
			
		||||
#if EITHER(MK2_MULTIPLEXER, PRUSA_MMU2)
 | 
			
		||||
// Průša MMU1, MMU 2.0, MMUS 2.0 and SMUFF force SINGLENOZZLE
 | 
			
		||||
#if HAS_MMU
 | 
			
		||||
  #define SINGLENOZZLE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -804,7 +804,11 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS
 | 
			
		||||
  #if !PIN_EXISTS(FIL_RUNOUT)
 | 
			
		||||
    #error "FILAMENT_RUNOUT_SENSOR requires FIL_RUNOUT_PIN."
 | 
			
		||||
  #elif NUM_RUNOUT_SENSORS > E_STEPPERS
 | 
			
		||||
    #error "NUM_RUNOUT_SENSORS cannot exceed the number of E steppers."
 | 
			
		||||
    #if HAS_PRUSA_MMU2
 | 
			
		||||
      #error "NUM_RUNOUT_SENSORS must be 1 with MMU2 / MMU2S."
 | 
			
		||||
    #else
 | 
			
		||||
      #error "NUM_RUNOUT_SENSORS cannot exceed the number of E steppers."
 | 
			
		||||
    #endif
 | 
			
		||||
  #elif NUM_RUNOUT_SENSORS >= 2 && !PIN_EXISTS(FIL_RUNOUT2)
 | 
			
		||||
    #error "FIL_RUNOUT2_PIN is required with NUM_RUNOUT_SENSORS >= 2."
 | 
			
		||||
  #elif NUM_RUNOUT_SENSORS >= 3 && !PIN_EXISTS(FIL_RUNOUT3)
 | 
			
		||||
@@ -867,6 +871,42 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS
 | 
			
		||||
  #error "INDIVIDUAL_AXIS_HOMING_MENU is incompatible with DELTA kinematics."
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Sanity checking for all Průša MMU
 | 
			
		||||
 */
 | 
			
		||||
#ifdef SNMM
 | 
			
		||||
  #error "SNMM is obsolete. Define MMU_MODEL as PRUSA_MMU1 instead."
 | 
			
		||||
#elif ENABLED(MK2_MULTIPLEXER)
 | 
			
		||||
  #error "MK2_MULTIPLEXER is obsolete. Define MMU_MODEL as PRUSA_MMU1 instead."
 | 
			
		||||
#elif ENABLED(PRUSA_MMU2)
 | 
			
		||||
  #error "PRUSA_MMU2 is obsolete. Define MMU_MODEL as PRUSA_MMU2 instead."
 | 
			
		||||
#elif ENABLED(PRUSA_MMU2_S_MODE)
 | 
			
		||||
  #error "PRUSA_MMU2_S_MODE is obsolete. Define MMU_MODEL as PRUSA_MMU2S instead."
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Multi-Material-Unit 2 / SMUFF requirements
 | 
			
		||||
 */
 | 
			
		||||
#if HAS_PRUSA_MMU2
 | 
			
		||||
  #if EXTRUDERS != 5
 | 
			
		||||
    #undef SINGLENOZZLE
 | 
			
		||||
    #error "PRUSA_MMU2(S) requires exactly 5 EXTRUDERS. Please update your Configuration."
 | 
			
		||||
  #elif DISABLED(NOZZLE_PARK_FEATURE)
 | 
			
		||||
    #error "PRUSA_MMU2(S) requires NOZZLE_PARK_FEATURE. Enable it to continue."
 | 
			
		||||
  #elif HAS_PRUSA_MMU2S && DISABLED(FILAMENT_RUNOUT_SENSOR)
 | 
			
		||||
    #error "PRUSA_MMU2S requires FILAMENT_RUNOUT_SENSOR. Enable it to continue."
 | 
			
		||||
  #elif ENABLED(MMU_EXTRUDER_SENSOR) && DISABLED(FILAMENT_RUNOUT_SENSOR)
 | 
			
		||||
    #error "MMU_EXTRUDER_SENSOR requires FILAMENT_RUNOUT_SENSOR. Enable it to continue."
 | 
			
		||||
  #elif ENABLED(MMU_EXTRUDER_SENSOR) && !HAS_LCD_MENU
 | 
			
		||||
    #error "MMU_EXTRUDER_SENSOR requires an LCD supporting MarlinUI to be enabled."
 | 
			
		||||
  #elif DISABLED(ADVANCED_PAUSE_FEATURE)
 | 
			
		||||
    static_assert(nullptr == strstr(MMU2_FILAMENT_RUNOUT_SCRIPT, "M600"), "ADVANCED_PAUSE_FEATURE is required to use M600 with PRUSA_MMU2(S) / SMUFF_EMU_MMU2(S).");
 | 
			
		||||
  #endif
 | 
			
		||||
#endif
 | 
			
		||||
#if HAS_SMUFF && EXTRUDERS > 12
 | 
			
		||||
  #error "Too many extruders for SMUFF_EMU_MMU2(S). (12 maximum)."
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Options only for EXTRUDERS > 1
 | 
			
		||||
 */
 | 
			
		||||
@@ -902,17 +942,14 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS
 | 
			
		||||
    #error "TOOLCHANGE_ZRAISE required for EXTRUDERS > 1."
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
#elif ENABLED(MK2_MULTIPLEXER)
 | 
			
		||||
  #error "MK2_MULTIPLEXER requires 2 or more EXTRUDERS."
 | 
			
		||||
#elif ENABLED(SINGLENOZZLE)
 | 
			
		||||
  #error "SINGLENOZZLE requires 2 or more EXTRUDERS."
 | 
			
		||||
#endif
 | 
			
		||||
#elif HAS_PRUSA_MMU1 || HAS_SMUFF
 | 
			
		||||
 | 
			
		||||
  #error "Multi-Material-Unit requires 2 or more EXTRUDERS."
 | 
			
		||||
 | 
			
		||||
#elif ENABLED(SINGLENOZZLE)
 | 
			
		||||
 | 
			
		||||
  #error "SINGLENOZZLE requires 2 or more EXTRUDERS."
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Sanity checking for the Průša MK2 Multiplexer
 | 
			
		||||
 */
 | 
			
		||||
#ifdef SNMM
 | 
			
		||||
  #error "SNMM is now MK2_MULTIPLEXER."
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -1870,48 +1907,46 @@ static_assert(hbm[Z_AXIS] >= 0, "HOMING_BUMP_MM.Z must be greater than or equal
 | 
			
		||||
/**
 | 
			
		||||
 * Test Extruder Stepper Pins
 | 
			
		||||
 */
 | 
			
		||||
#if DISABLED(MK2_MULTIPLEXER) // MK2_MULTIPLEXER uses E0 stepper only
 | 
			
		||||
  #if E_STEPPERS
 | 
			
		||||
    #if !(PINS_EXIST(E0_STEP, E0_DIR) && HAS_E0_ENABLE)
 | 
			
		||||
      #error "E0_STEP_PIN, E0_DIR_PIN, or E0_ENABLE_PIN not defined for this board."
 | 
			
		||||
#if E_STEPPERS
 | 
			
		||||
  #if !(PINS_EXIST(E0_STEP, E0_DIR) && HAS_E0_ENABLE)
 | 
			
		||||
    #error "E0_STEP_PIN, E0_DIR_PIN, or E0_ENABLE_PIN not defined for this board."
 | 
			
		||||
  #endif
 | 
			
		||||
  #if E_STEPPERS > 1
 | 
			
		||||
    #if !(PINS_EXIST(E1_STEP, E1_DIR) && HAS_E1_ENABLE)
 | 
			
		||||
      #error "E1_STEP_PIN, E1_DIR_PIN, or E1_ENABLE_PIN not defined for this board."
 | 
			
		||||
    #endif
 | 
			
		||||
    #if E_STEPPERS > 1
 | 
			
		||||
      #if !(PINS_EXIST(E1_STEP, E1_DIR) && HAS_E1_ENABLE)
 | 
			
		||||
        #error "E1_STEP_PIN, E1_DIR_PIN, or E1_ENABLE_PIN not defined for this board."
 | 
			
		||||
    #if E_STEPPERS > 2
 | 
			
		||||
      #if !(PINS_EXIST(E2_STEP, E2_DIR) && HAS_E2_ENABLE)
 | 
			
		||||
        #error "E2_STEP_PIN, E2_DIR_PIN, or E2_ENABLE_PIN not defined for this board."
 | 
			
		||||
      #endif
 | 
			
		||||
      #if E_STEPPERS > 2
 | 
			
		||||
        #if !(PINS_EXIST(E2_STEP, E2_DIR) && HAS_E2_ENABLE)
 | 
			
		||||
          #error "E2_STEP_PIN, E2_DIR_PIN, or E2_ENABLE_PIN not defined for this board."
 | 
			
		||||
      #if E_STEPPERS > 3
 | 
			
		||||
        #if !(PINS_EXIST(E3_STEP, E3_DIR) && HAS_E3_ENABLE)
 | 
			
		||||
          #error "E3_STEP_PIN, E3_DIR_PIN, or E3_ENABLE_PIN not defined for this board."
 | 
			
		||||
        #endif
 | 
			
		||||
        #if E_STEPPERS > 3
 | 
			
		||||
          #if !(PINS_EXIST(E3_STEP, E3_DIR) && HAS_E3_ENABLE)
 | 
			
		||||
            #error "E3_STEP_PIN, E3_DIR_PIN, or E3_ENABLE_PIN not defined for this board."
 | 
			
		||||
        #if E_STEPPERS > 4
 | 
			
		||||
          #if !(PINS_EXIST(E4_STEP, E4_DIR) && HAS_E4_ENABLE)
 | 
			
		||||
            #error "E4_STEP_PIN, E4_DIR_PIN, or E4_ENABLE_PIN not defined for this board."
 | 
			
		||||
          #endif
 | 
			
		||||
          #if E_STEPPERS > 4
 | 
			
		||||
            #if !(PINS_EXIST(E4_STEP, E4_DIR) && HAS_E4_ENABLE)
 | 
			
		||||
              #error "E4_STEP_PIN, E4_DIR_PIN, or E4_ENABLE_PIN not defined for this board."
 | 
			
		||||
          #if E_STEPPERS > 5
 | 
			
		||||
            #if !(PINS_EXIST(E5_STEP, E5_DIR) && HAS_E5_ENABLE)
 | 
			
		||||
              #error "E5_STEP_PIN, E5_DIR_PIN, or E5_ENABLE_PIN not defined for this board."
 | 
			
		||||
            #endif
 | 
			
		||||
            #if E_STEPPERS > 5
 | 
			
		||||
              #if !(PINS_EXIST(E5_STEP, E5_DIR) && HAS_E5_ENABLE)
 | 
			
		||||
                #error "E5_STEP_PIN, E5_DIR_PIN, or E5_ENABLE_PIN not defined for this board."
 | 
			
		||||
            #if E_STEPPERS > 6
 | 
			
		||||
              #if !(PINS_EXIST(E6_STEP, E6_DIR) && HAS_E6_ENABLE)
 | 
			
		||||
                #error "E6_STEP_PIN, E6_DIR_PIN, or E6_ENABLE_PIN not defined for this board."
 | 
			
		||||
              #endif
 | 
			
		||||
              #if E_STEPPERS > 6
 | 
			
		||||
                #if !(PINS_EXIST(E6_STEP, E6_DIR) && HAS_E6_ENABLE)
 | 
			
		||||
                  #error "E6_STEP_PIN, E6_DIR_PIN, or E6_ENABLE_PIN not defined for this board."
 | 
			
		||||
              #if E_STEPPERS > 7
 | 
			
		||||
                #if !(PINS_EXIST(E7_STEP, E7_DIR) && HAS_E7_ENABLE)
 | 
			
		||||
                  #error "E7_STEP_PIN, E7_DIR_PIN, or E7_ENABLE_PIN not defined for this board."
 | 
			
		||||
                #endif
 | 
			
		||||
                #if E_STEPPERS > 7
 | 
			
		||||
                  #if !(PINS_EXIST(E7_STEP, E7_DIR) && HAS_E7_ENABLE)
 | 
			
		||||
                    #error "E7_STEP_PIN, E7_DIR_PIN, or E7_ENABLE_PIN not defined for this board."
 | 
			
		||||
                  #endif
 | 
			
		||||
                #endif // E_STEPPERS > 7
 | 
			
		||||
              #endif // E_STEPPERS > 6
 | 
			
		||||
            #endif // E_STEPPERS > 5
 | 
			
		||||
          #endif // E_STEPPERS > 4
 | 
			
		||||
        #endif // E_STEPPERS > 3
 | 
			
		||||
      #endif // E_STEPPERS > 2
 | 
			
		||||
    #endif // E_STEPPERS > 1
 | 
			
		||||
  #endif // E_STEPPERS
 | 
			
		||||
#endif
 | 
			
		||||
              #endif // E_STEPPERS > 7
 | 
			
		||||
            #endif // E_STEPPERS > 6
 | 
			
		||||
          #endif // E_STEPPERS > 5
 | 
			
		||||
        #endif // E_STEPPERS > 4
 | 
			
		||||
      #endif // E_STEPPERS > 3
 | 
			
		||||
    #endif // E_STEPPERS > 2
 | 
			
		||||
  #endif // E_STEPPERS > 1
 | 
			
		||||
#endif // E_STEPPERS
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Endstop Tests
 | 
			
		||||
@@ -2977,23 +3012,6 @@ static_assert(   _ARR_TEST(3,0) && _ARR_TEST(3,1) && _ARR_TEST(3,2)
 | 
			
		||||
  #endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Průša MMU2 requirements
 | 
			
		||||
 */
 | 
			
		||||
#if ENABLED(PRUSA_MMU2)
 | 
			
		||||
  #if EXTRUDERS != 5
 | 
			
		||||
    #error "PRUSA_MMU2 requires EXTRUDERS = 5."
 | 
			
		||||
  #elif DISABLED(NOZZLE_PARK_FEATURE)
 | 
			
		||||
    #error "PRUSA_MMU2 requires NOZZLE_PARK_FEATURE. Enable it to continue."
 | 
			
		||||
  #elif EITHER(PRUSA_MMU2_S_MODE, MMU_EXTRUDER_SENSOR) && DISABLED(FILAMENT_RUNOUT_SENSOR)
 | 
			
		||||
    #error "PRUSA_MMU2_S_MODE or MMU_EXTRUDER_SENSOR requires FILAMENT_RUNOUT_SENSOR. Enable it to continue."
 | 
			
		||||
  #elif BOTH(PRUSA_MMU2_S_MODE, MMU_EXTRUDER_SENSOR)
 | 
			
		||||
    #error "Enable only one of PRUSA_MMU2_S_MODE or MMU_EXTRUDER_SENSOR."
 | 
			
		||||
  #elif DISABLED(ADVANCED_PAUSE_FEATURE)
 | 
			
		||||
    static_assert(nullptr == strstr(MMU2_FILAMENT_RUNOUT_SCRIPT, "M600"), "ADVANCED_PAUSE_FEATURE is required to use M600 with PRUSA_MMU2.");
 | 
			
		||||
  #endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Advanced PRINTCOUNTER settings
 | 
			
		||||
 */
 | 
			
		||||
 
 | 
			
		||||
@@ -46,7 +46,7 @@
 | 
			
		||||
  #define MACHINE_CAN_PAUSE 1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if ENABLED(PRUSA_MMU2)
 | 
			
		||||
#if ENABLED(MMU2_MENUS)
 | 
			
		||||
  #include "../../lcd/menu/menu_mmu2.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -24,13 +24,10 @@
 | 
			
		||||
 | 
			
		||||
#if BOTH(HAS_LCD_MENU, MMU2_MENUS)
 | 
			
		||||
 | 
			
		||||
#include "../../feature/mmu2/mmu2.h"
 | 
			
		||||
#include "../../feature/mmu/mmu2.h"
 | 
			
		||||
#include "menu_mmu2.h"
 | 
			
		||||
#include "menu_item.h"
 | 
			
		||||
 | 
			
		||||
uint8_t currentTool;
 | 
			
		||||
bool mmuMenuWait;
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// Load Filament
 | 
			
		||||
//
 | 
			
		||||
@@ -123,9 +120,12 @@ void menu_mmu2() {
 | 
			
		||||
// T* Choose Filament
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
inline void action_mmu2_choose(const uint8_t tool) {
 | 
			
		||||
  currentTool = tool;
 | 
			
		||||
  mmuMenuWait = false;
 | 
			
		||||
uint8_t feeder_index;
 | 
			
		||||
bool wait_for_mmu_menu;
 | 
			
		||||
 | 
			
		||||
inline void action_mmu2_chosen(const uint8_t index) {
 | 
			
		||||
  feeder_index = index;
 | 
			
		||||
  wait_for_mmu_menu = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void menu_mmu2_choose_filament() {
 | 
			
		||||
@@ -133,7 +133,7 @@ void menu_mmu2_choose_filament() {
 | 
			
		||||
  #if LCD_HEIGHT > 2
 | 
			
		||||
    STATIC_ITEM(MSG_MMU2_CHOOSE_FILAMENT_HEADER, SS_DEFAULT|SS_INVERT);
 | 
			
		||||
  #endif
 | 
			
		||||
  LOOP_L_N(i, 5) ACTION_ITEM_N(i, MSG_MMU2_FILAMENT_N, []{ action_mmu2_choose(MenuItemBase::itemIndex); });
 | 
			
		||||
  LOOP_L_N(i, 5) ACTION_ITEM_N(i, MSG_MMU2_FILAMENT_N, []{ action_mmu2_chosen(MenuItemBase::itemIndex); });
 | 
			
		||||
  END_MENU();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -142,32 +142,32 @@ void menu_mmu2_choose_filament() {
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
void menu_mmu2_pause() {
 | 
			
		||||
  currentTool = mmu2.get_current_tool();
 | 
			
		||||
  feeder_index = mmu2.get_current_tool();
 | 
			
		||||
  START_MENU();
 | 
			
		||||
  #if LCD_HEIGHT > 2
 | 
			
		||||
    STATIC_ITEM(MSG_FILAMENT_CHANGE_HEADER, SS_DEFAULT|SS_INVERT);
 | 
			
		||||
  #endif
 | 
			
		||||
  ACTION_ITEM(MSG_MMU2_RESUME, []{ mmuMenuWait = false; });
 | 
			
		||||
  ACTION_ITEM(MSG_MMU2_RESUME, []{ wait_for_mmu_menu = false; });
 | 
			
		||||
  ACTION_ITEM(MSG_MMU2_UNLOAD_FILAMENT, []{ mmu2.unload(); });
 | 
			
		||||
  ACTION_ITEM(MSG_MMU2_LOAD_FILAMENT, []{ mmu2.load_filament(currentTool); });
 | 
			
		||||
  ACTION_ITEM(MSG_MMU2_LOAD_TO_NOZZLE, []{ mmu2.load_filament_to_nozzle(currentTool); });
 | 
			
		||||
  ACTION_ITEM(MSG_MMU2_LOAD_FILAMENT, []{ mmu2.load_filament(feeder_index); });
 | 
			
		||||
  ACTION_ITEM(MSG_MMU2_LOAD_TO_NOZZLE, []{ mmu2.load_filament_to_nozzle(feeder_index); });
 | 
			
		||||
  END_MENU();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void mmu2_M600() {
 | 
			
		||||
  ui.defer_status_screen();
 | 
			
		||||
  ui.goto_screen(menu_mmu2_pause);
 | 
			
		||||
  mmuMenuWait = true;
 | 
			
		||||
  while (mmuMenuWait) idle();
 | 
			
		||||
  wait_for_mmu_menu = true;
 | 
			
		||||
  while (wait_for_mmu_menu) idle();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t mmu2_choose_filament() {
 | 
			
		||||
  ui.defer_status_screen();
 | 
			
		||||
  ui.goto_screen(menu_mmu2_choose_filament);
 | 
			
		||||
  mmuMenuWait = true;
 | 
			
		||||
  while (mmuMenuWait) idle();
 | 
			
		||||
  wait_for_mmu_menu = true;
 | 
			
		||||
  while (wait_for_mmu_menu) idle();
 | 
			
		||||
  ui.return_to_status();
 | 
			
		||||
  return currentTool;
 | 
			
		||||
  return feeder_index;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif // HAS_LCD_MENU && MMU2_MENUS
 | 
			
		||||
 
 | 
			
		||||
@@ -1068,46 +1068,30 @@ void MarlinSettings::postprocess() {
 | 
			
		||||
        #if AXIS_IS_TMC(Z4)
 | 
			
		||||
          tmc_stepper_current.Z4 = stepperZ4.getMilliamps();
 | 
			
		||||
        #endif
 | 
			
		||||
        #if MAX_EXTRUDERS
 | 
			
		||||
          #if AXIS_IS_TMC(E0)
 | 
			
		||||
            tmc_stepper_current.E0 = stepperE0.getMilliamps();
 | 
			
		||||
          #endif
 | 
			
		||||
          #if MAX_EXTRUDERS > 1
 | 
			
		||||
            #if AXIS_IS_TMC(E1)
 | 
			
		||||
              tmc_stepper_current.E1 = stepperE1.getMilliamps();
 | 
			
		||||
            #endif
 | 
			
		||||
            #if MAX_EXTRUDERS > 2
 | 
			
		||||
              #if AXIS_IS_TMC(E2)
 | 
			
		||||
                tmc_stepper_current.E2 = stepperE2.getMilliamps();
 | 
			
		||||
              #endif
 | 
			
		||||
              #if MAX_EXTRUDERS > 3
 | 
			
		||||
                #if AXIS_IS_TMC(E3)
 | 
			
		||||
                  tmc_stepper_current.E3 = stepperE3.getMilliamps();
 | 
			
		||||
                #endif
 | 
			
		||||
                #if MAX_EXTRUDERS > 4
 | 
			
		||||
                  #if AXIS_IS_TMC(E4)
 | 
			
		||||
                    tmc_stepper_current.E4 = stepperE4.getMilliamps();
 | 
			
		||||
                  #endif
 | 
			
		||||
                  #if MAX_EXTRUDERS > 5
 | 
			
		||||
                    #if AXIS_IS_TMC(E5)
 | 
			
		||||
                      tmc_stepper_current.E5 = stepperE5.getMilliamps();
 | 
			
		||||
                    #endif
 | 
			
		||||
                    #if MAX_EXTRUDERS > 6
 | 
			
		||||
                      #if AXIS_IS_TMC(E6)
 | 
			
		||||
                        tmc_stepper_current.E6 = stepperE6.getMilliamps();
 | 
			
		||||
                      #endif
 | 
			
		||||
                      #if MAX_EXTRUDERS > 7
 | 
			
		||||
                        #if AXIS_IS_TMC(E7)
 | 
			
		||||
                          tmc_stepper_current.E7 = stepperE7.getMilliamps();
 | 
			
		||||
                        #endif
 | 
			
		||||
                      #endif // MAX_EXTRUDERS > 7
 | 
			
		||||
                    #endif // MAX_EXTRUDERS > 6
 | 
			
		||||
                  #endif // MAX_EXTRUDERS > 5
 | 
			
		||||
                #endif // MAX_EXTRUDERS > 4
 | 
			
		||||
              #endif // MAX_EXTRUDERS > 3
 | 
			
		||||
            #endif // MAX_EXTRUDERS > 2
 | 
			
		||||
          #endif // MAX_EXTRUDERS > 1
 | 
			
		||||
        #endif // MAX_EXTRUDERS
 | 
			
		||||
        #if AXIS_IS_TMC(E0)
 | 
			
		||||
          tmc_stepper_current.E0 = stepperE0.getMilliamps();
 | 
			
		||||
        #endif
 | 
			
		||||
        #if AXIS_IS_TMC(E1)
 | 
			
		||||
          tmc_stepper_current.E1 = stepperE1.getMilliamps();
 | 
			
		||||
        #endif
 | 
			
		||||
        #if AXIS_IS_TMC(E2)
 | 
			
		||||
          tmc_stepper_current.E2 = stepperE2.getMilliamps();
 | 
			
		||||
        #endif
 | 
			
		||||
        #if AXIS_IS_TMC(E3)
 | 
			
		||||
          tmc_stepper_current.E3 = stepperE3.getMilliamps();
 | 
			
		||||
        #endif
 | 
			
		||||
        #if AXIS_IS_TMC(E4)
 | 
			
		||||
          tmc_stepper_current.E4 = stepperE4.getMilliamps();
 | 
			
		||||
        #endif
 | 
			
		||||
        #if AXIS_IS_TMC(E5)
 | 
			
		||||
          tmc_stepper_current.E5 = stepperE5.getMilliamps();
 | 
			
		||||
        #endif
 | 
			
		||||
        #if AXIS_IS_TMC(E6)
 | 
			
		||||
          tmc_stepper_current.E6 = stepperE6.getMilliamps();
 | 
			
		||||
        #endif
 | 
			
		||||
        #if AXIS_IS_TMC(E7)
 | 
			
		||||
          tmc_stepper_current.E7 = stepperE7.getMilliamps();
 | 
			
		||||
        #endif
 | 
			
		||||
      #endif
 | 
			
		||||
      EEPROM_WRITE(tmc_stepper_current);
 | 
			
		||||
    }
 | 
			
		||||
@@ -1144,46 +1128,30 @@ void MarlinSettings::postprocess() {
 | 
			
		||||
        #if AXIS_HAS_STEALTHCHOP(Z4)
 | 
			
		||||
          tmc_hybrid_threshold.Z4 = stepperZ4.get_pwm_thrs();
 | 
			
		||||
        #endif
 | 
			
		||||
        #if MAX_EXTRUDERS
 | 
			
		||||
          #if AXIS_HAS_STEALTHCHOP(E0)
 | 
			
		||||
            tmc_hybrid_threshold.E0 = stepperE0.get_pwm_thrs();
 | 
			
		||||
          #endif
 | 
			
		||||
          #if MAX_EXTRUDERS > 1
 | 
			
		||||
            #if AXIS_HAS_STEALTHCHOP(E1)
 | 
			
		||||
              tmc_hybrid_threshold.E1 = stepperE1.get_pwm_thrs();
 | 
			
		||||
            #endif
 | 
			
		||||
            #if MAX_EXTRUDERS > 2
 | 
			
		||||
              #if AXIS_HAS_STEALTHCHOP(E2)
 | 
			
		||||
                tmc_hybrid_threshold.E2 = stepperE2.get_pwm_thrs();
 | 
			
		||||
              #endif
 | 
			
		||||
              #if MAX_EXTRUDERS > 3
 | 
			
		||||
                #if AXIS_HAS_STEALTHCHOP(E3)
 | 
			
		||||
                  tmc_hybrid_threshold.E3 = stepperE3.get_pwm_thrs();
 | 
			
		||||
                #endif
 | 
			
		||||
                #if MAX_EXTRUDERS > 4
 | 
			
		||||
                  #if AXIS_HAS_STEALTHCHOP(E4)
 | 
			
		||||
                    tmc_hybrid_threshold.E4 = stepperE4.get_pwm_thrs();
 | 
			
		||||
                  #endif
 | 
			
		||||
                  #if MAX_EXTRUDERS > 5
 | 
			
		||||
                    #if AXIS_HAS_STEALTHCHOP(E5)
 | 
			
		||||
                      tmc_hybrid_threshold.E5 = stepperE5.get_pwm_thrs();
 | 
			
		||||
                    #endif
 | 
			
		||||
                    #if MAX_EXTRUDERS > 6
 | 
			
		||||
                      #if AXIS_HAS_STEALTHCHOP(E6)
 | 
			
		||||
                        tmc_hybrid_threshold.E6 = stepperE6.get_pwm_thrs();
 | 
			
		||||
                      #endif
 | 
			
		||||
                      #if MAX_EXTRUDERS > 7
 | 
			
		||||
                        #if AXIS_HAS_STEALTHCHOP(E7)
 | 
			
		||||
                          tmc_hybrid_threshold.E7 = stepperE7.get_pwm_thrs();
 | 
			
		||||
                        #endif
 | 
			
		||||
                      #endif // MAX_EXTRUDERS > 7
 | 
			
		||||
                    #endif // MAX_EXTRUDERS > 6
 | 
			
		||||
                  #endif // MAX_EXTRUDERS > 5
 | 
			
		||||
                #endif // MAX_EXTRUDERS > 4
 | 
			
		||||
              #endif // MAX_EXTRUDERS > 3
 | 
			
		||||
            #endif // MAX_EXTRUDERS > 2
 | 
			
		||||
          #endif // MAX_EXTRUDERS > 1
 | 
			
		||||
        #endif // MAX_EXTRUDERS
 | 
			
		||||
        #if AXIS_HAS_STEALTHCHOP(E0)
 | 
			
		||||
          tmc_hybrid_threshold.E0 = stepperE0.get_pwm_thrs();
 | 
			
		||||
        #endif
 | 
			
		||||
        #if AXIS_HAS_STEALTHCHOP(E1)
 | 
			
		||||
          tmc_hybrid_threshold.E1 = stepperE1.get_pwm_thrs();
 | 
			
		||||
        #endif
 | 
			
		||||
        #if AXIS_HAS_STEALTHCHOP(E2)
 | 
			
		||||
          tmc_hybrid_threshold.E2 = stepperE2.get_pwm_thrs();
 | 
			
		||||
        #endif
 | 
			
		||||
        #if AXIS_HAS_STEALTHCHOP(E3)
 | 
			
		||||
          tmc_hybrid_threshold.E3 = stepperE3.get_pwm_thrs();
 | 
			
		||||
        #endif
 | 
			
		||||
        #if AXIS_HAS_STEALTHCHOP(E4)
 | 
			
		||||
          tmc_hybrid_threshold.E4 = stepperE4.get_pwm_thrs();
 | 
			
		||||
        #endif
 | 
			
		||||
        #if AXIS_HAS_STEALTHCHOP(E5)
 | 
			
		||||
          tmc_hybrid_threshold.E5 = stepperE5.get_pwm_thrs();
 | 
			
		||||
        #endif
 | 
			
		||||
        #if AXIS_HAS_STEALTHCHOP(E6)
 | 
			
		||||
          tmc_hybrid_threshold.E6 = stepperE6.get_pwm_thrs();
 | 
			
		||||
        #endif
 | 
			
		||||
        #if AXIS_HAS_STEALTHCHOP(E7)
 | 
			
		||||
          tmc_hybrid_threshold.E7 = stepperE7.get_pwm_thrs();
 | 
			
		||||
        #endif
 | 
			
		||||
      #else
 | 
			
		||||
        const tmc_hybrid_threshold_t tmc_hybrid_threshold = {
 | 
			
		||||
          .X  = 100, .Y  = 100, .Z  =   3,
 | 
			
		||||
@@ -1219,73 +1187,54 @@ void MarlinSettings::postprocess() {
 | 
			
		||||
    {
 | 
			
		||||
      _FIELD_TEST(tmc_stealth_enabled);
 | 
			
		||||
 | 
			
		||||
      tmc_stealth_enabled_t tmc_stealth_enabled = { false, false, false, false, false, false, false, false, false, false, false, false, false };
 | 
			
		||||
 | 
			
		||||
      #if HAS_STEALTHCHOP
 | 
			
		||||
        #if AXIS_HAS_STEALTHCHOP(X)
 | 
			
		||||
          tmc_stealth_enabled.X = stepperX.get_stored_stealthChop();
 | 
			
		||||
        #endif
 | 
			
		||||
        #if AXIS_HAS_STEALTHCHOP(Y)
 | 
			
		||||
          tmc_stealth_enabled.Y = stepperY.get_stored_stealthChop();
 | 
			
		||||
        #endif
 | 
			
		||||
        #if AXIS_HAS_STEALTHCHOP(Z)
 | 
			
		||||
          tmc_stealth_enabled.Z = stepperZ.get_stored_stealthChop();
 | 
			
		||||
        #endif
 | 
			
		||||
        #if AXIS_HAS_STEALTHCHOP(X2)
 | 
			
		||||
          tmc_stealth_enabled.X2 = stepperX2.get_stored_stealthChop();
 | 
			
		||||
        #endif
 | 
			
		||||
        #if AXIS_HAS_STEALTHCHOP(Y2)
 | 
			
		||||
          tmc_stealth_enabled.Y2 = stepperY2.get_stored_stealthChop();
 | 
			
		||||
        #endif
 | 
			
		||||
        #if AXIS_HAS_STEALTHCHOP(Z2)
 | 
			
		||||
          tmc_stealth_enabled.Z2 = stepperZ2.get_stored_stealthChop();
 | 
			
		||||
        #endif
 | 
			
		||||
        #if AXIS_HAS_STEALTHCHOP(Z3)
 | 
			
		||||
          tmc_stealth_enabled.Z3 = stepperZ3.get_stored_stealthChop();
 | 
			
		||||
        #endif
 | 
			
		||||
        #if AXIS_HAS_STEALTHCHOP(Z4)
 | 
			
		||||
          tmc_stealth_enabled.Z4 = stepperZ4.get_stored_stealthChop();
 | 
			
		||||
        #endif
 | 
			
		||||
        #if MAX_EXTRUDERS
 | 
			
		||||
          #if AXIS_HAS_STEALTHCHOP(E0)
 | 
			
		||||
            tmc_stealth_enabled.E0 = stepperE0.get_stored_stealthChop();
 | 
			
		||||
          #endif
 | 
			
		||||
          #if MAX_EXTRUDERS > 1
 | 
			
		||||
            #if AXIS_HAS_STEALTHCHOP(E1)
 | 
			
		||||
              tmc_stealth_enabled.E1 = stepperE1.get_stored_stealthChop();
 | 
			
		||||
            #endif
 | 
			
		||||
            #if MAX_EXTRUDERS > 2
 | 
			
		||||
              #if AXIS_HAS_STEALTHCHOP(E2)
 | 
			
		||||
                tmc_stealth_enabled.E2 = stepperE2.get_stored_stealthChop();
 | 
			
		||||
              #endif
 | 
			
		||||
              #if MAX_EXTRUDERS > 3
 | 
			
		||||
                #if AXIS_HAS_STEALTHCHOP(E3)
 | 
			
		||||
                  tmc_stealth_enabled.E3 = stepperE3.get_stored_stealthChop();
 | 
			
		||||
                #endif
 | 
			
		||||
                #if MAX_EXTRUDERS > 4
 | 
			
		||||
                  #if AXIS_HAS_STEALTHCHOP(E4)
 | 
			
		||||
                    tmc_stealth_enabled.E4 = stepperE4.get_stored_stealthChop();
 | 
			
		||||
                  #endif
 | 
			
		||||
                  #if MAX_EXTRUDERS > 5
 | 
			
		||||
                    #if AXIS_HAS_STEALTHCHOP(E5)
 | 
			
		||||
                      tmc_stealth_enabled.E5 = stepperE5.get_stored_stealthChop();
 | 
			
		||||
                    #endif
 | 
			
		||||
                    #if MAX_EXTRUDERS > 6
 | 
			
		||||
                      #if AXIS_HAS_STEALTHCHOP(E6)
 | 
			
		||||
                        tmc_stealth_enabled.E6 = stepperE6.get_stored_stealthChop();
 | 
			
		||||
                      #endif
 | 
			
		||||
                      #if MAX_EXTRUDERS > 7
 | 
			
		||||
                        #if AXIS_HAS_STEALTHCHOP(E7)
 | 
			
		||||
                          tmc_stealth_enabled.E7 = stepperE7.get_stored_stealthChop();
 | 
			
		||||
                        #endif
 | 
			
		||||
                      #endif // MAX_EXTRUDERS > 7
 | 
			
		||||
                    #endif // MAX_EXTRUDERS > 6
 | 
			
		||||
                  #endif // MAX_EXTRUDERS > 5
 | 
			
		||||
                #endif // MAX_EXTRUDERS > 4
 | 
			
		||||
              #endif // MAX_EXTRUDERS > 3
 | 
			
		||||
            #endif // MAX_EXTRUDERS > 2
 | 
			
		||||
          #endif // MAX_EXTRUDERS > 1
 | 
			
		||||
        #endif // MAX_EXTRUDERS
 | 
			
		||||
      tmc_stealth_enabled_t tmc_stealth_enabled = { false };
 | 
			
		||||
      #if AXIS_HAS_STEALTHCHOP(X)
 | 
			
		||||
        tmc_stealth_enabled.X = stepperX.get_stored_stealthChop();
 | 
			
		||||
      #endif
 | 
			
		||||
      #if AXIS_HAS_STEALTHCHOP(Y)
 | 
			
		||||
        tmc_stealth_enabled.Y = stepperY.get_stored_stealthChop();
 | 
			
		||||
      #endif
 | 
			
		||||
      #if AXIS_HAS_STEALTHCHOP(Z)
 | 
			
		||||
        tmc_stealth_enabled.Z = stepperZ.get_stored_stealthChop();
 | 
			
		||||
      #endif
 | 
			
		||||
      #if AXIS_HAS_STEALTHCHOP(X2)
 | 
			
		||||
        tmc_stealth_enabled.X2 = stepperX2.get_stored_stealthChop();
 | 
			
		||||
      #endif
 | 
			
		||||
      #if AXIS_HAS_STEALTHCHOP(Y2)
 | 
			
		||||
        tmc_stealth_enabled.Y2 = stepperY2.get_stored_stealthChop();
 | 
			
		||||
      #endif
 | 
			
		||||
      #if AXIS_HAS_STEALTHCHOP(Z2)
 | 
			
		||||
        tmc_stealth_enabled.Z2 = stepperZ2.get_stored_stealthChop();
 | 
			
		||||
      #endif
 | 
			
		||||
      #if AXIS_HAS_STEALTHCHOP(Z3)
 | 
			
		||||
        tmc_stealth_enabled.Z3 = stepperZ3.get_stored_stealthChop();
 | 
			
		||||
      #endif
 | 
			
		||||
      #if AXIS_HAS_STEALTHCHOP(Z4)
 | 
			
		||||
        tmc_stealth_enabled.Z4 = stepperZ4.get_stored_stealthChop();
 | 
			
		||||
      #endif
 | 
			
		||||
      #if AXIS_HAS_STEALTHCHOP(E0)
 | 
			
		||||
        tmc_stealth_enabled.E0 = stepperE0.get_stored_stealthChop();
 | 
			
		||||
      #endif
 | 
			
		||||
      #if AXIS_HAS_STEALTHCHOP(E1)
 | 
			
		||||
        tmc_stealth_enabled.E1 = stepperE1.get_stored_stealthChop();
 | 
			
		||||
      #endif
 | 
			
		||||
      #if AXIS_HAS_STEALTHCHOP(E2)
 | 
			
		||||
        tmc_stealth_enabled.E2 = stepperE2.get_stored_stealthChop();
 | 
			
		||||
      #endif
 | 
			
		||||
      #if AXIS_HAS_STEALTHCHOP(E3)
 | 
			
		||||
        tmc_stealth_enabled.E3 = stepperE3.get_stored_stealthChop();
 | 
			
		||||
      #endif
 | 
			
		||||
      #if AXIS_HAS_STEALTHCHOP(E4)
 | 
			
		||||
        tmc_stealth_enabled.E4 = stepperE4.get_stored_stealthChop();
 | 
			
		||||
      #endif
 | 
			
		||||
      #if AXIS_HAS_STEALTHCHOP(E5)
 | 
			
		||||
        tmc_stealth_enabled.E5 = stepperE5.get_stored_stealthChop();
 | 
			
		||||
      #endif
 | 
			
		||||
      #if AXIS_HAS_STEALTHCHOP(E6)
 | 
			
		||||
        tmc_stealth_enabled.E6 = stepperE6.get_stored_stealthChop();
 | 
			
		||||
      #endif
 | 
			
		||||
      #if AXIS_HAS_STEALTHCHOP(E7)
 | 
			
		||||
        tmc_stealth_enabled.E7 = stepperE7.get_stored_stealthChop();
 | 
			
		||||
      #endif
 | 
			
		||||
      EEPROM_WRITE(tmc_stealth_enabled);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -417,12 +417,15 @@ void reset_stepper_drivers();    // Called by settings.load / settings.reset
 | 
			
		||||
    #define   NORM_E_DIR(E)   do{ E0_DIR_WRITE(E ?  INVERT_E0_DIR : !INVERT_E0_DIR); }while(0)
 | 
			
		||||
    #define    REV_E_DIR(E)   do{ E0_DIR_WRITE(E ? !INVERT_E0_DIR :  INVERT_E0_DIR); }while(0)
 | 
			
		||||
  #endif
 | 
			
		||||
#elif ENABLED(PRUSA_MMU2)
 | 
			
		||||
 | 
			
		||||
#elif HAS_PRUSA_MMU2
 | 
			
		||||
 | 
			
		||||
  #define E_STEP_WRITE(E,V) E0_STEP_WRITE(V)
 | 
			
		||||
  #define   NORM_E_DIR(E)   E0_DIR_WRITE(!INVERT_E0_DIR)
 | 
			
		||||
  #define    REV_E_DIR(E)   E0_DIR_WRITE( INVERT_E0_DIR)
 | 
			
		||||
 | 
			
		||||
#elif ENABLED(MK2_MULTIPLEXER) // One multiplexed stepper driver, reversed on odd index
 | 
			
		||||
#elif HAS_PRUSA_MMU1  // One multiplexed stepper driver, reversed on odd index
 | 
			
		||||
 | 
			
		||||
  #define E_STEP_WRITE(E,V) E0_STEP_WRITE(V)
 | 
			
		||||
  #define   NORM_E_DIR(E)   do{ E0_DIR_WRITE(TEST(E, 0) ? !INVERT_E0_DIR:  INVERT_E0_DIR); }while(0)
 | 
			
		||||
  #define    REV_E_DIR(E)   do{ E0_DIR_WRITE(TEST(E, 0) ?  INVERT_E0_DIR: !INVERT_E0_DIR); }while(0)
 | 
			
		||||
 
 | 
			
		||||
@@ -73,10 +73,6 @@
 | 
			
		||||
  #include "../feature/solenoid.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if ENABLED(MK2_MULTIPLEXER)
 | 
			
		||||
  #include "../feature/snmm.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if ENABLED(MIXING_EXTRUDER)
 | 
			
		||||
  #include "../feature/mixing.h"
 | 
			
		||||
#endif
 | 
			
		||||
@@ -89,8 +85,10 @@
 | 
			
		||||
  #include "../feature/fanmux.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if ENABLED(PRUSA_MMU2)
 | 
			
		||||
  #include "../feature/mmu2/mmu2.h"
 | 
			
		||||
#if HAS_PRUSA_MMU1
 | 
			
		||||
  #include "../feature/mmu/mmu.h"
 | 
			
		||||
#elif HAS_PRUSA_MMU2
 | 
			
		||||
  #include "../feature/mmu/mmu2.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if HAS_LCD_MENU
 | 
			
		||||
@@ -863,7 +861,7 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) {
 | 
			
		||||
      mixer.T(new_tool);
 | 
			
		||||
    #endif
 | 
			
		||||
 | 
			
		||||
  #elif ENABLED(PRUSA_MMU2)
 | 
			
		||||
  #elif HAS_PRUSA_MMU2
 | 
			
		||||
 | 
			
		||||
    UNUSED(no_move);
 | 
			
		||||
 | 
			
		||||
@@ -1171,8 +1169,6 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) {
 | 
			
		||||
          do_blocking_move_to_z(destination.z, planner.settings.max_feedrate_mm_s[Z_AXIS]);
 | 
			
		||||
      #endif
 | 
			
		||||
 | 
			
		||||
      TERN_(PRUSA_MMU2, mmu2.tool_change(new_tool));
 | 
			
		||||
 | 
			
		||||
      TERN_(SWITCHING_NOZZLE_TWO_SERVOS, lower_nozzle(new_tool));
 | 
			
		||||
 | 
			
		||||
    } // (new_tool != old_tool)
 | 
			
		||||
@@ -1184,7 +1180,7 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) {
 | 
			
		||||
      enable_solenoid_on_active_extruder();
 | 
			
		||||
    #endif
 | 
			
		||||
 | 
			
		||||
    #if ENABLED(MK2_MULTIPLEXER)
 | 
			
		||||
    #if HAS_PRUSA_MMU1
 | 
			
		||||
      if (new_tool >= E_STEPPERS) return invalid_extruder_error(new_tool);
 | 
			
		||||
      select_multiplexed_stepper(new_tool);
 | 
			
		||||
    #endif
 | 
			
		||||
 
 | 
			
		||||
@@ -131,9 +131,9 @@
 | 
			
		||||
#define PIN_P2_11                          P2_11  // Interrupt Capable
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// Průša i3 MK2 Multi Material Multiplexer Support
 | 
			
		||||
// Průša i3 MMU1 (Multi Material Multiplexer) Support
 | 
			
		||||
//
 | 
			
		||||
#if ENABLED(MK2_MULTIPLEXER)
 | 
			
		||||
#if HAS_PRUSA_MMU1
 | 
			
		||||
  #define E_MUX0_PIN                       P1_23  // J8-3
 | 
			
		||||
  #define E_MUX1_PIN                       P2_12  // J8-4
 | 
			
		||||
  #define E_MUX2_PIN                       P2_11  // J8-5
 | 
			
		||||
 
 | 
			
		||||
@@ -35,7 +35,12 @@
 | 
			
		||||
 *    These numbers are the same in any pin mapping.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define MAX_EXTRUDERS 8
 | 
			
		||||
#if HAS_SMUFF
 | 
			
		||||
  #define MAX_EXTRUDERS 12
 | 
			
		||||
#else
 | 
			
		||||
  #define MAX_EXTRUDERS 8
 | 
			
		||||
#endif
 | 
			
		||||
#define MAX_E_STEPPERS 8
 | 
			
		||||
 | 
			
		||||
#if   MB(RAMPS_13_EFB, RAMPS_14_EFB, RAMPS_PLUS_EFB, RAMPS_14_RE_ARM_EFB, RAMPS_SMART_EFB, RAMPS_DUO_EFB, RAMPS4DUE_EFB)
 | 
			
		||||
  #define IS_RAMPS_EFB
 | 
			
		||||
 
 | 
			
		||||
@@ -521,7 +521,7 @@
 | 
			
		||||
    #define X2_STEP_PIN   _EPIN(X2_E_INDEX, STEP)
 | 
			
		||||
    #define X2_DIR_PIN    _EPIN(X2_E_INDEX, DIR)
 | 
			
		||||
    #define X2_ENABLE_PIN _EPIN(X2_E_INDEX, ENABLE)
 | 
			
		||||
    #if X2_E_INDEX >= MAX_EXTRUDERS || !PIN_EXISTS(X2_STEP)
 | 
			
		||||
    #if X2_E_INDEX >= MAX_E_STEPPERS || !PIN_EXISTS(X2_STEP)
 | 
			
		||||
      #error "No E stepper plug left for X2!"
 | 
			
		||||
    #endif
 | 
			
		||||
  #endif
 | 
			
		||||
@@ -594,7 +594,7 @@
 | 
			
		||||
    #define Y2_STEP_PIN   _EPIN(Y2_E_INDEX, STEP)
 | 
			
		||||
    #define Y2_DIR_PIN    _EPIN(Y2_E_INDEX, DIR)
 | 
			
		||||
    #define Y2_ENABLE_PIN _EPIN(Y2_E_INDEX, ENABLE)
 | 
			
		||||
    #if Y2_E_INDEX >= MAX_EXTRUDERS || !PIN_EXISTS(Y2_STEP)
 | 
			
		||||
    #if Y2_E_INDEX >= MAX_E_STEPPERS || !PIN_EXISTS(Y2_STEP)
 | 
			
		||||
      #error "No E stepper plug left for Y2!"
 | 
			
		||||
    #endif
 | 
			
		||||
  #endif
 | 
			
		||||
@@ -662,7 +662,7 @@
 | 
			
		||||
    #define Z2_STEP_PIN   _EPIN(Z2_E_INDEX, STEP)
 | 
			
		||||
    #define Z2_DIR_PIN    _EPIN(Z2_E_INDEX, DIR)
 | 
			
		||||
    #define Z2_ENABLE_PIN _EPIN(Z2_E_INDEX, ENABLE)
 | 
			
		||||
    #if Z2_E_INDEX >= MAX_EXTRUDERS || !PIN_EXISTS(Z2_STEP)
 | 
			
		||||
    #if Z2_E_INDEX >= MAX_E_STEPPERS || !PIN_EXISTS(Z2_STEP)
 | 
			
		||||
      #error "No E stepper plug left for Z2!"
 | 
			
		||||
    #endif
 | 
			
		||||
  #endif
 | 
			
		||||
@@ -729,7 +729,7 @@
 | 
			
		||||
    #define Z3_STEP_PIN   _EPIN(Z3_E_INDEX, STEP)
 | 
			
		||||
    #define Z3_DIR_PIN    _EPIN(Z3_E_INDEX, DIR)
 | 
			
		||||
    #define Z3_ENABLE_PIN _EPIN(Z3_E_INDEX, ENABLE)
 | 
			
		||||
    #if Z3_E_INDEX >= MAX_EXTRUDERS || !PIN_EXISTS(Z3_STEP)
 | 
			
		||||
    #if Z3_E_INDEX >= MAX_E_STEPPERS || !PIN_EXISTS(Z3_STEP)
 | 
			
		||||
      #error "No E stepper plug left for Z3!"
 | 
			
		||||
    #endif
 | 
			
		||||
  #endif
 | 
			
		||||
@@ -796,7 +796,7 @@
 | 
			
		||||
    #define Z4_STEP_PIN   _EPIN(Z4_E_INDEX, STEP)
 | 
			
		||||
    #define Z4_DIR_PIN    _EPIN(Z4_E_INDEX, DIR)
 | 
			
		||||
    #define Z4_ENABLE_PIN _EPIN(Z4_E_INDEX, ENABLE)
 | 
			
		||||
    #if Z4_E_INDEX >= MAX_EXTRUDERS || !PIN_EXISTS(Z4_STEP)
 | 
			
		||||
    #if Z4_E_INDEX >= MAX_E_STEPPERS || !PIN_EXISTS(Z4_STEP)
 | 
			
		||||
      #error "No E stepper plug left for Z4!"
 | 
			
		||||
    #endif
 | 
			
		||||
  #endif
 | 
			
		||||
 
 | 
			
		||||
@@ -25,8 +25,8 @@
 | 
			
		||||
  #error "Oops! Select an STM32F4 board in 'Tools > Board.'"
 | 
			
		||||
#elif HOTENDS > 8 || E_STEPPERS > 8
 | 
			
		||||
  #error "BIGTREE GTR V1.0 supports up to 8 hotends / E-steppers."
 | 
			
		||||
#elif HOTENDS > MAX_EXTRUDERS || E_STEPPERS > MAX_EXTRUDERS
 | 
			
		||||
  #error "Marlin extruder/hotends limit! Increase MAX_EXTRUDERS to continue."
 | 
			
		||||
#elif HOTENDS > MAX_E_STEPPERS || E_STEPPERS > MAX_E_STEPPERS
 | 
			
		||||
  #error "Marlin extruder/hotends limit! Increase MAX_E_STEPPERS to continue."
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define BOARD_INFO_NAME "BTT GTR V1.0"
 | 
			
		||||
 
 | 
			
		||||
@@ -66,28 +66,38 @@ exec_test $1 $2 "Azteeg X3 Pro | EXTRUDERS 5 | RRDFGSC | UBL | LIN_ADVANCE | Sle
 | 
			
		||||
#
 | 
			
		||||
restore_configs
 | 
			
		||||
opt_set LCD_LANGUAGE zh_CN
 | 
			
		||||
opt_set MMU_MODEL PRUSA_MMU2S
 | 
			
		||||
opt_set EXTRUDERS 5
 | 
			
		||||
opt_set NUM_SERVOS 1
 | 
			
		||||
opt_enable ZONESTAR_LCD Z_PROBE_SERVO_NR Z_SERVO_ANGLES DEACTIVATE_SERVOS_AFTER_MOVE BOOT_MARLIN_LOGO_ANIMATED \
 | 
			
		||||
           AUTO_BED_LEVELING_3POINT DEBUG_LEVELING_FEATURE EEPROM_SETTINGS EEPROM_CHITCHAT M114_DETAIL \
 | 
			
		||||
           NO_VOLUMETRICS EXTENDED_CAPABILITIES_REPORT AUTO_REPORT_TEMPERATURES AUTOTEMP G38_PROBE_TARGET JOYSTICK \
 | 
			
		||||
           PRUSA_MMU2 MMU2_MENUS PRUSA_MMU2_S_MODE DIRECT_STEPPING DETECT_BROKEN_ENDSTOP \
 | 
			
		||||
           MMU2_MENUS DIRECT_STEPPING DETECT_BROKEN_ENDSTOP \
 | 
			
		||||
           FILAMENT_RUNOUT_SENSOR NOZZLE_PARK_FEATURE ADVANCED_PAUSE_FEATURE Z_SAFE_HOMING
 | 
			
		||||
exec_test $1 $2 "RAMPS | ZONESTAR + Chinese | MMU2 | Servo | 3-Point + Debug | G38 ..." "$3"
 | 
			
		||||
exec_test $1 $2 "RAMPS | ZONESTAR + Chinese | MMU2S | Servo | 3-Point + Debug | G38 ..." "$3"
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# 5 runout sensors with distinct states
 | 
			
		||||
#
 | 
			
		||||
restore_configs
 | 
			
		||||
opt_set MOTHERBOARD BOARD_AZTEEG_X3_PRO
 | 
			
		||||
opt_set EXTRUDERS 5
 | 
			
		||||
opt_set NUM_SERVOS 1
 | 
			
		||||
opt_set TEMP_SENSOR_1 1
 | 
			
		||||
opt_set TEMP_SENSOR_2 1
 | 
			
		||||
opt_set TEMP_SENSOR_3 1
 | 
			
		||||
opt_set TEMP_SENSOR_4 1
 | 
			
		||||
opt_enable ZONESTAR_LCD Z_PROBE_SERVO_NR Z_SERVO_ANGLES DEACTIVATE_SERVOS_AFTER_MOVE BOOT_MARLIN_LOGO_ANIMATED \
 | 
			
		||||
           AUTO_BED_LEVELING_3POINT DEBUG_LEVELING_FEATURE EEPROM_SETTINGS EEPROM_CHITCHAT M114_DETAIL \
 | 
			
		||||
           NO_VOLUMETRICS EXTENDED_CAPABILITIES_REPORT AUTO_REPORT_TEMPERATURES AUTOTEMP G38_PROBE_TARGET JOYSTICK \
 | 
			
		||||
           PRUSA_MMU2 MMU2_MENUS PRUSA_MMU2_S_MODE DIRECT_STEPPING DETECT_BROKEN_ENDSTOP \
 | 
			
		||||
           DIRECT_STEPPING DETECT_BROKEN_ENDSTOP \
 | 
			
		||||
           FILAMENT_RUNOUT_SENSOR NOZZLE_PARK_FEATURE ADVANCED_PAUSE_FEATURE Z_SAFE_HOMING FIL_RUNOUT3_PULL
 | 
			
		||||
opt_set MIXING_STEPPERS 5
 | 
			
		||||
opt_set NUM_RUNOUT_SENSORS 5
 | 
			
		||||
opt_set FIL_RUNOUT2_PIN 44
 | 
			
		||||
opt_set FIL_RUNOUT3_PIN 45
 | 
			
		||||
opt_set FIL_RUNOUT3_STATE HIGH
 | 
			
		||||
opt_set FIL_RUNOUT4_PIN 46
 | 
			
		||||
opt_set FIL_RUNOUT5_PIN 47
 | 
			
		||||
exec_test $1 $2 "Multiple runout sensors (x5) | Distinct runout states"
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
 
 | 
			
		||||
@@ -93,7 +93,8 @@ default_src_filter = +<src/*> -<src/config> -<src/HAL> +<src/HAL/shared>
 | 
			
		||||
  -<src/feature/leds/tempstat.cpp>
 | 
			
		||||
  -<src/feature/max7219.cpp>
 | 
			
		||||
  -<src/feature/mixing.cpp>
 | 
			
		||||
  -<src/feature/mmu2> -<src/gcode/feature/prusa_MMU2>
 | 
			
		||||
  -<src/feature/mmu/mmu.cpp>
 | 
			
		||||
  -<src/feature/mmu/mmu2.cpp> -<src/gcode/feature/prusa_MMU2>
 | 
			
		||||
  -<src/feature/password> -<src/gcode/feature/password>
 | 
			
		||||
  -<src/feature/pause.cpp>
 | 
			
		||||
  -<src/feature/power.cpp>
 | 
			
		||||
@@ -101,7 +102,6 @@ default_src_filter = +<src/*> -<src/config> -<src/HAL> +<src/HAL/shared>
 | 
			
		||||
  -<src/feature/powerloss.cpp> -<src/gcode/feature/powerloss>
 | 
			
		||||
  -<src/feature/probe_temp_comp.cpp>
 | 
			
		||||
  -<src/feature/runout.cpp> -<src/gcode/feature/runout>
 | 
			
		||||
  -<src/feature/snmm.cpp>
 | 
			
		||||
  -<src/feature/solenoid.cpp> -<src/gcode/control/M380_M381.cpp>
 | 
			
		||||
  -<src/feature/spindle_laser.cpp> -<src/gcode/control/M3-M5.cpp>
 | 
			
		||||
  -<src/feature/tmc_util.cpp> -<src/module/stepper/trinamic.cpp>
 | 
			
		||||
@@ -304,7 +304,8 @@ PRINTER_EVENT_LEDS      = src_filter=+<src/feature/leds/printer_event_leds.cpp>
 | 
			
		||||
TEMP_STAT_LEDS          = src_filter=+<src/feature/leds/tempstat.cpp>
 | 
			
		||||
MAX7219_DEBUG           = src_filter=+<src/feature/max7219.cpp> +<src/gcode/feature/leds/M7219.cpp>
 | 
			
		||||
MIXING_EXTRUDER         = src_filter=+<src/feature/mixing.cpp> +<src/gcode/feature/mixing/M163-M165.cpp>
 | 
			
		||||
PRUSA_MMU2              = src_filter=+<src/feature/mmu2> +<src/gcode/feature/prusa_MMU2>
 | 
			
		||||
HAS_PRUSA_MMU1          = src_filter=+<src/feature/mmu/mmu.cpp>
 | 
			
		||||
HAS_PRUSA_MMU2          = src_filter=+<src/feature/mmu/mmu2.cpp> +<src/gcode/feature/prusa_MMU2>
 | 
			
		||||
PASSWORD_FEATURE        = src_filter=+<src/feature/password> +<src/gcode/feature/password>
 | 
			
		||||
ADVANCED_PAUSE_FEATURE  = src_filter=+<src/feature/pause.cpp> +<src/gcode/feature/pause/M600.cpp> +<src/gcode/feature/pause/M603.cpp>
 | 
			
		||||
AUTO_POWER_CONTROL      = src_filter=+<src/feature/power.cpp>
 | 
			
		||||
@@ -312,8 +313,7 @@ HAS_POWER_MONITOR       = src_filter=+<src/feature/power_monitor.cpp> +<src/gcod
 | 
			
		||||
POWER_LOSS_RECOVERY     = src_filter=+<src/feature/powerloss.cpp> +<src/gcode/feature/powerloss>
 | 
			
		||||
PROBE_TEMP_COMPENSATION = src_filter=+<src/feature/probe_temp_comp.cpp> +<src/gcode/calibrate/G76_M192_M871.cpp>
 | 
			
		||||
HAS_FILAMENT_SENSOR     = src_filter=+<src/feature/runout.cpp> +<src/gcode/feature/runout>
 | 
			
		||||
MK2_MULTIPLEXER         = src_filter=+<src/feature/snmm.cpp>
 | 
			
		||||
EXT_SOLENOID|MANUAL_SOLENOID_CONTROL = src_filter=+<src/feature/solenoid.cpp> +<src/gcode/control/M380_M381.cpp>
 | 
			
		||||
(EXT|MANUAL)_SOLENOID.* = src_filter=+<src/feature/solenoid.cpp> +<src/gcode/control/M380_M381.cpp>
 | 
			
		||||
HAS_CUTTER              = src_filter=+<src/feature/spindle_laser.cpp> +<src/gcode/control/M3-M5.cpp>
 | 
			
		||||
EXPERIMENTAL_I2CBUS     = src_filter=+<src/feature/twibus.cpp> +<src/gcode/feature/i2c>
 | 
			
		||||
MECHANICAL_GANTRY_CAL.+ = src_filter=+<src/gcode/calibrate/G34.cpp>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user