Browse Source

Merge branch 'MK3' into MK3

PavelSindler 6 years ago
parent
commit
40679dcb3a

+ 1 - 0
.gitignore

@@ -12,3 +12,4 @@ Firmware/Doc
 /Firmware/Firmware - Shortcut.lnk
 /Firmware/variants/1_75mm_MK3-MMU-EINSy10a-E3Dv6full.h.bak
 /Firmware/Marlin_main.cpp~RF12cfae7.TMP
+/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h.bak

+ 2 - 2
Firmware/Configuration.h

@@ -7,8 +7,8 @@
 #define STR(x) STR_HELPER(x)
 
 // Firmware version
-#define FW_VERSION "3.4.0-RC1"
-#define FW_COMMIT_NR   1170
+#define FW_VERSION "3.4.0-RC2"
+#define FW_COMMIT_NR   1267
 // FW_VERSION_UNKNOWN means this is an unofficial build.
 // The firmware should only be checked into github with this symbol.
 #define FW_DEV_VERSION FW_VERSION_UNKNOWN

+ 5 - 2
Firmware/Marlin.h

@@ -348,6 +348,7 @@ extern bool sortAlpha;
 
 extern char dir_names[3][9];
 
+extern int8_t lcd_change_fil_state;
 // save/restore printing
 extern bool saved_printing;
 
@@ -359,6 +360,9 @@ extern uint8_t print_percent_done_normal;
 extern uint32_t print_time_remaining_normal;
 extern uint8_t print_percent_done_silent;
 extern uint32_t print_time_remaining_silent;
+extern uint16_t mcode_in_progress;
+extern uint16_t gcode_in_progress;
+
 #define PRINT_TIME_REMAINING_INIT 0xffffffff
 #define PRINT_PERCENT_DONE_INIT   0xff
 #define PRINTER_ACTIVE (IS_SD_PRINTING || is_usb_printing || isPrintPaused || (custom_message_type == CUSTOM_MSG_TYPE_TEMCAL) || saved_printing || (lcd_commands_type == LCD_COMMAND_V2_CAL) || card.paused || mmu_print_saved)
@@ -391,7 +395,6 @@ uint8_t check_printer_version();
 float temp_compensation_pinda_thermistor_offset(float temperature_pinda);
 #endif //PINDA_THERMISTOR
 
-void wait_for_heater(long codenum);
 void serialecho_temperatures();
 bool check_commands();
 
@@ -468,4 +471,4 @@ void proc_commands();
 void M600_load_filament();
 void M600_load_filament_movements();
 void M600_wait_for_user();
-void M600_check_state();
+void M600_check_state();

+ 250 - 203
Firmware/Marlin_main.cpp

@@ -543,8 +543,9 @@ static bool saved_extruder_relative_mode = false;
 //===========================================================================
 
 static void get_arc_coordinates();
-static bool setTargetedHotend(int code);
+static bool setTargetedHotend(int code, uint8_t &extruder);
 static void print_time_remaining_init();
+static void wait_for_heater(long codenum, uint8_t extruder);
 
 uint16_t gcode_in_progress = 0;
 uint16_t mcode_in_progress = 0;
@@ -1355,6 +1356,7 @@ void setup()
 	plan_init();  // Initialize planner;
 
 	factory_reset();
+     lcd_encoder_diff=0;
 
 #ifdef TMC2130
 	uint8_t silentMode = eeprom_read_byte((uint8_t*)EEPROM_SILENT);
@@ -1962,8 +1964,8 @@ void loop()
   checkHitEndstops();
   lcd_update(0);
 #ifdef FILAMENT_SENSOR
-	if (mcode_in_progress != 600) //M600 not in progress
-		fsensor_update();
+  if (mcode_in_progress != 600 && !mmu_enabled) //M600 not in progress
+	  fsensor_update();
 #endif //FILAMENT_SENSOR
 #ifdef TMC2130
 	tmc2130_check_overtemp();
@@ -3097,7 +3099,7 @@ void gcode_M600(bool automatic, float x_position, float y_position, float z_shif
 		st_synchronize();
 		
 		//Beep, manage nozzle heater and wait for user to start unload filament
-		if(!automatic) M600_wait_for_user();
+		if(!mmu_enabled) M600_wait_for_user();
 		
 		lcd_change_fil_state = 0;
 		
@@ -3118,12 +3120,29 @@ void gcode_M600(bool automatic, float x_position, float y_position, float z_shif
 		}
 
 		if (mmu_enabled)
+		{
+			if (!automatic) {
+				if (saved_printing) mmu_eject_filament(mmu_extruder, false); //if M600 was invoked by filament senzor (FINDA) eject filament so user can easily remove it
+				mmu_M600_wait_and_beep();
+				if (saved_printing) {
+
+					lcd_clear();
+					lcd_set_cursor(0, 2);
+					lcd_puts_P(_T(MSG_PLEASE_WAIT));
+
+					mmu_command(MMU_CMD_R0);
+					manage_response(false, false);
+				}
+			}
 			mmu_M600_load_filament(automatic);
+		}
 		else
 			M600_load_filament();
 
 		if(!automatic) M600_check_state();
 
+		lcd_update_enable(true);
+
       //Not let's go back to print
 	  fanSpeed = fanSpeedBckp;
 
@@ -3139,7 +3158,7 @@ void gcode_M600(bool automatic, float x_position, float y_position, float z_shif
       //Move Z back
       plan_buffer_line(lastpos[X_AXIS], lastpos[Y_AXIS], lastpos[Z_AXIS], current_position[E_AXIS], FILAMENTCHANGE_ZFEED, active_extruder);
       st_synchronize();  
-      
+
       //Set E position to original  
       plan_set_e_position(lastpos[E_AXIS]);
 
@@ -3162,8 +3181,11 @@ void gcode_M701()
 {
 	printf_P(PSTR("gcode_M701 begin\n"));
 
-	if (mmu_enabled)
-		extr_adj(mmu_extruder);//loads current extruder
+	if (mmu_enabled) 
+	{
+		extr_adj(tmp_extruder);//loads current extruder
+		mmu_extruder = tmp_extruder;
+	}
 	else
 	{
 		enable_z();
@@ -3212,15 +3234,18 @@ void gcode_M701()
 		custom_message_type = CUSTOM_MSG_TYPE_STATUS;
 
 #ifdef FILAMENT_SENSOR
-		fsensor_oq_meassure_stop();
-
-		if (!fsensor_oq_result())
+		if (mmu_enabled == false) 
 		{
-			bool disable = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Fil. sensor response is poor, disable it?"), false, true);
-			lcd_update_enable(true);
-			lcd_update(2);
-			if (disable)
-				fsensor_disable();
+			fsensor_oq_meassure_stop();
+
+			if (!fsensor_oq_result())
+			{
+				bool disable = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Fil. sensor response is poor, disable it?"), false, true);
+				lcd_update_enable(true);
+				lcd_update(2);
+				if (disable)
+					fsensor_disable();
+			}
 		}
 #endif //FILAMENT_SENSOR
 	}
@@ -3408,7 +3433,9 @@ void process_commands()
 	}
 #endif //BACKLASH_Y
 #endif //TMC2130
-
+	else if (code_seen("FSENSOR_RECOVER")) {
+		fsensor_restore_print_and_continue();
+  }
   else if(code_seen("PRUSA")){
 		if (code_seen("Ping")) {  //PRUSA Ping
 			if (farm_mode) {
@@ -5340,15 +5367,18 @@ Sigma_Exit:
 		break;
 
     case 104: // M104
-      if(setTargetedHotend(104)){
-        break;
-      }
-      if (code_seen('S'))
-      {
-          setTargetHotendSafe(code_value(), tmp_extruder);
-      }
-      setWatch();
-      break;
+    {
+          uint8_t extruder;
+          if(setTargetedHotend(104,extruder)){
+            break;
+          }
+          if (code_seen('S'))
+          {
+              setTargetHotendSafe(code_value(), extruder);
+          }
+          setWatch();
+          break;
+    }
     case 112: //  M112 -Emergency Stop
       kill(_n(""), 3);
       break;
@@ -5356,14 +5386,16 @@ Sigma_Exit:
       if (code_seen('S')) setTargetBed(code_value());
       break;
     case 105 : // M105
-      if(setTargetedHotend(105)){
+    {
+      uint8_t extruder;
+      if(setTargetedHotend(105, extruder)){
         break;
         }
       #if defined(TEMP_0_PIN) && TEMP_0_PIN > -1
         SERIAL_PROTOCOLPGM("ok T:");
-        SERIAL_PROTOCOL_F(degHotend(tmp_extruder),1);
+        SERIAL_PROTOCOL_F(degHotend(extruder),1);
         SERIAL_PROTOCOLPGM(" /");
-        SERIAL_PROTOCOL_F(degTargetHotend(tmp_extruder),1);
+        SERIAL_PROTOCOL_F(degTargetHotend(extruder),1);
         #if defined(TEMP_BED_PIN) && TEMP_BED_PIN > -1
           SERIAL_PROTOCOLPGM(" B:");
           SERIAL_PROTOCOL_F(degBed(),1);
@@ -5388,7 +5420,7 @@ Sigma_Exit:
         SERIAL_PROTOCOL((EXTRUDER_WATTS * getHeaterPower(tmp_extruder))/127);
         SERIAL_PROTOCOLPGM("W");
       #else
-        SERIAL_PROTOCOL(getHeaterPower(tmp_extruder));
+        SERIAL_PROTOCOL(getHeaterPower(extruder));
       #endif
 
         SERIAL_PROTOCOLPGM(" B@:");
@@ -5446,9 +5478,11 @@ Sigma_Exit:
 		KEEPALIVE_STATE(NOT_BUSY);
       return;
       break;
+    }
     case 109:
     {// M109 - Wait for extruder heater to reach target.
-      if(setTargetedHotend(109)){
+      uint8_t extruder;
+      if(setTargetedHotend(109, extruder)){
         break;
       }
       LCD_MESSAGERPGM(_T(MSG_HEATING));
@@ -5459,10 +5493,10 @@ Sigma_Exit:
         autotemp_enabled=false;
       #endif
       if (code_seen('S')) {
-          setTargetHotendSafe(code_value(), tmp_extruder);
+          setTargetHotendSafe(code_value(), extruder);
               CooldownNoWait = true;
             } else if (code_seen('R')) {
-                setTargetHotendSafe(code_value(), tmp_extruder);
+                setTargetHotendSafe(code_value(), extruder);
         CooldownNoWait = false;
       }
       #ifdef AUTOTEMP
@@ -5479,13 +5513,13 @@ Sigma_Exit:
       codenum = millis();
 
       /* See if we are heating up or cooling down */
-      target_direction = isHeatingHotend(tmp_extruder); // true if heating, false if cooling
+      target_direction = isHeatingHotend(extruder); // true if heating, false if cooling
 	  
 	  KEEPALIVE_STATE(NOT_BUSY);
 
       cancel_heatup = false;
 
-	  wait_for_heater(codenum); //loops until target temperature is reached
+	  wait_for_heater(codenum, extruder); //loops until target temperature is reached
 
         LCD_MESSAGERPGM(_T(MSG_HEATING_COMPLETE));
 		KEEPALIVE_STATE(IN_HANDLER);
@@ -5806,10 +5840,10 @@ Sigma_Exit:
     case 200: // M200 D<millimeters> set filament diameter and set E axis units to cubic millimeters (use S0 to set back to millimeters).
       {
 
-        tmp_extruder = active_extruder;
+        uint8_t extruder = active_extruder;
         if(code_seen('T')) {
-          tmp_extruder = code_value();
-		  if(tmp_extruder >= EXTRUDERS) {
+          extruder = code_value();
+		  if(extruder >= EXTRUDERS) {
             SERIAL_ECHO_START;
             SERIAL_ECHO(_i("M200 Invalid extruder "));////MSG_M200_INVALID_EXTRUDER c=0 r=0
             break;
@@ -5823,7 +5857,7 @@ Sigma_Exit:
 			// for all extruders
 		    volumetric_enabled = false;
 		  } else {
-            filament_size[tmp_extruder] = (float)code_value();
+            filament_size[extruder] = (float)code_value();
 			// make sure all extruders have some sane value for the filament size
 			filament_size[0] = (filament_size[0] == 0.0 ? DEFAULT_NOMINAL_FILAMENT_DIA : filament_size[0]);
             #if EXTRUDERS > 1
@@ -6011,25 +6045,26 @@ Sigma_Exit:
     #if EXTRUDERS > 1
     case 218: // M218 - set hotend offset (in mm), T<extruder_number> X<offset_on_X> Y<offset_on_Y>
     {
-      if(setTargetedHotend(218)){
+      uint8_t extruder;
+      if(setTargetedHotend(218, extruder)){
         break;
       }
       if(code_seen('X'))
       {
-        extruder_offset[X_AXIS][tmp_extruder] = code_value();
+        extruder_offset[X_AXIS][extruder] = code_value();
       }
       if(code_seen('Y'))
       {
-        extruder_offset[Y_AXIS][tmp_extruder] = code_value();
+        extruder_offset[Y_AXIS][extruder] = code_value();
       }
       SERIAL_ECHO_START;
       SERIAL_ECHORPGM(MSG_HOTEND_OFFSET);
-      for(tmp_extruder = 0; tmp_extruder < EXTRUDERS; tmp_extruder++)
+      for(extruder = 0; extruder < EXTRUDERS; extruder++)
       {
          SERIAL_ECHO(" ");
-         SERIAL_ECHO(extruder_offset[X_AXIS][tmp_extruder]);
+         SERIAL_ECHO(extruder_offset[X_AXIS][extruder]);
          SERIAL_ECHO(",");
-         SERIAL_ECHO(extruder_offset[Y_AXIS][tmp_extruder]);
+         SERIAL_ECHO(extruder_offset[Y_AXIS][extruder]);
       }
       SERIAL_ECHOLN("");
     }break;
@@ -6049,10 +6084,11 @@ Sigma_Exit:
         int tmp_code = code_value();
         if (code_seen('T'))
         {
-          if(setTargetedHotend(221)){
+          uint8_t extruder;
+          if(setTargetedHotend(221, extruder)){
             break;
           }
-          extruder_multiply[tmp_extruder] = tmp_code;
+          extruder_multiply[extruder] = tmp_code;
         }
         else
         {
@@ -6744,7 +6780,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 	case 701: //M701: load filament
 	{
 		if (mmu_enabled && code_seen('E'))
-			mmu_extruder = code_value();
+			tmp_extruder = code_value();
 		gcode_M701();
 	}
 	break;
@@ -6780,132 +6816,132 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 
   else if(code_seen('T'))
   {
-	  int index;
-	  st_synchronize();
-	  for (index = 1; *(strchr_pointer + index) == ' ' || *(strchr_pointer + index) == '\t'; index++);
-	   
-	  if ((*(strchr_pointer + index) < '0' || *(strchr_pointer + index) > '9') && *(strchr_pointer + index) != '?') {
-		  SERIAL_ECHOLNPGM("Invalid T code.");
-	  }
-	  else {
-		  if (*(strchr_pointer + index) == '?') {
-			  tmp_extruder = choose_extruder_menu();
-		  }
-		  else {
-			  tmp_extruder = code_value();
-		  }
-		  snmm_filaments_used |= (1 << tmp_extruder); //for stop print
+      int index;
+      st_synchronize();
+      for (index = 1; *(strchr_pointer + index) == ' ' || *(strchr_pointer + index) == '\t'; index++);
 
-if (mmu_enabled)
-{
-		  //printf_P(PSTR("T code: %d \n"), tmp_extruder);
-		  //mmu_printf_P(PSTR("T%d\n"), tmp_extruder);
-		  mmu_command(MMU_CMD_T0 + tmp_extruder);
+      if ((*(strchr_pointer + index) < '0' || *(strchr_pointer + index) > '4') && *(strchr_pointer + index) != '?') {
+          SERIAL_ECHOLNPGM("Invalid T code.");
+      }
+      else {
+          if (*(strchr_pointer + index) == '?') {
+              tmp_extruder = choose_extruder_menu();
+          }
+          else {
+              tmp_extruder = code_value();
+          }
+          snmm_filaments_used |= (1 << tmp_extruder); //for stop print
 
-		  manage_response(true, true);
+          if (mmu_enabled)
+          {
+              mmu_command(MMU_CMD_T0 + tmp_extruder);
 
-    	  mmu_extruder = tmp_extruder; //filament change is finished
+              manage_response(true, true);
+              mmu_command(MMU_CMD_C0);
+              mmu_extruder = tmp_extruder; //filament change is finished
 
-		  if (*(strchr_pointer + index) == '?')// for single material usage with mmu
-			  mmu_load_to_nozzle();
-}
-else
-{
+              if (*(strchr_pointer + index) == '?')// for single material usage with mmu
+              {
+                  mmu_load_to_nozzle();
+              }
+          }
+          else
+          {
 #ifdef SNMM
 
-	#ifdef LIN_ADVANCE
-          if (mmu_extruder != tmp_extruder)
-            clear_current_adv_vars(); //Check if the selected extruder is not the active one and reset LIN_ADVANCE variables if so.
-	#endif
-          
-		  mmu_extruder = tmp_extruder;
+#ifdef LIN_ADVANCE
+              if (mmu_extruder != tmp_extruder)
+                  clear_current_adv_vars(); //Check if the selected extruder is not the active one and reset LIN_ADVANCE variables if so.
+#endif
 
-		  
-		  delay(100);
-
-		  disable_e0();
-		  disable_e1();
-		  disable_e2();
-
-		  pinMode(E_MUX0_PIN, OUTPUT);
-		  pinMode(E_MUX1_PIN, OUTPUT);
-
-		  delay(100);
-		  SERIAL_ECHO_START;
-		  SERIAL_ECHO("T:");
-		  SERIAL_ECHOLN((int)tmp_extruder);
-		  switch (tmp_extruder) {
-		  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;
-		  }
-		  delay(100);
+              mmu_extruder = tmp_extruder;
+
+
+              delay(100);
+
+              disable_e0();
+              disable_e1();
+              disable_e2();
+
+              pinMode(E_MUX0_PIN, OUTPUT);
+              pinMode(E_MUX1_PIN, OUTPUT);
+
+              delay(100);
+              SERIAL_ECHO_START;
+              SERIAL_ECHO("T:");
+              SERIAL_ECHOLN((int)tmp_extruder);
+              switch (tmp_extruder) {
+              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;
+              }
+              delay(100);
 
 #else //SNMM
-		  if (tmp_extruder >= EXTRUDERS) {
-			  SERIAL_ECHO_START;
-			  SERIAL_ECHOPGM("T");
-			  SERIAL_PROTOCOLLN((int)tmp_extruder);
-			  SERIAL_ECHOLNRPGM(_n("Invalid extruder"));////MSG_INVALID_EXTRUDER c=0 r=0
-		  }
-		  else {
-			#if EXTRUDERS > 1
-		      boolean make_move = false;
-			#endif
-			  if (code_seen('F')) {
-			#if EXTRUDERS > 1
-				  make_move = true;
-			#endif
-				  next_feedrate = code_value();
-				  if (next_feedrate > 0.0) {
-					  feedrate = next_feedrate;
-				  }
-			  }
-			#if EXTRUDERS > 1
-			  if (tmp_extruder != active_extruder) {
-				  // Save current position to return to after applying extruder offset
-				  memcpy(destination, current_position, sizeof(destination));
-				  // Offset extruder (only by XY)
-				  int i;
-				  for (i = 0; i < 2; i++) {
-					  current_position[i] = current_position[i] -
-						  extruder_offset[i][active_extruder] +
-						  extruder_offset[i][tmp_extruder];
-				  }
-				  // Set the new active extruder and position
-				  active_extruder = tmp_extruder;
-				  plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
-				  // Move to the old position if 'F' was in the parameters
-				  if (make_move && Stopped == false) {
-					  prepare_move();
-				  }
-			  }
-			#endif
-			  SERIAL_ECHO_START;
-			  SERIAL_ECHORPGM(_n("Active Extruder: "));////MSG_ACTIVE_EXTRUDER c=0 r=0
-			  SERIAL_PROTOCOLLN((int)active_extruder);
-		  }
+              if (tmp_extruder >= EXTRUDERS) {
+                  SERIAL_ECHO_START;
+                  SERIAL_ECHOPGM("T");
+                  SERIAL_PROTOCOLLN((int)tmp_extruder);
+                  SERIAL_ECHOLNRPGM(_n("Invalid extruder"));////MSG_INVALID_EXTRUDER c=0 r=0
+              }
+              else {
+#if EXTRUDERS > 1
+                  boolean make_move = false;
+#endif
+                  if (code_seen('F')) {
+#if EXTRUDERS > 1
+                      make_move = true;
+#endif
+                      next_feedrate = code_value();
+                      if (next_feedrate > 0.0) {
+                          feedrate = next_feedrate;
+                      }
+                  }
+#if EXTRUDERS > 1
+                  if (tmp_extruder != active_extruder) {
+                      // Save current position to return to after applying extruder offset
+                      memcpy(destination, current_position, sizeof(destination));
+                      // Offset extruder (only by XY)
+                      int i;
+                      for (i = 0; i < 2; i++) {
+                          current_position[i] = current_position[i] -
+                                  extruder_offset[i][active_extruder] +
+                                  extruder_offset[i][tmp_extruder];
+                      }
+                      // Set the new active extruder and position
+                      active_extruder = tmp_extruder;
+                      plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
+                      // Move to the old position if 'F' was in the parameters
+                      if (make_move && Stopped == false) {
+                          prepare_move();
+                      }
+                  }
+#endif
+                  SERIAL_ECHO_START;
+                  SERIAL_ECHORPGM(_n("Active Extruder: "));////MSG_ACTIVE_EXTRUDER c=0 r=0
+                  SERIAL_PROTOCOLLN((int)active_extruder);
+              }
 
 #endif //SNMM
-}
-	  }
+          }
+      }
   } // end if(code_seen('T')) (end of T codes)
 
   else if (code_seen('D')) // D codes (debug)
@@ -7301,38 +7337,41 @@ static void handleSafetyTimer()
 void manage_inactivity(bool ignore_stepper_queue/*=false*/) //default argument set in Marlin.h
 {
 #ifdef FILAMENT_SENSOR
-	if (mcode_in_progress != 600) //M600 not in progress
+	if (mmu_enabled == false)
 	{
-		if (!moves_planned() && !IS_SD_PRINTING && !is_usb_printing && (lcd_commands_type != LCD_COMMAND_V2_CAL))
+		if (mcode_in_progress != 600) //M600 not in progress
 		{
-			if (fsensor_check_autoload())
+			if (!moves_planned() && !IS_SD_PRINTING && !is_usb_printing && (lcd_commands_type != LCD_COMMAND_V2_CAL))
 			{
-				fsensor_autoload_check_stop();
-				if (degHotend0() > EXTRUDE_MINTEMP)
+				if (fsensor_check_autoload())
 				{
-if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
-					tone(BEEPER, 1000);
-					delay_keep_alive(50);
-					noTone(BEEPER);
-					loading_flag = true;
-					enquecommand_front_P((PSTR("M701")));
-				}
-				else
-				{
-					lcd_update_enable(false);
-					lcd_clear();
-					lcd_set_cursor(0, 0);
-					lcd_puts_P(_T(MSG_ERROR));
-					lcd_set_cursor(0, 2);
-					lcd_puts_P(_T(MSG_PREHEAT_NOZZLE));
-					delay(2000);
-					lcd_clear();
-					lcd_update_enable(true);
+					fsensor_autoload_check_stop();
+					if (degHotend0() > EXTRUDE_MINTEMP)
+					{
+						if ((eSoundMode == e_SOUND_MODE_LOUD) || (eSoundMode == e_SOUND_MODE_ONCE))
+							tone(BEEPER, 1000);
+						delay_keep_alive(50);
+						noTone(BEEPER);
+						loading_flag = true;
+						enquecommand_front_P((PSTR("M701")));
+					}
+					else
+					{
+						lcd_update_enable(false);
+						lcd_clear();
+						lcd_set_cursor(0, 0);
+						lcd_puts_P(_T(MSG_ERROR));
+						lcd_set_cursor(0, 2);
+						lcd_puts_P(_T(MSG_PREHEAT_NOZZLE));
+						delay(2000);
+						lcd_clear();
+						lcd_update_enable(true);
+					}
 				}
 			}
+			else
+				fsensor_autoload_check_stop();
 		}
-		else
-			fsensor_autoload_check_stop();
 	}
 #endif //FILAMENT_SENSOR
 
@@ -7555,11 +7594,21 @@ void setPwmFrequency(uint8_t pin, int val)
 }
 #endif //FAST_PWM_FAN
 
-bool setTargetedHotend(int code){
-  tmp_extruder = active_extruder;
+//! @brief Get and validate extruder number
+//!
+//! If it is not specified, active_extruder is returned in parameter extruder.
+//! @param [in] code M code number
+//! @param [out] extruder
+//! @return error
+//! @retval true Invalid extruder specified in T code
+//! @retval false Valid extruder specified in T code, or not specifiead
+
+bool setTargetedHotend(int code, uint8_t &extruder)
+{
+  extruder = active_extruder;
   if(code_seen('T')) {
-    tmp_extruder = code_value();
-    if(tmp_extruder >= EXTRUDERS) {
+      extruder = code_value();
+    if(extruder >= EXTRUDERS) {
       SERIAL_ECHO_START;
       switch(code){
         case 104:
@@ -7578,7 +7627,7 @@ bool setTargetedHotend(int code){
           SERIAL_ECHO(_i("M221 Invalid extruder "));////MSG_M221_INVALID_EXTRUDER c=0 r=0
           break;
       }
-      SERIAL_PROTOCOLLN((int)tmp_extruder);
+      SERIAL_PROTOCOLLN((int)extruder);
       return true;
     }
   }
@@ -7643,7 +7692,7 @@ void delay_keep_alive(unsigned int ms)
     }
 }
 
-void wait_for_heater(long codenum) {
+static void wait_for_heater(long codenum, uint8_t extruder) {
 
 #ifdef TEMP_RESIDENCY_TIME
 	long residencyStart;
@@ -7659,9 +7708,9 @@ void wait_for_heater(long codenum) {
 		{ //Print Temp Reading and remaining time every 1 second while heating up/cooling down
 			if (!farm_mode) {
 				SERIAL_PROTOCOLPGM("T:");
-				SERIAL_PROTOCOL_F(degHotend(tmp_extruder), 1);
+				SERIAL_PROTOCOL_F(degHotend(extruder), 1);
 				SERIAL_PROTOCOLPGM(" E:");
-				SERIAL_PROTOCOL((int)tmp_extruder);
+				SERIAL_PROTOCOL((int)extruder);
 
 #ifdef TEMP_RESIDENCY_TIME
 				SERIAL_PROTOCOLPGM(" W:");
@@ -7686,9 +7735,9 @@ void wait_for_heater(long codenum) {
 #ifdef TEMP_RESIDENCY_TIME
 			/* start/restart the TEMP_RESIDENCY_TIME timer whenever we reach target temp for the first time
 			or when current temp falls outside the hysteresis after target temp was reached */
-			if ((residencyStart == -1 && target_direction && (degHotend(tmp_extruder) >= (degTargetHotend(tmp_extruder) - TEMP_WINDOW))) ||
-				(residencyStart == -1 && !target_direction && (degHotend(tmp_extruder) <= (degTargetHotend(tmp_extruder) + TEMP_WINDOW))) ||
-				(residencyStart > -1 && labs(degHotend(tmp_extruder) - degTargetHotend(tmp_extruder)) > TEMP_HYSTERESIS))
+			if ((residencyStart == -1 && target_direction && (degHotend(extruder) >= (degTargetHotend(extruder) - TEMP_WINDOW))) ||
+				(residencyStart == -1 && !target_direction && (degHotend(extruder) <= (degTargetHotend(extruder) + TEMP_WINDOW))) ||
+				(residencyStart > -1 && labs(degHotend(extruder) - degTargetHotend(extruder)) > TEMP_HYSTERESIS))
 			{
 				residencyStart = millis();
 			}
@@ -8843,8 +8892,7 @@ void M600_check_state()
 {
 		//Wait for user to check the state
 		lcd_change_fil_state = 0;
-		
-		while ((lcd_change_fil_state == 0)||(lcd_change_fil_state != 1)){
+		while (lcd_change_fil_state != 1){
 			lcd_change_fil_state = 0;
 			KEEPALIVE_STATE(PAUSED_FOR_USER);
 			lcd_alright();
@@ -8868,10 +8916,9 @@ void M600_check_state()
 				// Everything good             
 				default:
 					lcd_change_success();
-					lcd_update_enable(true);
 					break;
 			}
-	}
+		}
 }
 
 void M600_wait_for_user() {
@@ -9036,7 +9083,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 			fsensor_disable();
 	}
 #endif //FILAMENT_SENSOR
-
+	lcd_update_enable(false);
 }
 
 #define FIL_LOAD_LENGTH 60

+ 1 - 0
Firmware/eeprom.h

@@ -144,6 +144,7 @@
 // Sound Mode
 //#define EEPROM_SOUND_MODE (EEPROM_EXTRUDEMULTIPLY-1) // uint8
 #define EEPROM_SOUND_MODE (EEPROM_UVLO_TINY_Z_MICROSTEPS-1) // uint8
+#define EEPROM_AUTO_DEPLETE (EEPROM_SOUND_MODE-1) //bool
 
 // !!!!!
 // !!!!! this is end of EEPROM section ... all updates MUST BE inserted before this mark !!!!!

+ 49 - 20
Firmware/menu.cpp

@@ -9,15 +9,20 @@
 #include "Configuration.h"
 #include "Marlin.h"
 #include "ultralcd.h"
+#include "language.h"
 
 
 
 extern int32_t lcd_encoder;
 
+#define MENU_DEPTH_MAX       4
 
-menu_record_t menu_stack[MENU_DEPTH_MAX];
+static menu_record_t menu_stack[MENU_DEPTH_MAX];
 
 uint8_t menu_data[MENU_DATA_SIZE];
+#ifndef __AVR__
+#error "menu_data is non-portable to non 8bit processor"
+#endif
 
 uint8_t menu_depth = 0;
 
@@ -33,6 +38,8 @@ uint8_t menu_leaving = 0;
 
 menu_func_t menu_menu = 0;
 
+static_assert(sizeof(menu_data)>= sizeof(menu_data_edit_t),"menu_data_edit_t doesn't fit into menu_data");
+
 
 void menu_goto(menu_func_t menu, const uint32_t encoder, const bool feedback, bool reset_menu_state)
 {
@@ -86,7 +93,7 @@ void menu_back(void)
 	}
 }
 
-void menu_back_no_reset(void)
+static void menu_back_no_reset(void)
 {
 	if (menu_depth > 0)
 	{
@@ -120,7 +127,7 @@ void menu_submenu(menu_func_t submenu)
 	}
 }
 
-void menu_submenu_no_reset(menu_func_t submenu)
+static void menu_submenu_no_reset(menu_func_t submenu)
 {
 	if (menu_depth <= MENU_DEPTH_MAX)
 	{
@@ -158,7 +165,7 @@ int menu_draw_item_printf_P(char type_char, const char* format, ...)
 }
 */
 
-int menu_draw_item_puts_P(char type_char, const char* str)
+static int menu_draw_item_puts_P(char type_char, const char* str)
 {
     lcd_set_cursor(0, menu_row);
 	int cnt = lcd_printf_P(PSTR("%c%-18S%c"), (lcd_encoder == menu_item)?'>':' ', str, type_char);
@@ -263,8 +270,13 @@ const char menu_fmt_float31[] PROGMEM = "%c%.12S:%s%+06.1f";
 
 const char menu_fmt_float13[] PROGMEM = "%c%.12S:%s%+06.3f";
 
+const char menu_fmt_float13off[] PROGMEM = "%c%.12S:%s%";
+
+template<typename T>
+static void menu_draw_P(char chr, const char* str, int16_t val);
 
-void menu_draw_int3(char chr, const char* str, int16_t val)
+template<>
+void menu_draw_P<int16_t*>(char chr, const char* str, int16_t val)
 {
 	int text_len = strlen_P(str);
 	if (text_len > 15) text_len = 15;
@@ -274,6 +286,27 @@ void menu_draw_int3(char chr, const char* str, int16_t val)
 	lcd_printf_P(menu_fmt_int3, chr, str, spaces, val);
 }
 
+template<>
+void menu_draw_P<uint8_t*>(char chr, const char* str, int16_t val)
+{
+    menu_data_edit_t* _md = (menu_data_edit_t*)&(menu_data[0]);
+    int text_len = strlen_P(str);
+    if (text_len > 15) text_len = 15;
+    char spaces[21];
+    strcpy_P(spaces, menu_20x_space);
+    spaces[12 - text_len] = 0;
+    float factor = 1.0 + static_cast<float>(val) / 1000.0;
+    if (val <= _md->minEditValue)
+    {
+        lcd_printf_P(menu_fmt_float13off, chr, str, spaces);
+        lcd_puts_P(_i(" [off]"));
+    }
+    else
+    {
+        lcd_printf_P(menu_fmt_float13, chr, str, spaces, factor);
+    }
+}
+
 //draw up to 12 chars of text, ':' and float number in format +123.0
 void menu_draw_float31(char chr, const char* str, float val)
 {
@@ -296,16 +329,8 @@ void menu_draw_float13(char chr, const char* str, float val)
 	lcd_printf_P(menu_fmt_float13, chr, str, spaces, val);
 }
 
-typedef struct
-{
-    //Variables used when editing values.
-    const char* editLabel;
-    void* editValue;
-    int32_t minEditValue;
-	int32_t maxEditValue;
-} menu_data_edit_t;
-
-void _menu_edit_int3(void)
+template <typename T>
+static void _menu_edit_P(void)
 {
 	menu_data_edit_t* _md = (menu_data_edit_t*)&(menu_data[0]);
 	if (lcd_draw_update)
@@ -313,16 +338,17 @@ void _menu_edit_int3(void)
 		if (lcd_encoder < _md->minEditValue) lcd_encoder = _md->minEditValue;
 		if (lcd_encoder > _md->maxEditValue) lcd_encoder = _md->maxEditValue;
 		lcd_set_cursor(0, 1);
-		menu_draw_int3(' ', _md->editLabel, (int)lcd_encoder);
+		menu_draw_P<T>(' ', _md->editLabel, (int)lcd_encoder);
 	}
 	if (LCD_CLICKED)
 	{
-		*((int*)(_md->editValue)) = (int)lcd_encoder;
+		*((T)(_md->editValue)) = lcd_encoder;
 		menu_back_no_reset();
 	}
 }
 
-uint8_t menu_item_edit_int3(const char* str, int16_t* pval, int16_t min_val, int16_t max_val)
+template <typename T>
+uint8_t menu_item_edit_P(const char* str, T pval, int16_t min_val, int16_t max_val)
 {
 	menu_data_edit_t* _md = (menu_data_edit_t*)&(menu_data[0]);
 	if (menu_item == menu_line)
@@ -330,11 +356,11 @@ uint8_t menu_item_edit_int3(const char* str, int16_t* pval, int16_t min_val, int
 		if (lcd_draw_update) 
 		{
 			lcd_set_cursor(0, menu_row);
-			menu_draw_int3((lcd_encoder == menu_item)?'>':' ', str, *pval);
+			menu_draw_P<T>((lcd_encoder == menu_item)?'>':' ', str, *pval);
 		}
 		if (menu_clicked && (lcd_encoder == menu_item))
 		{
-			menu_submenu_no_reset(_menu_edit_int3);
+			menu_submenu_no_reset(_menu_edit_P<T>);
 			_md->editLabel = str;
 			_md->editValue = pval;
 			_md->minEditValue = min_val;
@@ -347,6 +373,9 @@ uint8_t menu_item_edit_int3(const char* str, int16_t* pval, int16_t min_val, int
 	return 0;
 }
 
+template uint8_t menu_item_edit_P<int16_t*>(const char* str, int16_t *pval, int16_t min_val, int16_t max_val);
+template uint8_t menu_item_edit_P<uint8_t*>(const char* str, uint8_t *pval, int16_t min_val, int16_t max_val);
+
 #undef _menu_data
 
 

+ 11 - 12
Firmware/menu.h

@@ -4,9 +4,7 @@
 
 #include <inttypes.h>
 
-#define MENU_DEPTH_MAX       4
 #define MENU_DATA_SIZE      32
-#define MENU_DATA_EDIT_SIZE 12
 
 //Function pointer to menu functions.
 typedef void (*menu_func_t)(void);
@@ -17,7 +15,14 @@ typedef struct
     int8_t position;
 } menu_record_t;
 
-extern menu_record_t menu_stack[MENU_DEPTH_MAX];
+typedef struct
+{
+    //Variables used when editing values.
+    const char* editLabel;
+    void* editValue;
+    int32_t minEditValue;
+    int32_t maxEditValue;
+} menu_data_edit_t;
 
 extern uint8_t menu_data[MENU_DATA_SIZE];
 
@@ -50,21 +55,16 @@ extern void menu_end(void);
 
 extern void menu_back(void);
 
-extern void menu_back_no_reset(void);
-
 extern void menu_back_if_clicked(void);
 
 extern void menu_back_if_clicked_fb(void);
 
 extern void menu_submenu(menu_func_t submenu);
 
-extern void menu_submenu_no_reset(menu_func_t submenu);
-
 extern uint8_t menu_item_ret(void);
 
 //extern int menu_draw_item_printf_P(char type_char, const char* format, ...);
 
-extern int menu_draw_item_puts_P(char type_char, const char* str);
 
 //int menu_draw_item_puts_P_int16(char type_char, const char* str, int16_t val, );
 
@@ -91,17 +91,16 @@ extern const char menu_fmt_int3[];
 
 extern const char menu_fmt_float31[];
 
-extern void menu_draw_int3(char chr, const char* str, int16_t val);
 
 extern void menu_draw_float31(char chr, const char* str, float val);
 
 extern void menu_draw_float13(char chr, const char* str, float val);
 
-extern void _menu_edit_int3(void);
 
-#define MENU_ITEM_EDIT_int3_P(str, pval, minval, maxval) do { if (menu_item_edit_int3(str, pval, minval, maxval)) return; } while (0)
+#define MENU_ITEM_EDIT_int3_P(str, pval, minval, maxval) do { if (menu_item_edit_P(str, pval, minval, maxval)) return; } while (0)
 //#define MENU_ITEM_EDIT_int3_P(str, pval, minval, maxval) MENU_ITEM_EDIT(int3, str, pval, minval, maxval)
-extern uint8_t menu_item_edit_int3(const char* str, int16_t* pval, int16_t min_val, int16_t max_val);
+template <typename T>
+extern uint8_t menu_item_edit_P(const char* str, T pval, int16_t min_val, int16_t max_val);
 
 
 #endif //_MENU_H

+ 215 - 35
Firmware/mmu.cpp

@@ -7,22 +7,22 @@
 #include "uart2.h"
 #include "temperature.h"
 #include "Configuration_prusa.h"
+#include "fsensor.h"
+#include "cardreader.h"
+#include "ultralcd.h"
+#include "sound.h"
 
-
-extern const char* lcd_display_message_fullscreen_P(const char *msg);
-extern void lcd_show_fullscreen_message_and_wait_P(const char *msg);
-extern int8_t lcd_show_fullscreen_message_yes_no_and_wait_P(const char *msg, bool allow_timeouting = true, bool default_yes = false);
-extern void lcd_return_to_status();
-extern void lcd_wait_for_heater();
-extern char choose_extruder_menu();
-
+#define CHECK_FINDA ((IS_SD_PRINTING || is_usb_printing) && (mcode_in_progress != 600) && !saved_printing && e_active())
 
 #define MMU_TODELAY 100
 #define MMU_TIMEOUT 10
+#define MMU_CMD_TIMEOUT 300000ul //5min timeout for mmu commands (except P0)
+#define MMU_P0_TIMEOUT 3000ul //timeout for P0 command: 3seconds
 
 #define MMU_HWRESET
 #define MMU_RST_PIN 76
 
+#define MMU_REQUIRED_FW_BUILDNR 83
 
 bool mmu_enabled = false;
 
@@ -103,6 +103,7 @@ void mmu_init(void)
 //mmu main loop - state machine processing
 void mmu_loop(void)
 {
+	int filament = 0;
 //	printf_P(PSTR("MMU loop, state=%d\n"), mmu_state);
 	switch (mmu_state)
 	{
@@ -137,6 +138,9 @@ void mmu_loop(void)
 		{
 			fscanf_P(uart2io, PSTR("%u"), &mmu_buildnr); //scan buildnr from buffer
 			printf_P(PSTR("MMU => '%dok'\n"), mmu_buildnr);
+			bool version_valid = mmu_check_version();
+			if (!version_valid) mmu_show_warning();
+			else puts_P(PSTR("MMU version valid"));
 			puts_P(PSTR("MMU <= 'P0'"));
 		    mmu_puts_P(PSTR("P0\n")); //send 'read finda' request
 			mmu_state = -4;
@@ -157,14 +161,46 @@ void mmu_loop(void)
 		{
 			if ((mmu_cmd >= MMU_CMD_T0) && (mmu_cmd <= MMU_CMD_T4))
 			{
-				int extruder = mmu_cmd - MMU_CMD_T0;
-				printf_P(PSTR("MMU <= 'T%d'\n"), extruder);
-				mmu_printf_P(PSTR("T%d\n"), extruder);
+				filament = mmu_cmd - MMU_CMD_T0;
+				printf_P(PSTR("MMU <= 'T%d'\n"), filament);
+				mmu_printf_P(PSTR("T%d\n"), filament);
+				mmu_state = 3; // wait for response
+			}
+			else if ((mmu_cmd >= MMU_CMD_L0) && (mmu_cmd <= MMU_CMD_L4))
+			{
+			    filament = mmu_cmd - MMU_CMD_L0;
+			    printf_P(PSTR("MMU <= 'L%d'\n"), filament);
+			    mmu_printf_P(PSTR("L%d\n"), filament);
+			    mmu_state = 3; // wait for response
+			}
+			else if (mmu_cmd == MMU_CMD_C0)
+			{
+				printf_P(PSTR("MMU <= 'C0'\n"));
+				mmu_puts_P(PSTR("C0\n")); //send 'continue loading'
+				mmu_state = 3;
+			}
+			else if (mmu_cmd == MMU_CMD_U0)
+			{
+				printf_P(PSTR("MMU <= 'U0'\n"));
+				mmu_puts_P(PSTR("U0\n")); //send 'unload current filament'
+				mmu_state = 3;
+			}
+			else if ((mmu_cmd >= MMU_CMD_E0) && (mmu_cmd <= MMU_CMD_E4))
+			{
+				int filament = mmu_cmd - MMU_CMD_E0;
+				printf_P(PSTR("MMU <= 'E%d'\n"), filament);
+				mmu_printf_P(PSTR("E%d\n"), filament); //send eject filament
+				mmu_state = 3; // wait for response
+			}
+			else if (mmu_cmd == MMU_CMD_R0)
+			{
+				printf_P(PSTR("MMU <= 'R0'\n"));
+				mmu_puts_P(PSTR("R0\n")); //send recover after eject
 				mmu_state = 3; // wait for response
 			}
 			mmu_cmd = 0;
 		}
-		else if ((mmu_last_response + 1000) < millis()) //request every 1s
+		else if ((mmu_last_response + 300) < millis()) //request every 300ms
 		{
 			puts_P(PSTR("MMU <= 'P0'"));
 		    mmu_puts_P(PSTR("P0\n")); //send 'read finda' request
@@ -176,24 +212,31 @@ void mmu_loop(void)
 		{
 			fscanf_P(uart2io, PSTR("%hhu"), &mmu_finda); //scan finda from buffer
 			printf_P(PSTR("MMU => '%dok'\n"), mmu_finda);
+			//printf_P(PSTR("Eact: %d\n"), int(e_active()));
+			if (!mmu_finda && CHECK_FINDA && fsensor_enabled) {
+				fsensor_stop_and_save_print();
+				enquecommand_front_P(PSTR("FSENSOR_RECOVER")); //then recover
+				if (lcd_autoDeplete) enquecommand_front_P(PSTR("M600 AUTO")); //save print and run M600 command
+				else enquecommand_front_P(PSTR("M600")); //save print and run M600 command
+			}
 			mmu_state = 1;
 			if (mmu_cmd == 0)
 				mmu_ready = true;
 		}
-		else if ((mmu_last_request + 30000) < millis())
+		else if ((mmu_last_request + MMU_P0_TIMEOUT) < millis())
 		{ //resend request after timeout (30s)
 			mmu_state = 1;
 		}
 		return;
-	case 3: //response to commands T0-T4
+	case 3: //response to mmu commands
 		if (mmu_rx_ok() > 0)
 		{
-			printf_P(PSTR("MMU => 'ok'\n"), mmu_finda);
+			printf_P(PSTR("MMU => 'ok'\n"));
 			mmu_ready = true;
 			mmu_state = 1;
 		}
-		else if ((mmu_last_request + 30000) < millis())
-		{ //resend request after timeout (30s)
+		else if ((mmu_last_request + MMU_CMD_TIMEOUT) < millis())
+		{ //resend request after timeout (5 min)
 			mmu_state = 1;
 		}
 		return;
@@ -289,7 +332,7 @@ void manage_response(bool move_axes, bool turn_off_nozzle)
 				  }
 				  st_synchronize();
 				  mmu_print_saved = true;
-				  
+				  printf_P(PSTR("MMU not responding\n"));
 				  hotend_temp_bckp = degTargetHotend(active_extruder);
 				  if (move_axes) {
 					  z_position_bckp = current_position[Z_AXIS];
@@ -311,23 +354,28 @@ void manage_response(bool move_axes, bool turn_off_nozzle)
 				  if (turn_off_nozzle) {
 					  //set nozzle target temperature to 0
 					  setAllTargetHotends(0);
-					  printf_P(PSTR("MMU not responding\n"));
-					  lcd_show_fullscreen_message_and_wait_P(_i("MMU needs user attention. Please press knob to resume nozzle target temperature."));
-					  setTargetHotend(hotend_temp_bckp, active_extruder);
-					  while ((degTargetHotend(active_extruder) - degHotend(active_extruder)) > 5) {
-						  delay_keep_alive(1000);
-						  lcd_wait_for_heater();
-					  }
 				  }
 			  }
-			  lcd_display_message_fullscreen_P(_i("Check MMU. Fix the issue and then press button on MMU unit."));
+			  lcd_display_message_fullscreen_P(_i("MMU needs user attention. Fix the issue and then press button on MMU unit."));
 			  delay_keep_alive(1000);
 		  }
 		  else if (mmu_print_saved) {
-			  printf_P(PSTR("MMU start responding\n"));
-			  lcd_clear();
-			  lcd_display_message_fullscreen_P(_i("MMU OK. Resuming..."));
+			  printf_P(PSTR("MMU starts responding\n"));
+			  if (turn_off_nozzle) 
+			  {
+				lcd_clear();
+				setTargetHotend(hotend_temp_bckp, active_extruder);
+				lcd_display_message_fullscreen_P(_i("MMU OK. Resuming temperature..."));
+				delay_keep_alive(3000);
+				while ((degTargetHotend(active_extruder) - degHotend(active_extruder)) > 5) 
+				{
+					delay_keep_alive(1000);
+					lcd_wait_for_heater();
+				}
+			  }			  
 			  if (move_axes) {
+				  lcd_clear();
+				  lcd_display_message_fullscreen_P(_i("MMU OK. Resuming position..."));
 				  current_position[X_AXIS] = x_position_bckp;
 				  current_position[Y_AXIS] = y_position_bckp;
 				  plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 50, active_extruder);
@@ -337,6 +385,8 @@ void manage_response(bool move_axes, bool turn_off_nozzle)
 				  st_synchronize();
 			  }
 			  else {
+				  lcd_clear();
+				  lcd_display_message_fullscreen_P(_i("MMU OK. Resuming..."));
 				  delay_keep_alive(1000); //delay just for showing MMU OK message for a while in case that there are no xyz movements
 			  }
 		  }
@@ -344,6 +394,12 @@ void manage_response(bool move_axes, bool turn_off_nozzle)
 	if (lcd_update_was_enabled) lcd_update_enable(true);
 }
 
+//! @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.
+//!
 void mmu_load_to_nozzle()
 {
 	st_synchronize();
@@ -369,17 +425,56 @@ void mmu_load_to_nozzle()
 	if (!saved_e_relative_mode) axis_relative_modes[E_AXIS] = false;
 }
 
+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;
+		lcd_display_message_fullscreen_P(_i("Remove old filament and press the knob to start loading new filament."));
+		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) {
+				if((eSoundMode==e_SOUND_MODE_LOUD)||((eSoundMode==e_SOUND_MODE_ONCE)&&bFirst))
+				{
+					bFirst=false;
+					WRITE(BEEPER, HIGH);
+				}
+			}
+			if (counterBeep == 20) {
+				WRITE(BEEPER, LOW);
+			}
+				
+			counterBeep++;
+			#endif //BEEPER > 0
+
+			delay_keep_alive(4);
+		}
+		WRITE(BEEPER, LOW);
+}
+
 void mmu_M600_load_filament(bool automatic)
 { 
 	//load filament for mmu v2
 
 		  bool response = false;
 		  bool yes = false;
+		  tmp_extruder = mmu_extruder;
 		  if (!automatic) {
+#ifdef MMU_M600_SWITCH_EXTRUDER
 			  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();
 			  else tmp_extruder = mmu_extruder;
-
+#endif //MMU_M600_SWITCH_EXTRUDER
 		  }
 		  else {
 			  tmp_extruder = (tmp_extruder+1)%5;
@@ -396,10 +491,12 @@ void mmu_M600_load_filament(bool automatic)
 		  mmu_command(MMU_CMD_T0 + tmp_extruder);
 
 		  manage_response(false, true);
+		  mmu_command(MMU_CMD_C0);
     	  mmu_extruder = tmp_extruder; //filament change is finished
 
 		  mmu_load_to_nozzle();
 
+
 		  st_synchronize();
 		  current_position[E_AXIS]+= FILAMENTCHANGE_FINALFEED ;
 		  plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2, active_extruder);
@@ -479,8 +576,13 @@ void display_loading()
 void extr_adj(int extruder) //loading filament for SNMM
 {
 #ifndef SNMM
-    printf_P(PSTR("L%d \n"),extruder);
-    fprintf_P(uart2io, PSTR("L%d\n"), extruder);
+    uint8_t cmd = MMU_CMD_L0 + extruder;
+    if (cmd > MMU_CMD_L4)
+    {
+        printf_P(PSTR("Filament out of range %d \n"),extruder);
+        return;
+    }
+    mmu_command(cmd);
 	
 	//show which filament is currently loaded
 	
@@ -490,7 +592,7 @@ void extr_adj(int extruder) //loading filament for SNMM
 	//if(strlen(_T(MSG_LOADING_FILAMENT))>18) lcd.setCursor(0, 1);
 	//else lcd.print(" ");
 	lcd_print(" ");
-	lcd_print(mmu_extruder + 1);
+	lcd_print(extruder + 1);
 
 	// get response
 	manage_response(false, false);
@@ -564,9 +666,8 @@ void extr_unload()
 		current_position[E_AXIS] -= 80;
 		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2500 / 60, active_extruder);
 		st_synchronize();
-		printf_P(PSTR("U0\n"));
-		fprintf_P(uart2io, PSTR("U0\n"));
 
+		mmu_command(MMU_CMD_U0);
 		// get response
 		manage_response(false, true);
 
@@ -688,6 +789,31 @@ void extr_adj_4()
 #endif
 }
 
+void mmu_eject_fil_0()
+{
+	mmu_eject_filament(0, true);
+}
+
+void mmu_eject_fil_1()
+{
+	mmu_eject_filament(1, true);
+}
+
+void mmu_eject_fil_2()
+{
+	mmu_eject_filament(2, true);
+}
+
+void mmu_eject_fil_3()
+{
+	mmu_eject_filament(3, true);
+}
+
+void mmu_eject_fil_4()
+{
+	mmu_eject_filament(4, true);
+}
+
 void load_all()
 {
 #ifndef SNMM
@@ -807,3 +933,57 @@ void extr_unload_4()
 	change_extr(4);
 	extr_unload();
 }
+
+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."));
+}
+
+void mmu_eject_filament(uint8_t filament, bool recover)
+{
+	if (filament < 5) 
+	{
+
+		if (degHotend0() > EXTRUDE_MINTEMP)
+		{
+			st_synchronize();
+			lcd_update_enable(false);
+			lcd_clear();
+			lcd_set_cursor(0, 1); lcd_puts_P(_i("Ejecting filament"));
+			current_position[E_AXIS] -= 80;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2500 / 60, active_extruder);
+			st_synchronize();
+
+			lcd_update_enable(true);
+
+			mmu_command(MMU_CMD_E0 + filament);
+			manage_response(false, false);
+			if (recover)
+			{
+				lcd_show_fullscreen_message_and_wait_P(_i("Please remove filament and then press the knob."));
+				mmu_command(MMU_CMD_R0);
+				manage_response(false, false);
+			}
+		}
+		else
+		{
+			lcd_clear();
+			lcd_set_cursor(0, 0);
+			lcd_puts_P(_T(MSG_ERROR));
+			lcd_set_cursor(0, 2);
+			lcd_puts_P(_T(MSG_PREHEAT_NOZZLE));
+			delay(2000);
+			lcd_clear();
+		}
+	}
+	else
+	{
+		puts_P(PSTR("Filament nr out of range!"));
+	}
+}

+ 24 - 1
Firmware/mmu.h

@@ -23,6 +23,20 @@ extern int16_t mmu_buildnr;
 #define MMU_CMD_T2   0x12
 #define MMU_CMD_T3   0x13
 #define MMU_CMD_T4   0x14
+#define MMU_CMD_L0   0x20
+#define MMU_CMD_L1   0x21
+#define MMU_CMD_L2   0x22
+#define MMU_CMD_L3   0x23
+#define MMU_CMD_L4   0x24
+#define MMU_CMD_C0   0x30
+#define MMU_CMD_U0   0x40
+#define MMU_CMD_E0   0x50
+#define MMU_CMD_E1   0x51
+#define MMU_CMD_E2   0x52
+#define MMU_CMD_E3   0x53
+#define MMU_CMD_E4   0x54
+#define MMU_CMD_R0   0x60
+
 
 extern int mmu_puts_P(const char* str);
 
@@ -49,7 +63,7 @@ extern void manage_response(bool move_axes, bool turn_off_nozzle);
 extern void mmu_load_to_nozzle();
 
 extern void mmu_M600_load_filament(bool automatic);
-
+extern void mmu_M600_wait_and_beep();
 
 extern void extr_mov(float shift, float feed_rate);
 extern void change_extr(int extr);
@@ -74,3 +88,12 @@ extern void extr_unload_1();
 extern void extr_unload_2();
 extern void extr_unload_3();
 extern void extr_unload_4();
+
+extern bool mmu_check_version();
+extern void mmu_show_warning();
+extern void mmu_eject_filament(uint8_t filament, bool recover);
+extern void mmu_eject_fil_0();
+extern void mmu_eject_fil_1();
+extern void mmu_eject_fil_2();
+extern void mmu_eject_fil_3();
+extern void mmu_eject_fil_4();

+ 17 - 0
Firmware/planner.cpp

@@ -494,6 +494,23 @@ void getHighESpeed()
 }
 #endif
 
+bool e_active()
+{
+	unsigned char e_active = 0;
+	block_t *block;
+  if(block_buffer_tail != block_buffer_head)
+  {
+    uint8_t block_index = block_buffer_tail;
+    while(block_index != block_buffer_head)
+    {
+      block = &block_buffer[block_index];
+      if(block->steps_e.wide != 0) e_active++;
+      block_index = (block_index+1) & (BLOCK_BUFFER_SIZE - 1);
+    }
+  }
+  return (e_active > 0) ? true : false ;
+}
+
 void check_axes_activity()
 {
   unsigned char x_active = 0;

+ 1 - 1
Firmware/planner.h

@@ -154,7 +154,7 @@ void plan_set_position(float x, float y, float z, const float &e);
 void plan_set_z_position(const float &z);
 void plan_set_e_position(const float &e);
 
-
+extern bool e_active();
 
 void check_axes_activity();
 

+ 19 - 7
Firmware/stepper.cpp

@@ -41,6 +41,8 @@
 int fsensor_counter = 0; //counter for e-steps
 #endif //FILAMENT_SENSOR
 
+#include "mmu.h"
+
 #ifdef DEBUG_STACK_MONITOR
 uint16_t SP_min = 0x21FF;
 #endif //DEBUG_STACK_MONITOR
@@ -470,8 +472,11 @@ FORCE_INLINE void stepper_next_block()
 #endif
 
 #ifdef FILAMENT_SENSOR
-    fsensor_counter = 0;
-    fsensor_st_block_begin(current_block);
+	if (mmu_enabled == false)
+	{
+		fsensor_counter = 0;
+		fsensor_st_block_begin(current_block);
+	}
 #endif //FILAMENT_SENSOR
     // The busy flag is set by the plan_get_current_block() call.
     // current_block->busy = true;
@@ -901,7 +906,10 @@ FORCE_INLINE void isr() {
         if (step_loops < estep_loops)
           estep_loops = step_loops;
     #ifdef FILAMENT_SENSOR
-        fsensor_counter += estep_loops;
+		if (mmu_enabled == false)
+		{
+			fsensor_counter += estep_loops;
+		}
     #endif //FILAMENT_SENSOR
         do {
           WRITE_NC(E0_STEP_PIN, !INVERT_E_STEP_PIN);
@@ -1027,7 +1035,9 @@ FORCE_INLINE void isr() {
         // There is not enough time to fit even a single additional tick.
         // Tick all the extruder ticks now.
     #ifdef FILAMENT_SENSOR
-        fsensor_counter += e_steps;
+		  if (mmu_enabled == false) {
+			  fsensor_counter += e_steps;
+		  }
     #endif //FILAMENT_SENSOR
         MSerial.checkRx(); // Check for serial chars.
         do {
@@ -1049,15 +1059,17 @@ FORCE_INLINE void isr() {
     // If current block is finished, reset pointer
     if (step_events_completed.wide >= current_block->step_event_count.wide) {
 #ifdef FILAMENT_SENSOR
-      fsensor_st_block_chunk(current_block, fsensor_counter);
-	    fsensor_counter = 0;
+		if (mmu_enabled == false) {
+			fsensor_st_block_chunk(current_block, fsensor_counter);
+			fsensor_counter = 0;
+		}
 #endif //FILAMENT_SENSOR
 
       current_block = NULL;
       plan_discard_current_block();
     }
 #ifdef FILAMENT_SENSOR
-  	else if (fsensor_counter >= fsensor_chunk_len)
+  	else if ((fsensor_counter >= fsensor_chunk_len) && (mmu_enabled == false))
   	{
       fsensor_st_block_chunk(current_block, fsensor_counter);
   	  fsensor_counter = 0;

+ 288 - 164
Firmware/ultralcd.cpp

@@ -35,7 +35,6 @@
 
 #include "mmu.h"
 
-extern int lcd_change_fil_state;
 extern bool fans_check_enabled;
 
 
@@ -88,6 +87,7 @@ unsigned long display_time; //just timer for showing pid finished message on lcd
 float pid_temp = DEFAULT_PID_TEMP;
 
 static bool forceMenuExpire = false;
+bool lcd_autoDeplete;
 
 
 static float manual_feedrate[] = MANUAL_FEEDRATE;
@@ -123,7 +123,7 @@ static void lcd_control_temperature_preheat_pla_settings_menu();
 static void lcd_control_temperature_preheat_abs_settings_menu();
 static void lcd_control_motion_menu();
 static void lcd_control_volumetric_menu();
-//static void lcd_settings_menu_back();
+static void lcd_settings_linearity_correction_menu_save();
 
 static void prusa_stat_printerstatus(int _status);
 static void prusa_stat_farm_number();
@@ -530,9 +530,9 @@ void lcdui_print_extruder(void)
 {
 	int chars = 0;
 	if (mmu_extruder == tmp_extruder)
-		chars = lcd_printf_P(_N(" T%u"), mmu_extruder);
+		chars = lcd_printf_P(_N(" T%u"), mmu_extruder+1);
 	else
-		chars = lcd_printf_P(_N(" %u>%u"), mmu_extruder, tmp_extruder);
+		chars = lcd_printf_P(_N(" %u>%u"), mmu_extruder+1, tmp_extruder+1);
 	lcd_space(5 - chars);
 }
 
@@ -597,8 +597,15 @@ void lcdui_print_time(void)
 	int chars = 0;
 	if ((PRINTER_ACTIVE) && ((print_time_remaining_normal != PRINT_TIME_REMAINING_INIT) || (starttime != 0)))
 	{
-		char suff = (print_time_remaining_normal == PRINT_TIME_REMAINING_INIT)?' ':'R';
-		chars = lcd_printf_P(_N("%c%02u:%02u%c"), LCD_STR_CLOCK[0], print_t / 60, print_t % 60, suff);
+          char suff = ' ';
+          char suff_doubt = ' ';
+		if (print_time_remaining_normal != PRINT_TIME_REMAINING_INIT)
+          {
+               suff = 'R';
+               if (feedmultiply != 100)
+                    suff_doubt = '?';
+          }
+		chars = lcd_printf_P(_N("%c%02u:%02u%c%c"), LCD_STR_CLOCK[0], print_t / 60, print_t % 60, suff, suff_doubt);
 	}
 	else
 		chars = lcd_printf_P(_N("%c--:--  "), LCD_STR_CLOCK[0]);
@@ -1882,20 +1889,22 @@ static void lcd_menu_extruder_info()
     //  Shutter register is an index of LASER shutter time. It is automatically controlled by the chip's internal
     //  auto-exposure algorithm. When the chip is tracking on a good reflection surface, the Shutter is small.
     //  When the chip is tracking on a poor reflection surface, the Shutter is large. Value ranges from 0 to 46.
-
-	if (!fsensor_enabled)
-		lcd_puts_P(_N("Filament sensor\n" "is disabled."));
-	else
+	if (mmu_enabled == false)
 	{
-		if (!moves_planned() && !IS_SD_PRINTING && !is_usb_printing && (lcd_commands_type != LCD_COMMAND_V2_CAL))
-			pat9125_update();
-		lcd_printf_P(_N(
-		  "Fil. Xd:%3d Yd:%3d\n"
-		  "Int: %3d  Shut: %3d"
-		 ),
-		 pat9125_x, pat9125_y,
-		 pat9125_b, pat9125_s
-		);
+		if (!fsensor_enabled)
+			lcd_puts_P(_N("Filament sensor\n" "is disabled."));
+		else
+		{
+			if (!moves_planned() && !IS_SD_PRINTING && !is_usb_printing && (lcd_commands_type != LCD_COMMAND_V2_CAL))
+				pat9125_update();
+			lcd_printf_P(_N(
+				"Fil. Xd:%3d Yd:%3d\n"
+				"Int: %3d  Shut: %3d"
+			),
+				pat9125_x, pat9125_y,
+				pat9125_b, pat9125_s
+			);
+		}
 	}
 #endif //FILAMENT_SENSOR
     
@@ -2090,9 +2099,7 @@ static void lcd_support_menu()
 		uint8_t ip[4];                 // 4bytes
 		char ip_str[3*4+3+1];          // 16bytes
 	} _menu_data_t;
-#if (22 > MENU_DATA_SIZE)
-#error "check MENU_DATA_SIZE definition!"
-#endif
+    static_assert(sizeof(menu_data)>= sizeof(_menu_data_t),"_menu_data_t doesn't fit into menu_data");
 	_menu_data_t* _md = (_menu_data_t*)&(menu_data[0]);
     if (_md->status == 0 || lcd_draw_update == 2)
 	{
@@ -2421,6 +2428,7 @@ static void lcd_menu_AutoLoadFilament()
     }
     else
     {
+        static_assert(sizeof(menu_data)>=sizeof(ShortTimer), "ShortTimer doesn't fit into menu_data");
 		ShortTimer* ptimer = (ShortTimer*)&(menu_data[0]);
         if (!ptimer->running()) ptimer->start();
         lcd_set_cursor(0, 0);
@@ -2537,9 +2545,7 @@ static void _lcd_move(const char *name, int axis, int min, int max)
 		bool initialized;              // 1byte
 		bool endstopsEnabledPrevious;  // 1byte
 	} _menu_data_t;
-#if (2 > MENU_DATA_SIZE)
-#error "check MENU_DATA_SIZE definition!"
-#endif
+	static_assert(sizeof(menu_data)>= sizeof(_menu_data_t),"_menu_data_t doesn't fit into menu_data");
 	_menu_data_t* _md = (_menu_data_t*)&(menu_data[0]);
 	if (!_md->initialized)
 	{
@@ -2743,9 +2749,7 @@ static void _lcd_babystep(int axis, const char *msg)
 		int babystepMem[3];            // 6bytes
 		float babystepMemMM[3];        // 12bytes
 	} _menu_data_t;
-#if (19 > MENU_DATA_SIZE)
-#error "check MENU_DATA_SIZE definition!"
-#endif
+	static_assert(sizeof(menu_data)>= sizeof(_menu_data_t),"_menu_data_t doesn't fit into menu_data");
 	_menu_data_t* _md = (_menu_data_t*)&(menu_data[0]);
 	if (_md->status == 0)
 	{
@@ -2826,16 +2830,14 @@ static void lcd_babystep_z()
 
 typedef struct
 {	// 12bytes + 9bytes = 21bytes total
-	uint8_t reserved[MENU_DATA_EDIT_SIZE]; //12 bytes reserved for number editing functions
+    menu_data_edit_t reserved; //12 bytes reserved for number editing functions
 	int8_t status;                   // 1byte
 	int16_t left;                    // 2byte
 	int16_t right;                   // 2byte
 	int16_t front;                   // 2byte
 	int16_t rear;                    // 2byte
 } _menu_data_adjust_bed_t;
-#if (21 > MENU_DATA_SIZE)
-#error "check MENU_DATA_SIZE definition!"
-#endif
+static_assert(sizeof(menu_data)>= sizeof(_menu_data_adjust_bed_t),"_menu_data_adjust_bed_t doesn't fit into menu_data");
 
 void lcd_adjust_bed_reset(void)
 {
@@ -3559,6 +3561,27 @@ void lcd_diag_show_end_stops()
     lcd_return_to_status();
 }
 
+#ifdef TMC2130
+static void lcd_show_pinda_state()
+{
+lcd_set_cursor(0, 0);
+lcd_puts_P((PSTR("P.I.N.D.A. state")));
+lcd_set_cursor(0, 2);
+lcd_puts_P(READ(Z_MIN_PIN)?(PSTR("Z1 (LED off)")):(PSTR("Z0 (LED on) "))); // !!! both strings must have same length (due to dynamic refreshing)
+}
+
+static void menu_show_pinda_state()
+{
+lcd_timeoutToStatus.stop();
+lcd_show_pinda_state();
+if(LCD_CLICKED)
+     {
+     lcd_timeoutToStatus.start();
+     menu_back();
+     }
+}
+#endif // defined TMC2130
+
 
 
 void prusa_statistics(int _message, uint8_t _fil_nr) {
@@ -4047,15 +4070,16 @@ static void lcd_crash_mode_set()
 static void lcd_fsensor_state_set()
 {
 	FSensorStateMenu = !FSensorStateMenu; //set also from fsensor_enable() and fsensor_disable()
-    if (!FSensorStateMenu) {
-        fsensor_disable();
-        if (fsensor_autoload_enabled)
-            menu_submenu(lcd_filament_autoload_info);
-    }else{
-        fsensor_enable();
-        if (fsensor_not_responding)
-            menu_submenu(lcd_fsensor_fail);
-    }
+	if (!FSensorStateMenu) {
+		fsensor_disable();
+		if (fsensor_autoload_enabled && !mmu_enabled)
+			menu_submenu(lcd_filament_autoload_info);
+	}
+	else {
+		fsensor_enable();
+		if (fsensor_not_responding && !mmu_enabled)
+			menu_submenu(lcd_fsensor_fail);
+	}
 }
 #endif //FILAMENT_SENSOR
 
@@ -4386,6 +4410,7 @@ void lcd_wizard(int state) {
 			break;
 		case 5: //is filament loaded?
 				//start to preheat nozzle and bed to save some time later
+               lcd_commands_type = LCD_COMMAND_V2_CAL;
 			setTargetHotend(PLA_PREHEAT_HOTEND_TEMP, 0);
 			setTargetBed(PLA_PREHEAT_HPB_TEMP);
 			wizard_event = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Is filament loaded?"), false);////MSG_WIZARD_FILAMENT_LOADED c=20 r=2
@@ -4423,6 +4448,7 @@ void lcd_wizard(int state) {
 #ifdef SNMM
 			change_extr(0);
 #endif
+               loading_flag = true;
 			gcode_M701();
 			state = 9;
 			break;
@@ -4495,28 +4521,181 @@ void lcd_wizard(int state) {
 	lcd_return_to_status();
 	lcd_update(2);
 }
-/*
+
+#ifdef TMC2130
 void lcd_settings_linearity_correction_menu(void)
 {
 	MENU_BEGIN();
-	if (menu_item_back_P(_T(MSG_MAIN)))
-	{
-		lcd_settings_menu_back();
-		return;
-	}
-//	MENU_ITEM_BACK_P(_T(MSG_SETTINGS));
+	MENU_ITEM_BACK_P(_T(MSG_SETTINGS));
 #ifdef TMC2130_LINEARITY_CORRECTION_XYZ
 	//tmc2130_wave_fac[X_AXIS]
-	int corr[4] = {tmc2130_wave_fac[X_AXIS], tmc2130_wave_fac[Y_AXIS], tmc2130_wave_fac[Z_AXIS], tmc2130_wave_fac[E_AXIS]};
 
-	MENU_ITEM_EDIT_int3_P(_i("X-correct"),  &corr[X_AXIS],  TMC2130_WAVE_FAC1000_MIN-TMC2130_WAVE_FAC1000_STP, TMC2130_WAVE_FAC1000_MAX);////MSG_EXTRUDER_CORRECTION c=9 r=0
-	MENU_ITEM_EDIT_int3_P(_i("Y-correct"),  &corr[Y_AXIS],  TMC2130_WAVE_FAC1000_MIN-TMC2130_WAVE_FAC1000_STP, TMC2130_WAVE_FAC1000_MAX);////MSG_EXTRUDER_CORRECTION c=9 r=0
-	MENU_ITEM_EDIT_int3_P(_i("Z-correct"),  &corr[Z_AXIS],  TMC2130_WAVE_FAC1000_MIN-TMC2130_WAVE_FAC1000_STP, TMC2130_WAVE_FAC1000_MAX);////MSG_EXTRUDER_CORRECTION c=9 r=0
+	MENU_ITEM_EDIT_int3_P(_i("X-correct"),  &tmc2130_wave_fac[X_AXIS],  TMC2130_WAVE_FAC1000_MIN-TMC2130_WAVE_FAC1000_STP, TMC2130_WAVE_FAC1000_MAX);////MSG_EXTRUDER_CORRECTION c=9 r=0
+	MENU_ITEM_EDIT_int3_P(_i("Y-correct"),  &tmc2130_wave_fac[Y_AXIS],  TMC2130_WAVE_FAC1000_MIN-TMC2130_WAVE_FAC1000_STP, TMC2130_WAVE_FAC1000_MAX);////MSG_EXTRUDER_CORRECTION c=9 r=0
+	MENU_ITEM_EDIT_int3_P(_i("Z-correct"),  &tmc2130_wave_fac[Z_AXIS],  TMC2130_WAVE_FAC1000_MIN-TMC2130_WAVE_FAC1000_STP, TMC2130_WAVE_FAC1000_MAX);////MSG_EXTRUDER_CORRECTION c=9 r=0
 #endif //TMC2130_LINEARITY_CORRECTION_XYZ
-	MENU_ITEM_EDIT_int3_P(_i("E-correct"),  &corr[E_AXIS],  TMC2130_WAVE_FAC1000_MIN-TMC2130_WAVE_FAC1000_STP, TMC2130_WAVE_FAC1000_MAX);////MSG_EXTRUDER_CORRECTION c=9 r=0
+	MENU_ITEM_EDIT_int3_P(_i("E-correct"),  &tmc2130_wave_fac[E_AXIS],  TMC2130_WAVE_FAC1000_MIN-TMC2130_WAVE_FAC1000_STP, TMC2130_WAVE_FAC1000_MAX);////MSG_EXTRUDER_CORRECTION c=9 r=0
 	MENU_END();
+	if(menu_leaving)
+	{
+	    lcd_settings_linearity_correction_menu_save();
+	}
+}
+#endif // TMC2130
+
+#ifdef FILAMENT_SENSOR
+#define SETTINGS_FILAMENT_SENSOR \
+do\
+{\
+    if (FSensorStateMenu == 0)\
+    {\
+        if (fsensor_not_responding)\
+        {\
+            /* Filament sensor not working*/\
+            MENU_ITEM_FUNCTION_P(_i("Fil. sensor [N/A]"), lcd_fsensor_state_set);/*////MSG_FSENSOR_NA c=0 r=0*/\
+            MENU_ITEM_SUBMENU_P(_T(MSG_FSENS_AUTOLOAD_NA), lcd_fsensor_fail);\
+        }\
+        else\
+        {\
+            /* Filament sensor turned off, working, no problems*/\
+            MENU_ITEM_FUNCTION_P(_T(MSG_FSENSOR_OFF), lcd_fsensor_state_set);\
+            if (mmu_enabled == false)if (mmu_enabled == false)\
+            {\
+                MENU_ITEM_SUBMENU_P(_T(MSG_FSENS_AUTOLOAD_NA), lcd_filament_autoload_info);\
+            }\
+        }\
+    }\
+    else\
+    {\
+        /* Filament sensor turned on, working, no problems*/\
+        MENU_ITEM_FUNCTION_P(_T(MSG_FSENSOR_ON), lcd_fsensor_state_set);\
+        if (mmu_enabled == false)\
+        {\
+            if (fsensor_autoload_enabled)\
+                MENU_ITEM_FUNCTION_P(_i("F. autoload  [on]"), lcd_set_filament_autoload);/*////MSG_FSENS_AUTOLOAD_ON c=17 r=1*/\
+            else\
+                MENU_ITEM_FUNCTION_P(_i("F. autoload [off]"), lcd_set_filament_autoload);/*////MSG_FSENS_AUTOLOAD_OFF c=17 r=1*/\
+        }\
+    }\
+}\
+while(0)
+
+#else //FILAMENT_SENSOR
+#define SETTINGS_FILAMENT_SENSOR do{}while(0)
+#endif //FILAMENT_SENSOR
+
+#ifdef TMC2130
+#define SETTINGS_SILENT_MODE \
+do\
+{\
+    if(!farm_mode)\
+    {\
+        if (SilentModeMenu == SILENT_MODE_NORMAL)\
+        {\
+            MENU_ITEM_FUNCTION_P(_T(MSG_STEALTH_MODE_OFF), lcd_silent_mode_set);\
+        }\
+        else MENU_ITEM_FUNCTION_P(_T(MSG_STEALTH_MODE_ON), lcd_silent_mode_set);\
+        if (SilentModeMenu == SILENT_MODE_NORMAL)\
+        {\
+            if (CrashDetectMenu == 0)\
+            {\
+                MENU_ITEM_FUNCTION_P(_T(MSG_CRASHDETECT_OFF), lcd_crash_mode_set);\
+            }\
+            else MENU_ITEM_FUNCTION_P(_T(MSG_CRASHDETECT_ON), lcd_crash_mode_set);\
+        }\
+        else MENU_ITEM_SUBMENU_P(_T(MSG_CRASHDETECT_NA), lcd_crash_mode_info);\
+    }\
+}\
+while (0)
+
+#else //TMC2130
+#define SETTINGS_SILENT_MODE \
+do\
+{\
+    if(!farm_mode)\
+    {\
+        switch (SilentModeMenu)\
+        {\
+        case SILENT_MODE_POWER:\
+            MENU_ITEM_FUNCTION_P(_T(MSG_SILENT_MODE_OFF), lcd_silent_mode_set);\
+            break;\
+        case SILENT_MODE_SILENT:\
+            MENU_ITEM_FUNCTION_P(_T(MSG_SILENT_MODE_ON), lcd_silent_mode_set);\
+            break;\
+        case SILENT_MODE_AUTO:\
+            MENU_ITEM_FUNCTION_P(_T(MSG_AUTO_MODE_ON), lcd_silent_mode_set);\
+            break;\
+        default:\
+            MENU_ITEM_FUNCTION_P(_T(MSG_SILENT_MODE_OFF), lcd_silent_mode_set);\
+            break; /* (probably) not needed*/\
+        }\
+    }\
+}\
+while (0)
+#endif //TMC2130
+
+#ifdef SDCARD_SORT_ALPHA
+#define SETTINGS_SD \
+do\
+{\
+    if (card.ToshibaFlashAir_isEnabled())\
+        MENU_ITEM_FUNCTION_P(_i("SD card [flshAir]"), lcd_toshiba_flash_air_compatibility_toggle);/*////MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON c=19 r=1*/\
+    else\
+        MENU_ITEM_FUNCTION_P(_i("SD card  [normal]"), lcd_toshiba_flash_air_compatibility_toggle);/*////MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF c=19 r=1*/\
+\
+    if (!farm_mode)\
+    {\
+        uint8_t sdSort;\
+        EEPROM_read(EEPROM_SD_SORT, (uint8_t*)&sdSort, sizeof(sdSort));\
+        switch (sdSort)\
+        {\
+          case SD_SORT_TIME: MENU_ITEM_FUNCTION_P(_i("Sort:      [time]"), lcd_sort_type_set); break;/*////MSG_SORT_TIME c=17 r=1*/\
+          case SD_SORT_ALPHA: MENU_ITEM_FUNCTION_P(_i("Sort:  [alphabet]"), lcd_sort_type_set); break;/*////MSG_SORT_ALPHA c=17 r=1*/\
+          default: MENU_ITEM_FUNCTION_P(_i("Sort:      [none]"), lcd_sort_type_set);/*////MSG_SORT_NONE c=17 r=1*/\
+        }\
+    }\
+}\
+while (0)
+#else // SDCARD_SORT_ALPHA
+#define SETTINGS_SD \
+do\
+{\
+    if (card.ToshibaFlashAir_isEnabled())\
+        MENU_ITEM_FUNCTION_P(_i("SD card [flshAir]"), lcd_toshiba_flash_air_compatibility_toggle);/*////MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON c=19 r=1*/\
+    else\
+        MENU_ITEM_FUNCTION_P(_i("SD card  [normal]"), lcd_toshiba_flash_air_compatibility_toggle);/*////MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF c=19 r=1*/\
+}\
+while (0)
+#endif // SDCARD_SORT_ALPHA
+
+#define SETTINGS_SOUND \
+do\
+{\
+    switch(eSoundMode)\
+         {\
+         case e_SOUND_MODE_LOUD:\
+              MENU_ITEM_FUNCTION_P(_i(MSG_SOUND_MODE_LOUD),lcd_sound_state_set);\
+              break;\
+         case e_SOUND_MODE_ONCE:\
+              MENU_ITEM_FUNCTION_P(_i(MSG_SOUND_MODE_ONCE),lcd_sound_state_set);\
+              break;\
+         case e_SOUND_MODE_SILENT:\
+              MENU_ITEM_FUNCTION_P(_i(MSG_SOUND_MODE_SILENT),lcd_sound_state_set);\
+              break;\
+         case e_SOUND_MODE_MUTE:\
+              MENU_ITEM_FUNCTION_P(_i(MSG_SOUND_MODE_MUTE),lcd_sound_state_set);\
+              break;\
+         default:\
+              MENU_ITEM_FUNCTION_P(_i(MSG_SOUND_MODE_LOUD),lcd_sound_state_set);\
+         }\
+}\
+while (0)
+
+static void auto_deplete_switch()
+{
+    lcd_autoDeplete = !lcd_autoDeplete;
+    eeprom_update_byte((unsigned char *)EEPROM_AUTO_DEPLETE, lcd_autoDeplete);
 }
-*/
 static void lcd_settings_menu()
 {
 	EEPROM_read(EEPROM_SILENT, (uint8_t*)&SilentModeMenu, sizeof(SilentModeMenu));
@@ -4525,70 +4704,28 @@ static void lcd_settings_menu()
 
 	MENU_ITEM_SUBMENU_P(_i("Temperature"), lcd_control_temperature_menu);////MSG_TEMPERATURE c=0 r=0
 	if (!homing_flag)
-	MENU_ITEM_SUBMENU_P(_i("Move axis"), lcd_move_menu_1mm);////MSG_MOVE_AXIS c=0 r=0
+	    MENU_ITEM_SUBMENU_P(_i("Move axis"), lcd_move_menu_1mm);////MSG_MOVE_AXIS c=0 r=0
 	if (!isPrintPaused)
-	MENU_ITEM_GCODE_P(_i("Disable steppers"), PSTR("M84"));////MSG_DISABLE_STEPPERS c=0 r=0
+	    MENU_ITEM_GCODE_P(_i("Disable steppers"), PSTR("M84"));////MSG_DISABLE_STEPPERS c=0 r=0
 
-#ifndef TMC2130
-	if (!farm_mode)
-	{ //dont show in menu if we are in farm mode
-		switch (SilentModeMenu)
-		{
-		case SILENT_MODE_POWER: MENU_ITEM_FUNCTION_P(_T(MSG_SILENT_MODE_OFF), lcd_silent_mode_set); break;
-		case SILENT_MODE_SILENT: MENU_ITEM_FUNCTION_P(_T(MSG_SILENT_MODE_ON), lcd_silent_mode_set); break;
-		case SILENT_MODE_AUTO: MENU_ITEM_FUNCTION_P(_T(MSG_AUTO_MODE_ON), lcd_silent_mode_set); break;
-		default: MENU_ITEM_FUNCTION_P(_T(MSG_SILENT_MODE_OFF), lcd_silent_mode_set); break; // (probably) not needed
-		}
-	}
-#endif //TMC2130
+	SETTINGS_FILAMENT_SENSOR;
 
-#ifdef FILAMENT_SENSOR
-	if (FSensorStateMenu == 0)
-	{
-		if (fsensor_not_responding)
-		{
-			// Filament sensor not working
-			MENU_ITEM_FUNCTION_P(_i("Fil. sensor [N/A]"), lcd_fsensor_state_set);////MSG_FSENSOR_NA c=0 r=0
-			MENU_ITEM_SUBMENU_P(_T(MSG_FSENS_AUTOLOAD_NA), lcd_fsensor_fail);
-		}
-		else
-		{
-			// Filament sensor turned off, working, no problems
-			MENU_ITEM_FUNCTION_P(_T(MSG_FSENSOR_OFF), lcd_fsensor_state_set);
-			MENU_ITEM_SUBMENU_P(_T(MSG_FSENS_AUTOLOAD_NA), lcd_filament_autoload_info);
-		}
-	}
-	else
+	if (mmu_enabled)
 	{
-		// Filament sensor turned on, working, no problems
-		MENU_ITEM_FUNCTION_P(_T(MSG_FSENSOR_ON), lcd_fsensor_state_set);
-		if (fsensor_autoload_enabled)
-			MENU_ITEM_FUNCTION_P(_i("F. autoload  [on]"), lcd_set_filament_autoload);////MSG_FSENS_AUTOLOAD_ON c=17 r=1
-		else
-			MENU_ITEM_FUNCTION_P(_i("F. autoload [off]"), lcd_set_filament_autoload);////MSG_FSENS_AUTOLOAD_OFF c=17 r=1
+        if (lcd_autoDeplete) MENU_ITEM_FUNCTION_P(_i("Auto deplete [on]"), auto_deplete_switch);
+        else MENU_ITEM_FUNCTION_P(_i("Auto deplete[off]"), auto_deplete_switch);
 	}
-#endif //FILAMENT_SENSOR
 
 	if (fans_check_enabled == true)
 		MENU_ITEM_FUNCTION_P(_i("Fans check   [on]"), lcd_set_fan_check);////MSG_FANS_CHECK_ON c=17 r=1
 	else
 		MENU_ITEM_FUNCTION_P(_i("Fans check  [off]"), lcd_set_fan_check);////MSG_FANS_CHECK_OFF c=17 r=1
 
-#ifdef TMC2130
-	if(!farm_mode)
-	{
-		if (SilentModeMenu == SILENT_MODE_NORMAL) { MENU_ITEM_FUNCTION_P(_T(MSG_STEALTH_MODE_OFF), lcd_silent_mode_set); }
-		else MENU_ITEM_FUNCTION_P(_T(MSG_STEALTH_MODE_ON), lcd_silent_mode_set);
-		if (SilentModeMenu == SILENT_MODE_NORMAL)
-		{
-			if (CrashDetectMenu == 0) { MENU_ITEM_FUNCTION_P(_T(MSG_CRASHDETECT_OFF), lcd_crash_mode_set); }
-			else MENU_ITEM_FUNCTION_P(_T(MSG_CRASHDETECT_ON), lcd_crash_mode_set);
-		}
-		else MENU_ITEM_SUBMENU_P(_T(MSG_CRASHDETECT_NA), lcd_crash_mode_info);
-	}
+	SETTINGS_SILENT_MODE;
 
-//  MENU_ITEM_SUBMENU_P(_i("Lin. correction"), lcd_settings_linearity_correction_menu);
-#endif //TMC2130
+#if defined (TMC2130) && defined (LINEARITY_CORRECTION)
+    MENU_ITEM_SUBMENU_P(_i("Lin. correction"), lcd_settings_linearity_correction_menu);
+#endif //LINEARITY_CORRECTION && TMC2130
 
   if (temp_cal_active == false)
 	  MENU_ITEM_FUNCTION_P(_i("Temp. cal.  [off]"), lcd_temp_calibration_set);////MSG_TEMP_CALIBRATION_OFF c=20 r=1
@@ -4609,45 +4746,9 @@ static void lcd_settings_menu()
 	MENU_ITEM_SUBMENU_P(_i("Select language"), lcd_language_menu);////MSG_LANGUAGE_SELECT c=0 r=0
 #endif //(LANG_MODE != 0)
 
-	if (card.ToshibaFlashAir_isEnabled())
-		MENU_ITEM_FUNCTION_P(_i("SD card [flshAir]"), lcd_toshiba_flash_air_compatibility_toggle);////MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON c=19 r=1
-	else
-		MENU_ITEM_FUNCTION_P(_i("SD card  [normal]"), lcd_toshiba_flash_air_compatibility_toggle);////MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF c=19 r=1
+	SETTINGS_SD;
+	SETTINGS_SOUND;
 
-#ifdef SDCARD_SORT_ALPHA
-	if (!farm_mode)
-	{
-		uint8_t sdSort;
-		EEPROM_read(EEPROM_SD_SORT, (uint8_t*)&sdSort, sizeof(sdSort));
-		switch (sdSort)
-		{
-		  case SD_SORT_TIME: MENU_ITEM_FUNCTION_P(_i("Sort:      [time]"), lcd_sort_type_set); break;////MSG_SORT_TIME c=17 r=1
-		  case SD_SORT_ALPHA: MENU_ITEM_FUNCTION_P(_i("Sort:  [alphabet]"), lcd_sort_type_set); break;////MSG_SORT_ALPHA c=17 r=1
-		  default: MENU_ITEM_FUNCTION_P(_i("Sort:      [none]"), lcd_sort_type_set);////MSG_SORT_NONE c=17 r=1
-		}
-	}
-#endif // SDCARD_SORT_ALPHA
-    
-
-//-//
-switch(eSoundMode)
-     {
-     case e_SOUND_MODE_LOUD:
-          MENU_ITEM_FUNCTION_P(_i(MSG_SOUND_MODE_LOUD),lcd_sound_state_set);
-          break;
-     case e_SOUND_MODE_ONCE:
-          MENU_ITEM_FUNCTION_P(_i(MSG_SOUND_MODE_ONCE),lcd_sound_state_set);
-          break;
-     case e_SOUND_MODE_SILENT:
-          MENU_ITEM_FUNCTION_P(_i(MSG_SOUND_MODE_SILENT),lcd_sound_state_set);
-          break;
-     case e_SOUND_MODE_MUTE:
-          MENU_ITEM_FUNCTION_P(_i(MSG_SOUND_MODE_MUTE),lcd_sound_state_set);
-          break;
-     default:
-          MENU_ITEM_FUNCTION_P(_i(MSG_SOUND_MODE_LOUD),lcd_sound_state_set);
-     }
-//-//
 	if (farm_mode)
 	{
 		MENU_ITEM_SUBMENU_P(PSTR("Farm number"), lcd_farm_no);
@@ -4672,8 +4773,8 @@ static void lcd_ustep_linearity_menu_save()
 }
 #endif //TMC2130
 
-/*
-static void lcd_settings_menu_back()
+
+static void lcd_settings_linearity_correction_menu_save()
 {
 #ifdef TMC2130
     bool changed = false;
@@ -4688,10 +4789,8 @@ static void lcd_settings_menu_back()
     lcd_ustep_linearity_menu_save();
     if (changed) tmc2130_init();
 #endif //TMC2130
-    menu_menu = lcd_main_menu;
-//    lcd_main_menu();
 }
-*/
+
 
 static void lcd_calibration_menu()
 {
@@ -4722,7 +4821,9 @@ static void lcd_calibration_menu()
 
     MENU_ITEM_SUBMENU_P(_i("Bed level correct"), lcd_adjust_bed);////MSG_BED_CORRECTION_MENU c=0 r=0
 	MENU_ITEM_SUBMENU_P(_i("PID calibration"), pid_extruder);////MSG_PID_EXTRUDER c=17 r=1
-#ifndef TMC2130
+#ifdef TMC2130
+    MENU_ITEM_SUBMENU_P(_i("Show pinda state"), menu_show_pinda_state);
+#else
     MENU_ITEM_SUBMENU_P(_i("Show end stops"), menu_show_end_stops);////MSG_SHOW_END_STOPS c=17 r=1
 #endif
 #ifndef MK1BP
@@ -5110,6 +5211,19 @@ static void fil_load_menu()
 	MENU_END();
 }
 
+static void mmu_fil_eject_menu()
+{
+	MENU_BEGIN();
+	MENU_ITEM_BACK_P(_T(MSG_MAIN));
+	MENU_ITEM_FUNCTION_P(_i("Eject filament 1"), mmu_eject_fil_0);
+	MENU_ITEM_FUNCTION_P(_i("Eject filament 2"), mmu_eject_fil_1);
+	MENU_ITEM_FUNCTION_P(_i("Eject filament 3"), mmu_eject_fil_2);
+	MENU_ITEM_FUNCTION_P(_i("Eject filament 4"), mmu_eject_fil_3);
+	MENU_ITEM_FUNCTION_P(_i("Eject filament 5"), mmu_eject_fil_4);
+
+	MENU_END();
+}
+
 static void fil_unload_menu()
 {
 	MENU_BEGIN();
@@ -5489,7 +5603,7 @@ static void lcd_main_menu()
     
         
     }*/
-    
+ 
   if ( ( IS_SD_PRINTING || is_usb_printing || (lcd_commands_type == LCD_COMMAND_V2_CAL)) && (current_position[Z_AXIS] < Z_HEIGHT_HIDE_LIVE_ADJUST_MENU) && !homing_flag && !mesh_bed_leveling_flag)
   {
 	MENU_ITEM_SUBMENU_P(_T(MSG_BABYSTEP_Z), lcd_babystep_z);//8
@@ -5558,6 +5672,7 @@ static void lcd_main_menu()
 	if (mmu_enabled)
 	{
 		MENU_ITEM_SUBMENU_P(_T(MSG_LOAD_FILAMENT), fil_load_menu);
+		MENU_ITEM_SUBMENU_P(_i("Eject filament"), mmu_fil_eject_menu);
 		if (mmu_enabled)
 			MENU_ITEM_GCODE_P(_T(MSG_UNLOAD_FILAMENT), PSTR("M702 C"));
 		else
@@ -5569,7 +5684,7 @@ static void lcd_main_menu()
 	else
 	{
 #ifdef FILAMENT_SENSOR
-		if ( ((fsensor_autoload_enabled == true) && (fsensor_enabled == true)))
+		if ((fsensor_autoload_enabled == true) && (fsensor_enabled == true) && (mmu_enabled == false))
 			MENU_ITEM_SUBMENU_P(_i("AutoLoad filament"), lcd_menu_AutoLoadFilament);////MSG_AUTOLOAD_FILAMENT c=17 r=0
 		else
 #endif //FILAMENT_SENSOR
@@ -5671,16 +5786,14 @@ static void lcd_colorprint_change() {
 static void lcd_tune_menu()
 {
 	typedef struct
-	{	// 3bytes total
-		// To recognize, whether the menu has been just initialized.
-		int8_t  status;                                 // 1byte
-		// Backup of extrudemultiply, to recognize, that the value has been changed and
-		// it needs to be applied.
-		int16_t extrudemultiply;                        // 2byte
+	{
+	    menu_data_edit_t reserved; //!< reserved for number editing functions
+		int8_t  status; //!< To recognize, whether the menu has been just initialized.
+		//! Backup of extrudemultiply, to recognize, that the value has been changed and
+		//! it needs to be applied.
+		int16_t extrudemultiply;
 	} _menu_data_t;
-#if (3 > MENU_DATA_SIZE)
-#error "check MENU_DATA_SIZE definition!"
-#endif
+	static_assert(sizeof(menu_data)>= sizeof(_menu_data_t),"_menu_data_t doesn't fit into menu_data");
 	_menu_data_t* _md = (_menu_data_t*)&(menu_data[0]);
 	if (_md->status == 0)
 	{
@@ -6092,14 +6205,19 @@ bool lcd_selftest()
 	{
 		_progress = lcd_selftest_screen(8, _progress, 3, true, 2000); //bed ok
 #ifdef FILAMENT_SENSOR
-		_progress = lcd_selftest_screen(9, _progress, 3, true, 2000); //check filaments sensor
-		_result = lcd_selftest_fsensor();
+		if (mmu_enabled == false) {
+			_progress = lcd_selftest_screen(9, _progress, 3, true, 2000); //check filaments sensor
+			_result = lcd_selftest_fsensor();
+		}
 #endif // FILAMENT_SENSOR
 	}
 	if (_result)
 	{
 #ifdef FILAMENT_SENSOR
-		_progress = lcd_selftest_screen(10, _progress, 3, true, 2000); //fil sensor OK
+		if (mmu_enabled == false)
+		{
+			_progress = lcd_selftest_screen(10, _progress, 3, true, 2000); //fil sensor OK
+		}
 #endif // FILAMENT_SENSOR
 		_progress = lcd_selftest_screen(11, _progress, 3, true, 5000); //all correct
 	}
@@ -6997,6 +7115,12 @@ void menu_action_sddirectory(const char* filename, char* longFilename)
 
 void ultralcd_init()
 {
+    {
+        uint8_t autoDepleteRaw = eeprom_read_byte(reinterpret_cast<uint8_t*>(EEPROM_AUTO_DEPLETE));
+        if (0xff == autoDepleteRaw) lcd_autoDeplete = false;
+        else lcd_autoDeplete = autoDepleteRaw;
+
+    }
 	lcd_init();
 	lcd_refresh();
 	lcd_longpress_func = menu_lcd_longpress_func;

+ 2 - 0
Firmware/ultralcd.h

@@ -45,6 +45,7 @@ void lcd_menu_statistics();
 extern const char* lcd_display_message_fullscreen_P(const char *msg, uint8_t &nlines);
 extern const char* lcd_display_message_fullscreen_P(const char *msg);
 
+extern void lcd_return_to_status();
 extern void lcd_wait_for_click();
 extern void lcd_show_fullscreen_message_and_wait_P(const char *msg);
 // 0: no, 1: yes, -1: timeouted
@@ -111,6 +112,7 @@ extern int8_t SilentModeMenu;
 
 extern bool cancel_heatup;
 extern bool isPrintPaused;
+extern bool lcd_autoDeplete;
 
 
 void lcd_ignore_click(bool b=true);

+ 2 - 1
Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h

@@ -100,7 +100,7 @@
 
 //Silent mode limits
 #define SILENT_MAX_ACCEL_XY      960ul  // max acceleration in silent mode in mm/s^2
-#define SILENT_MAX_FEEDRATE_XY   172  // max feedrate in mm/s
+#define SILENT_MAX_FEEDRATE_XY   100  // max feedrate in mm/s
 
 //Normal mode limits
 #define NORMAL_MAX_ACCEL_XY     2500ul  // max acceleration in normal mode in mm/s^2
@@ -183,6 +183,7 @@
 #define CMD_DIAGNOSTICS //Show cmd queue length on printer display
 #endif /* DEBUG_BUILD */
 
+#define LINEARITY_CORRECTION
 #define TMC2130_LINEARITY_CORRECTION
 #define TMC2130_LINEARITY_CORRECTION_XYZ
 //#define TMC2130_VARIABLE_RESOLUTION