@ -22,7 +22,7 @@
# include "../../inc/MarlinConfig.h"
# include "../../inc/MarlinConfig.h"
# if ENABLED(PRUSA_MMU2)
# if HAS_PRUSA_MMU2
# include "mmu2.h"
# include "mmu2.h"
# include "../../lcd/menu/menu_mmu2.h"
# include "../../lcd/menu/menu_mmu2.h"
@ -94,7 +94,7 @@ MMU2 mmu2;
# define mmuSerial MMU2_SERIAL
# define mmuSerial MMU2_SERIAL
bool MMU2 : : enabled , MMU2 : : ready , MMU2 : : mmu_print_saved ;
bool MMU2 : : enabled , MMU2 : : ready , MMU2 : : mmu_print_saved ;
# if ENABLED(PRUSA_MMU2_S_MODE)
# if HAS_PRUSA_MMU2S
bool MMU2 : : mmu2s_triggered ;
bool MMU2 : : mmu2s_triggered ;
# endif
# endif
uint8_t MMU2 : : cmd , MMU2 : : cmd_arg , MMU2 : : last_cmd , MMU2 : : extruder ;
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 ;
millis_t MMU2 : : prev_request , MMU2 : : prev_P0_request ;
char MMU2 : : rx_buffer [ MMU_RX_SIZE ] , MMU2 : : tx_buffer [ MMU_TX_SIZE ] ;
char MMU2 : : rx_buffer [ MMU_RX_SIZE ] , MMU2 : : tx_buffer [ MMU_TX_SIZE ] ;
# if BOTH(HAS_LCD_MENU, MMU2_MENUS)
struct E_Step {
struct E_Step {
float extrude ; //!< extrude distance in mm
float extrude ; //!< extrude distance in mm
feedRate_t feedRate ; //!< feed rate in mm/s
feedRate_t feedRate ; //!< feed rate in mm/s
} ;
} ;
static constexpr E_Step
static constexpr E_Step
ramming_sequence [ ] PROGMEM = { MMU2_RAMMING_SEQUENCE }
ramming_sequence [ ] PROGMEM = { MMU2_RAMMING_SEQUENCE }
, load_to_nozzle_sequence [ ] PROGMEM = { MMU2_LOAD_TO_NOZZLE_SEQUENCE }
, load_to_nozzle_sequence [ ] PROGMEM = { MMU2_LOAD_TO_NOZZLE_SEQUENCE }
# if ENABLED(PRUSA_MMU2_S_MODE)
# if HAS_PRUSA_MMU2S
, can_load_sequence [ ] PROGMEM = { MMU2_CAN_LOAD_SEQUENCE }
, can_load_sequence [ ] PROGMEM = { MMU2_CAN_LOAD_SEQUENCE }
, can_load_increment_sequence [ ] PROGMEM = { MMU2_CAN_LOAD_INCREMENT_SEQUENCE }
, can_load_increment_sequence [ ] PROGMEM = { MMU2_CAN_LOAD_INCREMENT_SEQUENCE }
# endif
# endif
;
;
# endif // MMU2_MENUS
MMU2 : : MMU2 ( ) {
MMU2 : : MMU2 ( ) {
rx_buffer [ 0 ] = ' \0 ' ;
rx_buffer [ 0 ] = ' \0 ' ;
@ -162,7 +158,7 @@ uint8_t MMU2::get_current_tool() {
return extruder = = MMU2_NO_TOOL ? - 1 : extruder ;
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)
# define FILAMENT_PRESENT() (READ(FIL_RUNOUT1_PIN) != FIL_RUNOUT1_STATE)
# endif
# endif
@ -188,7 +184,7 @@ void MMU2::mmu_loop() {
case - 2 :
case - 2 :
if ( rx_ok ( ) ) {
if ( rx_ok ( ) ) {
sscanf ( rx_buffer , " %uok \n " , & version ) ;
sscanf ( rx_buffer , " %h uok \n " , & version ) ;
DEBUG_ECHOLNPAIR ( " MMU => " , version , " \n MMU <= 'S2' " ) ;
DEBUG_ECHOLNPAIR ( " MMU => " , version , " \n MMU <= 'S2' " ) ;
@ -199,7 +195,7 @@ void MMU2::mmu_loop() {
case - 3 :
case - 3 :
if ( rx_ok ( ) ) {
if ( rx_ok ( ) ) {
sscanf ( rx_buffer , " %uok \n " , & buildnr ) ;
sscanf ( rx_buffer , " %h uok \n " , & buildnr ) ;
DEBUG_ECHOLNPAIR ( " MMU => " , buildnr ) ;
DEBUG_ECHOLNPAIR ( " MMU => " , buildnr ) ;
@ -242,7 +238,7 @@ void MMU2::mmu_loop() {
enabled = true ;
enabled = true ;
state = 1 ;
state = 1 ;
TERN_ ( PRUSA_MMU2_ S_MODE , mmu2s_triggered = false ) ;
TERN_ ( HAS_ PRUSA_MMU2S, mmu2s_triggered = false ) ;
}
}
break ;
break ;
@ -307,7 +303,7 @@ void MMU2::mmu_loop() {
state = 2 ; // wait for response
state = 2 ; // wait for response
}
}
TERN_ ( PRUSA_MMU2_ S_MODE , check_filament ( ) ) ;
TERN_ ( HAS_ PRUSA_MMU2S, check_filament ( ) ) ;
break ;
break ;
case 2 : // response to command P0
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)
else if ( ELAPSED ( millis ( ) , prev_request + MMU_P0_TIMEOUT ) ) // Resend request after timeout (3s)
state = 1 ;
state = 1 ;
TERN_ ( PRUSA_MMU2_ S_MODE , check_filament ( ) ) ;
TERN_ ( HAS_ PRUSA_MMU2S, check_filament ( ) ) ;
break ;
break ;
case 3 : // response to mmu commands
case 3 : // response to mmu commands
@ -340,9 +336,9 @@ void MMU2::mmu_loop() {
# endif
# endif
if ( rx_ok ( ) ) {
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 ;
bool can_reset = true ;
# if ENABLED(PRUSA_MMU2_S_MODE)
# if HAS_PRUSA_MMU2S
if ( ! mmu2s_triggered & & last_cmd = = MMU_CMD_C0 ) {
if ( ! mmu2s_triggered & & last_cmd = = MMU_CMD_C0 ) {
can_reset = false ;
can_reset = false ;
// MMU ok received but filament sensor not triggered, retrying...
// MMU ok received but filament sensor not triggered, retrying...
@ -367,7 +363,7 @@ void MMU2::mmu_loop() {
}
}
state = 1 ;
state = 1 ;
}
}
TERN_ ( PRUSA_MMU2_ S_MODE , check_filament ( ) ) ;
TERN_ ( HAS_ PRUSA_MMU2S, check_filament ( ) ) ;
break ;
break ;
}
}
}
}
@ -487,7 +483,7 @@ static void mmu2_not_responding() {
BUZZ ( 100 , 659 ) ;
BUZZ ( 100 , 659 ) ;
}
}
# if ENABLED(PRUSA_MMU2_S_MODE)
# if HAS_PRUSA_MMU2S
bool MMU2 : : load_to_gears ( ) {
bool MMU2 : : load_to_gears ( ) {
command ( MMU_CMD_C0 ) ;
command ( MMU_CMD_C0 ) ;
@ -541,23 +537,25 @@ static void mmu2_not_responding() {
* Tc Load to nozzle after filament was prepared by Tx and extruder nozzle is already heated .
* Tc Load to nozzle after filament was prepared by Tx and extruder nozzle is already heated .
*/
*/
void MMU2 : : tool_change ( const char * special ) {
void MMU2 : : tool_change ( const char * special ) {
if ( ! enabled ) return ;
if ( ! enabled ) return ;
# if ENABLED(MMU2_MENUS)
set_runout_valid ( false ) ;
set_runout_valid ( false ) ;
switch ( * special ) {
switch ( * special ) {
case ' ? ' : {
case ' ? ' : {
uint8_t index = mmu2_choose_filament ( ) ;
# if ENABLED(MMU2_MENUS)
const uint8_t index = mmu2_choose_filament ( ) ;
while ( ! thermalManager . wait_for_hotend ( active_extruder , false ) ) safe_delay ( 100 ) ;
while ( ! thermalManager . wait_for_hotend ( active_extruder , false ) ) safe_delay ( 100 ) ;
load_filament_to_nozzle ( index ) ;
load_filament_to_nozzle ( index ) ;
# else
BUZZ ( 400 , 40 ) ;
# endif
} break ;
} break ;
case ' x ' : {
case ' x ' : {
# if ENABLED(MMU2_MENUS)
planner . synchronize ( ) ;
planner . synchronize ( ) ;
uint8_t index = mmu2_choose_filament ( ) ;
const uint8_t index = mmu2_choose_filament ( ) ;
DISABLE_AXIS_E0 ( ) ;
DISABLE_AXIS_E0 ( ) ;
command ( MMU_CMD_T0 + index ) ;
command ( MMU_CMD_T0 + index ) ;
manage_response ( true , true ) ;
manage_response ( true , true ) ;
@ -568,6 +566,9 @@ static void mmu2_not_responding() {
extruder = index ;
extruder = index ;
active_extruder = 0 ;
active_extruder = 0 ;
}
}
# else
BUZZ ( 400 , 40 ) ;
# endif
} break ;
} break ;
case ' c ' : {
case ' c ' : {
@ -577,8 +578,6 @@ static void mmu2_not_responding() {
}
}
set_runout_valid ( true ) ;
set_runout_valid ( true ) ;
# endif // MMU2_MENUS
}
}
# elif ENABLED(MMU_EXTRUDER_SENSOR)
# elif ENABLED(MMU_EXTRUDER_SENSOR)
@ -628,20 +627,23 @@ static void mmu2_not_responding() {
void MMU2 : : tool_change ( const char * special ) {
void MMU2 : : tool_change ( const char * special ) {
if ( ! enabled ) return ;
if ( ! enabled ) return ;
# if ENABLED(MMU2_MENUS)
set_runout_valid ( false ) ;
set_runout_valid ( false ) ;
switch ( * special ) {
switch ( * special ) {
case ' ? ' : {
case ' ? ' : {
DEBUG_ECHOLNPGM ( " case ? \n " ) ;
DEBUG_ECHOLNPGM ( " case ? \n " ) ;
# if ENABLED(MMU2_MENUS)
uint8_t index = mmu2_choose_filament ( ) ;
uint8_t index = mmu2_choose_filament ( ) ;
while ( ! thermalManager . wait_for_hotend ( active_extruder , false ) ) safe_delay ( 100 ) ;
while ( ! thermalManager . wait_for_hotend ( active_extruder , false ) ) safe_delay ( 100 ) ;
load_filament_to_nozzle ( index ) ;
load_filament_to_nozzle ( index ) ;
# else
BUZZ ( 400 , 40 ) ;
# endif
} break ;
} break ;
case ' x ' : {
case ' x ' : {
DEBUG_ECHOLNPGM ( " case x \n " ) ;
DEBUG_ECHOLNPGM ( " case x \n " ) ;
# if ENABLED(MMU2_MENUS)
planner . synchronize ( ) ;
planner . synchronize ( ) ;
uint8_t index = mmu2_choose_filament ( ) ;
uint8_t index = mmu2_choose_filament ( ) ;
DISABLE_AXIS_E0 ( ) ;
DISABLE_AXIS_E0 ( ) ;
@ -654,6 +656,9 @@ static void mmu2_not_responding() {
ENABLE_AXIS_E0 ( ) ;
ENABLE_AXIS_E0 ( ) ;
extruder = index ;
extruder = index ;
active_extruder = 0 ;
active_extruder = 0 ;
# else
BUZZ ( 400 , 40 ) ;
# endif
} break ;
} break ;
case ' c ' : {
case ' c ' : {
@ -664,8 +669,6 @@ static void mmu2_not_responding() {
}
}
set_runout_valid ( true ) ;
set_runout_valid ( true ) ;
# endif // MMU2_MENUS
}
}
void MMU2 : : mmu_continue_loading ( ) {
void MMU2 : : mmu_continue_loading ( ) {
@ -682,12 +685,12 @@ static void mmu2_not_responding() {
mmu_idl_sens = 0 ;
mmu_idl_sens = 0 ;
}
}
# elif DISABLED(MMU_EXTRUDER_SENSOR) && DISABLED(PRUSA_MMU2_S_MODE)
# else // !HAS_PRUSA_MMU2S && !MMU_EXTRUDER_SENSOR
/**
/**
* Handle tool change
* Handle tool change
*/
*/
void MMU2 : : tool_change ( const uint8_t index ) {
void MMU2 : : tool_change ( const uint8_t index ) {
if ( ! enabled ) return ;
if ( ! enabled ) return ;
set_runout_valid ( false ) ;
set_runout_valid ( false ) ;
@ -707,32 +710,35 @@ void MMU2::tool_change(const uint8_t index) {
}
}
set_runout_valid ( true ) ;
set_runout_valid ( true ) ;
}
}
/**
/**
* Handle special T ? / Tx / Tc commands
* Handle special T ? / Tx / Tc commands
*
*
* T ? Gcode to extrude shouldn ' t have to follow , load to extruder wheels is done automatically
* 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 .
* 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 .
* Tc Load to nozzle after filament was prepared by Tx and extruder nozzle is already heated .
*/
*/
void MMU2 : : tool_change ( const char * special ) {
void MMU2 : : tool_change ( const char * special ) {
if ( ! enabled ) return ;
if ( ! enabled ) return ;
# if ENABLED(MMU2_MENUS)
set_runout_valid ( false ) ;
set_runout_valid ( false ) ;
switch ( * special ) {
switch ( * special ) {
case ' ? ' : {
case ' ? ' : {
DEBUG_ECHOLNPGM ( " case ? \n " ) ;
DEBUG_ECHOLNPGM ( " case ? \n " ) ;
# if ENABLED(MMU2_MENUS)
uint8_t index = mmu2_choose_filament ( ) ;
uint8_t index = mmu2_choose_filament ( ) ;
while ( ! thermalManager . wait_for_hotend ( active_extruder , false ) ) safe_delay ( 100 ) ;
while ( ! thermalManager . wait_for_hotend ( active_extruder , false ) ) safe_delay ( 100 ) ;
load_filament_to_nozzle ( index ) ;
load_filament_to_nozzle ( index ) ;
# else
BUZZ ( 400 , 40 ) ;
# endif
} break ;
} break ;
case ' x ' : {
case ' x ' : {
DEBUG_ECHOLNPGM ( " case x \n " ) ;
DEBUG_ECHOLNPGM ( " case x \n " ) ;
# if ENABLED(MMU2_MENUS)
planner . synchronize ( ) ;
planner . synchronize ( ) ;
uint8_t index = mmu2_choose_filament ( ) ;
uint8_t index = mmu2_choose_filament ( ) ;
DISABLE_AXIS_E0 ( ) ;
DISABLE_AXIS_E0 ( ) ;
@ -744,6 +750,9 @@ void MMU2::tool_change(const char* special) {
ENABLE_AXIS_E0 ( ) ;
ENABLE_AXIS_E0 ( ) ;
extruder = index ;
extruder = index ;
active_extruder = 0 ;
active_extruder = 0 ;
# else
BUZZ ( 400 , 40 ) ;
# endif
} break ;
} break ;
case ' c ' : {
case ' c ' : {
@ -754,11 +763,9 @@ void MMU2::tool_change(const char* special) {
}
}
set_runout_valid ( true ) ;
set_runout_valid ( true ) ;
# endif
}
}
# endif // MMU_EXTRUDER_SENSOR
# endif // HAS_PRUSA_MMU2S
/**
/**
* Set next command
* Set next command
@ -866,7 +873,7 @@ void MMU2::filament_runout() {
planner . synchronize ( ) ;
planner . synchronize ( ) ;
}
}
# if ENABLED(PRUSA_MMU2_S_MODE)
# if HAS_PRUSA_MMU2S
void MMU2 : : check_filament ( ) {
void MMU2 : : check_filament ( ) {
const bool present = FILAMENT_PRESENT ( ) ;
const bool present = FILAMENT_PRESENT ( ) ;
@ -907,22 +914,21 @@ void MMU2::filament_runout() {
DEBUG_ECHOLNPGM ( " succeeded. " ) ;
DEBUG_ECHOLNPGM ( " succeeded. " ) ;
return true ;
return true ;
}
}
# endif
# if BOTH(HAS_LCD_MENU, MMU2_MENUS)
# end if
// Load filament into MMU2
// Load filament into MMU2
void MMU2 : : load_filament ( const uint8_t index ) {
void MMU2 : : load_filament ( const uint8_t index ) {
if ( ! enabled ) return ;
if ( ! enabled ) return ;
command ( MMU_CMD_L0 + index ) ;
command ( MMU_CMD_L0 + index ) ;
manage_response ( false , false ) ;
manage_response ( false , false ) ;
BUZZ ( 200 , 404 ) ;
BUZZ ( 200 , 404 ) ;
}
}
/**
/**
* Switch material and load to nozzle
* Switch material and load to nozzle
*/
*/
bool MMU2 : : load_filament_to_nozzle ( const uint8_t index ) {
bool MMU2 : : load_filament_to_nozzle ( const uint8_t index ) {
if ( ! enabled ) return false ;
if ( ! enabled ) return false ;
@ -944,21 +950,21 @@ void MMU2::filament_runout() {
BUZZ ( 200 , 404 ) ;
BUZZ ( 200 , 404 ) ;
}
}
return success ;
return success ;
}
}
/**
/**
* Load filament to nozzle of multimaterial printer
* Load filament to nozzle of multimaterial printer
*
*
* This function is used only only after T ? ( user select filament ) and M600 ( change filament ) .
* 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
* It is not used after T0 . . T4 command ( select filament ) , in such case , gcode is responsible for loading
* filament to nozzle .
* filament to nozzle .
*/
*/
void MMU2 : : load_to_nozzle ( ) {
void MMU2 : : load_to_nozzle ( ) {
if ( ! enabled ) return ;
if ( ! enabled ) return ;
execute_extruder_sequence ( ( const E_Step * ) load_to_nozzle_sequence , COUNT ( load_to_nozzle_sequence ) ) ;
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 ) {
bool MMU2 : : eject_filament ( const uint8_t index , const bool recover ) {
if ( ! enabled ) return false ;
if ( ! enabled ) return false ;
@ -972,7 +978,7 @@ void MMU2::filament_runout() {
ENABLE_AXIS_E0 ( ) ;
ENABLE_AXIS_E0 ( ) ;
current_position . e - = MMU2_FILAMENTCHANGE_EJECT_FEED ;
current_position . e - = MMU2_FILAMENTCHANGE_EJECT_FEED ;
line_to_current_position ( 2500 / 60 ) ;
line_to_current_position ( MMM_TO_MMS ( 2500 ) ) ;
planner . synchronize ( ) ;
planner . synchronize ( ) ;
command ( MMU_CMD_E0 + index ) ;
command ( MMU_CMD_E0 + index ) ;
manage_response ( false , false ) ;
manage_response ( false , false ) ;
@ -1002,12 +1008,12 @@ void MMU2::filament_runout() {
DISABLE_AXIS_E0 ( ) ;
DISABLE_AXIS_E0 ( ) ;
return true ;
return true ;
}
}
/**
/**
* Unload from hotend and retract to MMU
* Unload from hotend and retract to MMU
*/
*/
bool MMU2 : : unload ( ) {
bool MMU2 : : unload ( ) {
if ( ! enabled ) return false ;
if ( ! enabled ) return false ;
@ -1030,16 +1036,16 @@ void MMU2::filament_runout() {
set_runout_valid ( false ) ;
set_runout_valid ( false ) ;
return true ;
return true ;
}
}
/**
/**
* Unload sequence to optimize shape of the tip of the unloaded filament
* Unload sequence to optimize shape of the tip of the unloaded filament
*/
*/
void MMU2 : : filament_ramming ( ) {
void MMU2 : : filament_ramming ( ) {
execute_extruder_sequence ( ( const E_Step * ) ramming_sequence , sizeof ( ramming_sequence ) / sizeof ( E_Step ) ) ;
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 ) {
void MMU2 : : execute_extruder_sequence ( const E_Step * sequence , int steps ) {
planner . synchronize ( ) ;
planner . synchronize ( ) ;
ENABLE_AXIS_E0 ( ) ;
ENABLE_AXIS_E0 ( ) ;
@ -1061,8 +1067,6 @@ void MMU2::filament_runout() {
}
}
DISABLE_AXIS_E0 ( ) ;
DISABLE_AXIS_E0 ( ) ;
}
}
# endif // HAS_LCD_MENU && MMU2_MENUS
# endif // PRUSA_MMU2
# endif // HAS_PRUSA_MMU2