Browse Source

initial version - merging from DEV multicolor

PavelSindler 8 years ago
parent
commit
fcce374a14

+ 5 - 2
Firmware/Configuration.h

@@ -5,7 +5,7 @@
 #include "Configuration_prusa.h"
 
 // Firmware version
-#define FW_version "3.0.10-alpha"
+#define FW_version "3.0.10-alpha-2"
 
 #define FW_PRUSA3D_MAGIC "PRUSA3DFW"
 #define FW_PRUSA3D_MAGIC_LEN 10
@@ -43,15 +43,18 @@
 #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_STEPS_PER_UNIT_E (EEPROM_TOSHIBA_FLASH_AIR_COMPATIBLITY-4)
 
 // 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

+ 14 - 10
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 "V0"
 
 #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
@@ -267,22 +269,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);

+ 1 - 0
Firmware/ConfigurationStore.h

@@ -1,5 +1,6 @@
 #ifndef CONFIG_STORE_H
 #define CONFIG_STORE_H
+#define EEPROM_SETTINGS
 
 #include "Configuration.h"
 

+ 2 - 0
Firmware/Marlin.h

@@ -111,6 +111,7 @@ FORCE_INLINE void serialprintPGM(const char *str)
 
 void get_command();
 void process_commands();
+void ramming();
 
 void manage_inactivity(bool ignore_stepper_queue=false);
 
@@ -282,6 +283,7 @@ 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 unsigned int usb_printing_counter;
 
 extern unsigned long kicktime;

+ 270 - 63
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
@@ -254,6 +255,7 @@ int extruder_multiply[EXTRUDERS] = {100
 };
 
 bool is_usb_printing = false;
+bool homing_flag = false;
 
 unsigned long kicktime = millis()+100000;
 
@@ -881,58 +883,35 @@ static void lcd_language_menu();
 // 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: erase everything, whole EEPROM will be set to 0xFF
+                   
+        // Level 0: Language reset
         case 0:
-            
-            lcd_print_at_PGM(1,2,PSTR("ERASING all data"));
-            
-            WRITE(BEEPER, HIGH);
-            _delay_ms(100);
-            WRITE(BEEPER, LOW);
-            _delay_ms(100);
-            WRITE(BEEPER, HIGH);
-            _delay_ms(100);
-            WRITE(BEEPER, LOW);
-            _delay_ms(200);
-            
-            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;
-            
-            
-        // Level 1: Language reset
-        case 1:
             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_print_at_PGM(1,2,PSTR("Shipping prep"));
+			//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();
@@ -945,8 +924,38 @@ void factory_reset(char level, bool quiet)
             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;
@@ -1013,7 +1022,7 @@ void setup()
   
   // 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();
@@ -1031,7 +1040,10 @@ void setup()
 	  if (!READ(BTN_ENC))
 	  {
           lcd_implementation_clear();
-          lcd_printPGM(PSTR("Factory RESET"));
+          
+		  
+		  lcd_printPGM(PSTR("Factory RESET"));
+		  
           
 		  SET_OUTPUT(BEEPER);
 		  WRITE(BEEPER, HIGH);
@@ -1043,19 +1055,17 @@ void setup()
           
 
 		  _delay_ms(2000);
-          if (!READ(BTN_ENC))
-          {
-          
-              factory_reset(0,false);
-          }
-          else
-          {
-              factory_reset(2,false);
-              
-          }
           
-          _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);
@@ -1245,6 +1255,7 @@ int serial_read_stream() {
 // 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)
 	{
@@ -1832,6 +1843,89 @@ void trace() {
     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
@@ -1855,6 +1949,11 @@ 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("fv")) {
         // get file version
@@ -1904,7 +2003,54 @@ void process_commands()
         // 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('Cal')) {
 		//  lcd_calibration();
 	  // }
@@ -2095,8 +2241,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')) {
@@ -2161,6 +2308,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)
@@ -2381,6 +2529,8 @@ void process_commands()
 
 	  if (farm_mode) { prusa_statistics(20); };
 
+	  homing_flag = false;
+
       break;
 
 #ifdef ENABLE_AUTO_BED_LEVELING
@@ -2721,7 +2871,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);
@@ -3148,6 +3298,12 @@ void process_commands()
 
     case 45: // M45: Prusa3D: bed skew and offset with manual Z up
     {
+		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.
@@ -3166,6 +3322,10 @@ void process_commands()
         // 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)) lcd_wait_for_cool_down();
+			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);
 
             // Move the print head close to the bed.
             current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
@@ -4354,7 +4514,7 @@ Sigma_Exit:
         #endif
 
         updatePID();
-        SERIAL_PROTOCOL(MSG_OK);
+        SERIAL_PROTOCOLRPGM(MSG_OK);
         SERIAL_PROTOCOL(" p:");
         SERIAL_PROTOCOL(Kp);
         SERIAL_PROTOCOL(" i:");
@@ -4378,7 +4538,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:");
@@ -4893,6 +5053,52 @@ case 404:  //M404 Enter the nominal filament width (3mm, 1.75mm ) N<3.0> or disp
   else if(code_seen('T'))
   {
     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_ECHO("T");
@@ -4932,6 +5138,7 @@ case 404:  //M404 Enter the nominal filament width (3mm, 1.75mm ) N<3.0> or disp
       SERIAL_ECHO(MSG_ACTIVE_EXTRUDER);
       SERIAL_PROTOCOLLN((int)active_extruder);
     }
+#endif
   } // end if(code_seen('T')) (end of T codes)
 
   else
@@ -5413,7 +5620,7 @@ bool setTargetedHotend(int code){
   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
 {
 	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)
 	{
@@ -5421,7 +5628,7 @@ 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_filament = eeprom_read_dword((uint32_t *)EEPROM_FILAMENTUSED); //_previous_filament unit: cm
 	unsigned long _previous_time = eeprom_read_dword((uint32_t *)EEPROM_TOTALTIME);
 
 	eeprom_update_dword((uint32_t *)EEPROM_TOTALTIME, _previous_time + (_total_print_time/60));

+ 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

+ 79 - 0
Firmware/language_all.cpp

@@ -424,6 +424,11 @@ const char * const MSG_CALIBRATE_BED_RESET_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_CALIBRATE_BED_RESET_PL
 };
 
+const char MSG_CALIBRATE_E_EN[] PROGMEM = "Calibrate E";
+const char * const MSG_CALIBRATE_E_LANG_TABLE[1] PROGMEM = {
+	MSG_CALIBRATE_E_EN
+};
+
 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";
@@ -437,6 +442,10 @@ const char * const MSG_CARD_MENU_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_CARD_MENU_PL
 };
 
+const char MSG_CHANGE_EXTR_EN[] PROGMEM = "Change extruder";
+const char * const MSG_CHANGE_EXTR_LANG_TABLE[1] PROGMEM = {
+	MSG_CHANGE_EXTR_EN
+};
 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!";
@@ -463,6 +472,10 @@ const char * const MSG_CHANGING_FILAMENT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_CHANGING_FILAMENT_PL
 };
 
+const char MSG_CLEAN_NOZZLE_E_EN[] PROGMEM = "E calibration finished. Please clean the nozzle. Click when done.";
+const char * const MSG_CLEAN_NOZZLE_E_LANG_TABLE[1] PROGMEM = {
+	MSG_CLEAN_NOZZLE_E_EN
+};
 const char MSG_CNG_SDCARD_EN[] PROGMEM = "Change SD card";
 const char * const MSG_CNG_SDCARD_LANG_TABLE[1] PROGMEM = {
 	MSG_CNG_SDCARD_EN
@@ -499,6 +512,11 @@ const char * const MSG_CONFIRM_NOZZLE_CLEAN_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_CONFIRM_NOZZLE_CLEAN_PL
 };
 
+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 * const MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_LANG_TABLE[1] PROGMEM = {
+	MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_EN
+};
+
 const char MSG_CONTROL_EN[] PROGMEM = "Control";
 const char * const MSG_CONTROL_LANG_TABLE[1] PROGMEM = {
 	MSG_CONTROL_EN
@@ -640,6 +658,10 @@ 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 * const MSG_E_CAL_KNOB_LANG_TABLE[1] PROGMEM = {
+	MSG_E_CAL_KNOB_EN
+};
 const char MSG_Enqueing_EN[] PROGMEM = "enqueing \"";
 const char * const MSG_Enqueing_LANG_TABLE[1] PROGMEM = {
 	MSG_Enqueing_EN
@@ -663,6 +685,10 @@ const char * const MSG_FAN_SPEED_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_FAN_SPEED_PL
 };
 
+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";
 const char MSG_FILAMENTCHANGE_CZ[] PROGMEM = "Vymenit filament";
 const char MSG_FILAMENTCHANGE_IT[] PROGMEM = "Camb. filamento";
@@ -676,6 +702,29 @@ const char * const MSG_FILAMENTCHANGE_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_FILAMENTCHANGE_PL
 };
 
+const char MSG_FILAMENT_CLEAN_EN[] PROGMEM = "Is color clear?";
+const char * const MSG_FILAMENT_CLEAN_LANG_TABLE[1] PROGMEM = {
+	MSG_FILAMENT_CLEAN_EN
+};
+const char MSG_FILAMENT_LOADING_T0_EN[] PROGMEM = "Insert filament into extruder 1. Click when done.";
+const char * const MSG_FILAMENT_LOADING_T0_LANG_TABLE[1] PROGMEM = {
+	MSG_FILAMENT_LOADING_T0_EN
+};
+
+const char MSG_FILAMENT_LOADING_T1_EN[] PROGMEM = "Insert filament into extruder 2. Click when done.";
+const char * const MSG_FILAMENT_LOADING_T1_LANG_TABLE[1] PROGMEM = {
+	MSG_FILAMENT_LOADING_T1_EN
+};
+
+const char MSG_FILAMENT_LOADING_T2_EN[] PROGMEM = "Insert filament into extruder 3. Click when done.";
+const char * const MSG_FILAMENT_LOADING_T2_LANG_TABLE[1] PROGMEM = {
+	MSG_FILAMENT_LOADING_T2_EN
+};
+
+const char MSG_FILAMENT_LOADING_T3_EN[] PROGMEM = "Insert filament into extruder 4. Click when done.";
+const char * const MSG_FILAMENT_LOADING_T3_LANG_TABLE[1] PROGMEM = {
+	MSG_FILAMENT_LOADING_T3_EN
+};
 const char MSG_FILE_PRINTED_EN[] PROGMEM = "Done printing file";
 const char * const MSG_FILE_PRINTED_LANG_TABLE[1] PROGMEM = {
 	MSG_FILE_PRINTED_EN
@@ -686,6 +735,19 @@ 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 * const MSG_FIL_ADJUSTING_LANG_TABLE[1] PROGMEM = {
+	MSG_FIL_ADJUSTING_EN
+};
+const char MSG_FIL_LOADED_CHECK_EN[] PROGMEM = "Is filament loaded?";
+const char * const MSG_FIL_LOADED_CHECK_LANG_TABLE[1] PROGMEM = {
+	MSG_FIL_LOADED_CHECK_EN
+};
+
+const char MSG_FIL_TUNING_EN[] PROGMEM = "Rotate the knob to adjust filament.";
+const char * const MSG_FIL_TUNING_LANG_TABLE[1] PROGMEM = {
+	MSG_FIL_TUNING_EN
+};
 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.";
@@ -958,6 +1020,10 @@ const char * const MSG_LOAD_FILAMENT_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_LOAD_FILAMENT_PL
 };
 
+const char MSG_LOOSE_PULLEY_EN[] PROGMEM = "Loose pulley";
+const char * const MSG_LOOSE_PULLEY_LANG_TABLE[1] PROGMEM = {
+	MSG_LOOSE_PULLEY_EN
+};
 const char MSG_M104_INVALID_EXTRUDER_EN[] PROGMEM = "M104 Invalid extruder ";
 const char * const MSG_M104_INVALID_EXTRUDER_LANG_TABLE[1] PROGMEM = {
 	MSG_M104_INVALID_EXTRUDER_EN
@@ -1011,6 +1077,10 @@ const char * const MSG_MAIN_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_MAIN_PL
 };
 
+const char MSG_MARK_FIL_EN[] PROGMEM = "Mark filament 100mm from extruder body. Click when done.";
+const char * const MSG_MARK_FIL_LANG_TABLE[1] PROGMEM = {
+	MSG_MARK_FIL_EN
+};
 const char MSG_MAX_EN[] PROGMEM = " \002 Max";
 const char * const MSG_MAX_LANG_TABLE[1] PROGMEM = {
 	MSG_MAX_EN
@@ -2003,6 +2073,11 @@ const char * const MSG_SPEED_LANG_TABLE[LANG_NUM] PROGMEM = {
 	MSG_SPEED_PL
 };
 
+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  ";
 const char MSG_STATISTICS_CZ[] PROGMEM = "Statistika  ";
 const char MSG_STATISTICS_IT[] PROGMEM = "Statistiche";
@@ -2256,6 +2331,10 @@ const char * const MSG_VTRAV_MIN_LANG_TABLE[1] PROGMEM = {
 	MSG_VTRAV_MIN_EN
 };
 
+const char MSG_WAITING_TEMP_EN[] PROGMEM = "Waiting for heater and bed cooling";
+const char * const MSG_WAITING_TEMP_LANG_TABLE[1] PROGMEM = {
+	MSG_WAITING_TEMP_EN
+};
 const char MSG_WATCH_EN[] PROGMEM = "Info screen";
 const char MSG_WATCH_CZ[] PROGMEM = "Informace";
 const char MSG_WATCH_IT[] PROGMEM = "Schermata info";

+ 36 - 0
Firmware/language_all.h

@@ -104,12 +104,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[1];
+#define MSG_CALIBRATE_E LANG_TABLE_SELECT_EXPLICIT(MSG_CALIBRATE_E_LANG_TABLE, 0)
 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[1];
+#define MSG_CHANGE_EXTR LANG_TABLE_SELECT_EXPLICIT(MSG_CHANGE_EXTR_LANG_TABLE, 0)
 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[1];
+#define MSG_CLEAN_NOZZLE_E LANG_TABLE_SELECT_EXPLICIT(MSG_CLEAN_NOZZLE_E_LANG_TABLE, 0)
 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 +124,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[1];
+#define MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ LANG_TABLE_SELECT_EXPLICIT(MSG_CONFIRM_NOZZLE_CLEAN_FIL_ADJ_LANG_TABLE, 0)
 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 +168,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[1];
+#define MSG_E_CAL_KNOB LANG_TABLE_SELECT_EXPLICIT(MSG_E_CAL_KNOB_LANG_TABLE, 0)
 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[1];
+#define MSG_FILAMENT_CLEAN LANG_TABLE_SELECT_EXPLICIT(MSG_FILAMENT_CLEAN_LANG_TABLE, 0)
+extern const char* const MSG_FILAMENT_LOADING_T0_LANG_TABLE[1];
+#define MSG_FILAMENT_LOADING_T0 LANG_TABLE_SELECT_EXPLICIT(MSG_FILAMENT_LOADING_T0_LANG_TABLE, 0)
+extern const char* const MSG_FILAMENT_LOADING_T1_LANG_TABLE[1];
+#define MSG_FILAMENT_LOADING_T1 LANG_TABLE_SELECT_EXPLICIT(MSG_FILAMENT_LOADING_T1_LANG_TABLE, 0)
+extern const char* const MSG_FILAMENT_LOADING_T2_LANG_TABLE[1];
+#define MSG_FILAMENT_LOADING_T2 LANG_TABLE_SELECT_EXPLICIT(MSG_FILAMENT_LOADING_T2_LANG_TABLE, 0)
+extern const char* const MSG_FILAMENT_LOADING_T3_LANG_TABLE[1];
+#define MSG_FILAMENT_LOADING_T3 LANG_TABLE_SELECT_EXPLICIT(MSG_FILAMENT_LOADING_T3_LANG_TABLE, 0)
 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[1];
+#define MSG_FIL_ADJUSTING LANG_TABLE_SELECT_EXPLICIT(MSG_FIL_ADJUSTING_LANG_TABLE, 0)
+extern const char* const MSG_FIL_LOADED_CHECK_LANG_TABLE[1];
+#define MSG_FIL_LOADED_CHECK LANG_TABLE_SELECT_EXPLICIT(MSG_FIL_LOADED_CHECK_LANG_TABLE, 0)
+extern const char* const MSG_FIL_TUNING_LANG_TABLE[1];
+#define MSG_FIL_TUNING LANG_TABLE_SELECT_EXPLICIT(MSG_FIL_TUNING_LANG_TABLE, 0)
 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];
@@ -226,6 +254,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[1];
+#define MSG_LOOSE_PULLEY LANG_TABLE_SELECT_EXPLICIT(MSG_LOOSE_PULLEY_LANG_TABLE, 0)
 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];
@@ -244,6 +274,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[1];
+#define MSG_MARK_FIL LANG_TABLE_SELECT_EXPLICIT(MSG_MARK_FIL_LANG_TABLE, 0)
 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];
@@ -448,6 +480,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];
@@ -498,6 +532,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[1];
+#define MSG_WAITING_TEMP LANG_TABLE_SELECT_EXPLICIT(MSG_WAITING_TEMP_LANG_TABLE, 0)
 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];

+ 20 - 0
Firmware/language_en.h

@@ -164,6 +164,7 @@
 #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 MSG_SELFTEST_FAN					"Fan test";
 #define(length=20) MSG_SELFTEST_COOLING_FAN			"Front print fan?";
@@ -230,6 +231,25 @@
 #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=4) 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=4) MSG_MARK_FIL						"Mark filament 100mm from extruder body. Click when done."
+#define(length=20, lines=4) MSG_CLEAN_NOZZLE_E				"E calibration finished. Please clean the nozzle. Click when done."
+#define(length=20, lines=2) MSG_WAITING_TEMP				"Waiting for heater and bed cooling"
+#define(length=20, lines=1) MSG_FILAMENT_CLEAN				"Is color clear?"
+
 #define MSG_BED_CORRECTION_MENU									"Bed level correct"
 #define MSG_BED_CORRECTION_LEFT									"Left side  um"
 #define MSG_BED_CORRECTION_RIGHT								"Right side um"

+ 1 - 1
Firmware/mesh_bed_calibration.cpp

@@ -2152,7 +2152,7 @@ static int babystepLoadZ = 0;
 
 void babystep_apply()
 {
-    // Apply Z height correction aka baby stepping before mesh bed leveing gets activated.
+    // 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.

+ 16 - 0
Firmware/pins.h

@@ -63,6 +63,14 @@
   #define TEMP_1_PIN 1
   #define TEMP_2_PIN -1
   
+#ifdef SNMM 
+
+#define E_MUX0_PIN 17
+#define E_MUX1_PIN 16
+#define E_MUX2_PIN 84
+
+
+#endif
   // The SDSS pin uses a different pin mapping from file Sd2PinMap.h
 #define SDSS               53
 
@@ -209,6 +217,14 @@
 
   #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

+ 923 - 43
Firmware/ultralcd.cpp

@@ -13,7 +13,7 @@
 #include "mesh_bed_leveling.h"
 //#include "Configuration.h"
 
-
+#include "SdFatUtil.h"
 
 #define _STRINGIFY(s) #s
 
@@ -446,7 +446,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);
@@ -499,7 +499,7 @@ 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 == 0) { lcd_commands_step = 7; custom_message = true;}
 			if (lcd_commands_step == 1 && !blocks_queued())
 			{
 				lcd_commands_step = 0;
@@ -510,32 +510,46 @@ void lcd_commands()
 				custom_message_type = 0;
    
 			}
+
+
 			if (lcd_commands_step == 2 && !blocks_queued())
+			{				
+				lcd_commands_step = lcd_show_fullscreen_message_yes_no_and_wait_P(MSG_FILAMENT_CLEAN) ? 1 : 4;
+				lcd_update_enable(true);
+				lcdDrawUpdate = 2;
+
+			}
+			if (lcd_commands_step == 3 && !blocks_queued()) {
+				lcd_commands_step = farm_mode ? 1:2; //don't show question about clear color if we are in farm mode
+			}
+
+			if (lcd_commands_step == 4 && !blocks_queued())
 			{
-				lcd_setstatuspgm(MSG_LOADING_FILAMENT);
-				enquecommand_P(PSTR(LOAD_FILAMENT_2));
-				lcd_commands_step = 1;
+				//lcd_setstatuspgm(MSG_LOADING_FILAMENT);
+				enquecommand_P(PSTR(LOAD_FILAMENT_2)); //slow_sequence
+				lcd_commands_step = 3;
 			}
-			if (lcd_commands_step == 3 && !blocks_queued())
+			if (lcd_commands_step == 5 && !blocks_queued())
 			{
-				enquecommand_P(PSTR(LOAD_FILAMENT_1));
-                enquecommand_P(PSTR("G4"));
-				lcd_commands_step = 2;
+				enquecommand_P(PSTR(LOAD_FILAMENT_1)); //fast sequence
+				lcd_setstatuspgm(MSG_LOADING_FILAMENT);
+                //enquecommand_P(PSTR("G4")); //dwell
+				lcd_commands_step = 4;
 			}
-			if (lcd_commands_step == 4 && !blocks_queued())
+			if (lcd_commands_step == 6 && !blocks_queued())
 			{
 				lcd_setstatuspgm(MSG_INSERT_FILAMENT);
-				enquecommand_P(PSTR(LOAD_FILAMENT_0));
+				enquecommand_P(PSTR(LOAD_FILAMENT_0)); //set E relative
                 enquecommand_P(PSTR("G1 E0.1 F400"));
-				lcd_commands_step = 3;
+				lcd_commands_step = 5;
 			}
-			if (lcd_commands_step == 5 && !blocks_queued())
+			if (lcd_commands_step == 7 && !blocks_queued())
 			{
 				lcd_setstatuspgm(MSG_PLEASE_WAIT);
 				enable_z();
 				custom_message = true;
 				custom_message_type = 2;
-				lcd_commands_step = 4;
+				lcd_commands_step = 6;
 			}
 	}
 
@@ -549,7 +563,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())
 		{
@@ -571,6 +587,7 @@ void lcd_commands()
 		}
 		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.
@@ -581,7 +598,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())
 		{
@@ -590,20 +611,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)
@@ -645,7 +729,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
 		}
 
 	}
@@ -936,6 +1024,9 @@ void lcd_loading_filament() {
 
 }
 
+
+
+
 void lcd_alright() {
   int enc_dif = 0;
   int cursor_pos = 1;
@@ -1051,7 +1142,7 @@ void lcd_LoadFilament()
 }
 
 
-static void lcd_menu_statistics()
+void lcd_menu_statistics()
 {
 
 	if (IS_SD_PRINTING)
@@ -1183,6 +1274,7 @@ static void _lcd_move(const char *name, int axis, int min, int max) {
 
 static void lcd_move_e()
 {
+	if (degHotend0() > EXTRUDE_MINTEMP) {
   if (encoderPosition != 0)
   {
     refresh_cmd_timeout();
@@ -1199,6 +1291,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.
@@ -1297,6 +1400,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()
@@ -1430,6 +1544,28 @@ void lcd_adjust_z() {
 
 }
 
+void lcd_wait_for_cool_down() {
+	while ((degHotend(0)>MAX_HOTEND_TEMP_CALIBRATION) || (degBed() > MAX_BED_TEMP_CALIBRATION)) {
+		lcd_display_message_fullscreen_P(MSG_WAITING_TEMP);
+
+		lcd.setCursor(0, 2);
+		lcd.print(LCD_STR_THERMOMETER[0]);
+		lcd.print(ftostr3(degHotend(0)));
+		lcd.print("/0");
+//		lcd.print(LCD_STR_DEGREE);
+//		lcd_printPGM(PSTR(LCD_STR_DEGREE));
+
+
+		lcd.setCursor(0, 3);
+		lcd.print(LCD_STR_BEDTEMP[0]);
+		lcd.print(ftostr3(degBed()));
+		lcd.print("/0");
+//		lcd_printPGM(PSTR(LCD_STR_DEGREE));
+
+		delay_keep_alive(1000);
+	}
+}
+
 // 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.
@@ -1505,10 +1641,10 @@ calibrated:
     plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
     
     
-    if(only_z){
+    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);
+        lcd_printPGM(MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2);*/
     }else{
         lcd_display_message_fullscreen_P(MSG_FIND_BED_OFFSET_AND_SKEW_LINE1);
         lcd_implementation_print_at(0, 2, 1);
@@ -2128,6 +2264,69 @@ void lcd_mesh_calibration_z()
   lcd_return_to_status();
 }
 
+#ifndef SNMM
+
+void lcd_calibrate_extruder() {
+	long steps_start = st_get_position(E_AXIS);
+	long steps_final;
+	float e_steps_per_unit;
+	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] += 70;
+	plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 5, active_extruder);
+	st_synchronize();
+	lcd_display_message_fullscreen_P(MSG_E_CAL_KNOB);
+	while (!LCD_CLICKED) {
+		//manage_inactivity(true);
+		manage_heater();
+		if (abs(encoderDiff) >= ENCODER_PULSES_PER_STEP) {
+			delay(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.05;
+				encoderPosition = 0;
+				plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 5, active_extruder);
+				lcdDrawUpdate = 1;
+			}
+		}
+		//end_position = current_position[E_AXIS];
+		//steps = st_get_position(E_AXIS);
+		//steps_final = st_get_position(E_AXIS);
+		//e_steps_per_unit = ((float)(steps_final - steps_start)) / 100;
+
+		//if (lcdDrawUpdate) lcd_implementation_drawedit(PSTR("Result:"), ftostr31(e_steps_per_unit));
+	}
+	steps_final = st_get_position(E_AXIS);
+	
+	e_steps_per_unit = ((float)(steps_final - steps_start)) / 100.f;
+	if (e_steps_per_unit < 100) e_steps_per_unit = 100;
+	if (e_steps_per_unit > 250) e_steps_per_unit = 250;
+
+	lcd_implementation_clear();
+	//axis_steps_per_unit[E_AXIS] = eeprom_read_float((float*)EEPROM_STEPS_PER_UNIT_E);
+	//lcd_implementation_drawedit(PSTR("Result"), ftostr31(axis_steps_per_unit[E_AXIS]));
+	//delay_keep_alive(2000);
+	//zapis do eeprom
+	//eeprom_update_float((float*)EEPROM_STEPS_PER_UNIT_E, e_steps_per_unit);
+
+	axis_steps_per_unit[E_AXIS] = e_steps_per_unit;
+	//enquecommand_P(PSTR("M92 E%f"), e_steps_per_unit);
+	enquecommand_P(PSTR("M500")); //store settings to eeprom
+	//axis_steps_per_unit[E_AXIS] = eeprom_read_float((float*)EEPROM_STEPS_PER_UNIT_E);
+	lcd_implementation_drawedit(PSTR("Result"), ftostr31(axis_steps_per_unit[E_AXIS]));
+	delay_keep_alive(2000);
+	lcd_show_fullscreen_message_and_wait_P(MSG_CLEAN_NOZZLE_E);
+	
+	lcd_update_enable(true);
+	lcd_return_to_status();
+	
+}
+
+#endif
+
 void lcd_toshiba_flash_air_compatibility_toggle()
 {
    card.ToshibaFlashAir_enable(! card.ToshibaFlashAir_isEnabled());
@@ -2142,8 +2341,10 @@ 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"));
@@ -2155,7 +2356,7 @@ static void lcd_settings_menu()
     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
 	}
@@ -2181,16 +2382,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
@@ -2382,7 +2586,341 @@ void lcd_mylang() {
 
 }
 
+char reset_menu() {
+	int enc_dif = 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(">");
+
+
+	enc_dif = encoderDiff;
+
+	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);
+			}
+
+		}
+
+		if (lcd_clicked()) {
+			while (lcd_clicked());
+			delay(10);
+			while (lcd_clicked());
+			return(cursor_pos);
+		}
+
+	}
+
+}
+
+#ifdef SNMM
+
+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);
+}
+
+
+void change_extr(int extr) { //switches multiplexer for extruders
+	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);
+	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()
 {
@@ -2596,7 +3134,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
@@ -2617,10 +3156,17 @@ static void lcd_main_menu()
   } 
   else 
   {
+	#ifndef SNMM
     MENU_ITEM(function, MSG_LOAD_FILAMENT, lcd_LoadFilament);
     MENU_ITEM(function, MSG_UNLOAD_FILAMENT, lcd_unLoadFilament);
+	#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);
-    MENU_ITEM(submenu, MSG_MENU_CALIBRATION, lcd_calibration_menu);
+    if(!isPrintPaused) MENU_ITEM(submenu, MSG_MENU_CALIBRATION, lcd_calibration_menu);
   }
 
   if (!is_usb_printing)
@@ -2628,11 +3174,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()
@@ -2794,6 +3348,35 @@ void lcd_sdcard_stop()
 	}
 
 }
+/*
+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()
 {
@@ -2843,6 +3426,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 () \
   { \
@@ -2931,22 +3581,40 @@ 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, 2000);
+		_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, 1500);
+		_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);
+		current_position[Z_AXIS] = current_position[Z_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 (_result)
@@ -2975,7 +3643,7 @@ static void lcd_selftest()
 		LCD_ALERTMESSAGERPGM(MSG_SELFTEST_FAILED);
 	}
 }
-static bool lcd_selfcheck_endstops()
+/*static bool lcd_selfcheck_endstops()
 {
 	bool _result = true;
 
@@ -2999,7 +3667,7 @@ static bool lcd_selfcheck_endstops()
 	manage_heater();
 	manage_inactivity();
 	return _result;
-}
+}*/
 static bool lcd_selfcheck_axis(int _axis, int _travel)
 {
 	bool _stepdone = false;
@@ -3012,14 +3680,14 @@ static bool lcd_selfcheck_axis(int _axis, int _travel)
 
 	do {
 
-		if (_axis == 2)
-		{
+		/*if (_axis == 2)
+		{*/
 			current_position[_axis] = current_position[_axis] - 1;
-		}
+		/*}
 		else
 		{
 			current_position[_axis] = current_position[_axis] - 3;
-		}
+		}*/
 
 		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();
@@ -3060,14 +3728,14 @@ static bool lcd_selfcheck_axis(int _axis, int _travel)
 		manage_heater();
 		manage_inactivity();
 
-		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)
 	{
@@ -3094,6 +3762,210 @@ 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;// = 20000 + millis();
+	refresh_cmd_timeout();
+
+
+	if (axis == 0) move = 50; //230;
+		else move = 50; //190
+
+
+		
+		/*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;*/
+				current_position_init = current_position[axis];
+				timeout_counter = millis() + 2500; 
+			/*}
+			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) return(false);
+			}
+		}*/
+		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(axis, 850); //set motor current higher
+			//max_jerk[X_AXIS] = 20;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], 200, active_extruder);
+			//max_jerk[X_AXIS] = DEFAULT_XJERK;
+			//digipot_current(axis, tmp_motor_loud[0]);
+			/*if (SilentMode == 1) digipot_current(2, tmp_motor[2]); //set back to normal operation currents
+			else */digipot_current(2, tmp_motor_loud[2]); //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)) {
+				//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);
+				lcd_selftest_error(8, (axis == 0) ? "X" : "Y", "");
+				return(false);
+			}
+			if (millis() > timeout_counter) {
+				lcd_selftest_error(8, (axis == 0) ? "X" : "Y", "");
+				return(false);
+			}else timeout_counter = millis() + 2500;
+		}
+		
+		endstop_triggered = false;
+		
+		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);
+					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_pulleys_2() {
+	int axis;
+	float current_position_init;
+	float trigger_position1, trigger_position2;
+	bool endstop_triggered = false;
+	for (axis = 0; axis < 2; axis++) {
+		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;
+				current_position_init = current_position[axis];
+				//timeout_counter = millis() + 10000;
+			}
+			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) return(false);
+			}
+		}
+	}
+	current_position[0] += 50;
+	plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder);
+	while (READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING != 1);
+	trigger_position1 = current_position[X_AXIS];
+	st_synchronize();
+	current_position[0] -= 40;
+	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();
+	current_position[0] += 40;
+	plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder);
+	while (READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING != 1);
+	trigger_position2 = current_position[X_AXIS];
+
+
+	if(trigger_position2 == trigger_position1) return true;
+	else return false;
+}
+
+
+static bool lcd_selfcheck_belts2() {
+
+	float current_position_init;
+	bool endstop_triggered = false;
+	int i, axis;
+	axis = 0;
+	//for (axis = 0; axis < 2; axis++) {
+
+	/*while (!endstop_triggered) {
+		if (READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING == 1) {
+			endstop_triggered = true;
+			current_position_init = current_position[axis];
+			current_position[axis] += 30;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], 50, active_extruder);
+			st_synchronize();
+			current_position[axis] -= 29;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], 500, active_extruder);
+			if (READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING == 1) return(false);
+			else return(true);
+		}
+		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();
+		}
+	}
+
+	while (!endstop_triggered) {
+		if (READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING == 1) {
+			endstop_triggered = true;
+			current_position_init = current_position[axis];
+			current_position[axis] += 30;
+			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], 50, active_extruder);
+			st_synchronize();
+			for (i = 0; i < 50; i++) {
+				current_position[axis] -= 1;
+				plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], 500, active_extruder);
+				current_position[axis] += 1;
+				plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], 500, active_extruder);
+				st_synchronize();
+			}
+			if (READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING == 1) return(false);
+			else return(true);
+		}
+		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();
+		}
+	}
+
+}
+*/
+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_check_heater(bool _isbed)
 {
 	int _counter = 0;
@@ -3220,7 +4092,14 @@ static void lcd_selftest_error(int _error_no, const char *_error_1, const char *
 		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);
@@ -3590,6 +4469,7 @@ void lcd_update(uint8_t lcdDrawUpdateOverride)
 	  {
 		  card.initsd();
 		  LCD_MESSAGERPGM(MSG_SD_INSERTED);
+		  //get_description();
 	  }
 	  else
 	  {
@@ -3677,7 +4557,7 @@ void lcd_update(uint8_t lcdDrawUpdateOverride)
 	  if (lcdDrawUpdate) lcdDrawUpdate--;
 	  lcd_next_update_millis = millis() + LCD_UPDATE_INTERVAL;
 	  }
-   
+	if (!SdFatUtil::test_stack_integrity()) stack_error();
 }
 
 void lcd_ignore_click(bool b)

+ 36 - 2
Firmware/ultralcd.h

@@ -39,7 +39,8 @@ void lcd_mylang();
   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) 
@@ -196,4 +197,37 @@ 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 stack_test();
+static int test();
+
+void stack_error();
+//void lcd_calibrate_extruder();
+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();
+
+union MenuData;
+
+char reset_menu();
+#endif //ULTRALCD_H

+ 6 - 0
Firmware/ultralcd_implementation_hitachi_HD44780.h

@@ -776,6 +776,12 @@ static void lcd_implementation_status_screen()
         
 	}
 
+#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("  "));