Browse Source

3.0.10 sync

michalprusa 7 years ago
parent
commit
3faef75a0d

+ 30 - 9
Firmware/Configuration.h

@@ -5,7 +5,7 @@
 #include "Configuration_prusa.h"
 
 // Firmware version
-#define FW_version "3.0.8"
+#define FW_version "3.0.10-8"
 
 #define FW_PRUSA3D_MAGIC "PRUSA3DFW"
 #define FW_PRUSA3D_MAGIC_LEN 10
@@ -18,7 +18,7 @@
 #define EEPROM_BABYSTEP_X 4092
 #define EEPROM_BABYSTEP_Y 4090
 #define EEPROM_BABYSTEP_Z 4088
-#define EEPROM_BABYSTEP_Z_SET 4087
+#define EEPROM_CALIBRATION_STATUS 4087
 #define EEPROM_BABYSTEP_Z0 4085
 #define EEPROM_FILAMENTUSED 4081
 // uint32_t
@@ -31,27 +31,30 @@
 // Offsets of the Z heiths of the calibration points from the first point.
 // The offsets are saved as 16bit signed int, scaled to tenths of microns.
 #define EEPROM_BED_CALIBRATION_Z_JITTER   (EEPROM_BED_CALIBRATION_VEC_Y-2*8)
-
-#define EEPROM_FARM_MODE (EEPROM_BED_CALIBRATION_Z_JITTER-4)
+#define EEPROM_FARM_MODE (EEPROM_BED_CALIBRATION_Z_JITTER-1)
+#define EEPROM_FARM_NUMBER (EEPROM_FARM_MODE-3)
 
 // Correction of the bed leveling, in micrometers.
 // Maximum 50 micrometers allowed.
 // Bed correction is valid if set to 1. If set to zero or 255, the successive 4 bytes are invalid.
-#define EEPROM_BED_CORRECTION_VALID (EEPROM_FARM_MODE-1)
+#define EEPROM_BED_CORRECTION_VALID (EEPROM_FARM_NUMBER-1)
 #define EEPROM_BED_CORRECTION_LEFT  (EEPROM_BED_CORRECTION_VALID-1)
 #define EEPROM_BED_CORRECTION_RIGHT (EEPROM_BED_CORRECTION_LEFT-1)
 #define EEPROM_BED_CORRECTION_FRONT (EEPROM_BED_CORRECTION_RIGHT-1)
 #define EEPROM_BED_CORRECTION_REAR  (EEPROM_BED_CORRECTION_FRONT-1)
 #define EEPROM_TOSHIBA_FLASH_AIR_COMPATIBLITY (EEPROM_BED_CORRECTION_REAR-1)
+#define EEPROM_PRINT_FLAG (EEPROM_TOSHIBA_FLASH_AIR_COMPATIBLITY-1)
 
 // Currently running firmware, each digit stored as uint16_t.
 // The flavor differentiates a dev, alpha, beta, release candidate or a release version.
+#define EEPROM_FIRMWARE_VERSION_END       (FW_PRUSA3D_MAGIC_LEN+8)
 #define EEPROM_FIRMWARE_VERSION_FLAVOR    (FW_PRUSA3D_MAGIC_LEN+6)
 #define EEPROM_FIRMWARE_VERSION_REVISION  (FW_PRUSA3D_MAGIC_LEN+4)
 #define EEPROM_FIRMWARE_VERSION_MINOR     (FW_PRUSA3D_MAGIC_LEN+2)
 #define EEPROM_FIRMWARE_VERSION_MAJOR     FW_PRUSA3D_MAGIC_LEN
 // Magic string, indicating that the current or the previous firmware running was the Prusa3D firmware.
-#define EEPROM_FIRMWARE_PRUSA_MAGIC
+#define EEPROM_FIRMWARE_PRUSA_MAGIC 0
+
 
 // This configuration file contains the basic settings.
 // Advanced settings can be found in Configuration_adv.h
@@ -692,14 +695,32 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of
 //#define FILAMENT_LCD_DISPLAY
 
 
+// Calibration status of the machine, to be stored into the EEPROM,
+// (unsigned char*)EEPROM_CALIBRATION_STATUS
+enum CalibrationStatus
+{
+    // Freshly assembled, needs to peform a self-test and the XYZ calibration.
+    CALIBRATION_STATUS_ASSEMBLED = 255,
 
+    // For the wizard: self test has been performed, now the XYZ calibration is needed.
+    // CALIBRATION_STATUS_XYZ_CALIBRATION = 250,
 
+    // For the wizard: factory assembled, needs to run Z calibration.
+    CALIBRATION_STATUS_Z_CALIBRATION = 240,
 
+    // The XYZ calibration has been performed, now it remains to run the V2Calibration.gcode.
+    CALIBRATION_STATUS_LIVE_ADJUST = 230,
 
-#include "Configuration_adv.h"
-#include "thermistortables.h"
-
+    // Calibrated, ready to print.
+    CALIBRATION_STATUS_CALIBRATED = 1,
 
+    // Legacy: resetted by issuing a G86 G-code.
+    // This value can only be expected after an upgrade from the initial MK2 firmware releases.
+    // Currently the G86 sets the calibration status to 
+    CALIBRATION_STATUS_UNKNOWN = 0,
+};
 
+#include "Configuration_adv.h"
+#include "thermistortables.h"
 
 #endif //__CONFIGURATION_H

+ 38 - 12
Firmware/ConfigurationStore.cpp

@@ -34,7 +34,7 @@ void _EEPROM_readData(int &pos, uint8_t* value, uint8_t size)
 
 
 
-#define EEPROM_OFFSET 100
+#define EEPROM_OFFSET 20
 
 
 // IMPORTANT:  Whenever there are changes made to the variables stored in EEPROM
@@ -43,7 +43,7 @@ void _EEPROM_readData(int &pos, uint8_t* value, uint8_t size)
 // wrong data being written to the variables.
 // ALSO:  always make sure the variables in the Store and retrieve sections are in the same order.
 
-#define EEPROM_VERSION "V13"
+#define EEPROM_VERSION "V1"
 
 #ifdef EEPROM_SETTINGS
 void Config_StoreSettings() 
@@ -59,9 +59,10 @@ void Config_StoreSettings()
   EEPROM_WRITE_VAR(i,minimumfeedrate);
   EEPROM_WRITE_VAR(i,mintravelfeedrate);
   EEPROM_WRITE_VAR(i,minsegmenttime);
-  EEPROM_WRITE_VAR(i,max_xy_jerk);
-  EEPROM_WRITE_VAR(i,max_z_jerk);
-  EEPROM_WRITE_VAR(i,max_e_jerk);
+  EEPROM_WRITE_VAR(i,max_jerk[X_AXIS]);
+  EEPROM_WRITE_VAR(i,max_jerk[Y_AXIS]);
+  EEPROM_WRITE_VAR(i,max_jerk[Z_AXIS]);
+  EEPROM_WRITE_VAR(i,max_jerk[E_AXIS]);
   EEPROM_WRITE_VAR(i,add_homing);
   #ifndef ULTIPANEL
   int plaPreheatHotendTemp = PLA_PREHEAT_HOTEND_TEMP, plaPreheatHPBTemp = PLA_PREHEAT_HPB_TEMP, plaPreheatFanSpeed = PLA_PREHEAT_FAN_SPEED;
@@ -70,12 +71,13 @@ void Config_StoreSettings()
 
   
   #endif
-  EEPROM_WRITE_VAR(i,plaPreheatHotendTemp);
+/*  EEPROM_WRITE_VAR(i,plaPreheatHotendTemp);
   EEPROM_WRITE_VAR(i,plaPreheatHPBTemp);
   EEPROM_WRITE_VAR(i,plaPreheatFanSpeed);
   EEPROM_WRITE_VAR(i,absPreheatHotendTemp);
   EEPROM_WRITE_VAR(i,absPreheatHPBTemp);
   EEPROM_WRITE_VAR(i,absPreheatFanSpeed);
+*/
   
   EEPROM_WRITE_VAR(i,zprobe_zoffset);
   #ifdef PIDTEMP
@@ -89,6 +91,11 @@ void Config_StoreSettings()
     EEPROM_WRITE_VAR(i,dummy);
     EEPROM_WRITE_VAR(i,dummy);
   #endif
+  #ifdef PIDTEMPBED
+	EEPROM_WRITE_VAR(i, bedKp);
+	EEPROM_WRITE_VAR(i, bedKi);
+	EEPROM_WRITE_VAR(i, bedKd);
+  #endif
   #ifndef DOGLCD
     int lcd_contrast = 32;
   #endif
@@ -117,7 +124,10 @@ void Config_StoreSettings()
   EEPROM_WRITE_VAR(i, filament_size[2]);
   #endif
   #endif
-  
+  /*MYSERIAL.print("Top address used:\n");
+  MYSERIAL.print(i);
+  MYSERIAL.print("\n");
+  */
   char ver2[4]=EEPROM_VERSION;
   i=EEPROM_OFFSET;
   EEPROM_WRITE_VAR(i,ver2); // validate data
@@ -191,6 +201,15 @@ void Config_PrintSettings()
     SERIAL_ECHOPAIR(" D" ,unscalePID_d(Kd));
     SERIAL_ECHOLN(""); 
 #endif
+#ifdef PIDTEMPBED
+	SERIAL_ECHO_START;
+	SERIAL_ECHOLNPGM("PID heatbed settings:");
+	SERIAL_ECHO_START;
+	SERIAL_ECHOPAIR("   M304 P", bedKp);
+	SERIAL_ECHOPAIR(" I", unscalePID_i(bedKi));
+	SERIAL_ECHOPAIR(" D", unscalePID_d(bedKd));
+	SERIAL_ECHOLN("");
+#endif
 #ifdef FWRETRACT
     SERIAL_ECHO_START;
     SERIAL_ECHOLNPGM("Retract: S=Length (mm) F:Speed (mm/m) Z: ZLift (mm)");
@@ -267,22 +286,24 @@ void Config_RetrieveSettings()
         EEPROM_READ_VAR(i,minimumfeedrate);
         EEPROM_READ_VAR(i,mintravelfeedrate);
         EEPROM_READ_VAR(i,minsegmenttime);
-        EEPROM_READ_VAR(i,max_xy_jerk);
-        EEPROM_READ_VAR(i,max_z_jerk);
-        EEPROM_READ_VAR(i,max_e_jerk);
+        EEPROM_READ_VAR(i,max_jerk[X_AXIS]);
+        EEPROM_READ_VAR(i,max_jerk[Y_AXIS]);
+		EEPROM_READ_VAR(i,max_jerk[Z_AXIS]);
+		EEPROM_READ_VAR(i,max_jerk[E_AXIS]);
         EEPROM_READ_VAR(i,add_homing);
         #ifndef ULTIPANEL
         int plaPreheatHotendTemp, plaPreheatHPBTemp, plaPreheatFanSpeed;
         int absPreheatHotendTemp, absPreheatHPBTemp, absPreheatFanSpeed;
 
         #endif
+	/*
         EEPROM_READ_VAR(i,plaPreheatHotendTemp);
         EEPROM_READ_VAR(i,plaPreheatHPBTemp);
         EEPROM_READ_VAR(i,plaPreheatFanSpeed);
         EEPROM_READ_VAR(i,absPreheatHotendTemp);
         EEPROM_READ_VAR(i,absPreheatHPBTemp);
         EEPROM_READ_VAR(i,absPreheatFanSpeed);
-        
+        */
 
         
         EEPROM_READ_VAR(i,zprobe_zoffset);
@@ -293,7 +314,12 @@ void Config_RetrieveSettings()
         EEPROM_READ_VAR(i,Kp);
         EEPROM_READ_VAR(i,Ki);
         EEPROM_READ_VAR(i,Kd);
-        #ifndef DOGLCD
+		#ifdef PIDTEMPBED
+		EEPROM_READ_VAR(i, bedKp);
+		EEPROM_READ_VAR(i, bedKi);
+		EEPROM_READ_VAR(i, bedKd);
+		#endif
+		#ifndef DOGLCD
         int lcd_contrast;
         #endif
         EEPROM_READ_VAR(i,lcd_contrast);

+ 4 - 0
Firmware/ConfigurationStore.h

@@ -1,5 +1,6 @@
 #ifndef CONFIG_STORE_H
 #define CONFIG_STORE_H
+#define EEPROM_SETTINGS
 
 #include "Configuration.h"
 
@@ -19,4 +20,7 @@ FORCE_INLINE void Config_StoreSettings() {}
 FORCE_INLINE void Config_RetrieveSettings() { Config_ResetDefault(); Config_PrintSettings(); }
 #endif
 
+inline uint8_t calibration_status() { return eeprom_read_byte((uint8_t*)EEPROM_CALIBRATION_STATUS); }
+inline uint8_t calibration_status_store(uint8_t status) { eeprom_update_byte((uint8_t*)EEPROM_CALIBRATION_STATUS, status); }
+
 #endif//CONFIG_STORE_H

+ 18 - 1
Firmware/Marlin.h

@@ -108,9 +108,10 @@ FORCE_INLINE void serialprintPGM(const char *str)
   }
 }
 
-
+bool is_buffer_empty();
 void get_command();
 void process_commands();
+void ramming();
 
 void manage_inactivity(bool ignore_stepper_queue=false);
 
@@ -282,15 +283,21 @@ extern float retract_recover_length, retract_recover_length_swap, retract_recove
 extern unsigned long starttime;
 extern unsigned long stoptime;
 extern bool is_usb_printing;
+extern bool homing_flag;
+extern bool loading_flag;
 extern unsigned int usb_printing_counter;
 
+extern unsigned long kicktime;
+
 extern unsigned long total_filament_used;
 void save_statistics(unsigned long _total_filament_used, unsigned long _total_print_time);
 extern unsigned int heating_status;
+extern unsigned int status_number;
 extern unsigned int heating_status_counter;
 extern bool custom_message;
 extern unsigned int custom_message_type;
 extern unsigned int custom_message_state;
+extern unsigned long PingTime;
 
 
 // Handling multiple extruders pins
@@ -312,3 +319,13 @@ extern void calculate_volumetric_multipliers();
 // Similar to the default Arduino delay function, 
 // but it keeps the background tasks running.
 extern void delay_keep_alive(int ms);
+
+extern void check_babystep();
+
+#ifdef DIS
+
+void d_setup();
+float d_ReadData();
+void bed_analysis(float x_dimension, float y_dimension, int x_points_num, int y_points_num, float shift_x, float shift_y);
+
+#endif

+ 1066 - 199
Firmware/Marlin_main.cpp

@@ -100,6 +100,7 @@
 // PRUSA CODES
 // P F - Returns FW versions
 // P R - Returns revision of printer
+// P Y - Starts filament allignment process for multicolor
 
 // G0  -> G1
 // G1  - Coordinated Movement X Y Z E
@@ -230,7 +231,7 @@ CardReader card;
 
 unsigned long TimeSent = millis();
 unsigned long TimeNow = millis();
-
+unsigned long PingTime = millis();
 union Data
 {
 byte b[2];
@@ -254,18 +255,26 @@ int extruder_multiply[EXTRUDERS] = {100
 };
 
 bool is_usb_printing = false;
+bool homing_flag = false;
+
+unsigned long kicktime = millis()+100000;
 
 unsigned int  usb_printing_counter;
 
 int lcd_change_fil_state = 0;
 int feedmultiplyBckp = 100;
 unsigned char lang_selected = 0;
+int8_t FarmMode = 0;
+
+bool prusa_sd_card_upload = false;
 
+unsigned int status_number = 0;
 
 unsigned long total_filament_used;
 unsigned int heating_status;
 unsigned int heating_status_counter;
 bool custom_message;
+bool loading_flag = false;
 unsigned int custom_message_type;
 unsigned int custom_message_state;
 
@@ -420,7 +429,7 @@ static bool cmdbuffer_front_already_processed = false;
 // Debugging information will be sent to serial line.
 // #define CMDBUFFER_DEBUG
 
-static int serial_count = 0;
+static int serial_count = 0;  //index of character read from serial line
 static boolean comment_mode = false;
 static char *strchr_pointer; // just a pointer to find chars in the command string like X, Y, Z, E, etc
 
@@ -567,8 +576,8 @@ bool cmdqueue_could_enqueue_front(int len_asked)
         cmdqueue_pop_front();
         cmdbuffer_front_already_processed = true;
     }
-    if (bufindr == bufindw && buflen > 0)
-        // Full buffer.
+	if (bufindr == bufindw && buflen > 0)
+		// Full buffer.
         return false;
     // Adjust the end of the write buffer based on whether a partial line is in the receive buffer.
     int endw = (serial_count > 0) ? (bufindw + MAX_CMD_SIZE + 1) : bufindw;
@@ -606,9 +615,9 @@ bool cmdqueue_could_enqueue_back(int len_asked)
     if (len_asked >= MAX_CMD_SIZE)
         return false;
 
-    if (bufindr == bufindw && buflen > 0)
-        // Full buffer.
-        return false;
+	if (bufindr == bufindw && buflen > 0)
+		// Full buffer.
+		return false;
 
     if (serial_count > 0) {
         // If there is some data stored starting at bufindw, len_asked is certainly smaller than
@@ -794,6 +803,11 @@ void repeatcommand_front()
     cmdbuffer_front_already_processed = true;
 } 
 
+bool is_buffer_empty()
+{
+	if (buflen == 0) return true;
+	else return false;
+}
 
 void setup_killpin()
 {
@@ -870,6 +884,96 @@ static void lcd_language_menu();
    enum MeshLevelingState { MeshReport, MeshStart, MeshNext, MeshSet };
 #endif
 
+
+// Factory reset function
+// This function is used to erase parts or whole EEPROM memory which is used for storing calibration and and so on.
+// Level input parameter sets depth of reset
+// Quiet parameter masks all waitings for user interact.
+int  er_progress = 0;
+void factory_reset(char level, bool quiet)
+{	
+	lcd_implementation_clear();
+	    
+    switch (level) {
+                   
+        // Level 0: Language reset
+        case 0:
+            WRITE(BEEPER, HIGH);
+            _delay_ms(100);
+            WRITE(BEEPER, LOW);
+            
+            lcd_force_language_selection();
+            break;
+         
+		//Level 1: Reset statistics
+		case 1:
+			WRITE(BEEPER, HIGH);
+			_delay_ms(100);
+			WRITE(BEEPER, LOW);
+			eeprom_update_dword((uint32_t *)EEPROM_TOTALTIME, 0);
+			eeprom_update_dword((uint32_t *)EEPROM_FILAMENTUSED, 0);
+			lcd_menu_statistics();
+            
+			break;
+
+        // Level 2: Prepare for shipping
+        case 2:
+			//lcd_printPGM(PSTR("Factory RESET"));
+            //lcd_print_at_PGM(1,2,PSTR("Shipping prep"));
+            
+            // Force language selection at the next boot up.
+            lcd_force_language_selection();
+            // Force the "Follow calibration flow" message at the next boot up.
+            calibration_status_store(CALIBRATION_STATUS_Z_CALIBRATION);
+            farm_no = 0;
+			farm_mode == false;
+			eeprom_update_byte((uint8_t*)EEPROM_FARM_MODE, farm_mode);
+            EEPROM_save_B(EEPROM_FARM_NUMBER, &farm_no);
+                       
+            WRITE(BEEPER, HIGH);
+            _delay_ms(100);
+            WRITE(BEEPER, LOW);
+			//_delay_ms(2000);
+            break;
+
+			// Level 3: erase everything, whole EEPROM will be set to 0xFF
+
+		case 3:
+			lcd_printPGM(PSTR("Factory RESET"));
+			lcd_print_at_PGM(1, 2, PSTR("ERASING all data"));
+
+			WRITE(BEEPER, HIGH);
+			_delay_ms(100);
+			WRITE(BEEPER, LOW);
+
+			er_progress = 0;
+			lcd_print_at_PGM(3, 3, PSTR("      "));
+			lcd_implementation_print_at(3, 3, er_progress);
+
+			// Erase EEPROM
+			for (int i = 0; i < 4096; i++) {
+				eeprom_write_byte((uint8_t*)i, 0xFF);
+
+				if (i % 41 == 0) {
+					er_progress++;
+					lcd_print_at_PGM(3, 3, PSTR("      "));
+					lcd_implementation_print_at(3, 3, er_progress);
+					lcd_printPGM(PSTR("%"));
+				}
+
+			}
+
+
+			break;
+        
+        default:
+            break;
+    }
+    
+
+}
+
+
 // "Setup" function is called by the Arduino framework on startup.
 // Before startup, the Timers-functions (PWM)/Analog RW and HardwareSerial provided by the Arduino-code 
 // are initialized by the main() routine provided by the Arduino framework.
@@ -924,10 +1028,10 @@ void setup()
   SERIAL_ECHO(freeMemory());
   SERIAL_ECHORPGM(MSG_PLANNER_BUFFER_BYTES);
   SERIAL_ECHOLN((int)sizeof(block_t)*BLOCK_BUFFER_SIZE);
-  
+  lcd_update_enable(false);
   // loads data from EEPROM if available else uses defaults (and resets step acceleration rate)
   Config_RetrieveSettings();
-
+  SdFatUtil::set_stack_guard(); //writes magic number at the end of static variables to protect against overwriting static memory by stack
   tp_init();    // Initialize temperature loop
   plan_init();  // Initialize planner;
   watchdog_init();
@@ -937,25 +1041,41 @@ void setup()
   // Reset the machine correction matrix.
   // It does not make sense to load the correction matrix until the machine is homed.
   world2machine_reset();
-
+  
   lcd_init();
   if (!READ(BTN_ENC))
   {
 	  _delay_ms(1000);
 	  if (!READ(BTN_ENC))
 	  {
+          lcd_implementation_clear();
+          
+		  
+		  lcd_printPGM(PSTR("Factory RESET"));
+		  
+          
 		  SET_OUTPUT(BEEPER);
 		  WRITE(BEEPER, HIGH);
+        
+          while (!READ(BTN_ENC));
+          
+          WRITE(BEEPER, LOW);
+          
+          
 
-		  lcd_force_language_selection();
-		  farm_no = 0;
-		  EEPROM_save_B(EEPROM_FARM_MODE, &farm_no);
-		  farm_mode = false;
-
-		  while (!READ(BTN_ENC));
-
-		  WRITE(BEEPER, LOW);
-
+		  _delay_ms(2000);
+          
+		  char level = reset_menu();
+		  factory_reset(level, false);
+          
+		  switch (level) {
+				case 0: _delay_ms(0); break;
+				case 1: _delay_ms(0); break;
+				case 2: _delay_ms(0); break;
+				case 3: _delay_ms(0); break;
+		  }
+		  // _delay_ms(100);
+/*
 #ifdef MESH_BED_LEVELING
 		  _delay_ms(2000);
 
@@ -970,7 +1090,7 @@ void setup()
 			  WRITE(BEEPER, LOW);
 
 			  int _z = 0;
-			  eeprom_write_byte((unsigned char*)EEPROM_BABYSTEP_Z_SET, 0x01);
+			  calibration_status_store(CALIBRATION_STATUS_CALIBRATED);
 			  EEPROM_save_B(EEPROM_BABYSTEP_X, &_z);
 			  EEPROM_save_B(EEPROM_BABYSTEP_Y, &_z);
 			  EEPROM_save_B(EEPROM_BABYSTEP_Z, &_z);
@@ -982,8 +1102,8 @@ void setup()
 			  _delay_ms(100);
 			  WRITE(BEEPER, LOW);
 		  }
-#endif // mesh
-
+#endif // mesh */
+         
 	  }
   }
   else
@@ -1005,19 +1125,13 @@ void setup()
 #if defined(Z_AXIS_ALWAYS_ON)
   enable_z();
 #endif
-
-  EEPROM_read_B(EEPROM_FARM_MODE, &farm_no);
-  if (farm_no > 0)
+  farm_mode = eeprom_read_byte((uint8_t*)EEPROM_FARM_MODE);
+  EEPROM_read_B(EEPROM_FARM_NUMBER, &farm_no);
+  if (farm_mode == 0xFF && farm_no == 0) farm_mode = false; //if farm_mode has not been stored to eeprom yet and farm number is set to zero, deactivate farm mode
+  if (farm_mode)
   {
-	  farm_mode = true;
-	  farm_no = farm_no;
 	  prusa_statistics(8);
   }
-  else
-  {
-	  farm_mode = false;
-	  farm_no = 0;
-  }
 
   // Enable Toshiba FlashAir SD card / WiFi enahanced card.
   card.ToshibaFlashAir_enable(eeprom_read_byte((unsigned char*)EEPROM_TOSHIBA_FLASH_AIR_COMPATIBLITY) == 1);
@@ -1043,24 +1157,108 @@ void setup()
     if (lang_selected >= LANG_NUM){
       lcd_mylang();
     }
-    
-  if (eeprom_read_byte((uint8_t*)EEPROM_BABYSTEP_Z_SET) == 0x0ff) {
+
+	check_babystep(); //checking if Z babystep is in allowed range
+	
+  if (calibration_status() == CALIBRATION_STATUS_ASSEMBLED ||
+      calibration_status() == CALIBRATION_STATUS_UNKNOWN) {
       // Reset the babystepping values, so the printer will not move the Z axis up when the babystepping is enabled.
       eeprom_update_word((uint16_t*)EEPROM_BABYSTEP_Z, 0);
+      // Show the message.
+      lcd_show_fullscreen_message_and_wait_P(MSG_FOLLOW_CALIBRATION_FLOW);
+  } else if (calibration_status() == CALIBRATION_STATUS_LIVE_ADJUST) {
       // Show the message.
       lcd_show_fullscreen_message_and_wait_P(MSG_BABYSTEP_Z_NOT_SET);
-      lcd_update_enable(true);
+  } else if (calibration_status() == CALIBRATION_STATUS_Z_CALIBRATION) {
+      // Show the message.
+      lcd_show_fullscreen_message_and_wait_P(MSG_FOLLOW_CALIBRATION_FLOW);
   }
+  lcd_update_enable(true);
 
   // Store the currently running firmware into an eeprom,
   // so the next time the firmware gets updated, it will know from which version it has been updated.
   update_current_firmware_version_to_eeprom();
 }
 
+void trace();
+
+#define CHUNK_SIZE 64 // bytes
+#define SAFETY_MARGIN 1
+char chunk[CHUNK_SIZE+SAFETY_MARGIN];
+int chunkHead = 0;
+
+int serial_read_stream() {
+
+    setTargetHotend(0, 0);
+    setTargetBed(0);
+
+    lcd_implementation_clear();
+    lcd_printPGM(PSTR(" Upload in progress"));
+
+    // first wait for how many bytes we will receive
+    uint32_t bytesToReceive;
+
+    // receive the four bytes
+    char bytesToReceiveBuffer[4];
+    for (int i=0; i<4; i++) {
+        int data;
+        while ((data = MYSERIAL.read()) == -1) {};
+        bytesToReceiveBuffer[i] = data;
+
+    }
+
+    // make it a uint32
+    memcpy(&bytesToReceive, &bytesToReceiveBuffer, 4);
+
+    // we're ready, notify the sender
+    MYSERIAL.write('+');
+
+    // lock in the routine
+    uint32_t receivedBytes = 0;
+    while (prusa_sd_card_upload) {
+        int i;
+        for (i=0; i<CHUNK_SIZE; i++) {
+            int data;
+
+            // check if we're not done
+            if (receivedBytes == bytesToReceive) {
+                break;
+            }
+
+            // read the next byte
+            while ((data = MYSERIAL.read()) == -1) {};
+            receivedBytes++;
+
+            // save it to the chunk
+            chunk[i] = data;
+        }
+
+        // write the chunk to SD
+        card.write_command_no_newline(&chunk[0]);
+
+        // notify the sender we're ready for more data
+        MYSERIAL.write('+');
+
+        // for safety
+        manage_heater();
+
+        // check if we're done
+        if(receivedBytes == bytesToReceive) {
+            trace(); // beep
+            card.closefile();
+            prusa_sd_card_upload = false;
+            SERIAL_PROTOCOLLNRPGM(MSG_FILE_SAVED);
+            return 0;
+        }
+
+    }
+}
+
 // The loop() function is called in an endless loop by the Arduino framework from the default main() routine.
 // Before loop(), the setup() function is called by the main() routine.
 void loop()
 {
+	bool stack_integrity = true;
 
 	if (usb_printing_counter > 0 && millis()-_usb_timer > 1000)
 	{
@@ -1073,7 +1271,14 @@ void loop()
 		is_usb_printing = false;
 	}
 
-  get_command();
+    if (prusa_sd_card_upload)
+    {
+        //we read byte-by byte
+        serial_read_stream();
+    } else 
+    {
+
+        get_command();
 
   #ifdef SDSUPPORT
   card.checkautostart(false);
@@ -1105,6 +1310,7 @@ void loop()
           cmdqueue_pop_front();
       cmdbuffer_front_already_processed = false;
   }
+}
   //check heater every n milliseconds
   manage_heater();
   manage_inactivity();
@@ -1115,10 +1321,16 @@ void loop()
 void get_command()
 {
     // Test and reserve space for the new command string.
-    if (! cmdqueue_could_enqueue_back(MAX_CMD_SIZE-1))
-        return;
+	if (!cmdqueue_could_enqueue_back(MAX_CMD_SIZE - 1)) 
+		return;
+	
+	bool rx_buffer_full = false; //flag that serial rx buffer is full
 
   while (MYSERIAL.available() > 0) {
+	  if (MYSERIAL.available() == RX_BUFFER_SIZE - 1) { //compare number of chars buffered in rx buffer with rx buffer size
+		  SERIAL_ECHOLNPGM("Full RX Buffer");   //if buffer was full, there is danger that reading of last gcode will not be completed
+		  rx_buffer_full = true;				//sets flag that buffer was full	
+	  }
     char serial_char = MYSERIAL.read();
       TimeSent = millis();
       TimeNow = millis();
@@ -1141,53 +1353,55 @@ void get_command()
       cmdbuffer[bufindw+serial_count+1] = 0; //terminate string
       if(!comment_mode){
         comment_mode = false; //for new command
-        if ((strchr_pointer = strchr(cmdbuffer+bufindw+1, 'N')) != NULL)
-        {
-          // Line number met. When sending a G-code over a serial line, each line may be stamped with its index,
-          // and Marlin tests, whether the successive lines are stamped with an increasing line number ID.
-          gcode_N = (strtol(strchr_pointer+1, NULL, 10));
-          if(gcode_N != gcode_LastN+1 && (strstr_P(cmdbuffer+bufindw+1, PSTR("M110")) == NULL) ) {
-            // M110 - set current line number.
-            // Line numbers not sent in succession.
-            SERIAL_ERROR_START;
-            SERIAL_ERRORRPGM(MSG_ERR_LINE_NO);
-            SERIAL_ERRORLN(gcode_LastN);
-            //Serial.println(gcode_N);
-            FlushSerialRequestResend();
-            serial_count = 0;
-            return;
-          }
+        if ((strchr_pointer = strstr(cmdbuffer+bufindw+1, "PRUSA")) == NULL && (strchr_pointer = strchr(cmdbuffer+bufindw+1, 'N')) != NULL) {
+            if ((strchr_pointer = strchr(cmdbuffer+bufindw+1, 'N')) != NULL)
+            {
+            // Line number met. When sending a G-code over a serial line, each line may be stamped with its index,
+            // and Marlin tests, whether the successive lines are stamped with an increasing line number ID.
+            gcode_N = (strtol(strchr_pointer+1, NULL, 10));
+            if(gcode_N != gcode_LastN+1 && (strstr_P(cmdbuffer+bufindw+1, PSTR("M110")) == NULL) ) {
+                // M110 - set current line number.
+                // Line numbers not sent in succession.
+                SERIAL_ERROR_START;
+                SERIAL_ERRORRPGM(MSG_ERR_LINE_NO);
+                SERIAL_ERRORLN(gcode_LastN);
+                //Serial.println(gcode_N);
+                FlushSerialRequestResend();
+                serial_count = 0;
+                return;
+            }
 
-          if((strchr_pointer = strchr(cmdbuffer+bufindw+1, '*')) != NULL)
-          {
-            byte checksum = 0;
-            char *p = cmdbuffer+bufindw+1;
-            while (p != strchr_pointer)
-                checksum = checksum^(*p++);
-            if (int(strtol(strchr_pointer+1, NULL, 10)) != int(checksum)) {
-              SERIAL_ERROR_START;
-              SERIAL_ERRORRPGM(MSG_ERR_CHECKSUM_MISMATCH);
-              SERIAL_ERRORLN(gcode_LastN);
-              FlushSerialRequestResend();
-              serial_count = 0;
-              return;
+            if((strchr_pointer = strchr(cmdbuffer+bufindw+1, '*')) != NULL)
+            {
+                byte checksum = 0;
+                char *p = cmdbuffer+bufindw+1;
+                while (p != strchr_pointer)
+                    checksum = checksum^(*p++);
+                if (int(strtol(strchr_pointer+1, NULL, 10)) != int(checksum)) {
+                SERIAL_ERROR_START;
+                SERIAL_ERRORRPGM(MSG_ERR_CHECKSUM_MISMATCH);
+                SERIAL_ERRORLN(gcode_LastN);
+                FlushSerialRequestResend();
+                serial_count = 0;
+                return;
+                }
+                // If no errors, remove the checksum and continue parsing.
+                *strchr_pointer = 0;
+            }
+            else
+            {
+                SERIAL_ERROR_START;
+                SERIAL_ERRORRPGM(MSG_ERR_NO_CHECKSUM);
+                SERIAL_ERRORLN(gcode_LastN);
+                FlushSerialRequestResend();
+                serial_count = 0;
+                return;
             }
-            // If no errors, remove the checksum and continue parsing.
-            *strchr_pointer = 0;
-          }
-          else
-          {
-            SERIAL_ERROR_START;
-            SERIAL_ERRORRPGM(MSG_ERR_NO_CHECKSUM);
-            SERIAL_ERRORLN(gcode_LastN);
-            FlushSerialRequestResend();
-            serial_count = 0;
-            return;
-          }
 
-          gcode_LastN = gcode_N;
-          //if no errors, continue parsing
-        } // end of 'N' command
+            gcode_LastN = gcode_N;
+            //if no errors, continue parsing
+            } // end of 'N' command
+        }
         else  // if we don't receive 'N' but still see '*'
         {
           if((strchr(cmdbuffer+bufindw+1, '*') != NULL))
@@ -1266,11 +1480,18 @@ void get_command()
         }
     }
 
+	//add comment
+	if (rx_buffer_full == true && serial_count > 0) {   //if rx buffer was full and string was not properly terminated
+		rx_buffer_full = false;
+		bufindw = bufindw - serial_count;				//adjust tail of the buffer to prepare buffer for writing new command
+		serial_count = 0;
+	}
+
   #ifdef SDSUPPORT
   if(!card.sdprinting || serial_count!=0){
     // If there is a half filled buffer from serial line, wait until return before
     // continuing with the serial line.
-    return;
+     return;
   }
 
   //'#' stops reading from SD to the buffer prematurely, so procedural macro calls are possible
@@ -1347,7 +1568,7 @@ void get_command()
 // Return True if a character was found
 static inline bool    code_seen(char code) { return (strchr_pointer = strchr(CMDBUFFER_CURRENT_STRING, code)) != NULL; }
 static inline bool    code_seen(const char *code) { return (strchr_pointer = strstr(CMDBUFFER_CURRENT_STRING, code)) != NULL; }
-static inline float   code_value()         { return strtod(strchr_pointer+1, NULL); }
+static inline float   code_value()      { return strtod(strchr_pointer+1, NULL);}
 static inline long    code_value_long()    { return strtol(strchr_pointer+1, NULL, 10); }
 static inline int16_t code_value_short()   { return int16_t(strtol(strchr_pointer+1, NULL, 10)); };
 static inline uint8_t code_value_uint8()   { return uint8_t(strtol(strchr_pointer+1, NULL, 10)); };
@@ -1631,6 +1852,96 @@ void refresh_cmd_timeout(void)
   } //retract
 #endif //FWRETRACT
 
+void trace() {
+    tone(BEEPER, 440);
+    delay(25);
+    noTone(BEEPER);
+    delay(20);
+}
+
+void ramming() {
+//	  float tmp[4] = DEFAULT_MAX_FEEDRATE;
+	if (current_temperature[0] < 230) {
+		//PLA
+
+		max_feedrate[E_AXIS] = 50;
+		//current_position[E_AXIS] -= 8;
+		//plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2100 / 60, active_extruder);
+		//current_position[E_AXIS] += 8;
+		//plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2100 / 60, active_extruder);
+		current_position[E_AXIS] += 5.4;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2800 / 60, active_extruder);
+		current_position[E_AXIS] += 3.2;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder);
+		current_position[E_AXIS] += 3;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3400 / 60, active_extruder);
+		st_synchronize();
+		max_feedrate[E_AXIS] = 80;
+		current_position[E_AXIS] -= 82;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 9500 / 60, active_extruder);
+		max_feedrate[E_AXIS] = 50;//tmp[E_AXIS];
+		current_position[E_AXIS] -= 20;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 1200 / 60, active_extruder);
+		current_position[E_AXIS] += 5;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 400 / 60, active_extruder);
+		current_position[E_AXIS] += 5;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600 / 60, active_extruder);
+		current_position[E_AXIS] -= 10;
+		st_synchronize();
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600 / 60, active_extruder);
+		current_position[E_AXIS] += 10;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600 / 60, active_extruder);
+		current_position[E_AXIS] -= 10;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 800 / 60, active_extruder);
+		current_position[E_AXIS] += 10;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 800 / 60, active_extruder);
+		current_position[E_AXIS] -= 10;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 800 / 60, active_extruder);
+		st_synchronize();
+	}
+	else {
+		//ABS
+		max_feedrate[E_AXIS] = 50;
+		//current_position[E_AXIS] -= 8;
+		//plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2100 / 60, active_extruder);
+		//current_position[E_AXIS] += 8;
+		//plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2100 / 60, active_extruder);
+		current_position[E_AXIS] += 3.1;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2000 / 60, active_extruder);
+		current_position[E_AXIS] += 3.1;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2500 / 60, active_extruder);
+		current_position[E_AXIS] += 4;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder);
+		st_synchronize();
+		/*current_position[X_AXIS] += 23; //delay
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600/60, active_extruder); //delay
+		current_position[X_AXIS] -= 23; //delay
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600/60, active_extruder); //delay*/
+		delay(4700);
+		max_feedrate[E_AXIS] = 80;
+		current_position[E_AXIS] -= 92;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 9900 / 60, active_extruder);
+		max_feedrate[E_AXIS] = 50;//tmp[E_AXIS];
+		current_position[E_AXIS] -= 5;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 800 / 60, active_extruder);
+		current_position[E_AXIS] += 5;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 400 / 60, active_extruder);
+		current_position[E_AXIS] -= 5;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600 / 60, active_extruder);
+		st_synchronize();
+		current_position[E_AXIS] += 5;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600 / 60, active_extruder);
+		current_position[E_AXIS] -= 5;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600 / 60, active_extruder);
+		current_position[E_AXIS] += 5;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600 / 60, active_extruder);
+		current_position[E_AXIS] -= 5;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600 / 60, active_extruder);
+		st_synchronize();
+
+	}
+  }
+
 void process_commands()
 {
   #ifdef FILAMENT_RUNOUT_SUPPORT
@@ -1654,8 +1965,49 @@ void process_commands()
 
   // PRUSA GCODES
 
+#ifdef SNMM
+  float tmp_motor[3] = DEFAULT_PWM_MOTOR_CURRENT;
+  float tmp_motor_loud[3] = DEFAULT_PWM_MOTOR_CURRENT_LOUD;
+  int8_t SilentMode;
+#endif
   if(code_seen("PRUSA")){
-    if(code_seen("Fir")){
+		if (code_seen("Ping")) {  //PRUSA Ping
+			if (farm_mode) {
+				PingTime = millis();
+				//MYSERIAL.print(farm_no); MYSERIAL.println(": OK");
+			}	  
+		}
+		else if (code_seen("PRN")) {
+		  MYSERIAL.println(status_number);
+
+		}else if (code_seen("fn")) {
+		  if (farm_mode) {
+			  MYSERIAL.println(farm_no);
+		  }
+		  else {
+			  MYSERIAL.println("Not in farm mode.");
+		  }
+		  
+		}else if (code_seen("fv")) {
+        // get file version
+        #ifdef SDSUPPORT
+        card.openFile(strchr_pointer + 3,true);
+        while (true) {
+            uint16_t readByte = card.get();
+            MYSERIAL.write(readByte);
+            if (readByte=='\n') {
+                break;
+            }
+        }
+        card.closefile();
+
+        #endif // SDSUPPORT
+
+    } else if (code_seen("M28")) {
+        trace();
+        prusa_sd_card_upload = true;
+        card.openFile(strchr_pointer+4,false);
+    } else if(code_seen("Fir")){
 
       SERIAL_PROTOCOLLN(FW_version);
 
@@ -1667,14 +2019,91 @@ void process_commands()
       lcd_force_language_selection();
     } else if(code_seen("Lz")) {
       EEPROM_save_B(EEPROM_BABYSTEP_Z,0);
-    } 
+      
+    } else if (code_seen("SERIAL LOW")) {
+        MYSERIAL.println("SERIAL LOW");
+        MYSERIAL.begin(BAUDRATE);
+        return;
+    } else if (code_seen("SERIAL HIGH")) {
+        MYSERIAL.println("SERIAL HIGH");
+        MYSERIAL.begin(1152000);
+        return;
+    } else if(code_seen("Beat")) {
+        // Kick farm link timer
+        kicktime = millis();
+
+    } else if(code_seen("FR")) {
+        // Factory full reset
+        factory_reset(0,true);
+        
+    }else if(code_seen("Y")) { //filaments adjustment at the beginning of print (for SNMM)
+	#ifdef SNMM
+		int extr;
+		SilentMode = eeprom_read_byte((uint8_t*)EEPROM_SILENT); //is  silent mode or loud mode set
+		lcd_implementation_clear();
+		lcd_display_message_fullscreen_P(MSG_FIL_ADJUSTING);
+		current_position[Z_AXIS] = 100; 
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 500, active_extruder); 
+		digipot_current(2, E_MOTOR_HIGH_CURRENT);
+		for (extr = 1; extr < 4; extr++) { //we dont know which filament is in nozzle, but we want to load filament0, so all other filaments must unloaded 
+			change_extr(extr);
+			ramming();			
+		}
+		change_extr(0);
+		current_position[E_AXIS] += FIL_LOAD_LENGTH; //loading filament0 into the nozzle
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 500, active_extruder);
+		st_synchronize();
+				
+		for (extr = 1; extr < 4; extr++) {	
+			digipot_current(2, E_MOTOR_LOW_CURRENT); //set lower current for extruder motors
+			change_extr(extr);
+			current_position[E_AXIS] += (FIL_LOAD_LENGTH + 3 * FIL_RETURN_LENGTH); //adjusting filaments
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 5000, active_extruder);
+			st_synchronize();
+			digipot_current(2, tmp_motor_loud[2]); //set back to normal operation currents
+			current_position[E_AXIS] -= FIL_RETURN_LENGTH;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 500, active_extruder);
+			st_synchronize();
+		}
+
+		change_extr(0);
+		current_position[E_AXIS] += 25;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 10, active_extruder);
+		digipot_current(2, E_MOTOR_HIGH_CURRENT);
+		ramming();
+		if (SilentMode == 1) digipot_current(2, tmp_motor[2]); //set back to normal operation currents
+		else digipot_current(2, tmp_motor_loud[2]);
+		st_synchronize();
+		lcd_show_fullscreen_message_and_wait_P(MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ);
+		lcd_implementation_clear();
+		lcd_printPGM(MSG_PLEASE_WAIT);
+		current_position[Z_AXIS] = 0;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 500, active_extruder);
+		st_synchronize();
+		lcd_update_enable(true);
+
+	#endif
+	}
+	else if (code_seen("SetF")) {
+#ifdef SNMM
+		bool not_finished = (eeprom_read_byte((unsigned char*)EEPROM_PRINT_FLAG) != PRINT_FINISHED);
+		eeprom_update_byte((unsigned char*)EEPROM_PRINT_FLAG, PRINT_STARTED);
+		if (not_finished) enquecommand_front_P(PSTR("PRUSA Y"));
+#endif
+	}
+	else if (code_seen("ResF")) {
+#ifdef SNMM
+		eeprom_update_byte((unsigned char*)EEPROM_PRINT_FLAG, PRINT_FINISHED);
+#endif
+	}
     //else if (code_seen('Cal')) {
 		//  lcd_calibration();
 	  // }
 
-  }
-  else 
-  if(code_seen('G'))
+  }  
+  else if (code_seen('^')) {
+    // nothing, this is a version line
+  } else if(code_seen('G'))
   {
     switch((int)code_value())
     {
@@ -1857,8 +2286,9 @@ void process_commands()
 
 
         get_coordinates(); // For X Y Z E F
-		total_filament_used = total_filament_used + ((destination[E_AXIS] - current_position[E_AXIS])*100);
-
+		if (total_filament_used > ((current_position[E_AXIS] - destination[E_AXIS]) * 100)) { //protection against total_filament_used overflow
+			total_filament_used = total_filament_used + ((destination[E_AXIS] - current_position[E_AXIS]) * 100);
+		}
           #ifdef FWRETRACT
             if(autoretract_enabled)
             if( !(code_seen('X') || code_seen('Y') || code_seen('Z')) && code_seen('E')) {
@@ -1923,6 +2353,7 @@ void process_commands()
       break;
       #endif //FWRETRACT
     case 28: //G28 Home all Axis one at a time
+		homing_flag = true;
 
 #ifdef ENABLE_AUTO_BED_LEVELING
       plan_bed_level_matrix.set_to_identity();  //Reset the plane ("erase" all leveling data)
@@ -2134,6 +2565,7 @@ void process_commands()
 	else
 		{
 			st_synchronize();
+			homing_flag = false;
 			// Push the commands to the front of the message queue in the reverse order!
 			// There shall be always enough space reserved for these commands.
 			// enquecommand_front_P((PSTR("G80")));
@@ -2143,6 +2575,8 @@ void process_commands()
 
 	  if (farm_mode) { prusa_statistics(20); };
 
+	  homing_flag = false;
+
       break;
 
 #ifdef ENABLE_AUTO_BED_LEVELING
@@ -2342,18 +2776,48 @@ void process_commands()
         }
         break;
 
-    /**
-     * G80: Mesh-based Z probe, probes a grid and produces a
-     *      mesh to compensate for variable bed height
-     *
-     * The S0 report the points as below
-     *
-     *  +----> X-axis
-     *  |
-     *  |
-     *  v Y-axis
-     *
-     */
+#ifdef DIS
+	case 77:
+	{
+		//G77 X200 Y150 XP100 YP15 XO10 Y015
+
+		//for 9 point mesh bed leveling G77 X203 Y196 XP3 YP3 XO0 YO0
+
+
+		//G77 X232 Y218 XP116 YP109 XO-11 YO0 
+
+		float dimension_x = 40;
+		float dimension_y = 40;
+		int points_x = 40;
+		int points_y = 40;
+		float offset_x = 74;
+		float offset_y = 33;
+
+		if (code_seen('X')) dimension_x = code_value();
+		if (code_seen('Y')) dimension_y = code_value();
+		if (code_seen('XP')) points_x = code_value();
+		if (code_seen('YP')) points_y = code_value();
+		if (code_seen('XO')) offset_x = code_value();
+		if (code_seen('YO')) offset_y = code_value();
+		
+		bed_analysis(dimension_x,dimension_y,points_x,points_y,offset_x,offset_y);
+		
+	} break;
+	
+#endif
+
+	/**
+	* G80: Mesh-based Z probe, probes a grid and produces a
+	*      mesh to compensate for variable bed height
+	*
+	* The S0 report the points as below
+	*
+	*  +----> X-axis
+	*  |
+	*  |
+	*  v Y-axis
+	*
+	*/
     case 80:
     case_G80:
         {
@@ -2483,7 +2947,7 @@ void process_commands()
                 if (correction == 0)
                     continue;
                 float offset = float(correction) * 0.001f;
-                if (fabs(offset) > 0.101f) {
+                if (fabs(offset) > 0.101f) {				
                     SERIAL_ERROR_START;
                     SERIAL_ECHOPGM("Excessive bed leveling correction: ");
                     SERIAL_ECHO(offset);
@@ -2617,14 +3081,14 @@ void process_commands()
              * This G-code will be performed at the start of a calibration script.
              */
         case 86:
-            eeprom_write_byte((unsigned char*)EEPROM_BABYSTEP_Z_SET, 0xFF);
+            calibration_status_store(CALIBRATION_STATUS_LIVE_ADJUST);
             break;
             /**
              * G87: Prusa3D specific: Enable babystep correction after home
              * This G-code will be performed at the end of a calibration script.
              */
         case 87:
-            eeprom_write_byte((unsigned char*)EEPROM_BABYSTEP_Z_SET, 0x01);
+            calibration_status_store(CALIBRATION_STATUS_CALIBRATED);
             break;
 
             /**
@@ -2660,16 +3124,17 @@ void process_commands()
       }
       break;
 
-	case 98:
-		farm_no = 21;
-		EEPROM_save_B(EEPROM_FARM_MODE, &farm_no);
-		farm_mode = true;
+	case 98: //activate farm mode
+		farm_mode = 1;
+		PingTime = millis();
+		eeprom_update_byte((unsigned char *)EEPROM_FARM_MODE, farm_mode);
 		break;
 
-	case 99:
-		farm_no = 0;
-		EEPROM_save_B(EEPROM_FARM_MODE, &farm_no);
-		farm_mode = false;
+	case 99: //deactivate farm mode
+		farm_mode = 0;
+		lcd_printer_connected();
+		eeprom_update_byte((unsigned char *)EEPROM_FARM_MODE, farm_mode);
+		lcd_update(2);
 		break;
 
 
@@ -2683,9 +3148,17 @@ void process_commands()
 
   else if(code_seen('M'))
   {
-    switch( (int)code_value() )
+	  int index;
+	  for (index = 1; *(strchr_pointer + index) == ' ' || *(strchr_pointer + index) == '\t'; index++);
+	   
+	 /*for (++strchr_pointer; *strchr_pointer == ' ' || *strchr_pointer == '\t'; ++strchr_pointer);*/
+	  if (*(strchr_pointer+index) < '0' || *(strchr_pointer+index) > '9') {
+		  SERIAL_ECHOLNPGM("Invalid M code");
+	  } else
+    switch((int)code_value())
     {
 #ifdef ULTIPANEL
+
     case 0: // M0 - Unconditional stop - Wait for user button press on LCD
     case 1: // M1 - Conditional stop - Wait for user button press on LCD
     {
@@ -2711,14 +3184,14 @@ void process_commands()
         LCD_MESSAGERPGM(MSG_USERWAIT);
       }
 
-      lcd_ignore_click();
+      lcd_ignore_click();				//call lcd_ignore_click aslo for else ???
       st_synchronize();
       previous_millis_cmd = millis();
       if (codenum > 0){
         codenum += millis();  // keep track of when we started waiting
         while(millis() < codenum && !lcd_clicked()){
           manage_heater();
-          manage_inactivity();
+          manage_inactivity(true);
           lcd_update();
         }
         lcd_ignore_click(false);
@@ -2727,7 +3200,7 @@ void process_commands()
             break;
         while(!lcd_clicked()){
           manage_heater();
-          manage_inactivity();
+          manage_inactivity(true);
           lcd_update();
         }
       }
@@ -2772,7 +3245,7 @@ void process_commands()
     case 24: //M24 - Start SD print
       card.startFileprint();
       starttime=millis();
-      break;
+	  break;
     case 25: //M25 - Pause SD print
       card.pauseSDPrint();
       break;
@@ -2900,6 +3373,11 @@ void process_commands()
      break;
 
     case 44: // M44: Prusa3D: Reset the bed skew and offset calibration.
+
+		// Reset the baby step value and the baby step applied flag.
+		calibration_status_store(CALIBRATION_STATUS_ASSEMBLED);
+		eeprom_update_word((uint16_t*)EEPROM_BABYSTEP_Z, 0);
+
         // Reset the skew and offset in both RAM and EEPROM.
         reset_bed_offset_and_skew();
         // Reset world2machine_rotation_and_skew and world2machine_shift, therefore
@@ -2910,6 +3388,17 @@ void process_commands()
 
     case 45: // M45: Prusa3D: bed skew and offset with manual Z up
     {
+		// Only Z calibration?
+		bool onlyZ = code_seen('Z');
+
+		if (!onlyZ) {
+			setTargetBed(0);
+			setTargetHotend(0, 0);
+			setTargetHotend(0, 1);
+			setTargetHotend(0, 2);
+			adjust_bed_reset(); //reset bed level correction
+		}
+		
         // Disable the default update procedure of the display. We will do a modal dialog.
         lcd_update_enable(false);
         // Let the planner use the uncorrected coordinates.
@@ -2922,12 +3411,17 @@ void process_commands()
         babystep_reset();
         // Mark all axes as in a need for homing.
         memset(axis_known_position, 0, sizeof(axis_known_position));
-        // Only Z calibration?
-        bool onlyZ = code_seen('Z');
-        
+                
         // Let the user move the Z axes up to the end stoppers.
         if (lcd_calibrate_z_end_stop_manual( onlyZ )) {
             refresh_cmd_timeout();
+			if (((degHotend(0) > MAX_HOTEND_TEMP_CALIBRATION) || (degBed() > MAX_BED_TEMP_CALIBRATION)) && (!onlyZ)) {
+				lcd_wait_for_cool_down();
+				lcd_show_fullscreen_message_and_wait_P(MSG_PAPER);
+				lcd_display_message_fullscreen_P(MSG_FIND_BED_OFFSET_AND_SKEW_LINE1);
+				lcd_implementation_print_at(0, 2, 1);
+				lcd_printPGM(MSG_FIND_BED_OFFSET_AND_SKEW_LINE2);
+			}
 
             // Move the print head close to the bed.
             current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
@@ -2955,10 +3449,15 @@ void process_commands()
                 world2machine_update_current();
                 //FIXME
                 bool result = sample_mesh_and_store_reference();
-                // if (result) babystep_apply();
+                if (result) {
+                    if (calibration_status() == CALIBRATION_STATUS_Z_CALIBRATION)
+                        // Shipped, the nozzle height has been set already. The user can start printing now.
+                        calibration_status_store(CALIBRATION_STATUS_CALIBRATED);
+                    // babystep_apply();
+                }
             } else {
                 // Reset the baby step value and the baby step applied flag.
-                eeprom_write_byte((unsigned char*)EEPROM_BABYSTEP_Z_SET, 0xFF);
+                calibration_status_store(CALIBRATION_STATUS_ASSEMBLED);
                 eeprom_update_word((uint16_t*)EEPROM_BABYSTEP_Z, 0);
                 // Complete XYZ calibration.
                 BedSkewOffsetDetectionResultType result = find_bed_offset_and_skew(verbosity_level);
@@ -2985,6 +3484,11 @@ void process_commands()
                     // if (result >= 0) babystep_apply();
                 }
                 lcd_bed_calibration_show_result(result, point_too_far_mask);
+                if (result >= 0) {
+                    // Calibration valid, the machine should be able to print. Advise the user to run the V2Calibration.gcode.
+                    calibration_status_store(CALIBRATION_STATUS_LIVE_ADJUST);
+                    lcd_show_fullscreen_message_and_wait_P(MSG_BABYSTEP_Z_NOT_SET);
+                }
             }
         } else {
             // Timeouted.
@@ -3385,8 +3889,7 @@ Sigma_Exit:
             SERIAL_PROTOCOL_F(rawHotendTemp(cur_extruder)/OVERSAMPLENR,0);
           }
         #endif
-
-        SERIAL_PROTOCOLLN("");
+		SERIAL_PROTOCOLLN("");
       return;
       break;
     case 109:
@@ -3438,22 +3941,24 @@ Sigma_Exit:
       #endif //TEMP_RESIDENCY_TIME
           if( (millis() - codenum) > 1000UL )
           { //Print Temp Reading and remaining time every 1 second while heating up/cooling down
-            SERIAL_PROTOCOLPGM("T:");
-            SERIAL_PROTOCOL_F(degHotend(tmp_extruder),1);
-            SERIAL_PROTOCOLPGM(" E:");
-            SERIAL_PROTOCOL((int)tmp_extruder);
-			
-            #ifdef TEMP_RESIDENCY_TIME
-              SERIAL_PROTOCOLPGM(" W:");
-              if(residencyStart > -1)
-              {
-                 codenum = ((TEMP_RESIDENCY_TIME * 1000UL) - (millis() - residencyStart)) / 1000UL;
-                 SERIAL_PROTOCOLLN( codenum );
-              }
-              else
-              {
-                 SERIAL_PROTOCOLLN( "?" );
-              }
+			  if (!farm_mode) {
+				  SERIAL_PROTOCOLPGM("T:");
+				  SERIAL_PROTOCOL_F(degHotend(tmp_extruder), 1);
+				  SERIAL_PROTOCOLPGM(" E:");
+				  SERIAL_PROTOCOL((int)tmp_extruder);
+
+			#ifdef TEMP_RESIDENCY_TIME
+				  SERIAL_PROTOCOLPGM(" W:");
+				  if (residencyStart > -1)
+				  {
+					  codenum = ((TEMP_RESIDENCY_TIME * 1000UL) - (millis() - residencyStart)) / 1000UL;
+					  SERIAL_PROTOCOLLN(codenum);
+				  }
+				  else
+				  {
+					  SERIAL_PROTOCOLLN("?");
+				  }
+			  }
             #else
               SERIAL_PROTOCOLLN("");
             #endif
@@ -3505,15 +4010,18 @@ Sigma_Exit:
         {
           if(( millis() - codenum) > 1000 ) //Print Temp Reading every 1 second while heating up.
           {
-            float tt=degHotend(active_extruder);
-            SERIAL_PROTOCOLPGM("T:");
-            SERIAL_PROTOCOL(tt);
-            SERIAL_PROTOCOLPGM(" E:");
-            SERIAL_PROTOCOL((int)active_extruder);
-            SERIAL_PROTOCOLPGM(" B:");
-            SERIAL_PROTOCOL_F(degBed(),1);
-            SERIAL_PROTOCOLLN("");
-            codenum = millis();
+			  if (!farm_mode) {
+				  float tt = degHotend(active_extruder);
+				  SERIAL_PROTOCOLPGM("T:");
+				  SERIAL_PROTOCOL(tt);
+				  SERIAL_PROTOCOLPGM(" E:");
+				  SERIAL_PROTOCOL((int)active_extruder);
+				  SERIAL_PROTOCOLPGM(" B:");
+				  SERIAL_PROTOCOL_F(degBed(), 1);
+				  SERIAL_PROTOCOLLN("");
+			  }
+				  codenum = millis();
+			  
           }
           manage_heater();
           manage_inactivity();
@@ -4106,7 +4614,7 @@ Sigma_Exit:
         #endif
 
         updatePID();
-        SERIAL_PROTOCOL(MSG_OK);
+        SERIAL_PROTOCOLRPGM(MSG_OK);
         SERIAL_PROTOCOL(" p:");
         SERIAL_PROTOCOL(Kp);
         SERIAL_PROTOCOL(" i:");
@@ -4130,7 +4638,7 @@ Sigma_Exit:
         if(code_seen('D')) bedKd = scalePID_d(code_value());
 
         updatePID();
-        SERIAL_PROTOCOL(MSG_OK);
+       	SERIAL_PROTOCOLRPGM(MSG_OK);
         SERIAL_PROTOCOL(" p:");
         SERIAL_PROTOCOL(bedKp);
         SERIAL_PROTOCOL(" i:");
@@ -4633,57 +5141,166 @@ case 404:  //M404 Enter the nominal filament width (3mm, 1.75mm ) N<3.0> or disp
       #endif
     }
     break;
+	case 701: //M701: load filament
+	{
+		enable_z();
+		custom_message = true;
+		custom_message_type = 2;
+		
+		lcd_setstatuspgm(MSG_LOADING_FILAMENT);
+		current_position[E_AXIS] += 65;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 400 / 60, active_extruder); //fast sequence
+
+		current_position[E_AXIS] += 40;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 100 / 60, active_extruder); //slow sequence
+		st_synchronize();
+
+		if (!farm_mode && loading_flag) {
+			bool clean = lcd_show_fullscreen_message_yes_no_and_wait_P(MSG_FILAMENT_CLEAN, false, true);
+
+			while (!clean) {
+				lcd_update_enable(true);
+				lcd_update(2);
+				current_position[E_AXIS] += 40;
+				plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 100 / 60, active_extruder); //slow sequence
+				st_synchronize();
+				clean = lcd_show_fullscreen_message_yes_no_and_wait_P(MSG_FILAMENT_CLEAN, false, true);
+			}
+		}
+		lcd_update_enable(true);
+		lcd_update(2);
+		lcd_setstatuspgm(WELCOME_MSG);
+		disable_z();
+		loading_flag = false;
+		custom_message = false;
+		custom_message_type = 0;
+	}
+	break;
+	case 702:
+	{
+		custom_message = true;
+		custom_message_type = 2;
+		lcd_setstatuspgm(MSG_UNLOADING_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], 7000 / 60, active_extruder);
+		st_synchronize();
+		lcd_setstatuspgm(WELCOME_MSG);
+		custom_message = false;
+		custom_message_type = 0;
+		
+	}
+	break;
+
     case 999: // M999: Restart after being stopped
       Stopped = false;
       lcd_reset_alert_level();
       gcode_LastN = Stopped_gcode_LastN;
       FlushSerialRequestResend();
     break;
+	default: SERIAL_ECHOLNPGM("Invalid M code.");
     }
+	
   } // end if(code_seen('M')) (end of M codes)
 
   else if(code_seen('T'))
   {
-    tmp_extruder = code_value();
-    if(tmp_extruder >= EXTRUDERS) {
-      SERIAL_ECHO_START;
-      SERIAL_ECHO("T");
-      SERIAL_ECHO(tmp_extruder);
-      SERIAL_ECHOLN(MSG_INVALID_EXTRUDER);
-    }
-    else {
-      boolean make_move = false;
-      if(code_seen('F')) {
-        make_move = true;
-        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_ECHO(MSG_ACTIVE_EXTRUDER);
-      SERIAL_PROTOCOLLN((int)active_extruder);
-    }
+	  int index;
+	  for (index = 1; *(strchr_pointer + index) == ' ' || *(strchr_pointer + index) == '\t'; index++);
+	   
+	  if (*(strchr_pointer + index) < '0' || *(strchr_pointer + index) > '9') {
+		  SERIAL_ECHOLNPGM("Invalid T code.");
+	  }
+	  else {
+		  tmp_extruder = code_value();
+#ifdef SNMM
+
+		  st_synchronize();
+		  delay(100);
+
+		  disable_e0();
+		  disable_e1();
+		  disable_e2();
+
+		  pinMode(E_MUX0_PIN, OUTPUT);
+		  pinMode(E_MUX1_PIN, OUTPUT);
+		  pinMode(E_MUX2_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);
+			  WRITE(E_MUX2_PIN, LOW);
+
+			  break;
+		  case 2:
+			  WRITE(E_MUX0_PIN, LOW);
+			  WRITE(E_MUX1_PIN, HIGH);
+			  WRITE(E_MUX2_PIN, LOW);
+
+			  break;
+		  case 3:
+			  WRITE(E_MUX0_PIN, HIGH);
+			  WRITE(E_MUX1_PIN, HIGH);
+			  WRITE(E_MUX2_PIN, LOW);
+
+			  break;
+		  default:
+			  WRITE(E_MUX0_PIN, LOW);
+			  WRITE(E_MUX1_PIN, LOW);
+			  WRITE(E_MUX2_PIN, LOW);
+
+			  break;
+		  }
+		  delay(100);
+
+#else
+		  if (tmp_extruder >= EXTRUDERS) {
+			  SERIAL_ECHO_START;
+			  SERIAL_ECHOPGM("T");
+			  SERIAL_PROTOCOLLN((int)tmp_extruder);
+			  SERIAL_ECHOLNRPGM(MSG_INVALID_EXTRUDER);
+		  }
+		  else {
+			  boolean make_move = false;
+			  if (code_seen('F')) {
+				  make_move = true;
+				  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(MSG_ACTIVE_EXTRUDER);
+			  SERIAL_PROTOCOLLN((int)active_extruder);
+		  }
+
+#endif
+	  }
   } // end if(code_seen('T')) (end of T codes)
 
   else
@@ -5143,7 +5760,7 @@ bool setTargetedHotend(int code){
       SERIAL_ECHO_START;
       switch(code){
         case 104:
-          SERIAL_ECHO(MSG_M104_INVALID_EXTRUDER);
+          SERIAL_ECHORPGM(MSG_M104_INVALID_EXTRUDER);
           break;
         case 105:
           SERIAL_ECHO(MSG_M105_INVALID_EXTRUDER);
@@ -5158,14 +5775,14 @@ bool setTargetedHotend(int code){
           SERIAL_ECHO(MSG_M221_INVALID_EXTRUDER);
           break;
       }
-      SERIAL_ECHOLN(tmp_extruder);
+      SERIAL_PROTOCOLLN((int)tmp_extruder);
       return true;
     }
   }
   return false;
 }
 
-void save_statistics(unsigned long _total_filament_used, unsigned long _total_print_time)
+void save_statistics(unsigned long _total_filament_used, unsigned long _total_print_time) //_total_filament_used unit: mm/100; print time in s
 {
 	if (eeprom_read_byte((uint8_t *)EEPROM_TOTALTIME) == 255 && eeprom_read_byte((uint8_t *)EEPROM_TOTALTIME + 1) == 255 && eeprom_read_byte((uint8_t *)EEPROM_TOTALTIME + 2) == 255 && eeprom_read_byte((uint8_t *)EEPROM_TOTALTIME + 3) == 255)
 	{
@@ -5173,10 +5790,10 @@ void save_statistics(unsigned long _total_filament_used, unsigned long _total_pr
 		eeprom_update_dword((uint32_t *)EEPROM_FILAMENTUSED, 0);
 	}
 
-	unsigned long _previous_filament = eeprom_read_dword((uint32_t *)EEPROM_FILAMENTUSED);
-	unsigned long _previous_time = eeprom_read_dword((uint32_t *)EEPROM_TOTALTIME);
+	unsigned long _previous_filament = eeprom_read_dword((uint32_t *)EEPROM_FILAMENTUSED); //_previous_filament unit: cm
+	unsigned long _previous_time = eeprom_read_dword((uint32_t *)EEPROM_TOTALTIME); //_previous_time unit: min
 
-	eeprom_update_dword((uint32_t *)EEPROM_TOTALTIME, _previous_time + (_total_print_time/60));
+	eeprom_update_dword((uint32_t *)EEPROM_TOTALTIME, _previous_time + (_total_print_time/60)); //EEPROM_TOTALTIME unit: min
 	eeprom_update_dword((uint32_t *)EEPROM_FILAMENTUSED, _previous_filament + (_total_filament_used / 1000));
 
 	total_filament_used = 0;
@@ -5226,3 +5843,253 @@ void delay_keep_alive(int ms)
         }
     }
 }
+
+void check_babystep() {
+	int babystep_z;
+	EEPROM_read_B(EEPROM_BABYSTEP_Z, &babystep_z);
+	if ((babystep_z < Z_BABYSTEP_MIN) || (babystep_z > Z_BABYSTEP_MAX)) {
+		babystep_z = 0; //if babystep value is out of min max range, set it to 0
+		SERIAL_ECHOLNPGM("Z live adjust out of range. Setting to 0");
+		EEPROM_save_B(EEPROM_BABYSTEP_Z, &babystep_z);
+		lcd_show_fullscreen_message_and_wait_P(PSTR("Z live adjust out of range. Setting to 0. Click to continue."));
+		lcd_update_enable(true);		
+	}	
+}
+#ifdef DIS
+void d_setup()
+{	
+	pinMode(D_DATACLOCK, INPUT_PULLUP);
+	pinMode(D_DATA, INPUT_PULLUP);
+	pinMode(D_REQUIRE, OUTPUT);
+	digitalWrite(D_REQUIRE, HIGH);
+}
+
+
+float d_ReadData()
+{
+	int digit[13];
+	String mergeOutput;
+	float output;
+
+	digitalWrite(D_REQUIRE, HIGH);
+	for (int i = 0; i<13; i++)
+	{
+		for (int j = 0; j < 4; j++)
+		{
+			while (digitalRead(D_DATACLOCK) == LOW) {}
+			while (digitalRead(D_DATACLOCK) == HIGH) {}
+			bitWrite(digit[i], j, digitalRead(D_DATA));
+		}
+	}
+
+	digitalWrite(D_REQUIRE, LOW);
+	mergeOutput = "";
+	output = 0;
+	for (int r = 5; r <= 10; r++) //Merge digits
+	{
+		mergeOutput += digit[r];
+	}
+	output = mergeOutput.toFloat();
+
+	if (digit[4] == 8) //Handle sign
+	{
+		output *= -1;
+	}
+
+	for (int i = digit[11]; i > 0; i--) //Handle floating point
+	{
+		output /= 10;
+	}
+
+	return output;
+
+}
+
+void bed_analysis(float x_dimension, float y_dimension, int x_points_num, int y_points_num, float shift_x, float shift_y) {
+	int t1 = 0;
+	int t_delay = 0;
+	int digit[13];
+	int m;
+	char str[3];
+	//String mergeOutput;
+	char mergeOutput[15];
+	float output;
+
+	int mesh_point = 0; //index number of calibration point
+	float bed_zero_ref_x = (-22.f + X_PROBE_OFFSET_FROM_EXTRUDER); //shift between zero point on bed and target and between probe and nozzle
+	float bed_zero_ref_y = (-0.6f + Y_PROBE_OFFSET_FROM_EXTRUDER);
+
+	float mesh_home_z_search = 4;
+	float row[x_points_num];
+	int ix = 0;
+	int iy = 0;
+
+	char* filename_wldsd = "wldsd.txt";
+	char data_wldsd[70];
+	char numb_wldsd[10];
+
+	d_setup();
+
+	if (!(axis_known_position[X_AXIS] && axis_known_position[Y_AXIS] && axis_known_position[Z_AXIS])) {
+		// We don't know where we are! HOME!
+		// Push the commands to the front of the message queue in the reverse order!
+		// There shall be always enough space reserved for these commands.
+		repeatcommand_front(); // repeat G80 with all its parameters
+		
+		enquecommand_front_P((PSTR("G28 W0")));
+		enquecommand_front_P((PSTR("G1 Z5")));
+		return;
+	}
+	bool custom_message_old = custom_message;
+	unsigned int custom_message_type_old = custom_message_type;
+	unsigned int custom_message_state_old = custom_message_state;
+	custom_message = true;
+	custom_message_type = 1;
+	custom_message_state = (x_points_num * y_points_num) + 10;
+	lcd_update(1);
+
+	mbl.reset();
+	babystep_undo();
+
+	card.openFile(filename_wldsd, false);
+
+	current_position[Z_AXIS] = mesh_home_z_search;
+	plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], homing_feedrate[Z_AXIS] / 60, active_extruder);
+
+	int XY_AXIS_FEEDRATE = homing_feedrate[X_AXIS] / 20;
+	int Z_PROBE_FEEDRATE = homing_feedrate[Z_AXIS] / 60;
+	int Z_LIFT_FEEDRATE = homing_feedrate[Z_AXIS] / 40;
+
+	setup_for_endstop_move(false);
+
+	SERIAL_PROTOCOLPGM("Num X,Y: ");
+	SERIAL_PROTOCOL(x_points_num);
+	SERIAL_PROTOCOLPGM(",");
+	SERIAL_PROTOCOL(y_points_num);
+	SERIAL_PROTOCOLPGM("\nZ search height: ");
+	SERIAL_PROTOCOL(mesh_home_z_search);
+	SERIAL_PROTOCOLPGM("\nDimension X,Y: ");
+	SERIAL_PROTOCOL(x_dimension);
+	SERIAL_PROTOCOLPGM(",");
+	SERIAL_PROTOCOL(y_dimension);
+	SERIAL_PROTOCOLLNPGM("\nMeasured points:");
+
+	while (mesh_point != x_points_num * y_points_num) {
+		ix = mesh_point % x_points_num; // from 0 to MESH_NUM_X_POINTS - 1
+		iy = mesh_point / x_points_num;
+		if (iy & 1) ix = (x_points_num - 1) - ix; // Zig zag
+		float z0 = 0.f;
+		current_position[Z_AXIS] = mesh_home_z_search;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], Z_LIFT_FEEDRATE, active_extruder);
+		st_synchronize();
+
+
+		current_position[X_AXIS] = 13.f + ix * (x_dimension / (x_points_num - 1)) - bed_zero_ref_x + shift_x;
+		current_position[Y_AXIS] = 6.4f + iy * (y_dimension / (y_points_num - 1)) - bed_zero_ref_y + shift_y;
+
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], XY_AXIS_FEEDRATE, active_extruder);
+		st_synchronize();
+
+		if (!find_bed_induction_sensor_point_z(-10.f)) { //if we have data from z calibration max allowed difference is 1mm for each point, if we dont have data max difference is 10mm from initial point  
+			break;
+			card.closefile();
+		}
+
+
+		//memset(numb_wldsd, 0, sizeof(numb_wldsd));
+		//dtostrf(d_ReadData(), 8, 5, numb_wldsd);
+		//strcat(data_wldsd, numb_wldsd);
+
+
+		
+		//MYSERIAL.println(data_wldsd);
+		//delay(1000);
+		//delay(3000);
+		//t1 = millis();
+		
+		//while (digitalRead(D_DATACLOCK) == LOW) {}
+		//while (digitalRead(D_DATACLOCK) == HIGH) {}
+		memset(digit, 0, sizeof(digit));
+		//cli();
+		digitalWrite(D_REQUIRE, LOW);	
+		
+		for (int i = 0; i<13; i++)
+		{
+			//t1 = millis();
+			for (int j = 0; j < 4; j++)
+			{
+				while (digitalRead(D_DATACLOCK) == LOW) {}				
+				while (digitalRead(D_DATACLOCK) == HIGH) {}
+				bitWrite(digit[i], j, digitalRead(D_DATA));
+			}
+			//t_delay = (millis() - t1);
+			//SERIAL_PROTOCOLPGM(" ");
+			//SERIAL_PROTOCOL_F(t_delay, 5);
+			//SERIAL_PROTOCOLPGM(" ");
+		}
+		//sei();
+		digitalWrite(D_REQUIRE, HIGH);
+		mergeOutput[0] = '\0';
+		output = 0;
+		for (int r = 5; r <= 10; r++) //Merge digits
+		{			
+			sprintf(str, "%d", digit[r]);
+			strcat(mergeOutput, str);
+		}
+		
+		output = atof(mergeOutput);
+
+		if (digit[4] == 8) //Handle sign
+		{
+			output *= -1;
+		}
+
+		for (int i = digit[11]; i > 0; i--) //Handle floating point
+		{
+			output *= 0.1;
+		}
+		
+
+		//output = d_ReadData();
+
+		//row[ix] = current_position[Z_AXIS];
+
+		memset(data_wldsd, 0, sizeof(data_wldsd));
+
+		for (int i = 0; i <3; i++) {
+			memset(numb_wldsd, 0, sizeof(numb_wldsd));
+			dtostrf(current_position[i], 8, 5, numb_wldsd);
+			strcat(data_wldsd, numb_wldsd);
+			strcat(data_wldsd, ";");
+
+		}
+		memset(numb_wldsd, 0, sizeof(numb_wldsd));
+		dtostrf(output, 8, 5, numb_wldsd);
+		strcat(data_wldsd, numb_wldsd);
+		//strcat(data_wldsd, ";");
+		card.write_command(data_wldsd);
+
+		
+		//row[ix] = d_ReadData();
+		
+		row[ix] = output; // current_position[Z_AXIS];
+
+		if (iy % 2 == 1 ? ix == 0 : ix == x_points_num - 1) {
+			for (int i = 0; i < x_points_num; i++) {
+				SERIAL_PROTOCOLPGM(" ");
+				SERIAL_PROTOCOL_F(row[i], 5);
+
+
+			}
+			SERIAL_PROTOCOLPGM("\n");
+		}
+		custom_message_state--;
+		mesh_point++;
+		lcd_update(1);
+
+	}
+	card.closefile();
+
+}
+
+#endif

+ 28 - 0
Firmware/SdFatUtil.cpp

@@ -44,6 +44,34 @@ int SdFatUtil::FreeRam() {
 }
 #endif  // __arm
 
+void SdFatUtil::set_stack_guard()
+{	
+	char i = 0;
+	uint32_t *stack_guard;
+
+	stack_guard = (uint32_t*)&__bss_end;
+	//for (i = 0; i < 10; i++) {
+		*stack_guard = STACK_GUARD_TEST_VALUE;
+	//}
+}
+
+bool SdFatUtil::test_stack_integrity()
+{
+	uint32_t* stack_guard = (uint32_t*)&__bss_end;
+	return (*stack_guard == STACK_GUARD_TEST_VALUE);
+}
+
+uint32_t SdFatUtil::get_stack_guard_test_value()
+{
+	//static char i = 0;
+	uint32_t* stack_guard;
+	uint32_t output;
+	stack_guard = (uint32_t*)&__bss_end;
+	//output = *(stack_guard + i);
+	//i++;
+	output = *stack_guard;
+	return(output);
+}
 //------------------------------------------------------------------------------
 /** %Print a string in flash memory.
  *

+ 3 - 0
Firmware/SdFatUtil.h

@@ -39,6 +39,9 @@ namespace SdFatUtil {
   void println_P( PGM_P str);
   void SerialPrint_P(PGM_P str);
   void SerialPrintln_P(PGM_P str);
+  void set_stack_guard();
+  bool test_stack_integrity();
+  uint32_t get_stack_guard_test_value();
 }
 
 using namespace SdFatUtil;  // NOLINT

+ 14 - 1
Firmware/cardreader.cpp

@@ -81,7 +81,7 @@ void CardReader::lsDive(const char *prepend, SdFile parent, const char * const m
         if(lsAction==LS_SerialPrint)
         {
           SERIAL_ECHO_START;
-          SERIAL_ECHOLN(MSG_SD_CANT_OPEN_SUBDIR);
+          SERIAL_ECHORPGM(MSG_SD_CANT_ENTER_SUBDIR);
           SERIAL_ECHOLN(lfilename);
         }
       }
@@ -501,6 +501,19 @@ void CardReader::write_command(char *buf)
   }
 }
 
+#define CHUNK_SIZE 64
+
+void CardReader::write_command_no_newline(char *buf)
+{
+  file.write(buf, CHUNK_SIZE);
+  if (file.writeError)
+  {
+    SERIAL_ERROR_START;
+    SERIAL_ERRORLNRPGM(MSG_SD_ERR_WRITE_TO_FILE);
+    MYSERIAL.println("An error while writing to the SD Card.");
+  }
+}
+
 
 void CardReader::checkautostart(bool force)
 {

+ 1 - 0
Firmware/cardreader.h

@@ -14,6 +14,7 @@ public:
   
   void initsd();
   void write_command(char *buf);
+  void write_command_no_newline(char *buf);
   //files auto[0-9].g on the sd card are performed in a row
   //this is to delay autostart and hence the initialisaiton of the sd card to some seconds after the normal init, so the device is available quick after a reset
 

+ 1 - 1
Firmware/langtool.pl

@@ -4,7 +4,7 @@
 use strict;
 use warnings;
 
-my @langs = ("en","cz","it","es","pl");
+my @langs = ("en","cz","it","es","pl","de");
 
 sub parselang 
 {

+ 852 - 207
Firmware/language_all.cpp

@@ -10,17 +10,19 @@ const char * const MSG_ACTIVE_EXTRUDER_LANG_TABLE[1] PROGMEM = {
 	MSG_ACTIVE_EXTRUDER_EN
 };
 
-const char MSG_ADJUSTZ_EN[] PROGMEM = "Auto adjust Z ?";
+const char MSG_ADJUSTZ_EN[] PROGMEM = "Auto adjust Z?";
 const char MSG_ADJUSTZ_CZ[] PROGMEM = "Auto doladit Z ?";
 const char MSG_ADJUSTZ_IT[] PROGMEM = "Autoregolare Z?";
-const char MSG_ADJUSTZ_ES[] PROGMEM = "Auto Micropaso Z?";
+const char MSG_ADJUSTZ_ES[] PROGMEM = "Ajustar Eje Z";
 const char MSG_ADJUSTZ_PL[] PROGMEM = "Autodostroic Z?";
+const char MSG_ADJUSTZ_DE[] PROGMEM = "Auto Z einstellen?";
 const char * const MSG_ADJUSTZ_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_ADJUSTZ_EN,
 	MSG_ADJUSTZ_CZ,
 	MSG_ADJUSTZ_IT,
 	MSG_ADJUSTZ_ES,
-	MSG_ADJUSTZ_PL
+	MSG_ADJUSTZ_PL,
+	MSG_ADJUSTZ_DE
 };
 
 const char MSG_AMAX_EN[] PROGMEM = "Amax ";
@@ -36,12 +38,14 @@ const char * const MSG_AUTHOR_LANG_TABLE[1] PROGMEM = {
 const char MSG_AUTO_HOME_EN[] PROGMEM = "Auto home";
 const char MSG_AUTO_HOME_IT[] PROGMEM = "Trova origine";
 const char MSG_AUTO_HOME_ES[] PROGMEM = "Llevar al origen";
+const char MSG_AUTO_HOME_DE[] PROGMEM = "Startposition";
 const char * const MSG_AUTO_HOME_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_AUTO_HOME_EN,
 	MSG_AUTO_HOME_EN,
 	MSG_AUTO_HOME_IT,
 	MSG_AUTO_HOME_ES,
-	MSG_AUTO_HOME_EN
+	MSG_AUTO_HOME_EN,
+	MSG_AUTO_HOME_DE
 };
 
 const char MSG_A_RETRACT_EN[] PROGMEM = "A-retract";
@@ -77,27 +81,31 @@ const char * const MSG_BABYSTEP_Y_LANG_TABLE[1] PROGMEM = {
 const char MSG_BABYSTEP_Z_EN[] PROGMEM = "Live adjust Z";
 const char MSG_BABYSTEP_Z_CZ[] PROGMEM = "Doladeni osy Z";
 const char MSG_BABYSTEP_Z_IT[] PROGMEM = "Compensazione Z";
-const char MSG_BABYSTEP_Z_ES[] PROGMEM = "Micropaso Z";
+const char MSG_BABYSTEP_Z_ES[] PROGMEM = "Micropaso Eje Z";
 const char MSG_BABYSTEP_Z_PL[] PROGMEM = "Dostrojenie osy Z";
+const char MSG_BABYSTEP_Z_DE[] PROGMEM = "Z einstellen";
 const char * const MSG_BABYSTEP_Z_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BABYSTEP_Z_EN,
 	MSG_BABYSTEP_Z_CZ,
 	MSG_BABYSTEP_Z_IT,
 	MSG_BABYSTEP_Z_ES,
-	MSG_BABYSTEP_Z_PL
+	MSG_BABYSTEP_Z_PL,
+	MSG_BABYSTEP_Z_DE
 };
 
-const char MSG_BABYSTEP_Z_NOT_SET_EN[] PROGMEM = "Printer has not been calibrated yet. Please follow the manual, chapter First steps, section Calibration flow.";
-const char MSG_BABYSTEP_Z_NOT_SET_CZ[] PROGMEM = "Tiskarna nebyla jeste zkalibrovana. Postupujte prosim podle manualu, kapitola Zaciname, odstavec Postup kalibrace.";
-const char MSG_BABYSTEP_Z_NOT_SET_IT[] PROGMEM = "Stampante ancora non calibrata. Si prega di seguire il manuale, capitolo PRIMI PASSI, sezione della calibrazione.";
-const char MSG_BABYSTEP_Z_NOT_SET_ES[] PROGMEM = "Impresora no esta calibrada todavia. Por favor usar el manual, el capitulo First steps, seleccion Calibration flow.";
-const char MSG_BABYSTEP_Z_NOT_SET_PL[] PROGMEM = "Drukarka nie zostala jeszcze skalibrowana. Prosze kierowac sie instrukcja, rozdzial Zaczynamy, podrozdzial Selftest.";
+const char MSG_BABYSTEP_Z_NOT_SET_EN[] PROGMEM = "Distance between tip of the nozzle and the bed surface has not been set yet. Please follow the manual, chapter First steps, section First layer calibration.";
+const char MSG_BABYSTEP_Z_NOT_SET_CZ[] PROGMEM = "Neni zkalibrovana vzdalenost trysky od tiskove podlozky. Postupujte prosim podle manualu, kapitola Zaciname, odstavec Nastaveni prvni vrstvy.";
+const char MSG_BABYSTEP_Z_NOT_SET_IT[] PROGMEM = "Distanza tra la punta dell'ugello e la superficie del letto non ancora imposta. Si prega di seguire il manuale, capitolo First steps, sezione First layer calibration.";
+const char MSG_BABYSTEP_Z_NOT_SET_ES[] PROGMEM = "Distancia entre la punta de la boquilla y la superficie de la cama no fijada aun. Por favor siga el manual, capitulo First steps, seccion First layer calibration.";
+const char MSG_BABYSTEP_Z_NOT_SET_PL[] PROGMEM = "Odleglosc dyszy od podkladki nie jest skalibrowana. Postepuj zgodnie z instrukcja rozdzial Zaczynamy, podrozdzial Kalibracja pierwszej warstwy.";
+const char MSG_BABYSTEP_Z_NOT_SET_DE[] PROGMEM = "Der Abstand zwischen der Spitze der Duese und der Bed ist noch nicht eingestellt. Bitte folgen Sie dem Handbuch, First steps, section First layer calibration.";
 const char * const MSG_BABYSTEP_Z_NOT_SET_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BABYSTEP_Z_NOT_SET_EN,
 	MSG_BABYSTEP_Z_NOT_SET_CZ,
 	MSG_BABYSTEP_Z_NOT_SET_IT,
 	MSG_BABYSTEP_Z_NOT_SET_ES,
-	MSG_BABYSTEP_Z_NOT_SET_PL
+	MSG_BABYSTEP_Z_NOT_SET_PL,
+	MSG_BABYSTEP_Z_NOT_SET_DE
 };
 
 const char MSG_BED_EN[] PROGMEM = "Bed";
@@ -109,33 +117,38 @@ const char * const MSG_BED_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_EN,
 	MSG_BED_IT,
 	MSG_BED_ES,
-	MSG_BED_PL
+	MSG_BED_PL,
+	MSG_BED_EN
 };
 
 const char MSG_BED_CORRECTION_FRONT_EN[] PROGMEM = "Front side um";
 const char MSG_BED_CORRECTION_FRONT_CZ[] PROGMEM = "Vpredu [um]";
-const char MSG_BED_CORRECTION_FRONT_IT[] PROGMEM = "Lato ateriore um";
+const char MSG_BED_CORRECTION_FRONT_IT[] PROGMEM = "Lato ateriore";
 const char MSG_BED_CORRECTION_FRONT_ES[] PROGMEM = "Adelante  [um]";
 const char MSG_BED_CORRECTION_FRONT_PL[] PROGMEM = "Do przodu [um]";
+const char MSG_BED_CORRECTION_FRONT_DE[] PROGMEM = "Vorderseite [um]";
 const char * const MSG_BED_CORRECTION_FRONT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_CORRECTION_FRONT_EN,
 	MSG_BED_CORRECTION_FRONT_CZ,
 	MSG_BED_CORRECTION_FRONT_IT,
 	MSG_BED_CORRECTION_FRONT_ES,
-	MSG_BED_CORRECTION_FRONT_PL
+	MSG_BED_CORRECTION_FRONT_PL,
+	MSG_BED_CORRECTION_FRONT_DE
 };
 
 const char MSG_BED_CORRECTION_LEFT_EN[] PROGMEM = "Left side  um";
 const char MSG_BED_CORRECTION_LEFT_CZ[] PROGMEM = "Vlevo  [um]";
-const char MSG_BED_CORRECTION_LEFT_IT[] PROGMEM = "Lato sinistro um";
+const char MSG_BED_CORRECTION_LEFT_IT[] PROGMEM = "Lato sinistro";
 const char MSG_BED_CORRECTION_LEFT_ES[] PROGMEM = "Izquierda [um]";
 const char MSG_BED_CORRECTION_LEFT_PL[] PROGMEM = "W lewo  [um]";
+const char MSG_BED_CORRECTION_LEFT_DE[] PROGMEM = "Linke Seite  [um]";
 const char * const MSG_BED_CORRECTION_LEFT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_CORRECTION_LEFT_EN,
 	MSG_BED_CORRECTION_LEFT_CZ,
 	MSG_BED_CORRECTION_LEFT_IT,
 	MSG_BED_CORRECTION_LEFT_ES,
-	MSG_BED_CORRECTION_LEFT_PL
+	MSG_BED_CORRECTION_LEFT_PL,
+	MSG_BED_CORRECTION_LEFT_DE
 };
 
 const char MSG_BED_CORRECTION_MENU_EN[] PROGMEM = "Bed level correct";
@@ -143,12 +156,14 @@ const char MSG_BED_CORRECTION_MENU_CZ[] PROGMEM = "Korekce podlozky";
 const char MSG_BED_CORRECTION_MENU_IT[] PROGMEM = "Correz. liv.letto";
 const char MSG_BED_CORRECTION_MENU_ES[] PROGMEM = "Corr. de la cama";
 const char MSG_BED_CORRECTION_MENU_PL[] PROGMEM = "Korekta podkladki";
+const char MSG_BED_CORRECTION_MENU_DE[] PROGMEM = "Bed level Korrekt";
 const char * const MSG_BED_CORRECTION_MENU_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_CORRECTION_MENU_EN,
 	MSG_BED_CORRECTION_MENU_CZ,
 	MSG_BED_CORRECTION_MENU_IT,
 	MSG_BED_CORRECTION_MENU_ES,
-	MSG_BED_CORRECTION_MENU_PL
+	MSG_BED_CORRECTION_MENU_PL,
+	MSG_BED_CORRECTION_MENU_DE
 };
 
 const char MSG_BED_CORRECTION_REAR_EN[] PROGMEM = "Rear side  um";
@@ -156,12 +171,14 @@ const char MSG_BED_CORRECTION_REAR_CZ[] PROGMEM = "Vzadu  [um]";
 const char MSG_BED_CORRECTION_REAR_IT[] PROGMEM = "Lato posteriore";
 const char MSG_BED_CORRECTION_REAR_ES[] PROGMEM = "Atras     [um]";
 const char MSG_BED_CORRECTION_REAR_PL[] PROGMEM = "Do tylu  [um]";
+const char MSG_BED_CORRECTION_REAR_DE[] PROGMEM = "Rueckseite  [um]";
 const char * const MSG_BED_CORRECTION_REAR_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_CORRECTION_REAR_EN,
 	MSG_BED_CORRECTION_REAR_CZ,
 	MSG_BED_CORRECTION_REAR_IT,
 	MSG_BED_CORRECTION_REAR_ES,
-	MSG_BED_CORRECTION_REAR_PL
+	MSG_BED_CORRECTION_REAR_PL,
+	MSG_BED_CORRECTION_REAR_DE
 };
 
 const char MSG_BED_CORRECTION_RESET_EN[] PROGMEM = "Reset";
@@ -171,41 +188,47 @@ const char * const MSG_BED_CORRECTION_RESET_LANG_TABLE[1] PROGMEM = {
 
 const char MSG_BED_CORRECTION_RIGHT_EN[] PROGMEM = "Right side um";
 const char MSG_BED_CORRECTION_RIGHT_CZ[] PROGMEM = "Vpravo [um]";
-const char MSG_BED_CORRECTION_RIGHT_IT[] PROGMEM = "Lato destro um";
+const char MSG_BED_CORRECTION_RIGHT_IT[] PROGMEM = "Lato destro";
 const char MSG_BED_CORRECTION_RIGHT_ES[] PROGMEM = "Derecha   [um]";
 const char MSG_BED_CORRECTION_RIGHT_PL[] PROGMEM = "W prawo [um]";
+const char MSG_BED_CORRECTION_RIGHT_DE[] PROGMEM = "Rechte Seite [um]";
 const char * const MSG_BED_CORRECTION_RIGHT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_CORRECTION_RIGHT_EN,
 	MSG_BED_CORRECTION_RIGHT_CZ,
 	MSG_BED_CORRECTION_RIGHT_IT,
 	MSG_BED_CORRECTION_RIGHT_ES,
-	MSG_BED_CORRECTION_RIGHT_PL
+	MSG_BED_CORRECTION_RIGHT_PL,
+	MSG_BED_CORRECTION_RIGHT_DE
 };
 
 const char MSG_BED_DONE_EN[] PROGMEM = "Bed done";
 const char MSG_BED_DONE_CZ[] PROGMEM = "Bed OK.";
 const char MSG_BED_DONE_IT[] PROGMEM = "Piatto fatto.";
-const char MSG_BED_DONE_ES[] PROGMEM = "Base listo.";
+const char MSG_BED_DONE_ES[] PROGMEM = "Base preparada";
 const char MSG_BED_DONE_PL[] PROGMEM = "Stolik OK.";
+const char MSG_BED_DONE_DE[] PROGMEM = "Bed OK";
 const char * const MSG_BED_DONE_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_DONE_EN,
 	MSG_BED_DONE_CZ,
 	MSG_BED_DONE_IT,
 	MSG_BED_DONE_ES,
-	MSG_BED_DONE_PL
+	MSG_BED_DONE_PL,
+	MSG_BED_DONE_DE
 };
 
 const char MSG_BED_HEATING_EN[] PROGMEM = "Bed Heating";
 const char MSG_BED_HEATING_CZ[] PROGMEM = "Zahrivani bed";
-const char MSG_BED_HEATING_IT[] PROGMEM = "Piatto riscaldam.";
-const char MSG_BED_HEATING_ES[] PROGMEM = "Base Calentando";
+const char MSG_BED_HEATING_IT[] PROGMEM = "Riscald. letto";
+const char MSG_BED_HEATING_ES[] PROGMEM = "Calentando Base";
 const char MSG_BED_HEATING_PL[] PROGMEM = "Grzanie stolika..";
+const char MSG_BED_HEATING_DE[] PROGMEM = "Bed erwaermen";
 const char * const MSG_BED_HEATING_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_HEATING_EN,
 	MSG_BED_HEATING_CZ,
 	MSG_BED_HEATING_IT,
 	MSG_BED_HEATING_ES,
-	MSG_BED_HEATING_PL
+	MSG_BED_HEATING_PL,
+	MSG_BED_HEATING_DE
 };
 
 const char MSG_BED_LEVELING_FAILED_POINT_HIGH_EN[] PROGMEM = "Bed leveling failed. Sensor triggered too high. Waiting for reset.";
@@ -213,12 +236,14 @@ const char MSG_BED_LEVELING_FAILED_POINT_HIGH_CZ[] PROGMEM = "Kalibrace Z selhal
 const char MSG_BED_LEVELING_FAILED_POINT_HIGH_IT[] PROGMEM = "Livellamento letto fallito.Risp sensore troppo prestoIn attesa di reset.";
 const char MSG_BED_LEVELING_FAILED_POINT_HIGH_ES[] PROGMEM = "Nivelacion fallada. Sensor funciona demasiado temprano. Esperando reset.";
 const char MSG_BED_LEVELING_FAILED_POINT_HIGH_PL[] PROGMEM = "Kalibracja Z nieudana. Sensor dotk. za wysoko. Czekam na reset.";
+const char MSG_BED_LEVELING_FAILED_POINT_HIGH_DE[] PROGMEM = "Z-Kalibrierung fehlgeschlg. Sensor zu hoch ausgeloest. Warte auf Reset.";
 const char * const MSG_BED_LEVELING_FAILED_POINT_HIGH_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_LEVELING_FAILED_POINT_HIGH_EN,
 	MSG_BED_LEVELING_FAILED_POINT_HIGH_CZ,
 	MSG_BED_LEVELING_FAILED_POINT_HIGH_IT,
 	MSG_BED_LEVELING_FAILED_POINT_HIGH_ES,
-	MSG_BED_LEVELING_FAILED_POINT_HIGH_PL
+	MSG_BED_LEVELING_FAILED_POINT_HIGH_PL,
+	MSG_BED_LEVELING_FAILED_POINT_HIGH_DE
 };
 
 const char MSG_BED_LEVELING_FAILED_POINT_LOW_EN[] PROGMEM = "Bed leveling failed. Sensor didnt trigger. Debris on nozzle? Waiting for reset.";
@@ -226,12 +251,14 @@ const char MSG_BED_LEVELING_FAILED_POINT_LOW_CZ[] PROGMEM = "Kalibrace Z selhala
 const char MSG_BED_LEVELING_FAILED_POINT_LOW_IT[] PROGMEM = "Livellamento letto fallito.NoRispSensor Residui su ugello? In attesa di reset.";
 const char MSG_BED_LEVELING_FAILED_POINT_LOW_ES[] PROGMEM = "Nivelacion fallada. Sensor no funciona. Escombros en Boqui.? Esperando reset.";
 const char MSG_BED_LEVELING_FAILED_POINT_LOW_PL[] PROGMEM = "Kalibracja nieudana. Sensor nie dotknal. Zanieczysz. dysza? Czekam na reset.";
+const char MSG_BED_LEVELING_FAILED_POINT_LOW_DE[] PROGMEM = "Z-Kal. fehlgeschlg. Sensor nicht ausgeloest. Schmutze Duese? Warte auf RST";
 const char * const MSG_BED_LEVELING_FAILED_POINT_LOW_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_LEVELING_FAILED_POINT_LOW_EN,
 	MSG_BED_LEVELING_FAILED_POINT_LOW_CZ,
 	MSG_BED_LEVELING_FAILED_POINT_LOW_IT,
 	MSG_BED_LEVELING_FAILED_POINT_LOW_ES,
-	MSG_BED_LEVELING_FAILED_POINT_LOW_PL
+	MSG_BED_LEVELING_FAILED_POINT_LOW_PL,
+	MSG_BED_LEVELING_FAILED_POINT_LOW_DE
 };
 
 const char MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED_EN[] PROGMEM = "Bed leveling failed. Sensor disconnected or cable broken. Waiting for reset.";
@@ -239,12 +266,14 @@ const char MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED_CZ[] PROGMEM = "Kalibrace
 const char MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED_IT[] PROGMEM = "Livellamento letto fallito. Sensore discon. o Cavo Dann. In attesa di reset.";
 const char MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED_ES[] PROGMEM = "Nivelacion fallada. Sensor desconectado o cables danados. Esperando reset.";
 const char MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED_PL[] PROGMEM = "Kalibracja nieudana. Sensor odlaczony lub uszkodz. kabel. Czekam na reset.";
+const char MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED_DE[] PROGMEM = "Z-Kalibrierung fehlgeschlg. Sensor nicht angeschlossen. Warte auf Reset.";
 const char * const MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED_EN,
 	MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED_CZ,
 	MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED_IT,
 	MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED_ES,
-	MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED_PL
+	MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED_PL,
+	MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED_DE
 };
 
 const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_EN[] PROGMEM = "XYZ calibration failed. Front calibration points not reachable.";
@@ -252,12 +281,14 @@ const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_CZ[] PROGMEM = "K
 const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_IT[] PROGMEM = "Calibrazione XYZ fallita. Punti anteriori non raggiungibili.";
 const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_ES[] PROGMEM = "Calibracion XYZ fallad. Punto delanteros no alcanzables.";
 const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_PL[] PROGMEM = "Kalibr. XYZ nieudana. Przed. punkty kalibr. zbyt do przodu. Wyrownac drukarke.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_DE[] PROGMEM = "XYZ-Kalibrierung fehlgeschlagen. Vordere Kalibrierpunkte sind zu weit nach vorne.";
 const char * const MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_EN,
 	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_CZ,
 	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_IT,
 	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_ES,
-	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_PL
+	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_PL,
+	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR_DE
 };
 
 const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_EN[] PROGMEM = "XYZ calibration failed. Left front calibration point not reachable.";
@@ -265,12 +296,14 @@ const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_CZ[] PROGMEM = "K
 const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_IT[] PROGMEM = "Calibrazione XYZ fallita. Punto anteriore sinistro non raggiungibile.";
 const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_ES[] PROGMEM = "Calibracion XYZ fallad. Punto delantero izquierdo no alcanzable.";
 const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_PL[] PROGMEM = "Kalibr. XYZ nieudana. Lewy przedni punkt zbyt do przodu. Wyrownac drukarke.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_DE[] PROGMEM = "XYZ-Kalibrierung fehlgeschlagen. Linker vorderer Kalibrierpunkt ist zu weit nach vorne.";
 const char * const MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_EN,
 	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_CZ,
 	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_IT,
 	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_ES,
-	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_PL
+	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_PL,
+	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR_DE
 };
 
 const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_EN[] PROGMEM = "XYZ calibration failed. Right front calibration point not reachable.";
@@ -278,12 +311,14 @@ const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_CZ[] PROGMEM = "
 const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_IT[] PROGMEM = "Calibrazione XYZ fallita. Punto anteriore destro non raggiungibile.";
 const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_ES[] PROGMEM = "Calibracion XYZ fallad. Punto delantero derecho no alcanzable.";
 const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_PL[] PROGMEM = "Kalibr. XYZ nieudana. Prawy przedni punkt zbyt do przodu. Wyrownac drukarke.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_DE[] PROGMEM = "XYZ-Kalibrierung fehlgeschlagen. Rechter vorderer Kalibrierpunkt ist zu weit nach vorne.";
 const char * const MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_EN,
 	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_CZ,
 	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_IT,
 	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_ES,
-	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_PL
+	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_PL,
+	MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR_DE
 };
 
 const char MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED_EN[] PROGMEM = "XYZ calibration failed. Please consult the manual.";
@@ -291,25 +326,29 @@ const char MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED_CZ[] PROGMEM = "Kalibrac
 const char MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED_IT[] PROGMEM = "Calibrazione XYZ fallita. Si prega di consultare il manuale.";
 const char MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED_ES[] PROGMEM = "Calibracion XYZ fallada. Consultar el manual por favor.";
 const char MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED_PL[] PROGMEM = "Kalibracja XYZ niepowiedziona. Sprawdzic w instrukcji.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED_DE[] PROGMEM = "XYZ-Kalibrierung fehlgeschlagen. Bitte schauen Sie in das Handbuch.";
 const char * const MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED_EN,
 	MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED_CZ,
 	MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED_IT,
 	MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED_ES,
-	MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED_PL
+	MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED_PL,
+	MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED_DE
 };
 
-const char MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_EN[] PROGMEM = "XYZ calibration ok. X/Y axes are perpendicular.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_CZ[] PROGMEM = "Kalibrace XYZ v poradku. X/Y osy jsou kolme.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_IT[] PROGMEM = "Calibrazione XYZ OK. Gli assi X/Y sono perpendicolari.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_ES[] PROGMEM = "Calibracion XYZ ok. Ejes X/Y perpendiculares.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_PL[] PROGMEM = "Kalibracja XYZ ok. Osie X/Y sa prostopadle.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_EN[] PROGMEM = "XYZ calibration ok. X/Y axes are perpendicular. Congratulations!";
+const char MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_CZ[] PROGMEM = "Kalibrace XYZ v poradku. X/Y osy jsou kolme. Gratuluji!";
+const char MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_IT[] PROGMEM = "Calibrazione XYZ OK. Gli assi X/Y sono perpendicolari. Complimenti!";
+const char MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_ES[] PROGMEM = "Calibracion XYZ ok. Ejes X/Y perpendiculares. Felicitaciones!";
+const char MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_PL[] PROGMEM = "Kalibracja XYZ ok. Osie X/Y sa prostopadle. Gratulacje!";
+const char MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_DE[] PROGMEM = "XYZ-Kalibrierung ok. X/Y-Achsen sind im Lot. Glueckwunsch!";
 const char * const MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_EN,
 	MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_CZ,
 	MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_IT,
 	MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_ES,
-	MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_PL
+	MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_PL,
+	MSG_BED_SKEW_OFFSET_DETECTION_PERFECT_DE
 };
 
 const char MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND_EN[] PROGMEM = "XYZ calibration failed. Bed calibration point was not found.";
@@ -317,38 +356,44 @@ const char MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND_CZ[] PROGMEM = "Kalibra
 const char MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND_IT[] PROGMEM = "Calibrazione XYZ fallita. Il punto di calibrazione sul letto non e' stato trovato.";
 const char MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND_ES[] PROGMEM = "Calibracion XYZ fallada. Puntos de calibracion en la cama no encontrados.";
 const char MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND_PL[] PROGMEM = "Kalibr. XYZ nieudana. Kalibracyjny punkt podkladki nieznaleziony.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND_DE[] PROGMEM = "XYZ-Kalibrierung fehlgeschlagen. Bed-Kalibrierpunkt nicht gefunden.";
 const char * const MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND_EN,
 	MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND_CZ,
 	MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND_IT,
 	MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND_ES,
-	MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND_PL
+	MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND_PL,
+	MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND_DE
 };
 
-const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_EN[] PROGMEM = "X/Y skewed severly. Skew will be corrected automatically.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_CZ[] PROGMEM = "X/Y osy jsou silne zkosene. Zkoseni bude automaticky vyrovnano pri tisku.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_IT[] PROGMEM = "X/Y fortemente distorto. La distorsione verra' corretta automaticamente.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_ES[] PROGMEM = "X/Y muy distorsionado. La distorsion sera corregida automaticamente.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_PL[] PROGMEM = "Osie X/Y sa mocno skosne. Skos bedzie aut. wyrownany przy druku.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_EN[] PROGMEM = "XYZ calibration all right. Skew will be corrected automatically.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_CZ[] PROGMEM = "Kalibrace XYZ v poradku. Zkoseni bude automaticky vyrovnano pri tisku.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_IT[] PROGMEM = "Calibrazion XYZ corretta. La distorsione verra' automaticamente compensata.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_ES[] PROGMEM = "Calibracion XYZ correcta. La inclinacion se corregira automaticamente.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_PL[] PROGMEM = "Kalibracja XYZ prawidlowa. Skosy beda automatycznie wyrownane przy druku.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_DE[] PROGMEM = "XYZ Kalibrierung in Ordnung. Schiefheit wird automatisch korrigiert.";
 const char * const MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_EN,
 	MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_CZ,
 	MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_IT,
 	MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_ES,
-	MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_PL
+	MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_PL,
+	MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME_DE
 };
 
-const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_EN[] PROGMEM = "XYZ calibration all right. X/Y axes are slightly skewed.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_CZ[] PROGMEM = "Kalibrace XYZ v poradku. X/Y osy mirne zkosene.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_IT[] PROGMEM = "Calibrazione XYZ compiuta. Gli assi X/Y sono leggermente distorti.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_ES[] PROGMEM = "Calibracion XYZ conseguida. Ejes X/Y un poco torcidos.";
-const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_PL[] PROGMEM = "Kalibracja XYZ w porzadku. Osie X/Y lekko skosne.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_EN[] PROGMEM = "XYZ calibration all right. X/Y axes are slightly skewed. Good job!";
+const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_CZ[] PROGMEM = "Kalibrace XYZ v poradku. X/Y osy mirne zkosene. Dobra prace!";
+const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_IT[] PROGMEM = "Calibrazion XYZ corretta. Assi X/Y leggermente storti. Ben fatto!";
+const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_ES[] PROGMEM = "Calibracion XYZ correcta. Los ejes X / Y estan ligeramente inclinados. Buen trabajo!";
+const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_PL[] PROGMEM = "Kalibracja XYZ prawidlowa. Osie X/Y lekko skosne. Dobra robota!";
+const char MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_DE[] PROGMEM = "XYZ Kalibrierung in Ordnung. X/Y Achsen sind etwas schief.";
 const char * const MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_EN,
 	MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_CZ,
 	MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_IT,
 	MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_ES,
-	MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_PL
+	MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_PL,
+	MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD_DE
 };
 
 const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_EN[] PROGMEM = "XYZ calibration compromised. Front calibration points not reachable.";
@@ -356,12 +401,14 @@ const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_CZ[] PROGMEM = "
 const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_IT[] PROGMEM = "Calibrazione XYZ compromessa. Punti anteriori non raggiungibili.";
 const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_ES[] PROGMEM = "Calibrazion XYZ comprometida. Punto delanteros no alcanzables.";
 const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_PL[] PROGMEM = "Kalibr. XYZ niedokladna. Przednie punkty kalibr. Zbyt wys. do przodu.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_DE[] PROGMEM = "XYZ-Kalibrierung ungenau. Vordere Kalibrierpunkte sind zu weit nach vorne.";
 const char * const MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_EN,
 	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_CZ,
 	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_IT,
 	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_ES,
-	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_PL
+	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_PL,
+	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR_DE
 };
 
 const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_EN[] PROGMEM = "XYZ calibration compromised. Left front calibration point not reachable.";
@@ -369,12 +416,14 @@ const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_CZ[] PROGMEM = "
 const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_IT[] PROGMEM = "Calibrazione XYZ compromessa. Punto anteriore sinistro non raggiungibile.";
 const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_ES[] PROGMEM = "Calibrazion XYZ comprometida. Punto delantero izquierdo no alcanzable.";
 const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_PL[] PROGMEM = "Kalibracja XYZ niedokladna. Lewy przedni punkt zbyt wysuniety do przodu.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_DE[] PROGMEM = "XYZ-Kalibrierung ungenau. Linker vorderer Kalibrierpunkt ist zu weit nach vorne.";
 const char * const MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_EN,
 	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_CZ,
 	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_IT,
 	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_ES,
-	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_PL
+	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_PL,
+	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR_DE
 };
 
 const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_EN[] PROGMEM = "XYZ calibration compromised. Right front calibration point not reachable.";
@@ -382,12 +431,14 @@ const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_CZ[] PROGMEM =
 const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_IT[] PROGMEM = "Calibrazione XYZ compromessa. Punto anteriore destro non raggiungibile.";
 const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_ES[] PROGMEM = "Calibrazion XYZ comprometida. Punto delantero derecho no alcanzable.";
 const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_PL[] PROGMEM = "Kalibracja XYZ niedokladna. Prawy przedni punkt zbyt wysuniety do przodu.";
+const char MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_DE[] PROGMEM = "XYZ-Kalibrierung ungenau. Rechter vorderer Kalibrierpunkt ist zu weit nach vorne.";
 const char * const MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_EN,
 	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_CZ,
 	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_IT,
 	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_ES,
-	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_PL
+	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_PL,
+	MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR_DE
 };
 
 const char MSG_BEGIN_FILE_LIST_EN[] PROGMEM = "Begin file list";
@@ -405,62 +456,117 @@ const char MSG_CALIBRATE_BED_CZ[] PROGMEM = "Kalibrace XYZ";
 const char MSG_CALIBRATE_BED_IT[] PROGMEM = "Calibra XYZ";
 const char MSG_CALIBRATE_BED_ES[] PROGMEM = "Calibra XYZ";
 const char MSG_CALIBRATE_BED_PL[] PROGMEM = "Kalibracja XYZ";
+const char MSG_CALIBRATE_BED_DE[] PROGMEM = "Kalibrierung XYZ";
 const char * const MSG_CALIBRATE_BED_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_CALIBRATE_BED_EN,
 	MSG_CALIBRATE_BED_CZ,
 	MSG_CALIBRATE_BED_IT,
 	MSG_CALIBRATE_BED_ES,
-	MSG_CALIBRATE_BED_PL
+	MSG_CALIBRATE_BED_PL,
+	MSG_CALIBRATE_BED_DE
 };
 
 const char MSG_CALIBRATE_BED_RESET_EN[] PROGMEM = "Reset XYZ calibr.";
 const char MSG_CALIBRATE_BED_RESET_CZ[] PROGMEM = "Reset XYZ kalibr.";
 const char MSG_CALIBRATE_BED_RESET_PL[] PROGMEM = "Reset kalibr. XYZ";
+const char MSG_CALIBRATE_BED_RESET_DE[] PROGMEM = "Reset XYZ Kalibr.";
 const char * const MSG_CALIBRATE_BED_RESET_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_CALIBRATE_BED_RESET_EN,
 	MSG_CALIBRATE_BED_RESET_CZ,
 	MSG_CALIBRATE_BED_RESET_EN,
 	MSG_CALIBRATE_BED_RESET_EN,
-	MSG_CALIBRATE_BED_RESET_PL
+	MSG_CALIBRATE_BED_RESET_PL,
+	MSG_CALIBRATE_BED_RESET_DE
+};
+
+const char MSG_CALIBRATE_E_EN[] PROGMEM = "Calibrate E";
+const char MSG_CALIBRATE_E_CZ[] PROGMEM = "Kalibrovat E";
+const char MSG_CALIBRATE_E_IT[] PROGMEM = "Calibra E";
+const char MSG_CALIBRATE_E_ES[] PROGMEM = "Calibrar E";
+const char MSG_CALIBRATE_E_PL[] PROGMEM = "Kalibruj E";
+const char MSG_CALIBRATE_E_DE[] PROGMEM = "Kalibriere E";
+const char * const MSG_CALIBRATE_E_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_CALIBRATE_E_EN,
+	MSG_CALIBRATE_E_CZ,
+	MSG_CALIBRATE_E_IT,
+	MSG_CALIBRATE_E_ES,
+	MSG_CALIBRATE_E_PL,
+	MSG_CALIBRATE_E_DE
 };
 
 const char MSG_CARD_MENU_EN[] PROGMEM = "Print from SD";
 const char MSG_CARD_MENU_CZ[] PROGMEM = "Tisk z SD";
 const char MSG_CARD_MENU_IT[] PROGMEM = "Stampa da SD";
-const char MSG_CARD_MENU_ES[] PROGMEM = "Menu de SD";
+const char MSG_CARD_MENU_ES[] PROGMEM = "Menu tarjeta SD";
 const char MSG_CARD_MENU_PL[] PROGMEM = "Druk z SD";
+const char MSG_CARD_MENU_DE[] PROGMEM = "Drucken von SD";
 const char * const MSG_CARD_MENU_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_CARD_MENU_EN,
 	MSG_CARD_MENU_CZ,
 	MSG_CARD_MENU_IT,
 	MSG_CARD_MENU_ES,
-	MSG_CARD_MENU_PL
+	MSG_CARD_MENU_PL,
+	MSG_CARD_MENU_DE
+};
+
+const char MSG_CHANGE_EXTR_EN[] PROGMEM = "Change extruder";
+const char MSG_CHANGE_EXTR_CZ[] PROGMEM = "Zmenit extruder";
+const char MSG_CHANGE_EXTR_IT[] PROGMEM = "Cambio estrusore.";
+const char MSG_CHANGE_EXTR_ES[] PROGMEM = "Cambiar extrusor.";
+const char MSG_CHANGE_EXTR_PL[] PROGMEM = "Zmienic ekstruder";
+const char MSG_CHANGE_EXTR_DE[] PROGMEM = "Wechsel extruder";
+const char * const MSG_CHANGE_EXTR_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_CHANGE_EXTR_EN,
+	MSG_CHANGE_EXTR_CZ,
+	MSG_CHANGE_EXTR_IT,
+	MSG_CHANGE_EXTR_ES,
+	MSG_CHANGE_EXTR_PL,
+	MSG_CHANGE_EXTR_DE
 };
 
 const char MSG_CHANGE_SUCCESS_EN[] PROGMEM = "Change success!";
 const char MSG_CHANGE_SUCCESS_CZ[] PROGMEM = "Zmena uspesna!";
-const char MSG_CHANGE_SUCCESS_IT[] PROGMEM = "Cambia. riuscito!";
-const char MSG_CHANGE_SUCCESS_ES[] PROGMEM = "Cambiar bien!";
+const char MSG_CHANGE_SUCCESS_IT[] PROGMEM = "Cambio riuscito!";
+const char MSG_CHANGE_SUCCESS_ES[] PROGMEM = "Cambio correcto";
 const char MSG_CHANGE_SUCCESS_PL[] PROGMEM = "Wymiana ok!";
+const char MSG_CHANGE_SUCCESS_DE[] PROGMEM = "Wechsel erfolgr.!";
 const char * const MSG_CHANGE_SUCCESS_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_CHANGE_SUCCESS_EN,
 	MSG_CHANGE_SUCCESS_CZ,
 	MSG_CHANGE_SUCCESS_IT,
 	MSG_CHANGE_SUCCESS_ES,
-	MSG_CHANGE_SUCCESS_PL
+	MSG_CHANGE_SUCCESS_PL,
+	MSG_CHANGE_SUCCESS_DE
 };
 
 const char MSG_CHANGING_FILAMENT_EN[] PROGMEM = "Changing filament!";
 const char MSG_CHANGING_FILAMENT_CZ[] PROGMEM = "Vymena filamentu!";
-const char MSG_CHANGING_FILAMENT_IT[] PROGMEM = "Mutevole fil.!";
-const char MSG_CHANGING_FILAMENT_ES[] PROGMEM = "Cambiando fil.!";
+const char MSG_CHANGING_FILAMENT_IT[] PROGMEM = "Cambiando filam.";
+const char MSG_CHANGING_FILAMENT_ES[] PROGMEM = "Cambiando filamento";
 const char MSG_CHANGING_FILAMENT_PL[] PROGMEM = "Wymiana filamentu";
+const char MSG_CHANGING_FILAMENT_DE[] PROGMEM = "Wechsel filament!";
 const char * const MSG_CHANGING_FILAMENT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_CHANGING_FILAMENT_EN,
 	MSG_CHANGING_FILAMENT_CZ,
 	MSG_CHANGING_FILAMENT_IT,
 	MSG_CHANGING_FILAMENT_ES,
-	MSG_CHANGING_FILAMENT_PL
+	MSG_CHANGING_FILAMENT_PL,
+	MSG_CHANGING_FILAMENT_DE
+};
+
+const char MSG_CLEAN_NOZZLE_E_EN[] PROGMEM = "E calibration finished. Please clean the nozzle. Click when done.";
+const char MSG_CLEAN_NOZZLE_E_CZ[] PROGMEM = "E kalibrace ukoncena. Prosim ocistete trysku. Po te potvrdte tlacitkem.";
+const char MSG_CLEAN_NOZZLE_E_IT[] PROGMEM = "Calibrazione E terminata. Si prega di pulire l'ugello. Click per continuare.";
+const char MSG_CLEAN_NOZZLE_E_ES[] PROGMEM = "E calibrado. Limpiar la boquilla. Haga clic una vez terminado.";
+const char MSG_CLEAN_NOZZLE_E_PL[] PROGMEM = "Kalibracja E skonczona. Prosze oczyscic dysze. Potem potwierdzic przyciskiem. ";
+const char MSG_CLEAN_NOZZLE_E_DE[] PROGMEM = "E-Kalibrierung beendet. Bitte reinigen Sie die Duese. Klicken wenn fertig.";
+const char * const MSG_CLEAN_NOZZLE_E_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_CLEAN_NOZZLE_E_EN,
+	MSG_CLEAN_NOZZLE_E_CZ,
+	MSG_CLEAN_NOZZLE_E_IT,
+	MSG_CLEAN_NOZZLE_E_ES,
+	MSG_CLEAN_NOZZLE_E_PL,
+	MSG_CLEAN_NOZZLE_E_DE
 };
 
 const char MSG_CNG_SDCARD_EN[] PROGMEM = "Change SD card";
@@ -478,12 +584,14 @@ const char MSG_CONFIRM_CARRIAGE_AT_THE_TOP_CZ[] PROGMEM = "Dojely oba Z voziky k
 const char MSG_CONFIRM_CARRIAGE_AT_THE_TOP_IT[] PROGMEM = "I carrelli Z sin/des sono altezza max?";
 const char MSG_CONFIRM_CARRIAGE_AT_THE_TOP_ES[] PROGMEM = "Carros Z izq./der. estan arriba maximo?";
 const char MSG_CONFIRM_CARRIAGE_AT_THE_TOP_PL[] PROGMEM = "Oba wozki dojechaly do gornej ramy?";
+const char MSG_CONFIRM_CARRIAGE_AT_THE_TOP_DE[] PROGMEM = "Sind Z-Schlitten ganz oben?";
 const char * const MSG_CONFIRM_CARRIAGE_AT_THE_TOP_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_CONFIRM_CARRIAGE_AT_THE_TOP_EN,
 	MSG_CONFIRM_CARRIAGE_AT_THE_TOP_CZ,
 	MSG_CONFIRM_CARRIAGE_AT_THE_TOP_IT,
 	MSG_CONFIRM_CARRIAGE_AT_THE_TOP_ES,
-	MSG_CONFIRM_CARRIAGE_AT_THE_TOP_PL
+	MSG_CONFIRM_CARRIAGE_AT_THE_TOP_PL,
+	MSG_CONFIRM_CARRIAGE_AT_THE_TOP_DE
 };
 
 const char MSG_CONFIRM_NOZZLE_CLEAN_EN[] PROGMEM = "Please clean the nozzle for calibration. Click when done.";
@@ -491,12 +599,29 @@ const char MSG_CONFIRM_NOZZLE_CLEAN_CZ[] PROGMEM = "Pro uspesnou kalibraci ocist
 const char MSG_CONFIRM_NOZZLE_CLEAN_IT[] PROGMEM = "Pulire l'ugello per la calibrazione, poi fare click.";
 const char MSG_CONFIRM_NOZZLE_CLEAN_ES[] PROGMEM = "Limpiar boquilla para calibracion. Click cuando acabes.";
 const char MSG_CONFIRM_NOZZLE_CLEAN_PL[] PROGMEM = "Dla prawidl. kalibracji prosze oczyscic dysze. Potw. guzikiem.";
+const char MSG_CONFIRM_NOZZLE_CLEAN_DE[] PROGMEM = "Bitte reinigen Sie die D\x81se zur Kalibrierung. Klicken wenn fertig.";
 const char * const MSG_CONFIRM_NOZZLE_CLEAN_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_CONFIRM_NOZZLE_CLEAN_EN,
 	MSG_CONFIRM_NOZZLE_CLEAN_CZ,
 	MSG_CONFIRM_NOZZLE_CLEAN_IT,
 	MSG_CONFIRM_NOZZLE_CLEAN_ES,
-	MSG_CONFIRM_NOZZLE_CLEAN_PL
+	MSG_CONFIRM_NOZZLE_CLEAN_PL,
+	MSG_CONFIRM_NOZZLE_CLEAN_DE
+};
+
+const char MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_EN[] PROGMEM = "Filaments are now adjusted. Please clean the nozzle for calibration. Click when done.";
+const char MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_CZ[] PROGMEM = "Filamenty jsou srovnany. Pro uspesnou kalibraci prosim ocistete trysku. Po te potvrdte tlacitkem.";
+const char MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_IT[] PROGMEM = "I filamenti sono regolati. Si prega di pulire l'ugello per la calibrazione. Click per continuare.";
+const char MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_ES[] PROGMEM = "Filamentos ajustados. Limpie la boquilla para calibracion. Haga clic una vez terminado.";
+const char MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_PL[] PROGMEM = "Dla prawidlowej kalibracji prosze oczyscic dysze. Potem potwierdzic przyciskiem.";
+const char MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_DE[] PROGMEM = "Filaments sind jetzt eingestellt. Bitte reinigen Sie die Duese zur Kalibrierung. Klicken wenn fertig.";
+const char * const MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_EN,
+	MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_CZ,
+	MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_IT,
+	MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_ES,
+	MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_PL,
+	MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_DE
 };
 
 const char MSG_CONTROL_EN[] PROGMEM = "Control";
@@ -509,25 +634,29 @@ const char MSG_COOLDOWN_CZ[] PROGMEM = "Zchladit";
 const char MSG_COOLDOWN_IT[] PROGMEM = "Raffredda";
 const char MSG_COOLDOWN_ES[] PROGMEM = "Enfriar";
 const char MSG_COOLDOWN_PL[] PROGMEM = "Wychlodzic";
+const char MSG_COOLDOWN_DE[] PROGMEM = "Abkuehlen";
 const char * const MSG_COOLDOWN_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_COOLDOWN_EN,
 	MSG_COOLDOWN_CZ,
 	MSG_COOLDOWN_IT,
 	MSG_COOLDOWN_ES,
-	MSG_COOLDOWN_PL
+	MSG_COOLDOWN_PL,
+	MSG_COOLDOWN_DE
 };
 
 const char MSG_CORRECTLY_EN[] PROGMEM = "Changed correctly?";
 const char MSG_CORRECTLY_CZ[] PROGMEM = "Vymena ok?";
 const char MSG_CORRECTLY_IT[] PROGMEM = "Cambiato corr.?";
-const char MSG_CORRECTLY_ES[] PROGMEM = "Cambiado correc.?";
+const char MSG_CORRECTLY_ES[] PROGMEM = "Cambiado correct.?";
 const char MSG_CORRECTLY_PL[] PROGMEM = "Wymiana ok?";
+const char MSG_CORRECTLY_DE[] PROGMEM = "Wechsel ok?";
 const char * const MSG_CORRECTLY_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_CORRECTLY_EN,
 	MSG_CORRECTLY_CZ,
 	MSG_CORRECTLY_IT,
 	MSG_CORRECTLY_ES,
-	MSG_CORRECTLY_PL
+	MSG_CORRECTLY_PL,
+	MSG_CORRECTLY_DE
 };
 
 const char MSG_COUNT_X_EN[] PROGMEM = " Count X: ";
@@ -540,23 +669,27 @@ const char MSG_DISABLE_STEPPERS_CZ[] PROGMEM = "Vypnout motory";
 const char MSG_DISABLE_STEPPERS_IT[] PROGMEM = "Disabilit motori";
 const char MSG_DISABLE_STEPPERS_ES[] PROGMEM = "Apagar motores";
 const char MSG_DISABLE_STEPPERS_PL[] PROGMEM = "Wylaczyc silniki";
+const char MSG_DISABLE_STEPPERS_DE[] PROGMEM = "Deaktiviere Motor";
 const char * const MSG_DISABLE_STEPPERS_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_DISABLE_STEPPERS_EN,
 	MSG_DISABLE_STEPPERS_CZ,
 	MSG_DISABLE_STEPPERS_IT,
 	MSG_DISABLE_STEPPERS_ES,
-	MSG_DISABLE_STEPPERS_PL
+	MSG_DISABLE_STEPPERS_PL,
+	MSG_DISABLE_STEPPERS_DE
 };
 
 const char MSG_DWELL_EN[] PROGMEM = "Sleep...";
 const char MSG_DWELL_IT[] PROGMEM = "Sospensione...";
-const char MSG_DWELL_ES[] PROGMEM = "Reposo...";
+const char MSG_DWELL_ES[] PROGMEM = "En espera";
+const char MSG_DWELL_DE[] PROGMEM = "Schlaf...";
 const char * const MSG_DWELL_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_DWELL_EN,
 	MSG_DWELL_EN,
 	MSG_DWELL_IT,
 	MSG_DWELL_ES,
-	MSG_DWELL_EN
+	MSG_DWELL_EN,
+	MSG_DWELL_DE
 };
 
 const char MSG_ENDSTOPS_HIT_EN[] PROGMEM = "endstops hit: ";
@@ -581,13 +714,16 @@ const char * const MSG_END_FILE_LIST_LANG_TABLE[1] PROGMEM = {
 
 const char MSG_ERROR_EN[] PROGMEM = "ERROR:";
 const char MSG_ERROR_CZ[] PROGMEM = "CHYBA:";
+const char MSG_ERROR_IT[] PROGMEM = "ERRORE:";
 const char MSG_ERROR_PL[] PROGMEM = "BLAD:";
+const char MSG_ERROR_DE[] PROGMEM = "FEHLER:";
 const char * const MSG_ERROR_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_ERROR_EN,
 	MSG_ERROR_CZ,
+	MSG_ERROR_IT,
 	MSG_ERROR_EN,
-	MSG_ERROR_EN,
-	MSG_ERROR_PL
+	MSG_ERROR_PL,
+	MSG_ERROR_DE
 };
 
 const char MSG_ERR_CHECKSUM_MISMATCH_EN[] PROGMEM = "checksum mismatch, Last Line: ";
@@ -640,6 +776,21 @@ const char * const MSG_EXTERNAL_RESET_LANG_TABLE[1] PROGMEM = {
 	MSG_EXTERNAL_RESET_EN
 };
 
+const char MSG_E_CAL_KNOB_EN[] PROGMEM = "Rotate knob until mark reaches extruder body. Click when done.";
+const char MSG_E_CAL_KNOB_CZ[] PROGMEM = "Otacejte tlacitkem dokud znacka nedosahne tela extruderu. Potvrdte tlacitkem.";
+const char MSG_E_CAL_KNOB_IT[] PROGMEM = "Girare la manopola affinche' il segno raggiunga il corpo dell'estrusore. Click per continuare.";
+const char MSG_E_CAL_KNOB_ES[] PROGMEM = "Rotar el mando hasta que la marca llegue al cuerpo del extrusor. Haga clic una vez terminado.";
+const char MSG_E_CAL_KNOB_PL[] PROGMEM = "Prosze otaczac przycisk poki znacznik nie dosiegnie ciala ekstrudera. Potwierdzic przyciskiem.";
+const char MSG_E_CAL_KNOB_DE[] PROGMEM = "Dreh den Knopf bis das Extruder Zeichen erreicht ist. Klicken wenn fertig.";
+const char * const MSG_E_CAL_KNOB_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_E_CAL_KNOB_EN,
+	MSG_E_CAL_KNOB_CZ,
+	MSG_E_CAL_KNOB_IT,
+	MSG_E_CAL_KNOB_ES,
+	MSG_E_CAL_KNOB_PL,
+	MSG_E_CAL_KNOB_DE
+};
+
 const char MSG_Enqueing_EN[] PROGMEM = "enqueing \"";
 const char * const MSG_Enqueing_LANG_TABLE[1] PROGMEM = {
 	MSG_Enqueing_EN
@@ -652,15 +803,22 @@ const char * const MSG_FACTOR_LANG_TABLE[1] PROGMEM = {
 
 const char MSG_FAN_SPEED_EN[] PROGMEM = "Fan speed";
 const char MSG_FAN_SPEED_CZ[] PROGMEM = "Rychlost vent.";
-const char MSG_FAN_SPEED_IT[] PROGMEM = "Velocita ventola";
-const char MSG_FAN_SPEED_ES[] PROGMEM = "Ventilador";
+const char MSG_FAN_SPEED_IT[] PROGMEM = "Velocita vent.";
+const char MSG_FAN_SPEED_ES[] PROGMEM = "Velocidad Vent.";
 const char MSG_FAN_SPEED_PL[] PROGMEM = "Predkosc went.";
+const char MSG_FAN_SPEED_DE[] PROGMEM = "Lueftergeschw.";
 const char * const MSG_FAN_SPEED_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_FAN_SPEED_EN,
 	MSG_FAN_SPEED_CZ,
 	MSG_FAN_SPEED_IT,
 	MSG_FAN_SPEED_ES,
-	MSG_FAN_SPEED_PL
+	MSG_FAN_SPEED_PL,
+	MSG_FAN_SPEED_DE
+};
+
+const char MSG_FARM_CARD_MENU_EN[] PROGMEM = "Farm mode print";
+const char * const MSG_FARM_CARD_MENU_LANG_TABLE[1] PROGMEM = {
+	MSG_FARM_CARD_MENU_EN
 };
 
 const char MSG_FILAMENTCHANGE_EN[] PROGMEM = "Change filament";
@@ -668,12 +826,89 @@ const char MSG_FILAMENTCHANGE_CZ[] PROGMEM = "Vymenit filament";
 const char MSG_FILAMENTCHANGE_IT[] PROGMEM = "Camb. filamento";
 const char MSG_FILAMENTCHANGE_ES[] PROGMEM = "Cambiar filamento";
 const char MSG_FILAMENTCHANGE_PL[] PROGMEM = "Wymienic filament";
+const char MSG_FILAMENTCHANGE_DE[] PROGMEM = "Wechsel filament";
 const char * const MSG_FILAMENTCHANGE_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_FILAMENTCHANGE_EN,
 	MSG_FILAMENTCHANGE_CZ,
 	MSG_FILAMENTCHANGE_IT,
 	MSG_FILAMENTCHANGE_ES,
-	MSG_FILAMENTCHANGE_PL
+	MSG_FILAMENTCHANGE_PL,
+	MSG_FILAMENTCHANGE_DE
+};
+
+const char MSG_FILAMENT_CLEAN_EN[] PROGMEM = "Is color clear?";
+const char MSG_FILAMENT_CLEAN_CZ[] PROGMEM = "Je barva cista?";
+const char MSG_FILAMENT_CLEAN_IT[] PROGMEM = "Il colore e' nitido?";
+const char MSG_FILAMENT_CLEAN_ES[] PROGMEM = "Es el nuevo color nitido?";
+const char MSG_FILAMENT_CLEAN_PL[] PROGMEM = "Czy kolor jest czysty?";
+const char MSG_FILAMENT_CLEAN_DE[] PROGMEM = "Ist Farbe klar?";
+const char * const MSG_FILAMENT_CLEAN_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_FILAMENT_CLEAN_EN,
+	MSG_FILAMENT_CLEAN_CZ,
+	MSG_FILAMENT_CLEAN_IT,
+	MSG_FILAMENT_CLEAN_ES,
+	MSG_FILAMENT_CLEAN_PL,
+	MSG_FILAMENT_CLEAN_DE
+};
+
+const char MSG_FILAMENT_LOADING_T0_EN[] PROGMEM = "Insert filament into extruder 1. Click when done.";
+const char MSG_FILAMENT_LOADING_T0_CZ[] PROGMEM = "Vlo\x9Ete filament do extruderu 1. Potvrdte tlacitkem.";
+const char MSG_FILAMENT_LOADING_T0_IT[] PROGMEM = "Inserire filamento nell'estrusore 1. Click per continuare.";
+const char MSG_FILAMENT_LOADING_T0_ES[] PROGMEM = "Insertar filamento en el extrusor 1. Haga clic una vez terminado.";
+const char MSG_FILAMENT_LOADING_T0_PL[] PROGMEM = "Wloz filament do ekstrudera 1. Potwierdz przyciskiem.";
+const char MSG_FILAMENT_LOADING_T0_DE[] PROGMEM = "Filament in extruder 1 einlegen. Klicken wenn fertig.";
+const char * const MSG_FILAMENT_LOADING_T0_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_FILAMENT_LOADING_T0_EN,
+	MSG_FILAMENT_LOADING_T0_CZ,
+	MSG_FILAMENT_LOADING_T0_IT,
+	MSG_FILAMENT_LOADING_T0_ES,
+	MSG_FILAMENT_LOADING_T0_PL,
+	MSG_FILAMENT_LOADING_T0_DE
+};
+
+const char MSG_FILAMENT_LOADING_T1_EN[] PROGMEM = "Insert filament into extruder 2. Click when done.";
+const char MSG_FILAMENT_LOADING_T1_CZ[] PROGMEM = "Vlo\x9Ete filament do extruderu 2. Potvrdte tlacitkem.";
+const char MSG_FILAMENT_LOADING_T1_IT[] PROGMEM = "Inserire filamento nell'estrusore 2. Click per continuare.";
+const char MSG_FILAMENT_LOADING_T1_ES[] PROGMEM = "Insertar filamento en el extrusor 2. Haga clic una vez terminado.";
+const char MSG_FILAMENT_LOADING_T1_PL[] PROGMEM = "Wloz filament do ekstrudera 2. Potwierdz przyciskiem.";
+const char MSG_FILAMENT_LOADING_T1_DE[] PROGMEM = "Filament in extruder 2 einlegen. Klicken wenn fertig.";
+const char * const MSG_FILAMENT_LOADING_T1_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_FILAMENT_LOADING_T1_EN,
+	MSG_FILAMENT_LOADING_T1_CZ,
+	MSG_FILAMENT_LOADING_T1_IT,
+	MSG_FILAMENT_LOADING_T1_ES,
+	MSG_FILAMENT_LOADING_T1_PL,
+	MSG_FILAMENT_LOADING_T1_DE
+};
+
+const char MSG_FILAMENT_LOADING_T2_EN[] PROGMEM = "Insert filament into extruder 3. Click when done.";
+const char MSG_FILAMENT_LOADING_T2_CZ[] PROGMEM = "Vlo\x9Ete filament do extruderu 3. Potvrdte tlacitkem.";
+const char MSG_FILAMENT_LOADING_T2_IT[] PROGMEM = "Inserire filamento nell'estrusore 3. Click per continuare.";
+const char MSG_FILAMENT_LOADING_T2_ES[] PROGMEM = "Insertar filamento en el extrusor 3. Haga clic una vez terminado.";
+const char MSG_FILAMENT_LOADING_T2_PL[] PROGMEM = "Wloz filament do ekstrudera 3. Potwierdz przyciskiem.";
+const char MSG_FILAMENT_LOADING_T2_DE[] PROGMEM = "Filament in extruder 3 einlegen. Klicken wenn fertig.";
+const char * const MSG_FILAMENT_LOADING_T2_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_FILAMENT_LOADING_T2_EN,
+	MSG_FILAMENT_LOADING_T2_CZ,
+	MSG_FILAMENT_LOADING_T2_IT,
+	MSG_FILAMENT_LOADING_T2_ES,
+	MSG_FILAMENT_LOADING_T2_PL,
+	MSG_FILAMENT_LOADING_T2_DE
+};
+
+const char MSG_FILAMENT_LOADING_T3_EN[] PROGMEM = "Insert filament into extruder 4. Click when done.";
+const char MSG_FILAMENT_LOADING_T3_CZ[] PROGMEM = "Vlo\x9Ete filament do extruderu 4. Potvrdte tlacitkem.";
+const char MSG_FILAMENT_LOADING_T3_IT[] PROGMEM = "Inserire filamento nell'estrusore 4. Click per continuare.";
+const char MSG_FILAMENT_LOADING_T3_ES[] PROGMEM = "Insertar filamento en el extrusor 4. Haga clic una vez terminado.";
+const char MSG_FILAMENT_LOADING_T3_PL[] PROGMEM = "Wloz filament do ekstrudera 4. Potwierdz przyciskiem.";
+const char MSG_FILAMENT_LOADING_T3_DE[] PROGMEM = "Filament in extruder 4 einlegen. Klicken wenn fertig.";
+const char * const MSG_FILAMENT_LOADING_T3_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_FILAMENT_LOADING_T3_EN,
+	MSG_FILAMENT_LOADING_T3_CZ,
+	MSG_FILAMENT_LOADING_T3_IT,
+	MSG_FILAMENT_LOADING_T3_ES,
+	MSG_FILAMENT_LOADING_T3_PL,
+	MSG_FILAMENT_LOADING_T3_DE
 };
 
 const char MSG_FILE_PRINTED_EN[] PROGMEM = "Done printing file";
@@ -686,17 +921,64 @@ const char * const MSG_FILE_SAVED_LANG_TABLE[1] PROGMEM = {
 	MSG_FILE_SAVED_EN
 };
 
+const char MSG_FIL_ADJUSTING_EN[] PROGMEM = "Adjusting filaments. Please wait.";
+const char MSG_FIL_ADJUSTING_CZ[] PROGMEM = "Probiha srovnani filamentu. Prosim cekejte.";
+const char MSG_FIL_ADJUSTING_IT[] PROGMEM = "Filamento in fase di regolazione. Attendere prego.";
+const char MSG_FIL_ADJUSTING_ES[] PROGMEM = "Ajustando filamentos. Esperar por favor.";
+const char MSG_FIL_ADJUSTING_PL[] PROGMEM = "Przebiega wyrownanie filamentow. Prosze czekac.";
+const char MSG_FIL_ADJUSTING_DE[] PROGMEM = "Einstellen Filament. Bitte warten.";
+const char * const MSG_FIL_ADJUSTING_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_FIL_ADJUSTING_EN,
+	MSG_FIL_ADJUSTING_CZ,
+	MSG_FIL_ADJUSTING_IT,
+	MSG_FIL_ADJUSTING_ES,
+	MSG_FIL_ADJUSTING_PL,
+	MSG_FIL_ADJUSTING_DE
+};
+
+const char MSG_FIL_LOADED_CHECK_EN[] PROGMEM = "Is filament loaded?";
+const char MSG_FIL_LOADED_CHECK_CZ[] PROGMEM = "Je filament zaveden?";
+const char MSG_FIL_LOADED_CHECK_IT[] PROGMEM = "Filamento caricato?";
+const char MSG_FIL_LOADED_CHECK_ES[] PROGMEM = "Esta cargado el filamento?";
+const char MSG_FIL_LOADED_CHECK_PL[] PROGMEM = "Czy filament jest wprowadzony?";
+const char MSG_FIL_LOADED_CHECK_DE[] PROGMEM = "Filament eingelegt?";
+const char * const MSG_FIL_LOADED_CHECK_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_FIL_LOADED_CHECK_EN,
+	MSG_FIL_LOADED_CHECK_CZ,
+	MSG_FIL_LOADED_CHECK_IT,
+	MSG_FIL_LOADED_CHECK_ES,
+	MSG_FIL_LOADED_CHECK_PL,
+	MSG_FIL_LOADED_CHECK_DE
+};
+
+const char MSG_FIL_TUNING_EN[] PROGMEM = "Rotate the knob to adjust filament.";
+const char MSG_FIL_TUNING_CZ[] PROGMEM = "Otacenim tlacitka doladte pozici filamentu.";
+const char MSG_FIL_TUNING_IT[] PROGMEM = "Girare la manopola per regolare il filamento";
+const char MSG_FIL_TUNING_ES[] PROGMEM = "Rotar el mando para ajustar el filamento.";
+const char MSG_FIL_TUNING_PL[] PROGMEM = "Obrotem przycisku dostroj pozycje filamentu.";
+const char MSG_FIL_TUNING_DE[] PROGMEM = "Knopf drehen um Filam. einzustellen.";
+const char * const MSG_FIL_TUNING_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_FIL_TUNING_EN,
+	MSG_FIL_TUNING_CZ,
+	MSG_FIL_TUNING_IT,
+	MSG_FIL_TUNING_ES,
+	MSG_FIL_TUNING_PL,
+	MSG_FIL_TUNING_DE
+};
+
 const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_EN[] PROGMEM = "Searching bed calibration point";
 const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_CZ[] PROGMEM = "Hledam kalibracni bod podlozky";
 const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_IT[] PROGMEM = "Ricerca del letto punto di calibraz.";
 const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_ES[] PROGMEM = "Buscando cama punto de calibracion";
 const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_PL[] PROGMEM = "Szukam punktu kalibracyjnego podkladki";
+const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_DE[] PROGMEM = "Suchen Bed Kalibrierpunkt";
 const char * const MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_EN,
 	MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_CZ,
 	MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_IT,
 	MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_ES,
-	MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_PL
+	MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_PL,
+	MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_DE
 };
 
 const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_EN[] PROGMEM = " of 4";
@@ -704,12 +986,14 @@ const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_CZ[] PROGMEM = " z 4";
 const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_IT[] PROGMEM = " su 4";
 const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_ES[] PROGMEM = " de 4";
 const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_PL[] PROGMEM = " z 4";
+const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_DE[] PROGMEM = " von 4";
 const char * const MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_EN,
 	MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_CZ,
 	MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_IT,
 	MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_ES,
-	MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_PL
+	MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_PL,
+	MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_DE
 };
 
 const char MSG_FLOW_EN[] PROGMEM = "Flow";
@@ -717,12 +1001,14 @@ const char MSG_FLOW_CZ[] PROGMEM = "Prutok";
 const char MSG_FLOW_IT[] PROGMEM = "Flusso";
 const char MSG_FLOW_ES[] PROGMEM = "Flujo";
 const char MSG_FLOW_PL[] PROGMEM = "Przeplyw";
+const char MSG_FLOW_DE[] PROGMEM = "Durchfluss";
 const char * const MSG_FLOW_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_FLOW_EN,
 	MSG_FLOW_CZ,
 	MSG_FLOW_IT,
 	MSG_FLOW_ES,
-	MSG_FLOW_PL
+	MSG_FLOW_PL,
+	MSG_FLOW_DE
 };
 
 const char MSG_FLOW0_EN[] PROGMEM = "Flow 0";
@@ -740,6 +1026,21 @@ const char * const MSG_FLOW2_LANG_TABLE[1] PROGMEM = {
 	MSG_FLOW2_EN
 };
 
+const char MSG_FOLLOW_CALIBRATION_FLOW_EN[] PROGMEM = "Printer has not been calibrated yet. Please follow the manual, chapter First steps, section Calibration flow.";
+const char MSG_FOLLOW_CALIBRATION_FLOW_CZ[] PROGMEM = "Tiskarna nebyla jeste zkalibrovana. Postupujte prosim podle manualu, kapitola Zaciname, odstavec Postup kalibrace.";
+const char MSG_FOLLOW_CALIBRATION_FLOW_IT[] PROGMEM = "Stampante ancora non calibrata. Si prega di seguire il manuale, capitolo PRIMI PASSI, sezione della calibrazione.";
+const char MSG_FOLLOW_CALIBRATION_FLOW_ES[] PROGMEM = "Impresora no esta calibrada todavia. Por favor usar el manual, el capitulo First steps, seleccion Calibration flow.";
+const char MSG_FOLLOW_CALIBRATION_FLOW_PL[] PROGMEM = "Drukarka nie zostala jeszcze skalibrowana. Prosze kierowac sie instrukcja, rozdzial Zaczynamy, podrozdzial Selftest.";
+const char MSG_FOLLOW_CALIBRATION_FLOW_DE[] PROGMEM = "Der Drucker wurde noch nicht kalibriert. Bitte folgen Sie dem Handbuch, Kapitel First steps, Abschnitt Calibration flow.";
+const char * const MSG_FOLLOW_CALIBRATION_FLOW_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_FOLLOW_CALIBRATION_FLOW_EN,
+	MSG_FOLLOW_CALIBRATION_FLOW_CZ,
+	MSG_FOLLOW_CALIBRATION_FLOW_IT,
+	MSG_FOLLOW_CALIBRATION_FLOW_ES,
+	MSG_FOLLOW_CALIBRATION_FLOW_PL,
+	MSG_FOLLOW_CALIBRATION_FLOW_DE
+};
+
 const char MSG_FREE_MEMORY_EN[] PROGMEM = " Free Memory: ";
 const char * const MSG_FREE_MEMORY_LANG_TABLE[1] PROGMEM = {
 	MSG_FREE_MEMORY_EN
@@ -750,25 +1051,29 @@ const char MSG_HEATING_CZ[] PROGMEM = "Zahrivani";
 const char MSG_HEATING_IT[] PROGMEM = "Riscaldamento...";
 const char MSG_HEATING_ES[] PROGMEM = "Calentando...";
 const char MSG_HEATING_PL[] PROGMEM = "Grzanie...";
+const char MSG_HEATING_DE[] PROGMEM = "Erwaermen";
 const char * const MSG_HEATING_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_HEATING_EN,
 	MSG_HEATING_CZ,
 	MSG_HEATING_IT,
 	MSG_HEATING_ES,
-	MSG_HEATING_PL
+	MSG_HEATING_PL,
+	MSG_HEATING_DE
 };
 
 const char MSG_HEATING_COMPLETE_EN[] PROGMEM = "Heating done.";
 const char MSG_HEATING_COMPLETE_CZ[] PROGMEM = "Zahrivani OK.";
-const char MSG_HEATING_COMPLETE_IT[] PROGMEM = "Riscaldamento fatto.";
-const char MSG_HEATING_COMPLETE_ES[] PROGMEM = "Calentando listo.";
+const char MSG_HEATING_COMPLETE_IT[] PROGMEM = "Riscald. completo";
+const char MSG_HEATING_COMPLETE_ES[] PROGMEM = "Calentamiento final.";
 const char MSG_HEATING_COMPLETE_PL[] PROGMEM = "Grzanie OK.";
+const char MSG_HEATING_COMPLETE_DE[] PROGMEM = "Erwaermen OK";
 const char * const MSG_HEATING_COMPLETE_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_HEATING_COMPLETE_EN,
 	MSG_HEATING_COMPLETE_CZ,
 	MSG_HEATING_COMPLETE_IT,
 	MSG_HEATING_COMPLETE_ES,
-	MSG_HEATING_COMPLETE_PL
+	MSG_HEATING_COMPLETE_PL,
+	MSG_HEATING_COMPLETE_DE
 };
 
 const char MSG_HOMEYZ_EN[] PROGMEM = "Calibrate Z";
@@ -776,12 +1081,14 @@ const char MSG_HOMEYZ_CZ[] PROGMEM = "Kalibrovat Z";
 const char MSG_HOMEYZ_IT[] PROGMEM = "Calibra Z";
 const char MSG_HOMEYZ_ES[] PROGMEM = "Calibrar Z";
 const char MSG_HOMEYZ_PL[] PROGMEM = "Kalibruj Z";
+const char MSG_HOMEYZ_DE[] PROGMEM = "Kalibrieren Z";
 const char * const MSG_HOMEYZ_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_HOMEYZ_EN,
 	MSG_HOMEYZ_CZ,
 	MSG_HOMEYZ_IT,
 	MSG_HOMEYZ_ES,
-	MSG_HOMEYZ_PL
+	MSG_HOMEYZ_PL,
+	MSG_HOMEYZ_DE
 };
 
 const char MSG_HOMEYZ_DONE_EN[] PROGMEM = "Calibration done";
@@ -789,12 +1096,14 @@ const char MSG_HOMEYZ_DONE_CZ[] PROGMEM = "Kalibrace OK";
 const char MSG_HOMEYZ_DONE_IT[] PROGMEM = "Calibrazione OK";
 const char MSG_HOMEYZ_DONE_ES[] PROGMEM = "Calibracion OK";
 const char MSG_HOMEYZ_DONE_PL[] PROGMEM = "Kalibracja OK";
+const char MSG_HOMEYZ_DONE_DE[] PROGMEM = "Kalibrierung OK";
 const char * const MSG_HOMEYZ_DONE_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_HOMEYZ_DONE_EN,
 	MSG_HOMEYZ_DONE_CZ,
 	MSG_HOMEYZ_DONE_IT,
 	MSG_HOMEYZ_DONE_ES,
-	MSG_HOMEYZ_DONE_PL
+	MSG_HOMEYZ_DONE_PL,
+	MSG_HOMEYZ_DONE_DE
 };
 
 const char MSG_HOMEYZ_PROGRESS_EN[] PROGMEM = "Calibrating Z";
@@ -802,12 +1111,14 @@ const char MSG_HOMEYZ_PROGRESS_CZ[] PROGMEM = "Kalibruji Z";
 const char MSG_HOMEYZ_PROGRESS_IT[] PROGMEM = "Calibrando Z";
 const char MSG_HOMEYZ_PROGRESS_ES[] PROGMEM = "Calibrando Z";
 const char MSG_HOMEYZ_PROGRESS_PL[] PROGMEM = "Kalibruje Z";
+const char MSG_HOMEYZ_PROGRESS_DE[] PROGMEM = "Kalibriere Z";
 const char * const MSG_HOMEYZ_PROGRESS_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_HOMEYZ_PROGRESS_EN,
 	MSG_HOMEYZ_PROGRESS_CZ,
 	MSG_HOMEYZ_PROGRESS_IT,
 	MSG_HOMEYZ_PROGRESS_ES,
-	MSG_HOMEYZ_PROGRESS_PL
+	MSG_HOMEYZ_PROGRESS_PL,
+	MSG_HOMEYZ_PROGRESS_DE
 };
 
 const char MSG_HOTEND_OFFSET_EN[] PROGMEM = "Hotend offsets:";
@@ -820,12 +1131,14 @@ const char MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1_CZ[] PROGMEM = "Zlepsuji presno
 const char MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1_IT[] PROGMEM = "Perfezion. il letto punto di calibraz.";
 const char MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1_ES[] PROGMEM = "Mejorando cama punto de calibracion";
 const char MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1_PL[] PROGMEM = "Poprawiam precyzyjnosc punktu kalibracyjnego";
+const char MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1_DE[] PROGMEM = "Verbesserung Bed Kalibrierpunkt";
 const char * const MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1_EN,
 	MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1_CZ,
 	MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1_IT,
 	MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1_ES,
-	MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1_PL
+	MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1_PL,
+	MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE1_DE
 };
 
 const char MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2_EN[] PROGMEM = " of 9";
@@ -833,12 +1146,14 @@ const char MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2_CZ[] PROGMEM = " z 9";
 const char MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2_IT[] PROGMEM = " su 9";
 const char MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2_ES[] PROGMEM = " de 9";
 const char MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2_PL[] PROGMEM = " z 9";
+const char MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2_DE[] PROGMEM = " von 9";
 const char * const MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2_EN,
 	MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2_CZ,
 	MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2_IT,
 	MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2_ES,
-	MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2_PL
+	MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2_PL,
+	MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2_DE
 };
 
 const char MSG_INIT_SDCARD_EN[] PROGMEM = "Init. SD card";
@@ -849,14 +1164,16 @@ const char * const MSG_INIT_SDCARD_LANG_TABLE[1] PROGMEM = {
 const char MSG_INSERT_FILAMENT_EN[] PROGMEM = "Insert filament";
 const char MSG_INSERT_FILAMENT_CZ[] PROGMEM = "Vlozte filament";
 const char MSG_INSERT_FILAMENT_IT[] PROGMEM = "Inserire filamento";
-const char MSG_INSERT_FILAMENT_ES[] PROGMEM = "Inserta filamento";
+const char MSG_INSERT_FILAMENT_ES[] PROGMEM = "Introducir filamento";
 const char MSG_INSERT_FILAMENT_PL[] PROGMEM = "Wprowadz filament";
+const char MSG_INSERT_FILAMENT_DE[] PROGMEM = "Filament einlegen";
 const char * const MSG_INSERT_FILAMENT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_INSERT_FILAMENT_EN,
 	MSG_INSERT_FILAMENT_CZ,
 	MSG_INSERT_FILAMENT_IT,
 	MSG_INSERT_FILAMENT_ES,
-	MSG_INSERT_FILAMENT_PL
+	MSG_INSERT_FILAMENT_PL,
+	MSG_INSERT_FILAMENT_DE
 };
 
 const char MSG_INVALID_EXTRUDER_EN[] PROGMEM = "Invalid extruder";
@@ -866,12 +1183,13 @@ const char * const MSG_INVALID_EXTRUDER_LANG_TABLE[1] PROGMEM = {
 
 const char MSG_KILLED_EN[] PROGMEM = "KILLED. ";
 const char MSG_KILLED_IT[] PROGMEM = "IN TILT.";
-const char MSG_KILLED_ES[] PROGMEM = "PARADA DE EMERG.";
+const char MSG_KILLED_ES[] PROGMEM = "PARADA DE EMERGENCIA";
 const char * const MSG_KILLED_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_KILLED_EN,
 	MSG_KILLED_EN,
 	MSG_KILLED_IT,
 	MSG_KILLED_ES,
+	MSG_KILLED_EN,
 	MSG_KILLED_EN
 };
 
@@ -880,51 +1198,59 @@ const char MSG_LANGUAGE_NAME_CZ[] PROGMEM = "Cestina";
 const char MSG_LANGUAGE_NAME_IT[] PROGMEM = "Italiano";
 const char MSG_LANGUAGE_NAME_ES[] PROGMEM = "Espanol";
 const char MSG_LANGUAGE_NAME_PL[] PROGMEM = "Polski";
+const char MSG_LANGUAGE_NAME_DE[] PROGMEM = "Deutsch";
 const char * const MSG_LANGUAGE_NAME_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_LANGUAGE_NAME_EN,
 	MSG_LANGUAGE_NAME_CZ,
 	MSG_LANGUAGE_NAME_IT,
 	MSG_LANGUAGE_NAME_ES,
-	MSG_LANGUAGE_NAME_PL
+	MSG_LANGUAGE_NAME_PL,
+	MSG_LANGUAGE_NAME_DE
 };
 
 const char MSG_LANGUAGE_SELECT_EN[] PROGMEM = "Select language";
 const char MSG_LANGUAGE_SELECT_CZ[] PROGMEM = "Vyber jazyka";
 const char MSG_LANGUAGE_SELECT_IT[] PROGMEM = "Seleziona lingua";
-const char MSG_LANGUAGE_SELECT_ES[] PROGMEM = "Cambia la lengua ";
+const char MSG_LANGUAGE_SELECT_ES[] PROGMEM = "Cambiae el idioma";
 const char MSG_LANGUAGE_SELECT_PL[] PROGMEM = "Wybor jezyka";
+const char MSG_LANGUAGE_SELECT_DE[] PROGMEM = "Waehle Sprache";
 const char * const MSG_LANGUAGE_SELECT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_LANGUAGE_SELECT_EN,
 	MSG_LANGUAGE_SELECT_CZ,
 	MSG_LANGUAGE_SELECT_IT,
 	MSG_LANGUAGE_SELECT_ES,
-	MSG_LANGUAGE_SELECT_PL
+	MSG_LANGUAGE_SELECT_PL,
+	MSG_LANGUAGE_SELECT_DE
 };
 
 const char MSG_LOADING_COLOR_EN[] PROGMEM = "Loading color";
 const char MSG_LOADING_COLOR_CZ[] PROGMEM = "Cisteni barvy";
-const char MSG_LOADING_COLOR_IT[] PROGMEM = "Cargando color";
-const char MSG_LOADING_COLOR_ES[] PROGMEM = "Cargando color";
+const char MSG_LOADING_COLOR_IT[] PROGMEM = "Caricando colore";
+const char MSG_LOADING_COLOR_ES[] PROGMEM = "Cambiando color";
 const char MSG_LOADING_COLOR_PL[] PROGMEM = "Czyszcz. koloru";
+const char MSG_LOADING_COLOR_DE[] PROGMEM = "Lade Farbe";
 const char * const MSG_LOADING_COLOR_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_LOADING_COLOR_EN,
 	MSG_LOADING_COLOR_CZ,
 	MSG_LOADING_COLOR_IT,
 	MSG_LOADING_COLOR_ES,
-	MSG_LOADING_COLOR_PL
+	MSG_LOADING_COLOR_PL,
+	MSG_LOADING_COLOR_DE
 };
 
 const char MSG_LOADING_FILAMENT_EN[] PROGMEM = "Loading filament";
 const char MSG_LOADING_FILAMENT_CZ[] PROGMEM = "Zavadeni filamentu";
-const char MSG_LOADING_FILAMENT_IT[] PROGMEM = "Cargando fil.";
-const char MSG_LOADING_FILAMENT_ES[] PROGMEM = "Cargando fil.";
+const char MSG_LOADING_FILAMENT_IT[] PROGMEM = "Caricando filam.";
+const char MSG_LOADING_FILAMENT_ES[] PROGMEM = "Introduciendo filam.";
 const char MSG_LOADING_FILAMENT_PL[] PROGMEM = "Wprow. filamentu";
+const char MSG_LOADING_FILAMENT_DE[] PROGMEM = "Filament-Eifuehrung";
 const char * const MSG_LOADING_FILAMENT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_LOADING_FILAMENT_EN,
 	MSG_LOADING_FILAMENT_CZ,
 	MSG_LOADING_FILAMENT_IT,
 	MSG_LOADING_FILAMENT_ES,
-	MSG_LOADING_FILAMENT_PL
+	MSG_LOADING_FILAMENT_PL,
+	MSG_LOADING_FILAMENT_DE
 };
 
 const char MSG_LOAD_EPROM_EN[] PROGMEM = "Load memory";
@@ -935,14 +1261,31 @@ const char * const MSG_LOAD_EPROM_LANG_TABLE[1] PROGMEM = {
 const char MSG_LOAD_FILAMENT_EN[] PROGMEM = "Load filament";
 const char MSG_LOAD_FILAMENT_CZ[] PROGMEM = "Zavest filament";
 const char MSG_LOAD_FILAMENT_IT[] PROGMEM = "Carica filamento";
-const char MSG_LOAD_FILAMENT_ES[] PROGMEM = "Poner filamento";
+const char MSG_LOAD_FILAMENT_ES[] PROGMEM = "Introducir filam.";
 const char MSG_LOAD_FILAMENT_PL[] PROGMEM = "Wprowadz filament";
+const char MSG_LOAD_FILAMENT_DE[] PROGMEM = "Lege Filament ein";
 const char * const MSG_LOAD_FILAMENT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_LOAD_FILAMENT_EN,
 	MSG_LOAD_FILAMENT_CZ,
 	MSG_LOAD_FILAMENT_IT,
 	MSG_LOAD_FILAMENT_ES,
-	MSG_LOAD_FILAMENT_PL
+	MSG_LOAD_FILAMENT_PL,
+	MSG_LOAD_FILAMENT_DE
+};
+
+const char MSG_LOOSE_PULLEY_EN[] PROGMEM = "Loose pulley";
+const char MSG_LOOSE_PULLEY_CZ[] PROGMEM = "Uvolnena remenicka";
+const char MSG_LOOSE_PULLEY_IT[] PROGMEM = "Puleggia lenta";
+const char MSG_LOOSE_PULLEY_ES[] PROGMEM = "Polea suelta";
+const char MSG_LOOSE_PULLEY_PL[] PROGMEM = "Kolo pasowe";
+const char MSG_LOOSE_PULLEY_DE[] PROGMEM = "Lose Riemenschei.";
+const char * const MSG_LOOSE_PULLEY_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_LOOSE_PULLEY_EN,
+	MSG_LOOSE_PULLEY_CZ,
+	MSG_LOOSE_PULLEY_IT,
+	MSG_LOOSE_PULLEY_ES,
+	MSG_LOOSE_PULLEY_PL,
+	MSG_LOOSE_PULLEY_DE
 };
 
 const char MSG_M104_INVALID_EXTRUDER_EN[] PROGMEM = "M104 Invalid extruder ";
@@ -990,12 +1333,29 @@ const char MSG_MAIN_CZ[] PROGMEM = "Hlavni nabidka";
 const char MSG_MAIN_IT[] PROGMEM = "Menu principale";
 const char MSG_MAIN_ES[] PROGMEM = "Menu principal";
 const char MSG_MAIN_PL[] PROGMEM = "Menu glowne";
+const char MSG_MAIN_DE[] PROGMEM = "Hauptmenue";
 const char * const MSG_MAIN_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_MAIN_EN,
 	MSG_MAIN_CZ,
 	MSG_MAIN_IT,
 	MSG_MAIN_ES,
-	MSG_MAIN_PL
+	MSG_MAIN_PL,
+	MSG_MAIN_DE
+};
+
+const char MSG_MARK_FIL_EN[] PROGMEM = "Mark filament 100mm from extruder body. Click when done.";
+const char MSG_MARK_FIL_CZ[] PROGMEM = "Oznacte filament 100 mm od tela extruderu a po te potvrdte tlacitkem.";
+const char MSG_MARK_FIL_IT[] PROGMEM = "Segnare il filamento a 100 mm di distanza dal corpo dell'estrusore. Click per continuare.";
+const char MSG_MARK_FIL_ES[] PROGMEM = "Marque el filamento 100 mm por encima del final del extrusor. Hacer clic una vez terminado.";
+const char MSG_MARK_FIL_PL[] PROGMEM = "Prosze oznaczyc filament 100 mm od ciala ekstrudera. Potwierdzic przyciskiem.";
+const char MSG_MARK_FIL_DE[] PROGMEM = "Markier Filament 100mm vom Extrudergehaeuse. Klicken wenn Fertig.";
+const char * const MSG_MARK_FIL_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_MARK_FIL_EN,
+	MSG_MARK_FIL_CZ,
+	MSG_MARK_FIL_IT,
+	MSG_MARK_FIL_ES,
+	MSG_MARK_FIL_PL,
+	MSG_MARK_FIL_DE
 };
 
 const char MSG_MAX_EN[] PROGMEM = " \002 Max";
@@ -1008,12 +1368,14 @@ const char MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1_CZ[] PROGMEM = "Merim referenc
 const char MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1_IT[] PROGMEM = "Misurare l'altezza di riferimento del punto di calibrazione";
 const char MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1_ES[] PROGMEM = "Medir la altura del punto de la calibracion";
 const char MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1_PL[] PROGMEM = "Okreslam wysokosc odniesienia punktu kalibracyjnego";
+const char MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1_DE[] PROGMEM = "Messen der Referenzhoehe des Kalibrierpunktes";
 const char * const MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1_EN,
 	MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1_CZ,
 	MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1_IT,
 	MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1_ES,
-	MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1_PL
+	MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1_PL,
+	MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1_DE
 };
 
 const char MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2_EN[] PROGMEM = " of 9";
@@ -1021,12 +1383,14 @@ const char MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2_CZ[] PROGMEM = " z 9";
 const char MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2_IT[] PROGMEM = " su 9";
 const char MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2_ES[] PROGMEM = " de 9";
 const char MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2_PL[] PROGMEM = " z 9";
+const char MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2_DE[] PROGMEM = " von 9";
 const char * const MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2_EN,
 	MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2_CZ,
 	MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2_IT,
 	MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2_ES,
-	MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2_PL
+	MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2_PL,
+	MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2_DE
 };
 
 const char MSG_MENU_CALIBRATION_EN[] PROGMEM = "Calibration";
@@ -1034,12 +1398,14 @@ const char MSG_MENU_CALIBRATION_CZ[] PROGMEM = "Kalibrace";
 const char MSG_MENU_CALIBRATION_IT[] PROGMEM = "Calibrazione";
 const char MSG_MENU_CALIBRATION_ES[] PROGMEM = "Calibracion";
 const char MSG_MENU_CALIBRATION_PL[] PROGMEM = "Kalibracja";
+const char MSG_MENU_CALIBRATION_DE[] PROGMEM = "Kalibrierung";
 const char * const MSG_MENU_CALIBRATION_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_MENU_CALIBRATION_EN,
 	MSG_MENU_CALIBRATION_CZ,
 	MSG_MENU_CALIBRATION_IT,
 	MSG_MENU_CALIBRATION_ES,
-	MSG_MENU_CALIBRATION_PL
+	MSG_MENU_CALIBRATION_PL,
+	MSG_MENU_CALIBRATION_DE
 };
 
 const char MSG_MESH_BED_LEVELING_EN[] PROGMEM = "Mesh Bed Leveling";
@@ -1049,6 +1415,7 @@ const char * const MSG_MESH_BED_LEVELING_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_MESH_BED_LEVELING_EN,
 	MSG_MESH_BED_LEVELING_IT,
 	MSG_MESH_BED_LEVELING_EN,
+	MSG_MESH_BED_LEVELING_EN,
 	MSG_MESH_BED_LEVELING_EN
 };
 
@@ -1082,12 +1449,14 @@ const char MSG_MOVE_AXIS_CZ[] PROGMEM = "Posunout osu";
 const char MSG_MOVE_AXIS_IT[] PROGMEM = "Muovi asse";
 const char MSG_MOVE_AXIS_ES[] PROGMEM = "Mover ejes";
 const char MSG_MOVE_AXIS_PL[] PROGMEM = "Ruch osi";
+const char MSG_MOVE_AXIS_DE[] PROGMEM = "Bewege Achse";
 const char * const MSG_MOVE_AXIS_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_MOVE_AXIS_EN,
 	MSG_MOVE_AXIS_CZ,
 	MSG_MOVE_AXIS_IT,
 	MSG_MOVE_AXIS_ES,
-	MSG_MOVE_AXIS_PL
+	MSG_MOVE_AXIS_PL,
+	MSG_MOVE_AXIS_DE
 };
 
 const char MSG_MOVE_CARRIAGE_TO_THE_TOP_EN[] PROGMEM = "Calibrating XYZ. Rotate the knob to move the Z carriage up to the end stoppers. Click when done.";
@@ -1095,12 +1464,14 @@ const char MSG_MOVE_CARRIAGE_TO_THE_TOP_CZ[] PROGMEM = "Kalibrace XYZ. Otacenim
 const char MSG_MOVE_CARRIAGE_TO_THE_TOP_IT[] PROGMEM = "Calibrazione XYZ. Ruotare la manopola per alzare il carrello Z fino all'altezza massima. Click per terminare.";
 const char MSG_MOVE_CARRIAGE_TO_THE_TOP_ES[] PROGMEM = "Calibrando XYZ. Gira el boton para subir el carro Z hasta golpe piezas superioras. Despues haz clic.";
 const char MSG_MOVE_CARRIAGE_TO_THE_TOP_PL[] PROGMEM = "Kalibracja XYZ. Przekrec galke, aby przesunac os Z do gornych krancowek. Nacisnij, by potwierdzic.";
+const char MSG_MOVE_CARRIAGE_TO_THE_TOP_DE[] PROGMEM = "Kalibrieren von XYZ. Drehen Sie den Knopf, um den Z-Schlitten bis zum Anschlag zu bewegen. Klicken wenn fertig.";
 const char * const MSG_MOVE_CARRIAGE_TO_THE_TOP_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_MOVE_CARRIAGE_TO_THE_TOP_EN,
 	MSG_MOVE_CARRIAGE_TO_THE_TOP_CZ,
 	MSG_MOVE_CARRIAGE_TO_THE_TOP_IT,
 	MSG_MOVE_CARRIAGE_TO_THE_TOP_ES,
-	MSG_MOVE_CARRIAGE_TO_THE_TOP_PL
+	MSG_MOVE_CARRIAGE_TO_THE_TOP_PL,
+	MSG_MOVE_CARRIAGE_TO_THE_TOP_DE
 };
 
 const char MSG_MOVE_CARRIAGE_TO_THE_TOP_Z_EN[] PROGMEM = "Calibrating Z. Rotate the knob to move the Z carriage up to the end stoppers. Click when done.";
@@ -1108,22 +1479,25 @@ const char MSG_MOVE_CARRIAGE_TO_THE_TOP_Z_CZ[] PROGMEM = "Kalibrace Z. Otacenim
 const char MSG_MOVE_CARRIAGE_TO_THE_TOP_Z_IT[] PROGMEM = "Calibrazione Z. Ruotare la manopola per alzare il carrello Z fino all'altezza massima. Click per terminare.";
 const char MSG_MOVE_CARRIAGE_TO_THE_TOP_Z_ES[] PROGMEM = "Calibrando Z. Gira el boton para subir el carro Z hasta golpe piezas superioras. Despues haz clic.";
 const char MSG_MOVE_CARRIAGE_TO_THE_TOP_Z_PL[] PROGMEM = "Kalibracja Z. Przekrec galke, aby przesunac os Z do gornych krancowek. Nacisnij, by potwierdzic.";
+const char MSG_MOVE_CARRIAGE_TO_THE_TOP_Z_DE[] PROGMEM = "Kalibrieren von Z. Drehen Sie den Knopf, um den Z-Schlitten bis zum Anschlag zu bewegen. Klicken wenn fertig.";
 const char * const MSG_MOVE_CARRIAGE_TO_THE_TOP_Z_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_MOVE_CARRIAGE_TO_THE_TOP_Z_EN,
 	MSG_MOVE_CARRIAGE_TO_THE_TOP_Z_CZ,
 	MSG_MOVE_CARRIAGE_TO_THE_TOP_Z_IT,
 	MSG_MOVE_CARRIAGE_TO_THE_TOP_Z_ES,
-	MSG_MOVE_CARRIAGE_TO_THE_TOP_Z_PL
+	MSG_MOVE_CARRIAGE_TO_THE_TOP_Z_PL,
+	MSG_MOVE_CARRIAGE_TO_THE_TOP_Z_DE
 };
 
 const char MSG_MOVE_E_EN[] PROGMEM = "Extruder";
 const char MSG_MOVE_E_IT[] PROGMEM = "Muovi Estrusore";
-const char MSG_MOVE_E_ES[] PROGMEM = "Extrusor";
+const char MSG_MOVE_E_ES[] PROGMEM = "Extruir";
 const char * const MSG_MOVE_E_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_MOVE_E_EN,
 	MSG_MOVE_E_EN,
 	MSG_MOVE_E_IT,
 	MSG_MOVE_E_ES,
+	MSG_MOVE_E_EN,
 	MSG_MOVE_E_EN
 };
 
@@ -1132,12 +1506,14 @@ const char MSG_MOVE_X_CZ[] PROGMEM = "Posunout X";
 const char MSG_MOVE_X_IT[] PROGMEM = "Muovi X";
 const char MSG_MOVE_X_ES[] PROGMEM = "Mover X";
 const char MSG_MOVE_X_PL[] PROGMEM = "Przesunac X";
+const char MSG_MOVE_X_DE[] PROGMEM = "Bewege X";
 const char * const MSG_MOVE_X_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_MOVE_X_EN,
 	MSG_MOVE_X_CZ,
 	MSG_MOVE_X_IT,
 	MSG_MOVE_X_ES,
-	MSG_MOVE_X_PL
+	MSG_MOVE_X_PL,
+	MSG_MOVE_X_DE
 };
 
 const char MSG_MOVE_Y_EN[] PROGMEM = "Move Y";
@@ -1145,12 +1521,14 @@ const char MSG_MOVE_Y_CZ[] PROGMEM = "Posunout Y";
 const char MSG_MOVE_Y_IT[] PROGMEM = "Muovi Y";
 const char MSG_MOVE_Y_ES[] PROGMEM = "Mover Y";
 const char MSG_MOVE_Y_PL[] PROGMEM = "Przesunac Y";
+const char MSG_MOVE_Y_DE[] PROGMEM = "Bewege Y";
 const char * const MSG_MOVE_Y_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_MOVE_Y_EN,
 	MSG_MOVE_Y_CZ,
 	MSG_MOVE_Y_IT,
 	MSG_MOVE_Y_ES,
-	MSG_MOVE_Y_PL
+	MSG_MOVE_Y_PL,
+	MSG_MOVE_Y_DE
 };
 
 const char MSG_MOVE_Z_EN[] PROGMEM = "Move Z";
@@ -1158,12 +1536,14 @@ const char MSG_MOVE_Z_CZ[] PROGMEM = "Posunout Z";
 const char MSG_MOVE_Z_IT[] PROGMEM = "Muovi Z";
 const char MSG_MOVE_Z_ES[] PROGMEM = "Mover Z";
 const char MSG_MOVE_Z_PL[] PROGMEM = "Przesunac Z";
+const char MSG_MOVE_Z_DE[] PROGMEM = "Bewege Z";
 const char * const MSG_MOVE_Z_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_MOVE_Z_EN,
 	MSG_MOVE_Z_CZ,
 	MSG_MOVE_Z_IT,
 	MSG_MOVE_Z_ES,
-	MSG_MOVE_Z_PL
+	MSG_MOVE_Z_PL,
+	MSG_MOVE_Z_DE
 };
 
 const char MSG_NEW_FIRMWARE_AVAILABLE_EN[] PROGMEM = "New firmware version available:";
@@ -1171,12 +1551,14 @@ const char MSG_NEW_FIRMWARE_AVAILABLE_CZ[] PROGMEM = "Vysla nova verze firmware:
 const char MSG_NEW_FIRMWARE_AVAILABLE_IT[] PROGMEM = "Nuova versione del firmware disponibile";
 const char MSG_NEW_FIRMWARE_AVAILABLE_ES[] PROGMEM = "Nuevo firmware disponible:";
 const char MSG_NEW_FIRMWARE_AVAILABLE_PL[] PROGMEM = "Wyszla nowa wersja firmware:";
+const char MSG_NEW_FIRMWARE_AVAILABLE_DE[] PROGMEM = "Neue Firmware Version verfuegbar:";
 const char * const MSG_NEW_FIRMWARE_AVAILABLE_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_NEW_FIRMWARE_AVAILABLE_EN,
 	MSG_NEW_FIRMWARE_AVAILABLE_CZ,
 	MSG_NEW_FIRMWARE_AVAILABLE_IT,
 	MSG_NEW_FIRMWARE_AVAILABLE_ES,
-	MSG_NEW_FIRMWARE_AVAILABLE_PL
+	MSG_NEW_FIRMWARE_AVAILABLE_PL,
+	MSG_NEW_FIRMWARE_AVAILABLE_DE
 };
 
 const char MSG_NEW_FIRMWARE_PLEASE_UPGRADE_EN[] PROGMEM = "Please upgrade.";
@@ -1184,62 +1566,72 @@ const char MSG_NEW_FIRMWARE_PLEASE_UPGRADE_CZ[] PROGMEM = "Prosim aktualizujte."
 const char MSG_NEW_FIRMWARE_PLEASE_UPGRADE_IT[] PROGMEM = "Prega aggiorna.";
 const char MSG_NEW_FIRMWARE_PLEASE_UPGRADE_ES[] PROGMEM = "Actualizar por favor";
 const char MSG_NEW_FIRMWARE_PLEASE_UPGRADE_PL[] PROGMEM = "Prosze zaktualizowac";
+const char MSG_NEW_FIRMWARE_PLEASE_UPGRADE_DE[] PROGMEM = "Bitte aktualisieren.";
 const char * const MSG_NEW_FIRMWARE_PLEASE_UPGRADE_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_NEW_FIRMWARE_PLEASE_UPGRADE_EN,
 	MSG_NEW_FIRMWARE_PLEASE_UPGRADE_CZ,
 	MSG_NEW_FIRMWARE_PLEASE_UPGRADE_IT,
 	MSG_NEW_FIRMWARE_PLEASE_UPGRADE_ES,
-	MSG_NEW_FIRMWARE_PLEASE_UPGRADE_PL
+	MSG_NEW_FIRMWARE_PLEASE_UPGRADE_PL,
+	MSG_NEW_FIRMWARE_PLEASE_UPGRADE_DE
 };
 
 const char MSG_NO_EN[] PROGMEM = "No";
 const char MSG_NO_CZ[] PROGMEM = "Ne";
 const char MSG_NO_PL[] PROGMEM = "Nie";
+const char MSG_NO_DE[] PROGMEM = "Nein";
 const char * const MSG_NO_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_NO_EN,
 	MSG_NO_CZ,
 	MSG_NO_EN,
 	MSG_NO_EN,
-	MSG_NO_PL
+	MSG_NO_PL,
+	MSG_NO_DE
 };
 
 const char MSG_NOT_COLOR_EN[] PROGMEM = "Color not clear";
 const char MSG_NOT_COLOR_CZ[] PROGMEM = "Barva neni cista";
-const char MSG_NOT_COLOR_IT[] PROGMEM = "Color no claro";
-const char MSG_NOT_COLOR_ES[] PROGMEM = "Color no claro";
+const char MSG_NOT_COLOR_IT[] PROGMEM = "Colore non puro";
+const char MSG_NOT_COLOR_ES[] PROGMEM = "Color no homogeneo";
 const char MSG_NOT_COLOR_PL[] PROGMEM = "Kolor zanieczysz.";
+const char MSG_NOT_COLOR_DE[] PROGMEM = "Farbe nicht klar";
 const char * const MSG_NOT_COLOR_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_NOT_COLOR_EN,
 	MSG_NOT_COLOR_CZ,
 	MSG_NOT_COLOR_IT,
 	MSG_NOT_COLOR_ES,
-	MSG_NOT_COLOR_PL
+	MSG_NOT_COLOR_PL,
+	MSG_NOT_COLOR_DE
 };
 
 const char MSG_NOT_LOADED_EN[] PROGMEM = "Filament not loaded";
 const char MSG_NOT_LOADED_CZ[] PROGMEM = "Filament nezaveden";
-const char MSG_NOT_LOADED_IT[] PROGMEM = "Fil. no cargado";
-const char MSG_NOT_LOADED_ES[] PROGMEM = "Fil. no cargado";
+const char MSG_NOT_LOADED_IT[] PROGMEM = "Fil. non caricato";
+const char MSG_NOT_LOADED_ES[] PROGMEM = "Fil. no introducido";
 const char MSG_NOT_LOADED_PL[] PROGMEM = "Brak filamentu";
+const char MSG_NOT_LOADED_DE[] PROGMEM = "Filam. nicht geladen";
 const char * const MSG_NOT_LOADED_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_NOT_LOADED_EN,
 	MSG_NOT_LOADED_CZ,
 	MSG_NOT_LOADED_IT,
 	MSG_NOT_LOADED_ES,
-	MSG_NOT_LOADED_PL
+	MSG_NOT_LOADED_PL,
+	MSG_NOT_LOADED_DE
 };
 
 const char MSG_NOZZLE_EN[] PROGMEM = "Nozzle";
 const char MSG_NOZZLE_CZ[] PROGMEM = "Tryska";
 const char MSG_NOZZLE_IT[] PROGMEM = "Ugello";
-const char MSG_NOZZLE_ES[] PROGMEM = "Fusor";
+const char MSG_NOZZLE_ES[] PROGMEM = "Boquilla";
 const char MSG_NOZZLE_PL[] PROGMEM = "Dysza";
+const char MSG_NOZZLE_DE[] PROGMEM = "Duese";
 const char * const MSG_NOZZLE_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_NOZZLE_EN,
 	MSG_NOZZLE_CZ,
 	MSG_NOZZLE_IT,
 	MSG_NOZZLE_ES,
-	MSG_NOZZLE_PL
+	MSG_NOZZLE_PL,
+	MSG_NOZZLE_DE
 };
 
 const char MSG_NOZZLE1_EN[] PROGMEM = "Nozzle2";
@@ -1257,23 +1649,27 @@ const char MSG_NO_CARD_CZ[] PROGMEM = "Zadna SD karta";
 const char MSG_NO_CARD_IT[] PROGMEM = "Nessuna SD";
 const char MSG_NO_CARD_ES[] PROGMEM = "No hay tarjeta SD";
 const char MSG_NO_CARD_PL[] PROGMEM = "Brak karty SD";
+const char MSG_NO_CARD_DE[] PROGMEM = "Keine SD Karte";
 const char * const MSG_NO_CARD_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_NO_CARD_EN,
 	MSG_NO_CARD_CZ,
 	MSG_NO_CARD_IT,
 	MSG_NO_CARD_ES,
-	MSG_NO_CARD_PL
+	MSG_NO_CARD_PL,
+	MSG_NO_CARD_DE
 };
 
 const char MSG_NO_MOVE_EN[] PROGMEM = "No move.";
 const char MSG_NO_MOVE_IT[] PROGMEM = "Nessun movimento.";
 const char MSG_NO_MOVE_ES[] PROGMEM = "Sin movimiento";
+const char MSG_NO_MOVE_DE[] PROGMEM = "Keine Bewegung.";
 const char * const MSG_NO_MOVE_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_NO_MOVE_EN,
 	MSG_NO_MOVE_EN,
 	MSG_NO_MOVE_IT,
 	MSG_NO_MOVE_ES,
-	MSG_NO_MOVE_EN
+	MSG_NO_MOVE_EN,
+	MSG_NO_MOVE_DE
 };
 
 const char MSG_OFF_EN[] PROGMEM = "Off";
@@ -1291,29 +1687,48 @@ const char * const MSG_ON_LANG_TABLE[1] PROGMEM = {
 	MSG_ON_EN
 };
 
+const char MSG_PAPER_EN[] PROGMEM = "Place a sheet of paper under the nozzle during the calibration of first 4 points. If the nozzle catches the paper, power off the printer immediately.";
+const char MSG_PAPER_CZ[] PROGMEM = "Umistete list papiru na podlozku a udrzujte jej pod tryskou behem mereni prvnich 4 bodu. Pokud tryska zachyti papir, vypnete tiskarnu.";
+const char MSG_PAPER_IT[] PROGMEM = "Porre un foglio sotto l'ugello durante la calibrazione dei primi 4 punti. In caso l'ugello muova il foglio spegnere prontamente la stampante.";
+const char MSG_PAPER_ES[] PROGMEM = "Colocar una hoja de papel sobre la superficie de impresion durante la calibracion de los primeros 4 puntos. Si la boquilla mueve el papel, apagar impresora inmediatamente.";
+const char MSG_PAPER_PL[] PROGMEM = "Umiesc kartke papieru na podkladce i trzymaj pod dysza podczas pomiaru pierwszych 4 punktow. Jesli dysza zahaczy o papier, wylacz drukarke.";
+const char MSG_PAPER_DE[] PROGMEM = "Legen ein Blatt Papier unter die Duese waehrend der Kalibrierung der ersten 4 Punkte. Wenn die Duese das Papier einfaengt, Drucker sofort ausschalten";
+const char * const MSG_PAPER_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_PAPER_EN,
+	MSG_PAPER_CZ,
+	MSG_PAPER_IT,
+	MSG_PAPER_ES,
+	MSG_PAPER_PL,
+	MSG_PAPER_DE
+};
+
 const char MSG_PAUSE_PRINT_EN[] PROGMEM = "Pause print";
 const char MSG_PAUSE_PRINT_CZ[] PROGMEM = "Pozastavit tisk";
 const char MSG_PAUSE_PRINT_IT[] PROGMEM = "Metti in pausa";
 const char MSG_PAUSE_PRINT_ES[] PROGMEM = "Pausar impresion";
 const char MSG_PAUSE_PRINT_PL[] PROGMEM = "Przerwac druk";
+const char MSG_PAUSE_PRINT_DE[] PROGMEM = "Druck aussetzen";
 const char * const MSG_PAUSE_PRINT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_PAUSE_PRINT_EN,
 	MSG_PAUSE_PRINT_CZ,
 	MSG_PAUSE_PRINT_IT,
 	MSG_PAUSE_PRINT_ES,
-	MSG_PAUSE_PRINT_PL
+	MSG_PAUSE_PRINT_PL,
+	MSG_PAUSE_PRINT_DE
 };
 
 const char MSG_PICK_Z_EN[] PROGMEM = "Pick print";
 const char MSG_PICK_Z_CZ[] PROGMEM = "Vyberte vytisk";
-const char MSG_PICK_Z_ES[] PROGMEM = "Vyberte vytisk";
+const char MSG_PICK_Z_ES[] PROGMEM = "Esc. Modelo Adecuado";
 const char MSG_PICK_Z_PL[] PROGMEM = "Vyberte vytisk";
+const char MSG_PICK_Z_DE[] PROGMEM = "Waehle Abdruck";
 const char * const MSG_PICK_Z_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_PICK_Z_EN,
 	MSG_PICK_Z_CZ,
 	MSG_PICK_Z_EN,
 	MSG_PICK_Z_ES,
-	MSG_PICK_Z_PL
+	MSG_PICK_Z_PL,
+	MSG_PICK_Z_DE
 };
 
 const char MSG_PLANNER_BUFFER_BYTES_EN[] PROGMEM = "  PlannerBufferBytes: ";
@@ -1324,14 +1739,16 @@ const char * const MSG_PLANNER_BUFFER_BYTES_LANG_TABLE[1] PROGMEM = {
 const char MSG_PLEASE_WAIT_EN[] PROGMEM = "Please wait";
 const char MSG_PLEASE_WAIT_CZ[] PROGMEM = "Prosim cekejte";
 const char MSG_PLEASE_WAIT_IT[] PROGMEM = "Aspetta";
-const char MSG_PLEASE_WAIT_ES[] PROGMEM = "Espera";
+const char MSG_PLEASE_WAIT_ES[] PROGMEM = "Por Favor Esperar";
 const char MSG_PLEASE_WAIT_PL[] PROGMEM = "Prosze czekac";
+const char MSG_PLEASE_WAIT_DE[] PROGMEM = "Bitte warten";
 const char * const MSG_PLEASE_WAIT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_PLEASE_WAIT_EN,
 	MSG_PLEASE_WAIT_CZ,
 	MSG_PLEASE_WAIT_IT,
 	MSG_PLEASE_WAIT_ES,
-	MSG_PLEASE_WAIT_PL
+	MSG_PLEASE_WAIT_PL,
+	MSG_PLEASE_WAIT_DE
 };
 
 const char MSG_POSITION_UNKNOWN_EN[] PROGMEM = "Home X/Y before Z";
@@ -1349,50 +1766,64 @@ const char MSG_PREHEAT_CZ[] PROGMEM = "Predehrev";
 const char MSG_PREHEAT_IT[] PROGMEM = "Preriscalda";
 const char MSG_PREHEAT_ES[] PROGMEM = "Precalentar";
 const char MSG_PREHEAT_PL[] PROGMEM = "Grzanie";
+const char MSG_PREHEAT_DE[] PROGMEM = "Vorwaermen";
 const char * const MSG_PREHEAT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_PREHEAT_EN,
 	MSG_PREHEAT_CZ,
 	MSG_PREHEAT_IT,
 	MSG_PREHEAT_ES,
-	MSG_PREHEAT_PL
+	MSG_PREHEAT_PL,
+	MSG_PREHEAT_DE
 };
 
 const char MSG_PREHEAT_NOZZLE_EN[] PROGMEM = "Preheat the nozzle!";
 const char MSG_PREHEAT_NOZZLE_CZ[] PROGMEM = "Predehrejte trysku!";
 const char MSG_PREHEAT_NOZZLE_IT[] PROGMEM = "Preris. ugello!";
-const char MSG_PREHEAT_NOZZLE_ES[] PROGMEM = "Precal. extrusor!";
+const char MSG_PREHEAT_NOZZLE_ES[] PROGMEM = "Precalentar extrusor";
 const char MSG_PREHEAT_NOZZLE_PL[] PROGMEM = "Nagrzej dysze!";
+const char MSG_PREHEAT_NOZZLE_DE[] PROGMEM = "Worwaermen Duese";
 const char * const MSG_PREHEAT_NOZZLE_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_PREHEAT_NOZZLE_EN,
 	MSG_PREHEAT_NOZZLE_CZ,
 	MSG_PREHEAT_NOZZLE_IT,
 	MSG_PREHEAT_NOZZLE_ES,
-	MSG_PREHEAT_NOZZLE_PL
+	MSG_PREHEAT_NOZZLE_PL,
+	MSG_PREHEAT_NOZZLE_DE
 };
 
-const char MSG_PRESS_EN[] PROGMEM = "And press the knob";
-const char MSG_PRESS_CZ[] PROGMEM = "A stisknete tlacitko";
-const char MSG_PRESS_IT[] PROGMEM = "Y pulse el mando";
-const char MSG_PRESS_ES[] PROGMEM = "Y pulse el mando";
+const char MSG_PRESS_EN[] PROGMEM = "and press the knob";
+const char MSG_PRESS_CZ[] PROGMEM = "a stisknete tlacitko";
+const char MSG_PRESS_IT[] PROGMEM = "e cliccare manopola";
+const char MSG_PRESS_ES[] PROGMEM = "Pulsar el mando";
 const char MSG_PRESS_PL[] PROGMEM = "Nacisnij przycisk";
+const char MSG_PRESS_DE[] PROGMEM = "und Knopf druecken";
 const char * const MSG_PRESS_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_PRESS_EN,
 	MSG_PRESS_CZ,
 	MSG_PRESS_IT,
 	MSG_PRESS_ES,
-	MSG_PRESS_PL
+	MSG_PRESS_PL,
+	MSG_PRESS_DE
+};
+
+const char MSG_PRINTER_DISCONNECTED_EN[] PROGMEM = "Printer disconnected";
+const char * const MSG_PRINTER_DISCONNECTED_LANG_TABLE[1] PROGMEM = {
+	MSG_PRINTER_DISCONNECTED_EN
 };
 
 const char MSG_PRINT_ABORTED_EN[] PROGMEM = "Print aborted";
 const char MSG_PRINT_ABORTED_CZ[] PROGMEM = "Tisk prerusen";
 const char MSG_PRINT_ABORTED_IT[] PROGMEM = "Stampa abortita";
+const char MSG_PRINT_ABORTED_ES[] PROGMEM = "Impresion cancelada";
 const char MSG_PRINT_ABORTED_PL[] PROGMEM = "Druk przerwany";
+const char MSG_PRINT_ABORTED_DE[] PROGMEM = "Druck abgebrochen";
 const char * const MSG_PRINT_ABORTED_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_PRINT_ABORTED_EN,
 	MSG_PRINT_ABORTED_CZ,
 	MSG_PRINT_ABORTED_IT,
-	MSG_PRINT_ABORTED_EN,
-	MSG_PRINT_ABORTED_PL
+	MSG_PRINT_ABORTED_ES,
+	MSG_PRINT_ABORTED_PL,
+	MSG_PRINT_ABORTED_DE
 };
 
 const char MSG_PRUSA3D_EN[] PROGMEM = "prusa3d.com";
@@ -1403,7 +1834,8 @@ const char * const MSG_PRUSA3D_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_PRUSA3D_CZ,
 	MSG_PRUSA3D_EN,
 	MSG_PRUSA3D_EN,
-	MSG_PRUSA3D_PL
+	MSG_PRUSA3D_PL,
+	MSG_PRUSA3D_EN
 };
 
 const char MSG_PRUSA3D_FORUM_EN[] PROGMEM = "forum.prusa3d.com";
@@ -1414,7 +1846,8 @@ const char * const MSG_PRUSA3D_FORUM_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_PRUSA3D_FORUM_CZ,
 	MSG_PRUSA3D_FORUM_EN,
 	MSG_PRUSA3D_FORUM_EN,
-	MSG_PRUSA3D_FORUM_PL
+	MSG_PRUSA3D_FORUM_PL,
+	MSG_PRUSA3D_FORUM_EN
 };
 
 const char MSG_PRUSA3D_HOWTO_EN[] PROGMEM = "howto.prusa3d.com";
@@ -1425,20 +1858,23 @@ const char * const MSG_PRUSA3D_HOWTO_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_PRUSA3D_HOWTO_CZ,
 	MSG_PRUSA3D_HOWTO_EN,
 	MSG_PRUSA3D_HOWTO_EN,
-	MSG_PRUSA3D_HOWTO_PL
+	MSG_PRUSA3D_HOWTO_PL,
+	MSG_PRUSA3D_HOWTO_EN
 };
 
 const char MSG_REBOOT_EN[] PROGMEM = "Reboot the printer";
 const char MSG_REBOOT_CZ[] PROGMEM = "Restartujte tiskarnu";
 const char MSG_REBOOT_IT[] PROGMEM = "Riavvia stampante";
-const char MSG_REBOOT_ES[] PROGMEM = "Reiniciar la imp.";
+const char MSG_REBOOT_ES[] PROGMEM = "Reiniciar impresora";
 const char MSG_REBOOT_PL[] PROGMEM = "Restart drukarki";
+const char MSG_REBOOT_DE[] PROGMEM = "Reboot den Printer";
 const char * const MSG_REBOOT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_REBOOT_EN,
 	MSG_REBOOT_CZ,
 	MSG_REBOOT_IT,
 	MSG_REBOOT_ES,
-	MSG_REBOOT_PL
+	MSG_REBOOT_PL,
+	MSG_REBOOT_DE
 };
 
 const char MSG_RECTRACT_EN[] PROGMEM = "Rectract";
@@ -1456,6 +1892,11 @@ const char * const MSG_RESEND_LANG_TABLE[1] PROGMEM = {
 	MSG_RESEND_EN
 };
 
+const char MSG_RESET_CALIBRATE_E_EN[] PROGMEM = "Reset E Cal.";
+const char * const MSG_RESET_CALIBRATE_E_LANG_TABLE[1] PROGMEM = {
+	MSG_RESET_CALIBRATE_E_EN
+};
+
 const char MSG_RESTORE_FAILSAFE_EN[] PROGMEM = "Restore failsafe";
 const char * const MSG_RESTORE_FAILSAFE_LANG_TABLE[1] PROGMEM = {
 	MSG_RESTORE_FAILSAFE_EN
@@ -1466,25 +1907,29 @@ const char MSG_RESUME_PRINT_CZ[] PROGMEM = "Pokracovat";
 const char MSG_RESUME_PRINT_IT[] PROGMEM = "Riprendi stampa";
 const char MSG_RESUME_PRINT_ES[] PROGMEM = "Reanudar impres.";
 const char MSG_RESUME_PRINT_PL[] PROGMEM = "Kontynuowac";
+const char MSG_RESUME_PRINT_DE[] PROGMEM = "Fortsetzen";
 const char * const MSG_RESUME_PRINT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_RESUME_PRINT_EN,
 	MSG_RESUME_PRINT_CZ,
 	MSG_RESUME_PRINT_IT,
 	MSG_RESUME_PRINT_ES,
-	MSG_RESUME_PRINT_PL
+	MSG_RESUME_PRINT_PL,
+	MSG_RESUME_PRINT_DE
 };
 
 const char MSG_RESUMING_EN[] PROGMEM = "Resuming print";
 const char MSG_RESUMING_CZ[] PROGMEM = "Obnoveni tisku";
 const char MSG_RESUMING_IT[] PROGMEM = "Riprendi stampa";
-const char MSG_RESUMING_ES[] PROGMEM = "Resumiendo impre.";
+const char MSG_RESUMING_ES[] PROGMEM = "Resumiendo impresion";
 const char MSG_RESUMING_PL[] PROGMEM = "Wznowienie druku";
+const char MSG_RESUMING_DE[] PROGMEM = "Druck fortgesetzt";
 const char * const MSG_RESUMING_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_RESUMING_EN,
 	MSG_RESUMING_CZ,
 	MSG_RESUMING_IT,
 	MSG_RESUMING_ES,
-	MSG_RESUMING_PL
+	MSG_RESUMING_PL,
+	MSG_RESUMING_DE
 };
 
 const char MSG_SD_CANT_ENTER_SUBDIR_EN[] PROGMEM = "Cannot enter subdir: ";
@@ -1525,14 +1970,16 @@ const char * const MSG_SD_INIT_FAIL_LANG_TABLE[1] PROGMEM = {
 const char MSG_SD_INSERTED_EN[] PROGMEM = "Card inserted";
 const char MSG_SD_INSERTED_CZ[] PROGMEM = "Karta vlozena";
 const char MSG_SD_INSERTED_IT[] PROGMEM = "SD inserita";
-const char MSG_SD_INSERTED_ES[] PROGMEM = "Tarjeta colocada";
+const char MSG_SD_INSERTED_ES[] PROGMEM = "Tarjeta insertada";
 const char MSG_SD_INSERTED_PL[] PROGMEM = "Karta wlozona";
+const char MSG_SD_INSERTED_DE[] PROGMEM = "SD eingesetzt";
 const char * const MSG_SD_INSERTED_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SD_INSERTED_EN,
 	MSG_SD_INSERTED_CZ,
 	MSG_SD_INSERTED_IT,
 	MSG_SD_INSERTED_ES,
-	MSG_SD_INSERTED_PL
+	MSG_SD_INSERTED_PL,
+	MSG_SD_INSERTED_DE
 };
 
 const char MSG_SD_NOT_PRINTING_EN[] PROGMEM = "Not SD printing";
@@ -1560,12 +2007,14 @@ const char MSG_SD_REMOVED_CZ[] PROGMEM = "Karta vyjmuta";
 const char MSG_SD_REMOVED_IT[] PROGMEM = "SD rimossa";
 const char MSG_SD_REMOVED_ES[] PROGMEM = "Tarjeta retirada";
 const char MSG_SD_REMOVED_PL[] PROGMEM = "Karta wyjeta";
+const char MSG_SD_REMOVED_DE[] PROGMEM = "SD entfernt ";
 const char * const MSG_SD_REMOVED_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SD_REMOVED_EN,
 	MSG_SD_REMOVED_CZ,
 	MSG_SD_REMOVED_IT,
 	MSG_SD_REMOVED_ES,
-	MSG_SD_REMOVED_PL
+	MSG_SD_REMOVED_PL,
+	MSG_SD_REMOVED_DE
 };
 
 const char MSG_SD_SIZE_EN[] PROGMEM = " Size: ";
@@ -1591,12 +2040,14 @@ const char * const MSG_SD_WRITE_TO_FILE_LANG_TABLE[1] PROGMEM = {
 const char MSG_SELFTEST_EN[] PROGMEM = "Selftest         ";
 const char MSG_SELFTEST_IT[] PROGMEM = "Autotest";
 const char MSG_SELFTEST_ES[] PROGMEM = "Autotest";
+const char MSG_SELFTEST_DE[] PROGMEM = "Selbsttest       ";
 const char * const MSG_SELFTEST_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SELFTEST_EN,
 	MSG_SELFTEST_EN,
 	MSG_SELFTEST_IT,
 	MSG_SELFTEST_ES,
-	MSG_SELFTEST_EN
+	MSG_SELFTEST_EN,
+	MSG_SELFTEST_DE
 };
 
 const char MSG_SELFTEST_BEDHEATER_EN[] PROGMEM = "Bed / Heater";
@@ -1607,6 +2058,7 @@ const char * const MSG_SELFTEST_BEDHEATER_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SELFTEST_BEDHEATER_EN,
 	MSG_SELFTEST_BEDHEATER_IT,
 	MSG_SELFTEST_BEDHEATER_ES,
+	MSG_SELFTEST_BEDHEATER_EN,
 	MSG_SELFTEST_BEDHEATER_EN
 };
 
@@ -1615,12 +2067,14 @@ const char MSG_SELFTEST_CHECK_ALLCORRECT_CZ[] PROGMEM = "Vse OK           ";
 const char MSG_SELFTEST_CHECK_ALLCORRECT_IT[] PROGMEM = "Nessun errore";
 const char MSG_SELFTEST_CHECK_ALLCORRECT_ES[] PROGMEM = "Todo bie ";
 const char MSG_SELFTEST_CHECK_ALLCORRECT_PL[] PROGMEM = "Wszystko OK      ";
+const char MSG_SELFTEST_CHECK_ALLCORRECT_DE[] PROGMEM = "Alles richtig    ";
 const char * const MSG_SELFTEST_CHECK_ALLCORRECT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SELFTEST_CHECK_ALLCORRECT_EN,
 	MSG_SELFTEST_CHECK_ALLCORRECT_CZ,
 	MSG_SELFTEST_CHECK_ALLCORRECT_IT,
 	MSG_SELFTEST_CHECK_ALLCORRECT_ES,
-	MSG_SELFTEST_CHECK_ALLCORRECT_PL
+	MSG_SELFTEST_CHECK_ALLCORRECT_PL,
+	MSG_SELFTEST_CHECK_ALLCORRECT_DE
 };
 
 const char MSG_SELFTEST_CHECK_BED_EN[] PROGMEM = "Checking bed     ";
@@ -1628,12 +2082,14 @@ const char MSG_SELFTEST_CHECK_BED_CZ[] PROGMEM = "Kontrola bed     ";
 const char MSG_SELFTEST_CHECK_BED_IT[] PROGMEM = "Verifica letto";
 const char MSG_SELFTEST_CHECK_BED_ES[] PROGMEM = "Control de cama";
 const char MSG_SELFTEST_CHECK_BED_PL[] PROGMEM = "Kontrola bed     ";
+const char MSG_SELFTEST_CHECK_BED_DE[] PROGMEM = "Pr\x81fe Bed        ";
 const char * const MSG_SELFTEST_CHECK_BED_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SELFTEST_CHECK_BED_EN,
 	MSG_SELFTEST_CHECK_BED_CZ,
 	MSG_SELFTEST_CHECK_BED_IT,
 	MSG_SELFTEST_CHECK_BED_ES,
-	MSG_SELFTEST_CHECK_BED_PL
+	MSG_SELFTEST_CHECK_BED_PL,
+	MSG_SELFTEST_CHECK_BED_DE
 };
 
 const char MSG_SELFTEST_CHECK_ENDSTOPS_EN[] PROGMEM = "Checking endstops";
@@ -1641,12 +2097,14 @@ const char MSG_SELFTEST_CHECK_ENDSTOPS_CZ[] PROGMEM = "Kontrola endstops";
 const char MSG_SELFTEST_CHECK_ENDSTOPS_IT[] PROGMEM = "Verifica finecorsa";
 const char MSG_SELFTEST_CHECK_ENDSTOPS_ES[] PROGMEM = "Cont. topes final";
 const char MSG_SELFTEST_CHECK_ENDSTOPS_PL[] PROGMEM = "Kontrola endstops";
+const char MSG_SELFTEST_CHECK_ENDSTOPS_DE[] PROGMEM = "Pr\x81fe endstops   ";
 const char * const MSG_SELFTEST_CHECK_ENDSTOPS_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SELFTEST_CHECK_ENDSTOPS_EN,
 	MSG_SELFTEST_CHECK_ENDSTOPS_CZ,
 	MSG_SELFTEST_CHECK_ENDSTOPS_IT,
 	MSG_SELFTEST_CHECK_ENDSTOPS_ES,
-	MSG_SELFTEST_CHECK_ENDSTOPS_PL
+	MSG_SELFTEST_CHECK_ENDSTOPS_PL,
+	MSG_SELFTEST_CHECK_ENDSTOPS_DE
 };
 
 const char MSG_SELFTEST_CHECK_HOTEND_EN[] PROGMEM = "Checking hotend  ";
@@ -1654,12 +2112,14 @@ const char MSG_SELFTEST_CHECK_HOTEND_CZ[] PROGMEM = "Kontrola hotend  ";
 const char MSG_SELFTEST_CHECK_HOTEND_IT[] PROGMEM = "Verifica ugello";
 const char MSG_SELFTEST_CHECK_HOTEND_ES[] PROGMEM = "Control hotend ";
 const char MSG_SELFTEST_CHECK_HOTEND_PL[] PROGMEM = "Kontrola hotend  ";
+const char MSG_SELFTEST_CHECK_HOTEND_DE[] PROGMEM = "Pr\x81fe hotend     ";
 const char * const MSG_SELFTEST_CHECK_HOTEND_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SELFTEST_CHECK_HOTEND_EN,
 	MSG_SELFTEST_CHECK_HOTEND_CZ,
 	MSG_SELFTEST_CHECK_HOTEND_IT,
 	MSG_SELFTEST_CHECK_HOTEND_ES,
-	MSG_SELFTEST_CHECK_HOTEND_PL
+	MSG_SELFTEST_CHECK_HOTEND_PL,
+	MSG_SELFTEST_CHECK_HOTEND_DE
 };
 
 const char MSG_SELFTEST_CHECK_X_EN[] PROGMEM = "Checking X axis  ";
@@ -1667,12 +2127,14 @@ const char MSG_SELFTEST_CHECK_X_CZ[] PROGMEM = "Kontrola X axis  ";
 const char MSG_SELFTEST_CHECK_X_IT[] PROGMEM = "Verifica asse X";
 const char MSG_SELFTEST_CHECK_X_ES[] PROGMEM = "Control del eje X";
 const char MSG_SELFTEST_CHECK_X_PL[] PROGMEM = "Kontrola X axis  ";
+const char MSG_SELFTEST_CHECK_X_DE[] PROGMEM = "Pr\x81fe X Achse    ";
 const char * const MSG_SELFTEST_CHECK_X_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SELFTEST_CHECK_X_EN,
 	MSG_SELFTEST_CHECK_X_CZ,
 	MSG_SELFTEST_CHECK_X_IT,
 	MSG_SELFTEST_CHECK_X_ES,
-	MSG_SELFTEST_CHECK_X_PL
+	MSG_SELFTEST_CHECK_X_PL,
+	MSG_SELFTEST_CHECK_X_DE
 };
 
 const char MSG_SELFTEST_CHECK_Y_EN[] PROGMEM = "Checking Y axis  ";
@@ -1680,12 +2142,14 @@ const char MSG_SELFTEST_CHECK_Y_CZ[] PROGMEM = "Kontrola Y axis  ";
 const char MSG_SELFTEST_CHECK_Y_IT[] PROGMEM = "Verifica asse Y";
 const char MSG_SELFTEST_CHECK_Y_ES[] PROGMEM = "Control del eje Y";
 const char MSG_SELFTEST_CHECK_Y_PL[] PROGMEM = "Kontrola Y axis  ";
+const char MSG_SELFTEST_CHECK_Y_DE[] PROGMEM = "Pr\x81fe Y Achse    ";
 const char * const MSG_SELFTEST_CHECK_Y_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SELFTEST_CHECK_Y_EN,
 	MSG_SELFTEST_CHECK_Y_CZ,
 	MSG_SELFTEST_CHECK_Y_IT,
 	MSG_SELFTEST_CHECK_Y_ES,
-	MSG_SELFTEST_CHECK_Y_PL
+	MSG_SELFTEST_CHECK_Y_PL,
+	MSG_SELFTEST_CHECK_Y_DE
 };
 
 const char MSG_SELFTEST_CHECK_Z_EN[] PROGMEM = "Checking Z axis  ";
@@ -1693,12 +2157,29 @@ const char MSG_SELFTEST_CHECK_Z_CZ[] PROGMEM = "Kontrola Z axis  ";
 const char MSG_SELFTEST_CHECK_Z_IT[] PROGMEM = "Verifica asse Z";
 const char MSG_SELFTEST_CHECK_Z_ES[] PROGMEM = "Control del eje Z";
 const char MSG_SELFTEST_CHECK_Z_PL[] PROGMEM = "Kontrola Z axis  ";
+const char MSG_SELFTEST_CHECK_Z_DE[] PROGMEM = "Pr\x81fe Z Achse    ";
 const char * const MSG_SELFTEST_CHECK_Z_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SELFTEST_CHECK_Z_EN,
 	MSG_SELFTEST_CHECK_Z_CZ,
 	MSG_SELFTEST_CHECK_Z_IT,
 	MSG_SELFTEST_CHECK_Z_ES,
-	MSG_SELFTEST_CHECK_Z_PL
+	MSG_SELFTEST_CHECK_Z_PL,
+	MSG_SELFTEST_CHECK_Z_DE
+};
+
+const char MSG_SELFTEST_COOLING_FAN_EN[] PROGMEM = "Front print fan?";;
+const char MSG_SELFTEST_COOLING_FAN_CZ[] PROGMEM = "Predni tiskovy vent?";;
+const char MSG_SELFTEST_COOLING_FAN_IT[] PROGMEM = "Vent di stampa ant.?";;
+const char MSG_SELFTEST_COOLING_FAN_ES[] PROGMEM = "Vent. al frente?";;
+const char MSG_SELFTEST_COOLING_FAN_PL[] PROGMEM = "Przodni went. druku?";;
+const char MSG_SELFTEST_COOLING_FAN_DE[] PROGMEM = "Vord. Frontluefter?";
+const char * const MSG_SELFTEST_COOLING_FAN_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_SELFTEST_COOLING_FAN_EN,
+	MSG_SELFTEST_COOLING_FAN_CZ,
+	MSG_SELFTEST_COOLING_FAN_IT,
+	MSG_SELFTEST_COOLING_FAN_ES,
+	MSG_SELFTEST_COOLING_FAN_PL,
+	MSG_SELFTEST_COOLING_FAN_DE
 };
 
 const char MSG_SELFTEST_ENDSTOP_EN[] PROGMEM = "Endstop";
@@ -1709,6 +2190,7 @@ const char * const MSG_SELFTEST_ENDSTOP_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SELFTEST_ENDSTOP_EN,
 	MSG_SELFTEST_ENDSTOP_IT,
 	MSG_SELFTEST_ENDSTOP_ES,
+	MSG_SELFTEST_ENDSTOP_EN,
 	MSG_SELFTEST_ENDSTOP_EN
 };
 
@@ -1720,29 +2202,49 @@ const char * const MSG_SELFTEST_ENDSTOPS_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SELFTEST_ENDSTOPS_EN,
 	MSG_SELFTEST_ENDSTOPS_IT,
 	MSG_SELFTEST_ENDSTOPS_ES,
+	MSG_SELFTEST_ENDSTOPS_EN,
 	MSG_SELFTEST_ENDSTOPS_EN
 };
 
 const char MSG_SELFTEST_ENDSTOP_NOTHIT_EN[] PROGMEM = "Endstop not hit";
 const char MSG_SELFTEST_ENDSTOP_NOTHIT_IT[] PROGMEM = "Finec. fuori por.";
 const char MSG_SELFTEST_ENDSTOP_NOTHIT_ES[] PROGMEM = "Tope fin. no toc.";
+const char MSG_SELFTEST_ENDSTOP_NOTHIT_DE[] PROGMEM = "End nicht getrof.";
 const char * const MSG_SELFTEST_ENDSTOP_NOTHIT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SELFTEST_ENDSTOP_NOTHIT_EN,
 	MSG_SELFTEST_ENDSTOP_NOTHIT_EN,
 	MSG_SELFTEST_ENDSTOP_NOTHIT_IT,
 	MSG_SELFTEST_ENDSTOP_NOTHIT_ES,
-	MSG_SELFTEST_ENDSTOP_NOTHIT_EN
+	MSG_SELFTEST_ENDSTOP_NOTHIT_EN,
+	MSG_SELFTEST_ENDSTOP_NOTHIT_DE
 };
 
 const char MSG_SELFTEST_ERROR_EN[] PROGMEM = "Selftest error !";
 const char MSG_SELFTEST_ERROR_IT[] PROGMEM = "Autotest negativo";
 const char MSG_SELFTEST_ERROR_ES[] PROGMEM = "Autotest error!";
+const char MSG_SELFTEST_ERROR_DE[] PROGMEM = "Selbtest Fehler!";
 const char * const MSG_SELFTEST_ERROR_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SELFTEST_ERROR_EN,
 	MSG_SELFTEST_ERROR_EN,
 	MSG_SELFTEST_ERROR_IT,
 	MSG_SELFTEST_ERROR_ES,
-	MSG_SELFTEST_ERROR_EN
+	MSG_SELFTEST_ERROR_EN,
+	MSG_SELFTEST_ERROR_DE
+};
+
+const char MSG_SELFTEST_EXTRUDER_FAN_EN[] PROGMEM = "Left hotend fan?";;
+const char MSG_SELFTEST_EXTRUDER_FAN_CZ[] PROGMEM = "Levy vent na trysce?";;
+const char MSG_SELFTEST_EXTRUDER_FAN_IT[] PROGMEM = "Vent SX sull'ugello?";;
+const char MSG_SELFTEST_EXTRUDER_FAN_ES[] PROGMEM = "Vent. en la izg?";;
+const char MSG_SELFTEST_EXTRUDER_FAN_PL[] PROGMEM = "Lewy went na dysze?";;
+const char MSG_SELFTEST_EXTRUDER_FAN_DE[] PROGMEM = "Link. Hotendluefter?";
+const char * const MSG_SELFTEST_EXTRUDER_FAN_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_SELFTEST_EXTRUDER_FAN_EN,
+	MSG_SELFTEST_EXTRUDER_FAN_CZ,
+	MSG_SELFTEST_EXTRUDER_FAN_IT,
+	MSG_SELFTEST_EXTRUDER_FAN_ES,
+	MSG_SELFTEST_EXTRUDER_FAN_PL,
+	MSG_SELFTEST_EXTRUDER_FAN_DE
 };
 
 const char MSG_SELFTEST_FAILED_EN[] PROGMEM = "Selftest failed  ";
@@ -1750,12 +2252,59 @@ const char MSG_SELFTEST_FAILED_CZ[] PROGMEM = "Selftest selhal  ";
 const char MSG_SELFTEST_FAILED_IT[] PROGMEM = "Autotest fallito";
 const char MSG_SELFTEST_FAILED_ES[] PROGMEM = "Autotest fallado";
 const char MSG_SELFTEST_FAILED_PL[] PROGMEM = "Selftest nieudany";
+const char MSG_SELFTEST_FAILED_DE[] PROGMEM = "Selbtest fehlgeschlg";
 const char * const MSG_SELFTEST_FAILED_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SELFTEST_FAILED_EN,
 	MSG_SELFTEST_FAILED_CZ,
 	MSG_SELFTEST_FAILED_IT,
 	MSG_SELFTEST_FAILED_ES,
-	MSG_SELFTEST_FAILED_PL
+	MSG_SELFTEST_FAILED_PL,
+	MSG_SELFTEST_FAILED_DE
+};
+
+const char MSG_SELFTEST_FAN_EN[] PROGMEM = "Fan test";;
+const char MSG_SELFTEST_FAN_CZ[] PROGMEM = "Test ventilatoru";;
+const char MSG_SELFTEST_FAN_IT[] PROGMEM = "Prova del ventilator";;
+const char MSG_SELFTEST_FAN_ES[] PROGMEM = "Test del ventilador";;
+const char MSG_SELFTEST_FAN_PL[] PROGMEM = "Test wentylatora";;
+const char MSG_SELFTEST_FAN_DE[] PROGMEM = "Lueftertest";
+const char * const MSG_SELFTEST_FAN_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_SELFTEST_FAN_EN,
+	MSG_SELFTEST_FAN_CZ,
+	MSG_SELFTEST_FAN_IT,
+	MSG_SELFTEST_FAN_ES,
+	MSG_SELFTEST_FAN_PL,
+	MSG_SELFTEST_FAN_DE
+};
+
+const char MSG_SELFTEST_FAN_NO_EN[] PROGMEM = "Not spinning";;
+const char MSG_SELFTEST_FAN_NO_CZ[] PROGMEM = "Netoci se";;
+const char MSG_SELFTEST_FAN_NO_IT[] PROGMEM = "Non si gira";;
+const char MSG_SELFTEST_FAN_NO_ES[] PROGMEM = "Ventilador no gira";;
+const char MSG_SELFTEST_FAN_NO_PL[] PROGMEM = "Nekreci sie";;
+const char MSG_SELFTEST_FAN_NO_DE[] PROGMEM = "Dreht nicht";
+const char * const MSG_SELFTEST_FAN_NO_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_SELFTEST_FAN_NO_EN,
+	MSG_SELFTEST_FAN_NO_CZ,
+	MSG_SELFTEST_FAN_NO_IT,
+	MSG_SELFTEST_FAN_NO_ES,
+	MSG_SELFTEST_FAN_NO_PL,
+	MSG_SELFTEST_FAN_NO_DE
+};
+
+const char MSG_SELFTEST_FAN_YES_EN[] PROGMEM = "Spinning";;
+const char MSG_SELFTEST_FAN_YES_CZ[] PROGMEM = "Toci se";;
+const char MSG_SELFTEST_FAN_YES_IT[] PROGMEM = "Gira";;
+const char MSG_SELFTEST_FAN_YES_ES[] PROGMEM = "Ventilador gira";;
+const char MSG_SELFTEST_FAN_YES_PL[] PROGMEM = "Kreci sie";;
+const char MSG_SELFTEST_FAN_YES_DE[] PROGMEM = "Dreht";
+const char * const MSG_SELFTEST_FAN_YES_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_SELFTEST_FAN_YES_EN,
+	MSG_SELFTEST_FAN_YES_CZ,
+	MSG_SELFTEST_FAN_YES_IT,
+	MSG_SELFTEST_FAN_YES_ES,
+	MSG_SELFTEST_FAN_YES_PL,
+	MSG_SELFTEST_FAN_YES_DE
 };
 
 const char MSG_SELFTEST_HEATERTHERMISTOR_EN[] PROGMEM = "Heater/Thermistor";
@@ -1766,6 +2315,7 @@ const char * const MSG_SELFTEST_HEATERTHERMISTOR_LANG_TABLE[LANG_NUM] PROGMEM =
 	MSG_SELFTEST_HEATERTHERMISTOR_EN,
 	MSG_SELFTEST_HEATERTHERMISTOR_IT,
 	MSG_SELFTEST_HEATERTHERMISTOR_ES,
+	MSG_SELFTEST_HEATERTHERMISTOR_EN,
 	MSG_SELFTEST_HEATERTHERMISTOR_EN
 };
 
@@ -1777,7 +2327,8 @@ const char * const MSG_SELFTEST_MOTOR_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SELFTEST_MOTOR_EN,
 	MSG_SELFTEST_MOTOR_IT,
 	MSG_SELFTEST_MOTOR_EN,
-	MSG_SELFTEST_MOTOR_PL
+	MSG_SELFTEST_MOTOR_PL,
+	MSG_SELFTEST_MOTOR_EN
 };
 
 const char MSG_SELFTEST_NOTCONNECTED_EN[] PROGMEM = "Not connected";
@@ -1785,22 +2336,26 @@ const char MSG_SELFTEST_NOTCONNECTED_CZ[] PROGMEM = "Nezapojeno    ";
 const char MSG_SELFTEST_NOTCONNECTED_IT[] PROGMEM = "Non connesso";
 const char MSG_SELFTEST_NOTCONNECTED_ES[] PROGMEM = "No hay conexion  ";
 const char MSG_SELFTEST_NOTCONNECTED_PL[] PROGMEM = "Nie podlaczono   ";
+const char MSG_SELFTEST_NOTCONNECTED_DE[] PROGMEM = "Nicht angeschlossen";
 const char * const MSG_SELFTEST_NOTCONNECTED_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SELFTEST_NOTCONNECTED_EN,
 	MSG_SELFTEST_NOTCONNECTED_CZ,
 	MSG_SELFTEST_NOTCONNECTED_IT,
 	MSG_SELFTEST_NOTCONNECTED_ES,
-	MSG_SELFTEST_NOTCONNECTED_PL
+	MSG_SELFTEST_NOTCONNECTED_PL,
+	MSG_SELFTEST_NOTCONNECTED_DE
 };
 
 const char MSG_SELFTEST_OK_EN[] PROGMEM = "Self test OK";
 const char MSG_SELFTEST_OK_IT[] PROGMEM = "Autotest OK";
+const char MSG_SELFTEST_OK_DE[] PROGMEM = "Selbsttest OK";
 const char * const MSG_SELFTEST_OK_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SELFTEST_OK_EN,
 	MSG_SELFTEST_OK_EN,
 	MSG_SELFTEST_OK_IT,
 	MSG_SELFTEST_OK_EN,
-	MSG_SELFTEST_OK_EN
+	MSG_SELFTEST_OK_EN,
+	MSG_SELFTEST_OK_DE
 };
 
 const char MSG_SELFTEST_PLEASECHECK_EN[] PROGMEM = "Please check :";
@@ -1808,23 +2363,27 @@ const char MSG_SELFTEST_PLEASECHECK_CZ[] PROGMEM = "Zkontrolujte :";
 const char MSG_SELFTEST_PLEASECHECK_IT[] PROGMEM = "Verificare:";
 const char MSG_SELFTEST_PLEASECHECK_ES[] PROGMEM = "Controla :";
 const char MSG_SELFTEST_PLEASECHECK_PL[] PROGMEM = "Skontroluj :";
+const char MSG_SELFTEST_PLEASECHECK_DE[] PROGMEM = "Bitte pruefe:";
 const char * const MSG_SELFTEST_PLEASECHECK_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SELFTEST_PLEASECHECK_EN,
 	MSG_SELFTEST_PLEASECHECK_CZ,
 	MSG_SELFTEST_PLEASECHECK_IT,
 	MSG_SELFTEST_PLEASECHECK_ES,
-	MSG_SELFTEST_PLEASECHECK_PL
+	MSG_SELFTEST_PLEASECHECK_PL,
+	MSG_SELFTEST_PLEASECHECK_DE
 };
 
 const char MSG_SELFTEST_START_EN[] PROGMEM = "Self test start  ";
 const char MSG_SELFTEST_START_IT[] PROGMEM = "Avvia autotest";
 const char MSG_SELFTEST_START_ES[] PROGMEM = "Autotest salida";
+const char MSG_SELFTEST_START_DE[] PROGMEM = "Selbsttest start ";
 const char * const MSG_SELFTEST_START_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SELFTEST_START_EN,
 	MSG_SELFTEST_START_EN,
 	MSG_SELFTEST_START_IT,
 	MSG_SELFTEST_START_ES,
-	MSG_SELFTEST_START_EN
+	MSG_SELFTEST_START_EN,
+	MSG_SELFTEST_START_DE
 };
 
 const char MSG_SELFTEST_WIRINGERROR_EN[] PROGMEM = "Wiring error";
@@ -1832,12 +2391,14 @@ const char MSG_SELFTEST_WIRINGERROR_CZ[] PROGMEM = "Chyba zapojeni";
 const char MSG_SELFTEST_WIRINGERROR_IT[] PROGMEM = "Errore cablaggio";
 const char MSG_SELFTEST_WIRINGERROR_ES[] PROGMEM = "Error de conexion";
 const char MSG_SELFTEST_WIRINGERROR_PL[] PROGMEM = "Blad polaczenia";
+const char MSG_SELFTEST_WIRINGERROR_DE[] PROGMEM = "Verdrahtungfehler";
 const char * const MSG_SELFTEST_WIRINGERROR_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SELFTEST_WIRINGERROR_EN,
 	MSG_SELFTEST_WIRINGERROR_CZ,
 	MSG_SELFTEST_WIRINGERROR_IT,
 	MSG_SELFTEST_WIRINGERROR_ES,
-	MSG_SELFTEST_WIRINGERROR_PL
+	MSG_SELFTEST_WIRINGERROR_PL,
+	MSG_SELFTEST_WIRINGERROR_DE
 };
 
 const char MSG_SERIAL_ERROR_MENU_STRUCTURE_EN[] PROGMEM = "Error in menu structure";
@@ -1848,14 +2409,16 @@ const char * const MSG_SERIAL_ERROR_MENU_STRUCTURE_LANG_TABLE[1] PROGMEM = {
 const char MSG_SETTINGS_EN[] PROGMEM = "Settings";
 const char MSG_SETTINGS_CZ[] PROGMEM = "Nastaveni";
 const char MSG_SETTINGS_IT[] PROGMEM = "Impostazioni";
-const char MSG_SETTINGS_ES[] PROGMEM = "Ajuste";
+const char MSG_SETTINGS_ES[] PROGMEM = "Configuracion";
 const char MSG_SETTINGS_PL[] PROGMEM = "Ustawienia";
+const char MSG_SETTINGS_DE[] PROGMEM = "Einstellungen";
 const char * const MSG_SETTINGS_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SETTINGS_EN,
 	MSG_SETTINGS_CZ,
 	MSG_SETTINGS_IT,
 	MSG_SETTINGS_ES,
-	MSG_SETTINGS_PL
+	MSG_SETTINGS_PL,
+	MSG_SETTINGS_DE
 };
 
 const char MSG_SET_HOME_OFFSETS_EN[] PROGMEM = "Set home offsets";
@@ -1873,25 +2436,29 @@ const char MSG_SHOW_END_STOPS_CZ[] PROGMEM = "Stav konc. spin.";
 const char MSG_SHOW_END_STOPS_IT[] PROGMEM = "Stato finecorsa";
 const char MSG_SHOW_END_STOPS_ES[] PROGMEM = "Ensena tope final";
 const char MSG_SHOW_END_STOPS_PL[] PROGMEM = "Pokaz krancowki";
+const char MSG_SHOW_END_STOPS_DE[] PROGMEM = "Anzeigen endstops";
 const char * const MSG_SHOW_END_STOPS_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SHOW_END_STOPS_EN,
 	MSG_SHOW_END_STOPS_CZ,
 	MSG_SHOW_END_STOPS_IT,
 	MSG_SHOW_END_STOPS_ES,
-	MSG_SHOW_END_STOPS_PL
+	MSG_SHOW_END_STOPS_PL,
+	MSG_SHOW_END_STOPS_DE
 };
 
 const char MSG_SILENT_MODE_OFF_EN[] PROGMEM = "Mode [high power]";
 const char MSG_SILENT_MODE_OFF_CZ[] PROGMEM = "Mod  [vys. vykon]";
-const char MSG_SILENT_MODE_OFF_IT[] PROGMEM = "Mode [prestante]";
-const char MSG_SILENT_MODE_OFF_ES[] PROGMEM = "Modo [mas fuerza]";
+const char MSG_SILENT_MODE_OFF_IT[] PROGMEM = "Mode      [forte]";
+const char MSG_SILENT_MODE_OFF_ES[] PROGMEM = "Modo [rend.pleno]";
 const char MSG_SILENT_MODE_OFF_PL[] PROGMEM = "Mod [w wydajnosc]";
+const char MSG_SILENT_MODE_OFF_DE[] PROGMEM = "Mode [Hohe Leist]";
 const char * const MSG_SILENT_MODE_OFF_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SILENT_MODE_OFF_EN,
 	MSG_SILENT_MODE_OFF_CZ,
 	MSG_SILENT_MODE_OFF_IT,
 	MSG_SILENT_MODE_OFF_ES,
-	MSG_SILENT_MODE_OFF_PL
+	MSG_SILENT_MODE_OFF_PL,
+	MSG_SILENT_MODE_OFF_DE
 };
 
 const char MSG_SILENT_MODE_ON_EN[] PROGMEM = "Mode     [silent]";
@@ -1899,12 +2466,14 @@ const char MSG_SILENT_MODE_ON_CZ[] PROGMEM = "Mod       [tichy]";
 const char MSG_SILENT_MODE_ON_IT[] PROGMEM = "Modo [silenzioso]";
 const char MSG_SILENT_MODE_ON_ES[] PROGMEM = "Modo   [silencio]";
 const char MSG_SILENT_MODE_ON_PL[] PROGMEM = "Mod       [cichy]";
+const char MSG_SILENT_MODE_ON_DE[] PROGMEM = "Mode     [leise]";
 const char * const MSG_SILENT_MODE_ON_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SILENT_MODE_ON_EN,
 	MSG_SILENT_MODE_ON_CZ,
 	MSG_SILENT_MODE_ON_IT,
 	MSG_SILENT_MODE_ON_ES,
-	MSG_SILENT_MODE_ON_PL
+	MSG_SILENT_MODE_ON_PL,
+	MSG_SILENT_MODE_ON_DE
 };
 
 const char MSG_SOFTWARE_RESET_EN[] PROGMEM = " Software Reset";
@@ -1917,12 +2486,19 @@ const char MSG_SPEED_CZ[] PROGMEM = "Rychlost";
 const char MSG_SPEED_IT[] PROGMEM = "Velocita";
 const char MSG_SPEED_ES[] PROGMEM = "Velocidad";
 const char MSG_SPEED_PL[] PROGMEM = "Predkosc";
+const char MSG_SPEED_DE[] PROGMEM = "Geschwindigkeit";
 const char * const MSG_SPEED_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SPEED_EN,
 	MSG_SPEED_CZ,
 	MSG_SPEED_IT,
 	MSG_SPEED_ES,
-	MSG_SPEED_PL
+	MSG_SPEED_PL,
+	MSG_SPEED_DE
+};
+
+const char MSG_STACK_ERROR_EN[] PROGMEM = "Error - static memory has been overwritten";
+const char * const MSG_STACK_ERROR_LANG_TABLE[1] PROGMEM = {
+	MSG_STACK_ERROR_EN
 };
 
 const char MSG_STATISTICS_EN[] PROGMEM = "Statistics  ";
@@ -1930,12 +2506,14 @@ const char MSG_STATISTICS_CZ[] PROGMEM = "Statistika  ";
 const char MSG_STATISTICS_IT[] PROGMEM = "Statistiche";
 const char MSG_STATISTICS_ES[] PROGMEM = "Estadistica  ";
 const char MSG_STATISTICS_PL[] PROGMEM = "Statystyka  ";
+const char MSG_STATISTICS_DE[] PROGMEM = "Statistiken ";
 const char * const MSG_STATISTICS_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_STATISTICS_EN,
 	MSG_STATISTICS_CZ,
 	MSG_STATISTICS_IT,
 	MSG_STATISTICS_ES,
-	MSG_STATISTICS_PL
+	MSG_STATISTICS_PL,
+	MSG_STATISTICS_DE
 };
 
 const char MSG_STATS_FILAMENTUSED_EN[] PROGMEM = "Filament used:  ";
@@ -1943,12 +2521,14 @@ const char MSG_STATS_FILAMENTUSED_CZ[] PROGMEM = "Filament :  ";
 const char MSG_STATS_FILAMENTUSED_IT[] PROGMEM = "Filamento usato:";
 const char MSG_STATS_FILAMENTUSED_ES[] PROGMEM = "Filamento :  ";
 const char MSG_STATS_FILAMENTUSED_PL[] PROGMEM = "Filament :  ";
+const char MSG_STATS_FILAMENTUSED_DE[] PROGMEM = "Filamentverbrauch:";
 const char * const MSG_STATS_FILAMENTUSED_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_STATS_FILAMENTUSED_EN,
 	MSG_STATS_FILAMENTUSED_CZ,
 	MSG_STATS_FILAMENTUSED_IT,
 	MSG_STATS_FILAMENTUSED_ES,
-	MSG_STATS_FILAMENTUSED_PL
+	MSG_STATS_FILAMENTUSED_PL,
+	MSG_STATS_FILAMENTUSED_DE
 };
 
 const char MSG_STATS_PRINTTIME_EN[] PROGMEM = "Print time:  ";
@@ -1956,12 +2536,14 @@ const char MSG_STATS_PRINTTIME_CZ[] PROGMEM = "Cas tisku :  ";
 const char MSG_STATS_PRINTTIME_IT[] PROGMEM = "Tempo di stampa:";
 const char MSG_STATS_PRINTTIME_ES[] PROGMEM = "Tiempo de imp.:";
 const char MSG_STATS_PRINTTIME_PL[] PROGMEM = "Czas druku :  ";
+const char MSG_STATS_PRINTTIME_DE[] PROGMEM = "Druckzeit:  ";
 const char * const MSG_STATS_PRINTTIME_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_STATS_PRINTTIME_EN,
 	MSG_STATS_PRINTTIME_CZ,
 	MSG_STATS_PRINTTIME_IT,
 	MSG_STATS_PRINTTIME_ES,
-	MSG_STATS_PRINTTIME_PL
+	MSG_STATS_PRINTTIME_PL,
+	MSG_STATS_PRINTTIME_DE
 };
 
 const char MSG_STATS_TOTALFILAMENT_EN[] PROGMEM = "Total filament :";
@@ -1969,12 +2551,14 @@ const char MSG_STATS_TOTALFILAMENT_CZ[] PROGMEM = "Filament celkem :";
 const char MSG_STATS_TOTALFILAMENT_IT[] PROGMEM = "Filamento tot:";
 const char MSG_STATS_TOTALFILAMENT_ES[] PROGMEM = "Filamento total:";
 const char MSG_STATS_TOTALFILAMENT_PL[] PROGMEM = "Filament lacznie :";
+const char MSG_STATS_TOTALFILAMENT_DE[] PROGMEM = "Totales Filament:";
 const char * const MSG_STATS_TOTALFILAMENT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_STATS_TOTALFILAMENT_EN,
 	MSG_STATS_TOTALFILAMENT_CZ,
 	MSG_STATS_TOTALFILAMENT_IT,
 	MSG_STATS_TOTALFILAMENT_ES,
-	MSG_STATS_TOTALFILAMENT_PL
+	MSG_STATS_TOTALFILAMENT_PL,
+	MSG_STATS_TOTALFILAMENT_DE
 };
 
 const char MSG_STATS_TOTALPRINTTIME_EN[] PROGMEM = "Total print time :";
@@ -1982,12 +2566,14 @@ const char MSG_STATS_TOTALPRINTTIME_CZ[] PROGMEM = "Celkovy cas :";
 const char MSG_STATS_TOTALPRINTTIME_IT[] PROGMEM = "Tempo stampa tot:";
 const char MSG_STATS_TOTALPRINTTIME_ES[] PROGMEM = "Tiempo total :";
 const char MSG_STATS_TOTALPRINTTIME_PL[] PROGMEM = "Czas calkowity :";
+const char MSG_STATS_TOTALPRINTTIME_DE[] PROGMEM = "Totale Druckzeit:";
 const char * const MSG_STATS_TOTALPRINTTIME_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_STATS_TOTALPRINTTIME_EN,
 	MSG_STATS_TOTALPRINTTIME_CZ,
 	MSG_STATS_TOTALPRINTTIME_IT,
 	MSG_STATS_TOTALPRINTTIME_ES,
-	MSG_STATS_TOTALPRINTTIME_PL
+	MSG_STATS_TOTALPRINTTIME_PL,
+	MSG_STATS_TOTALPRINTTIME_DE
 };
 
 const char MSG_STEPPER_TOO_HIGH_EN[] PROGMEM = "Steprate too high: ";
@@ -1998,12 +2584,14 @@ const char * const MSG_STEPPER_TOO_HIGH_LANG_TABLE[1] PROGMEM = {
 const char MSG_STOPPED_EN[] PROGMEM = "STOPPED. ";
 const char MSG_STOPPED_IT[] PROGMEM = "ARRESTATO.";
 const char MSG_STOPPED_ES[] PROGMEM = "PARADA";
+const char MSG_STOPPED_DE[] PROGMEM = "GESTOPPT. ";
 const char * const MSG_STOPPED_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_STOPPED_EN,
 	MSG_STOPPED_EN,
 	MSG_STOPPED_IT,
 	MSG_STOPPED_ES,
-	MSG_STOPPED_EN
+	MSG_STOPPED_EN,
+	MSG_STOPPED_DE
 };
 
 const char MSG_STOP_PRINT_EN[] PROGMEM = "Stop print";
@@ -2011,12 +2599,14 @@ const char MSG_STOP_PRINT_CZ[] PROGMEM = "Zastavit tisk";
 const char MSG_STOP_PRINT_IT[] PROGMEM = "Arresta stampa";
 const char MSG_STOP_PRINT_ES[] PROGMEM = "Detener impresion";
 const char MSG_STOP_PRINT_PL[] PROGMEM = "Zatrzymac druk";
+const char MSG_STOP_PRINT_DE[] PROGMEM = "Druck halten";
 const char * const MSG_STOP_PRINT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_STOP_PRINT_EN,
 	MSG_STOP_PRINT_CZ,
 	MSG_STOP_PRINT_IT,
 	MSG_STOP_PRINT_ES,
-	MSG_STOP_PRINT_PL
+	MSG_STOP_PRINT_PL,
+	MSG_STOP_PRINT_DE
 };
 
 const char MSG_STORE_EPROM_EN[] PROGMEM = "Store memory";
@@ -2026,48 +2616,56 @@ const char * const MSG_STORE_EPROM_LANG_TABLE[1] PROGMEM = {
 
 const char MSG_SUPPORT_EN[] PROGMEM = "Support";
 const char MSG_SUPPORT_CZ[] PROGMEM = "Podpora";
+const char MSG_SUPPORT_ES[] PROGMEM = "Soporte";
 const char MSG_SUPPORT_PL[] PROGMEM = "Pomoc";
 const char * const MSG_SUPPORT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SUPPORT_EN,
 	MSG_SUPPORT_CZ,
 	MSG_SUPPORT_EN,
-	MSG_SUPPORT_EN,
-	MSG_SUPPORT_PL
+	MSG_SUPPORT_ES,
+	MSG_SUPPORT_PL,
+	MSG_SUPPORT_EN
 };
 
 const char MSG_SWITCH_PS_OFF_EN[] PROGMEM = "Switch power off";
 const char MSG_SWITCH_PS_OFF_CZ[] PROGMEM = "Zapnout zdroj";
 const char MSG_SWITCH_PS_OFF_PL[] PROGMEM = "Zapnout zdroj";
+const char MSG_SWITCH_PS_OFF_DE[] PROGMEM = "Netzteil AUS";
 const char * const MSG_SWITCH_PS_OFF_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SWITCH_PS_OFF_EN,
 	MSG_SWITCH_PS_OFF_CZ,
 	MSG_SWITCH_PS_OFF_EN,
 	MSG_SWITCH_PS_OFF_EN,
-	MSG_SWITCH_PS_OFF_PL
+	MSG_SWITCH_PS_OFF_PL,
+	MSG_SWITCH_PS_OFF_DE
 };
 
 const char MSG_SWITCH_PS_ON_EN[] PROGMEM = "Switch power on";
 const char MSG_SWITCH_PS_ON_CZ[] PROGMEM = "Vypnout zdroj";
 const char MSG_SWITCH_PS_ON_PL[] PROGMEM = "Vypnout zdroj";
+const char MSG_SWITCH_PS_ON_DE[] PROGMEM = "Netzteil EIN";
 const char * const MSG_SWITCH_PS_ON_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SWITCH_PS_ON_EN,
 	MSG_SWITCH_PS_ON_CZ,
 	MSG_SWITCH_PS_ON_EN,
 	MSG_SWITCH_PS_ON_EN,
-	MSG_SWITCH_PS_ON_PL
+	MSG_SWITCH_PS_ON_PL,
+	MSG_SWITCH_PS_ON_DE
 };
 
 const char MSG_TAKE_EFFECT_EN[] PROGMEM = " for take effect";
 const char MSG_TAKE_EFFECT_CZ[] PROGMEM = " pro projeveni zmen";
 const char MSG_TAKE_EFFECT_IT[] PROGMEM = " per attualizzare";
-const char MSG_TAKE_EFFECT_ES[] PROGMEM = "para tomar efecto";
-const char MSG_TAKE_EFFECT_PL[] PROGMEM = "wprow. zmian";
+const char MSG_TAKE_EFFECT_ES[] PROGMEM = " para aplicar cambios";
+const char MSG_TAKE_EFFECT_PL[] PROGMEM = " wprow. zmian";
+const char MSG_TAKE_EFFECT_DE[] PROGMEM = " um wirksam zu sein";
 const char * const MSG_TAKE_EFFECT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_TAKE_EFFECT_EN,
 	MSG_TAKE_EFFECT_CZ,
 	MSG_TAKE_EFFECT_IT,
 	MSG_TAKE_EFFECT_ES,
-	MSG_TAKE_EFFECT_PL
+	MSG_TAKE_EFFECT_PL,
+	MSG_TAKE_EFFECT_DE
 };
 
 const char MSG_TEMPERATURE_EN[] PROGMEM = "Temperature";
@@ -2075,12 +2673,14 @@ const char MSG_TEMPERATURE_CZ[] PROGMEM = "Teplota";
 const char MSG_TEMPERATURE_IT[] PROGMEM = "Temperatura";
 const char MSG_TEMPERATURE_ES[] PROGMEM = "Temperatura";
 const char MSG_TEMPERATURE_PL[] PROGMEM = "Temperatura";
+const char MSG_TEMPERATURE_DE[] PROGMEM = "Temperatur";
 const char * const MSG_TEMPERATURE_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_TEMPERATURE_EN,
 	MSG_TEMPERATURE_CZ,
 	MSG_TEMPERATURE_IT,
 	MSG_TEMPERATURE_ES,
-	MSG_TEMPERATURE_PL
+	MSG_TEMPERATURE_PL,
+	MSG_TEMPERATURE_DE
 };
 
 const char MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF_EN[] PROGMEM = "SD card [normal]";
@@ -2090,7 +2690,8 @@ const char * const MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF_LANG_TABLE[LANG_NUM]
 	MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF_EN,
 	MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF_EN,
 	MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF_EN,
-	MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF_PL
+	MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF_PL,
+	MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF_EN
 };
 
 const char MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON_EN[] PROGMEM = "SD card [FlshAir]";
@@ -2100,7 +2701,8 @@ const char * const MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON_LANG_TABLE[LANG_NUM] P
 	MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON_EN,
 	MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON_EN,
 	MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON_EN,
-	MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON_PL
+	MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON_PL,
+	MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON_EN
 };
 
 const char MSG_TUNE_EN[] PROGMEM = "Tune";
@@ -2108,12 +2710,14 @@ const char MSG_TUNE_CZ[] PROGMEM = "Ladit";
 const char MSG_TUNE_IT[] PROGMEM = "Regola";
 const char MSG_TUNE_ES[] PROGMEM = "Ajustar";
 const char MSG_TUNE_PL[] PROGMEM = "Nastroic";
+const char MSG_TUNE_DE[] PROGMEM = "Feineinstellen";
 const char * const MSG_TUNE_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_TUNE_EN,
 	MSG_TUNE_CZ,
 	MSG_TUNE_IT,
 	MSG_TUNE_ES,
-	MSG_TUNE_PL
+	MSG_TUNE_PL,
+	MSG_TUNE_DE
 };
 
 const char MSG_UNKNOWN_COMMAND_EN[] PROGMEM = "Unknown command: \"";
@@ -2121,17 +2725,34 @@ const char * const MSG_UNKNOWN_COMMAND_LANG_TABLE[1] PROGMEM = {
 	MSG_UNKNOWN_COMMAND_EN
 };
 
+const char MSG_UNLOADING_FILAMENT_EN[] PROGMEM = "Unloading filament";
+const char MSG_UNLOADING_FILAMENT_CZ[] PROGMEM = "Vysouvam filament";
+const char MSG_UNLOADING_FILAMENT_IT[] PROGMEM = "Rilasc. filamento";
+const char MSG_UNLOADING_FILAMENT_ES[] PROGMEM = "Soltando filamento";
+const char MSG_UNLOADING_FILAMENT_PL[] PROGMEM = "Wysuwam filament";
+const char MSG_UNLOADING_FILAMENT_DE[] PROGMEM = "Filam. auswerfen";
+const char * const MSG_UNLOADING_FILAMENT_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_UNLOADING_FILAMENT_EN,
+	MSG_UNLOADING_FILAMENT_CZ,
+	MSG_UNLOADING_FILAMENT_IT,
+	MSG_UNLOADING_FILAMENT_ES,
+	MSG_UNLOADING_FILAMENT_PL,
+	MSG_UNLOADING_FILAMENT_DE
+};
+
 const char MSG_UNLOAD_FILAMENT_EN[] PROGMEM = "Unload filament";
 const char MSG_UNLOAD_FILAMENT_CZ[] PROGMEM = "Vyjmout filament";
 const char MSG_UNLOAD_FILAMENT_IT[] PROGMEM = "Scarica filamento";
-const char MSG_UNLOAD_FILAMENT_ES[] PROGMEM = "Sacar filamento";
+const char MSG_UNLOAD_FILAMENT_ES[] PROGMEM = "Soltar filamento";
 const char MSG_UNLOAD_FILAMENT_PL[] PROGMEM = "Wyjac filament";
+const char MSG_UNLOAD_FILAMENT_DE[] PROGMEM = "Entnehm filament";
 const char * const MSG_UNLOAD_FILAMENT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_UNLOAD_FILAMENT_EN,
 	MSG_UNLOAD_FILAMENT_CZ,
 	MSG_UNLOAD_FILAMENT_IT,
 	MSG_UNLOAD_FILAMENT_ES,
-	MSG_UNLOAD_FILAMENT_PL
+	MSG_UNLOAD_FILAMENT_PL,
+	MSG_UNLOAD_FILAMENT_DE
 };
 
 const char MSG_USB_PRINTING_EN[] PROGMEM = "USB printing  ";
@@ -2144,18 +2765,21 @@ const char * const MSG_USB_PRINTING_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_USB_PRINTING_CZ,
 	MSG_USB_PRINTING_IT,
 	MSG_USB_PRINTING_ES,
-	MSG_USB_PRINTING_PL
+	MSG_USB_PRINTING_PL,
+	MSG_USB_PRINTING_EN
 };
 
 const char MSG_USERWAIT_EN[] PROGMEM = "Wait for user...";
 const char MSG_USERWAIT_IT[] PROGMEM = "Attendendo utente";
 const char MSG_USERWAIT_ES[] PROGMEM = "Esperando ordenes";
+const char MSG_USERWAIT_DE[] PROGMEM = "Warte auf user...";
 const char * const MSG_USERWAIT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_USERWAIT_EN,
 	MSG_USERWAIT_EN,
 	MSG_USERWAIT_IT,
 	MSG_USERWAIT_ES,
-	MSG_USERWAIT_EN
+	MSG_USERWAIT_EN,
+	MSG_USERWAIT_DE
 };
 
 const char MSG_VMIN_EN[] PROGMEM = "Vmin";
@@ -2178,17 +2802,34 @@ const char * const MSG_VTRAV_MIN_LANG_TABLE[1] PROGMEM = {
 	MSG_VTRAV_MIN_EN
 };
 
+const char MSG_WAITING_TEMP_EN[] PROGMEM = "Waiting for nozzle and bed cooling";
+const char MSG_WAITING_TEMP_CZ[] PROGMEM = "Cekani na zchladnuti trysky a podlozky.";
+const char MSG_WAITING_TEMP_IT[] PROGMEM = "In attesa del raffreddamento della testina e del piatto";
+const char MSG_WAITING_TEMP_ES[] PROGMEM = "Esperando enfriamiento de la cama y del extrusor.";
+const char MSG_WAITING_TEMP_PL[] PROGMEM = "Oczekiwanie na wychlodzenie dyszy i podkladki.";
+const char MSG_WAITING_TEMP_DE[] PROGMEM = "Warten auf Abkuehlung von Heater und Bed.";
+const char * const MSG_WAITING_TEMP_LANG_TABLE[LANG_NUM] PROGMEM = {
+	MSG_WAITING_TEMP_EN,
+	MSG_WAITING_TEMP_CZ,
+	MSG_WAITING_TEMP_IT,
+	MSG_WAITING_TEMP_ES,
+	MSG_WAITING_TEMP_PL,
+	MSG_WAITING_TEMP_DE
+};
+
 const char MSG_WATCH_EN[] PROGMEM = "Info screen";
 const char MSG_WATCH_CZ[] PROGMEM = "Informace";
 const char MSG_WATCH_IT[] PROGMEM = "Schermata info";
 const char MSG_WATCH_ES[] PROGMEM = "Monitorizar";
 const char MSG_WATCH_PL[] PROGMEM = "Informacje";
+const char MSG_WATCH_DE[] PROGMEM = "Information";
 const char * const MSG_WATCH_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_WATCH_EN,
 	MSG_WATCH_CZ,
 	MSG_WATCH_IT,
 	MSG_WATCH_ES,
-	MSG_WATCH_PL
+	MSG_WATCH_PL,
+	MSG_WATCH_DE
 };
 
 const char MSG_WATCHDOG_RESET_EN[] PROGMEM = " Watchdog Reset";
@@ -2211,12 +2852,14 @@ const char MSG_YES_CZ[] PROGMEM = "Ano";
 const char MSG_YES_IT[] PROGMEM = "Si";
 const char MSG_YES_ES[] PROGMEM = "Si";
 const char MSG_YES_PL[] PROGMEM = "Tak";
+const char MSG_YES_DE[] PROGMEM = "Ja";
 const char * const MSG_YES_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_YES_EN,
 	MSG_YES_CZ,
 	MSG_YES_IT,
 	MSG_YES_ES,
-	MSG_YES_PL
+	MSG_YES_PL,
+	MSG_YES_DE
 };
 
 const char MSG_Y_MAX_EN[] PROGMEM = "y_max: ";
@@ -2251,15 +2894,17 @@ const char * const MSG_Z_MIN_LANG_TABLE[1] PROGMEM = {
 
 const char WELCOME_MSG_EN[] PROGMEM = CUSTOM_MENDEL_NAME " ready.";
 const char WELCOME_MSG_CZ[] PROGMEM = CUSTOM_MENDEL_NAME " ok";
-const char WELCOME_MSG_IT[] PROGMEM = CUSTOM_MENDEL_NAME "pronta.";
-const char WELCOME_MSG_ES[] PROGMEM = CUSTOM_MENDEL_NAME " lista";
+const char WELCOME_MSG_IT[] PROGMEM = CUSTOM_MENDEL_NAME " pronta.";
+const char WELCOME_MSG_ES[] PROGMEM = CUSTOM_MENDEL_NAME " prep.";
 const char WELCOME_MSG_PL[] PROGMEM = CUSTOM_MENDEL_NAME " gotowa";
+const char WELCOME_MSG_DE[] PROGMEM = CUSTOM_MENDEL_NAME " klar.";
 const char * const WELCOME_MSG_LANG_TABLE[LANG_NUM] PROGMEM = {
 	WELCOME_MSG_EN,
 	WELCOME_MSG_CZ,
 	WELCOME_MSG_IT,
 	WELCOME_MSG_ES,
-	WELCOME_MSG_PL
+	WELCOME_MSG_PL,
+	WELCOME_MSG_DE
 };
 
 

+ 58 - 1
Firmware/language_all.h

@@ -7,6 +7,7 @@
 #define LANG_ID_IT 2
 #define LANG_ID_ES 3
 #define LANG_ID_PL 4
+#define LANG_ID_DE 5
 // Language is not defined and it shall be selected from the menu.
 #define LANG_ID_FORCE_SELECTION 254
 // Language is not defined on a virgin RAMBo board.
@@ -16,7 +17,7 @@
 #define LANG_ID_DEFAULT LANG_ID_CZ
 
 // Number of languages available in the language table.
-#define LANG_NUM 5
+#define LANG_NUM 6
 
 // Currectly active language selection.
 extern unsigned char lang_selected;
@@ -104,12 +105,18 @@ extern const char* const MSG_CALIBRATE_BED_LANG_TABLE[LANG_NUM];
 #define MSG_CALIBRATE_BED LANG_TABLE_SELECT(MSG_CALIBRATE_BED_LANG_TABLE)
 extern const char* const MSG_CALIBRATE_BED_RESET_LANG_TABLE[LANG_NUM];
 #define MSG_CALIBRATE_BED_RESET LANG_TABLE_SELECT(MSG_CALIBRATE_BED_RESET_LANG_TABLE)
+extern const char* const MSG_CALIBRATE_E_LANG_TABLE[LANG_NUM];
+#define MSG_CALIBRATE_E LANG_TABLE_SELECT(MSG_CALIBRATE_E_LANG_TABLE)
 extern const char* const MSG_CARD_MENU_LANG_TABLE[LANG_NUM];
 #define MSG_CARD_MENU LANG_TABLE_SELECT(MSG_CARD_MENU_LANG_TABLE)
+extern const char* const MSG_CHANGE_EXTR_LANG_TABLE[LANG_NUM];
+#define MSG_CHANGE_EXTR LANG_TABLE_SELECT(MSG_CHANGE_EXTR_LANG_TABLE)
 extern const char* const MSG_CHANGE_SUCCESS_LANG_TABLE[LANG_NUM];
 #define MSG_CHANGE_SUCCESS LANG_TABLE_SELECT(MSG_CHANGE_SUCCESS_LANG_TABLE)
 extern const char* const MSG_CHANGING_FILAMENT_LANG_TABLE[LANG_NUM];
 #define MSG_CHANGING_FILAMENT LANG_TABLE_SELECT(MSG_CHANGING_FILAMENT_LANG_TABLE)
+extern const char* const MSG_CLEAN_NOZZLE_E_LANG_TABLE[LANG_NUM];
+#define MSG_CLEAN_NOZZLE_E LANG_TABLE_SELECT(MSG_CLEAN_NOZZLE_E_LANG_TABLE)
 extern const char* const MSG_CNG_SDCARD_LANG_TABLE[1];
 #define MSG_CNG_SDCARD LANG_TABLE_SELECT_EXPLICIT(MSG_CNG_SDCARD_LANG_TABLE, 0)
 extern const char* const MSG_CONFIGURATION_VER_LANG_TABLE[1];
@@ -118,6 +125,8 @@ extern const char* const MSG_CONFIRM_CARRIAGE_AT_THE_TOP_LANG_TABLE[LANG_NUM];
 #define MSG_CONFIRM_CARRIAGE_AT_THE_TOP LANG_TABLE_SELECT(MSG_CONFIRM_CARRIAGE_AT_THE_TOP_LANG_TABLE)
 extern const char* const MSG_CONFIRM_NOZZLE_CLEAN_LANG_TABLE[LANG_NUM];
 #define MSG_CONFIRM_NOZZLE_CLEAN LANG_TABLE_SELECT(MSG_CONFIRM_NOZZLE_CLEAN_LANG_TABLE)
+extern const char* const MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_LANG_TABLE[LANG_NUM];
+#define MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ LANG_TABLE_SELECT(MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_LANG_TABLE)
 extern const char* const MSG_CONTROL_LANG_TABLE[1];
 #define MSG_CONTROL LANG_TABLE_SELECT_EXPLICIT(MSG_CONTROL_LANG_TABLE, 0)
 extern const char* const MSG_COOLDOWN_LANG_TABLE[LANG_NUM];
@@ -160,18 +169,38 @@ extern const char* const MSG_ERR_STOPPED_LANG_TABLE[1];
 #define MSG_ERR_STOPPED LANG_TABLE_SELECT_EXPLICIT(MSG_ERR_STOPPED_LANG_TABLE, 0)
 extern const char* const MSG_EXTERNAL_RESET_LANG_TABLE[1];
 #define MSG_EXTERNAL_RESET LANG_TABLE_SELECT_EXPLICIT(MSG_EXTERNAL_RESET_LANG_TABLE, 0)
+extern const char* const MSG_E_CAL_KNOB_LANG_TABLE[LANG_NUM];
+#define MSG_E_CAL_KNOB LANG_TABLE_SELECT(MSG_E_CAL_KNOB_LANG_TABLE)
 extern const char* const MSG_Enqueing_LANG_TABLE[1];
 #define MSG_Enqueing LANG_TABLE_SELECT_EXPLICIT(MSG_Enqueing_LANG_TABLE, 0)
 extern const char* const MSG_FACTOR_LANG_TABLE[1];
 #define MSG_FACTOR LANG_TABLE_SELECT_EXPLICIT(MSG_FACTOR_LANG_TABLE, 0)
 extern const char* const MSG_FAN_SPEED_LANG_TABLE[LANG_NUM];
 #define MSG_FAN_SPEED LANG_TABLE_SELECT(MSG_FAN_SPEED_LANG_TABLE)
+extern const char* const MSG_FARM_CARD_MENU_LANG_TABLE[1];
+#define MSG_FARM_CARD_MENU LANG_TABLE_SELECT_EXPLICIT(MSG_FARM_CARD_MENU_LANG_TABLE, 0)
 extern const char* const MSG_FILAMENTCHANGE_LANG_TABLE[LANG_NUM];
 #define MSG_FILAMENTCHANGE LANG_TABLE_SELECT(MSG_FILAMENTCHANGE_LANG_TABLE)
+extern const char* const MSG_FILAMENT_CLEAN_LANG_TABLE[LANG_NUM];
+#define MSG_FILAMENT_CLEAN LANG_TABLE_SELECT(MSG_FILAMENT_CLEAN_LANG_TABLE)
+extern const char* const MSG_FILAMENT_LOADING_T0_LANG_TABLE[LANG_NUM];
+#define MSG_FILAMENT_LOADING_T0 LANG_TABLE_SELECT(MSG_FILAMENT_LOADING_T0_LANG_TABLE)
+extern const char* const MSG_FILAMENT_LOADING_T1_LANG_TABLE[LANG_NUM];
+#define MSG_FILAMENT_LOADING_T1 LANG_TABLE_SELECT(MSG_FILAMENT_LOADING_T1_LANG_TABLE)
+extern const char* const MSG_FILAMENT_LOADING_T2_LANG_TABLE[LANG_NUM];
+#define MSG_FILAMENT_LOADING_T2 LANG_TABLE_SELECT(MSG_FILAMENT_LOADING_T2_LANG_TABLE)
+extern const char* const MSG_FILAMENT_LOADING_T3_LANG_TABLE[LANG_NUM];
+#define MSG_FILAMENT_LOADING_T3 LANG_TABLE_SELECT(MSG_FILAMENT_LOADING_T3_LANG_TABLE)
 extern const char* const MSG_FILE_PRINTED_LANG_TABLE[1];
 #define MSG_FILE_PRINTED LANG_TABLE_SELECT_EXPLICIT(MSG_FILE_PRINTED_LANG_TABLE, 0)
 extern const char* const MSG_FILE_SAVED_LANG_TABLE[1];
 #define MSG_FILE_SAVED LANG_TABLE_SELECT_EXPLICIT(MSG_FILE_SAVED_LANG_TABLE, 0)
+extern const char* const MSG_FIL_ADJUSTING_LANG_TABLE[LANG_NUM];
+#define MSG_FIL_ADJUSTING LANG_TABLE_SELECT(MSG_FIL_ADJUSTING_LANG_TABLE)
+extern const char* const MSG_FIL_LOADED_CHECK_LANG_TABLE[LANG_NUM];
+#define MSG_FIL_LOADED_CHECK LANG_TABLE_SELECT(MSG_FIL_LOADED_CHECK_LANG_TABLE)
+extern const char* const MSG_FIL_TUNING_LANG_TABLE[LANG_NUM];
+#define MSG_FIL_TUNING LANG_TABLE_SELECT(MSG_FIL_TUNING_LANG_TABLE)
 extern const char* const MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_LANG_TABLE[LANG_NUM];
 #define MSG_FIND_BED_OFFSET_AND_SKEW_LINE1 LANG_TABLE_SELECT(MSG_FIND_BED_OFFSET_AND_SKEW_LINE1_LANG_TABLE)
 extern const char* const MSG_FIND_BED_OFFSET_AND_SKEW_LINE2_LANG_TABLE[LANG_NUM];
@@ -184,6 +213,8 @@ extern const char* const MSG_FLOW1_LANG_TABLE[1];
 #define MSG_FLOW1 LANG_TABLE_SELECT_EXPLICIT(MSG_FLOW1_LANG_TABLE, 0)
 extern const char* const MSG_FLOW2_LANG_TABLE[1];
 #define MSG_FLOW2 LANG_TABLE_SELECT_EXPLICIT(MSG_FLOW2_LANG_TABLE, 0)
+extern const char* const MSG_FOLLOW_CALIBRATION_FLOW_LANG_TABLE[LANG_NUM];
+#define MSG_FOLLOW_CALIBRATION_FLOW LANG_TABLE_SELECT(MSG_FOLLOW_CALIBRATION_FLOW_LANG_TABLE)
 extern const char* const MSG_FREE_MEMORY_LANG_TABLE[1];
 #define MSG_FREE_MEMORY LANG_TABLE_SELECT_EXPLICIT(MSG_FREE_MEMORY_LANG_TABLE, 0)
 extern const char* const MSG_HEATING_LANG_TABLE[LANG_NUM];
@@ -224,6 +255,8 @@ extern const char* const MSG_LOAD_EPROM_LANG_TABLE[1];
 #define MSG_LOAD_EPROM LANG_TABLE_SELECT_EXPLICIT(MSG_LOAD_EPROM_LANG_TABLE, 0)
 extern const char* const MSG_LOAD_FILAMENT_LANG_TABLE[LANG_NUM];
 #define MSG_LOAD_FILAMENT LANG_TABLE_SELECT(MSG_LOAD_FILAMENT_LANG_TABLE)
+extern const char* const MSG_LOOSE_PULLEY_LANG_TABLE[LANG_NUM];
+#define MSG_LOOSE_PULLEY LANG_TABLE_SELECT(MSG_LOOSE_PULLEY_LANG_TABLE)
 extern const char* const MSG_M104_INVALID_EXTRUDER_LANG_TABLE[1];
 #define MSG_M104_INVALID_EXTRUDER LANG_TABLE_SELECT_EXPLICIT(MSG_M104_INVALID_EXTRUDER_LANG_TABLE, 0)
 extern const char* const MSG_M105_INVALID_EXTRUDER_LANG_TABLE[1];
@@ -242,6 +275,8 @@ extern const char* const MSG_M221_INVALID_EXTRUDER_LANG_TABLE[1];
 #define MSG_M221_INVALID_EXTRUDER LANG_TABLE_SELECT_EXPLICIT(MSG_M221_INVALID_EXTRUDER_LANG_TABLE, 0)
 extern const char* const MSG_MAIN_LANG_TABLE[LANG_NUM];
 #define MSG_MAIN LANG_TABLE_SELECT(MSG_MAIN_LANG_TABLE)
+extern const char* const MSG_MARK_FIL_LANG_TABLE[LANG_NUM];
+#define MSG_MARK_FIL LANG_TABLE_SELECT(MSG_MARK_FIL_LANG_TABLE)
 extern const char* const MSG_MAX_LANG_TABLE[1];
 #define MSG_MAX LANG_TABLE_SELECT_EXPLICIT(MSG_MAX_LANG_TABLE, 0)
 extern const char* const MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1_LANG_TABLE[LANG_NUM];
@@ -302,6 +337,8 @@ extern const char* const MSG_OK_LANG_TABLE[1];
 #define MSG_OK LANG_TABLE_SELECT_EXPLICIT(MSG_OK_LANG_TABLE, 0)
 extern const char* const MSG_ON_LANG_TABLE[1];
 #define MSG_ON LANG_TABLE_SELECT_EXPLICIT(MSG_ON_LANG_TABLE, 0)
+extern const char* const MSG_PAPER_LANG_TABLE[LANG_NUM];
+#define MSG_PAPER LANG_TABLE_SELECT(MSG_PAPER_LANG_TABLE)
 extern const char* const MSG_PAUSE_PRINT_LANG_TABLE[LANG_NUM];
 #define MSG_PAUSE_PRINT LANG_TABLE_SELECT(MSG_PAUSE_PRINT_LANG_TABLE)
 extern const char* const MSG_PICK_Z_LANG_TABLE[LANG_NUM];
@@ -320,6 +357,8 @@ extern const char* const MSG_PREHEAT_NOZZLE_LANG_TABLE[LANG_NUM];
 #define MSG_PREHEAT_NOZZLE LANG_TABLE_SELECT(MSG_PREHEAT_NOZZLE_LANG_TABLE)
 extern const char* const MSG_PRESS_LANG_TABLE[LANG_NUM];
 #define MSG_PRESS LANG_TABLE_SELECT(MSG_PRESS_LANG_TABLE)
+extern const char* const MSG_PRINTER_DISCONNECTED_LANG_TABLE[1];
+#define MSG_PRINTER_DISCONNECTED LANG_TABLE_SELECT_EXPLICIT(MSG_PRINTER_DISCONNECTED_LANG_TABLE, 0)
 extern const char* const MSG_PRINT_ABORTED_LANG_TABLE[LANG_NUM];
 #define MSG_PRINT_ABORTED LANG_TABLE_SELECT(MSG_PRINT_ABORTED_LANG_TABLE)
 extern const char* const MSG_PRUSA3D_LANG_TABLE[LANG_NUM];
@@ -336,6 +375,8 @@ extern const char* const MSG_REFRESH_LANG_TABLE[1];
 #define MSG_REFRESH LANG_TABLE_SELECT_EXPLICIT(MSG_REFRESH_LANG_TABLE, 0)
 extern const char* const MSG_RESEND_LANG_TABLE[1];
 #define MSG_RESEND LANG_TABLE_SELECT_EXPLICIT(MSG_RESEND_LANG_TABLE, 0)
+extern const char* const MSG_RESET_CALIBRATE_E_LANG_TABLE[1];
+#define MSG_RESET_CALIBRATE_E LANG_TABLE_SELECT_EXPLICIT(MSG_RESET_CALIBRATE_E_LANG_TABLE, 0)
 extern const char* const MSG_RESTORE_FAILSAFE_LANG_TABLE[1];
 #define MSG_RESTORE_FAILSAFE LANG_TABLE_SELECT_EXPLICIT(MSG_RESTORE_FAILSAFE_LANG_TABLE, 0)
 extern const char* const MSG_RESUME_PRINT_LANG_TABLE[LANG_NUM];
@@ -394,6 +435,8 @@ extern const char* const MSG_SELFTEST_CHECK_Y_LANG_TABLE[LANG_NUM];
 #define MSG_SELFTEST_CHECK_Y LANG_TABLE_SELECT(MSG_SELFTEST_CHECK_Y_LANG_TABLE)
 extern const char* const MSG_SELFTEST_CHECK_Z_LANG_TABLE[LANG_NUM];
 #define MSG_SELFTEST_CHECK_Z LANG_TABLE_SELECT(MSG_SELFTEST_CHECK_Z_LANG_TABLE)
+extern const char* const MSG_SELFTEST_COOLING_FAN_LANG_TABLE[LANG_NUM];
+#define MSG_SELFTEST_COOLING_FAN LANG_TABLE_SELECT(MSG_SELFTEST_COOLING_FAN_LANG_TABLE)
 extern const char* const MSG_SELFTEST_ENDSTOP_LANG_TABLE[LANG_NUM];
 #define MSG_SELFTEST_ENDSTOP LANG_TABLE_SELECT(MSG_SELFTEST_ENDSTOP_LANG_TABLE)
 extern const char* const MSG_SELFTEST_ENDSTOPS_LANG_TABLE[LANG_NUM];
@@ -402,8 +445,16 @@ extern const char* const MSG_SELFTEST_ENDSTOP_NOTHIT_LANG_TABLE[LANG_NUM];
 #define MSG_SELFTEST_ENDSTOP_NOTHIT LANG_TABLE_SELECT(MSG_SELFTEST_ENDSTOP_NOTHIT_LANG_TABLE)
 extern const char* const MSG_SELFTEST_ERROR_LANG_TABLE[LANG_NUM];
 #define MSG_SELFTEST_ERROR LANG_TABLE_SELECT(MSG_SELFTEST_ERROR_LANG_TABLE)
+extern const char* const MSG_SELFTEST_EXTRUDER_FAN_LANG_TABLE[LANG_NUM];
+#define MSG_SELFTEST_EXTRUDER_FAN LANG_TABLE_SELECT(MSG_SELFTEST_EXTRUDER_FAN_LANG_TABLE)
 extern const char* const MSG_SELFTEST_FAILED_LANG_TABLE[LANG_NUM];
 #define MSG_SELFTEST_FAILED LANG_TABLE_SELECT(MSG_SELFTEST_FAILED_LANG_TABLE)
+extern const char* const MSG_SELFTEST_FAN_LANG_TABLE[LANG_NUM];
+#define MSG_SELFTEST_FAN LANG_TABLE_SELECT(MSG_SELFTEST_FAN_LANG_TABLE)
+extern const char* const MSG_SELFTEST_FAN_NO_LANG_TABLE[LANG_NUM];
+#define MSG_SELFTEST_FAN_NO LANG_TABLE_SELECT(MSG_SELFTEST_FAN_NO_LANG_TABLE)
+extern const char* const MSG_SELFTEST_FAN_YES_LANG_TABLE[LANG_NUM];
+#define MSG_SELFTEST_FAN_YES LANG_TABLE_SELECT(MSG_SELFTEST_FAN_YES_LANG_TABLE)
 extern const char* const MSG_SELFTEST_HEATERTHERMISTOR_LANG_TABLE[LANG_NUM];
 #define MSG_SELFTEST_HEATERTHERMISTOR LANG_TABLE_SELECT(MSG_SELFTEST_HEATERTHERMISTOR_LANG_TABLE)
 extern const char* const MSG_SELFTEST_MOTOR_LANG_TABLE[LANG_NUM];
@@ -436,6 +487,8 @@ extern const char* const MSG_SOFTWARE_RESET_LANG_TABLE[1];
 #define MSG_SOFTWARE_RESET LANG_TABLE_SELECT_EXPLICIT(MSG_SOFTWARE_RESET_LANG_TABLE, 0)
 extern const char* const MSG_SPEED_LANG_TABLE[LANG_NUM];
 #define MSG_SPEED LANG_TABLE_SELECT(MSG_SPEED_LANG_TABLE)
+extern const char* const MSG_STACK_ERROR_LANG_TABLE[1];
+#define MSG_STACK_ERROR LANG_TABLE_SELECT_EXPLICIT(MSG_STACK_ERROR_LANG_TABLE, 0)
 extern const char* const MSG_STATISTICS_LANG_TABLE[LANG_NUM];
 #define MSG_STATISTICS LANG_TABLE_SELECT(MSG_STATISTICS_LANG_TABLE)
 extern const char* const MSG_STATS_FILAMENTUSED_LANG_TABLE[LANG_NUM];
@@ -472,6 +525,8 @@ extern const char* const MSG_TUNE_LANG_TABLE[LANG_NUM];
 #define MSG_TUNE LANG_TABLE_SELECT(MSG_TUNE_LANG_TABLE)
 extern const char* const MSG_UNKNOWN_COMMAND_LANG_TABLE[1];
 #define MSG_UNKNOWN_COMMAND LANG_TABLE_SELECT_EXPLICIT(MSG_UNKNOWN_COMMAND_LANG_TABLE, 0)
+extern const char* const MSG_UNLOADING_FILAMENT_LANG_TABLE[LANG_NUM];
+#define MSG_UNLOADING_FILAMENT LANG_TABLE_SELECT(MSG_UNLOADING_FILAMENT_LANG_TABLE)
 extern const char* const MSG_UNLOAD_FILAMENT_LANG_TABLE[LANG_NUM];
 #define MSG_UNLOAD_FILAMENT LANG_TABLE_SELECT(MSG_UNLOAD_FILAMENT_LANG_TABLE)
 extern const char* const MSG_USB_PRINTING_LANG_TABLE[LANG_NUM];
@@ -486,6 +541,8 @@ extern const char* const MSG_VOLUMETRIC_ENABLED_LANG_TABLE[1];
 #define MSG_VOLUMETRIC_ENABLED LANG_TABLE_SELECT_EXPLICIT(MSG_VOLUMETRIC_ENABLED_LANG_TABLE, 0)
 extern const char* const MSG_VTRAV_MIN_LANG_TABLE[1];
 #define MSG_VTRAV_MIN LANG_TABLE_SELECT_EXPLICIT(MSG_VTRAV_MIN_LANG_TABLE, 0)
+extern const char* const MSG_WAITING_TEMP_LANG_TABLE[LANG_NUM];
+#define MSG_WAITING_TEMP LANG_TABLE_SELECT(MSG_WAITING_TEMP_LANG_TABLE)
 extern const char* const MSG_WATCH_LANG_TABLE[LANG_NUM];
 #define MSG_WATCH LANG_TABLE_SELECT(MSG_WATCH_LANG_TABLE)
 extern const char* const MSG_WATCHDOG_RESET_LANG_TABLE[1];

+ 35 - 6
Firmware/language_cz.h

@@ -88,7 +88,7 @@
 #define MSG_PLEASE_WAIT			"Prosim cekejte"
 #define MSG_LOADING_COLOR		"Cisteni barvy"
 #define MSG_CHANGE_SUCCESS		"Zmena uspesna!"
-#define MSG_PRESS				"A stisknete tlacitko"
+#define MSG_PRESS				"a stisknete tlacitko"
 #define MSG_INSERT_FILAMENT		"Vlozte filament"
 #define MSG_CHANGING_FILAMENT	"Vymena filamentu!"
 
@@ -171,6 +171,12 @@
 #define MSG_SELFTEST_ENDSTOP_NOTHIT			"Endstop not hit"
 #define MSG_SELFTEST_OK						"Self test OK"
 
+#define(length=20) MSG_SELFTEST_FAN					"Test ventilatoru";
+#define(length=20) MSG_SELFTEST_COOLING_FAN			"Predni tiskovy vent?";
+#define(length=20) MSG_SELFTEST_EXTRUDER_FAN			"Levy vent na trysce?";
+#define MSG_SELFTEST_FAN_YES				"Toci se";
+#define MSG_SELFTEST_FAN_NO					"Netoci se";
+
 #define MSG_STATS_TOTALFILAMENT				"Filament celkem :"
 #define MSG_STATS_TOTALPRINTTIME			"Celkovy cas :"
 #define MSG_STATS_FILAMENTUSED				"Filament :  "
@@ -209,9 +215,9 @@
 
 #define MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND			"Kalibrace XYZ selhala. Kalibracni bod podlozky nenalezen."
 #define MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED			"Kalibrace XYZ selhala. Nahlednete do manualu."
-#define MSG_BED_SKEW_OFFSET_DETECTION_PERFECT					"Kalibrace XYZ v poradku. X/Y osy jsou kolme."
-#define MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD					"Kalibrace XYZ v poradku. X/Y osy mirne zkosene."
-#define MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME				"X/Y osy jsou silne zkosene. Zkoseni bude automaticky vyrovnano pri tisku."
+#define MSG_BED_SKEW_OFFSET_DETECTION_PERFECT					"Kalibrace XYZ v poradku. X/Y osy jsou kolme. Gratuluji!"
+#define MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD					"Kalibrace XYZ v poradku. X/Y osy mirne zkosene. Dobra prace!"
+#define MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME				"Kalibrace XYZ v poradku. Zkoseni bude automaticky vyrovnano pri tisku."
 #define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR		"Kalibrace XYZ selhala. Levy predni bod moc vpredu. Srovnejte tiskarnu."
 #define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR	"Kalibrace XYZ selhala. Pravy predni bod moc vpredu. Srovnejte tiskarnu."
 #define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR		"Kalibrace XYZ selhala. Predni kalibracni body moc vpredu. Srovnejte tiskarnu."
@@ -225,7 +231,8 @@
 
 #define MSG_NEW_FIRMWARE_AVAILABLE								"Vysla nova verze firmware:"
 #define MSG_NEW_FIRMWARE_PLEASE_UPGRADE							"Prosim aktualizujte."
-#define MSG_BABYSTEP_Z_NOT_SET                          		"Tiskarna nebyla jeste zkalibrovana. Postupujte prosim podle manualu, kapitola Zaciname, odstavec Postup kalibrace."
+#define MSG_FOLLOW_CALIBRATION_FLOW                        		"Tiskarna nebyla jeste zkalibrovana. Postupujte prosim podle manualu, kapitola Zaciname, odstavec Postup kalibrace."
+#define MSG_BABYSTEP_Z_NOT_SET                          		"Neni zkalibrovana vzdalenost trysky od tiskove podlozky. Postupujte prosim podle manualu, kapitola Zaciname, odstavec Nastaveni prvni vrstvy."
 
 #define MSG_BED_CORRECTION_MENU									"Korekce podlozky"
 #define MSG_BED_CORRECTION_LEFT									"Vlevo  [um]"
@@ -234,5 +241,27 @@
 #define MSG_BED_CORRECTION_REAR									"Vzadu  [um]"
 #define MSG_BED_CORRECTION_RESET								"Reset"
 
-
+#define MSG_MESH_BED_LEVELING									"Mesh Bed Leveling"
 #define MSG_MENU_CALIBRATION									"Kalibrace"
+#define MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF					"SD card [normal]"
+#define MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON					"SD card [FlshAir]"
+
+#define MSG_LOOSE_PULLEY								"Uvolnena remenicka"
+#define MSG_FILAMENT_LOADING_T0							"Vložte filament do extruderu 1. Potvrdte tlacitkem."
+#define MSG_FILAMENT_LOADING_T1							"Vložte filament do extruderu 2. Potvrdte tlacitkem."
+#define MSG_FILAMENT_LOADING_T2							"Vložte filament do extruderu 3. Potvrdte tlacitkem."
+#define MSG_FILAMENT_LOADING_T3							"Vložte filament do extruderu 4. Potvrdte tlacitkem."
+#define MSG_CHANGE_EXTR									"Zmenit extruder"
+#define MSG_FIL_LOADED_CHECK							"Je filament zaveden?"
+#define MSG_FIL_TUNING									"Otacenim tlacitka doladte pozici filamentu."
+#define MSG_FIL_ADJUSTING								"Probiha srovnani filamentu. Prosim cekejte."
+#define MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ				"Filamenty jsou srovnany. Pro uspesnou kalibraci prosim ocistete trysku. Po te potvrdte tlacitkem."
+#define MSG_CALIBRATE_E									"Kalibrovat E"
+#define MSG_E_CAL_KNOB									"Otacejte tlacitkem dokud znacka nedosahne tela extruderu. Potvrdte tlacitkem."
+#define MSG_MARK_FIL									"Oznacte filament 100 mm od tela extruderu a po te potvrdte tlacitkem."
+#define MSG_CLEAN_NOZZLE_E								"E kalibrace ukoncena. Prosim ocistete trysku. Po te potvrdte tlacitkem."
+#define MSG_WAITING_TEMP								"Cekani na zchladnuti trysky a podlozky."
+#define MSG_FILAMENT_CLEAN								"Je barva cista?" 
+#define MSG_UNLOADING_FILAMENT							"Vysouvam filament"
+
+#define MSG_PAPER										"Umistete list papiru na podlozku a udrzujte jej pod tryskou behem mereni prvnich 4 bodu. Pokud tryska zachyti papir, vypnete tiskarnu."

+ 40 - 7
Firmware/language_en.h

@@ -27,7 +27,7 @@
 #define MSG_NOZZLE1                         "Nozzle2"
 #define MSG_NOZZLE2                         "Nozzle3"
 #define MSG_BED                             "Bed"
-#define MSG_FAN_SPEED                       "Fan speed"
+#define(length=14) MSG_FAN_SPEED                       "Fan speed"
 #define MSG_FLOW                            "Flow"
 #define MSG_FLOW0                           "Flow 0"
 #define MSG_FLOW1                           "Flow 1"
@@ -64,7 +64,7 @@
 #define MSG_BABYSTEP_X                      "Babystep X"
 #define MSG_BABYSTEP_Y                      "Babystep Y"
 #define MSG_BABYSTEP_Z                      "Live adjust Z"
-#define MSG_ADJUSTZ							"Auto adjust Z ?"
+#define MSG_ADJUSTZ							"Auto adjust Z?"
 #define MSG_PICK_Z							"Pick print"
 
 #define MSG_SETTINGS                         "Settings"
@@ -85,7 +85,7 @@
 #define(length=20) MSG_PLEASE_WAIT			"Please wait"
 #define MSG_LOADING_COLOR		"Loading color"
 #define MSG_CHANGE_SUCCESS		"Change success!"
-#define(length=20) MSG_PRESS				"And press the knob"
+#define(length=20) MSG_PRESS				"and press the knob"
 #define(length=20) MSG_INSERT_FILAMENT		"Insert filament"
 #define(length=20) MSG_CHANGING_FILAMENT	"Changing filament!"
 
@@ -164,6 +164,14 @@
 #define MSG_SELFTEST_ENDSTOP				"Endstop"
 #define MSG_SELFTEST_ENDSTOP_NOTHIT			"Endstop not hit"
 #define MSG_SELFTEST_OK						"Self test OK"
+#define MSG_LOOSE_PULLEY					"Loose pulley"
+
+#define(length=20) MSG_SELFTEST_FAN					"Fan test";
+#define(length=20) MSG_SELFTEST_COOLING_FAN			"Front print fan?";
+#define(length=20) MSG_SELFTEST_EXTRUDER_FAN			"Left hotend fan?";
+#define MSG_SELFTEST_FAN_YES				"Spinning";
+#define MSG_SELFTEST_FAN_NO					"Not spinning";
+
 #define(length=20) MSG_STATS_TOTALFILAMENT	"Total filament :"
 #define(length=20) MSG_STATS_TOTALPRINTTIME "Total print time :"
 #define(length=20) MSG_STATS_FILAMENTUSED	"Filament used:  "
@@ -203,9 +211,9 @@
 
 #define(length=20,lines=8) MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND			"XYZ calibration failed. Bed calibration point was not found."
 #define(length=20,lines=8) MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED				"XYZ calibration failed. Please consult the manual."
-#define(length=20,lines=8) MSG_BED_SKEW_OFFSET_DETECTION_PERFECT					"XYZ calibration ok. X/Y axes are perpendicular."
-#define(length=20,lines=8) MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD					"XYZ calibration all right. X/Y axes are slightly skewed."
-#define(length=20,lines=8) MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME				"X/Y skewed severly. Skew will be corrected automatically."
+#define(length=20,lines=8) MSG_BED_SKEW_OFFSET_DETECTION_PERFECT					"XYZ calibration ok. X/Y axes are perpendicular. Congratulations!"
+#define(length=20,lines=8) MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD					"XYZ calibration all right. X/Y axes are slightly skewed. Good job!"
+#define(length=20,lines=8) MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME				"XYZ calibration all right. Skew will be corrected automatically."
 #define(length=20,lines=8) MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR		"XYZ calibration failed. Left front calibration point not reachable."
 #define(length=20,lines=8) MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR		"XYZ calibration failed. Right front calibration point not reachable."
 #define(length=20,lines=8) MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR		"XYZ calibration failed. Front calibration points not reachable."
@@ -220,7 +228,31 @@
 #define(length=20,lines=2) MSG_NEW_FIRMWARE_AVAILABLE								"New firmware version available:"
 #define(length=20) MSG_NEW_FIRMWARE_PLEASE_UPGRADE									"Please upgrade."
 
-#define(length=20,lines=8) MSG_BABYSTEP_Z_NOT_SET									"Printer has not been calibrated yet. Please follow the manual, chapter First steps, section Calibration flow."
+#define(length=20,lines=8) MSG_FOLLOW_CALIBRATION_FLOW								"Printer has not been calibrated yet. Please follow the manual, chapter First steps, section Calibration flow."
+#define(length=20,lines=12) MSG_BABYSTEP_Z_NOT_SET									"Distance between tip of the nozzle and the bed surface has not been set yet. Please follow the manual, chapter First steps, section First layer calibration."
+
+#define(length=20, lines=4) MSG_FILAMENT_LOADING_T0							"Insert filament into extruder 1. Click when done."
+#define(length=20, lines=4) MSG_FILAMENT_LOADING_T1							"Insert filament into extruder 2. Click when done."
+#define(length=20, lines=4) MSG_FILAMENT_LOADING_T2							"Insert filament into extruder 3. Click when done."
+#define(length=20, lines=4) MSG_FILAMENT_LOADING_T3							"Insert filament into extruder 4. Click when done."
+#define(length=20, lines=1) MSG_CHANGE_EXTR									"Change extruder"
+
+#define(length=20, lines=1) MSG_FIL_LOADED_CHECK								"Is filament loaded?"
+#define(length=20, lines=2) MSG_FIL_TUNING										"Rotate the knob to adjust filament."
+#define(length=20, lines=4) MSG_FIL_ADJUSTING								"Adjusting filaments. Please wait."
+#define(length=20,lines=8) MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ			"Filaments are now adjusted. Please clean the nozzle for calibration. Click when done."
+#define(length=20, lines=4) MSG_STACK_ERROR						"Error - static memory has been overwritten"
+#define(length=20, lines=1) MSG_CALIBRATE_E						"Calibrate E"
+//#define(length=20, lines=1) MSG_RESET_CALIBRATE_E				"Reset E Cal."
+#define(length=20, lines=8) MSG_E_CAL_KNOB						"Rotate knob until mark reaches extruder body. Click when done."
+
+//#define(length=20, lines=1) MSG_FARM_CARD_MENU					"Farm mode print"
+#define(length=20, lines=8) MSG_MARK_FIL						"Mark filament 100mm from extruder body. Click when done."
+#define(length=20, lines=8) MSG_CLEAN_NOZZLE_E				"E calibration finished. Please clean the nozzle. Click when done."
+#define(length=20, lines=3) MSG_WAITING_TEMP				"Waiting for nozzle and bed cooling"
+#define(length=20, lines=2) MSG_FILAMENT_CLEAN				"Is color clear?"
+#define(lenght=20) MSG_UNLOADING_FILAMENT			"Unloading filament"
+#define(length=20, lines=8) MSG_PAPER						"Place a sheet of paper under the nozzle during the calibration of first 4 points. If the nozzle catches the paper, power off the printer immediately."
 
 #define MSG_BED_CORRECTION_MENU									"Bed level correct"
 #define MSG_BED_CORRECTION_LEFT									"Left side  um"
@@ -233,3 +265,4 @@
 #define MSG_MENU_CALIBRATION									"Calibration"
 #define MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF					"SD card [normal]"
 #define MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON					"SD card [FlshAir]"
+#define MSG_PRINTER_DISCONNECTED								"Printer disconnected"

+ 68 - 39
Firmware/language_es.h

@@ -6,8 +6,8 @@
  *
  */
 
-#define WELCOME_MSG                         CUSTOM_MENDEL_NAME " lista"
-#define MSG_SD_INSERTED                     "Tarjeta colocada"
+#define WELCOME_MSG                         CUSTOM_MENDEL_NAME " prep."
+#define MSG_SD_INSERTED                     "Tarjeta insertada"
 #define MSG_SD_REMOVED                      "Tarjeta retirada"
 #define MSG_MAIN                            "Menu principal"
 #define MSG_DISABLE_STEPPERS                "Apagar motores"
@@ -17,11 +17,11 @@
 #define MSG_MOVE_X                          "Mover X"
 #define MSG_MOVE_Y                          "Mover Y"
 #define MSG_MOVE_Z                          "Mover Z"
-#define MSG_MOVE_E                          "Extrusor"
+#define MSG_MOVE_E                          "Extruir"
 #define MSG_SPEED                           "Velocidad"
-#define MSG_NOZZLE                          "Fusor"
+#define MSG_NOZZLE                          "Boquilla"
 #define MSG_BED                             "Base"
-#define MSG_FAN_SPEED                       "Ventilador"
+#define MSG_FAN_SPEED                       "Velocidad Vent."
 #define MSG_FLOW                            "Flujo"
 #define MSG_TEMPERATURE                     "Temperatura"
 #define MSG_WATCH                           "Monitorizar"
@@ -29,49 +29,49 @@
 #define MSG_PAUSE_PRINT                     "Pausar impresion"
 #define MSG_RESUME_PRINT                    "Reanudar impres."
 #define MSG_STOP_PRINT                      "Detener impresion"
-#define MSG_CARD_MENU                       "Menu de SD"
+#define MSG_CARD_MENU                       "Menu tarjeta SD"
 #define MSG_NO_CARD                         "No hay tarjeta SD"
-#define MSG_DWELL                           "Reposo..."
+#define MSG_DWELL                           "En espera"
 #define MSG_USERWAIT                        "Esperando ordenes"
-#define MSG_RESUMING                        "Resumiendo impre."
-#define MSG_PRINT_ABORTED                   "Print aborted"
+#define MSG_RESUMING                        "Resumiendo impresion"
+#define MSG_PRINT_ABORTED                   "Impresion cancelada" 
 #define MSG_NO_MOVE                         "Sin movimiento"
-#define MSG_KILLED                          "PARADA DE EMERG."
+#define MSG_KILLED                          "PARADA DE EMERGENCIA"
 #define MSG_STOPPED                         "PARADA"
 #define MSG_FILAMENTCHANGE                  "Cambiar filamento"
-#define MSG_BABYSTEP_Z                      "Micropaso Z"
-#define MSG_ADJUSTZ							"Auto Micropaso Z?"
-#define MSG_PICK_Z							"Vyberte vytisk"
+#define MSG_BABYSTEP_Z                      "Micropaso Eje Z"
+#define MSG_ADJUSTZ			    "Ajustar Eje Z"			
+#define MSG_PICK_Z			    "Esc. Modelo Adecuado"
 
-#define MSG_SETTINGS                        "Ajuste"
+#define MSG_SETTINGS                        "Configuracion"
 #define MSG_PREHEAT                         "Precalentar"
-#define MSG_UNLOAD_FILAMENT                 "Sacar filamento"
-#define MSG_LOAD_FILAMENT					"Poner filamento"
+#define MSG_UNLOAD_FILAMENT                 "Soltar filamento"
+#define MSG_LOAD_FILAMENT		    "Introducir filam."
 #define MSG_ERROR							"ERROR:"
-#define MSG_PREHEAT_NOZZLE                  "Precal. extrusor!"
-#define MSG_SUPPORT							"Support"
-#define MSG_CORRECTLY						"Cambiado correc.?"
+#define MSG_PREHEAT_NOZZLE                  "Precalentar extrusor"
+#define MSG_SUPPORT			    "Soporte"
+#define MSG_CORRECTLY			    "Cambiado correct.?"
 #define MSG_YES								"Si"
 #define MSG_NO								"No"
-#define MSG_NOT_LOADED 						"Fil. no cargado"
-#define MSG_NOT_COLOR 						"Color no claro"
-#define MSG_LOADING_FILAMENT				"Cargando fil."
-#define MSG_PLEASE_WAIT						"Espera"
-#define MSG_LOADING_COLOR					"Cargando color"
-#define MSG_CHANGE_SUCCESS					"Cambiar bien!"
-#define MSG_PRESS							"Y pulse el mando"
-#define MSG_INSERT_FILAMENT					"Inserta filamento"
-#define MSG_CHANGING_FILAMENT				"Cambiando fil.!"
+#define MSG_NOT_LOADED 			    "Fil. no introducido"
+#define MSG_NOT_COLOR 			    "Color no homogeneo"
+#define MSG_LOADING_FILAMENT		    "Introduciendo filam."
+#define MSG_PLEASE_WAIT			    "Por Favor Esperar"
+#define MSG_LOADING_COLOR                   "Cambiando color" 
+#define MSG_CHANGE_SUCCESS		    "Cambio correcto"
+#define MSG_PRESS			    "Pulsar el mando"
+#define MSG_INSERT_FILAMENT		    "Introducir filamento"
+#define MSG_CHANGING_FILAMENT		    "Cambiando filamento"
 #define MSG_SILENT_MODE_ON					"Modo   [silencio]"
-#define MSG_SILENT_MODE_OFF					"Modo [mas fuerza]" 
-#define MSG_REBOOT							"Reiniciar la imp."
-#define MSG_TAKE_EFFECT						"para tomar efecto"											
+#define MSG_SILENT_MODE_OFF		    "Modo [rend.pleno]" 
+#define MSG_REBOOT			    "Reiniciar impresora"
+#define MSG_TAKE_EFFECT			    " para aplicar cambios" 
 #define MSG_HEATING                         "Calentando..."
-#define MSG_HEATING_COMPLETE                "Calentando listo."
-#define MSG_BED_HEATING                     "Base Calentando"
-#define MSG_BED_DONE                        "Base listo."
+#define MSG_HEATING_COMPLETE                "Calentamiento final."
+#define MSG_BED_HEATING                     "Calentando Base"
+#define MSG_BED_DONE                        "Base preparada"
 #define MSG_LANGUAGE_NAME					"Espanol"
-#define MSG_LANGUAGE_SELECT					"Cambia la lengua "
+#define MSG_LANGUAGE_SELECT		    "Cambiae el idioma"
 #define MSG_PRUSA3D							"prusa3d.com"
 #define MSG_PRUSA3D_FORUM					"forum.prusa3d.com"
 #define MSG_PRUSA3D_HOWTO					"howto.prusa3d.com"
@@ -166,6 +166,12 @@
 #define MSG_SELFTEST_ENDSTOP_NOTHIT         "Tope fin. no toc."
 #define MSG_SELFTEST_OK                     "Self test OK"
 
+#define(length=20) MSG_SELFTEST_FAN					"Test del ventilador";
+#define(length=20) MSG_SELFTEST_COOLING_FAN			"Vent. al frente?";
+#define(length=20) MSG_SELFTEST_EXTRUDER_FAN			"Vent. en la izg?";
+#define MSG_SELFTEST_FAN_YES				"Ventilador gira";
+#define MSG_SELFTEST_FAN_NO					"Ventilador no gira";
+
 #define MSG_STATS_TOTALFILAMENT             "Filamento total:"
 #define MSG_STATS_TOTALPRINTTIME            "Tiempo total :"
 #define MSG_STATS_FILAMENTUSED              "Filamento :  "
@@ -202,9 +208,9 @@
 
 #define MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND           "Calibracion XYZ fallada. Puntos de calibracion en la cama no encontrados."
 #define MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED            "Calibracion XYZ fallada. Consultar el manual por favor."
-#define MSG_BED_SKEW_OFFSET_DETECTION_PERFECT               "Calibracion XYZ ok. Ejes X/Y perpendiculares."
-#define MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD             "Calibracion XYZ conseguida. Ejes X/Y un poco torcidos."
-#define MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME          "X/Y muy distorsionado. La distorsion sera corregida automaticamente."
+#define MSG_BED_SKEW_OFFSET_DETECTION_PERFECT               "Calibracion XYZ ok. Ejes X/Y perpendiculares. Felicitaciones!"
+#define MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD             "Calibracion XYZ correcta. Los ejes X / Y estan ligeramente inclinados. Buen trabajo!"
+#define MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME          "Calibracion XYZ correcta. La inclinacion se corregira automaticamente."
 #define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR     "Calibracion XYZ fallad. Punto delantero izquierdo no alcanzable."
 #define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR        "Calibracion XYZ fallad. Punto delantero derecho no alcanzable."
 #define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR     "Calibracion XYZ fallad. Punto delanteros no alcanzables."
@@ -216,7 +222,8 @@
 #define MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED      			"Nivelacion fallada. Sensor desconectado o cables danados. Esperando reset."
 #define MSG_NEW_FIRMWARE_AVAILABLE                  				"Nuevo firmware disponible:"
 #define MSG_NEW_FIRMWARE_PLEASE_UPGRADE                 			"Actualizar por favor"
-#define MSG_BABYSTEP_Z_NOT_SET                      			"Impresora no esta calibrada todavia. Por favor usar el manual, el capitulo First steps, seleccion Calibration flow."
+#define MSG_FOLLOW_CALIBRATION_FLOW                    			"Impresora no esta calibrada todavia. Por favor usar el manual, el capitulo First steps, seleccion Calibration flow."
+#define MSG_BABYSTEP_Z_NOT_SET                      			"Distancia entre la punta de la boquilla y la superficie de la cama no fijada aun. Por favor siga el manual, capitulo First steps, seccion First layer calibration."
 #define MSG_BED_CORRECTION_MENU                                 "Corr. de la cama"
 #define MSG_BED_CORRECTION_LEFT                                 "Izquierda [um]"
 #define MSG_BED_CORRECTION_RIGHT                                "Derecha   [um]"
@@ -224,4 +231,26 @@
 #define MSG_BED_CORRECTION_REAR                                 "Atras     [um]"
 #define MSG_BED_CORRECTION_RESET                                "Reset"
 
+#define MSG_MESH_BED_LEVELING									"Mesh Bed Leveling"
 #define MSG_MENU_CALIBRATION									"Calibracion"
+#define MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF					"SD card [normal]"
+#define MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON					"SD card [FlshAir]"
+
+#define MSG_LOOSE_PULLEY								"Polea suelta"
+#define MSG_FILAMENT_LOADING_T0							"Insertar filamento en el extrusor 1. Haga clic una vez terminado."
+#define MSG_FILAMENT_LOADING_T1							"Insertar filamento en el extrusor 2. Haga clic una vez terminado."
+#define MSG_FILAMENT_LOADING_T2							"Insertar filamento en el extrusor 3. Haga clic una vez terminado."
+#define MSG_FILAMENT_LOADING_T3							"Insertar filamento en el extrusor 4. Haga clic una vez terminado."
+#define MSG_CHANGE_EXTR									"Cambiar extrusor."
+#define MSG_FIL_LOADED_CHECK							"Esta cargado el filamento?"
+#define MSG_FIL_TUNING									"Rotar el mando para ajustar el filamento."
+#define MSG_FIL_ADJUSTING								"Ajustando filamentos. Esperar por favor."
+#define MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ				"Filamentos ajustados. Limpie la boquilla para calibracion. Haga clic una vez terminado."
+#define MSG_CALIBRATE_E									"Calibrar E"
+#define MSG_E_CAL_KNOB									"Rotar el mando hasta que la marca llegue al cuerpo del extrusor. Haga clic una vez terminado."
+#define MSG_MARK_FIL									"Marque el filamento 100 mm por encima del final del extrusor. Hacer clic una vez terminado."
+#define MSG_CLEAN_NOZZLE_E								"E calibrado. Limpiar la boquilla. Haga clic una vez terminado."
+#define MSG_WAITING_TEMP								"Esperando enfriamiento de la cama y del extrusor."
+#define MSG_FILAMENT_CLEAN								"Es el nuevo color nitido?"
+#define MSG_UNLOADING_FILAMENT							"Soltando filamento"
+#define MSG_PAPER										"Colocar una hoja de papel sobre la superficie de impresion durante la calibracion de los primeros 4 puntos. Si la boquilla mueve el papel, apagar impresora inmediatamente."

+ 49 - 20
Firmware/language_it.h

@@ -1,4 +1,4 @@
-#define WELCOME_MSG                         CUSTOM_MENDEL_NAME "pronta."
+#define WELCOME_MSG                         CUSTOM_MENDEL_NAME " pronta."
 #define MSG_SD_INSERTED                     "SD inserita"
 #define MSG_SD_REMOVED                      "SD rimossa"
 #define MSG_MAIN                            "Menu principale"
@@ -22,7 +22,7 @@
 #define MSG_NOZZLE1                         "Nozzle2"
 #define MSG_NOZZLE2                         "Nozzle3"
 #define MSG_BED                             "Letto"
-#define MSG_FAN_SPEED                       "Velocita ventola"
+#define MSG_FAN_SPEED                       "Velocita vent."
 #define MSG_FLOW                            "Flusso"
 #define MSG_TEMPERATURE                     "Temperatura"
 #define MSG_MOTION                          "Motion"
@@ -64,27 +64,27 @@
 #define MSG_SUPPORT 						"Support"
 #define MSG_YES								"Si"
 #define MSG_NO								"No"
-#define MSG_NOT_LOADED 						"Fil. no cargado"
-#define MSG_NOT_COLOR 						"Color no claro"
-#define MSG_LOADING_COLOR					"Cargando color"
-#define MSG_CHANGE_SUCCESS					"Cambia. riuscito!"
-#define MSG_PRESS							"Y pulse el mando"
+#define MSG_NOT_LOADED 						"Fil. non caricato"
+#define MSG_NOT_COLOR 						"Colore non puro"
+#define MSG_LOADING_COLOR					"Caricando colore"
+#define MSG_CHANGE_SUCCESS					"Cambio riuscito!"
+#define MSG_PRESS							"e cliccare manopola"
 #define MSG_INSERT_FILAMENT					"Inserire filamento"
-#define MSG_CHANGING_FILAMENT				"Mutevole fil.!"
+#define MSG_CHANGING_FILAMENT				"Cambiando filam."
 
 #define MSG_PLEASE_WAIT						"Aspetta"
 #define MSG_PREHEAT_NOZZLE                  "Preris. ugello!"
-#define MSG_HEATING_COMPLETE                "Riscaldamento fatto."
-#define MSG_BED_HEATING                     "Piatto riscaldam."
+#define MSG_HEATING_COMPLETE                "Riscald. completo"
+#define MSG_BED_HEATING                     "Riscald. letto"
 #define MSG_BED_DONE                        "Piatto fatto."
-#define MSG_ERROR                        	"ERROR:"
+#define MSG_ERROR                        	"ERRORE:"
 #define MSG_CORRECTLY						"Cambiato corr.?"
-#define MSG_LOADING_FILAMENT				"Cargando fil."
+#define MSG_LOADING_FILAMENT				"Caricando filam."
 #define MSG_UNLOAD_FILAMENT                 "Scarica filamento"
 #define MSG_LOAD_FILAMENT                   "Carica filamento"
 
 #define MSG_SILENT_MODE_ON		    "Modo [silenzioso]"
-#define MSG_SILENT_MODE_OFF		    "Mode [prestante]" 
+#define MSG_SILENT_MODE_OFF		    "Mode      [forte]" 
 #define MSG_REBOOT			    "Riavvia stampante"
 #define MSG_TAKE_EFFECT			    " per attualizzare"
 
@@ -151,6 +151,13 @@
 #define MSG_SELFTEST_ENDSTOP		    "Finecorsa"
 #define MSG_SELFTEST_ENDSTOP_NOTHIT	    "Finec. fuori por."
 #define MSG_SELFTEST_OK			    "Autotest OK"
+
+#define(length=20) MSG_SELFTEST_FAN					"Prova del ventilator";
+#define(length=20) MSG_SELFTEST_COOLING_FAN			"Vent di stampa ant.?";
+#define(length=20) MSG_SELFTEST_EXTRUDER_FAN        "Vent SX sull'ugello?";
+#define MSG_SELFTEST_FAN_YES				"Gira";
+#define MSG_SELFTEST_FAN_NO					"Non si gira";
+
 #define MSG_STATS_TOTALFILAMENT		    "Filamento tot:"
 #define MSG_STATS_TOTALPRINTTIME	    "Tempo stampa tot:"
 #define MSG_STATS_FILAMENTUSED		    "Filamento usato:"
@@ -192,9 +199,9 @@
 
 #define MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND		"Calibrazione XYZ fallita. Il punto di calibrazione sul letto non e' stato trovato."
 #define MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED		"Calibrazione XYZ fallita. Si prega di consultare il manuale."
-#define MSG_BED_SKEW_OFFSET_DETECTION_PERFECT			"Calibrazione XYZ OK. Gli assi X/Y sono perpendicolari."
-#define MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD			"Calibrazione XYZ compiuta. Gli assi X/Y sono leggermente distorti."
-#define MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME		"X/Y fortemente distorto. La distorsione verra' corretta automaticamente."
+#define MSG_BED_SKEW_OFFSET_DETECTION_PERFECT			"Calibrazione XYZ OK. Gli assi X/Y sono perpendicolari. Complimenti!"
+#define MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD			"Calibrazion XYZ corretta. Assi X/Y leggermente storti. Ben fatto!"
+#define MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME		"Calibrazion XYZ corretta. La distorsione verra' automaticamente compensata."
 #define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR	"Calibrazione XYZ fallita. Punto anteriore sinistro non raggiungibile."
 #define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR	"Calibrazione XYZ fallita. Punto anteriore destro non raggiungibile."
 #define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR	"Calibrazione XYZ fallita. Punti anteriori non raggiungibili."
@@ -209,14 +216,36 @@
 #define MSG_NEW_FIRMWARE_AVAILABLE						"Nuova versione del firmware disponibile"
 #define MSG_NEW_FIRMWARE_PLEASE_UPGRADE					"Prega aggiorna."
 
-#define MSG_BABYSTEP_Z_NOT_SET							"Stampante ancora non calibrata. Si prega di seguire il manuale, capitolo PRIMI PASSI, sezione della calibrazione."
+#define MSG_FOLLOW_CALIBRATION_FLOW						"Stampante ancora non calibrata. Si prega di seguire il manuale, capitolo PRIMI PASSI, sezione della calibrazione."
+#define MSG_BABYSTEP_Z_NOT_SET							"Distanza tra la punta dell'ugello e la superficie del letto non ancora imposta. Si prega di seguire il manuale, capitolo First steps, sezione First layer calibration."
 
 #define MSG_BED_CORRECTION_MENU							"Correz. liv.letto"
-#define MSG_BED_CORRECTION_LEFT							"Lato sinistro um"
-#define MSG_BED_CORRECTION_RIGHT						"Lato destro um"
-#define MSG_BED_CORRECTION_FRONT						"Lato ateriore um"
+#define MSG_BED_CORRECTION_LEFT							"Lato sinistro"
+#define MSG_BED_CORRECTION_RIGHT						"Lato destro"
+#define MSG_BED_CORRECTION_FRONT						"Lato ateriore"
 #define MSG_BED_CORRECTION_REAR							"Lato posteriore"
 #define MSG_BED_CORRECTION_RESET						"Reset"			
 
 #define MSG_MESH_BED_LEVELING							"Mesh livel. letto"
 #define MSG_MENU_CALIBRATION							"Calibrazione"
+#define MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF					"SD card [normal]"
+#define MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON					"SD card [FlshAir]"
+
+#define MSG_LOOSE_PULLEY								"Puleggia lenta"
+#define MSG_FILAMENT_LOADING_T0							"Inserire filamento nell'estrusore 1. Click per continuare."
+#define MSG_FILAMENT_LOADING_T1							"Inserire filamento nell'estrusore 2. Click per continuare."
+#define MSG_FILAMENT_LOADING_T2							"Inserire filamento nell'estrusore 3. Click per continuare."
+#define MSG_FILAMENT_LOADING_T3							"Inserire filamento nell'estrusore 4. Click per continuare."
+#define MSG_CHANGE_EXTR									"Cambio estrusore."
+#define MSG_FIL_LOADED_CHECK							"Filamento caricato?"
+#define MSG_FIL_TUNING									"Girare la manopola per regolare il filamento"
+#define MSG_FIL_ADJUSTING								"Filamento in fase di regolazione. Attendere prego."
+#define MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ				"I filamenti sono regolati. Si prega di pulire l'ugello per la calibrazione. Click per continuare."
+#define MSG_CALIBRATE_E									"Calibra E"
+#define MSG_E_CAL_KNOB									"Girare la manopola affinche' il segno raggiunga il corpo dell'estrusore. Click per continuare."
+#define MSG_MARK_FIL									"Segnare il filamento a 100 mm di distanza dal corpo dell'estrusore. Click per continuare."
+#define MSG_CLEAN_NOZZLE_E								"Calibrazione E terminata. Si prega di pulire l'ugello. Click per continuare."
+#define MSG_WAITING_TEMP								"In attesa del raffreddamento della testina e del piatto"
+#define MSG_FILAMENT_CLEAN								"Il colore e' nitido?"
+#define MSG_UNLOADING_FILAMENT							"Rilasc. filamento"
+#define MSG_PAPER										"Porre un foglio sotto l'ugello durante la calibrazione dei primi 4 punti. In caso l'ugello muova il foglio spegnere prontamente la stampante."

+ 32 - 5
Firmware/language_pl.h

@@ -64,7 +64,7 @@
 #define MSG_SILENT_MODE_ON                                      "Mod       [cichy]"
 #define MSG_SILENT_MODE_OFF                                     "Mod [w wydajnosc]" 
 #define MSG_REBOOT                                                      "Restart drukarki"
-#define MSG_TAKE_EFFECT                                         "wprow. zmian"   
+#define MSG_TAKE_EFFECT                                         " wprow. zmian"   
 #define MSG_HEATING                         "Grzanie..."
 #define MSG_HEATING_COMPLETE                "Grzanie OK."
 #define MSG_BED_HEATING                     "Grzanie stolika.."
@@ -172,6 +172,12 @@
 #define MSG_SELFTEST_ENDSTOP_NOTHIT         "Endstop not hit"
 #define MSG_SELFTEST_OK                     "Self test OK"
 
+#define(length=20) MSG_SELFTEST_FAN					"Test wentylatora";
+#define(length=20) MSG_SELFTEST_COOLING_FAN			"Przodni went. druku?";
+#define(length=20) MSG_SELFTEST_EXTRUDER_FAN			"Lewy went na dysze?";
+#define MSG_SELFTEST_FAN_YES				"Kreci sie";
+#define MSG_SELFTEST_FAN_NO					"Nekreci sie";
+
 #define MSG_STATS_TOTALFILAMENT             "Filament lacznie :"
 #define MSG_STATS_TOTALPRINTTIME            "Czas calkowity :"
 #define MSG_STATS_FILAMENTUSED              "Filament :  "
@@ -208,9 +214,9 @@
 
 #define MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND           "Kalibr. XYZ nieudana. Kalibracyjny punkt podkladki nieznaleziony."
 #define MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED            "Kalibracja XYZ niepowiedziona. Sprawdzic w instrukcji."
-#define MSG_BED_SKEW_OFFSET_DETECTION_PERFECT                   "Kalibracja XYZ ok. Osie X/Y sa prostopadle."
-#define MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD                 "Kalibracja XYZ w porzadku. Osie X/Y lekko skosne."
-#define MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME              "Osie X/Y sa mocno skosne. Skos bedzie aut. wyrownany przy druku."
+#define MSG_BED_SKEW_OFFSET_DETECTION_PERFECT                   "Kalibracja XYZ ok. Osie X/Y sa prostopadle. Gratulacje!"
+#define MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD                 "Kalibracja XYZ prawidlowa. Osie X/Y lekko skosne. Dobra robota!"
+#define MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME              "Kalibracja XYZ prawidlowa. Skosy beda automatycznie wyrownane przy druku."
 #define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR     "Kalibr. XYZ nieudana. Lewy przedni punkt zbyt do przodu. Wyrownac drukarke."
 #define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR    "Kalibr. XYZ nieudana. Prawy przedni punkt zbyt do przodu. Wyrownac drukarke."
 #define MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR     "Kalibr. XYZ nieudana. Przed. punkty kalibr. zbyt do przodu. Wyrownac drukarke."
@@ -222,7 +228,8 @@
 #define MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED              "Kalibracja nieudana. Sensor odlaczony lub uszkodz. kabel. Czekam na reset."
 #define MSG_NEW_FIRMWARE_AVAILABLE                              "Wyszla nowa wersja firmware:"
 #define MSG_NEW_FIRMWARE_PLEASE_UPGRADE                         "Prosze zaktualizowac"
-#define MSG_BABYSTEP_Z_NOT_SET                                  "Drukarka nie zostala jeszcze skalibrowana. Prosze kierowac sie instrukcja, rozdzial Zaczynamy, podrozdzial Selftest."
+#define MSG_FOLLOW_CALIBRATION_FLOW                             "Drukarka nie zostala jeszcze skalibrowana. Prosze kierowac sie instrukcja, rozdzial Zaczynamy, podrozdzial Selftest."
+#define MSG_BABYSTEP_Z_NOT_SET                                  "Odleglosc dyszy od podkladki nie jest skalibrowana. Postepuj zgodnie z instrukcja rozdzial Zaczynamy, podrozdzial Kalibracja pierwszej warstwy."
 #define MSG_BED_CORRECTION_MENU                                 "Korekta podkladki"
 #define MSG_BED_CORRECTION_LEFT                                 "W lewo  [um]"
 #define MSG_BED_CORRECTION_RIGHT                                "W prawo [um]"
@@ -230,6 +237,26 @@
 #define MSG_BED_CORRECTION_REAR                                 "Do tylu  [um]"
 #define MSG_BED_CORRECTION_RESET                                "Reset"
 
+#define MSG_MESH_BED_LEVELING									"Mesh Bed Leveling"
 #define MSG_MENU_CALIBRATION									"Kalibracja"
 #define MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF					"karta SD [normal]"
 #define MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON					"karta SD[FlshAir]"
+
+#define MSG_LOOSE_PULLEY										"Kolo pasowe"
+#define MSG_FILAMENT_LOADING_T0									"Wloz filament do ekstrudera 1. Potwierdz przyciskiem."
+#define MSG_FILAMENT_LOADING_T1									"Wloz filament do ekstrudera 2. Potwierdz przyciskiem."
+#define MSG_FILAMENT_LOADING_T2									"Wloz filament do ekstrudera 3. Potwierdz przyciskiem."
+#define MSG_FILAMENT_LOADING_T3									"Wloz filament do ekstrudera 4. Potwierdz przyciskiem."
+#define MSG_CHANGE_EXTR											"Zmienic ekstruder"
+#define MSG_FIL_LOADED_CHECK									"Czy filament jest wprowadzony?"
+#define MSG_FIL_TUNING											"Obrotem przycisku dostroj pozycje filamentu."
+#define MSG_FIL_ADJUSTING										"Przebiega wyrownanie filamentow. Prosze czekac."
+#define MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ						"Dla prawidlowej kalibracji prosze oczyscic dysze. Potem potwierdzic przyciskiem."
+#define MSG_CALIBRATE_E											"Kalibruj E"
+#define MSG_E_CAL_KNOB											"Prosze otaczac przycisk poki znacznik nie dosiegnie ciala ekstrudera. Potwierdzic przyciskiem."
+#define MSG_MARK_FIL											"Prosze oznaczyc filament 100 mm od ciala ekstrudera. Potwierdzic przyciskiem."
+#define MSG_CLEAN_NOZZLE_E										"Kalibracja E skonczona. Prosze oczyscic dysze. Potem potwierdzic przyciskiem. "
+#define MSG_WAITING_TEMP										"Oczekiwanie na wychlodzenie dyszy i podkladki."
+#define MSG_FILAMENT_CLEAN										"Czy kolor jest czysty?"
+#define MSG_UNLOADING_FILAMENT									"Wysuwam filament"
+#define MSG_PAPER												"Umiesc kartke papieru na podkladce i trzymaj pod dysza podczas pomiaru pierwszych 4 punktow. Jesli dysza zahaczy o papier, wylacz drukarke."

+ 79 - 11
Firmware/mesh_bed_calibration.cpp

@@ -1,5 +1,6 @@
 #include "Marlin.h"
 #include "Configuration.h"
+#include "ConfigurationStore.h"
 #include "language_all.h"
 #include "mesh_bed_calibration.h"
 #include "mesh_bed_leveling.h"
@@ -411,18 +412,55 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS(
         cntr[1] = 0.f;
         float wx = 0.f;
         float wy = 0.f;
-        for (int8_t i = 0; i < 9; ++ i) {
+        for (int8_t i = 0; i < npts; ++ i) {
             float x = vec_x[0] * measured_pts[i * 2] + vec_y[0] * measured_pts[i * 2 + 1];
             float y = vec_x[1] * measured_pts[i * 2] + vec_y[1] * measured_pts[i * 2 + 1];
             float w = point_weight_x(i, y);
-            cntr[0] += w * (pgm_read_float(true_pts + i * 2) - x);
-            wx += w;
+			cntr[0] += w * (pgm_read_float(true_pts + i * 2) - x);
+			wx += w;
+			if (verbosity_level >= 20) {
+				MYSERIAL.print(i);
+				SERIAL_ECHOLNPGM("");
+				SERIAL_ECHOLNPGM("Weight_x:");
+				MYSERIAL.print(w);
+				SERIAL_ECHOLNPGM("");
+				SERIAL_ECHOLNPGM("cntr[0]:");
+				MYSERIAL.print(cntr[0]);
+				SERIAL_ECHOLNPGM("");
+				SERIAL_ECHOLNPGM("wx:");
+				MYSERIAL.print(wx);
+			}
             w = point_weight_y(i, y);
-            cntr[1] += w * (pgm_read_float(true_pts + i * 2 + 1) - y);
-            wy += w;
-        }
+			cntr[1] += w * (pgm_read_float(true_pts + i * 2 + 1) - y);
+			wy += w;
+
+			if (verbosity_level >= 20) {
+				SERIAL_ECHOLNPGM("");
+				SERIAL_ECHOLNPGM("Weight_y:");
+				MYSERIAL.print(w);
+				SERIAL_ECHOLNPGM("");
+				SERIAL_ECHOLNPGM("cntr[1]:");
+				MYSERIAL.print(cntr[1]);
+				SERIAL_ECHOLNPGM("");
+				SERIAL_ECHOLNPGM("wy:");
+				MYSERIAL.print(wy);
+				SERIAL_ECHOLNPGM("");
+				SERIAL_ECHOLNPGM("");
+			}
+		}
         cntr[0] /= wx;
         cntr[1] /= wy;
+		if (verbosity_level >= 20) {
+			SERIAL_ECHOLNPGM("");
+			SERIAL_ECHOLNPGM("Final cntr values:");
+			SERIAL_ECHOLNPGM("cntr[0]:");
+			MYSERIAL.print(cntr[0]);
+			SERIAL_ECHOLNPGM("");
+			SERIAL_ECHOLNPGM("cntr[1]:");
+			MYSERIAL.print(cntr[1]);
+			SERIAL_ECHOLNPGM("");
+		}
+
     }
     #endif
 
@@ -511,6 +549,7 @@ void reset_bed_offset_and_skew()
 }
 
 bool is_bed_z_jitter_data_valid()
+// offsets of the Z heiths of the calibration points from the first point are saved as 16bit signed int, scaled to tenths of microns
 {
     for (int8_t i = 0; i < 8; ++ i)
         if (eeprom_read_word((uint16_t*)(EEPROM_BED_CALIBRATION_Z_JITTER+i*2)) == 0x0FFFF)
@@ -603,18 +642,24 @@ void world2machine_initialize()
         // Length of the vec_x shall be close to unity.
         float l = sqrt(vec_x[0] * vec_x[0] + vec_x[1] * vec_x[1]);
         if (l < 0.9 || l > 1.1) {
+			SERIAL_ECHOLNPGM("X vector length:");
+			MYSERIAL.println(l);
             SERIAL_ECHOLNPGM("Invalid bed correction matrix. Length of the X vector out of range.");
             reset = true;
         }
         // Length of the vec_y shall be close to unity.
         l = sqrt(vec_y[0] * vec_y[0] + vec_y[1] * vec_y[1]);
         if (l < 0.9 || l > 1.1) {
-            SERIAL_ECHOLNPGM("Invalid bed correction matrix. Length of the X vector out of range.");
+			SERIAL_ECHOLNPGM("Y vector length:");
+			MYSERIAL.println(l);
+            SERIAL_ECHOLNPGM("Invalid bed correction matrix. Length of the Y vector out of range.");
             reset = true;
         }
         // Correction of the zero point shall be reasonably small.
         l = sqrt(cntr[0] * cntr[0] + cntr[1] * cntr[1]);
         if (l > 15.f) {
+			SERIAL_ECHOLNPGM("Zero point correction:");
+			MYSERIAL.println(l);
             SERIAL_ECHOLNPGM("Invalid bed correction matrix. Shift out of range.");
             reset = true;
         }
@@ -1652,7 +1697,27 @@ BedSkewOffsetDetectionResultType find_bed_offset_and_skew(int8_t verbosity_level
         eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y +0), vec_y[0]);
         eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y +4), vec_y[1]);
     #endif
-
+		if (verbosity_level >= 10) {
+			// Length of the vec_x
+			float l = sqrt(vec_x[0] * vec_x[0] + vec_x[1] * vec_x[1]);
+			SERIAL_ECHOLNPGM("X vector length:");
+			MYSERIAL.println(l);
+
+			// Length of the vec_y
+			l = sqrt(vec_y[0] * vec_y[0] + vec_y[1] * vec_y[1]);
+			SERIAL_ECHOLNPGM("Y vector length:");
+			MYSERIAL.println(l);
+			// Zero point correction
+			l = sqrt(cntr[0] * cntr[0] + cntr[1] * cntr[1]);
+			SERIAL_ECHOLNPGM("Zero point correction:");
+			MYSERIAL.println(l);
+
+			// vec_x and vec_y shall be nearly perpendicular.
+			l = vec_x[0] * vec_y[0] + vec_x[1] * vec_y[1];
+			SERIAL_ECHOLNPGM("Perpendicularity");
+			MYSERIAL.println(fabs(l));
+			SERIAL_ECHOLNPGM("Saving bed calibration vectors to EEPROM");
+		}
         // Correct the current_position to match the transformed coordinate system after world2machine_rotation_and_skew and world2machine_shift were set.
         world2machine_update_current();
 
@@ -2151,11 +2216,14 @@ static int babystepLoadZ = 0;
 
 void babystep_apply()
 {
-    // Apply Z height correction aka baby stepping before mesh bed leveing gets activated.
-    if(eeprom_read_byte((unsigned char*)EEPROM_BABYSTEP_Z_SET) == 0x01)
+    // Apply Z height correction aka baby stepping before mesh bed leveling gets activated.
+    if(calibration_status() == CALIBRATION_STATUS_CALIBRATED)
     {
-        // End of G80: Apply the baby stepping value.
+		check_babystep(); //checking if babystep is in allowed range, otherwise setting babystep to 0
+		
+		// End of G80: Apply the baby stepping value.
         EEPROM_read_B(EEPROM_BABYSTEP_Z,&babystepLoadZ);
+							
     #if 0
         SERIAL_ECHO("Z baby step: ");
         SERIAL_ECHO(babystepLoadZ);

+ 31 - 7
Firmware/pins.h

@@ -39,21 +39,21 @@
   #define X_STEP_PIN 37
   #define X_DIR_PIN 48
   #define X_MIN_PIN 12
-  #define X_MAX_PIN 24
+  #define X_MAX_PIN 30
   #define X_ENABLE_PIN 29
   #define X_MS1_PIN 40
   #define X_MS2_PIN 41
   #define Y_STEP_PIN 36
   #define Y_DIR_PIN 49
   #define Y_MIN_PIN 11
-  #define Y_MAX_PIN 23
+  #define Y_MAX_PIN 24
   #define Y_ENABLE_PIN 28
   #define Y_MS1_PIN 69
   #define Y_MS2_PIN 39
   #define Z_STEP_PIN 35
   #define Z_DIR_PIN 47
   #define Z_MIN_PIN 10
-  #define Z_MAX_PIN 30
+  #define Z_MAX_PIN 23
   #define Z_ENABLE_PIN 27
   #define Z_MS1_PIN 68
   #define Z_MS2_PIN 67
@@ -63,7 +63,23 @@
   #define TEMP_1_PIN 1
   #define TEMP_2_PIN -1
   
-  // The SDSS pin uses a different pin mapping from file Sd2PinMap.h
+#ifdef SNMM 
+
+#define E_MUX0_PIN 17
+#define E_MUX1_PIN 16
+#define E_MUX2_PIN 84
+
+
+#endif
+ 
+#ifdef DIS
+#define D_REQUIRE 30
+#define D_DATA 20
+#define D_DATACLOCK 21
+
+#endif
+
+// The SDSS pin uses a different pin mapping from file Sd2PinMap.h
 #define SDSS               53
 
 #ifndef SDSUPPORT
@@ -209,25 +225,33 @@
 
   #define FR_SENS 21
 
+#ifdef SNMM
+
+#define E_MUX0_PIN 17
+#define E_MUX1_PIN 16
+#define E_MUX2_PIN 84
+
+
+#endif
   #define LARGE_FLASH true
   #define X_STEP_PIN 37
   #define X_DIR_PIN 48
   #define X_MIN_PIN 12
-  #define X_MAX_PIN 24
+  #define X_MAX_PIN 30
   #define X_ENABLE_PIN 29
   #define X_MS1_PIN 40
   #define X_MS2_PIN 41
   #define Y_STEP_PIN 36
   #define Y_DIR_PIN 49
   #define Y_MIN_PIN 11
-  #define Y_MAX_PIN 23
+  #define Y_MAX_PIN 24
   #define Y_ENABLE_PIN 28
   #define Y_MS1_PIN 69
   #define Y_MS2_PIN 39
   #define Z_STEP_PIN 35
   #define Z_DIR_PIN 47
   #define Z_MIN_PIN 10
-  #define Z_MAX_PIN 30
+  #define Z_MAX_PIN 23
   #define Z_ENABLE_PIN 27
   #define Z_MS1_PIN 68
   #define Z_MS2_PIN 67

+ 1 - 1
Firmware/stepper.cpp

@@ -1017,7 +1017,7 @@ void digipot_init() //Initialize Digipot Motor Current
     pinMode(MOTOR_CURRENT_PWM_XY_PIN, OUTPUT);
     pinMode(MOTOR_CURRENT_PWM_Z_PIN, OUTPUT);
     pinMode(MOTOR_CURRENT_PWM_E_PIN, OUTPUT);
-    if(SilentMode == 0){
+    if((SilentMode == 0) || (farm_mode) ){
 
      motor_current_setting[0] = motor_current_setting_loud[0];
      motor_current_setting[1] = motor_current_setting_loud[1];

+ 74 - 10
Firmware/temperature.cpp

@@ -158,6 +158,13 @@ static float analog2temp(int raw, uint8_t e);
 static float analog2tempBed(int raw);
 static void updateTemperaturesFromRawValues();
 
+enum TempRunawayStates
+{
+	TempRunaway_INACTIVE = 0,
+	TempRunaway_PREHEAT = 1,
+	TempRunaway_ACTIVE = 2,
+};
+
 #ifdef WATCH_TEMP_PERIOD
 int watch_start_temp[EXTRUDERS] = ARRAY_BY_EXTRUDERS(0,0,0);
 unsigned long watchmillis[EXTRUDERS] = ARRAY_BY_EXTRUDERS(0,0,0);
@@ -1049,6 +1056,9 @@ void temp_runaway_check(int _heater_id, float _target_temperature, float _curren
 	float __hysteresis = 0;
 	int __timeout = 0;
 	bool temp_runaway_check_active = false;
+	static float __preheat_start = 0;
+	static int __preheat_counter = 0;
+	static int __preheat_errors = 0;
 
 	_heater_id = (_isbed) ? _heater_id++ : _heater_id;
 
@@ -1069,8 +1079,8 @@ void temp_runaway_check(int _heater_id, float _target_temperature, float _curren
 
 	if (millis() - temp_runaway_timer[_heater_id] > 2000)
 	{
-		temp_runaway_timer[_heater_id] = millis();
 
+		temp_runaway_timer[_heater_id] = millis();
 		if (_output == 0)
 		{
 			temp_runaway_check_active = false;
@@ -1081,19 +1091,47 @@ void temp_runaway_check(int _heater_id, float _target_temperature, float _curren
 		{
 			if (_target_temperature > 0)
 			{
-				temp_runaway_status[_heater_id] = 1;
+				temp_runaway_status[_heater_id] = TempRunaway_PREHEAT;
 				temp_runaway_target[_heater_id] = _target_temperature;
+				__preheat_start = _current_temperature;
+				__preheat_counter = 0;
 			}
 			else
 			{
-				temp_runaway_status[_heater_id] = 0;
+				temp_runaway_status[_heater_id] = TempRunaway_INACTIVE;
 				temp_runaway_target[_heater_id] = _target_temperature;
 			}
 		}
 
-		if (_current_temperature >= _target_temperature  && temp_runaway_status[_heater_id] == 1)
+		if (temp_runaway_status[_heater_id] == TempRunaway_PREHEAT)
 		{
-			temp_runaway_status[_heater_id] = 2;
+			if (_current_temperature < 150)
+			{
+				__preheat_counter++;
+				if (__preheat_counter > 8)
+				{
+					if (_current_temperature - __preheat_start < 2) {
+						__preheat_errors++;
+					}
+					else {
+						__preheat_errors = 0;
+					}
+
+					if (__preheat_errors > 5)
+					{
+						if (farm_mode) { prusa_statistics(0); }
+						temp_runaway_stop(true);
+						if (farm_mode) { prusa_statistics(91); }
+					}
+					__preheat_start = _current_temperature;
+					__preheat_counter = 0;
+				}
+			}
+		}
+
+		if (_current_temperature >= _target_temperature  && temp_runaway_status[_heater_id] == TempRunaway_PREHEAT)
+		{
+			temp_runaway_status[_heater_id] = TempRunaway_ACTIVE;
 			temp_runaway_check_active = false;
 		}
 
@@ -1109,16 +1147,18 @@ void temp_runaway_check(int _heater_id, float _target_temperature, float _curren
 			if (_target_temperature - __hysteresis < _current_temperature && _current_temperature < _target_temperature + __hysteresis)
 			{
 				temp_runaway_check_active = false;
+				temp_runaway_error_counter[_heater_id] = 0;
 			}
 			else
 			{
-				if (temp_runaway_status[_heater_id] > 1)
+				if (temp_runaway_status[_heater_id] > TempRunaway_PREHEAT)
 				{
 					temp_runaway_error_counter[_heater_id]++;
-
 					if (temp_runaway_error_counter[_heater_id] * 2 > __timeout)
 					{
-						temp_runaway_stop();
+						if (farm_mode) { prusa_statistics(0); }
+						temp_runaway_stop(false);
+						if (farm_mode) { prusa_statistics(90); }
 					}
 				}
 			}
@@ -1127,7 +1167,7 @@ void temp_runaway_check(int _heater_id, float _target_temperature, float _curren
 	}
 }
 
-void temp_runaway_stop()
+void temp_runaway_stop(bool isPreheat)
 {
 	cancel_heatup = true;
 	quickStop();
@@ -1136,7 +1176,7 @@ void temp_runaway_stop()
 		card.sdprinting = false;
 		card.closefile();
 	}
-	LCD_ALERTMESSAGEPGM("THERMAL RUNAWAY");
+	
 	disable_heater();
 	disable_x();
 	disable_y();
@@ -1149,6 +1189,26 @@ void temp_runaway_stop()
 	delayMicroseconds(500);
 	WRITE(BEEPER, LOW);
 	delayMicroseconds(100);
+
+	if (isPreheat)
+	{
+		Stop();
+		LCD_ALERTMESSAGEPGM("   PREHEAT ERROR");
+		SERIAL_ERROR_START;
+		SERIAL_ERRORLNPGM(": THERMAL RUNAWAY ( PREHEAT )");
+		SET_OUTPUT(EXTRUDER_0_AUTO_FAN_PIN);
+		SET_OUTPUT(FAN_PIN);
+		WRITE(EXTRUDER_0_AUTO_FAN_PIN, 1);
+		analogWrite(FAN_PIN, 255);
+		fanSpeed = 255;
+		delayMicroseconds(2000);
+	}
+	else
+	{
+		LCD_ALERTMESSAGEPGM("THERMAL RUNAWAY");
+		SERIAL_ERROR_START;
+		SERIAL_ERRORLNPGM(": THERMAL RUNAWAY");
+	}
 }
 #endif
 
@@ -1213,6 +1273,7 @@ void max_temp_error(uint8_t e) {
     WRITE(BEEPER, 1);
     // fanSpeed will consumed by the check_axes_activity() routine.
     fanSpeed=255;
+	if (farm_mode) { prusa_statistics(93); }
 }
 
 void min_temp_error(uint8_t e) {
@@ -1226,6 +1287,8 @@ void min_temp_error(uint8_t e) {
   #ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE
   Stop();
   #endif
+  if (farm_mode) { prusa_statistics(92); }
+
 }
 
 void bed_max_temp_error(void) {
@@ -1240,6 +1303,7 @@ void bed_max_temp_error(void) {
   #ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE
   Stop();
   #endif
+
 }
 
 void bed_min_temp_error(void) {

+ 1 - 1
Firmware/temperature.h

@@ -180,7 +180,7 @@ static float temp_runaway_timer[4];
 static int temp_runaway_error_counter[4];
 
 void temp_runaway_check(int _heater_id, float _target_temperature, float _current_temperature, float _output, bool _isbed);
-void temp_runaway_stop();
+void temp_runaway_stop(bool isPreheat);
 #endif
 
 int getHeaterPower(int heater);

+ 1428 - 293
Firmware/ultralcd.cpp

@@ -13,7 +13,7 @@
 #include "mesh_bed_leveling.h"
 //#include "Configuration.h"
 
-
+#include "SdFatUtil.h"
 
 #define _STRINGIFY(s) #s
 
@@ -25,6 +25,8 @@ extern int lcd_change_fil_state;
 //Function pointer to menu functions.
 typedef void (*menuFunc_t)();
 
+static void lcd_sd_updir();
+
 struct EditMenuParentState
 {
     //prevMenu and prevEncoderPosition are used to store the previous menu location when editing settings.
@@ -97,12 +99,17 @@ int8_t SilentModeMenu = 0;
 int lcd_commands_type=LCD_COMMAND_IDLE;
 int lcd_commands_step=0;
 bool isPrintPaused = false;
-bool farm_mode = false;
+uint8_t farm_mode = 0;
 int farm_no = 0;
 int farm_timer = 30;
 int farm_status = 0;
+unsigned long allert_timer = millis();
+bool printer_connected = true;
 
 
+bool long_press_active = false;
+long long_press_timer = millis();
+bool button_pressed = false;
 
 bool menuExiting = false;
 
@@ -149,6 +156,7 @@ static void lcd_control_motion_menu();
 static void lcd_control_volumetric_menu();
 
 static void prusa_stat_printerstatus(int _status);
+static void prusa_stat_farm_number();
 static void prusa_stat_temperatures();
 static void prusa_stat_printinfo();
 static void lcd_farm_no();
@@ -261,15 +269,16 @@ volatile uint8_t buttons_reprapworld_keypad; // to store the reprapworld_keypad
 volatile uint8_t slow_buttons;//Contains the bits of the currently pressed buttons.
 #endif
 uint8_t currentMenuViewOffset;              /* scroll offset in the current menu */
-uint32_t blocking_enc;
 uint8_t lastEncoderBits;
 uint32_t encoderPosition;
+uint32_t savedEncoderPosition;
 #if (SDCARDDETECT > 0)
 bool lcd_oldcardstatus;
 #endif
 #endif //ULTIPANEL
 
 menuFunc_t currentMenu = lcd_status_screen; /* function pointer to the currently active menu */
+menuFunc_t savedMenu;
 uint32_t lcd_next_update_millis;
 uint8_t lcd_status_update_delay;
 bool ignore_click = false;
@@ -392,7 +401,7 @@ static void lcd_status_screen()
 		farm_timer--;
 		if (farm_timer < 1)
 		{
-			farm_timer = 90;
+			farm_timer = 180;
 			prusa_statistics(0);
 		}
 		switch (farm_timer)
@@ -444,7 +453,7 @@ static void lcd_status_screen()
 
   //if (--langsel ==0) {langsel=1;current_click=true;}
 
-  if (current_click)
+  if (current_click && (lcd_commands_type != LCD_COMMAND_STOP_PRINT)) //click is aborted unless stop print finishes
   {
 
     lcd_goto_menu(lcd_main_menu);
@@ -489,54 +498,18 @@ static void lcd_status_screen()
   else if (feedmultiply > 999)
     feedmultiply = 999;
 #endif //ULTIPANEL
+
+  if (farm_mode && !printer_connected) {
+	  lcd.setCursor(0, 3);
+	  lcd_printPGM(MSG_PRINTER_DISCONNECTED);
+  }
+
 }
 
 #ifdef ULTIPANEL
 
 void lcd_commands()
 {
-	if (lcd_commands_type == LCD_COMMAND_LOAD_FILAMENT)   //// load filament sequence
-	{
-		if (lcd_commands_step == 0) { lcd_commands_step = 5; custom_message = true; }
-			if (lcd_commands_step == 1 && !blocks_queued())
-			{
-				lcd_commands_step = 0;
-				lcd_commands_type = 0;
-				lcd_setstatuspgm(WELCOME_MSG);
-				disable_z();
-				custom_message = false;
-				custom_message_type = 0;
-   
-			}
-			if (lcd_commands_step == 2 && !blocks_queued())
-			{
-				lcd_setstatuspgm(MSG_LOADING_FILAMENT);
-				enquecommand_P(PSTR(LOAD_FILAMENT_2));
-				lcd_commands_step = 1;
-			}
-			if (lcd_commands_step == 3 && !blocks_queued())
-			{
-				enquecommand_P(PSTR(LOAD_FILAMENT_1));
-                enquecommand_P(PSTR("G4"));
-				lcd_commands_step = 2;
-			}
-			if (lcd_commands_step == 4 && !blocks_queued())
-			{
-				lcd_setstatuspgm(MSG_INSERT_FILAMENT);
-				enquecommand_P(PSTR(LOAD_FILAMENT_0));
-                enquecommand_P(PSTR("G1 E0.1 F400"));
-				lcd_commands_step = 3;
-			}
-			if (lcd_commands_step == 5 && !blocks_queued())
-			{
-				lcd_setstatuspgm(MSG_PLEASE_WAIT);
-				enable_z();
-				custom_message = true;
-				custom_message_type = 2;
-				lcd_commands_step = 4;
-			}
-	}
-
 	if (lcd_commands_type == LCD_COMMAND_STOP_PRINT)   /// stop print
 	{
 
@@ -547,7 +520,9 @@ void lcd_commands()
 			lcd_commands_step = 0;
 			lcd_commands_type = 0;
 			lcd_setstatuspgm(WELCOME_MSG);
+			custom_message_type = 0;
 			custom_message = false;
+			isPrintPaused = false;
 		}
 		if (lcd_commands_step == 2 && !blocks_queued())
 		{
@@ -564,11 +539,15 @@ void lcd_commands()
 		{
       // M84: Disable steppers.
 			enquecommand_P(PSTR("M84"));
+#ifdef SNMM
+			enquecommand_P(PSTR("PRUSA ResF")); //resets flag at the end of the print (used for SNMM)
+#endif
 			autotempShutdown();
 			lcd_commands_step = 2;
 		}
 		if (lcd_commands_step == 4 && !blocks_queued())
 		{
+			lcd_setstatuspgm(MSG_PLEASE_WAIT);
       // G90: Absolute positioning.
 			enquecommand_P(PSTR("G90"));
       // M83: Set extruder to relative mode.
@@ -579,7 +558,11 @@ void lcd_commands()
 			enquecommand_P(PSTR("G1 X50 Y" STRINGIFY(Y_MAX_POS) " E0 F7000"));
 			#endif
 			lcd_ignore_click(false);
+			#ifdef SNMM
+			lcd_commands_step = 7;
+			#else
 			lcd_commands_step = 3;
+			#endif
 		}
 		if (lcd_commands_step == 5 && !blocks_queued())
 		{
@@ -588,20 +571,83 @@ void lcd_commands()
 			enquecommand_P(PSTR("G91"));
       // Lift up.
 			enquecommand_P(PSTR("G1 Z15 F1500"));
-			lcd_commands_step = 4;
+			if (axis_known_position[X_AXIS] && axis_known_position[Y_AXIS]) lcd_commands_step = 4;
+			else lcd_commands_step = 3;
 		}
 		if (lcd_commands_step == 6 && !blocks_queued())
 		{
 			lcd_setstatuspgm(MSG_PRINT_ABORTED);
 			cancel_heatup = true;
 			setTargetBed(0);
-			setTargetHotend(0, 0);
+			#ifndef SNMM
+			setTargetHotend(0, 0);	//to heating when changing filament for multicolor
 			setTargetHotend(0, 1);
 			setTargetHotend(0, 2);
+			#endif
 			manage_heater();
+			custom_message = true;
+			custom_message_type = 2;
 			lcd_commands_step = 5;
 		}
-
+		if (lcd_commands_step == 7 && !blocks_queued()) {
+			/*ramming();
+			st_synchronize();
+			change_extr(0);*/
+			st_synchronize();
+			enquecommand_P(PSTR("M907 E700")); //set extruder current higher
+			enquecommand_P(PSTR("M203 E50"));
+			st_synchronize();
+			if (current_temperature[0] < 230) {
+				// PLA
+								
+				//enquecommand_P(PSTR("G1 E-8 F2100.000000"));
+				//enquecommand_P(PSTR("G1 E8 F2100.000000"));
+				enquecommand_P(PSTR("G1 E5.4 F2800.000000"));
+				enquecommand_P(PSTR("G1 E3.2 F3000.000000"));
+				enquecommand_P(PSTR("G1 E3 F3400.000000"));
+				enquecommand_P(PSTR("M203 E80"));
+				st_synchronize();
+				enquecommand_P(PSTR("G1 E-82 F9500.000000"));
+				enquecommand_P(PSTR("M203 E50"));
+				enquecommand_P(PSTR("G1 E-20 F1200.000000"));
+				enquecommand_P(PSTR("G1 E5 F400.000000"));
+				enquecommand_P(PSTR("G1 E5 F600.000000"));
+				st_synchronize();
+				enquecommand_P(PSTR("G1 E-10 F600.000000"));
+				enquecommand_P(PSTR("G1 E+10 F600.000000"));
+				enquecommand_P(PSTR("G1 E-10 F800.000000"));
+				enquecommand_P(PSTR("G1 E+10 F800.000000"));
+				enquecommand_P(PSTR("G1 E-10 F800.000000"));
+				st_synchronize();
+			}else {
+				// ABS
+				
+				//enquecommand_P(PSTR("G1 E-8 F2100.000000"));
+				//enquecommand_P(PSTR("G1 E8 F2100.000000"));
+				enquecommand_P(PSTR("G1 E3.1 F2000.000000"));
+				enquecommand_P(PSTR("G1 E3.1 F2500.000000"));
+				enquecommand_P(PSTR("G1 E4 F3000.000000"));
+				st_synchronize();
+				enquecommand_P(PSTR("G4 P4700"));
+				enquecommand_P(PSTR("M203 E80"));
+				enquecommand_P(PSTR("G1 E-92 F9900.000000"));
+				enquecommand_P(PSTR("M203 E50"));
+				enquecommand_P(PSTR("G1 E-5 F800.000000"));
+				enquecommand_P(PSTR("G1 E5 F400.000000"));
+				st_synchronize();
+				enquecommand_P(PSTR("G1 E-5 F600.000000"));
+				enquecommand_P(PSTR("G1 E5 F600.000000"));
+				enquecommand_P(PSTR("G1 E-5 F600.000000"));
+				enquecommand_P(PSTR("G1 E5 F600.000000"));
+				enquecommand_P(PSTR("G1 E5 F600.000000"));
+				st_synchronize();
+			}
+			enquecommand_P(PSTR("T0"));
+			enquecommand_P(PSTR("M907 E550")); //set extruder current to 500
+			//digipot_init();
+			
+			lcd_commands_step = 3;
+		}
 	}
 
 	if (lcd_commands_type == 3)
@@ -643,7 +689,11 @@ void lcd_commands()
 			enquecommand_P(PSTR("G91"));
 			enquecommand_P(PSTR("G1 Z15 F1500"));
 			st_synchronize();
+			#ifdef SNMM
+			lcd_commands_step = 7;
+			#else
 			lcd_commands_step = 5;
+			#endif
 		}
 
 	}
@@ -822,9 +872,8 @@ void lcd_unLoadFilament()
 {
 
   if (degHotend0() > EXTRUDE_MINTEMP) {
-
-    enquecommand_P(PSTR(UNLOAD_FILAMENT_0));
-    enquecommand_P(PSTR(UNLOAD_FILAMENT_1));
+	
+	  enquecommand_P(PSTR("M702")); //unload filament
 
   } else {
 
@@ -934,6 +983,9 @@ void lcd_loading_filament() {
 
 }
 
+
+
+
 void lcd_alright() {
   int enc_dif = 0;
   int cursor_pos = 1;
@@ -1029,10 +1081,9 @@ void lcd_LoadFilament()
   if (degHotend0() > EXTRUDE_MINTEMP) 
   {
 	  custom_message = true;
-	  lcd_commands_type = LCD_COMMAND_LOAD_FILAMENT;
-	  SERIAL_ECHOLN("Loading filament");
-	  // commands() will handle the rest
-    
+	  loading_flag = true;
+	  enquecommand_P(PSTR("M701")); //load filament
+	  SERIAL_ECHOLN("Loading filament");	    
     }
   else 
   {
@@ -1049,7 +1100,7 @@ void lcd_LoadFilament()
 }
 
 
-static void lcd_menu_statistics()
+void lcd_menu_statistics()
 {
 
 	if (IS_SD_PRINTING)
@@ -1058,7 +1109,6 @@ static void lcd_menu_statistics()
 		int _cm = (total_filament_used - (_met * 100000))/10;
 		
 		int _t = (millis() - starttime) / 1000;
-
 		int _h = _t / 3600;
 		int _m = (_t - (_h * 3600)) / 60;
 		int _s = _t - ((_h * 3600) + (_m * 60));
@@ -1092,8 +1142,10 @@ static void lcd_menu_statistics()
 	else
 	{
 		unsigned long _filament = eeprom_read_dword((uint32_t *)EEPROM_FILAMENTUSED);
-		unsigned long _time = eeprom_read_dword((uint32_t *)EEPROM_TOTALTIME);
-		uint8_t _days, _hours, _minutes;
+		unsigned long _time = eeprom_read_dword((uint32_t *)EEPROM_TOTALTIME); //in minutes
+		
+		uint8_t _hours, _minutes;
+		uint32_t _days;
 
 		float _filament_m = (float)_filament;
 		int _filament_km = (_filament >= 100000) ? _filament / 100000 : 0;
@@ -1162,7 +1214,7 @@ static void lcd_menu_statistics()
 
 
 static void _lcd_move(const char *name, int axis, int min, int max) {
-  if (encoderPosition != 0) {
+	if (encoderPosition != 0) {
     refresh_cmd_timeout();
     if (! planner_queue_full()) {
       current_position[axis] += float((int)encoderPosition) * move_menu_scale;
@@ -1175,12 +1227,14 @@ static void _lcd_move(const char *name, int axis, int min, int max) {
     }
   }
   if (lcdDrawUpdate) lcd_implementation_drawedit(name, ftostr31(current_position[axis]));
-  if (LCD_CLICKED) lcd_goto_menu(lcd_move_menu_axis);
+  if (LCD_CLICKED) lcd_goto_menu(lcd_move_menu_axis); {
+  }
 }
 
 
 static void lcd_move_e()
 {
+	if (degHotend0() > EXTRUDE_MINTEMP) {
   if (encoderPosition != 0)
   {
     refresh_cmd_timeout();
@@ -1197,6 +1251,17 @@ static void lcd_move_e()
   }
   if (LCD_CLICKED) lcd_goto_menu(lcd_move_menu_axis);
 }
+	else {
+		lcd_implementation_clear();
+		lcd.setCursor(0, 0);
+		lcd_printPGM(MSG_ERROR);
+		lcd.setCursor(0, 2);
+		lcd_printPGM(MSG_PREHEAT_NOZZLE);
+
+		delay(2000);
+		lcd_return_to_status();
+	}
+}
 
 
 // Save a single axis babystep value.
@@ -1237,22 +1302,37 @@ static void _lcd_babystep(int axis, const char *msg)
         // Menu was entered.
         // Initialize its status.
         menuData.babyStep.status = 1;
-        EEPROM_read_B(EEPROM_BABYSTEP_X, &menuData.babyStep.babystepMem[0]);
+		check_babystep();
+
+		EEPROM_read_B(EEPROM_BABYSTEP_X, &menuData.babyStep.babystepMem[0]);
         EEPROM_read_B(EEPROM_BABYSTEP_Y, &menuData.babyStep.babystepMem[1]);
         EEPROM_read_B(EEPROM_BABYSTEP_Z, &menuData.babyStep.babystepMem[2]);
+		
         menuData.babyStep.babystepMemMM[0] = menuData.babyStep.babystepMem[0]/axis_steps_per_unit[X_AXIS];
         menuData.babyStep.babystepMemMM[1] = menuData.babyStep.babystepMem[1]/axis_steps_per_unit[Y_AXIS];
         menuData.babyStep.babystepMemMM[2] = menuData.babyStep.babystepMem[2]/axis_steps_per_unit[Z_AXIS];
         lcdDrawUpdate = 1;
+		//SERIAL_ECHO("Z baby step: ");
+		//SERIAL_ECHO(menuData.babyStep.babystepMem[2]);
+        // Wait 90 seconds before closing the live adjust dialog.
+        lcd_timeoutToStatus = millis() + 90000;
     }
 
   if (encoderPosition != 0) 
   {
-    CRITICAL_SECTION_START
-    babystepsTodo[axis] += (int)encoderPosition;
-    CRITICAL_SECTION_END
+	if (homing_flag) encoderPosition = 0;
+
     menuData.babyStep.babystepMem[axis] += (int)encoderPosition;
-    menuData.babyStep.babystepMemMM[axis] = menuData.babyStep.babystepMem[axis]/axis_steps_per_unit[Z_AXIS];
+	if (axis == 2) {
+		if (menuData.babyStep.babystepMem[axis] < Z_BABYSTEP_MIN) menuData.babyStep.babystepMem[axis] = Z_BABYSTEP_MIN; //-3999 -> -9.99 mm
+		else  if (menuData.babyStep.babystepMem[axis] > Z_BABYSTEP_MAX) menuData.babyStep.babystepMem[axis] = Z_BABYSTEP_MAX; //0
+		else {
+			CRITICAL_SECTION_START
+				babystepsTodo[axis] += (int)encoderPosition;
+			CRITICAL_SECTION_END		
+		}
+	}
+    menuData.babyStep.babystepMemMM[axis] = menuData.babyStep.babystepMem[axis]/axis_steps_per_unit[axis]; 
 	  delay(50);
 	  encoderPosition = 0;
     lcdDrawUpdate = 1;
@@ -1293,6 +1373,17 @@ static void lcd_adjust_bed_reset()
     menuData.adjustBed.status = 0;
 }
 
+void adjust_bed_reset() {
+	eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_VALID, 1);
+	eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_LEFT, 0);
+	eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_RIGHT, 0);
+	eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_FRONT, 0);
+	eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_REAR, 0);
+	menuData.adjustBed.left = menuData.adjustBed.left2 = 0;
+	menuData.adjustBed.right = menuData.adjustBed.right2 = 0;
+	menuData.adjustBed.front = menuData.adjustBed.front2 = 0;
+	menuData.adjustBed.rear = menuData.adjustBed.rear2 = 0;
+}
 #define BED_ADJUSTMENT_UM_MAX 50
 
 static void lcd_adjust_bed()
@@ -1426,6 +1517,28 @@ void lcd_adjust_z() {
 
 }
 
+void lcd_wait_for_cool_down() {
+	lcd_set_custom_characters_degree();
+	while ((degHotend(0)>MAX_HOTEND_TEMP_CALIBRATION) || (degBed() > MAX_BED_TEMP_CALIBRATION)) {
+		lcd_display_message_fullscreen_P(MSG_WAITING_TEMP);
+
+		lcd.setCursor(0, 4);
+		lcd.print(LCD_STR_THERMOMETER[0]);
+		lcd.print(ftostr3(degHotend(0)));
+		lcd.print("/0");		
+		lcd.print(LCD_STR_DEGREE);
+
+		lcd.setCursor(9, 4);
+		lcd.print(LCD_STR_BEDTEMP[0]);
+		lcd.print(ftostr3(degBed()));
+		lcd.print("/0");		
+		lcd.print(LCD_STR_DEGREE);
+		lcd_set_custom_characters();
+		delay_keep_alive(1000);
+	}
+	lcd_set_custom_characters_arrows();
+}
+
 // Lets the user move the Z carriage up to the end stoppers.
 // When done, it sets the current Z to Z_MAX_POS and returns true.
 // Otherwise the Z calibration is not changed and false is returned.
@@ -1484,6 +1597,7 @@ bool lcd_calibrate_z_end_stop_manual(bool only_z)
             lcd_show_fullscreen_message_and_wait_P(MSG_CONFIRM_NOZZLE_CLEAN);
             clean_nozzle_asked = true;
         }
+		
 
         // Let the user confirm, that the Z carriage is at the top end stoppers.
         int8_t result = lcd_show_fullscreen_message_yes_no_and_wait_P(MSG_CONFIRM_CARRIAGE_AT_THE_TOP, false);
@@ -1499,6 +1613,20 @@ calibrated:
     // during the search for the induction points.
     current_position[Z_AXIS] = Z_MAX_POS-3.f;
     plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
+    
+    
+    if(only_z){
+        lcd_display_message_fullscreen_P(MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1);
+        lcd_implementation_print_at(0, 3, 1);
+        lcd_printPGM(MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2);
+    }else{
+		lcd_show_fullscreen_message_and_wait_P(MSG_PAPER);
+        lcd_display_message_fullscreen_P(MSG_FIND_BED_OFFSET_AND_SKEW_LINE1);
+        lcd_implementation_print_at(0, 2, 1);
+        lcd_printPGM(MSG_FIND_BED_OFFSET_AND_SKEW_LINE2);
+    }
+    
+    
     return true;
 
 canceled:
@@ -1613,49 +1741,58 @@ void lcd_wait_for_click()
     }
 }
 
-int8_t lcd_show_fullscreen_message_yes_no_and_wait_P(const char *msg, bool allow_timeouting)
+int8_t lcd_show_fullscreen_message_yes_no_and_wait_P(const char *msg, bool allow_timeouting, bool default_yes)
 {
-    lcd_display_message_fullscreen_P(msg);
 
-    lcd.setCursor(1, 2);
-    lcd_printPGM(MSG_YES);
-    lcd.setCursor(0, 3);
-    lcd_printPGM(PSTR(">"));
-    lcd_printPGM(MSG_NO);
-    bool yes = false;
-
-    // Wait for user confirmation or a timeout.
-    unsigned long previous_millis_cmd = millis();
-    int8_t        enc_dif = encoderDiff;
-    for (;;) {
-        if (allow_timeouting && millis() - previous_millis_cmd > LCD_TIMEOUT_TO_STATUS)
-            return -1;
-        manage_heater();
-        manage_inactivity(true);
-        if (abs((enc_dif - encoderDiff)) > 4) {
-            if (abs(enc_dif - encoderDiff) > 1) {
-                lcd.setCursor(0, 2);
-                if (enc_dif > encoderDiff && yes) {
-                    lcd_printPGM((PSTR(" ")));
-                    lcd.setCursor(0, 3);
-                    lcd_printPGM((PSTR(">")));
-                    yes = false;
-                } else if (enc_dif < encoderDiff && ! yes) {
-                    lcd_printPGM((PSTR(">")));
-                    lcd.setCursor(0, 3);
-                    lcd_printPGM((PSTR(" ")));
-                    yes = true;
-                }
-                enc_dif = encoderDiff;
-            }
-        }
-        if (lcd_clicked()) {
-            while (lcd_clicked()) ;
-            delay(10);
-            while (lcd_clicked()) ;
-            return yes;
-        }
-    }
+	lcd_display_message_fullscreen_P(msg);
+	
+	if (default_yes) {
+		lcd.setCursor(0, 2);
+		lcd_printPGM(PSTR(">"));
+		lcd_printPGM(MSG_YES);
+		lcd.setCursor(1, 3);
+		lcd_printPGM(MSG_NO);
+	}
+	else {
+		lcd.setCursor(1, 2);
+		lcd_printPGM(MSG_YES);
+		lcd.setCursor(0, 3);
+		lcd_printPGM(PSTR(">"));
+		lcd_printPGM(MSG_NO);
+	}
+	bool yes = default_yes ? true : false;
+
+	// Wait for user confirmation or a timeout.
+	unsigned long previous_millis_cmd = millis();
+	int8_t        enc_dif = encoderDiff;
+	for (;;) {
+		if (allow_timeouting && millis() - previous_millis_cmd > LCD_TIMEOUT_TO_STATUS)
+			return -1;
+		manage_heater();
+		manage_inactivity(true);
+		if (abs(enc_dif - encoderDiff) > 4) {
+			lcd.setCursor(0, 2);
+				if (enc_dif < encoderDiff && yes) {
+					lcd_printPGM((PSTR(" ")));
+					lcd.setCursor(0, 3);
+					lcd_printPGM((PSTR(">")));
+					yes = false;
+				}
+				else if (enc_dif > encoderDiff && !yes) {
+					lcd_printPGM((PSTR(">")));
+					lcd.setCursor(0, 3);
+					lcd_printPGM((PSTR(" ")));
+					yes = true;
+				}
+				enc_dif = encoderDiff;
+		}
+		if (lcd_clicked()) {
+			while (lcd_clicked());
+			delay(10);
+			while (lcd_clicked());
+			return yes;
+		}
+	}
 }
 
 void lcd_bed_calibration_show_result(BedSkewOffsetDetectionResultType result, uint8_t point_too_far_mask)
@@ -1751,6 +1888,7 @@ void lcd_diag_show_end_stops()
 
 
 void prusa_statistics(int _message) {
+	
 
 	switch (_message)
 	{
@@ -1760,14 +1898,18 @@ void prusa_statistics(int _message) {
 		{
 			SERIAL_ECHO("{");
 			prusa_stat_printerstatus(4);
+			prusa_stat_farm_number();
 			prusa_stat_printinfo();
 			SERIAL_ECHOLN("}");
+			status_number = 4;
 		}
 		else
 		{
 			SERIAL_ECHO("{");
 			prusa_stat_printerstatus(1);
+			prusa_stat_farm_number();
 			SERIAL_ECHOLN("}");
+			status_number = 1;
 		}
 		break;
 
@@ -1775,7 +1917,9 @@ void prusa_statistics(int _message) {
 		farm_status = 2;
 		SERIAL_ECHO("{");
 		prusa_stat_printerstatus(2);
+		prusa_stat_farm_number();
 		SERIAL_ECHOLN("}");
+		status_number = 2;
 		farm_timer = 1;
 		break;
 
@@ -1783,7 +1927,9 @@ void prusa_statistics(int _message) {
 		farm_status = 3;
 		SERIAL_ECHO("{");
 		prusa_stat_printerstatus(3);
+		prusa_stat_farm_number();
 		SERIAL_ECHOLN("}");
+		status_number = 3;
 		farm_timer = 1;
 
 		if (IS_SD_PRINTING)
@@ -1791,13 +1937,17 @@ void prusa_statistics(int _message) {
 			farm_status = 4;
 			SERIAL_ECHO("{");
 			prusa_stat_printerstatus(4);
+			prusa_stat_farm_number();
 			SERIAL_ECHOLN("}");
+			status_number = 4;
 		}
 		else
 		{
 			SERIAL_ECHO("{");
 			prusa_stat_printerstatus(3);
-			SERIAL_ECHOLN("}");;
+			prusa_stat_farm_number();
+			SERIAL_ECHOLN("}");
+			status_number = 3;
 		}
 		farm_timer = 1;
 		break;
@@ -1806,45 +1956,88 @@ void prusa_statistics(int _message) {
 
 		break;
 	case 4:		// print succesfull
-		SERIAL_ECHOLN("{[RES:1]}");
+		SERIAL_ECHOLN("{[RES:1]");
+		prusa_stat_printerstatus(status_number);
+		prusa_stat_farm_number();
+		SERIAL_ECHOLN("}");
 		farm_timer = 2;
 		break;
 	case 5:		// print not succesfull
-		SERIAL_ECHOLN("{[RES:0]}");
+		SERIAL_ECHOLN("{[RES:0]");
+		prusa_stat_printerstatus(status_number);
+		prusa_stat_farm_number();
+		SERIAL_ECHOLN("}");
 		farm_timer = 2;
 		break;
 	case 6:		// print done
-		SERIAL_ECHOLN("{[PRN:8]}");
+		SERIAL_ECHOLN("{[PRN:8]");
+		prusa_stat_farm_number();
+		SERIAL_ECHOLN("}");
+		status_number = 8;
 		farm_timer = 2;
 		break;
 	case 7:		// print done - stopped
-		SERIAL_ECHOLN("{[PRN:9]}");
+		SERIAL_ECHOLN("{[PRN:9]");
+		prusa_stat_farm_number();
+		SERIAL_ECHOLN("}");
+		status_number = 9;
 		farm_timer = 2;
 		break;
 	case 8:		// printer started
 		SERIAL_ECHO("{[PRN:0][PFN:");
+		status_number = 0;
 		SERIAL_ECHO(farm_no);
 		SERIAL_ECHOLN("]}");
 		farm_timer = 2;
 		break;
 	case 20:		// echo farm no
-		SERIAL_ECHO("{[PFN:");
-		SERIAL_ECHO(farm_no);
-		SERIAL_ECHOLN("]}");
+		SERIAL_ECHOLN("{");
+		prusa_stat_printerstatus(status_number);
+		prusa_stat_farm_number();
+		SERIAL_ECHOLN("}");
 		farm_timer = 5;
 		break;
 	case 21: // temperatures
 		SERIAL_ECHO("{");
 		prusa_stat_temperatures();
+		prusa_stat_farm_number();
+		prusa_stat_printerstatus(status_number);
 		SERIAL_ECHOLN("}");
 		break;
     case 22: // waiting for filament change
-        SERIAL_ECHOLN("{[PRN:5]}");
+        SERIAL_ECHOLN("{[PRN:5]");
+		prusa_stat_farm_number();
+		SERIAL_ECHOLN("}");
+		status_number = 5;
         break;
-            
+	
+	case 90: // Error - Thermal Runaway
+		SERIAL_ECHOLN("{[ERR:1]");
+		prusa_stat_farm_number();
+		SERIAL_ECHOLN("}");
+		break;
+	case 91: // Error - Thermal Runaway Preheat
+		SERIAL_ECHOLN("{[ERR:2]");
+		prusa_stat_farm_number();
+		SERIAL_ECHOLN("}");
+		break;
+	case 92: // Error - Min temp
+		SERIAL_ECHOLN("{[ERR:3]");
+		prusa_stat_farm_number();
+		SERIAL_ECHOLN("}");
+		break;
+	case 93: // Error - Max temp
+		SERIAL_ECHOLN("{[ERR:4]");
+		prusa_stat_farm_number();
+		SERIAL_ECHOLN("}");
+		break;
+
     case 99:		// heartbeat
         SERIAL_ECHO("{[PRN:99]");
         prusa_stat_temperatures();
+		SERIAL_ECHO("[PFN:");
+		SERIAL_ECHO(farm_no);
+		SERIAL_ECHO("]");
         SERIAL_ECHOLN("}");
             
         break;
@@ -1859,6 +2052,12 @@ static void prusa_stat_printerstatus(int _status)
 	SERIAL_ECHO("]");
 }
 
+static void prusa_stat_farm_number() {
+	SERIAL_ECHO("[PFN:");
+	SERIAL_ECHO(farm_no);
+	SERIAL_ECHO("]");
+}
+
 static void prusa_stat_temperatures()
 {
 	SERIAL_ECHO("[ST0:");
@@ -1984,41 +2183,30 @@ void lcd_pick_babystep(){
             
         }
         
-        
         if (lcd_clicked()) {
             fsm = cursor_pos;
             int babyStepZ;
             EEPROM_read_B(EEPROM_BABYSTEP_Z0+((fsm-1)*2),&babyStepZ);
             EEPROM_save_B(EEPROM_BABYSTEP_Z,&babyStepZ);
-            eeprom_write_byte((unsigned char*)EEPROM_BABYSTEP_Z_SET, 0x01);
+            calibration_status_store(CALIBRATION_STATUS_CALIBRATED);
             delay(500);
             
         }
-        
-        
-        
     };
     
-    
     lcd_implementation_clear();
     lcd_return_to_status();
 }
 
 void lcd_move_menu_axis()
 {
-  START_MENU();
-  MENU_ITEM(back, MSG_SETTINGS, lcd_settings_menu);
-  MENU_ITEM(submenu, MSG_MOVE_X, lcd_move_x);
-  MENU_ITEM(submenu, MSG_MOVE_Y, lcd_move_y);
-  if (move_menu_scale < 10.0)
-  {
-	  if (!isPrintPaused)
-	  {
-		  MENU_ITEM(submenu, MSG_MOVE_Z, lcd_move_z);
-	  }
-	  MENU_ITEM(submenu, MSG_MOVE_E, lcd_move_e);
-  }
-  END_MENU();
+	START_MENU();
+	MENU_ITEM(back, MSG_SETTINGS, lcd_settings_menu);
+	MENU_ITEM(submenu, MSG_MOVE_X, lcd_move_x);
+	MENU_ITEM(submenu, MSG_MOVE_Y, lcd_move_y);
+	MENU_ITEM(submenu, MSG_MOVE_Z, lcd_move_z);
+	MENU_ITEM(submenu, MSG_MOVE_E, lcd_move_e);
+	END_MENU();
 }
 
 static void lcd_move_menu_1mm()
@@ -2103,6 +2291,103 @@ void lcd_mesh_calibration_z()
   lcd_return_to_status();
 }
 
+#ifndef SNMM
+
+/*void lcd_calibrate_extruder() {
+	
+	if (degHotend0() > EXTRUDE_MINTEMP)
+	{
+		current_position[E_AXIS] = 0;									//set initial position to zero
+		plan_set_e_position(current_position[E_AXIS]);
+		
+		//long steps_start = st_get_position(E_AXIS);
+
+		long steps_final;
+		float e_steps_per_unit;
+		float feedrate = (180 / axis_steps_per_unit[E_AXIS]) * 1;	//3	//initial automatic extrusion feedrate (depends on current value of axis_steps_per_unit to avoid too fast extrusion)
+		float e_shift_calibration = (axis_steps_per_unit[E_AXIS] > 180 ) ? ((180 / axis_steps_per_unit[E_AXIS]) * 70): 70; //length of initial automatic extrusion sequence
+		const char   *msg_e_cal_knob = MSG_E_CAL_KNOB;
+		const char   *msg_next_e_cal_knob = lcd_display_message_fullscreen_P(msg_e_cal_knob);
+		const bool    multi_screen = msg_next_e_cal_knob != NULL;
+		unsigned long msg_millis;
+
+		lcd_show_fullscreen_message_and_wait_P(MSG_MARK_FIL);
+		lcd_implementation_clear();
+		
+		
+		lcd.setCursor(0, 1); lcd_printPGM(MSG_PLEASE_WAIT);
+		current_position[E_AXIS] += e_shift_calibration;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], feedrate, active_extruder);
+		st_synchronize();
+
+		lcd_display_message_fullscreen_P(msg_e_cal_knob);
+		msg_millis = millis();
+		while (!LCD_CLICKED) {
+			if (multi_screen && millis() - msg_millis > 5000) {
+				if (msg_next_e_cal_knob == NULL)
+					msg_next_e_cal_knob = msg_e_cal_knob;
+					msg_next_e_cal_knob = lcd_display_message_fullscreen_P(msg_next_e_cal_knob);
+					msg_millis = millis();
+			}
+
+			//manage_inactivity(true);
+			manage_heater();
+			if (abs(encoderDiff) >= ENCODER_PULSES_PER_STEP) {						//adjusting mark by knob rotation
+				delay_keep_alive(50);
+				//previous_millis_cmd = millis();
+				encoderPosition += (encoderDiff / ENCODER_PULSES_PER_STEP);
+				encoderDiff = 0;
+				if (!planner_queue_full()) {
+					current_position[E_AXIS] += float(abs((int)encoderPosition)) * 0.01; //0.05
+					encoderPosition = 0;
+					plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], feedrate, active_extruder);
+					
+				}
+			}	
+		}
+		
+		steps_final = current_position[E_AXIS] * axis_steps_per_unit[E_AXIS];
+		//steps_final = st_get_position(E_AXIS);
+		lcdDrawUpdate = 1;
+		e_steps_per_unit = ((float)(steps_final)) / 100.0f;
+		if (e_steps_per_unit < MIN_E_STEPS_PER_UNIT) e_steps_per_unit = MIN_E_STEPS_PER_UNIT;				
+		if (e_steps_per_unit > MAX_E_STEPS_PER_UNIT) e_steps_per_unit = MAX_E_STEPS_PER_UNIT;
+
+		lcd_implementation_clear();
+
+		axis_steps_per_unit[E_AXIS] = e_steps_per_unit;
+		enquecommand_P(PSTR("M500")); //store settings to eeprom
+	
+		//lcd_implementation_drawedit(PSTR("Result"), ftostr31(axis_steps_per_unit[E_AXIS]));
+		//delay_keep_alive(2000);
+		delay_keep_alive(500);
+		lcd_show_fullscreen_message_and_wait_P(MSG_CLEAN_NOZZLE_E);
+		lcd_update_enable(true);
+		lcdDrawUpdate = 2;
+
+	}
+	else
+	{
+		lcd_implementation_clear();
+		lcd.setCursor(0, 0);
+		lcd_printPGM(MSG_ERROR);
+		lcd.setCursor(0, 2);
+		lcd_printPGM(MSG_PREHEAT_NOZZLE);
+		delay(2000);
+		lcd_implementation_clear();
+	}
+	lcd_return_to_status();
+}
+
+void lcd_extr_cal_reset() {
+	float tmp1[] = DEFAULT_AXIS_STEPS_PER_UNIT;
+	axis_steps_per_unit[E_AXIS] = tmp1[3];
+	//extrudemultiply = 100;
+	enquecommand_P(PSTR("M500"));
+}*/
+
+#endif
+
 void lcd_toshiba_flash_air_compatibility_toggle()
 {
    card.ToshibaFlashAir_enable(! card.ToshibaFlashAir_isEnabled());
@@ -2117,22 +2402,24 @@ static void lcd_settings_menu()
   MENU_ITEM(back, MSG_MAIN, lcd_main_menu);
 
   MENU_ITEM(submenu, MSG_TEMPERATURE, lcd_control_temperature_menu);
-  MENU_ITEM(submenu, MSG_MOVE_AXIS, lcd_move_menu_1mm);
-  
+  if (!homing_flag)
+  {
+	  MENU_ITEM(submenu, MSG_MOVE_AXIS, lcd_move_menu_1mm);
+  }
   if (!isPrintPaused)
   {
 	  MENU_ITEM(gcode, MSG_DISABLE_STEPPERS, PSTR("M84"));
   }
 
-  if (SilentModeMenu == 0) {
+  if ((SilentModeMenu == 0) || (farm_mode) ) {
     MENU_ITEM(function, MSG_SILENT_MODE_OFF, lcd_silent_mode_set);
   } else {
     MENU_ITEM(function, MSG_SILENT_MODE_ON, lcd_silent_mode_set);
   }
   
-	if (!isPrintPaused)
+	if (!isPrintPaused && !homing_flag)
 	{
-		MENU_ITEM(submenu, MSG_BABYSTEP_Z, lcd_babystep_z);//8
+		MENU_ITEM(submenu, MSG_BABYSTEP_Z, lcd_babystep_z);
 	}
 	MENU_ITEM(submenu, MSG_LANGUAGE_SELECT, lcd_language_menu);
 
@@ -2145,6 +2432,7 @@ static void lcd_settings_menu()
     if (farm_mode)
     {
         MENU_ITEM(submenu, PSTR("Farm number"), lcd_farm_no);
+		MENU_ITEM(function, PSTR("Disable farm mode"), lcd_disable_farm_mode);
     }
 
 	END_MENU();
@@ -2156,16 +2444,19 @@ static void lcd_calibration_menu()
   MENU_ITEM(back, MSG_MAIN, lcd_main_menu);
   if (!isPrintPaused)
   {
-    MENU_ITEM(submenu, MSG_SELFTEST, lcd_selftest);
+    MENU_ITEM(function, MSG_SELFTEST, lcd_selftest);
 #ifndef MESH_BED_LEVELING
     // MK1
     // "Calibrate Z"
     MENU_ITEM(gcode, MSG_HOMEYZ, PSTR("G28 Z"));
 #else
     // MK2
-    MENU_ITEM(submenu, MSG_CALIBRATE_BED, lcd_mesh_calibration);
+MENU_ITEM(function, MSG_CALIBRATE_BED, lcd_mesh_calibration);
     // "Calibrate Z" with storing the reference values to EEPROM.
     MENU_ITEM(submenu, MSG_HOMEYZ, lcd_mesh_calibration_z);
+#ifndef SNMM
+	//MENU_ITEM(function, MSG_CALIBRATE_E, lcd_calibrate_extruder);
+#endif
     // "Mesh Bed Leveling"
     MENU_ITEM(submenu, MSG_MESH_BED_LEVELING, lcd_mesh_bedleveling);
 #endif
@@ -2173,6 +2464,9 @@ static void lcd_calibration_menu()
     MENU_ITEM(submenu, MSG_BED_CORRECTION_MENU, lcd_adjust_bed);
     MENU_ITEM(submenu, MSG_SHOW_END_STOPS, menu_show_end_stops);
     MENU_ITEM(gcode, MSG_CALIBRATE_BED_RESET, PSTR("M44"));
+#ifndef SNMM
+	//MENU_ITEM(function, MSG_RESET_CALIBRATE_E, lcd_extr_cal_reset);
+#endif
   }
   
   END_MENU();
@@ -2357,94 +2651,477 @@ void lcd_mylang() {
 
 }
 
-
-
-static void lcd_farm_no()
-{
+char reset_menu() {
 	int enc_dif = 0;
-	int _farmno = farm_no;
-	int _ret = 0;
+	char cursor_pos = 0;
+
 	lcd_implementation_clear();
 
+	lcd.setCursor(1, 0);
+
+	lcd_printPGM(PSTR("Language"));
+		
+
+	lcd.setCursor(1, 1);
+
+	lcd_printPGM(PSTR("Statistics"));
+
+
+	lcd.setCursor(1, 2);
+	
+	lcd_printPGM(PSTR("Shiping prep"));
+
+	lcd.setCursor(1, 3);
+	
+	lcd_printPGM(PSTR("All data"));
+
 	lcd.setCursor(0, 0);
-	lcd.print("Farm no");
 
-	do
-	{
+	lcd.print(">");
 
-		if (abs((enc_dif - encoderDiff)) > 2) {
-			if (enc_dif > encoderDiff) {
-				_farmno--;
-			}
 
-			if (enc_dif < encoderDiff) {
-				_farmno++;
-			}
-			enc_dif = 0;
-			encoderDiff = 0;
-		}
+	enc_dif = encoderDiff;
 
-		if (_farmno > 254) { _farmno = 1; }
-		if (_farmno < 1) { _farmno = 254; }
+	while (1) {
 
+		manage_heater();
+		manage_inactivity(true);
+
+		if (abs((enc_dif - encoderDiff)) > 4) {
+
+			if ((abs(enc_dif - encoderDiff)) > 1) {
+				if (enc_dif > encoderDiff) {
+					cursor_pos--;
+				}
+
+				if (enc_dif < encoderDiff) {
+					cursor_pos++;
+				}
+
+				if (cursor_pos > 3) {
+					cursor_pos = 3;
+				}
+
+				if (cursor_pos < 0) {
+					cursor_pos = 0;
+				}
+				lcd.setCursor(0, 0);
+				lcd.print(" ");
+				lcd.setCursor(0, 1);
+				lcd.print(" ");
+				lcd.setCursor(0, 2);
+				lcd.print(" ");
+				lcd.setCursor(0, 3);
+				lcd.print(" ");
+				lcd.setCursor(0, cursor_pos);
+				lcd.print(">");
+				enc_dif = encoderDiff;
+				delay(100);
+			}
 
-		lcd.setCursor(0, 2);
-		lcd.print(_farmno);
-		lcd.print("  ");
-		delay(100);
+		}
 
-		if (lcd_clicked())
-		{
-			_ret = 1;
-			farm_no = _farmno;
-			EEPROM_save_B(EEPROM_FARM_MODE, &farm_no);
-			prusa_statistics(20);
-			lcd_return_to_status();
+		if (lcd_clicked()) {
+			while (lcd_clicked());
+			delay(10);
+			while (lcd_clicked());
+			return(cursor_pos);
 		}
 
-		manage_heater();
-	} while (_ret == 0);
+	}
 
 }
 
-void lcd_confirm_print()
-{
-	int enc_dif = 0;
-	int cursor_pos = 1;
-	int _ret = 0;
-	int _t = 0;
+static void lcd_disable_farm_mode() {
+	int8_t disable = lcd_show_fullscreen_message_yes_no_and_wait_P(PSTR("Disable farm mode?"), true, false); //allow timeouting, default no
+	if (disable) {
+		enquecommand_P(PSTR("G99"));
+		lcd_return_to_status();
+	}
+	else {
+		lcd_goto_menu(lcd_settings_menu);
+	}
+	lcd_update_enable(true);
+	lcdDrawUpdate = 2;
+	
+}
 
+static void lcd_ping_allert() {
+	if ((abs(millis() - allert_timer)*0.001) > PING_ALLERT_PERIOD) {
+		allert_timer = millis();
+		SET_OUTPUT(BEEPER);
+		for (int i = 0; i < 2; i++) {
+			WRITE(BEEPER, HIGH);
+			delay(50);
+			WRITE(BEEPER, LOW);
+			delay(100);
+		}
+	}
 
-	lcd_implementation_clear();
+};
 
-	lcd.setCursor(0, 0);
-	lcd.print("Print ok ?");
 
-	do
-	{
+#ifdef SNMM
 
-		if (abs((enc_dif - encoderDiff)) > 2) {
-			if (enc_dif > encoderDiff) {
-				cursor_pos--;
-			}
+static 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;
+	plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], feed_rate, active_extruder);
+	set_extrude_min_temp(EXTRUDE_MINTEMP);
+}
 
-			if (enc_dif < encoderDiff) {
-				cursor_pos++;
-			}
-		}
 
-		if (cursor_pos > 2) { cursor_pos = 2; }
-		if (cursor_pos < 1) { cursor_pos = 1; }
+void change_extr(int extr) { //switches multiplexer for extruders
+	st_synchronize();
+	delay(100);
 
-		lcd.setCursor(0, 2); lcd.print("          ");
-		lcd.setCursor(0, 3); lcd.print("          ");
-		lcd.setCursor(2, 2);
-		lcd_printPGM(MSG_YES);
-		lcd.setCursor(2, 3);
-		lcd_printPGM(MSG_NO);
-		lcd.setCursor(0, 1 + cursor_pos);
-		lcd.print(">");
-		delay(100);
+	disable_e0();
+	disable_e1();
+	disable_e2();
+
+	pinMode(E_MUX0_PIN, OUTPUT);
+	pinMode(E_MUX1_PIN, OUTPUT);
+	pinMode(E_MUX2_PIN, OUTPUT);
+	switch (extr) {
+	case 1:
+		WRITE(E_MUX0_PIN, HIGH);
+		WRITE(E_MUX1_PIN, LOW);
+		WRITE(E_MUX2_PIN, LOW);
+		
+		break;
+	case 2:
+		WRITE(E_MUX0_PIN, LOW);
+		WRITE(E_MUX1_PIN, HIGH);
+		WRITE(E_MUX2_PIN, LOW);
+		
+		break;
+	case 3:
+		WRITE(E_MUX0_PIN, HIGH);
+		WRITE(E_MUX1_PIN, HIGH);
+		WRITE(E_MUX2_PIN, LOW);
+		
+		break;
+	default:
+		WRITE(E_MUX0_PIN, LOW);
+		WRITE(E_MUX1_PIN, LOW);
+		WRITE(E_MUX2_PIN, LOW);
+		
+		break;
+	}
+	delay(100);
+}
+
+static int get_ext_nr() { //reads multiplexer input pins and return current extruder number (counted from 0)
+	return(4 * READ(E_MUX2_PIN) + 2 * READ(E_MUX1_PIN) + READ(E_MUX0_PIN));
+}
+
+
+static void extr_adj(int extruder) //loading filament for SNMM
+{
+	bool correct;
+	max_feedrate[E_AXIS] =80;
+	//max_feedrate[E_AXIS] = 50;
+	START:
+	lcd_implementation_clear();
+	lcd.setCursor(0, 0); 
+	switch (extruder) {
+	case 1: lcd_display_message_fullscreen_P(MSG_FILAMENT_LOADING_T1); break;
+	case 2: lcd_display_message_fullscreen_P(MSG_FILAMENT_LOADING_T2); break;
+	case 3: lcd_display_message_fullscreen_P(MSG_FILAMENT_LOADING_T3); break;
+	default: lcd_display_message_fullscreen_P(MSG_FILAMENT_LOADING_T0); break;   
+	}
+			
+	do{
+		extr_mov(0.001,1000);
+		delay_keep_alive(2);
+	} while (!lcd_clicked());
+	//delay_keep_alive(500);
+
+	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, 500);
+	lcd_implementation_clear();
+	lcd.setCursor(0, 1); lcd_printPGM(MSG_PLEASE_WAIT);
+	st_synchronize();
+	max_feedrate[E_AXIS] = 50;
+	lcd_update_enable(true);
+	lcd_return_to_status();
+	lcdDrawUpdate = 2;
+}
+
+
+static void extr_unload() { //unloads filament
+	float tmp_motor[3] = DEFAULT_PWM_MOTOR_CURRENT;
+	float tmp_motor_loud[3] = DEFAULT_PWM_MOTOR_CURRENT_LOUD;
+	int8_t SilentMode;
+
+	if (degHotend0() > EXTRUDE_MINTEMP) {
+		lcd_implementation_clear();
+		lcd_display_message_fullscreen_P(PSTR(""));
+		max_feedrate[E_AXIS] = 50;
+		lcd.setCursor(0, 1); lcd_printPGM(MSG_PLEASE_WAIT);
+		current_position[Z_AXIS] += 15; //lifting in Z direction to make space for extrusion
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 25, active_extruder);
+
+		
+		current_position[E_AXIS] += 10; //extrusion
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 10, active_extruder);
+		digipot_current(2, E_MOTOR_HIGH_CURRENT);
+		if (current_temperature[0] < 230) { //PLA & all other filaments
+			current_position[E_AXIS] += 5.4;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2800 / 60, active_extruder);
+			current_position[E_AXIS] += 3.2;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder);
+			current_position[E_AXIS] += 3;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3400 / 60, active_extruder);
+		}
+		else { //ABS
+			current_position[E_AXIS] += 3.1;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2000 / 60, active_extruder);
+			current_position[E_AXIS] += 3.1;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2500 / 60, active_extruder);
+			current_position[E_AXIS] += 4;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder);
+			/*current_position[X_AXIS] += 23; //delay
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600 / 60, active_extruder); //delay
+			current_position[X_AXIS] -= 23; //delay
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 600 / 60, active_extruder); //delay*/
+			delay_keep_alive(4700);
+		}
+	
+		max_feedrate[E_AXIS] = 80;
+		current_position[E_AXIS] -= (BOWDEN_LENGTH + 60 + FIL_LOAD_LENGTH) / 2;   
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 500, active_extruder);
+		current_position[E_AXIS] -= (BOWDEN_LENGTH + 60 + FIL_LOAD_LENGTH) / 2;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 500, active_extruder);
+		st_synchronize();
+		//digipot_init();
+		if (SilentMode == 1) digipot_current(2, tmp_motor[2]); //set back to normal operation currents
+		else digipot_current(2, tmp_motor_loud[2]);
+		lcd_update_enable(true);
+		lcd_return_to_status();
+		max_feedrate[E_AXIS] = 50;
+	}
+	else {
+
+		lcd_implementation_clear();
+		lcd.setCursor(0, 0);
+		lcd_printPGM(MSG_ERROR);
+		lcd.setCursor(0, 2);
+		lcd_printPGM(MSG_PREHEAT_NOZZLE);
+
+		delay(2000);
+		lcd_implementation_clear();
+	}
+
+	lcd_return_to_status();
+
+
+
+
+}
+
+//wrapper functions for loading filament
+static void extr_adj_0(){
+	change_extr(0);
+	extr_adj(0);
+}
+static void extr_adj_1() {
+	change_extr(1);
+	extr_adj(1);
+}
+static void extr_adj_2() {
+	change_extr(2);
+	extr_adj(2);
+}
+static void extr_adj_3() {
+	change_extr(3);
+	extr_adj(3);
+}
+
+//wrapper functions for changing extruders
+static void extr_change_0() {
+	change_extr(0);
+	lcd_return_to_status();
+}
+static void extr_change_1() {
+	change_extr(1);
+	lcd_return_to_status();
+}
+static void extr_change_2() {
+	change_extr(2);
+	lcd_return_to_status();
+}
+static void extr_change_3() {
+	change_extr(3);
+	lcd_return_to_status();
+}
+
+//wrapper functions for unloading filament
+static void extr_unload_0() {
+	change_extr(0);
+	extr_unload();
+}
+static void extr_unload_1() {
+	change_extr(1);
+	extr_unload();
+}
+static void extr_unload_2() {
+	change_extr(2);
+	extr_unload();
+}
+static void extr_unload_3() {
+	change_extr(3);
+	extr_unload();
+}
+
+
+static void fil_load_menu()
+{
+	START_MENU();
+	MENU_ITEM(back, MSG_MAIN, lcd_main_menu);
+	MENU_ITEM(function, PSTR("Load filament 1"), extr_adj_0);
+	MENU_ITEM(function, PSTR("Load filament 2 "), extr_adj_1);
+	MENU_ITEM(function, PSTR("Load filament 3"), extr_adj_2);
+	MENU_ITEM(function, PSTR("Load filament 4"), extr_adj_3);
+	
+	END_MENU();
+}
+
+
+static void fil_unload_menu()
+{
+	START_MENU();
+	MENU_ITEM(back, MSG_MAIN, lcd_main_menu);
+	MENU_ITEM(function, PSTR("Unload filament 1"), extr_unload_0);
+	MENU_ITEM(function, PSTR("Unload filament 2"), extr_unload_1);
+	MENU_ITEM(function, PSTR("Unload filament 3"), extr_unload_2);
+	MENU_ITEM(function, PSTR("Unload filament 4"), extr_unload_3);
+
+	END_MENU();
+}
+
+static void change_extr_menu(){
+	START_MENU();
+	MENU_ITEM(back, MSG_MAIN, lcd_main_menu);
+	MENU_ITEM(function, PSTR("Extruder 1"), extr_change_0);
+	MENU_ITEM(function, PSTR("Extruder 2"), extr_change_1);
+	MENU_ITEM(function, PSTR("Extruder 3"), extr_change_2);
+	MENU_ITEM(function, PSTR("Extruder 4"), extr_change_3);
+
+	END_MENU();
+}
+
+#endif
+
+static void lcd_farm_no()
+{
+	char step = 0;
+	int enc_dif = 0;
+	int _farmno = farm_no;
+	int _ret = 0;
+	lcd_implementation_clear();
+
+	lcd.setCursor(0, 0);
+	lcd.print("Farm no");
+
+	do
+	{
+
+		if (abs((enc_dif - encoderDiff)) > 2) {
+			if (enc_dif > encoderDiff) {
+				switch (step) {
+				case(0): if (_farmno >= 100) _farmno -= 100; break;
+				case(1): if (_farmno % 100 >= 10) _farmno -= 10; break;
+				case(2): if (_farmno % 10 >= 1) _farmno--; break;
+				default: break;
+				}
+			}
+
+			if (enc_dif < encoderDiff) {
+				switch (step) {
+				case(0): if (_farmno < 900) _farmno += 100; break;
+				case(1): if (_farmno % 100 < 90) _farmno += 10; break;
+				case(2): if (_farmno % 10 <= 8)_farmno++; break;
+				default: break;
+				}
+			}
+			enc_dif = 0;
+			encoderDiff = 0;
+		}
+
+		lcd.setCursor(0, 2);
+		if (_farmno < 100) lcd.print("0");
+		if (_farmno < 10) lcd.print("0");
+		lcd.print(_farmno);
+		lcd.print("  ");
+		lcd.setCursor(0, 3);
+		lcd.print("   ");
+
+
+		lcd.setCursor(step, 3);
+		lcd.print("^");
+		delay(100);
+
+		if (lcd_clicked())
+		{
+			delay(200);
+			step++;
+			if(step == 3) {
+				_ret = 1;
+				farm_no = _farmno;
+				EEPROM_save_B(EEPROM_FARM_NUMBER, &farm_no);
+				prusa_statistics(20);
+				lcd_return_to_status();
+			}
+		}
+
+		manage_heater();
+	} while (_ret == 0);
+
+}
+
+void lcd_confirm_print()
+{
+	int enc_dif = 0;
+	int cursor_pos = 1;
+	int _ret = 0;
+	int _t = 0;
+
+
+	lcd_implementation_clear();
+
+	lcd.setCursor(0, 0);
+	lcd.print("Print ok ?");
+
+	do
+	{
+
+		if (abs((enc_dif - encoderDiff)) > 2) {
+			if (enc_dif > encoderDiff) {
+				cursor_pos--;
+			}
+
+			if (enc_dif < encoderDiff) {
+				cursor_pos++;
+			}
+		}
+
+		if (cursor_pos > 2) { cursor_pos = 2; }
+		if (cursor_pos < 1) { cursor_pos = 1; }
+
+		lcd.setCursor(0, 2); lcd.print("          ");
+		lcd.setCursor(0, 3); lcd.print("          ");
+		lcd.setCursor(2, 2);
+		lcd_printPGM(MSG_YES);
+		lcd.setCursor(2, 3);
+		lcd_printPGM(MSG_NO);
+		lcd.setCursor(0, 1 + cursor_pos);
+		lcd.print(">");
+		delay(100);
 
 		_t = _t + 1;
 		if (_t>100)
@@ -2487,8 +3164,58 @@ static void lcd_main_menu()
 
   
  MENU_ITEM(back, MSG_WATCH, lcd_status_screen);
-
-  if ( ( IS_SD_PRINTING || is_usb_printing ) && (current_position[Z_AXIS] < Z_HEIGHT_HIDE_LIVE_ADJUST_MENU) ) 
+   /* if (farm_mode && !IS_SD_PRINTING )
+    {
+    
+        int tempScrool = 0;
+        if (lcdDrawUpdate == 0 && LCD_CLICKED == 0)
+            //delay(100);
+            return; // nothing to do (so don't thrash the SD card)
+        uint16_t fileCnt = card.getnrfilenames();
+        
+        card.getWorkDirName();
+        if (card.filename[0] == '/')
+        {
+#if SDCARDDETECT == -1
+            MENU_ITEM(function, MSG_REFRESH, lcd_sd_refresh);
+#endif
+        } else {
+            MENU_ITEM(function, PSTR(LCD_STR_FOLDER ".."), lcd_sd_updir);
+        }
+        
+        for (uint16_t i = 0; i < fileCnt; i++)
+        {
+            if (_menuItemNr == _lineNr)
+            {
+#ifndef SDCARD_RATHERRECENTFIRST
+                card.getfilename(i);
+#else
+                card.getfilename(fileCnt - 1 - i);
+#endif
+                if (card.filenameIsDir)
+                {
+                    MENU_ITEM(sddirectory, MSG_CARD_MENU, card.filename, card.longFilename);
+                } else {
+                    
+                    MENU_ITEM(sdfile, MSG_CARD_MENU, card.filename, card.longFilename);
+                    
+                    
+                    
+                    
+                }
+            } else {
+                MENU_ITEM_DUMMY();
+            }
+        }
+        
+        MENU_ITEM(back, PSTR("- - - - - - - - -"), lcd_status_screen);
+    
+        
+    }*/
+    
+    
+    
+  if ( ( IS_SD_PRINTING || is_usb_printing ) && (current_position[Z_AXIS] < Z_HEIGHT_HIDE_LIVE_ADJUST_MENU) && !homing_flag) 
   {
 	MENU_ITEM(submenu, MSG_BABYSTEP_Z, lcd_babystep_z);//8
   }
@@ -2521,7 +3248,8 @@ static void lcd_main_menu()
 	{
 		if (!is_usb_printing)
 		{
-			MENU_ITEM(submenu, MSG_CARD_MENU, lcd_sdcard_menu);
+			//if (farm_mode) MENU_ITEM(submenu, MSG_FARM_CARD_MENU, lcd_farm_sdcard_menu);
+			/*else*/ MENU_ITEM(submenu, MSG_CARD_MENU, lcd_sdcard_menu);
 		}
 #if SDCARDDETECT < 1
       MENU_ITEM(gcode, MSG_CNG_SDCARD, PSTR("M21"));  // SD-card changed by user
@@ -2539,13 +3267,24 @@ static void lcd_main_menu()
 
   if (IS_SD_PRINTING || is_usb_printing)
   {
+	  if (farm_mode)
+	  {
+		  MENU_ITEM(submenu, PSTR("Farm number"), lcd_farm_no);
+	  }
   } 
   else 
   {
+	#ifndef SNMM
     MENU_ITEM(function, MSG_LOAD_FILAMENT, lcd_LoadFilament);
     MENU_ITEM(function, MSG_UNLOAD_FILAMENT, lcd_unLoadFilament);
-    MENU_ITEM(submenu, MSG_SETTINGS, lcd_settings_menu);
-    MENU_ITEM(submenu, MSG_MENU_CALIBRATION, lcd_calibration_menu);
+	#endif
+	#ifdef SNMM
+	MENU_ITEM(submenu, MSG_LOAD_FILAMENT, fil_load_menu);
+	MENU_ITEM(submenu, MSG_UNLOAD_FILAMENT, fil_unload_menu);
+	MENU_ITEM(submenu, MSG_CHANGE_EXTR, change_extr_menu);
+	#endif
+	MENU_ITEM(submenu, MSG_SETTINGS, lcd_settings_menu);
+    if(!isPrintPaused) MENU_ITEM(submenu, MSG_MENU_CALIBRATION, lcd_calibration_menu);
   }
 
   if (!is_usb_printing)
@@ -2553,11 +3292,19 @@ static void lcd_main_menu()
 	  MENU_ITEM(submenu, MSG_STATISTICS, lcd_menu_statistics);
   }
   MENU_ITEM(submenu, MSG_SUPPORT, lcd_support_menu);
-
   END_MENU();
-}
 
+}
 
+void stack_error() {
+	SET_OUTPUT(BEEPER);
+	WRITE(BEEPER, HIGH);
+	delay(1000);
+	WRITE(BEEPER, LOW);
+	lcd_display_message_fullscreen_P(MSG_STACK_ERROR);
+	//err_triggered = 1;
+	 while (1) delay_keep_alive(1000);
+}
 
 #ifdef SDSUPPORT
 static void lcd_autostart_sd()
@@ -2704,16 +3451,50 @@ void lcd_sdcard_stop()
 				card.closefile();
 
 				stoptime = millis();
-				unsigned long t = (stoptime - starttime) / 1000;
+				unsigned long t = (stoptime - starttime) / 1000; //time in s
 				save_statistics(total_filament_used, t);
 
 				lcd_return_to_status();
 				lcd_ignore_click(true);
 				lcd_commands_type = LCD_COMMAND_STOP_PRINT;
+            
+                // Turn off the print fan
+                SET_OUTPUT(FAN_PIN);
+                WRITE(FAN_PIN, 0);
+                fanSpeed=0;
 		}
 	}
 
 }
+/*
+void getFileDescription(char *name, char *description) {
+	// get file description, ie the REAL filenam, ie the second line
+	card.openFile(name, true);
+	int i = 0;
+	// skip the first line (which is the version line)
+	while (true) {
+		uint16_t readByte = card.get();
+		if (readByte == '\n') {
+			break;
+		}
+	}
+	// read the second line (which is the description line)
+	while (true) {
+		uint16_t readByte = card.get();
+		if (i == 0) {
+			// skip the first '^'
+			readByte = card.get();
+		}
+		description[i] = readByte;
+		i++;
+		if (readByte == '\n') {
+			break;
+		}
+	}
+	card.closefile();
+	description[i-1] = 0;
+}
+*/
 
 void lcd_sdcard_menu()
 {
@@ -2763,6 +3544,73 @@ void lcd_sdcard_menu()
   END_MENU();
 }
 
+//char description [10] [31];
+
+/*void get_description() {
+	uint16_t fileCnt = card.getnrfilenames();
+	for (uint16_t i = 0; i < fileCnt; i++)
+	{
+		card.getfilename(fileCnt - 1 - i);
+		getFileDescription(card.filename, description[i]);
+	}
+}*/
+
+/*void lcd_farm_sdcard_menu() 
+{
+	static int i = 0;
+	if (i == 0) {
+		get_description();
+		i++;
+	}
+		//int j;
+		//char description[31];
+		int tempScrool = 0;
+		if (lcdDrawUpdate == 0 && LCD_CLICKED == 0)
+			//delay(100);
+			return; // nothing to do (so don't thrash the SD card)
+		uint16_t fileCnt = card.getnrfilenames();
+
+		START_MENU();
+		MENU_ITEM(back, MSG_MAIN, lcd_main_menu);
+		card.getWorkDirName();
+		if (card.filename[0] == '/')
+		{
+#if SDCARDDETECT == -1
+			MENU_ITEM(function, MSG_REFRESH, lcd_sd_refresh);
+#endif
+		}
+		else {
+			MENU_ITEM(function, PSTR(LCD_STR_FOLDER ".."), lcd_sd_updir);
+		}
+
+
+
+		for (uint16_t i = 0; i < fileCnt; i++)
+		{
+			if (_menuItemNr == _lineNr)
+			{
+#ifndef SDCARD_RATHERRECENTFIRST
+				card.getfilename(i);
+#else
+				card.getfilename(fileCnt - 1 - i);
+#endif
+				if (card.filenameIsDir)
+				{
+					MENU_ITEM(sddirectory, MSG_CARD_MENU, card.filename, card.longFilename);
+				}
+				else {
+					
+					MENU_ITEM(sdfile, MSG_CARD_MENU, card.filename, description[i]);
+				}
+			}
+			else {
+				MENU_ITEM_DUMMY();
+			}
+		}
+		END_MENU();
+
+}*/
+
 #define menu_edit_type(_type, _name, _strFunc, scale) \
   void menu_edit_ ## _name () \
   { \
@@ -2819,17 +3667,29 @@ menu_edit_type(float, float51, ftostr51, 10)
 menu_edit_type(float, float52, ftostr52, 100)
 menu_edit_type(unsigned long, long5, ftostr5, 0.01)
 
-
 static void lcd_selftest()
 {
 	int _progress = 0;
 	bool _result = false;
 
-	_progress = lcd_selftest_screen(-1, _progress, 4, true, 2000);
+	lcd_implementation_clear();
+	lcd.setCursor(0, 0); lcd_printPGM(MSG_SELFTEST_START);
+	delay(2000);
+
+
+	_result = lcd_selftest_fan_dialog(1);
 
-	_progress = lcd_selftest_screen(0, _progress, 3, true, 2000);
-	_result = lcd_selfcheck_endstops();
+	if (_result)
+	{
+		_result = lcd_selftest_fan_dialog(2);
+	}
 
+	if (_result)
+	{
+		_progress = lcd_selftest_screen(0, _progress, 3, true, 2000);
+		_result = lcd_selfcheck_endstops();
+	}
+		
 	if (_result)
 	{
 		_progress = lcd_selftest_screen(1, _progress, 3, true, 1000);
@@ -2838,22 +3698,39 @@ static void lcd_selftest()
 
 	if (_result)
 	{
+		current_position[Z_AXIS] += 15;									//move Z axis higher to avoid false triggering of Z end stop in case that we are very low - just above heatbed
 		_progress = lcd_selftest_screen(2, _progress, 3, true, 2000);
-		_result = lcd_selfcheck_axis(0, X_MAX_POS);
+		_result = lcd_selfcheck_axis(X_AXIS, X_MAX_POS);
+		
+	}
+
+	if (_result)
+	{
+		_progress = lcd_selftest_screen(2, _progress, 3, true, 0);
+		_result = lcd_selfcheck_pulleys(X_AXIS);
 	}
 
+
 	if (_result)
 	{
 		_progress = lcd_selftest_screen(3, _progress, 3, true, 1500);
-		_result = lcd_selfcheck_axis(1, Y_MAX_POS);
+		_result = lcd_selfcheck_axis(Y_AXIS, Y_MAX_POS);
 	}
 
+	if (_result)
+	{
+		_progress = lcd_selftest_screen(3, _progress, 3, true, 0);
+		_result = lcd_selfcheck_pulleys(Y_AXIS);
+	}
+
+
 	if (_result)
 	{
 		current_position[X_AXIS] = current_position[X_AXIS] - 3;
 		current_position[Y_AXIS] = current_position[Y_AXIS] - 14;
 		_progress = lcd_selftest_screen(4, _progress, 3, true, 1500);
 		_result = lcd_selfcheck_axis(2, Z_MAX_POS);
+		enquecommand_P(PSTR("G28 W"));
 	}
 
 	if (_result)
@@ -2869,44 +3746,21 @@ static void lcd_selftest()
 	{
 		_progress = lcd_selftest_screen(7, _progress, 3, true, 5000);
 	}
-
+	lcd_reset_alert_level();
+	enquecommand_P(PSTR("M84"));
 	lcd_implementation_clear();
 	lcd_next_update_millis = millis() + LCD_UPDATE_INTERVAL;
 
 	if (_result)
 	{
-		LCD_ALERTMESSAGERPGM(MSG_SELFTEST_OK);
+		LCD_ALERTMESSAGERPGM(MSG_SELFTEST_OK);				
 	}
 	else
 	{
 		LCD_ALERTMESSAGERPGM(MSG_SELFTEST_FAILED);
 	}
 }
-static bool lcd_selfcheck_endstops()
-{
-	bool _result = true;
-
-	if (READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING == 1 || READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING == 1 || READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING == 1)
-	{
-		current_position[0] = (READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING == 1) ? current_position[0] = current_position[0] + 10 : current_position[0];
-		current_position[1] = (READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING == 1) ? current_position[1] = current_position[1] + 10 : current_position[1];
-		current_position[2] = (READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING == 1) ? current_position[2] = current_position[2] + 10 : current_position[2];
-	}
-	plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], manual_feedrate[0] / 60, active_extruder);
-	delay(500);
 
-	if (READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING == 1 || READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING == 1 || READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING == 1)
-	{
-		_result = false;
-		String  _error = String((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING == 1) ? "X" : "") +
-			String((READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING == 1) ? "Y" : "") +
-			String((READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING == 1) ? "Z" : "");
-		lcd_selftest_error(3, _error.c_str(), "");
-	}
-	manage_heater();
-	manage_inactivity();
-	return _result;
-}
 static bool lcd_selfcheck_axis(int _axis, int _travel)
 {
 	bool _stepdone = false;
@@ -2918,15 +3772,7 @@ static bool lcd_selfcheck_axis(int _axis, int _travel)
 	_travel = _travel + (_travel / 10);
 
 	do {
-
-		if (_axis == 2)
-		{
-			current_position[_axis] = current_position[_axis] - 1;
-		}
-		else
-		{
-			current_position[_axis] = current_position[_axis] - 3;
-		}
+		current_position[_axis] = current_position[_axis] - 1;
 
 		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder);
 		st_synchronize();
@@ -2937,19 +3783,21 @@ static bool lcd_selfcheck_axis(int _axis, int _travel)
 			{
 				_stepresult = (READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING == 1) ? true : false;
 				_err_endstop = (READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING == 1) ? 1 : 2;
-				disable_x();
+				
 			}
 			if (_axis == 1)
 			{
 				_stepresult = (READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING == 1) ? true : false;
 				_err_endstop = (READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING == 1) ? 0 : 2;
-				disable_y();
+				
 			}
 			if (_axis == 2)
 			{
 				_stepresult = (READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING == 1) ? true : false;
 				_err_endstop = (READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING == 1) ? 0 : 1;
-				disable_z();
+				/*disable_x();
+				disable_y();
+				disable_z();*/
 			}
 			_stepdone = true;
 		}
@@ -2965,16 +3813,16 @@ static bool lcd_selfcheck_axis(int _axis, int _travel)
 		}
 
 		manage_heater();
-		manage_inactivity();
+		manage_inactivity(true);
 
-		delay(100);
+		//delay(100);
 		(_travel_done <= _travel) ? _travel_done++ : _stepdone = true;
 
 	} while (!_stepdone);
 
 
-	current_position[_axis] = current_position[_axis] + 15;
-	plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder);
+	//current_position[_axis] = current_position[_axis] + 15;
+	//plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder);
 
 	if (!_stepresult)
 	{
@@ -3001,6 +3849,98 @@ static bool lcd_selfcheck_axis(int _axis, int _travel)
 
 	return _stepresult;
 }
+
+static bool lcd_selfcheck_pulleys(int axis)
+{
+	float tmp_motor_loud[3] = DEFAULT_PWM_MOTOR_CURRENT_LOUD;
+	float tmp_motor[3] = DEFAULT_PWM_MOTOR_CURRENT;
+	float current_position_init;
+	float move;
+	bool endstop_triggered = false;
+	bool result = true;
+	int i;
+	unsigned long timeout_counter;
+	refresh_cmd_timeout();
+	manage_inactivity(true);
+
+	if (axis == 0) move = 50; //X_AXIS 
+		else move = 50; //Y_AXIS
+
+		current_position_init = current_position[axis];
+				
+		current_position[axis] += 2;
+		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder);
+		for (i = 0; i < 5; i++) {
+			refresh_cmd_timeout();
+			current_position[axis] = current_position[axis] + move;
+			digipot_current(0, 850); //set motor current higher
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], 200, active_extruder);
+			st_synchronize();
+			if (SilentModeMenu == 1) digipot_current(0, tmp_motor[0]); //set back to normal operation currents
+			else digipot_current(0, tmp_motor_loud[0]); //set motor current back			
+			current_position[axis] = current_position[axis] - move;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], 50, active_extruder);
+			st_synchronize();
+			if ((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING == 1) || (READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING == 1)) {
+				lcd_selftest_error(8, (axis == 0) ? "X" : "Y", "");
+				return(false);
+			}
+		}
+		timeout_counter = millis() + 2500;
+		endstop_triggered = false;
+		manage_inactivity(true);
+		while (!endstop_triggered) {
+			if ((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING == 1) || (READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING == 1)) {
+				endstop_triggered = true;
+				if (current_position_init - 1 <= current_position[axis] && current_position_init + 1 >= current_position[axis]) {
+					current_position[axis] += 15;
+					plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder);
+					st_synchronize();
+					return(true);
+				}
+				else {
+					lcd_selftest_error(8, (axis == 0) ? "X" : "Y", "");
+					return(false);
+				}
+			}
+			else {
+				current_position[axis] -= 1;
+				plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder);
+				st_synchronize();
+				if (millis() > timeout_counter) {
+					lcd_selftest_error(8, (axis == 0) ? "X" : "Y", "");
+					return(false);
+				}
+			}
+		}		
+}
+
+static bool lcd_selfcheck_endstops()
+{
+	bool _result = true;
+
+	if (READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING == 1 || READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING == 1 || READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING == 1)
+	{
+		current_position[0] = (READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING == 1) ? current_position[0] = current_position[0] + 10 : current_position[0];
+		current_position[1] = (READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING == 1) ? current_position[1] = current_position[1] + 10 : current_position[1];
+		current_position[2] = (READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING == 1) ? current_position[2] = current_position[2] + 10 : current_position[2];
+	}
+	plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], manual_feedrate[0] / 60, active_extruder);
+	delay(500);
+
+	if (READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING == 1 || READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING == 1 || READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING == 1)
+	{
+		_result = false;
+		String  _error = String((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING == 1) ? "X" : "") +
+			String((READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING == 1) ? "Y" : "") +
+			String((READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING == 1) ? "Z" : "");
+		lcd_selftest_error(3, _error.c_str(), "");
+	}
+	manage_heater();
+	manage_inactivity(true);
+	return _result;
+}
+
 static bool lcd_selfcheck_check_heater(bool _isbed)
 {
 	int _counter = 0;
@@ -3015,14 +3955,14 @@ static bool lcd_selfcheck_check_heater(bool _isbed)
 	target_temperature[0] = (_isbed) ? 0 : 100;
 	target_temperature_bed = (_isbed) ? 100 : 0;
 	manage_heater();
-	manage_inactivity();
+	manage_inactivity(true);
 
 	do {
 		_counter++;
 		(_counter < _cycles) ? _docycle = true : _docycle = false;
 
 		manage_heater();
-		manage_inactivity();
+		manage_inactivity(true);
 		_progress = (_isbed) ? lcd_selftest_screen(5, _progress, 2, false, 400) : lcd_selftest_screen(1, _progress, 2, false, 400);
 
 	} while (_docycle);
@@ -3051,7 +3991,7 @@ static bool lcd_selfcheck_check_heater(bool _isbed)
 	}
 
 	manage_heater();
-	manage_inactivity();
+	manage_inactivity(true);
 	return _stepresult;
 
 }
@@ -3111,7 +4051,30 @@ static void lcd_selftest_error(int _error_no, const char *_error_1, const char *
 		lcd.setCursor(18, 3);
 		lcd.print(_error_1);
 		break;
-
+	case 6:
+		lcd.setCursor(0, 2);
+		lcd_printPGM(MSG_SELFTEST_COOLING_FAN);
+		lcd.setCursor(0, 3);
+		lcd_printPGM(MSG_SELFTEST_WIRINGERROR);
+		lcd.setCursor(18, 3);
+		lcd.print(_error_1);
+		break;
+	case 7:
+		lcd.setCursor(0, 2);
+		lcd_printPGM(MSG_SELFTEST_EXTRUDER_FAN);
+		lcd.setCursor(0, 3);
+		lcd_printPGM(MSG_SELFTEST_WIRINGERROR);
+		lcd.setCursor(18, 3);
+		lcd.print(_error_1);
+		break;
+	case 8:
+		lcd.setCursor(0, 2);
+		lcd_printPGM(MSG_LOOSE_PULLEY);
+		lcd.setCursor(0, 3);
+		lcd_printPGM(MSG_SELFTEST_MOTOR);
+		lcd.setCursor(18, 3);
+		lcd.print(_error_1);
+		break;
 	}
 
 	delay(1000);
@@ -3127,8 +4090,114 @@ static void lcd_selftest_error(int _error_no, const char *_error_1, const char *
 	lcd_return_to_status();
 
 }
+
+static bool lcd_selftest_fan_dialog(int _fan)
+{
+	bool _result = false;
+	int _errno = 0;
+	lcd_implementation_clear();
+
+	lcd.setCursor(0, 0); lcd_printPGM(MSG_SELFTEST_FAN);
+	switch (_fan)
+	{
+	case 1:
+		// extruder cooling fan
+		lcd.setCursor(0, 1); lcd_printPGM(MSG_SELFTEST_EXTRUDER_FAN);
+		SET_OUTPUT(EXTRUDER_0_AUTO_FAN_PIN);
+		WRITE(EXTRUDER_0_AUTO_FAN_PIN, 1);
+		_errno = 7;
+		break;
+	case 2:
+		// object cooling fan
+		lcd.setCursor(0, 1); lcd_printPGM(MSG_SELFTEST_COOLING_FAN);
+		SET_OUTPUT(FAN_PIN);
+		analogWrite(FAN_PIN, 255);
+		_errno = 6;
+		break;
+	}
+	delay(500);
+
+	lcd.setCursor(1, 2); lcd_printPGM(MSG_SELFTEST_FAN_YES);
+	lcd.setCursor(0, 3); lcd.print(">");
+	lcd.setCursor(1, 3); lcd_printPGM(MSG_SELFTEST_FAN_NO);
+
+
+
+
+
+	int8_t enc_dif = 0;
+	bool _response = false;
+	do
+	{
+
+		switch (_fan)
+		{
+		case 1:
+			// extruder cooling fan
+			SET_OUTPUT(EXTRUDER_0_AUTO_FAN_PIN);
+			WRITE(EXTRUDER_0_AUTO_FAN_PIN, 1);
+			break;
+		case 2:
+			// object cooling fan
+			SET_OUTPUT(FAN_PIN);
+			analogWrite(FAN_PIN, 255);
+			break;
+		}
+
+
+		if (abs((enc_dif - encoderDiff)) > 2) {
+			if (enc_dif > encoderDiff) {
+				_result = true;
+				lcd.setCursor(0, 2); lcd.print(">");
+				lcd.setCursor(1, 2); lcd_printPGM(MSG_SELFTEST_FAN_YES);
+				lcd.setCursor(0, 3); lcd.print(" ");
+				lcd.setCursor(1, 3); lcd_printPGM(MSG_SELFTEST_FAN_NO);
+			}
+
+			if (enc_dif < encoderDiff) {
+				_result = false;
+				lcd.setCursor(0, 2); lcd.print(" ");
+				lcd.setCursor(1, 2); lcd_printPGM(MSG_SELFTEST_FAN_YES);
+				lcd.setCursor(0, 3); lcd.print(">");
+				lcd.setCursor(1, 3); lcd_printPGM(MSG_SELFTEST_FAN_NO);
+			}
+			enc_dif = 0;
+			encoderDiff = 0;
+		}
+
+
+		manage_heater();
+		delay(100);
+
+		if (lcd_clicked())
+		{
+			_response = true;
+		}
+
+
+	} while (!_response);
+
+	SET_OUTPUT(EXTRUDER_0_AUTO_FAN_PIN);
+	WRITE(EXTRUDER_0_AUTO_FAN_PIN, 0);
+	SET_OUTPUT(FAN_PIN);
+	analogWrite(FAN_PIN, 0);
+
+	fanSpeed = 0;
+	manage_heater();
+
+	if (!_result)
+	{
+		const char *_err;
+		lcd_selftest_error(_errno, _err, _err);
+	}
+
+	return _result;
+
+}
+
 static int lcd_selftest_screen(int _step, int _progress, int _progress_scale, bool _clear, int _delay)
 {
+	
 	lcd_next_update_millis = millis() + (LCD_UPDATE_INTERVAL * 10000);
 
 	int _step_block = 0;
@@ -3152,21 +4221,23 @@ static int lcd_selftest_screen(int _step, int _progress, int _progress_scale, bo
 	lcd.setCursor(0, 1);
 	lcd.print("--------------------");
 
-	_step_block = 1;
-	lcd_selftest_screen_step(3, 9, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Hotend", _indicator);
-
-	_step_block = 2;
-	lcd_selftest_screen_step(2, 2, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "X", _indicator);
+	if (_step != 7)
+	{
+		_step_block = 1;
+		lcd_selftest_screen_step(3, 9, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Hotend", _indicator);
 
-	_step_block = 3;
-	lcd_selftest_screen_step(2, 8, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Y", _indicator);
+		_step_block = 2;
+		lcd_selftest_screen_step(2, 2, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "X", _indicator);
 
-	_step_block = 4;
-	lcd_selftest_screen_step(2, 14, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Z", _indicator);
+		_step_block = 3;
+		lcd_selftest_screen_step(2, 8, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Y", _indicator);
 
-	_step_block = 5;
-	lcd_selftest_screen_step(3, 0, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Bed", _indicator);
+		_step_block = 4;
+		lcd_selftest_screen_step(2, 14, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Z", _indicator);
 
+		_step_block = 5;
+		lcd_selftest_screen_step(3, 0, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Bed", _indicator);
+	}
 
 	if (_delay > 0) delay(_delay);
 	_progress++;
@@ -3204,7 +4275,7 @@ static void lcd_selftest_screen_step(int _row, int _col, int _state, const char
 static void lcd_quick_feedback()
 {
   lcdDrawUpdate = 2;
-  blocking_enc = millis() + 500;
+  button_pressed = false;
   lcd_implementation_quick_feedback();
 }
 
@@ -3226,6 +4297,7 @@ static void menu_action_function(menuFunc_t data) {
 }
 static void menu_action_sdfile(const char* filename, char* longFilename)
 {
+  loading_flag = false;
   char cmd[30];
   char* c;
   sprintf_P(cmd, PSTR("M23 %s"), filename);
@@ -3254,6 +4326,7 @@ static void menu_action_setting_edit_callback_bool(const char* pstr, bool* ptr,
 #endif//ULTIPANEL
 
 /** LCD API **/
+
 void lcd_init()
 {
   lcd_implementation_init();
@@ -3313,7 +4386,7 @@ void lcd_init()
 //#include <avr/pgmspace.h>
 
 static volatile bool lcd_update_enabled = true;
-static unsigned long lcd_timeoutToStatus = 0;
+unsigned long lcd_timeoutToStatus = 0;
 
 void lcd_update_enable(bool enabled)
 {
@@ -3347,16 +4420,17 @@ void lcd_update_enable(bool enabled)
 
 void lcd_update(uint8_t lcdDrawUpdateOverride)
 {
-  if (lcdDrawUpdate < lcdDrawUpdateOverride)
-    lcdDrawUpdate = lcdDrawUpdateOverride;
 
-  if (! lcd_update_enabled)
-      return;
+	if (lcdDrawUpdate < lcdDrawUpdateOverride)
+		lcdDrawUpdate = lcdDrawUpdateOverride;
+
+	if (!lcd_update_enabled)
+		return;
 
 #ifdef LCD_HAS_SLOW_BUTTONS
   slow_buttons = lcd_implementation_read_slow_buttons(); // buttons which take too long to read in interrupt context
 #endif
-
+  
   lcd_buttons_update();
 
 #if (SDCARDDETECT > 0)
@@ -3374,6 +4448,7 @@ void lcd_update(uint8_t lcdDrawUpdateOverride)
 	  {
 		  card.initsd();
 		  LCD_MESSAGERPGM(MSG_SD_INSERTED);
+		  //get_description();
 	  }
 	  else
 	  {
@@ -3417,8 +4492,8 @@ void lcd_update(uint8_t lcdDrawUpdateOverride)
 		  encoderDiff = 0;
 		  lcd_timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS;
 	  }
-	  if (LCD_CLICKED)
-		  lcd_timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS;
+
+	  /*if (LCD_CLICKED)*/ lcd_timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS;
 #endif//ULTIPANEL
 
 #ifdef DOGLCD        // Changes due to different driver architecture of the DOGM display
@@ -3461,9 +4536,28 @@ void lcd_update(uint8_t lcdDrawUpdateOverride)
 	  if (lcdDrawUpdate) lcdDrawUpdate--;
 	  lcd_next_update_millis = millis() + LCD_UPDATE_INTERVAL;
 	  }
-   
+	if (!SdFatUtil::test_stack_integrity()) stack_error();
+	lcd_ping(); //check that we have received ping command if we are in farm mode
+}
+
+void lcd_printer_connected() {
+	printer_connected = true;
 }
 
+void lcd_ping() { //chceck if printer is connected to monitoring when in farm mode
+	if (farm_mode) {
+		bool empty = is_buffer_empty();
+		if ((millis() - PingTime) * 0.001 > (empty ? PING_TIME : PING_TIME_LONG)) { //if commands buffer is empty use shorter time period
+																							  //if there are comamnds in buffer, some long gcodes can delay execution of ping command
+																							  //therefore longer period is used
+			printer_connected = false;
+			//lcd_ping_allert(); //acustic signals
+		}
+		else {
+			lcd_printer_connected();
+		}
+	}
+}
 void lcd_ignore_click(bool b)
 {
   ignore_click = b;
@@ -3534,9 +4628,50 @@ void lcd_buttons_update()
   if (READ(BTN_EN1) == 0)  newbutton |= EN_A;
   if (READ(BTN_EN2) == 0)  newbutton |= EN_B;
 #if BTN_ENC > 0
-  if ((blocking_enc < millis()) && (READ(BTN_ENC) == 0))
-    newbutton |= EN_C;
-#endif
+  if (lcd_update_enabled == true) { //if we are in non-modal mode, long press can be used and short press triggers with button release
+	  if (READ(BTN_ENC) == 0) { //button is pressed	  
+
+		  if (button_pressed == false && long_press_active == false) {
+			  if (currentMenu != lcd_move_z) {
+				  savedMenu = currentMenu;
+				  savedEncoderPosition = encoderPosition;
+			  }
+			  long_press_timer = millis();
+			  button_pressed = true;
+		  }
+		  else {
+			  if (millis() - long_press_timer > LONG_PRESS_TIME) { //long press activated
+				   
+				  long_press_active = true;
+				  move_menu_scale = 1.0;
+				  lcd_goto_menu(lcd_move_z);
+			  }
+		  }
+	  }
+	  else { //button not pressed
+		  if (button_pressed) { //button was released
+			  if (long_press_active == false) { //button released before long press gets activated
+				  if (currentMenu == lcd_move_z) {
+					  //return to previously active menu and previous encoder position
+					  lcd_goto_menu(savedMenu, savedEncoderPosition);
+				  }
+				  else {
+					  newbutton |= EN_C;
+				  }
+			  }
+			  //button_pressed is set back to false via lcd_quick_feedback function
+		  }
+		  else {			  
+			  long_press_active = false;
+		  }
+	  }
+  }
+  else { //we are in modal mode
+	  if (READ(BTN_ENC) == 0)
+		  newbutton |= EN_C; 
+  }
+  
+#endif  
   buttons = newbutton;
 #ifdef LCD_HAS_SLOW_BUTTONS
   buttons |= slow_buttons;

+ 44 - 4
Firmware/ultralcd.h

@@ -31,14 +31,17 @@
 void lcd_mylang();
   bool lcd_detected(void);
 
+  
   static void lcd_selftest();
   static bool lcd_selfcheck_endstops();
   static bool lcd_selfcheck_axis(int _axis, int _travel);
   static bool lcd_selfcheck_check_heater(bool _isbed);
   static int  lcd_selftest_screen(int _step, int _progress, int _progress_scale, bool _clear, int _delay);
   static void lcd_selftest_screen_step(int _row, int _col, int _state, const char *_name, const char *_indicator);
+  static bool lcd_selftest_fan_dialog(int _fan);
   static void lcd_selftest_error(int _error_no, const char *_error_1, const char *_error_2);
-  static void lcd_menu_statistics();
+  void lcd_menu_statistics();
+  static bool lcd_selfcheck_pulleys(int axis);
 
   extern const char* lcd_display_message_fullscreen_P(const char *msg, uint8_t &nlines);
   inline const char* lcd_display_message_fullscreen_P(const char *msg) 
@@ -47,7 +50,7 @@ void lcd_mylang();
   extern void lcd_wait_for_click();
   extern void lcd_show_fullscreen_message_and_wait_P(const char *msg);
   // 0: no, 1: yes, -1: timeouted
-  extern int8_t lcd_show_fullscreen_message_yes_no_and_wait_P(const char *msg, bool allow_timeouting = true);
+  extern int8_t lcd_show_fullscreen_message_yes_no_and_wait_P(const char *msg, bool allow_timeouting = true, bool default_yes = false);
 
   // Ask the user to move the Z axis up to the end stoppers and let
   // the user confirm that it has been done.
@@ -89,9 +92,10 @@ void lcd_mylang();
   #define LCD_COMMAND_STOP_PRINT 2
   #define LCD_COMMAND_FARM_MODE_CONFIRM 4
 
+  extern unsigned long lcd_timeoutToStatus;
   extern int lcd_commands_type;
   
-  extern bool farm_mode;
+  extern uint8_t farm_mode;
   extern int farm_no;
   extern int farm_timer;
   extern int farm_status;
@@ -194,4 +198,40 @@ extern void lcd_implementation_print_at(uint8_t x, uint8_t y, int i);
 extern void lcd_implementation_print(float f);
 extern void lcd_implementation_print_at(uint8_t x, uint8_t y, const char *str);
 
-#endif //ULTRALCD_H
+
+void change_extr(int extr);
+static int get_ext_nr();
+static void extr_adj(int extruder);
+static void extr_adj_0();
+static void extr_adj_1();
+static void extr_adj_2();
+static void extr_adj_3();
+static void fil_load_menu();
+static void fil_unload_menu();
+static void extr_unload_0();
+static void extr_unload_1();
+static void extr_unload_2();
+static void extr_unload_3();
+static void lcd_disable_farm_mode();
+
+void stack_error();
+static void lcd_ping_allert();
+void lcd_printer_connected();
+void lcd_ping();
+
+void lcd_calibrate_extruder();
+void lcd_farm_sdcard_menu();
+
+//void getFileDescription(char *name, char *description);
+
+void lcd_farm_sdcard_menu_w();
+//void get_description();
+
+void lcd_wait_for_cool_down();
+void adjust_bed_reset();
+void lcd_extr_cal_reset();
+
+union MenuData;
+
+char reset_menu();
+#endif //ULTRALCD_H

+ 24 - 3
Firmware/ultralcd_implementation_hitachi_HD44780.h

@@ -757,17 +757,38 @@ static void lcd_implementation_status_screen()
 		}
 	}
     
-    // Farm number display
+	// Farm number display
 	if (farm_mode)
 	{
 		lcd_printPGM(PSTR(" F"));
 		lcd.print(farm_no);
 		lcd_printPGM(PSTR("  "));
+        
+        // Beat display
+        lcd.setCursor(LCD_WIDTH - 1, 0);
+        if ( (millis() - kicktime) < 60000 ) {
+        
+            lcd_printPGM(PSTR("L"));
+        
+        }else{
+            lcd_printPGM(PSTR(" "));
+        }
+        
+	}
+	else {
+		lcd.setCursor(LCD_WIDTH - 8 - 2, 2);
+		lcd_printPGM(PSTR(" "));
 	}
 
+#ifdef SNMM
+		lcd_printPGM(PSTR(" E"));
+		lcd.print(get_ext_nr()+1);
+	
+#endif
+
     //Print time elapsed
-    lcd.setCursor(LCD_WIDTH - 8 -2, 2);
-    lcd_printPGM(PSTR("  "));
+    lcd.setCursor(LCD_WIDTH - 8 -1, 2);
+    lcd_printPGM(PSTR(" "));
     lcd.print(LCD_STR_CLOCK[0]);
     if(starttime != 0)
     {

+ 30 - 13
Firmware/variants/1_75mm_MK2-RAMBo10a-E3Dv6full.h

@@ -37,7 +37,7 @@ const bool Z_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic o
 #define MANUAL_Z_HOME_POS 0.15
 
 // Travel limits after homing
-#define X_MAX_POS 255
+#define X_MAX_POS 250
 #define X_MIN_POS 0
 #define Y_MAX_POS 210
 #define Y_MIN_POS -2.2
@@ -93,20 +93,18 @@ EXTRUDER SETTINGS
 #define EXTRUDER_AUTO_FAN_TEMPERATURE 50
 #define EXTRUDER_AUTO_FAN_SPEED   255  // == full speed
 
+// Prusa Single extruder multiple material suport
+//#define SNMM
 
+#ifdef SNMM
+//#define BOWDEN_LENGTH	408
+#define BOWDEN_LENGTH 457 //total length for filament fast loading part; max length for extrusion is 465 mm!
+#define FIL_LOAD_LENGTH 102 //length for loading filament into the nozzle
+#define FIL_RETURN_LENGTH 30.5 //for filament adjusting (PRUSAY code)
+#define E_MOTOR_LOW_CURRENT 350 // current for PRUSAY code
+#define E_MOTOR_HIGH_CURRENT 700 //current for unloading filament, stop print, PRUSAY ramming
 
-/*------------------------------------
-LOAD/UNLOAD FILAMENT SETTINGS
-*------------------------------------*/
-
-// Load filament commands
-#define LOAD_FILAMENT_0 "M83"
-#define LOAD_FILAMENT_1 "G1 E70 F400"
-#define LOAD_FILAMENT_2 "G1 E40 F100"
-
-// Unload filament commands
-#define UNLOAD_FILAMENT_0 "M83"
-#define UNLOAD_FILAMENT_1 "G1 E-80 F7000"
+#endif
 
 /*------------------------------------
 CHANGE FILAMENT SETTINGS
@@ -312,5 +310,24 @@ THERMISTORS SETTINGS
 #define TEMP_SENSOR_2 0
 #define TEMP_SENSOR_BED 1
 
+#define STACK_GUARD_TEST_VALUE 0xA2A2
+
+#define MAX_BED_TEMP_CALIBRATION 50
+#define MAX_HOTEND_TEMP_CALIBRATION 50
+
+#define MAX_E_STEPS_PER_UNIT 250
+#define MIN_E_STEPS_PER_UNIT 100
+
+#define PRINT_STARTED 0xFE
+#define PRINT_FINISHED 0xFF
+
+#define Z_BABYSTEP_MIN -3999
+#define Z_BABYSTEP_MAX 0
+
+#define PING_TIME 60 //time in s
+#define PING_TIME_LONG 600 //10 min; used when length of commands buffer > 0 to avoid false triggering when dealing with long gcodes
+#define PING_ALLERT_PERIOD 60 //time in s
+
+#define LONG_PRESS_TIME 1000 //time in ms for button long press
 
 #endif //__CONFIGURATION_PRUSA_H

+ 30 - 13
Firmware/variants/1_75mm_MK2-RAMBo13a-E3Dv6full.h

@@ -37,7 +37,7 @@ const bool Z_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic o
 #define MANUAL_Z_HOME_POS 0.15
 
 // Travel limits after homing
-#define X_MAX_POS 255
+#define X_MAX_POS 250
 #define X_MIN_POS 0
 #define Y_MAX_POS 210
 #define Y_MIN_POS -2.2
@@ -93,20 +93,18 @@ EXTRUDER SETTINGS
 #define EXTRUDER_AUTO_FAN_TEMPERATURE 50
 #define EXTRUDER_AUTO_FAN_SPEED   255  // == full speed
 
+// Prusa Single extruder multiple material suport
+//#define SNMM
 
+#ifdef SNMM
+//#define BOWDEN_LENGTH	408
+#define BOWDEN_LENGTH 457 //total length for filament fast loading part; max length for extrusion is 465 mm!
+#define FIL_LOAD_LENGTH 102 //length for loading filament into the nozzle
+#define FIL_RETURN_LENGTH 30.5 //for filament adjusting (PRUSAY code)
+#define E_MOTOR_LOW_CURRENT 350 // current for PRUSAY code
+#define E_MOTOR_HIGH_CURRENT 700 //current for unloading filament, stop print, PRUSAY ramming
 
-/*------------------------------------
-LOAD/UNLOAD FILAMENT SETTINGS
-*------------------------------------*/
-
-// Load filament commands
-#define LOAD_FILAMENT_0 "M83"
-#define LOAD_FILAMENT_1 "G1 E70 F400"
-#define LOAD_FILAMENT_2 "G1 E40 F100"
-
-// Unload filament commands
-#define UNLOAD_FILAMENT_0 "M83"
-#define UNLOAD_FILAMENT_1 "G1 E-80 F7000"
+#endif
 
 /*------------------------------------
 CHANGE FILAMENT SETTINGS
@@ -312,5 +310,24 @@ THERMISTORS SETTINGS
 #define TEMP_SENSOR_2 0
 #define TEMP_SENSOR_BED 1
 
+#define STACK_GUARD_TEST_VALUE 0xA2A2
+
+#define MAX_BED_TEMP_CALIBRATION 50
+#define MAX_HOTEND_TEMP_CALIBRATION 50
+
+#define MAX_E_STEPS_PER_UNIT 250
+#define MIN_E_STEPS_PER_UNIT 100
+
+#define PRINT_STARTED 0xFE
+#define PRINT_FINISHED 0xFF
+
+#define Z_BABYSTEP_MIN -3999
+#define Z_BABYSTEP_MAX 0
+
+#define PING_TIME 60 //time in s
+#define PING_TIME_LONG 600 //10 min; used when length of commands buffer > 0 to avoid false triggering when dealing with long gcodes
+#define PING_ALLERT_PERIOD 60 //time in s
+
+#define LONG_PRESS_TIME 1000 //time in ms for button long press
 
 #endif //__CONFIGURATION_PRUSA_H