Fix IDEX layer shift and DIR states (#19756)
Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
This commit is contained in:
		
				
					committed by
					
						 Scott Lahteine
						Scott Lahteine
					
				
			
			
				
	
			
			
			
						parent
						
							19498040ef
						
					
				
				
					commit
					3becc3ad63
				
			| @@ -223,8 +223,7 @@ bool load_filament(const float &slow_load_length/*=0*/, const float &fast_load_l | ||||
|   #if ENABLED(DUAL_X_CARRIAGE) | ||||
|     const int8_t saved_ext        = active_extruder; | ||||
|     const bool saved_ext_dup_mode = extruder_duplication_enabled; | ||||
|     active_extruder = DXC_ext; | ||||
|     extruder_duplication_enabled = false; | ||||
|     set_duplication_enabled(false, DXC_ext); | ||||
|   #endif | ||||
|  | ||||
|   // Slow Load filament | ||||
| @@ -245,9 +244,7 @@ bool load_filament(const float &slow_load_length/*=0*/, const float &fast_load_l | ||||
|   } | ||||
|  | ||||
|   #if ENABLED(DUAL_X_CARRIAGE)      // Tie the two extruders movement back together. | ||||
|     active_extruder = saved_ext; | ||||
|     extruder_duplication_enabled = saved_ext_dup_mode; | ||||
|     stepper.set_directions(); | ||||
|     set_duplication_enabled(saved_ext_dup_mode, saved_ext); | ||||
|   #endif | ||||
|  | ||||
|   #if ENABLED(ADVANCED_PAUSE_CONTINUOUS_PURGE) | ||||
| @@ -439,17 +436,14 @@ bool pause_print(const float &retract, const xyz_pos_t &park_point, const float | ||||
|   #if ENABLED(DUAL_X_CARRIAGE) | ||||
|     const int8_t saved_ext        = active_extruder; | ||||
|     const bool saved_ext_dup_mode = extruder_duplication_enabled; | ||||
|     active_extruder = DXC_ext; | ||||
|     extruder_duplication_enabled = false; | ||||
|     set_duplication_enabled(false, DXC_ext); | ||||
|   #endif | ||||
|  | ||||
|   if (unload_length)   // Unload the filament | ||||
|     unload_filament(unload_length, show_lcd, PAUSE_MODE_CHANGE_FILAMENT); | ||||
|  | ||||
|   #if ENABLED(DUAL_X_CARRIAGE) | ||||
|     active_extruder = saved_ext; | ||||
|     extruder_duplication_enabled = saved_ext_dup_mode; | ||||
|     stepper.set_directions(); | ||||
|     set_duplication_enabled(saved_ext_dup_mode, saved_ext); | ||||
|   #endif | ||||
|  | ||||
|   return true; | ||||
| @@ -495,8 +489,7 @@ void wait_for_confirmation(const bool is_reload/*=false*/, const int8_t max_beep | ||||
|   #if ENABLED(DUAL_X_CARRIAGE) | ||||
|     const int8_t saved_ext        = active_extruder; | ||||
|     const bool saved_ext_dup_mode = extruder_duplication_enabled; | ||||
|     active_extruder = DXC_ext; | ||||
|     extruder_duplication_enabled = false; | ||||
|     set_duplication_enabled(false, DXC_ext); | ||||
|   #endif | ||||
|  | ||||
|   // Wait for filament insert by user and press button | ||||
| @@ -550,9 +543,7 @@ void wait_for_confirmation(const bool is_reload/*=false*/, const int8_t max_beep | ||||
|     idle_no_sleep(); | ||||
|   } | ||||
|   #if ENABLED(DUAL_X_CARRIAGE) | ||||
|     active_extruder = saved_ext; | ||||
|     extruder_duplication_enabled = saved_ext_dup_mode; | ||||
|     stepper.set_directions(); | ||||
|     set_duplication_enabled(saved_ext_dup_mode, saved_ext); | ||||
|   #endif | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -89,10 +89,11 @@ bool pause_print(const float &retract, const xyz_pos_t &park_point, const float | ||||
|  | ||||
| void wait_for_confirmation(const bool is_reload=false, const int8_t max_beep_count=0 DXC_PARAMS); | ||||
|  | ||||
| void resume_print(const float &slow_load_length=0, const float &fast_load_length=0, const float &extrude_length=ADVANCED_PAUSE_PURGE_LENGTH, const int8_t max_beep_count=0, int16_t targetTemp=0 DXC_PARAMS); | ||||
| void resume_print(const float &slow_load_length=0, const float &fast_load_length=0, const float &extrude_length=ADVANCED_PAUSE_PURGE_LENGTH, | ||||
|                     const int8_t max_beep_count=0, int16_t targetTemp=0 DXC_PARAMS); | ||||
|  | ||||
| bool load_filament(const float &slow_load_length=0, const float &fast_load_length=0, const float &extrude_length=0, const int8_t max_beep_count=0, const bool show_lcd=false, | ||||
|                           const bool pause_for_user=false, const PauseMode mode=PAUSE_MODE_PAUSE_PRINT DXC_PARAMS); | ||||
| bool load_filament(const float &slow_load_length=0, const float &fast_load_length=0, const float &extrude_length=0, const int8_t max_beep_count=0, | ||||
|                     const bool show_lcd=false, const bool pause_for_user=false, const PauseMode mode=PAUSE_MODE_PAUSE_PRINT DXC_PARAMS); | ||||
|  | ||||
| bool unload_filament(const float &unload_length, const bool show_lcd=false, const PauseMode mode=PAUSE_MODE_PAUSE_PRINT | ||||
|   #if BOTH(FILAMENT_UNLOAD_ALL_EXTRUDERS, MIXING_EXTRUDER) | ||||
|   | ||||
| @@ -237,7 +237,7 @@ class FilamentSensorBase { | ||||
|         #if NUM_RUNOUT_SENSORS == 1 | ||||
|           UNUSED(extruder); | ||||
|         #else | ||||
|           if ( !TERN0(DUAL_X_CARRIAGE, dxc_is_duplicating()) | ||||
|           if ( !TERN0(DUAL_X_CARRIAGE, idex_is_duplicating()) | ||||
|             && !TERN0(MULTI_NOZZLE_DUPLICATION, extruder_duplication_enabled) | ||||
|           ) return TEST(runout_states, extruder); // A specific extruder ran out | ||||
|         #endif | ||||
|   | ||||
| @@ -110,9 +110,8 @@ void GcodeSuite::G35() { | ||||
|     tool_change(0, true); | ||||
|   #endif | ||||
|  | ||||
|   #if HAS_DUPLICATION_MODE | ||||
|     extruder_duplication_enabled = false; | ||||
|   #endif | ||||
|   // Disable duplication mode on homing | ||||
|   TERN_(HAS_DUPLICATION_MODE, set_duplication_enabled(false)); | ||||
|  | ||||
|   // Home all before this procedure | ||||
|   home_all_axes(); | ||||
|   | ||||
| @@ -134,8 +134,8 @@ | ||||
|  | ||||
|       if (DEBUGGING(LEVELING)) DEBUG_POS("home_z_safely", destination); | ||||
|  | ||||
|       // This causes the carriage on Dual X to unpark | ||||
|       TERN_(DUAL_X_CARRIAGE, active_extruder_parked = false); | ||||
|       // Free the active extruder for movement | ||||
|       TERN_(DUAL_X_CARRIAGE, idex_set_parked(false)); | ||||
|  | ||||
|       TERN_(SENSORLESS_HOMING, safe_delay(500)); // Short delay needed to settle | ||||
|  | ||||
| @@ -282,7 +282,7 @@ void GcodeSuite::G28() { | ||||
|     tool_change(0, true); | ||||
|   #endif | ||||
|  | ||||
|   TERN_(HAS_DUPLICATION_MODE, extruder_duplication_enabled = false); | ||||
|   TERN_(HAS_DUPLICATION_MODE, set_duplication_enabled(false)); | ||||
|  | ||||
|   remember_feedrate_scaling_off(); | ||||
|  | ||||
| @@ -342,16 +342,14 @@ void GcodeSuite::G28() { | ||||
|         homeaxis(X_AXIS); | ||||
|  | ||||
|         // Remember this extruder's position for later tool change | ||||
|         inactive_extruder_x_pos = current_position.x; | ||||
|         inactive_extruder_x = current_position.x; | ||||
|  | ||||
|         // Home the 1st (left) extruder | ||||
|         active_extruder = 0; | ||||
|         homeaxis(X_AXIS); | ||||
|  | ||||
|         // Consider the active extruder to be parked | ||||
|         raised_parked_position = current_position; | ||||
|         delayed_move_time = 0; | ||||
|         active_extruder_parked = true; | ||||
|         // Consider the active extruder to be in its "parked" position | ||||
|         idex_set_parked(); | ||||
|  | ||||
|       #else | ||||
|  | ||||
| @@ -392,7 +390,7 @@ void GcodeSuite::G28() { | ||||
|    */ | ||||
|   #if ENABLED(DUAL_X_CARRIAGE) | ||||
|  | ||||
|     if (dxc_is_duplicating()) { | ||||
|     if (idex_is_duplicating()) { | ||||
|  | ||||
|       TERN_(IMPROVE_HOMING_RELIABILITY, slow_homing = begin_slow_homing()); | ||||
|  | ||||
| @@ -401,19 +399,17 @@ void GcodeSuite::G28() { | ||||
|       homeaxis(X_AXIS); | ||||
|  | ||||
|       // Remember this extruder's position for later tool change | ||||
|       inactive_extruder_x_pos = current_position.x; | ||||
|       inactive_extruder_x = current_position.x; | ||||
|  | ||||
|       // Home the 1st (left) extruder | ||||
|       active_extruder = 0; | ||||
|       homeaxis(X_AXIS); | ||||
|  | ||||
|       // Consider the active extruder to be parked | ||||
|       raised_parked_position = current_position; | ||||
|       delayed_move_time = 0; | ||||
|       active_extruder_parked = true; | ||||
|       extruder_duplication_enabled = IDEX_saved_duplication_state; | ||||
|       dual_x_carriage_mode         = IDEX_saved_mode; | ||||
|       stepper.set_directions(); | ||||
|       idex_set_parked(); | ||||
|  | ||||
|       dual_x_carriage_mode = IDEX_saved_mode; | ||||
|       set_duplication_enabled(IDEX_saved_duplication_state); | ||||
|  | ||||
|       TERN_(IMPROVE_HOMING_RELIABILITY, end_slow_homing(slow_homing)); | ||||
|     } | ||||
|   | ||||
| @@ -113,7 +113,7 @@ void GcodeSuite::G34() { | ||||
|       tool_change(0, true); | ||||
|     #endif | ||||
|  | ||||
|     TERN_(HAS_DUPLICATION_MODE, extruder_duplication_enabled = false); | ||||
|     TERN_(HAS_DUPLICATION_MODE, set_duplication_enabled(false)); | ||||
|  | ||||
|     // In BLTOUCH HS mode, the probe travels in a deployed state. | ||||
|     // Users of G34 might have a badly misaligned bed, so raise Z by the | ||||
|   | ||||
| @@ -68,7 +68,7 @@ | ||||
|       const DualXMode previous_mode = dual_x_carriage_mode; | ||||
|  | ||||
|       dual_x_carriage_mode = (DualXMode)parser.value_byte(); | ||||
|       mirrored_duplication_mode = false; | ||||
|       idex_set_mirrored_mode(false); | ||||
|  | ||||
|       if (dual_x_carriage_mode == DXC_MIRRORED_MODE) { | ||||
|         if (previous_mode != DXC_DUPLICATION_MODE) { | ||||
| @@ -77,8 +77,7 @@ | ||||
|           dual_x_carriage_mode = DEFAULT_DUAL_X_CARRIAGE_MODE; | ||||
|           return; | ||||
|         } | ||||
|         mirrored_duplication_mode = true; | ||||
|         stepper.set_directions(); | ||||
|         idex_set_mirrored_mode(true); | ||||
|         float x_jog = current_position.x - .1; | ||||
|         for (uint8_t i = 2; --i;) { | ||||
|           planner.buffer_line(x_jog, current_position.y, current_position.z, current_position.e, feedrate_mm_s, 0); | ||||
| @@ -102,10 +101,8 @@ | ||||
|           dual_x_carriage_mode = DEFAULT_DUAL_X_CARRIAGE_MODE; | ||||
|           break; | ||||
|       } | ||||
|       active_extruder_parked = false; | ||||
|       extruder_duplication_enabled = false; | ||||
|       stepper.set_directions(); | ||||
|       delayed_move_time = 0; | ||||
|       idex_set_parked(false); | ||||
|       set_duplication_enabled(false); | ||||
|     } | ||||
|     else if (!parser.seen('W'))  // if no S or W parameter, the DXC mode gets reset to the user's default | ||||
|       dual_x_carriage_mode = DEFAULT_DUAL_X_CARRIAGE_MODE; | ||||
| @@ -125,7 +122,7 @@ | ||||
|         if (!active_extruder_parked) DEBUG_ECHOPGM(" NOT "); | ||||
|         DEBUG_ECHOPGM(" parked."); | ||||
|         DEBUG_ECHOPAIR("\nactive_extruder_x_pos: ", current_position.x); | ||||
|         DEBUG_ECHOPAIR("\ninactive_extruder_x_pos: ", inactive_extruder_x_pos); | ||||
|         DEBUG_ECHOPAIR("\ninactive_extruder_x: ", inactive_extruder_x); | ||||
|         DEBUG_ECHOPAIR("\nextruder_duplication_enabled: ", int(extruder_duplication_enabled)); | ||||
|         DEBUG_ECHOPAIR("\nduplicate_extruder_x_offset: ", duplicate_extruder_x_offset); | ||||
|         DEBUG_ECHOPAIR("\nduplicate_extruder_temp_offset: ", duplicate_extruder_temp_offset); | ||||
| @@ -166,7 +163,7 @@ | ||||
|       if (parser.seenval('P')) duplication_e_mask = parser.value_int();   // Set the mask directly | ||||
|       else if (parser.seenval('E')) duplication_e_mask = pow(2, parser.value_int() + 1) - 1; // Set the mask by E index | ||||
|       ena = (2 == parser.intval('S', extruder_duplication_enabled ? 2 : 0)); | ||||
|       extruder_duplication_enabled = ena && (duplication_e_mask >= 3); | ||||
|       set_duplication_enabled(ena && (duplication_e_mask >= 3)); | ||||
|     } | ||||
|     SERIAL_ECHO_START(); | ||||
|     SERIAL_ECHOPGM(STR_DUPLICATION_MODE); | ||||
|   | ||||
| @@ -87,7 +87,7 @@ void GcodeSuite::M600() { | ||||
|     if (!parser.seen('T')) {  // If no tool index is specified, M600 was (probably) sent in response to filament runout. | ||||
|                               // In this case, for duplicating modes set DXC_ext to the extruder that ran out. | ||||
|       #if HAS_FILAMENT_SENSOR && NUM_RUNOUT_SENSORS > 1 | ||||
|         if (dxc_is_duplicating()) | ||||
|         if (idex_is_duplicating()) | ||||
|           DXC_ext = (READ(FIL_RUNOUT2_PIN) == FIL_RUNOUT_STATE) ? 1 : 0; | ||||
|       #else | ||||
|         DXC_ext = active_extruder; | ||||
| @@ -108,7 +108,7 @@ void GcodeSuite::M600() { | ||||
|   #if HAS_MULTI_EXTRUDER | ||||
|     // Change toolhead if specified | ||||
|     const uint8_t active_extruder_before_filament_change = active_extruder; | ||||
|     if (active_extruder != target_extruder && TERN1(DUAL_X_CARRIAGE, !dxc_is_duplicating())) | ||||
|     if (active_extruder != target_extruder && TERN1(DUAL_X_CARRIAGE, !idex_is_duplicating())) | ||||
|       tool_change(target_extruder, false); | ||||
|   #endif | ||||
|  | ||||
|   | ||||
| @@ -94,7 +94,7 @@ void GcodeSuite::M104() { | ||||
|     thermalManager.setTargetHotend(temp, target_extruder); | ||||
|  | ||||
|     #if ENABLED(DUAL_X_CARRIAGE) | ||||
|       if (dxc_is_duplicating() && target_extruder == 0) | ||||
|       if (idex_is_duplicating() && target_extruder == 0) | ||||
|         thermalManager.setTargetHotend(temp ? temp + duplicate_extruder_temp_offset : 0, 1); | ||||
|     #endif | ||||
|  | ||||
| @@ -172,7 +172,7 @@ void GcodeSuite::M109() { | ||||
|     thermalManager.setTargetHotend(temp, target_extruder); | ||||
|  | ||||
|     #if ENABLED(DUAL_X_CARRIAGE) | ||||
|       if (dxc_is_duplicating() && target_extruder == 0) | ||||
|       if (idex_is_duplicating() && target_extruder == 0) | ||||
|         thermalManager.setTargetHotend(temp ? temp + duplicate_extruder_temp_offset : 0, 1); | ||||
|     #endif | ||||
|  | ||||
|   | ||||
| @@ -62,11 +62,11 @@ const uint8_t L64XX_Marlin::index_to_dir[MAX_L64XX] = { | ||||
|   INVERT_X_DIR, INVERT_Y_DIR, INVERT_Z_DIR | ||||
|   , (INVERT_X_DIR)                            // X2 | ||||
|     #if ENABLED(X_DUAL_STEPPER_DRIVERS) | ||||
|       ^ (INVERT_X2_VS_X_DIR) | ||||
|       ^ ENABLED(INVERT_X2_VS_X_DIR) | ||||
|     #endif | ||||
|   , (INVERT_Y_DIR)                            // Y2 | ||||
|     #if ENABLED(Y_DUAL_STEPPER_DRIVERS) | ||||
|       ^ (INVERT_Y2_VS_Y_DIR) | ||||
|       ^ ENABLED(INVERT_Y2_VS_Y_DIR) | ||||
|     #endif | ||||
|   , INVERT_Z_DIR, INVERT_Z_DIR, INVERT_Z_DIR  // Z2,Z3,Z4 | ||||
|  | ||||
|   | ||||
| @@ -569,7 +569,7 @@ void restore_feedrate_and_scaling() { | ||||
|           soft_endstop.min.x = X2_MIN_POS; | ||||
|           soft_endstop.max.x = dual_max_x; | ||||
|         } | ||||
|         else if (dxc_is_duplicating()) { | ||||
|         else if (idex_is_duplicating()) { | ||||
|           // In Duplication Mode, T0 can move as far left as X1_MIN_POS | ||||
|           // but not so far to the right that T1 would move past the end | ||||
|           soft_endstop.min.x = X1_MIN_POS; | ||||
| @@ -932,8 +932,7 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) { | ||||
| #endif // !UBL_SEGMENTED | ||||
|  | ||||
| #if HAS_DUPLICATION_MODE | ||||
|   bool extruder_duplication_enabled, | ||||
|        mirrored_duplication_mode; | ||||
|   bool extruder_duplication_enabled; | ||||
|   #if ENABLED(MULTI_NOZZLE_DUPLICATION) | ||||
|     uint8_t duplication_e_mask; // = 0 | ||||
|   #endif | ||||
| @@ -942,12 +941,13 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) { | ||||
| #if ENABLED(DUAL_X_CARRIAGE) | ||||
|  | ||||
|   DualXMode dual_x_carriage_mode         = DEFAULT_DUAL_X_CARRIAGE_MODE; | ||||
|   float inactive_extruder_x_pos          = X2_MAX_POS,                    // used in mode 0 & 1 | ||||
|         duplicate_extruder_x_offset      = DEFAULT_DUPLICATION_X_OFFSET;  // used in mode 2 | ||||
|   xyz_pos_t raised_parked_position;                                       // used in mode 1 | ||||
|   bool active_extruder_parked            = false;                         // used in mode 1 & 2 | ||||
|   millis_t delayed_move_time             = 0;                             // used in mode 1 | ||||
|   int16_t duplicate_extruder_temp_offset = 0;                             // used in mode 2 | ||||
|   float inactive_extruder_x              = X2_MAX_POS,                    // Used in mode 0 & 1 | ||||
|         duplicate_extruder_x_offset      = DEFAULT_DUPLICATION_X_OFFSET;  // Used in mode 2 | ||||
|   xyz_pos_t raised_parked_position;                                       // Used in mode 1 | ||||
|   bool active_extruder_parked            = false;                         // Used in mode 1 & 2 | ||||
|   millis_t delayed_move_time             = 0;                             // Used in mode 1 | ||||
|   int16_t duplicate_extruder_temp_offset = 0;                             // Used in mode 2 | ||||
|   bool idex_mirrored_mode                = false;                         // Used in mode 3 | ||||
|  | ||||
|   float x_home_pos(const uint8_t extruder) { | ||||
|     if (extruder == 0) | ||||
| @@ -962,6 +962,23 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) { | ||||
|       return hotend_offset[1].x > 0 ? hotend_offset[1].x : X2_HOME_POS; | ||||
|   } | ||||
|  | ||||
|   void idex_set_mirrored_mode(const bool mirr) { | ||||
|     idex_mirrored_mode = mirr; | ||||
|     stepper.set_directions(); | ||||
|   } | ||||
|  | ||||
|   void set_duplication_enabled(const bool dupe, const int8_t tool_index/*=-1*/) { | ||||
|     extruder_duplication_enabled = dupe; | ||||
|     if (tool_index >= 0) active_extruder = tool_index; | ||||
|     stepper.set_directions(); | ||||
|   } | ||||
|  | ||||
|   void idex_set_parked(const bool park/*=true*/) { | ||||
|     delayed_move_time = 0; | ||||
|     active_extruder_parked = park; | ||||
|     if (park) raised_parked_position = current_position;  // Remember current raised toolhead position for use by unpark | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Prepare a linear move in a dual X axis setup | ||||
|    * | ||||
| @@ -970,9 +987,10 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) { | ||||
|   inline bool dual_x_carriage_unpark() { | ||||
|     if (active_extruder_parked) { | ||||
|       switch (dual_x_carriage_mode) { | ||||
|         case DXC_FULL_CONTROL_MODE: | ||||
|           break; | ||||
|         case DXC_AUTO_PARK_MODE: | ||||
|  | ||||
|         case DXC_FULL_CONTROL_MODE: break; | ||||
|  | ||||
|         case DXC_AUTO_PARK_MODE: { | ||||
|           if (current_position.e == destination.e) { | ||||
|             // This is a travel move (with no extrusion) | ||||
|             // Skip it, but keep track of the current position | ||||
| @@ -984,23 +1002,27 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) { | ||||
|               return true; | ||||
|             } | ||||
|           } | ||||
|           // unpark extruder: 1) raise, 2) move into starting XY position, 3) lower | ||||
|           // | ||||
|           // Un-park the active extruder | ||||
|           // | ||||
|           const feedRate_t fr_zfast = planner.settings.max_feedrate_mm_s[Z_AXIS]; | ||||
|           #define CURPOS current_position | ||||
|           #define RAISED raised_parked_position | ||||
|           //  1. Move to the raised parked XYZ. Presumably the tool is already at XY. | ||||
|           if (planner.buffer_line(RAISED.x, RAISED.y, RAISED.z, CURPOS.e, fr_zfast, active_extruder)) { | ||||
|             //  2. Move to the current native XY and raised Z. Presumably this is a null move. | ||||
|             if (planner.buffer_line(CURPOS.x, CURPOS.y, RAISED.z, CURPOS.e, PLANNER_XY_FEEDRATE(), active_extruder)) { | ||||
|               //  3. Lower Z back down | ||||
|               line_to_current_position(fr_zfast); | ||||
|             } | ||||
|           } | ||||
|           planner.synchronize(); // paranoia | ||||
|           stepper.set_directions(); | ||||
|  | ||||
|             #define CUR_X    current_position.x | ||||
|             #define CUR_Y    current_position.y | ||||
|             #define CUR_Z    current_position.z | ||||
|             #define CUR_E    current_position.e | ||||
|             #define RAISED_X raised_parked_position.x | ||||
|             #define RAISED_Y raised_parked_position.y | ||||
|             #define RAISED_Z raised_parked_position.z | ||||
|           idex_set_parked(false); | ||||
|           if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("idex_set_parked(false)"); | ||||
|         } break; | ||||
|  | ||||
|             if (  planner.buffer_line(RAISED_X, RAISED_Y, RAISED_Z, CUR_E, planner.settings.max_feedrate_mm_s[Z_AXIS], active_extruder)) | ||||
|               if (planner.buffer_line(   CUR_X,    CUR_Y, RAISED_Z, CUR_E, PLANNER_XY_FEEDRATE(),             active_extruder)) | ||||
|                   line_to_current_position(planner.settings.max_feedrate_mm_s[Z_AXIS]); | ||||
|           delayed_move_time = 0; | ||||
|           active_extruder_parked = false; | ||||
|           if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Clear active_extruder_parked"); | ||||
|           break; | ||||
|         case DXC_MIRRORED_MODE: | ||||
|         case DXC_DUPLICATION_MODE: | ||||
|           if (active_extruder == 0) { | ||||
| @@ -1008,22 +1030,23 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) { | ||||
|             if (dual_x_carriage_mode == DXC_DUPLICATION_MODE) | ||||
|               new_pos.x += duplicate_extruder_x_offset; | ||||
|             else | ||||
|               new_pos.x = inactive_extruder_x_pos; | ||||
|             // move duplicate extruder into correct duplication position. | ||||
|             if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("Set planner X", inactive_extruder_x_pos, " ... Line to X", new_pos.x); | ||||
|             planner.set_position_mm(inactive_extruder_x_pos, current_position.y, current_position.z, current_position.e); | ||||
|               new_pos.x = inactive_extruder_x; | ||||
|             // Move duplicate extruder into correct duplication position. | ||||
|             if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("Set planner X", inactive_extruder_x, " ... Line to X", new_pos.x); | ||||
|             planner.set_position_mm(inactive_extruder_x, current_position.y, current_position.z, current_position.e); | ||||
|             if (!planner.buffer_line(new_pos, planner.settings.max_feedrate_mm_s[X_AXIS], 1)) break; | ||||
|  | ||||
|             planner.synchronize(); | ||||
|             sync_plan_position(); | ||||
|             extruder_duplication_enabled = true; | ||||
|             active_extruder_parked = false; | ||||
|             if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Set extruder_duplication_enabled\nClear active_extruder_parked"); | ||||
|  | ||||
|             set_duplication_enabled(true); | ||||
|             idex_set_parked(false); | ||||
|             if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("set_duplication_enabled(true)\nidex_set_parked(false)"); | ||||
|           } | ||||
|           else if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Active extruder not 0"); | ||||
|           break; | ||||
|       } | ||||
|     } | ||||
|     stepper.set_directions(); | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -384,8 +384,7 @@ bool homing_needed_error(uint8_t axis_bits=0x07); | ||||
|  * Duplication mode | ||||
|  */ | ||||
| #if HAS_DUPLICATION_MODE | ||||
|   extern bool extruder_duplication_enabled,       // Used in Dual X mode 2 | ||||
|               mirrored_duplication_mode;          // Used in Dual X mode 3 | ||||
|   extern bool extruder_duplication_enabled;       // Used in Dual X mode 2 | ||||
|   #if ENABLED(MULTI_NOZZLE_DUPLICATION) | ||||
|     extern uint8_t duplication_e_mask; | ||||
|   #endif | ||||
| @@ -404,23 +403,29 @@ bool homing_needed_error(uint8_t axis_bits=0x07); | ||||
|   }; | ||||
|  | ||||
|   extern DualXMode dual_x_carriage_mode; | ||||
|   extern float inactive_extruder_x_pos,           // Used in mode 0 & 1 | ||||
|   extern float inactive_extruder_x,               // Used in mode 0 & 1 | ||||
|                duplicate_extruder_x_offset;       // Used in mode 2 & 3 | ||||
|   extern xyz_pos_t raised_parked_position;        // Used in mode 1 | ||||
|   extern bool active_extruder_parked;             // Used in mode 1, 2 & 3 | ||||
|   extern millis_t delayed_move_time;              // Used in mode 1 | ||||
|   extern int16_t duplicate_extruder_temp_offset;  // Used in mode 2 & 3 | ||||
|   extern bool idex_mirrored_mode;                 // Used in mode 3 | ||||
|  | ||||
|   FORCE_INLINE bool dxc_is_duplicating() { return dual_x_carriage_mode >= DXC_DUPLICATION_MODE; } | ||||
|   FORCE_INLINE bool idex_is_duplicating() { return dual_x_carriage_mode >= DXC_DUPLICATION_MODE; } | ||||
|  | ||||
|   float x_home_pos(const uint8_t extruder); | ||||
|  | ||||
|   FORCE_INLINE int x_home_dir(const uint8_t extruder) { return extruder ? X2_HOME_DIR : X_HOME_DIR; } | ||||
|  | ||||
|   void set_duplication_enabled(const bool dupe, const int8_t tool_index=-1); | ||||
|   void idex_set_mirrored_mode(const bool mirr); | ||||
|   void idex_set_parked(const bool park=true); | ||||
|  | ||||
| #else | ||||
|  | ||||
|   #if ENABLED(MULTI_NOZZLE_DUPLICATION) | ||||
|     enum DualXMode : char { DXC_DUPLICATION_MODE = 2 }; | ||||
|     FORCE_INLINE void set_duplication_enabled(const bool dupe) { extruder_duplication_enabled = dupe; } | ||||
|   #endif | ||||
|  | ||||
|   FORCE_INLINE int x_home_dir(const uint8_t) { return home_dir(X_AXIS); } | ||||
|   | ||||
| @@ -348,7 +348,7 @@ xyze_int8_t Stepper::count_direction{0}; | ||||
|   } | ||||
|  | ||||
| #if ENABLED(X_DUAL_STEPPER_DRIVERS) | ||||
|   #define X_APPLY_DIR(v,Q) do{ X_DIR_WRITE(v); X2_DIR_WRITE((v) != INVERT_X2_VS_X_DIR); }while(0) | ||||
|   #define X_APPLY_DIR(v,Q) do{ X_DIR_WRITE(v); X2_DIR_WRITE((v) ^ ENABLED(INVERT_X2_VS_X_DIR)); }while(0) | ||||
|   #if ENABLED(X_DUAL_ENDSTOPS) | ||||
|     #define X_APPLY_STEP(v,Q) DUAL_ENDSTOP_APPLY_STEP(X,v) | ||||
|   #else | ||||
| @@ -356,7 +356,7 @@ xyze_int8_t Stepper::count_direction{0}; | ||||
|   #endif | ||||
| #elif ENABLED(DUAL_X_CARRIAGE) | ||||
|   #define X_APPLY_DIR(v,ALWAYS) do{ \ | ||||
|     if (extruder_duplication_enabled || ALWAYS) { X_DIR_WRITE(v); X2_DIR_WRITE(mirrored_duplication_mode ? !(v) : v); } \ | ||||
|     if (extruder_duplication_enabled || ALWAYS) { X_DIR_WRITE(v); X2_DIR_WRITE((v) ^ idex_mirrored_mode); } \ | ||||
|     else if (last_moved_extruder) X2_DIR_WRITE(v); else X_DIR_WRITE(v); \ | ||||
|   }while(0) | ||||
|   #define X_APPLY_STEP(v,ALWAYS) do{ \ | ||||
| @@ -369,7 +369,7 @@ xyze_int8_t Stepper::count_direction{0}; | ||||
| #endif | ||||
|  | ||||
| #if ENABLED(Y_DUAL_STEPPER_DRIVERS) | ||||
|   #define Y_APPLY_DIR(v,Q) do{ Y_DIR_WRITE(v); Y2_DIR_WRITE((v) != INVERT_Y2_VS_Y_DIR); }while(0) | ||||
|   #define Y_APPLY_DIR(v,Q) do{ Y_DIR_WRITE(v); Y2_DIR_WRITE((v) ^ ENABLED(INVERT_Y2_VS_Y_DIR)); }while(0) | ||||
|   #if ENABLED(Y_DUAL_ENDSTOPS) | ||||
|     #define Y_APPLY_STEP(v,Q) DUAL_ENDSTOP_APPLY_STEP(Y,v) | ||||
|   #else | ||||
| @@ -1605,10 +1605,9 @@ void Stepper::pulse_phase_isr() { | ||||
|               PAGE_SEGMENT_UPDATE(Z, high >> 4); | ||||
|               PAGE_SEGMENT_UPDATE(E, high & 0xF); | ||||
|  | ||||
|               if (dm != last_direction_bits) { | ||||
|                 last_direction_bits = dm; | ||||
|                 set_directions(); | ||||
|               } | ||||
|               if (dm != last_direction_bits) | ||||
|                 set_directions(dm); | ||||
|  | ||||
|             } break; | ||||
|  | ||||
|             default: break; | ||||
| @@ -2131,9 +2130,7 @@ uint32_t Stepper::block_phase_isr() { | ||||
|         MIXER_STEPPER_SETUP(); | ||||
|       #endif | ||||
|  | ||||
|       #if HAS_MULTI_EXTRUDER | ||||
|         stepper_extruder = current_block->extruder; | ||||
|       #endif | ||||
|       TERN_(HAS_MULTI_EXTRUDER, stepper_extruder = current_block->extruder); | ||||
|  | ||||
|       // Initialize the trapezoid generator from the current block. | ||||
|       #if ENABLED(LIN_ADVANCE) | ||||
| @@ -2151,17 +2148,14 @@ uint32_t Stepper::block_phase_isr() { | ||||
|         else LA_isr_rate = LA_ADV_NEVER; | ||||
|       #endif | ||||
|  | ||||
|       if ( ENABLED(HAS_L64XX)  // Always set direction for L64xx (Also enables the chips) | ||||
|       if ( ENABLED(HAS_L64XX)       // Always set direction for L64xx (Also enables the chips) | ||||
|         || ENABLED(DUAL_X_CARRIAGE) // TODO: Find out why this fixes "jittery" small circles | ||||
|         || current_block->direction_bits != last_direction_bits | ||||
|         || TERN(MIXING_EXTRUDER, false, stepper_extruder != last_moved_extruder) | ||||
|       ) { | ||||
|         last_direction_bits = current_block->direction_bits; | ||||
|         #if HAS_MULTI_EXTRUDER | ||||
|           last_moved_extruder = stepper_extruder; | ||||
|         #endif | ||||
|  | ||||
|         TERN_(HAS_MULTI_EXTRUDER, last_moved_extruder = stepper_extruder); | ||||
|         TERN_(HAS_L64XX, L64XX_OK_to_power_up = true); | ||||
|         set_directions(); | ||||
|         set_directions(current_block->direction_bits); | ||||
|       } | ||||
|  | ||||
|       #if ENABLED(LASER_POWER_INLINE) | ||||
| @@ -2583,12 +2577,9 @@ void Stepper::init() { | ||||
|   #endif | ||||
|  | ||||
|   // Init direction bits for first moves | ||||
|   last_direction_bits = 0 | ||||
|     | (INVERT_X_DIR ? _BV(X_AXIS) : 0) | ||||
|     | (INVERT_Y_DIR ? _BV(Y_AXIS) : 0) | ||||
|     | (INVERT_Z_DIR ? _BV(Z_AXIS) : 0); | ||||
|  | ||||
|   set_directions(); | ||||
|   set_directions((INVERT_X_DIR ? _BV(X_AXIS) : 0) | ||||
|                | (INVERT_Y_DIR ? _BV(Y_AXIS) : 0) | ||||
|                | (INVERT_Z_DIR ? _BV(Z_AXIS) : 0)); | ||||
|  | ||||
|   #if HAS_MOTOR_CURRENT_SPI || HAS_MOTOR_CURRENT_PWM | ||||
|     initialized = true; | ||||
|   | ||||
| @@ -514,9 +514,15 @@ class Stepper { | ||||
|       static void refresh_motor_power(); | ||||
|     #endif | ||||
|  | ||||
|     // Set direction bits for all steppers | ||||
|     // Update direction states for all steppers | ||||
|     static void set_directions(); | ||||
|  | ||||
|     // Set direction bits and update all stepper DIR states | ||||
|     static void set_directions(const uint8_t bits) { | ||||
|       last_direction_bits = bits; | ||||
|       set_directions(); | ||||
|     } | ||||
|  | ||||
|   private: | ||||
|  | ||||
|     // Set the current position in steps | ||||
|   | ||||
| @@ -61,6 +61,10 @@ | ||||
|   #include "../gcode/gcode.h" | ||||
| #endif | ||||
|  | ||||
| #if ENABLED(DUAL_X_CARRIAGE) | ||||
|   #include "stepper.h" | ||||
| #endif | ||||
|  | ||||
| #if ANY(SWITCHING_EXTRUDER, SWITCHING_NOZZLE, SWITCHING_TOOLHEAD) | ||||
|   #include "servo.h" | ||||
| #endif | ||||
| @@ -701,6 +705,13 @@ inline void fast_line_to_current(const AxisEnum fr_axis) { _line_to_current(fr_a | ||||
|  | ||||
| #if ENABLED(DUAL_X_CARRIAGE) | ||||
|  | ||||
|   /** | ||||
|    * @brief Dual X Tool Change | ||||
|    * @details Change tools, with extra behavior based on current mode | ||||
|    * | ||||
|    * @param new_tool Tool index to activate | ||||
|    * @param no_move Flag indicating no moves should take place | ||||
|    */ | ||||
|   inline void dualx_tool_change(const uint8_t new_tool, bool &no_move) { | ||||
|  | ||||
|     DEBUG_ECHOPGM("Dual X Carriage Mode "); | ||||
| @@ -711,17 +722,16 @@ inline void fast_line_to_current(const AxisEnum fr_axis) { _line_to_current(fr_a | ||||
|       case DXC_MIRRORED_MODE:     DEBUG_ECHOLNPGM("MIRRORED");     break; | ||||
|     } | ||||
|  | ||||
|     // Get the home position of the currently-active tool | ||||
|     const float xhome = x_home_pos(active_extruder); | ||||
|     if (dual_x_carriage_mode == DXC_AUTO_PARK_MODE | ||||
|         && IsRunning() && !no_move | ||||
|         && (delayed_move_time || current_position.x != xhome) | ||||
|  | ||||
|     if (dual_x_carriage_mode == DXC_AUTO_PARK_MODE                  // If Auto-Park mode is enabled | ||||
|         && IsRunning() && !no_move                                  // ...and movement is permitted | ||||
|         && (delayed_move_time || current_position.x != xhome)       // ...and delayed_move_time is set OR not "already parked"... | ||||
|     ) { | ||||
|  | ||||
|       DEBUG_ECHOLNPAIR("MoveX to ", xhome); | ||||
|  | ||||
|       // Park old head | ||||
|       current_position.x = xhome; | ||||
|       line_to_current_position(planner.settings.max_feedrate_mm_s[X_AXIS]); | ||||
|       line_to_current_position(planner.settings.max_feedrate_mm_s[X_AXIS]);   // Park the current head | ||||
|       planner.synchronize(); | ||||
|     } | ||||
|  | ||||
| @@ -736,20 +746,21 @@ inline void fast_line_to_current(const AxisEnum fr_axis) { _line_to_current(fr_a | ||||
|     switch (dual_x_carriage_mode) { | ||||
|       case DXC_FULL_CONTROL_MODE: | ||||
|         // New current position is the position of the activated extruder | ||||
|         current_position.x = inactive_extruder_x_pos; | ||||
|         current_position.x = inactive_extruder_x; | ||||
|         // Save the inactive extruder's position (from the old current_position) | ||||
|         inactive_extruder_x_pos = destination.x; | ||||
|         inactive_extruder_x = destination.x; | ||||
|         DEBUG_ECHOLNPAIR("DXC Full Control curr.x=", current_position.x, " dest.x=", destination.x); | ||||
|         break; | ||||
|       case DXC_AUTO_PARK_MODE: | ||||
|         // record current raised toolhead position for use by unpark | ||||
|         raised_parked_position = current_position; | ||||
|         active_extruder_parked = true; | ||||
|         delayed_move_time = 0; | ||||
|         idex_set_parked(); | ||||
|         break; | ||||
|       default: | ||||
|         break; | ||||
|     } | ||||
|  | ||||
|     // Ensure X axis DIR pertains to the correct carriage | ||||
|     stepper.set_directions(); | ||||
|  | ||||
|     DEBUG_ECHOLNPAIR("Active extruder parked: ", active_extruder_parked ? "yes" : "no"); | ||||
|     DEBUG_POS("New extruder (parked)", current_position); | ||||
|   } | ||||
| @@ -875,7 +886,7 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) { | ||||
|     planner.synchronize(); | ||||
|  | ||||
|     #if ENABLED(DUAL_X_CARRIAGE)  // Only T0 allowed if the Printer is in DXC_DUPLICATION_MODE or DXC_MIRRORED_MODE | ||||
|       if (new_tool != 0 && dxc_is_duplicating()) | ||||
|       if (new_tool != 0 && idex_is_duplicating()) | ||||
|          return invalid_extruder_error(new_tool); | ||||
|     #endif | ||||
|  | ||||
| @@ -1151,7 +1162,7 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) { | ||||
|           } | ||||
|         #endif | ||||
|  | ||||
|         TERN_(DUAL_X_CARRIAGE, active_extruder_parked = false); | ||||
|         TERN_(DUAL_X_CARRIAGE, idex_set_parked(false)); | ||||
|       } | ||||
|  | ||||
|       #if ENABLED(SWITCHING_NOZZLE) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user