2019-01-04 20:26:13 +00:00
//! @file
2018-08-02 16:54:00 +00:00
# include "mmu.h"
# include "planner.h"
# include "language.h"
# include "lcd.h"
# include "uart2.h"
# include "temperature.h"
# include "Configuration_prusa.h"
2018-08-27 02:21:43 +00:00
# include "fsensor.h"
# include "cardreader.h"
2020-10-26 07:42:26 +00:00
# include "cmdqueue.h"
2018-08-27 17:36:54 +00:00
# include "ultralcd.h"
2018-08-27 14:12:10 +00:00
# include "sound.h"
2018-10-18 00:44:16 +00:00
# include "printers.h"
2018-09-03 18:00:46 +00:00
# include <avr/pgmspace.h>
2019-01-04 20:11:42 +00:00
# include "AutoDeplete.h"
2020-09-11 14:43:38 +00:00
# include "fastio.h"
# include "pins.h"
2019-07-09 10:16:51 +00:00
//-//
# include "util.h"
2018-08-02 16:54:00 +00:00
2018-11-13 15:04:46 +00:00
# ifdef TMC2130
# include "tmc2130.h"
# endif //TMC2130
2018-08-13 17:38:55 +00:00
# define MMU_TODELAY 100
# define MMU_TIMEOUT 10
2019-02-15 13:17:47 +00:00
# define MMU_CMD_TIMEOUT 45000ul //45s timeout for mmu commands (except P0)
2018-08-26 19:39:37 +00:00
# define MMU_P0_TIMEOUT 3000ul //timeout for P0 command: 3seconds
2019-01-04 20:07:52 +00:00
# define MMU_MAX_RESEND_ATTEMPTS 2
2018-08-13 17:38:55 +00:00
2018-08-07 18:37:59 +00:00
2019-02-12 20:43:26 +00:00
namespace
{
2019-02-12 20:53:11 +00:00
enum class S : uint_least8_t
2019-02-12 20:43:26 +00:00
{
2019-02-12 20:53:11 +00:00
WaitStealthMode ,
2019-02-12 20:43:26 +00:00
GetFindaInit ,
GetBuildNr ,
GetVersion ,
Init ,
Disabled ,
Idle ,
GetFinda ,
WaitCmd , //!< wait for command response
2019-02-13 18:10:55 +00:00
Pause ,
2019-02-12 20:43:26 +00:00
GetDrvError , //!< get power failures count
2019-03-11 11:33:22 +00:00
SwitchMode //switch mmu between stealth and normal mode
2019-02-12 20:43:26 +00:00
} ;
}
2018-08-02 16:54:00 +00:00
bool mmu_enabled = false ;
2018-08-20 18:53:53 +00:00
bool mmu_ready = false ;
2018-12-12 21:32:47 +00:00
bool mmu_fil_loaded = false ; //if true: blocks execution of duplicit T-codes
2018-08-20 18:53:53 +00:00
2019-02-12 20:43:26 +00:00
static S mmu_state = S : : Disabled ;
2018-08-13 17:38:55 +00:00
2019-02-13 00:51:39 +00:00
MmuCmd mmu_cmd = MmuCmd : : None ;
2018-08-20 18:53:53 +00:00
2018-12-21 16:12:16 +00:00
//idler ir sensor
2019-03-21 18:37:34 +00:00
static uint8_t mmu_idl_sens = 0 ;
2019-01-24 00:12:30 +00:00
bool ir_sensor_detected = false ;
2019-03-21 18:37:34 +00:00
static bool mmu_loading_flag = false ; //when set to true, we assume that mmu2 unload was finished and loading phase is now performed; printer can send 'A' to mmu2 to abort loading process
2018-12-06 18:19:50 +00:00
2018-12-12 13:50:55 +00:00
uint8_t mmu_extruder = MMU_FILAMENT_UNKNOWN ;
2018-08-07 18:37:59 +00:00
2018-08-23 13:41:47 +00:00
//! This variable probably has no meaning and is planed to be removed
2018-12-12 13:50:55 +00:00
uint8_t tmp_extruder = MMU_FILAMENT_UNKNOWN ;
2018-08-13 17:38:55 +00:00
2018-08-07 18:37:59 +00:00
int8_t mmu_finda = - 1 ;
2019-10-31 16:45:22 +00:00
uint32_t mmu_last_finda_response = 0 ;
2018-08-07 18:37:59 +00:00
int16_t mmu_version = - 1 ;
2018-08-13 17:38:55 +00:00
int16_t mmu_buildnr = - 1 ;
2018-08-20 18:53:53 +00:00
uint32_t mmu_last_request = 0 ;
uint32_t mmu_last_response = 0 ;
2019-02-13 00:51:39 +00:00
MmuCmd mmu_last_cmd = MmuCmd : : None ;
2018-12-21 19:56:45 +00:00
uint16_t mmu_power_failures = 0 ;
2018-08-07 18:37:59 +00:00
2019-02-12 22:24:23 +00:00
# ifdef MMU_DEBUG
2019-06-18 17:15:16 +00:00
static const auto DEBUG_PUTCHAR = putchar ;
2019-02-12 22:24:23 +00:00
static const auto DEBUG_PUTS_P = puts_P ;
static const auto DEBUG_PRINTF_P = printf_P ;
# else //MMU_DEBUG
2019-06-18 17:15:16 +00:00
# define DEBUG_PUTCHAR(c)
2019-02-12 22:24:23 +00:00
# define DEBUG_PUTS_P(str)
# define DEBUG_PRINTF_P( __fmt, ... )
# endif //MMU_DEBUG
# if defined(MMU_FINDA_DEBUG) && defined(MMU_DEBUG)
static const auto FDEBUG_PUTS_P = puts_P ;
static const auto FDEBUG_PRINTF_P = printf_P ;
# else
# define FDEBUG_PUTS_P(str)
# define FDEBUG_PRINTF_P( __fmt, ... )
# endif //defined(MMU_FINDA_DEBUG) && defined(MMU_DEBUG)
2018-08-07 18:37:59 +00:00
//clear rx buffer
void mmu_clr_rx_buf ( void )
{
while ( fgetc ( uart2io ) > = 0 ) ;
}
//send command - puts
int mmu_puts_P ( const char * str )
{
mmu_clr_rx_buf ( ) ; //clear rx buffer
2018-08-20 18:53:53 +00:00
int r = fputs_P ( str , uart2io ) ; //send command
2019-01-27 21:48:51 +00:00
mmu_last_request = _millis ( ) ;
2018-08-20 18:53:53 +00:00
return r ;
2018-08-07 18:37:59 +00:00
}
//send command - printf
int mmu_printf_P ( const char * format , . . . )
{
va_list args ;
va_start ( args , format ) ;
mmu_clr_rx_buf ( ) ; //clear rx buffer
int r = vfprintf_P ( uart2io , format , args ) ; //send command
va_end ( args ) ;
2019-01-27 21:48:51 +00:00
mmu_last_request = _millis ( ) ;
2018-08-07 18:37:59 +00:00
return r ;
}
//check 'ok' response
int8_t mmu_rx_ok ( void )
{
2018-08-20 18:53:53 +00:00
int8_t res = uart2_rx_str_P ( PSTR ( " ok \n " ) ) ;
2019-01-27 21:48:51 +00:00
if ( res = = 1 ) mmu_last_response = _millis ( ) ;
2018-08-20 18:53:53 +00:00
return res ;
2018-08-07 18:37:59 +00:00
}
//check 'start' response
int8_t mmu_rx_start ( void )
{
2018-08-20 18:53:53 +00:00
int8_t res = uart2_rx_str_P ( PSTR ( " start \n " ) ) ;
2019-01-27 21:48:51 +00:00
if ( res = = 1 ) mmu_last_response = _millis ( ) ;
2018-08-20 18:53:53 +00:00
return res ;
2018-08-07 18:37:59 +00:00
}
2018-08-13 17:38:55 +00:00
//initialize mmu2 unit - first part - should be done at begining of startup process
void mmu_init ( void )
2018-08-07 18:37:59 +00:00
{
2018-10-19 15:54:48 +00:00
# ifdef MMU_HWRESET
2018-08-13 17:38:55 +00:00
digitalWrite ( MMU_RST_PIN , HIGH ) ;
pinMode ( MMU_RST_PIN , OUTPUT ) ; //setup reset pin
2018-10-19 15:54:48 +00:00
# endif //MMU_HWRESET
2018-08-07 18:37:59 +00:00
uart2_init ( ) ; //init uart2
_delay_ms ( 10 ) ; //wait 10ms for sure
2018-08-13 17:38:55 +00:00
mmu_reset ( ) ; //reset mmu (HW or SW), do not wait for response
2019-02-12 20:43:26 +00:00
mmu_state = S : : Init ;
2020-09-11 14:43:38 +00:00
SET_INPUT ( IR_SENSOR_PIN ) ; //input mode
WRITE ( IR_SENSOR_PIN , 1 ) ; //pullup
2018-12-21 16:12:16 +00:00
}
2019-01-28 16:27:16 +00:00
//if IR_SENSOR defined, always returns true
//otherwise check for ir sensor and returns true if idler IR sensor was detected, otherwise returns false
2019-01-24 00:12:30 +00:00
bool check_for_ir_sensor ( )
2018-12-21 16:12:16 +00:00
{
2019-01-24 00:12:30 +00:00
# ifdef IR_SENSOR
return true ;
2019-01-28 16:27:16 +00:00
# else //IR_SENSOR
2019-01-24 00:12:30 +00:00
2018-12-21 16:12:16 +00:00
bool detected = false ;
2019-01-24 00:12:30 +00:00
//if IR_SENSOR_PIN input is low and pat9125sensor is not present we detected idler sensor
2020-09-11 14:43:38 +00:00
if ( ( READ ( IR_SENSOR_PIN ) = = 0 )
2019-01-24 00:12:30 +00:00
# ifdef PAT9125
& & fsensor_not_responding
# endif //PAT9125
)
{
detected = true ;
//printf_P(PSTR("Idler IR sensor detected\n"));
2018-12-21 16:12:16 +00:00
}
else
{
2019-01-24 00:12:30 +00:00
//printf_P(PSTR("Idler IR sensor not detected\n"));
2018-12-21 16:12:16 +00:00
}
return detected ;
2019-01-28 16:27:16 +00:00
# endif //IR_SENSOR
2018-08-13 17:38:55 +00:00
}
2019-02-22 16:15:40 +00:00
static bool activate_stealth_mode ( )
{
2019-03-11 11:33:22 +00:00
# ifdef MMU_FORCE_STEALTH_MODE
2019-03-04 16:04:22 +00:00
return true ;
# else
2019-03-10 15:03:46 +00:00
return ( eeprom_read_byte ( ( uint8_t * ) EEPROM_MMU_STEALTH ) = = 1 ) ;
2019-03-04 16:04:22 +00:00
# endif
2019-02-22 16:15:40 +00:00
}
2018-08-13 17:38:55 +00:00
//mmu main loop - state machine processing
void mmu_loop ( void )
{
2019-01-04 20:07:52 +00:00
static uint8_t mmu_attempt_nr = 0 ;
2018-08-13 17:38:55 +00:00
// printf_P(PSTR("MMU loop, state=%d\n"), mmu_state);
switch ( mmu_state )
2018-08-07 18:37:59 +00:00
{
2019-02-12 20:43:26 +00:00
case S : : Disabled :
2018-08-13 17:38:55 +00:00
return ;
2019-02-12 20:43:26 +00:00
case S : : Init :
2018-08-13 17:38:55 +00:00
if ( mmu_rx_start ( ) > 0 )
{
2019-02-12 22:24:23 +00:00
DEBUG_PUTS_P ( PSTR ( " MMU => 'start' " ) ) ;
DEBUG_PUTS_P ( PSTR ( " MMU <= 'S1' " ) ) ;
2018-08-13 17:38:55 +00:00
mmu_puts_P ( PSTR ( " S1 \n " ) ) ; //send 'read version' request
2019-02-12 20:43:26 +00:00
mmu_state = S : : GetVersion ;
2018-08-13 17:38:55 +00:00
}
2019-01-27 21:48:51 +00:00
else if ( _millis ( ) > 30000 ) //30sec after reset disable mmu
2018-08-13 17:38:55 +00:00
{
puts_P ( PSTR ( " MMU not responding - DISABLED " ) ) ;
2019-02-12 20:43:26 +00:00
mmu_state = S : : Disabled ;
2018-08-13 17:38:55 +00:00
}
return ;
2019-02-12 20:43:26 +00:00
case S : : GetVersion :
2018-08-13 17:38:55 +00:00
if ( mmu_rx_ok ( ) > 0 )
{
fscanf_P ( uart2io , PSTR ( " %u " ) , & mmu_version ) ; //scan version from buffer
2019-02-12 22:24:23 +00:00
DEBUG_PRINTF_P ( PSTR ( " MMU => '%dok' \n " ) , mmu_version ) ;
DEBUG_PUTS_P ( PSTR ( " MMU <= 'S2' " ) ) ;
2018-09-10 18:08:13 +00:00
mmu_puts_P ( PSTR ( " S2 \n " ) ) ; //send 'read buildnr' request
2019-02-12 20:43:26 +00:00
mmu_state = S : : GetBuildNr ;
2018-08-13 17:38:55 +00:00
}
return ;
2019-02-12 20:43:26 +00:00
case S : : GetBuildNr :
2018-08-13 17:38:55 +00:00
if ( mmu_rx_ok ( ) > 0 )
{
fscanf_P ( uart2io , PSTR ( " %u " ) , & mmu_buildnr ) ; //scan buildnr from buffer
2019-02-12 22:24:23 +00:00
DEBUG_PRINTF_P ( PSTR ( " MMU => '%dok' \n " ) , mmu_buildnr ) ;
2018-08-25 14:15:35 +00:00
bool version_valid = mmu_check_version ( ) ;
if ( ! version_valid ) mmu_show_warning ( ) ;
else puts_P ( PSTR ( " MMU version valid " ) ) ;
2019-02-22 16:15:40 +00:00
if ( ! activate_stealth_mode ( ) )
2018-10-18 00:44:16 +00:00
{
2019-02-12 22:24:23 +00:00
FDEBUG_PUTS_P ( PSTR ( " MMU <= 'P0' " ) ) ;
2018-10-18 00:44:16 +00:00
mmu_puts_P ( PSTR ( " P0 \n " ) ) ; //send 'read finda' request
2019-02-12 20:43:26 +00:00
mmu_state = S : : GetFindaInit ;
2018-10-18 00:44:16 +00:00
}
else
{
2019-02-12 22:24:23 +00:00
DEBUG_PUTS_P ( PSTR ( " MMU <= 'M1' " ) ) ;
2018-10-18 00:44:16 +00:00
mmu_puts_P ( PSTR ( " M1 \n " ) ) ; //set mmu mode to stealth
2019-02-12 20:43:26 +00:00
mmu_state = S : : WaitStealthMode ;
2018-10-18 00:44:16 +00:00
}
}
return ;
2019-02-12 20:43:26 +00:00
case S : : WaitStealthMode :
2018-10-18 00:44:16 +00:00
if ( mmu_rx_ok ( ) > 0 )
{
2019-02-12 22:24:23 +00:00
FDEBUG_PUTS_P ( PSTR ( " MMU <= 'P0' " ) ) ;
2018-08-13 17:38:55 +00:00
mmu_puts_P ( PSTR ( " P0 \n " ) ) ; //send 'read finda' request
2019-02-12 20:43:26 +00:00
mmu_state = S : : GetFindaInit ;
2018-08-13 17:38:55 +00:00
}
return ;
2019-02-12 20:43:26 +00:00
case S : : GetFindaInit :
2018-08-13 17:38:55 +00:00
if ( mmu_rx_ok ( ) > 0 )
{
fscanf_P ( uart2io , PSTR ( " %hhu " ) , & mmu_finda ) ; //scan finda from buffer
2019-10-31 16:45:22 +00:00
mmu_last_finda_response = _millis ( ) ;
2019-02-12 22:24:23 +00:00
FDEBUG_PRINTF_P ( PSTR ( " MMU => '%dok' \n " ) , mmu_finda ) ;
2018-08-13 17:38:55 +00:00
puts_P ( PSTR ( " MMU - ENABLED " ) ) ;
mmu_enabled = true ;
2019-07-10 15:39:24 +00:00
//-//
// ... PrinterType/Name
fSetMmuMode ( true ) ;
2019-02-12 20:43:26 +00:00
mmu_state = S : : Idle ;
2018-08-13 17:38:55 +00:00
}
return ;
2019-02-12 20:43:26 +00:00
case S : : Idle :
2019-02-13 16:12:35 +00:00
if ( mmu_cmd ! = MmuCmd : : None ) //command request ?
2018-08-20 18:53:53 +00:00
{
2019-02-13 00:51:39 +00:00
if ( ( mmu_cmd > = MmuCmd : : T0 ) & & ( mmu_cmd < = MmuCmd : : T4 ) )
2018-08-20 18:53:53 +00:00
{
2019-02-13 15:37:54 +00:00
const uint8_t filament = mmu_cmd - MmuCmd : : T0 ;
2019-02-12 22:24:23 +00:00
DEBUG_PRINTF_P ( PSTR ( " MMU <= 'T%d' \n " ) , filament ) ;
2018-08-28 21:50:31 +00:00
mmu_printf_P ( PSTR ( " T%d \n " ) , filament ) ;
2019-02-12 20:43:26 +00:00
mmu_state = S : : WaitCmd ; // wait for response
2018-12-12 21:32:47 +00:00
mmu_fil_loaded = true ;
2019-01-15 00:28:51 +00:00
mmu_idl_sens = 1 ;
2018-08-20 18:53:53 +00:00
}
2019-02-13 00:51:39 +00:00
else if ( ( mmu_cmd > = MmuCmd : : L0 ) & & ( mmu_cmd < = MmuCmd : : L4 ) )
2018-08-24 01:49:51 +00:00
{
2019-02-13 15:37:54 +00:00
const uint8_t filament = mmu_cmd - MmuCmd : : L0 ;
2019-02-12 22:24:23 +00:00
DEBUG_PRINTF_P ( PSTR ( " MMU <= 'L%d' \n " ) , filament ) ;
2018-08-24 01:49:51 +00:00
mmu_printf_P ( PSTR ( " L%d \n " ) , filament ) ;
2019-02-12 20:43:26 +00:00
mmu_state = S : : WaitCmd ; // wait for response
2018-08-24 01:49:51 +00:00
}
2019-02-13 00:51:39 +00:00
else if ( mmu_cmd = = MmuCmd : : C0 )
2018-08-24 16:28:05 +00:00
{
2019-02-12 22:24:23 +00:00
DEBUG_PRINTF_P ( PSTR ( " MMU <= 'C0' \n " ) ) ;
2018-08-26 21:55:29 +00:00
mmu_puts_P ( PSTR ( " C0 \n " ) ) ; //send 'continue loading'
2019-02-12 20:43:26 +00:00
mmu_state = S : : WaitCmd ;
2019-01-15 00:28:51 +00:00
mmu_idl_sens = 1 ;
2018-08-24 16:28:05 +00:00
}
2019-02-13 00:51:39 +00:00
else if ( mmu_cmd = = MmuCmd : : U0 )
2018-08-26 20:08:52 +00:00
{
2019-02-12 22:24:23 +00:00
DEBUG_PRINTF_P ( PSTR ( " MMU <= 'U0' \n " ) ) ;
2018-08-26 21:55:29 +00:00
mmu_puts_P ( PSTR ( " U0 \n " ) ) ; //send 'unload current filament'
2018-12-12 21:32:47 +00:00
mmu_fil_loaded = false ;
2019-02-12 20:43:26 +00:00
mmu_state = S : : WaitCmd ;
2018-08-24 16:28:05 +00:00
}
2019-02-13 00:51:39 +00:00
else if ( ( mmu_cmd > = MmuCmd : : E0 ) & & ( mmu_cmd < = MmuCmd : : E4 ) )
2018-08-28 21:50:31 +00:00
{
2019-02-13 15:37:54 +00:00
const uint8_t filament = mmu_cmd - MmuCmd : : E0 ;
2019-02-12 22:24:23 +00:00
DEBUG_PRINTF_P ( PSTR ( " MMU <= 'E%d' \n " ) , filament ) ;
2018-08-28 21:50:31 +00:00
mmu_printf_P ( PSTR ( " E%d \n " ) , filament ) ; //send eject filament
2018-12-12 21:32:47 +00:00
mmu_fil_loaded = false ;
2019-02-12 20:43:26 +00:00
mmu_state = S : : WaitCmd ;
2018-08-28 21:50:31 +00:00
}
2019-02-26 16:58:00 +00:00
else if ( ( mmu_cmd > = MmuCmd : : K0 ) & & ( mmu_cmd < = MmuCmd : : K4 ) )
{
const uint8_t filament = mmu_cmd - MmuCmd : : K0 ;
DEBUG_PRINTF_P ( PSTR ( " MMU <= 'K%d' \n " ) , filament ) ;
mmu_printf_P ( PSTR ( " K%d \n " ) , filament ) ; //send eject filament
mmu_fil_loaded = false ;
mmu_state = S : : WaitCmd ;
}
2019-02-13 00:51:39 +00:00
else if ( mmu_cmd = = MmuCmd : : R0 )
2018-08-28 21:50:31 +00:00
{
2019-02-12 22:24:23 +00:00
DEBUG_PRINTF_P ( PSTR ( " MMU <= 'R0' \n " ) ) ;
2018-08-28 21:50:31 +00:00
mmu_puts_P ( PSTR ( " R0 \n " ) ) ; //send recover after eject
2019-02-12 20:43:26 +00:00
mmu_state = S : : WaitCmd ;
2018-08-28 21:50:31 +00:00
}
2019-02-13 00:51:39 +00:00
else if ( mmu_cmd = = MmuCmd : : S3 )
2018-12-21 19:56:45 +00:00
{
2019-02-12 22:24:23 +00:00
DEBUG_PRINTF_P ( PSTR ( " MMU <= 'S3' \n " ) ) ;
2018-12-21 19:56:45 +00:00
mmu_puts_P ( PSTR ( " S3 \n " ) ) ; //send power failures request
2019-02-12 20:43:26 +00:00
mmu_state = S : : GetDrvError ;
2018-12-21 19:56:45 +00:00
}
2019-02-13 18:10:55 +00:00
else if ( mmu_cmd = = MmuCmd : : W0 )
{
DEBUG_PRINTF_P ( PSTR ( " MMU <= 'W0' \n " ) ) ;
mmu_puts_P ( PSTR ( " W0 \n " ) ) ;
mmu_state = S : : Pause ;
}
2018-12-18 17:47:54 +00:00
mmu_last_cmd = mmu_cmd ;
2019-02-13 00:51:39 +00:00
mmu_cmd = MmuCmd : : None ;
2018-08-20 18:53:53 +00:00
}
2019-03-11 11:33:22 +00:00
else if ( ( eeprom_read_byte ( ( uint8_t * ) EEPROM_MMU_STEALTH ) ! = SilentModeMenu_MMU ) & & mmu_ready ) {
DEBUG_PRINTF_P ( PSTR ( " MMU <= 'M%d' \n " ) , SilentModeMenu_MMU ) ;
mmu_printf_P ( PSTR ( " M%d \n " ) , SilentModeMenu_MMU ) ;
mmu_state = S : : SwitchMode ;
}
2019-01-27 21:48:51 +00:00
else if ( ( mmu_last_response + 300 ) < _millis ( ) ) //request every 300ms
2018-08-20 18:53:53 +00:00
{
2019-01-24 00:12:30 +00:00
# ifndef IR_SENSOR
if ( check_for_ir_sensor ( ) ) ir_sensor_detected = true ;
# endif //IR_SENSOR not defined
2019-02-12 22:24:23 +00:00
FDEBUG_PUTS_P ( PSTR ( " MMU <= 'P0' " ) ) ;
2018-08-20 18:53:53 +00:00
mmu_puts_P ( PSTR ( " P0 \n " ) ) ; //send 'read finda' request
2019-02-12 20:43:26 +00:00
mmu_state = S : : GetFinda ;
2018-08-20 18:53:53 +00:00
}
return ;
2019-02-12 20:43:26 +00:00
case S : : GetFinda : //response to command P0
2019-02-15 13:19:30 +00:00
if ( mmu_idl_sens )
2019-02-15 13:17:47 +00:00
{
2020-09-11 14:43:38 +00:00
if ( READ ( IR_SENSOR_PIN ) = = 0 & & mmu_loading_flag )
2019-02-15 13:17:47 +00:00
{
# ifdef MMU_DEBUG
printf_P ( PSTR ( " MMU <= 'A' \n " ) ) ;
# endif //MMU_DEBUG
mmu_puts_P ( PSTR ( " A \n " ) ) ; //send 'abort' request
mmu_idl_sens = 0 ;
//printf_P(PSTR("MMU IDLER_SENSOR = 0 - ABORT\n"));
}
//else
//printf_P(PSTR("MMU IDLER_SENSOR = 1 - WAIT\n"));
}
2018-08-20 18:53:53 +00:00
if ( mmu_rx_ok ( ) > 0 )
{
fscanf_P ( uart2io , PSTR ( " %hhu " ) , & mmu_finda ) ; //scan finda from buffer
2019-10-31 16:45:22 +00:00
mmu_last_finda_response = _millis ( ) ;
2019-02-12 22:24:23 +00:00
FDEBUG_PRINTF_P ( PSTR ( " MMU => '%dok' \n " ) , mmu_finda ) ;
2018-08-27 02:21:43 +00:00
//printf_P(PSTR("Eact: %d\n"), int(e_active()));
2019-01-24 00:12:30 +00:00
if ( ! mmu_finda & & CHECK_FSENSOR & & fsensor_enabled ) {
2019-10-16 16:47:18 +00:00
fsensor_checkpoint_print ( ) ;
2020-02-06 02:41:31 +00:00
if ( mmu_extruder ! = MMU_FILAMENT_UNKNOWN ) // Can't deplete unknown extruder.
ad_markDepleted ( mmu_extruder ) ;
if ( lcd_autoDepleteEnabled ( ) & & ! ad_allDepleted ( ) & & mmu_extruder ! = MMU_FILAMENT_UNKNOWN ) // Can't auto if F=?
2019-01-04 20:11:42 +00:00
{
enquecommand_front_P ( PSTR ( " M600 AUTO " ) ) ; //save print and run M600 command
}
else
{
enquecommand_front_P ( PSTR ( " M600 " ) ) ; //save print and run M600 command
}
2018-08-27 02:21:43 +00:00
}
2019-02-12 20:43:26 +00:00
mmu_state = S : : Idle ;
2019-02-13 16:12:35 +00:00
if ( mmu_cmd = = MmuCmd : : None )
2018-08-21 14:41:01 +00:00
mmu_ready = true ;
2018-08-20 18:53:53 +00:00
}
2019-01-27 21:48:51 +00:00
else if ( ( mmu_last_request + MMU_P0_TIMEOUT ) < _millis ( ) )
2018-08-20 18:53:53 +00:00
{ //resend request after timeout (30s)
2019-02-12 20:43:26 +00:00
mmu_state = S : : Idle ;
2018-08-20 18:53:53 +00:00
}
return ;
2019-02-12 20:43:26 +00:00
case S : : WaitCmd : //response to mmu commands
2019-01-15 00:28:51 +00:00
if ( mmu_idl_sens )
{
2020-09-11 14:43:38 +00:00
if ( READ ( IR_SENSOR_PIN ) = = 0 & & mmu_loading_flag )
2019-01-15 00:28:51 +00:00
{
2019-02-12 22:24:23 +00:00
DEBUG_PRINTF_P ( PSTR ( " MMU <= 'A' \n " ) ) ;
2019-01-15 00:28:51 +00:00
mmu_puts_P ( PSTR ( " A \n " ) ) ; //send 'abort' request
mmu_idl_sens = 0 ;
//printf_P(PSTR("MMU IDLER_SENSOR = 0 - ABORT\n"));
}
//else
//printf_P(PSTR("MMU IDLER_SENSOR = 1 - WAIT\n"));
}
2018-08-20 18:53:53 +00:00
if ( mmu_rx_ok ( ) > 0 )
{
2019-02-12 22:24:23 +00:00
DEBUG_PRINTF_P ( PSTR ( " MMU => 'ok' \n " ) ) ;
2019-01-04 20:07:52 +00:00
mmu_attempt_nr = 0 ;
2019-02-13 00:51:39 +00:00
mmu_last_cmd = MmuCmd : : None ;
2018-08-20 18:53:53 +00:00
mmu_ready = true ;
2019-02-12 20:43:26 +00:00
mmu_state = S : : Idle ;
2018-08-20 18:53:53 +00:00
}
2019-01-27 21:48:51 +00:00
else if ( ( mmu_last_request + MMU_CMD_TIMEOUT ) < _millis ( ) )
2018-08-26 19:39:37 +00:00
{ //resend request after timeout (5 min)
2019-07-25 17:09:52 +00:00
if ( mmu_last_cmd ! = MmuCmd : : None )
2018-12-18 17:47:54 +00:00
{
2019-07-25 17:09:52 +00:00
if ( mmu_attempt_nr + + < MMU_MAX_RESEND_ATTEMPTS & &
mmu_last_cmd > = MmuCmd : : T0 & & mmu_last_cmd < = MmuCmd : : T4 )
{
2019-02-12 22:24:23 +00:00
DEBUG_PRINTF_P ( PSTR ( " MMU retry attempt nr. %d \n " ) , mmu_attempt_nr - 1 ) ;
2019-01-04 20:07:52 +00:00
mmu_cmd = mmu_last_cmd ;
}
else {
2019-02-13 00:51:39 +00:00
mmu_cmd = MmuCmd : : None ;
mmu_last_cmd = MmuCmd : : None ; //check
2019-01-04 20:07:52 +00:00
mmu_attempt_nr = 0 ;
}
2018-12-18 17:47:54 +00:00
}
2019-02-12 20:43:26 +00:00
mmu_state = S : : Idle ;
2018-08-20 18:53:53 +00:00
}
return ;
2019-02-13 18:10:55 +00:00
case S : : Pause :
if ( mmu_rx_ok ( ) > 0 )
{
DEBUG_PRINTF_P ( PSTR ( " MMU => 'ok', resume print \n " ) ) ;
mmu_attempt_nr = 0 ;
mmu_last_cmd = MmuCmd : : None ;
mmu_ready = true ;
mmu_state = S : : Idle ;
lcd_resume_print ( ) ;
}
if ( mmu_cmd ! = MmuCmd : : None )
{
mmu_state = S : : Idle ;
}
return ;
2019-02-12 20:43:26 +00:00
case S : : GetDrvError :
2018-12-21 19:56:45 +00:00
if ( mmu_rx_ok ( ) > 0 )
{
2019-01-04 20:07:52 +00:00
fscanf_P ( uart2io , PSTR ( " %d " ) , & mmu_power_failures ) ; //scan power failures
2019-02-12 22:24:23 +00:00
DEBUG_PRINTF_P ( PSTR ( " MMU => 'ok' \n " ) ) ;
2019-02-13 00:51:39 +00:00
mmu_last_cmd = MmuCmd : : None ;
2018-12-21 22:07:39 +00:00
mmu_ready = true ;
2019-02-12 20:43:26 +00:00
mmu_state = S : : Idle ;
2018-12-21 19:56:45 +00:00
}
2019-01-27 21:48:51 +00:00
else if ( ( mmu_last_request + MMU_CMD_TIMEOUT ) < _millis ( ) )
2019-03-11 11:33:22 +00:00
{ //timeout 45 s
mmu_state = S : : Idle ;
}
return ;
case S : : SwitchMode :
if ( mmu_rx_ok ( ) > 0 )
{
DEBUG_PRINTF_P ( PSTR ( " MMU => 'ok' \n " ) ) ;
eeprom_update_byte ( ( uint8_t * ) EEPROM_MMU_STEALTH , SilentModeMenu_MMU ) ;
2019-02-12 20:43:26 +00:00
mmu_state = S : : Idle ;
2018-12-21 19:56:45 +00:00
}
2019-03-11 11:33:22 +00:00
else if ( ( mmu_last_request + MMU_CMD_TIMEOUT ) < _millis ( ) )
{ //timeout 45 s
2019-02-12 20:43:26 +00:00
mmu_state = S : : Idle ;
2018-12-21 19:56:45 +00:00
}
2019-03-11 11:33:22 +00:00
return ;
2018-08-07 18:37:59 +00:00
}
}
2018-08-13 17:38:55 +00:00
void mmu_reset ( void )
2018-08-07 18:37:59 +00:00
{
2018-08-13 17:38:55 +00:00
# ifdef MMU_HWRESET //HW - pulse reset pin
digitalWrite ( MMU_RST_PIN , LOW ) ;
_delay_us ( 100 ) ;
digitalWrite ( MMU_RST_PIN , HIGH ) ;
# else //SW - send X0 command
mmu_puts_P ( PSTR ( " X0 \n " ) ) ;
# endif
2018-08-07 18:37:59 +00:00
}
2018-08-13 17:38:55 +00:00
int8_t mmu_set_filament_type ( uint8_t extruder , uint8_t filament )
2018-08-07 18:37:59 +00:00
{
2018-08-13 17:38:55 +00:00
printf_P ( PSTR ( " MMU <= 'F%d %d' \n " ) , extruder , filament ) ;
mmu_printf_P ( PSTR ( " F%d %d \n " ) , extruder , filament ) ;
unsigned char timeout = MMU_TIMEOUT ; //10x100ms
2018-08-07 18:37:59 +00:00
while ( ( mmu_rx_ok ( ) < = 0 ) & & ( - - timeout ) )
2018-08-13 17:38:55 +00:00
delay_keep_alive ( MMU_TODELAY ) ;
return timeout ? 1 : 0 ;
2018-08-07 18:37:59 +00:00
}
2019-01-04 20:26:13 +00:00
//! @brief Enqueue MMUv2 command
//!
//! Call manage_response() after enqueuing to process command.
//! If T command is enqueued, it disables current for extruder motor if TMC2130 driver present.
//! If T or L command is enqueued, it marks filament loaded in AutoDeplete module.
2019-02-13 00:51:39 +00:00
void mmu_command ( MmuCmd cmd )
2018-08-07 18:37:59 +00:00
{
2019-02-13 00:51:39 +00:00
if ( ( cmd > = MmuCmd : : T0 ) & & ( cmd < = MmuCmd : : T4 ) )
2018-11-13 15:04:46 +00:00
{
//disable extruder motor
2019-01-04 20:11:42 +00:00
# ifdef TMC2130
2018-11-13 15:04:46 +00:00
tmc2130_set_pwr ( E_AXIS , 0 ) ;
2019-01-04 20:11:42 +00:00
# endif //TMC2130
2018-11-13 15:04:46 +00:00
//printf_P(PSTR("E-axis disabled\n"));
2019-02-13 00:51:39 +00:00
ad_markLoaded ( cmd - MmuCmd : : T0 ) ;
2018-11-13 15:04:46 +00:00
}
2019-02-13 00:51:39 +00:00
if ( ( cmd > = MmuCmd : : L0 ) & & ( cmd < = MmuCmd : : L4 ) )
2019-01-04 20:11:42 +00:00
{
2019-02-13 00:51:39 +00:00
ad_markLoaded ( cmd - MmuCmd : : L0 ) ;
2019-01-04 20:11:42 +00:00
}
2018-11-13 15:04:46 +00:00
2018-08-20 18:53:53 +00:00
mmu_cmd = cmd ;
mmu_ready = false ;
}
2019-01-22 13:05:08 +00:00
//! @brief Rotate extruder idler to catch filament
//! @par synchronize
//! * true blocking call
//! * false non-blocking call
2019-01-22 09:56:07 +00:00
void mmu_load_step ( bool synchronize )
{
2019-01-04 20:07:52 +00:00
current_position [ E_AXIS ] = current_position [ E_AXIS ] + MMU_LOAD_FEEDRATE * 0.1 ;
2020-06-01 15:51:28 +00:00
plan_buffer_line_curposXYZE ( MMU_LOAD_FEEDRATE ) ;
2019-01-22 09:56:07 +00:00
if ( synchronize ) st_synchronize ( ) ;
2018-12-12 21:32:47 +00:00
}
2019-01-04 20:07:52 +00:00
2019-01-15 00:28:51 +00:00
//! @brief Is nozzle hot enough to move extruder wheels and do we have idler sensor?
//!
//! Do load steps only if temperature is higher then min. temp for safe extrusion and
//! idler sensor present.
//! Otherwise "cold extrusion prevented" would be send to serial line periodically
//! and watchdog reset will be triggered by lack of keep_alive processing.
//!
//! @retval true temperature is high enough to move extruder
//! @retval false temperature is not high enough to move extruder, turned
//! off E-stepper to prevent over-heating and allow filament pull-out if necessary
bool can_extrude ( )
{
2019-01-25 17:03:05 +00:00
if ( ( degHotend ( active_extruder ) < EXTRUDE_MINTEMP ) | | ! ir_sensor_detected )
2019-01-15 00:28:51 +00:00
{
disable_e0 ( ) ;
delay_keep_alive ( 100 ) ;
return false ;
}
return true ;
2018-12-12 21:32:47 +00:00
}
2019-01-04 20:07:52 +00:00
2019-02-15 13:17:47 +00:00
static void get_response_print_info ( uint8_t move ) {
printf_P ( PSTR ( " mmu_get_response - begin move: " ) , move ) ;
switch ( move ) {
2021-01-22 16:56:05 +00:00
case MMU_LOAD_MOVE : puts_P ( PSTR ( " load " ) ) ; break ;
case MMU_UNLOAD_MOVE : puts_P ( PSTR ( " unload " ) ) ; break ;
case MMU_TCODE_MOVE : puts_P ( PSTR ( " T-code " ) ) ; break ;
case MMU_NO_MOVE : puts_P ( PSTR ( " no move " ) ) ; break ;
default : puts_P ( PSTR ( " error: unknown move " ) ) ; break ;
2019-02-15 13:17:47 +00:00
}
}
2018-12-12 21:32:47 +00:00
bool mmu_get_response ( uint8_t move )
2018-08-20 18:53:53 +00:00
{
2018-12-21 16:12:16 +00:00
2019-02-15 13:17:47 +00:00
get_response_print_info ( move ) ;
2018-08-20 18:53:53 +00:00
KEEPALIVE_STATE ( IN_PROCESS ) ;
2019-02-13 16:12:35 +00:00
while ( mmu_cmd ! = MmuCmd : : None )
2018-08-21 14:41:01 +00:00
{
delay_keep_alive ( 100 ) ;
}
2018-12-12 21:32:47 +00:00
2018-08-20 18:53:53 +00:00
while ( ! mmu_ready )
{
2019-02-13 16:12:35 +00:00
if ( ( mmu_state ! = S : : WaitCmd ) & & ( mmu_last_cmd = = MmuCmd : : None ) )
2018-08-20 18:53:53 +00:00
break ;
2018-12-12 21:32:47 +00:00
switch ( move ) {
2019-01-15 00:28:51 +00:00
case MMU_LOAD_MOVE :
mmu_loading_flag = true ;
if ( can_extrude ( ) ) mmu_load_step ( ) ;
2019-01-04 20:07:52 +00:00
//don't rely on "ok" signal from mmu unit; if filament detected by idler sensor during loading stop loading movements to prevent infinite loading
2020-09-11 14:43:38 +00:00
if ( READ ( IR_SENSOR_PIN ) = = 0 ) move = MMU_NO_MOVE ;
2018-12-12 21:32:47 +00:00
break ;
case MMU_UNLOAD_MOVE :
2020-09-11 14:43:38 +00:00
if ( READ ( IR_SENSOR_PIN ) = = 0 ) //filament is still detected by idler sensor, printer helps with unlading
2019-01-15 00:28:51 +00:00
{
if ( can_extrude ( ) )
{
2021-01-22 16:56:05 +00:00
puts_P ( PSTR ( " Unload 1 " ) ) ;
2019-01-15 00:28:51 +00:00
current_position [ E_AXIS ] = current_position [ E_AXIS ] - MMU_LOAD_FEEDRATE * MMU_LOAD_TIME_MS * 0.001 ;
2020-06-01 15:51:28 +00:00
plan_buffer_line_curposXYZE ( MMU_LOAD_FEEDRATE ) ;
2019-01-15 00:28:51 +00:00
st_synchronize ( ) ;
}
2018-12-18 15:08:29 +00:00
}
else //filament was unloaded from idler, no additional movements needed
{
2021-01-22 16:56:05 +00:00
puts_P ( PSTR ( " Unloading finished 1 " ) ) ;
2018-12-18 15:08:29 +00:00
disable_e0 ( ) ; //turn off E-stepper to prevent overheating and alow filament pull-out if necessary
move = MMU_NO_MOVE ;
}
2018-12-12 21:32:47 +00:00
break ;
2018-12-18 15:08:29 +00:00
case MMU_TCODE_MOVE : //first do unload and then continue with infinite loading movements
2020-09-11 14:43:38 +00:00
if ( READ ( IR_SENSOR_PIN ) = = 0 ) //filament detected by idler sensor, we must unload first
2019-01-15 00:28:51 +00:00
{
if ( can_extrude ( ) )
{
2021-01-22 16:56:05 +00:00
puts_P ( PSTR ( " Unload 2 " ) ) ;
2019-01-15 00:28:51 +00:00
current_position [ E_AXIS ] = current_position [ E_AXIS ] - MMU_LOAD_FEEDRATE * MMU_LOAD_TIME_MS * 0.001 ;
2020-06-01 15:51:28 +00:00
plan_buffer_line_curposXYZE ( MMU_LOAD_FEEDRATE ) ;
2019-01-15 00:28:51 +00:00
st_synchronize ( ) ;
}
2018-12-18 15:08:29 +00:00
}
else //delay to allow mmu unit to pull out filament from bondtech gears and then start with infinite loading
{
2021-01-22 16:56:05 +00:00
puts_P ( PSTR ( " Unloading finished 2 " ) ) ;
2018-12-18 15:08:29 +00:00
disable_e0 ( ) ; //turn off E-stepper to prevent overheating and alow filament pull-out if necessary
delay_keep_alive ( MMU_LOAD_TIME_MS ) ;
move = MMU_LOAD_MOVE ;
2019-02-15 13:17:47 +00:00
get_response_print_info ( move ) ;
2018-12-18 15:08:29 +00:00
}
2018-12-12 21:32:47 +00:00
break ;
2018-12-17 20:25:07 +00:00
case MMU_NO_MOVE :
2018-12-12 21:32:47 +00:00
default :
delay_keep_alive ( 100 ) ;
break ;
}
2018-08-20 18:53:53 +00:00
}
2019-01-04 20:07:52 +00:00
printf_P ( PSTR ( " mmu_get_response() returning: %d \n " ) , mmu_ready ) ;
2018-08-20 18:53:53 +00:00
bool ret = mmu_ready ;
mmu_ready = false ;
2018-08-21 14:41:01 +00:00
// printf_P(PSTR("mmu_get_response - end %d\n"), ret?1:0);
2018-08-20 18:53:53 +00:00
return ret ;
2018-08-07 18:37:59 +00:00
}
2018-08-02 16:54:00 +00:00
2019-01-22 13:05:08 +00:00
//! @brief Wait for active extruder to reach temperature set
//!
//! This function is blocking and showing lcd_wait_for_heater() screen
//! which is constantly updated with nozzle temperature.
2019-01-22 09:56:07 +00:00
void mmu_wait_for_heater_blocking ( )
{
while ( ( degTargetHotend ( active_extruder ) - degHotend ( active_extruder ) ) > 5 )
{
delay_keep_alive ( 1000 ) ;
lcd_wait_for_heater ( ) ;
}
}
2018-08-13 17:38:55 +00:00
2018-12-12 21:32:47 +00:00
void manage_response ( bool move_axes , bool turn_off_nozzle , uint8_t move )
2018-08-13 17:38:55 +00:00
{
bool response = false ;
mmu_print_saved = false ;
bool lcd_update_was_enabled = false ;
float hotend_temp_bckp = degTargetHotend ( active_extruder ) ;
float z_position_bckp = current_position [ Z_AXIS ] ;
float x_position_bckp = current_position [ X_AXIS ] ;
float y_position_bckp = current_position [ Y_AXIS ] ;
2018-11-02 18:31:10 +00:00
uint8_t screen = 0 ; //used for showing multiscreen messages
2019-02-15 13:17:47 +00:00
mmu_loading_flag = false ;
2018-08-13 17:38:55 +00:00
while ( ! response )
{
2018-12-12 21:32:47 +00:00
response = mmu_get_response ( move ) ; //wait for "ok" from mmu
2018-08-13 17:38:55 +00:00
if ( ! response ) { //no "ok" was received in reserved time frame, user will fix the issue on mmu unit
if ( ! mmu_print_saved ) { //first occurence, we are saving current position, park print head in certain position and disable nozzle heater
2019-01-04 21:23:11 +00:00
uint8_t mmu_fail = eeprom_read_byte ( ( uint8_t * ) EEPROM_MMU_FAIL ) ;
uint16_t mmu_fail_tot = eeprom_read_word ( ( uint16_t * ) EEPROM_MMU_FAIL_TOT ) ;
if ( mmu_fail < 255 ) eeprom_update_byte ( ( uint8_t * ) EEPROM_MMU_FAIL , mmu_fail + 1 ) ;
if ( mmu_fail_tot < 65535 ) eeprom_update_word ( ( uint16_t * ) EEPROM_MMU_FAIL_TOT , mmu_fail_tot + 1 ) ;
2018-08-13 17:38:55 +00:00
if ( lcd_update_enabled ) {
lcd_update_was_enabled = true ;
lcd_update_enable ( false ) ;
}
st_synchronize ( ) ;
mmu_print_saved = true ;
2021-01-22 16:56:05 +00:00
puts_P ( PSTR ( " MMU not responding " ) ) ;
2019-04-04 17:04:15 +00:00
KEEPALIVE_STATE ( PAUSED_FOR_USER ) ;
2018-08-13 17:38:55 +00:00
hotend_temp_bckp = degTargetHotend ( active_extruder ) ;
if ( move_axes ) {
z_position_bckp = current_position [ Z_AXIS ] ;
x_position_bckp = current_position [ X_AXIS ] ;
y_position_bckp = current_position [ Y_AXIS ] ;
//lift z
current_position [ Z_AXIS ] + = Z_PAUSE_LIFT ;
if ( current_position [ Z_AXIS ] > Z_MAX_POS ) current_position [ Z_AXIS ] = Z_MAX_POS ;
2020-06-01 15:51:28 +00:00
plan_buffer_line_curposXYZE ( 15 ) ;
2018-08-13 17:38:55 +00:00
st_synchronize ( ) ;
//Move XY to side
current_position [ X_AXIS ] = X_PAUSE_POS ;
current_position [ Y_AXIS ] = Y_PAUSE_POS ;
2020-06-01 15:51:28 +00:00
plan_buffer_line_curposXYZE ( 50 ) ;
2018-08-13 17:38:55 +00:00
st_synchronize ( ) ;
}
if ( turn_off_nozzle ) {
//set nozzle target temperature to 0
setAllTargetHotends ( 0 ) ;
}
2019-01-04 20:07:52 +00:00
disable_e0 ( ) ; //turn off E-stepper to prevent overheating and alow filament pull-out if necessary
2018-08-13 17:38:55 +00:00
}
2018-11-02 18:31:10 +00:00
//first three lines are used for printing multiscreen message; last line contains measured and target nozzle temperature
if ( screen = = 0 ) { //screen 0
2021-03-30 16:11:22 +00:00
lcd_display_message_fullscreen_P ( _i ( " MMU needs user attention. " ) ) ; ////MSG_MMU_USER_ATTENTION c=20 r=3
2018-11-02 18:31:10 +00:00
screen + + ;
}
else { //screen 1
2021-03-31 04:41:17 +00:00
if ( ( degTargetHotend ( active_extruder ) = = 0 ) & & turn_off_nozzle ) lcd_display_message_fullscreen_P ( _i ( " Press the knob to resume nozzle temperature. " ) ) ; ////MSG_RESUME_NOZZLE_TEMP c=20 r=4
2021-03-30 07:11:19 +00:00
else lcd_display_message_fullscreen_P ( _i ( " Fix the issue and then press button on MMU unit. " ) ) ; ////MSG_MMU_FIX_ISSUE c=20 r=4
2018-11-02 18:31:10 +00:00
screen = 0 ;
}
lcd_set_degree ( ) ;
//5 seconds delay
2019-01-04 20:07:52 +00:00
for ( uint8_t i = 0 ; i < 5 ; i + + ) {
2018-11-02 18:31:10 +00:00
if ( lcd_clicked ( ) ) {
setTargetHotend ( hotend_temp_bckp , active_extruder ) ;
2019-01-04 20:07:52 +00:00
/// mmu_cmd = mmu_last_cmd;
2018-11-02 18:31:10 +00:00
break ;
2019-01-04 20:07:52 +00:00
}
//Print the hotend temperature (9 chars total) and fill rest of the line with space
lcd_set_cursor ( 0 , 4 ) ; //line 4
int chars = lcd_printf_P ( _N ( " %c%3d/%d%c " ) , LCD_STR_THERMOMETER [ 0 ] , ( int ) ( degHotend ( active_extruder ) + 0.5 ) , ( int ) ( degTargetHotend ( active_extruder ) + 0.5 ) , LCD_STR_DEGREE [ 0 ] ) ;
lcd_space ( 9 - chars ) ;
delay_keep_alive ( 1000 ) ;
2018-11-02 18:31:10 +00:00
}
2018-08-13 17:38:55 +00:00
}
else if ( mmu_print_saved ) {
2021-01-22 16:56:05 +00:00
puts_P ( PSTR ( " MMU starts responding " ) ) ;
2019-04-04 17:04:15 +00:00
KEEPALIVE_STATE ( IN_HANDLER ) ;
2019-02-15 13:17:47 +00:00
mmu_loading_flag = false ;
2018-08-26 19:39:37 +00:00
if ( turn_off_nozzle )
{
lcd_clear ( ) ;
setTargetHotend ( hotend_temp_bckp , active_extruder ) ;
2018-11-02 18:31:10 +00:00
if ( ( ( degTargetHotend ( active_extruder ) - degHotend ( active_extruder ) ) > 5 ) ) {
lcd_display_message_fullscreen_P ( _i ( " MMU OK. Resuming temperature... " ) ) ;
delay_keep_alive ( 3000 ) ;
}
2020-06-01 15:51:28 +00:00
mmu_wait_for_heater_blocking ( ) ;
2018-08-26 19:39:37 +00:00
}
2018-08-13 17:38:55 +00:00
if ( move_axes ) {
2018-08-26 19:39:37 +00:00
lcd_clear ( ) ;
lcd_display_message_fullscreen_P ( _i ( " MMU OK. Resuming position... " ) ) ;
2018-08-13 17:38:55 +00:00
current_position [ X_AXIS ] = x_position_bckp ;
current_position [ Y_AXIS ] = y_position_bckp ;
2020-06-01 15:51:28 +00:00
plan_buffer_line_curposXYZE ( 50 ) ;
2018-08-13 17:38:55 +00:00
st_synchronize ( ) ;
current_position [ Z_AXIS ] = z_position_bckp ;
2020-06-01 15:51:28 +00:00
plan_buffer_line_curposXYZE ( 15 ) ;
2018-08-13 17:38:55 +00:00
st_synchronize ( ) ;
}
else {
2018-08-26 19:39:37 +00:00
lcd_clear ( ) ;
lcd_display_message_fullscreen_P ( _i ( " MMU OK. Resuming... " ) ) ;
2018-08-13 17:38:55 +00:00
delay_keep_alive ( 1000 ) ; //delay just for showing MMU OK message for a while in case that there are no xyz movements
}
}
}
if ( lcd_update_was_enabled ) lcd_update_enable ( true ) ;
2018-11-13 15:04:46 +00:00
# ifdef TMC2130
//enable extruder motor (disabled in mmu_command, start of T-code processing)
tmc2130_set_pwr ( E_AXIS , 1 ) ;
//printf_P(PSTR("E-axis enabled\n"));
# endif //TMC2130
2018-08-13 17:38:55 +00:00
}
2018-08-28 16:52:16 +00:00
//! @brief 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.
//!
2018-08-13 17:38:55 +00:00
void mmu_load_to_nozzle ( )
{
st_synchronize ( ) ;
2020-03-05 09:22:35 +00:00
const bool saved_e_relative_mode = axis_relative_modes & E_AXIS_MASK ;
if ( ! saved_e_relative_mode ) axis_relative_modes | = E_AXIS_MASK ;
2019-01-24 00:12:30 +00:00
if ( ir_sensor_detected )
2018-12-21 17:51:13 +00:00
{
2018-12-21 19:56:45 +00:00
current_position [ E_AXIS ] + = 3.0f ;
2018-12-21 17:51:13 +00:00
}
else
{
2018-12-21 19:56:45 +00:00
current_position [ E_AXIS ] + = 7.2f ;
2018-12-21 17:51:13 +00:00
}
2018-08-13 17:38:55 +00:00
float feedrate = 562 ;
2020-06-01 15:51:28 +00:00
plan_buffer_line_curposXYZE ( feedrate / 60 ) ;
2018-08-13 17:38:55 +00:00
st_synchronize ( ) ;
current_position [ E_AXIS ] + = 14.4f ;
feedrate = 871 ;
2020-06-01 15:51:28 +00:00
plan_buffer_line_curposXYZE ( feedrate / 60 ) ;
2018-08-13 17:38:55 +00:00
st_synchronize ( ) ;
current_position [ E_AXIS ] + = 36.0f ;
feedrate = 1393 ;
2020-06-01 15:51:28 +00:00
plan_buffer_line_curposXYZE ( feedrate / 60 ) ;
2018-08-13 17:38:55 +00:00
st_synchronize ( ) ;
current_position [ E_AXIS ] + = 14.4f ;
feedrate = 871 ;
2020-06-01 15:51:28 +00:00
plan_buffer_line_curposXYZE ( feedrate / 60 ) ;
2018-08-13 17:38:55 +00:00
st_synchronize ( ) ;
2020-03-05 09:22:35 +00:00
if ( ! saved_e_relative_mode ) axis_relative_modes & = ~ E_AXIS_MASK ;
2018-08-13 17:38:55 +00:00
}
2018-08-27 14:12:10 +00:00
void mmu_M600_wait_and_beep ( ) {
//Beep and wait for user to remove old filament and prepare new filament for load
KEEPALIVE_STATE ( PAUSED_FOR_USER ) ;
int counterBeep = 0 ;
2020-05-12 20:23:40 +00:00
lcd_display_message_fullscreen_P ( _i ( " Remove old filament and press the knob to start loading new filament. " ) ) ; ////MSG_REMOVE_OLD_FILAMENT c=20 r=5
2018-08-27 14:12:10 +00:00
bool bFirst = true ;
while ( ! lcd_clicked ( ) ) {
manage_heater ( ) ;
manage_inactivity ( true ) ;
# if BEEPER > 0
if ( counterBeep = = 500 ) {
counterBeep = 0 ;
}
SET_OUTPUT ( BEEPER ) ;
if ( counterBeep = = 0 ) {
2019-06-10 13:03:52 +00:00
if ( ( eSoundMode = = e_SOUND_MODE_BLIND ) | | ( eSoundMode = = e_SOUND_MODE_LOUD ) | | ( ( eSoundMode = = e_SOUND_MODE_ONCE ) & & bFirst ) )
2018-08-27 14:12:10 +00:00
{
bFirst = false ;
WRITE ( BEEPER , HIGH ) ;
}
}
if ( counterBeep = = 20 ) {
WRITE ( BEEPER , LOW ) ;
}
counterBeep + + ;
# endif //BEEPER > 0
delay_keep_alive ( 4 ) ;
}
WRITE ( BEEPER , LOW ) ;
}
2019-03-04 21:00:24 +00:00
//! @brief load filament for mmu v2
//! @par nozzle_temp nozzle temperature to load filament
void mmu_M600_load_filament ( bool automatic , float nozzle_temp )
2018-08-13 17:38:55 +00:00
{
2019-03-04 21:17:43 +00:00
tmp_extruder = mmu_extruder ;
if ( ! automatic )
{
# ifdef MMU_M600_SWITCH_EXTRUDER
bool yes = lcd_show_fullscreen_message_yes_no_and_wait_P ( _i ( " Do you want to switch extruder? " ) , false ) ;
if ( yes ) tmp_extruder = choose_extruder_menu ( ) ;
# endif //MMU_M600_SWITCH_EXTRUDER
}
else
{
tmp_extruder = ad_getAlternative ( tmp_extruder ) ;
}
lcd_update_enable ( false ) ;
lcd_clear ( ) ;
2021-01-22 17:34:47 +00:00
lcd_puts_at_P ( 0 , 1 , _T ( MSG_LOADING_FILAMENT ) ) ;
2021-01-22 16:11:51 +00:00
lcd_print ( ' ' ) ;
2019-03-04 21:17:43 +00:00
lcd_print ( tmp_extruder + 1 ) ;
snmm_filaments_used | = ( 1 < < tmp_extruder ) ; //for stop print
//printf_P(PSTR("T code: %d \n"), tmp_extruder);
//mmu_printf_P(PSTR("T%d\n"), tmp_extruder);
setTargetHotend ( nozzle_temp , active_extruder ) ;
mmu_wait_for_heater_blocking ( ) ;
mmu_command ( MmuCmd : : T0 + tmp_extruder ) ;
manage_response ( false , true , MMU_LOAD_MOVE ) ;
2019-08-16 18:20:17 +00:00
mmu_continue_loading ( is_usb_printing | | ( lcd_commands_type = = LcdCommands : : Layer1Cal ) ) ;
2019-03-04 21:17:43 +00:00
mmu_extruder = tmp_extruder ; //filament change is finished
mmu_load_to_nozzle ( ) ;
load_filament_final_feed ( ) ;
st_synchronize ( ) ;
2018-08-13 17:38:55 +00:00
}
2018-11-12 19:09:54 +00:00
# ifdef SNMM
2018-08-02 16:54:00 +00:00
void extr_mov ( float shift , float feed_rate )
{ //move extruder no matter what the current heater temperature is
set_extrude_min_temp ( .0 ) ;
current_position [ E_AXIS ] + = shift ;
2019-08-21 07:59:51 +00:00
plan_buffer_line_curposXYZE ( feed_rate , active_extruder ) ;
2018-08-02 16:54:00 +00:00
set_extrude_min_temp ( EXTRUDE_MINTEMP ) ;
}
2018-11-12 19:09:54 +00:00
# endif //SNMM
2018-08-02 16:54:00 +00:00
2018-08-07 13:01:49 +00:00
void change_extr ( int
# ifdef SNMM
extr
# endif //SNMM
) { //switches multiplexer for extruders
2018-08-02 16:54:00 +00:00
# ifdef SNMM
st_synchronize ( ) ;
2019-01-27 21:48:51 +00:00
_delay ( 100 ) ;
2018-08-02 16:54:00 +00:00
disable_e0 ( ) ;
disable_e1 ( ) ;
disable_e2 ( ) ;
2018-08-07 18:37:59 +00:00
mmu_extruder = extr ;
2018-08-02 16:54:00 +00:00
pinMode ( E_MUX0_PIN , OUTPUT ) ;
pinMode ( E_MUX1_PIN , OUTPUT ) ;
switch ( extr ) {
case 1 :
WRITE ( E_MUX0_PIN , HIGH ) ;
WRITE ( E_MUX1_PIN , LOW ) ;
break ;
case 2 :
WRITE ( E_MUX0_PIN , LOW ) ;
WRITE ( E_MUX1_PIN , HIGH ) ;
break ;
case 3 :
WRITE ( E_MUX0_PIN , HIGH ) ;
WRITE ( E_MUX1_PIN , HIGH ) ;
break ;
default :
WRITE ( E_MUX0_PIN , LOW ) ;
WRITE ( E_MUX1_PIN , LOW ) ;
break ;
}
2019-01-27 21:48:51 +00:00
_delay ( 100 ) ;
2018-08-02 16:54:00 +00:00
# endif
}
int get_ext_nr ( )
{ //reads multiplexer input pins and return current extruder number (counted from 0)
# ifndef SNMM
2018-08-07 18:37:59 +00:00
return ( mmu_extruder ) ; //update needed
2018-08-02 16:54:00 +00:00
# else
return ( 2 * READ ( E_MUX1_PIN ) + READ ( E_MUX0_PIN ) ) ;
# endif
}
void display_loading ( )
{
2018-08-07 18:37:59 +00:00
switch ( mmu_extruder )
2018-08-02 16:54:00 +00:00
{
case 1 : lcd_display_message_fullscreen_P ( _T ( MSG_FILAMENT_LOADING_T1 ) ) ; break ;
case 2 : lcd_display_message_fullscreen_P ( _T ( MSG_FILAMENT_LOADING_T2 ) ) ; break ;
case 3 : lcd_display_message_fullscreen_P ( _T ( MSG_FILAMENT_LOADING_T3 ) ) ; break ;
default : lcd_display_message_fullscreen_P ( _T ( MSG_FILAMENT_LOADING_T0 ) ) ; break ;
}
}
2019-05-14 16:25:43 +00:00
void extr_adj ( uint8_t extruder ) //loading filament for SNMM
2018-08-02 16:54:00 +00:00
{
# ifndef SNMM
2019-02-13 16:12:35 +00:00
MmuCmd cmd = MmuCmd : : L0 + extruder ;
2019-07-30 17:06:57 +00:00
if ( extruder > ( MmuCmd : : L4 - MmuCmd : : L0 ) )
2018-08-24 01:49:51 +00:00
{
printf_P ( PSTR ( " Filament out of range %d \n " ) , extruder ) ;
return ;
}
mmu_command ( cmd ) ;
2018-08-02 16:54:00 +00:00
//show which filament is currently loaded
lcd_update_enable ( false ) ;
lcd_clear ( ) ;
2021-01-22 17:34:47 +00:00
lcd_puts_at_P ( 0 , 1 , _T ( MSG_LOADING_FILAMENT ) ) ;
2018-08-02 16:54:00 +00:00
//if(strlen(_T(MSG_LOADING_FILAMENT))>18) lcd.setCursor(0, 1);
//else lcd.print(" ");
2021-01-22 16:11:51 +00:00
lcd_print ( ' ' ) ;
2018-08-24 01:49:51 +00:00
lcd_print ( extruder + 1 ) ;
2018-08-02 16:54:00 +00:00
// get response
2018-08-03 17:14:17 +00:00
manage_response ( false , false ) ;
2018-08-02 16:54:00 +00:00
lcd_update_enable ( true ) ;
//lcd_return_to_status();
# else
bool correct ;
max_feedrate [ E_AXIS ] = 80 ;
//max_feedrate[E_AXIS] = 50;
START :
lcd_clear ( ) ;
lcd_set_cursor ( 0 , 0 ) ;
switch ( extruder ) {
case 1 : lcd_display_message_fullscreen_P ( _T ( MSG_FILAMENT_LOADING_T1 ) ) ; break ;
case 2 : lcd_display_message_fullscreen_P ( _T ( MSG_FILAMENT_LOADING_T2 ) ) ; break ;
case 3 : lcd_display_message_fullscreen_P ( _T ( MSG_FILAMENT_LOADING_T3 ) ) ; break ;
default : lcd_display_message_fullscreen_P ( _T ( MSG_FILAMENT_LOADING_T0 ) ) ; break ;
}
KEEPALIVE_STATE ( PAUSED_FOR_USER ) ;
do {
extr_mov ( 0.001 , 1000 ) ;
delay_keep_alive ( 2 ) ;
} while ( ! lcd_clicked ( ) ) ;
//delay_keep_alive(500);
KEEPALIVE_STATE ( IN_HANDLER ) ;
st_synchronize ( ) ;
//correct = lcd_show_fullscreen_message_yes_no_and_wait_P(MSG_FIL_LOADED_CHECK, false);
//if (!correct) goto START;
//extr_mov(BOWDEN_LENGTH/2.f, 500); //dividing by 2 is there because of max. extrusion length limitation (x_max + y_max)
//extr_mov(BOWDEN_LENGTH/2.f, 500);
extr_mov ( bowden_length [ extruder ] , 500 ) ;
lcd_clear ( ) ;
lcd_set_cursor ( 0 , 0 ) ; lcd_puts_P ( _T ( MSG_LOADING_FILAMENT ) ) ;
if ( strlen ( _T ( MSG_LOADING_FILAMENT ) ) > 18 ) lcd_set_cursor ( 0 , 1 ) ;
2021-01-22 16:11:51 +00:00
else lcd_print ( ' ' ) ;
2018-08-07 18:37:59 +00:00
lcd_print ( mmu_extruder + 1 ) ;
2018-08-02 16:54:00 +00:00
lcd_set_cursor ( 0 , 2 ) ; lcd_puts_P ( _T ( MSG_PLEASE_WAIT ) ) ;
st_synchronize ( ) ;
max_feedrate [ E_AXIS ] = 50 ;
lcd_update_enable ( true ) ;
lcd_return_to_status ( ) ;
lcdDrawUpdate = 2 ;
# endif
}
2018-09-03 18:00:46 +00:00
struct E_step
{
float extrude ; //!< extrude distance in mm
float feed_rate ; //!< feed rate in mm/s
} ;
static const E_step ramming_sequence [ ] PROGMEM =
{
{ 1.0 , 1000.0 / 60 } ,
{ 1.0 , 1500.0 / 60 } ,
{ 2.0 , 2000.0 / 60 } ,
{ 1.5 , 3000.0 / 60 } ,
{ 2.5 , 4000.0 / 60 } ,
{ - 15.0 , 5000.0 / 60 } ,
{ - 14.0 , 1200.0 / 60 } ,
{ - 6.0 , 600.0 / 60 } ,
{ 10.0 , 700.0 / 60 } ,
{ - 10.0 , 400.0 / 60 } ,
{ - 50.0 , 2000.0 / 60 } ,
} ;
2018-09-03 15:32:42 +00:00
//! @brief Unload sequence to optimize shape of the tip of the unloaded filament
2019-01-22 09:56:07 +00:00
void mmu_filament_ramming ( )
2018-09-03 15:32:42 +00:00
{
2018-09-03 18:00:46 +00:00
for ( uint8_t i = 0 ; i < ( sizeof ( ramming_sequence ) / sizeof ( E_step ) ) ; + + i )
{
current_position [ E_AXIS ] + = pgm_read_float ( & ( ramming_sequence [ i ] . extrude ) ) ;
2020-06-01 15:51:28 +00:00
plan_buffer_line_curposXYZE ( pgm_read_float ( & ( ramming_sequence [ i ] . feed_rate ) ) ) ;
2018-09-03 18:00:46 +00:00
st_synchronize ( ) ;
}
2018-09-03 15:32:42 +00:00
}
2018-08-02 16:54:00 +00:00
2019-02-21 03:45:44 +00:00
2019-03-01 15:18:16 +00:00
//! @brief show which filament is currently unloaded
2019-02-26 22:17:52 +00:00
void extr_unload_view ( )
{
2019-03-01 15:18:16 +00:00
lcd_clear ( ) ;
2021-01-22 17:34:47 +00:00
lcd_puts_at_P ( 0 , 1 , _T ( MSG_UNLOADING_FILAMENT ) ) ;
2021-01-22 16:11:51 +00:00
lcd_print ( ' ' ) ;
if ( mmu_extruder = = MMU_FILAMENT_UNKNOWN ) lcd_print ( ' ' ) ;
2019-03-01 15:18:16 +00:00
else lcd_print ( mmu_extruder + 1 ) ;
2019-02-26 22:17:52 +00:00
}
2018-08-02 16:54:00 +00:00
void extr_unload ( )
{ //unload just current filament for multimaterial printers
# ifdef SNMM
float tmp_motor [ 3 ] = DEFAULT_PWM_MOTOR_CURRENT ;
float tmp_motor_loud [ 3 ] = DEFAULT_PWM_MOTOR_CURRENT_LOUD ;
uint8_t SilentMode = eeprom_read_byte ( ( uint8_t * ) EEPROM_SILENT ) ;
# endif
if ( degHotend0 ( ) > EXTRUDE_MINTEMP )
{
# ifndef SNMM
st_synchronize ( ) ;
2019-03-01 15:18:16 +00:00
menu_submenu ( extr_unload_view ) ;
2018-08-02 16:54:00 +00:00
2019-01-22 09:56:07 +00:00
mmu_filament_ramming ( ) ;
2018-08-02 16:54:00 +00:00
2019-02-13 00:51:39 +00:00
mmu_command ( MmuCmd : : U0 ) ;
2018-08-02 16:54:00 +00:00
// get response
2018-12-12 21:32:47 +00:00
manage_response ( false , true , MMU_UNLOAD_MOVE ) ;
2018-08-02 16:54:00 +00:00
2019-03-01 15:18:16 +00:00
menu_back ( ) ;
2018-08-02 16:54:00 +00:00
# else //SNMM
lcd_clear ( ) ;
lcd_display_message_fullscreen_P ( PSTR ( " " ) ) ;
max_feedrate [ E_AXIS ] = 50 ;
lcd_set_cursor ( 0 , 0 ) ; lcd_puts_P ( _T ( MSG_UNLOADING_FILAMENT ) ) ;
2021-01-22 16:11:51 +00:00
lcd_print ( ' ' ) ;
2018-08-07 18:37:59 +00:00
lcd_print ( mmu_extruder + 1 ) ;
2018-08-02 16:54:00 +00:00
lcd_set_cursor ( 0 , 2 ) ; lcd_puts_P ( _T ( MSG_PLEASE_WAIT ) ) ;
if ( current_position [ Z_AXIS ] < 15 ) {
current_position [ Z_AXIS ] + = 15 ; //lifting in Z direction to make space for extrusion
2019-08-21 07:59:51 +00:00
plan_buffer_line_curposXYZE ( 25 , active_extruder ) ;
2018-08-02 16:54:00 +00:00
}
current_position [ E_AXIS ] + = 10 ; //extrusion
2019-08-21 07:59:51 +00:00
plan_buffer_line_curposXYZE ( 10 , active_extruder ) ;
2018-08-02 16:54:00 +00:00
st_current_set ( 2 , E_MOTOR_HIGH_CURRENT ) ;
if ( current_temperature [ 0 ] < 230 ) { //PLA & all other filaments
current_position [ E_AXIS ] + = 5.4 ;
2019-08-21 07:59:51 +00:00
plan_buffer_line_curposXYZE ( 2800 / 60 , active_extruder ) ;
2018-08-02 16:54:00 +00:00
current_position [ E_AXIS ] + = 3.2 ;
2019-08-21 07:59:51 +00:00
plan_buffer_line_curposXYZE ( 3000 / 60 , active_extruder ) ;
2018-08-02 16:54:00 +00:00
current_position [ E_AXIS ] + = 3 ;
2019-08-21 07:59:51 +00:00
plan_buffer_line_curposXYZE ( 3400 / 60 , active_extruder ) ;
2018-08-02 16:54:00 +00:00
}
else { //ABS
current_position [ E_AXIS ] + = 3.1 ;
2019-08-21 07:59:51 +00:00
plan_buffer_line_curposXYZE ( 2000 / 60 , active_extruder ) ;
2018-08-02 16:54:00 +00:00
current_position [ E_AXIS ] + = 3.1 ;
2019-08-21 07:59:51 +00:00
plan_buffer_line_curposXYZE ( 2500 / 60 , active_extruder ) ;
2018-08-02 16:54:00 +00:00
current_position [ E_AXIS ] + = 4 ;
2019-08-21 07:59:51 +00:00
plan_buffer_line_curposXYZE ( 3000 / 60 , active_extruder ) ;
2018-08-02 16:54:00 +00:00
/*current_position[X_AXIS] += 23; //delay
2019-08-21 07:59:51 +00:00
plan_buffer_line_curposXYZE ( 600 / 60 , active_extruder ) ; //delay
2018-08-02 16:54:00 +00:00
current_position [ X_AXIS ] - = 23 ; //delay
2019-08-21 07:59:51 +00:00
plan_buffer_line_curposXYZE ( 600 / 60 , active_extruder ) ; //delay*/
2018-08-02 16:54:00 +00:00
delay_keep_alive ( 4700 ) ;
}
max_feedrate [ E_AXIS ] = 80 ;
2018-08-07 18:37:59 +00:00
current_position [ E_AXIS ] - = ( bowden_length [ mmu_extruder ] + 60 + FIL_LOAD_LENGTH ) / 2 ;
2019-08-21 07:59:51 +00:00
plan_buffer_line_curposXYZE ( 500 , active_extruder ) ;
2018-08-07 18:37:59 +00:00
current_position [ E_AXIS ] - = ( bowden_length [ mmu_extruder ] + 60 + FIL_LOAD_LENGTH ) / 2 ;
2019-08-21 07:59:51 +00:00
plan_buffer_line_curposXYZE ( 500 , active_extruder ) ;
2018-08-02 16:54:00 +00:00
st_synchronize ( ) ;
//st_current_init();
if ( SilentMode ! = SILENT_MODE_OFF ) st_current_set ( 2 , tmp_motor [ 2 ] ) ; //set back to normal operation currents
else st_current_set ( 2 , tmp_motor_loud [ 2 ] ) ;
lcd_update_enable ( true ) ;
lcd_return_to_status ( ) ;
max_feedrate [ E_AXIS ] = 50 ;
# endif //SNMM
}
else
{
2018-11-01 15:29:09 +00:00
show_preheat_nozzle_warning ( ) ;
2018-08-02 16:54:00 +00:00
}
}
//wrapper functions for loading filament
void extr_adj_0 ( )
{
# ifndef SNMM
enquecommand_P ( PSTR ( " M701 E0 " ) ) ;
# else
change_extr ( 0 ) ;
extr_adj ( 0 ) ;
# endif
}
void extr_adj_1 ( )
{
# ifndef SNMM
enquecommand_P ( PSTR ( " M701 E1 " ) ) ;
# else
change_extr ( 1 ) ;
extr_adj ( 1 ) ;
# endif
}
void extr_adj_2 ( )
{
# ifndef SNMM
enquecommand_P ( PSTR ( " M701 E2 " ) ) ;
# else
change_extr ( 2 ) ;
extr_adj ( 2 ) ;
# endif
}
void extr_adj_3 ( )
{
# ifndef SNMM
enquecommand_P ( PSTR ( " M701 E3 " ) ) ;
# else
change_extr ( 3 ) ;
extr_adj ( 3 ) ;
# endif
}
void extr_adj_4 ( )
{
# ifndef SNMM
enquecommand_P ( PSTR ( " M701 E4 " ) ) ;
# else
change_extr ( 4 ) ;
extr_adj ( 4 ) ;
# endif
}
void load_all ( )
{
# ifndef SNMM
enquecommand_P ( PSTR ( " M701 E0 " ) ) ;
enquecommand_P ( PSTR ( " M701 E1 " ) ) ;
enquecommand_P ( PSTR ( " M701 E2 " ) ) ;
enquecommand_P ( PSTR ( " M701 E3 " ) ) ;
enquecommand_P ( PSTR ( " M701 E4 " ) ) ;
# else
for ( int i = 0 ; i < 4 ; i + + )
{
change_extr ( i ) ;
extr_adj ( i ) ;
}
# endif
}
//wrapper functions for changing extruders
void extr_change_0 ( )
{
change_extr ( 0 ) ;
lcd_return_to_status ( ) ;
}
void extr_change_1 ( )
{
change_extr ( 1 ) ;
lcd_return_to_status ( ) ;
}
void extr_change_2 ( )
{
change_extr ( 2 ) ;
lcd_return_to_status ( ) ;
}
void extr_change_3 ( )
{
change_extr ( 3 ) ;
lcd_return_to_status ( ) ;
}
2018-10-31 20:48:05 +00:00
# ifdef SNMM
2018-08-02 16:54:00 +00:00
//wrapper functions for unloading filament
void extr_unload_all ( )
{
if ( degHotend0 ( ) > EXTRUDE_MINTEMP )
{
for ( int i = 0 ; i < 4 ; i + + )
{
change_extr ( i ) ;
extr_unload ( ) ;
}
}
else
{
2018-11-01 15:29:09 +00:00
show_preheat_nozzle_warning ( ) ;
2018-08-02 16:54:00 +00:00
lcd_return_to_status ( ) ;
}
}
//unloading just used filament (for snmm)
void extr_unload_used ( )
{
if ( degHotend0 ( ) > EXTRUDE_MINTEMP ) {
for ( int i = 0 ; i < 4 ; i + + ) {
if ( snmm_filaments_used & ( 1 < < i ) ) {
change_extr ( i ) ;
extr_unload ( ) ;
}
}
snmm_filaments_used = 0 ;
}
else {
2018-11-01 15:29:09 +00:00
show_preheat_nozzle_warning ( ) ;
2018-08-02 16:54:00 +00:00
lcd_return_to_status ( ) ;
}
}
2018-10-31 20:48:05 +00:00
# endif //SNMM
2018-08-02 16:54:00 +00:00
void extr_unload_0 ( )
{
change_extr ( 0 ) ;
extr_unload ( ) ;
}
void extr_unload_1 ( )
{
change_extr ( 1 ) ;
extr_unload ( ) ;
}
void extr_unload_2 ( )
{
change_extr ( 2 ) ;
extr_unload ( ) ;
}
void extr_unload_3 ( )
{
change_extr ( 3 ) ;
extr_unload ( ) ;
}
void extr_unload_4 ( )
{
change_extr ( 4 ) ;
extr_unload ( ) ;
}
2018-08-25 14:15:35 +00:00
bool mmu_check_version ( )
{
return ( mmu_buildnr > = MMU_REQUIRED_FW_BUILDNR ) ;
}
void mmu_show_warning ( )
{
printf_P ( PSTR ( " MMU2 firmware version invalid. Required version: build number %d or higher. " ) , MMU_REQUIRED_FW_BUILDNR ) ;
kill ( _i ( " Please update firmware in your MMU2. Waiting for reset. " ) ) ;
}
2018-08-28 21:50:31 +00:00
2018-11-01 15:29:09 +00:00
void lcd_mmu_load_to_nozzle ( uint8_t filament_nr )
{
2019-05-14 14:45:15 +00:00
menu_back ( ) ;
bFilamentAction = false ; // NOT in "mmu_load_to_nozzle_menu()"
if ( degHotend0 ( ) > EXTRUDE_MINTEMP )
{
tmp_extruder = filament_nr ;
lcd_update_enable ( false ) ;
lcd_clear ( ) ;
2021-01-22 17:34:47 +00:00
lcd_puts_at_P ( 0 , 1 , _T ( MSG_LOADING_FILAMENT ) ) ;
2021-01-22 16:11:51 +00:00
lcd_print ( ' ' ) ;
2019-05-14 14:45:15 +00:00
lcd_print ( tmp_extruder + 1 ) ;
mmu_command ( MmuCmd : : T0 + tmp_extruder ) ;
manage_response ( true , true , MMU_TCODE_MOVE ) ;
mmu_continue_loading ( false ) ;
mmu_extruder = tmp_extruder ; //filament change is finished
2019-06-05 16:12:46 +00:00
raise_z_above ( MIN_Z_FOR_LOAD , false ) ;
2019-05-14 14:45:15 +00:00
mmu_load_to_nozzle ( ) ;
load_filament_final_feed ( ) ;
st_synchronize ( ) ;
2019-06-12 16:42:55 +00:00
custom_message_type = CustomMsg : : FilamentLoading ;
2019-05-14 14:45:15 +00:00
lcd_setstatuspgm ( _T ( MSG_LOADING_FILAMENT ) ) ;
lcd_return_to_status ( ) ;
lcd_update_enable ( true ) ;
lcd_load_filament_color_check ( ) ;
lcd_setstatuspgm ( _T ( WELCOME_MSG ) ) ;
2019-06-12 16:42:55 +00:00
custom_message_type = CustomMsg : : Status ;
2019-05-14 14:45:15 +00:00
}
else
{
show_preheat_nozzle_warning ( ) ;
}
2018-11-01 15:29:09 +00:00
}
2019-03-15 02:38:37 +00:00
# ifdef MMU_HAS_CUTTER
2019-02-26 16:58:00 +00:00
void mmu_cut_filament ( uint8_t filament_nr )
{
2019-05-14 14:25:29 +00:00
menu_back ( ) ;
2019-03-15 02:38:37 +00:00
bFilamentAction = false ; // NOT in "mmu_load_to_nozzle_menu()"
if ( degHotend0 ( ) > EXTRUDE_MINTEMP )
{
LcdUpdateDisabler disableLcdUpdate ;
lcd_clear ( ) ;
2021-03-30 07:01:58 +00:00
lcd_puts_at_P ( 0 , 1 , _i ( " Cutting filament " ) ) ; ////MSG_MMU_CUTTING_FIL c=18
2021-01-22 16:11:51 +00:00
lcd_print ( ' ' ) ;
2019-03-15 02:38:37 +00:00
lcd_print ( filament_nr + 1 ) ;
mmu_filament_ramming ( ) ;
mmu_command ( MmuCmd : : K0 + filament_nr ) ;
manage_response ( false , false , MMU_UNLOAD_MOVE ) ;
}
else
{
show_preheat_nozzle_warning ( ) ;
}
2019-02-26 16:58:00 +00:00
}
2019-03-15 02:38:37 +00:00
# endif //MMU_HAS_CUTTER
2019-02-26 16:58:00 +00:00
2018-08-28 23:58:28 +00:00
void mmu_eject_filament ( uint8_t filament , bool recover )
2018-08-28 21:50:31 +00:00
{
2019-02-20 02:01:33 +00:00
//-//
2019-02-21 03:45:44 +00:00
bFilamentAction = false ; // NOT in "mmu_fil_eject_menu()"
2018-08-28 23:58:28 +00:00
if ( filament < 5 )
{
2018-08-29 11:16:17 +00:00
if ( degHotend0 ( ) > EXTRUDE_MINTEMP )
2018-08-28 23:58:28 +00:00
{
2018-08-29 11:16:17 +00:00
st_synchronize ( ) ;
2018-09-17 15:05:11 +00:00
{
LcdUpdateDisabler disableLcdUpdate ;
lcd_clear ( ) ;
2021-01-22 17:34:47 +00:00
lcd_puts_at_P ( 0 , 1 , _i ( " Ejecting filament " ) ) ;
2019-02-26 12:40:23 +00:00
mmu_filament_ramming ( ) ;
2019-02-13 16:12:35 +00:00
mmu_command ( MmuCmd : : E0 + filament ) ;
2018-12-12 21:32:47 +00:00
manage_response ( false , false , MMU_UNLOAD_MOVE ) ;
2018-09-17 19:23:13 +00:00
if ( recover )
{
lcd_show_fullscreen_message_and_wait_P ( _i ( " Please remove filament and then press the knob. " ) ) ;
2019-02-13 00:51:39 +00:00
mmu_command ( MmuCmd : : R0 ) ;
2018-09-17 19:23:13 +00:00
manage_response ( false , false ) ;
}
}
2018-08-29 11:16:17 +00:00
}
else
{
2018-11-01 15:29:09 +00:00
show_preheat_nozzle_warning ( ) ;
2018-08-28 23:58:28 +00:00
}
}
else
{
puts_P ( PSTR ( " Filament nr out of range! " ) ) ;
}
2018-09-03 15:32:42 +00:00
}
2018-12-12 13:50:55 +00:00
2019-06-18 17:15:16 +00:00
//! @brief Fits filament tip into heatbreak?
//!
2019-06-18 18:00:02 +00:00
//! If PTFE tube is jammed, this causes filament to be unloaded and no longer
//! being detected by the pulley IR sensor.
2019-06-18 17:15:16 +00:00
//! @retval true Fits
//! @retval false Doesn't fit
static bool can_load ( )
{
current_position [ E_AXIS ] + = 60 ;
2020-06-01 15:51:28 +00:00
plan_buffer_line_curposXYZE ( MMU_LOAD_FEEDRATE ) ;
2019-06-18 17:15:16 +00:00
current_position [ E_AXIS ] - = 52 ;
2020-06-01 15:51:28 +00:00
plan_buffer_line_curposXYZE ( MMU_LOAD_FEEDRATE ) ;
2019-06-18 17:15:16 +00:00
st_synchronize ( ) ;
uint_least8_t filament_detected_count = 0 ;
const float e_increment = 0.2 ;
const uint_least8_t steps = 6.0 / e_increment ;
DEBUG_PUTS_P ( PSTR ( " MMU can_load: " ) ) ;
for ( uint_least8_t i = 0 ; i < steps ; + + i )
{
current_position [ E_AXIS ] - = e_increment ;
2020-06-01 15:51:28 +00:00
plan_buffer_line_curposXYZE ( MMU_LOAD_FEEDRATE ) ;
2019-06-18 17:15:16 +00:00
st_synchronize ( ) ;
2020-09-11 14:43:38 +00:00
if ( 0 = = READ ( IR_SENSOR_PIN ) )
2019-06-18 17:15:16 +00:00
{
+ + filament_detected_count ;
DEBUG_PUTCHAR ( ' O ' ) ;
}
else
{
DEBUG_PUTCHAR ( ' o ' ) ;
}
}
if ( filament_detected_count > steps - 4 )
{
DEBUG_PUTS_P ( PSTR ( " succeeded. " ) ) ;
return true ;
}
else
{
DEBUG_PUTS_P ( PSTR ( " failed. " ) ) ;
return false ;
}
}
2019-02-21 01:30:01 +00:00
//! @brief load more
//!
//! Try to feed more filament from MMU if it is not detected by filament sensor.
2019-06-18 17:15:16 +00:00
//! @retval true Success, filament detected by IR sensor
//! @retval false Failed, filament not detected by IR sensor after maximum number of attempts
static bool load_more ( )
2018-12-12 13:50:55 +00:00
{
2019-02-05 17:25:11 +00:00
for ( uint8_t i = 0 ; i < MMU_IDLER_SENSOR_ATTEMPTS_NR ; i + + )
{
2020-09-11 14:43:38 +00:00
if ( READ ( IR_SENSOR_PIN ) = = 0 ) return true ;
2019-02-12 22:24:23 +00:00
DEBUG_PRINTF_P ( PSTR ( " Additional load attempt nr. %d \n " ) , i ) ;
2019-02-13 00:51:39 +00:00
mmu_command ( MmuCmd : : C0 ) ;
2019-02-05 17:25:11 +00:00
manage_response ( true , true , MMU_LOAD_MOVE ) ;
}
2019-06-18 17:15:16 +00:00
return false ;
2019-02-05 17:25:11 +00:00
}
2019-04-09 18:50:29 +00:00
static void increment_load_fail ( )
2019-02-05 17:25:11 +00:00
{
2019-04-09 18:50:29 +00:00
uint8_t mmu_load_fail = eeprom_read_byte ( ( uint8_t * ) EEPROM_MMU_LOAD_FAIL ) ;
uint16_t mmu_load_fail_tot = eeprom_read_word ( ( uint16_t * ) EEPROM_MMU_LOAD_FAIL_TOT ) ;
if ( mmu_load_fail < 255 ) eeprom_update_byte ( ( uint8_t * ) EEPROM_MMU_LOAD_FAIL , mmu_load_fail + 1 ) ;
if ( mmu_load_fail_tot < 65535 ) eeprom_update_word ( ( uint16_t * ) EEPROM_MMU_LOAD_FAIL_TOT , mmu_load_fail_tot + 1 ) ;
}
//! @brief continue loading filament
2019-04-04 16:15:37 +00:00
//! @par blocking
2019-04-09 18:50:29 +00:00
//! * true blocking - do not return until successful load
//! * false non-blocking - pause print and return on load failure
//!
//! @startuml
//! [*] --> [*] : !ir_sensor_detected /\n send MmuCmd::C0
//! [*] --> LoadMore
//! LoadMore --> [*] : filament \ndetected
//! LoadMore --> Retry : !filament detected /\n increment load fail
//! Retry --> [*] : filament \ndetected
//! Retry --> Unload : !filament \ndetected
//! Unload --> [*] : non-blocking
//! Unload --> Retry : button \nclicked
//!
//! Retry : Cut filament if enabled
//! Retry : repeat last T-code
//! Unload : unload filament
//! Unload : pause print
//! Unload : show error message
//!
//! @enduml
2019-04-04 16:15:37 +00:00
void mmu_continue_loading ( bool blocking )
2018-12-12 13:50:55 +00:00
{
2019-04-09 18:50:29 +00:00
if ( ! ir_sensor_detected )
2019-02-05 17:25:11 +00:00
{
2019-04-09 18:50:29 +00:00
mmu_command ( MmuCmd : : C0 ) ;
return ;
}
2018-12-12 21:32:47 +00:00
2019-06-18 17:15:16 +00:00
bool success = load_more ( ) ;
if ( success ) success = can_load ( ) ;
2019-02-05 17:25:11 +00:00
2019-04-09 18:50:29 +00:00
enum class Ls : uint_least8_t
{
2019-06-12 14:20:21 +00:00
Enter ,
Retry ,
Unload ,
2019-04-09 18:50:29 +00:00
} ;
2019-06-12 14:20:21 +00:00
Ls state = Ls : : Enter ;
2018-12-21 16:12:16 +00:00
2019-09-10 16:49:23 +00:00
const uint_least8_t max_retry = 3 ;
2019-06-18 17:15:16 +00:00
uint_least8_t retry = 0 ;
2019-04-09 18:50:29 +00:00
2019-06-18 17:15:16 +00:00
while ( ! success )
2019-04-09 18:50:29 +00:00
{
switch ( state )
{
2019-06-12 14:20:21 +00:00
case Ls : : Enter :
2019-04-09 18:50:29 +00:00
increment_load_fail ( ) ;
2021-02-03 18:45:37 +00:00
// FALLTHRU
2019-06-12 14:20:21 +00:00
case Ls : : Retry :
2019-09-10 16:36:14 +00:00
+ + retry ; // overflow not handled, as it is not dangerous.
if ( retry > = max_retry )
2019-04-09 18:50:29 +00:00
{
2019-09-10 16:36:14 +00:00
state = Ls : : Unload ;
# ifdef MMU_HAS_CUTTER
if ( 1 = = eeprom_read_byte ( ( uint8_t * ) EEPROM_MMU_CUTTER_ENABLED ) )
{
mmu_command ( MmuCmd : : K0 + tmp_extruder ) ;
manage_response ( true , true , MMU_UNLOAD_MOVE ) ;
}
2019-03-15 02:38:37 +00:00
# endif //MMU_HAS_CUTTER
2019-09-10 16:36:14 +00:00
}
2019-02-13 16:12:35 +00:00
mmu_command ( MmuCmd : : T0 + tmp_extruder ) ;
2019-02-05 17:25:11 +00:00
manage_response ( true , true , MMU_TCODE_MOVE ) ;
2019-06-18 17:15:16 +00:00
success = load_more ( ) ;
if ( success ) success = can_load ( ) ;
2019-09-10 16:36:14 +00:00
2019-04-09 18:50:29 +00:00
break ;
2019-06-12 14:20:21 +00:00
case Ls : : Unload :
2019-04-09 18:50:29 +00:00
stop_and_save_print_to_ram ( 0 , 0 ) ;
2019-11-02 11:15:13 +00:00
long_pause ( ) ;
2019-04-09 18:50:29 +00:00
mmu_command ( MmuCmd : : U0 ) ;
manage_response ( false , true , MMU_UNLOAD_MOVE ) ;
setAllTargetHotends ( 0 ) ;
2021-04-26 05:22:22 +00:00
lcd_setstatuspgm ( _i ( " MMU load failed " ) ) ; ////MSG_MMU_LOAD_FAILED c=20
2019-04-09 18:50:29 +00:00
if ( blocking )
2019-02-05 17:25:11 +00:00
{
2019-04-09 18:50:29 +00:00
marlin_wait_for_click ( ) ;
2019-12-28 19:26:19 +00:00
st_synchronize ( ) ;
2019-04-09 18:50:29 +00:00
restore_print_from_ram_and_continue ( 0 ) ;
2019-06-12 14:20:21 +00:00
state = Ls : : Retry ;
2019-02-05 17:25:11 +00:00
}
2019-04-09 18:50:29 +00:00
else
2019-02-05 17:25:11 +00:00
{
mmu_fil_loaded = false ; //so we can retry same T-code again
isPrintPaused = true ;
2019-02-13 18:10:55 +00:00
mmu_command ( MmuCmd : : W0 ) ;
2019-04-09 18:50:29 +00:00
return ;
2019-02-05 17:25:11 +00:00
}
2019-04-09 18:50:29 +00:00
break ;
}
}
2018-12-12 13:50:55 +00:00
}