Browse Source

Merge remote-tracking branch 'prusa3d/MK3_dev' into simplify_EEPROM_M500

Known limitation: Unable to compile.
Marek Bel 5 years ago
parent
commit
1585dc66b0

+ 6 - 4
Firmware/ConfigurationStore.cpp

@@ -13,10 +13,11 @@ M500_conf cs;
 
 #ifdef DEBUG_EEPROM_WRITE
 #define EEPROM_WRITE_VAR(pos, value) _EEPROM_writeData(pos, (uint8_t*)&value, sizeof(value), #value)
+static void _EEPROM_writeData(int &pos, uint8_t* value, uint8_t size, char* name)
 #else //DEBUG_EEPROM_WRITE
-#define EEPROM_WRITE_VAR(pos, value) _EEPROM_writeData(pos, (uint8_t*)&value, sizeof(value), 0)
+#define EEPROM_WRITE_VAR(pos, value) _EEPROM_writeData(pos, (uint8_t*)&value, sizeof(value))
+static void _EEPROM_writeData(int &pos, uint8_t* value, uint8_t size)
 #endif //DEBUG_EEPROM_WRITE
-void _EEPROM_writeData(int &pos, uint8_t* value, uint8_t size, char* name)
 {
 #ifdef DEBUG_EEPROM_WRITE
 	printf_P(PSTR("EEPROM_WRITE_VAR addr=0x%04x size=0x%02hhx name=%s\n"), pos, size, name);
@@ -41,10 +42,11 @@ void _EEPROM_writeData(int &pos, uint8_t* value, uint8_t size, char* name)
 
 #ifdef DEBUG_EEPROM_READ
 #define EEPROM_READ_VAR(pos, value) _EEPROM_readData(pos, (uint8_t*)&value, sizeof(value), #value)
+static void _EEPROM_readData(int &pos, uint8_t* value, uint8_t size, char* name)
 #else //DEBUG_EEPROM_READ
-#define EEPROM_READ_VAR(pos, value) _EEPROM_readData(pos, (uint8_t*)&value, sizeof(value), 0)
+#define EEPROM_READ_VAR(pos, value) _EEPROM_readData(pos, (uint8_t*)&value, sizeof(value))
+static void _EEPROM_readData(int &pos, uint8_t* value, uint8_t size)
 #endif //DEBUG_EEPROM_READ
-void _EEPROM_readData(int &pos, uint8_t* value, uint8_t size, char* name)
 {
 #ifdef DEBUG_EEPROM_READ
 	printf_P(PSTR("EEPROM_READ_VAR addr=0x%04x size=0x%02hhx name=%s\n"), pos, size, name);

+ 1 - 2
Firmware/Dcodes.cpp

@@ -34,7 +34,6 @@ void print_eeprom(uint16_t address, uint16_t count, uint8_t countperline = 16)
 		uint8_t count_line = countperline;
 		while (count && count_line)
 		{
-			uint8_t data = 0;
 			putchar(' ');
 			print_hex_byte(eeprom_read_byte((uint8_t*)address++));
 			count_line--;
@@ -115,7 +114,7 @@ void dcode_3()
 		count = parse_hex(strchr_pointer + 1, data, 16);
 		if (count > 0)
 		{
-			for (int i = 0; i < count; i++)
+			for (uint16_t i = 0; i < count; i++)
 				eeprom_write_byte((uint8_t*)(address + i), data[i]);
 			printf_P(_N("%d bytes written to EEPROM at address 0x%04x"), count, address);
 			putchar('\n');

+ 12 - 9
Firmware/Marlin.h

@@ -148,7 +148,7 @@ void manage_inactivity(bool ignore_stepper_queue=false);
 			#define disable_z() { WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN,!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; }
 		  #else
 			#define  enable_z() WRITE(Z_ENABLE_PIN, Z_ENABLE_ON)
-			#define  disable_z() ;
+			#define  disable_z() {}
 		  #endif
 	#else
 		#ifdef Z_DUAL_STEPPER_DRIVERS
@@ -160,8 +160,8 @@ void manage_inactivity(bool ignore_stepper_queue=false);
 		#endif
 	#endif
 #else
-  #define enable_z() ;
-  #define disable_z() ;
+  #define enable_z() {}
+  #define disable_z() {}
 #endif
 
 
@@ -278,6 +278,7 @@ extern float max_pos[3];
 extern bool axis_known_position[3];
 extern int fanSpeed;
 extern void homeaxis(int axis, uint8_t cnt = 1, uint8_t* pstep = 0);
+extern int8_t lcd_change_fil_state;
 
 
 #ifdef FAN_SOFT_PWM
@@ -328,10 +329,6 @@ extern uint8_t active_extruder;
 #endif
 
 //Long pause
-extern int saved_feedmultiply;
-extern float HotendTempBckp;
-extern int fanSpeedBckp;
-extern float pause_lastpos[4];
 extern unsigned long pause_time;
 extern unsigned long start_pause_print;
 extern unsigned long t_fan_rising_edge;
@@ -355,12 +352,14 @@ extern uint8_t print_percent_done_normal;
 extern uint16_t print_time_remaining_normal;
 extern uint8_t print_percent_done_silent;
 extern uint16_t print_time_remaining_silent;
+
+#define PRINT_TIME_REMAINING_INIT 0xffff
+
 extern uint16_t mcode_in_progress;
 extern uint16_t gcode_in_progress;
 
 extern bool wizard_active; //autoload temporarily disabled during wizard
 
-#define PRINT_TIME_REMAINING_INIT 0xffff
 #define PRINT_PERCENT_DONE_INIT   0xff
 #define PRINTER_ACTIVE (IS_SD_PRINTING || is_usb_printing || isPrintPaused || (custom_message_type == CUSTOM_MSG_TYPE_TEMCAL) || saved_printing || (lcd_commands_type == LCD_COMMAND_V2_CAL) || card.paused || mmu_print_saved)
 
@@ -373,6 +372,7 @@ extern void delay_keep_alive(unsigned int ms);
 extern void check_babystep();
 
 extern void long_pause();
+extern void crashdet_stop_and_save_print();
 
 #ifdef DIS
 
@@ -413,6 +413,9 @@ extern void print_world_coordinates();
 extern void print_physical_coordinates();
 extern void print_mesh_bed_leveling_table();
 
+extern void stop_and_save_print_to_ram(float z_move, float e_move);
+extern void restore_print_from_ram_and_continue(float e_move);
+
 
 //estimated time to end of the print
 extern uint16_t print_time_remaining();
@@ -467,5 +470,5 @@ void proc_commands();
 
 void M600_load_filament();
 void M600_load_filament_movements();
-void M600_wait_for_user();
+void M600_wait_for_user(float HotendTempBckp);
 void M600_check_state();

+ 446 - 433
Firmware/Marlin_main.cpp

@@ -145,135 +145,7 @@
 #define FILAMENT_DEFAULT 0
 #define FILAMENT_FLEX 1
 #define FILAMENT_PVA 2
-
-// look here for descriptions of G-codes: http://linuxcnc.org/handbook/gcode/g-code.html
-// http://objects.reprap.org/wiki/Mendel_User_Manual:_RepRapGCodes
-
-//Implemented Codes
-//-------------------
-
-// PRUSA CODES
-// P F - Returns FW versions
-// P R - Returns revision of printer
-
-// G0  -> G1
-// G1  - Coordinated Movement X Y Z E
-// G2  - CW ARC
-// G3  - CCW ARC
-// G4  - Dwell S<seconds> or P<milliseconds>
-// G10 - retract filament according to settings of M207
-// G11 - retract recover filament according to settings of M208
-// G28 - Home all Axis
-// G29 - Detailed Z-Probe, probes the bed at 3 or more points.  Will fail if you haven't homed yet.
-// G30 - Single Z Probe, probes bed at current XY location.
-// G31 - Dock sled (Z_PROBE_SLED only)
-// G32 - Undock sled (Z_PROBE_SLED only)
-// G80 - Automatic mesh bed leveling
-// G81 - Print bed profile
-// G90 - Use Absolute Coordinates
-// G91 - Use Relative Coordinates
-// G92 - Set current position to coordinates given
-
-// M Codes
-// M0   - Unconditional stop - Wait for user to press a button on the LCD
-// M1   - Same as M0
-// M17  - Enable/Power all stepper motors
-// M18  - Disable all stepper motors; same as M84
-// M20  - List SD card
-// M21  - Init SD card
-// M22  - Release SD card
-// M23  - Select SD file (M23 filename.g)
-// M24  - Start/resume SD print
-// M25  - Pause SD print
-// M26  - Set SD position in bytes (M26 S12345)
-// M27  - Report SD print status
-// M28  - Start SD write (M28 filename.g)
-// M29  - Stop SD write
-// M30  - Delete file from SD (M30 filename.g)
-// M31  - Output time since last M109 or SD card start to serial
-// M32  - Select file and start SD print (Can be used _while_ printing from SD card files):
-//        syntax "M32 /path/filename#", or "M32 S<startpos bytes> !filename#"
-//        Call gcode file : "M32 P !filename#" and return to caller file after finishing (similar to #include).
-//        The '#' is necessary when calling from within sd files, as it stops buffer prereading
-// M42  - Change pin status via gcode Use M42 Px Sy to set pin x to value y, when omitting Px the onboard led will be used.
-// M73  - Show percent done and print time remaining
-// M80  - Turn on Power Supply
-// M81  - Turn off Power Supply
-// M82  - Set E codes absolute (default)
-// M83  - Set E codes relative while in Absolute Coordinates (G90) mode
-// M84  - Disable steppers until next move,
-//        or use S<seconds> to specify an inactivity timeout, after which the steppers will be disabled.  S0 to disable the timeout.
-// M85  - Set inactivity shutdown timer with parameter S<seconds>. To disable set zero (default)
-// M86  - Set safety timer expiration time with parameter S<seconds>; M86 S0 will disable safety timer
-// M92  - Set axis_steps_per_unit - same syntax as G92
-// M104 - Set extruder target temp
-// M105 - Read current temp
-// M106 - Fan on
-// M107 - Fan off
-// M109 - Sxxx Wait for extruder current temp to reach target temp. Waits only when heating
-//        Rxxx Wait for extruder current temp to reach target temp. Waits when heating and cooling
-//        IF AUTOTEMP is enabled, S<mintemp> B<maxtemp> F<factor>. Exit autotemp by any M109 without F
-// M112 - Emergency stop
-// M113 - Get or set the timeout interval for Host Keepalive "busy" messages
-// M114 - Output current position to serial port
-// M115 - Capabilities string
-// M117 - display message
-// M119 - Output Endstop status to serial port
-// M126 - Solenoid Air Valve Open (BariCUDA support by jmil)
-// M127 - Solenoid Air Valve Closed (BariCUDA vent to atmospheric pressure by jmil)
-// M128 - EtoP Open (BariCUDA EtoP = electricity to air pressure transducer by jmil)
-// M129 - EtoP Closed (BariCUDA EtoP = electricity to air pressure transducer by jmil)
-// M140 - Set bed target temp
-// M150 - Set BlinkM Color Output R: Red<0-255> U(!): Green<0-255> B: Blue<0-255> over i2c, G for green does not work.
-// M190 - Sxxx Wait for bed current temp to reach target temp. Waits only when heating
-//        Rxxx Wait for bed current temp to reach target temp. Waits when heating and cooling
-// M200 D<millimeters>- set filament diameter and set E axis units to cubic millimeters (use S0 to set back to millimeters).
-// M201 - Set max acceleration in units/s^2 for print moves (M201 X1000 Y1000)
-// M202 - Set max acceleration in units/s^2 for travel moves (M202 X1000 Y1000) Unused in Marlin!!
-// M203 - Set maximum feedrate that your machine can sustain (M203 X200 Y200 Z300 E10000) in mm/sec
-// M204 - Set default acceleration: S normal moves T filament only moves (M204 S3000 T7000) in mm/sec^2  also sets minimum segment time in ms (B20000) to prevent buffer under-runs and M20 minimum feedrate
-// M205 -  advanced settings:  minimum travel speed S=while printing T=travel only,  B=minimum segment time X= maximum xy jerk, Z=maximum Z jerk, E=maximum E jerk
-// M206 - set additional homing offset
-// M207 - set retract length S[positive mm] F[feedrate mm/min] Z[additional zlift/hop], stays in mm regardless of M200 setting
-// M208 - set recover=unretract length S[positive mm surplus to the M207 S*] F[feedrate mm/sec]
-// M209 - S<1=true/0=false> enable automatic retract detect if the slicer did not support G10/11: every normal extrude-only move will be classified as retract depending on the direction.
-// M218 - set hotend offset (in mm): T<extruder_number> X<offset_on_X> Y<offset_on_Y>
-// M220 S<factor in percent>- set speed factor override percentage
-// M221 S<factor in percent>- set extrude factor override percentage
-// M226 P<pin number> S<pin state>- Wait until the specified pin reaches the state required
-// M240 - Trigger a camera to take a photograph
-// M250 - Set LCD contrast C<contrast value> (value 0..63)
-// M280 - set servo position absolute. P: servo index, S: angle or microseconds
-// M300 - Play beep sound S<frequency Hz> P<duration ms>
-// M301 - Set PID parameters P I and D
-// M302 - Allow cold extrudes, or set the minimum extrude S<temperature>.
-// M303 - PID relay autotune S<temperature> sets the target temperature. (default target temperature = 150C)
-// M304 - Set bed PID parameters P I and D
-// M400 - Finish all moves
-// M401 - Lower z-probe if present
-// M402 - Raise z-probe if present
-// M404 - N<dia in mm> Enter the nominal filament width (3mm, 1.75mm ) or will display nominal filament width without parameters
-// M405 - Turn on Filament Sensor extrusion control.  Optional D<delay in cm> to set delay in centimeters between sensor and extruder 
-// M406 - Turn off Filament Sensor extrusion control 
-// M407 - Displays measured filament diameter 
-// M500 - stores parameters in EEPROM
-// M501 - reads parameters from EEPROM (if you need reset them after you changed them temporarily).
-// M502 - reverts to the default "factory settings".  You still need to store them in EEPROM afterwards if you want to.
-// M503 - print the current settings (from memory not from EEPROM)
-// M509 - force language selection on next restart
-// M540 - Use S[0|1] to enable or disable the stop SD card print on endstop hit (requires ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED)
-// M600 - Pause for filament change X[pos] Y[pos] Z[relative lift] E[initial retract] L[later retract distance for removal]
-// M605 - Set dual x-carriage movement mode: S<mode> [ X<duplication x-offset> R<duplication temp offset> ]
-// M860 - Wait for PINDA thermistor to reach target temperature.
-// M861 - Set / Read PINDA temperature compensation offsets
-// M900 - Set LIN_ADVANCE options, if enabled. See Configuration_adv.h for details.
-// M907 - Set digital trimpot motor current using axis codes.
-// M908 - Control digital trimpot directly.
-// M350 - Set microstepping mode.
-// M351 - Toggle MS1 MS2 pins directly.
-
-// M928 - Start SD logging (M928 filename.g) - ended by M29
-// M999 - Restart after being stopped by error
+#define FILAMENT_UNDEFINED 255
 
 //Stepper Movement Variables
 
@@ -305,7 +177,6 @@ float homing_feedrate[] = HOMING_FEEDRATE;
 // Other axes are always absolute or relative based on the common relative_mode flag.
 bool axis_relative_modes[] = AXIS_RELATIVE_MODES;
 int feedmultiply=100; //100->1 200->2
-int saved_feedmultiply;
 int extrudemultiply=100; //100->1 200->2
 int extruder_multiply[EXTRUDERS] = {100
   #if EXTRUDERS > 1
@@ -329,10 +200,6 @@ unsigned int  usb_printing_counter;
 
 int8_t lcd_change_fil_state = 0;
 
-int feedmultiplyBckp = 100;
-float HotendTempBckp = 0;
-int fanSpeedBckp = 0;
-float pause_lastpos[4];
 unsigned long pause_time = 0;
 unsigned long start_pause_print = millis();
 unsigned long t_fan_rising_edge = millis();
@@ -450,8 +317,6 @@ bool no_response = false;
 uint8_t important_status;
 uint8_t saved_filament_type;
 
-// save/restore printing
-bool saved_printing = false;
 
 // save/restore printing in case that mmu was not responding 
 bool mmu_print_saved = false;
@@ -512,15 +377,20 @@ unsigned long chdkHigh = 0;
 boolean chdkActive = false;
 #endif
 
-// save/restore printing
-static uint32_t saved_sdpos = 0;
+//! @name RAM save/restore printing
+//! @{
+bool saved_printing = false; //!< Print is paused and saved in RAM
+static uint32_t saved_sdpos = 0; //!< SD card position, or line number in case of USB printing
 static uint8_t saved_printing_type = PRINTING_TYPE_SD;
 static float saved_pos[4] = { 0, 0, 0, 0 };
-// Feedrate hopefully derived from an active block of the planner at the time the print has been canceled, in mm/min.
+//! Feedrate hopefully derived from an active block of the planner at the time the print has been canceled, in mm/min.
 static float saved_feedrate2 = 0;
 static uint8_t saved_active_extruder = 0;
+static float saved_extruder_temperature = 0.0; //!< Active extruder temperature
 static bool saved_extruder_under_pressure = false;
 static bool saved_extruder_relative_mode = false;
+static int saved_fanSpeed = 0; //!< Print fan speed
+//! @}
 
 //===========================================================================
 //=============================Routines======================================
@@ -632,9 +502,6 @@ void servo_init()
 }
 
 
-void stop_and_save_print_to_ram(float z_move, float e_move);
-void restore_print_from_ram_and_continue(float e_move);
-
 bool fans_check_enabled = true;
 
 
@@ -730,16 +597,11 @@ void crashdet_detected(uint8_t mask)
 	if (automatic_recovery_after_crash) {
 		enquecommand_P(PSTR("CRASH_RECOVER"));
 	}else{
-		HotendTempBckp = degTargetHotend(active_extruder);
 		setTargetHotend(0, active_extruder);
 		bool yesno = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Crash detected. Resume print?"), false);
 		lcd_update_enable(true);
 		if (yesno)
 		{
-			char cmd1[10];
-			strcpy(cmd1, "M109 S");
-			strcat(cmd1, ftostr3(HotendTempBckp));
-			enquecommand(cmd1);
 			enquecommand_P(PSTR("CRASH_RECOVER"));
 		}
 		else
@@ -786,9 +648,8 @@ void failstats_reset_print()
 // 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)
+static void factory_reset(char level)
 {	
 	lcd_clear();
     switch (level) {
@@ -877,7 +738,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 
 			// Erase EEPROM
 			for (int i = 0; i < 4096; i++) {
-				eeprom_write_byte((uint8_t*)i, 0xFF);
+				eeprom_update_byte((uint8_t*)i, 0xFF);
 
 				if (i % 41 == 0) {
 					er_progress++;
@@ -903,9 +764,9 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 }
 
 
-FILE _uartout = {0};
+FILE _uartout; //= {0}; Global variable is always zero initialized. No need to explicitly state this.
 
-int uart_putchar(char c, FILE *stream)
+int uart_putchar(char c, FILE *)
 {
 	MYSERIAL.write(c);
 	return 0;
@@ -950,7 +811,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 			_delay_ms(2000);
 
 			char level = reset_menu();
-			factory_reset(level, false);
+			factory_reset(level);
 
 			switch (level) {
 			case 0: _delay_ms(0); break;
@@ -1627,7 +1488,7 @@ void setup()
 	  erase_eeprom_section(EEPROM_OFFSET, 156); 							   //erase M500 part of eeprom
   }
   if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE) == 1) {
-	  lcd_wizard(0);
+	  lcd_wizard(WizState::Run);
   }
   if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE) == 0) { //dont show calibration status messages if wizard is currently active
 	  if (calibration_status() == CALIBRATION_STATUS_ASSEMBLED ||
@@ -2001,23 +1862,25 @@ static void axis_is_at_home(int axis) {
 inline void set_current_to_destination() { memcpy(current_position, destination, sizeof(current_position)); }
 inline void set_destination_to_current() { memcpy(destination, current_position, sizeof(destination)); }
 
-
-static void setup_for_endstop_move(bool enable_endstops_now = true) {
+//! @return original feedmultiply
+static int setup_for_endstop_move(bool enable_endstops_now = true) {
     saved_feedrate = feedrate;
-    saved_feedmultiply = feedmultiply;
+    int l_feedmultiply = feedmultiply;
     feedmultiply = 100;
     previous_millis_cmd = millis();
     
     enable_endstops(enable_endstops_now);
+    return l_feedmultiply;
 }
 
-static void clean_up_after_endstop_move() {
+//! @param original_feedmultiply feedmultiply to restore
+static void clean_up_after_endstop_move(int original_feedmultiply) {
 #ifdef ENDSTOPS_ONLY_FOR_HOMING
     enable_endstops(false);
 #endif
     
     feedrate = saved_feedrate;
-    feedmultiply = saved_feedmultiply;
+    feedmultiply = original_feedmultiply;
     previous_millis_cmd = millis();
 }
 
@@ -2250,43 +2113,43 @@ void homeaxis(int axis, uint8_t cnt, uint8_t* pstep)
 #endif //TMC2130
 
 
-        // Move right a bit, so that the print head does not touch the left end position,
-        // and the following left movement has a chance to achieve the required velocity
+        // Move away a bit, so that the print head does not touch the end position,
+        // and the following movement to endstop has a chance to achieve the required velocity
         // for the stall guard to work.
         current_position[axis] = 0;
         plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
 		set_destination_to_current();
 //        destination[axis] = 11.f;
-        destination[axis] = 3.f;
+        destination[axis] = -3.f * axis_home_dir;
         plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
         st_synchronize();
-        // Move left away from the possible collision with the collision detection disabled.
+        // Move away from the possible collision with opposite endstop with the collision detection disabled.
         endstops_hit_on_purpose();
         enable_endstops(false);
         current_position[axis] = 0;
         plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
-        destination[axis] = - 1.;
+        destination[axis] = 1. * axis_home_dir;
         plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
         st_synchronize();
         // Now continue to move up to the left end stop with the collision detection enabled.
         enable_endstops(true);
-        destination[axis] = - 1.1 * max_length(axis);
+        destination[axis] = 1.1 * axis_home_dir * max_length(axis);
         plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
         st_synchronize();
 		for (uint8_t i = 0; i < cnt; i++)
 		{
-			// Move right from the collision to a known distance from the left end stop with the collision detection disabled.
+			// Move away from the collision to a known distance from the left end stop with the collision detection disabled.
 			endstops_hit_on_purpose();
 			enable_endstops(false);
 			current_position[axis] = 0;
 			plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
-			destination[axis] = 10.f;
+			destination[axis] = -10.f * axis_home_dir;
 			plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
 			st_synchronize();
 			endstops_hit_on_purpose();
 			// Now move left up to the collision, this time with a repeatable velocity.
 			enable_endstops(true);
-			destination[axis] = - 11.f;
+			destination[axis] = 11.f * axis_home_dir;
 #ifdef TMC2130
 			feedrate = homing_feedrate[axis];
 #else //TMC2130
@@ -2310,10 +2173,10 @@ void homeaxis(int axis, uint8_t cnt, uint8_t* pstep)
 		{
 			tmc2130_goto_step(axis, orig, 2, 1000, tmc2130_get_res(axis));
 			if (back > 0)
-				tmc2130_do_steps(axis, back, 1, 1000);
+				tmc2130_do_steps(axis, back, -axis_home_dir, 1000);
 		}
 		else
-			tmc2130_do_steps(axis, 8, 2, 1000);
+			tmc2130_do_steps(axis, 8, -axis_home_dir, 1000);
 		tmc2130_home_exit();
 #endif //TMC2130
 
@@ -2321,9 +2184,9 @@ void homeaxis(int axis, uint8_t cnt, uint8_t* pstep)
         axis_known_position[axis] = true;
         // Move from minimum
 #ifdef TMC2130
-        float dist = 0.01f * tmc2130_home_fsteps[axis];
+        float dist = - axis_home_dir * 0.01f * tmc2130_home_fsteps[axis];
 #else //TMC2130
-        float dist = 0.01f * 64;
+        float dist = - axis_home_dir * 0.01f * 64;
 #endif //TMC2130
         current_position[axis] -= dist;
         plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
@@ -2602,7 +2465,7 @@ void gcode_G28(bool home_x_axis, long home_x_value, bool home_y_axis, long home_
         babystep_undo();
 
       saved_feedrate = feedrate;
-      saved_feedmultiply = feedmultiply;
+      int l_feedmultiply = feedmultiply;
       feedmultiply = 100;
       previous_millis_cmd = millis();
 
@@ -2788,7 +2651,7 @@ void gcode_G28(bool home_x_axis, long home_x_value, bool home_y_axis, long home_
       #endif
 
       feedrate = saved_feedrate;
-      feedmultiply = saved_feedmultiply;
+      feedmultiply = l_feedmultiply;
       previous_millis_cmd = millis();
       endstops_hit_on_purpose();
 #ifndef MESH_BED_LEVELING
@@ -2839,6 +2702,11 @@ void adjust_bed_reset()
 	eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_REAR, 0);
 }
 
+//! @brief Calibrate XYZ
+//! @param onlyZ if true, calibrate only Z axis
+//! @param verbosity_level
+//! @retval true Succeeded
+//! @retval false Failed
 bool gcode_M45(bool onlyZ, int8_t verbosity_level)
 {
 	bool final_result = false;
@@ -2868,7 +2736,7 @@ bool gcode_M45(bool onlyZ, int8_t verbosity_level)
 
 	// Home in the XY plane.
 	//set_destination_to_current();
-	setup_for_endstop_move();
+	int l_feedmultiply = setup_for_endstop_move();
 	lcd_display_message_fullscreen_P(_T(MSG_AUTO_HOME));
 	home_xy();
 
@@ -2926,18 +2794,9 @@ bool gcode_M45(bool onlyZ, int8_t verbosity_level)
 
 		if (st_get_position_mm(Z_AXIS) == MESH_HOME_Z_SEARCH)
 		{
-
-			int8_t verbosity_level = 0;
-			if (code_seen('V'))
-			{
-				// Just 'V' without a number counts as V1.
-				char c = strchr_pointer[1];
-				verbosity_level = (c == ' ' || c == '\t' || c == 0) ? 1 : code_value_short();
-			}
-
 			if (onlyZ)
 			{
-				clean_up_after_endstop_move();
+				clean_up_after_endstop_move(l_feedmultiply);
 				// Z only calibration.
 				// Load the machine correction matrix
 				world2machine_initialize();
@@ -2962,7 +2821,7 @@ bool gcode_M45(bool onlyZ, int8_t verbosity_level)
 				// Complete XYZ calibration.
 				uint8_t point_too_far_mask = 0;
 				BedSkewOffsetDetectionResultType result = find_bed_offset_and_skew(verbosity_level, point_too_far_mask);
-				clean_up_after_endstop_move();
+				clean_up_after_endstop_move(l_feedmultiply);
 				// Print head up.
 				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] / 40, active_extruder);
@@ -2979,10 +2838,10 @@ bool gcode_M45(bool onlyZ, int8_t verbosity_level)
 					mbl.reset();
 					world2machine_reset();
 					// Home in the XY plane.
-					setup_for_endstop_move();
+					int l_feedmultiply = setup_for_endstop_move();
 					home_xy();
 					result = improve_bed_offset_and_skew(1, verbosity_level, point_too_far_mask);
-					clean_up_after_endstop_move();
+					clean_up_after_endstop_move(l_feedmultiply);
 					// Print head up.
 					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] / 40, active_extruder);
@@ -3047,117 +2906,124 @@ void gcode_M114()
 	SERIAL_PROTOCOLLN("");
 }
 
-void gcode_M600(bool automatic, float x_position, float y_position, float z_shift, float e_shift, float e_shift_late) {
-		st_synchronize();
-		float lastpos[4];
+static void gcode_M600(bool automatic, float x_position, float y_position, float z_shift, float e_shift, float /*e_shift_late*/)
+{
+    st_synchronize();
+    float lastpos[4];
 
-		if (farm_mode)
-		{
-			prusa_statistics(22);
-		}
+    if (farm_mode)
+    {
+        prusa_statistics(22);
+    }
 
-		//First backup current position and settings
-        feedmultiplyBckp=feedmultiply;
-        HotendTempBckp = degTargetHotend(active_extruder);
-		fanSpeedBckp = fanSpeed;
+    //First backup current position and settings
+    int feedmultiplyBckp = feedmultiply;
+    float HotendTempBckp = degTargetHotend(active_extruder);
+    int fanSpeedBckp = fanSpeed;
 
-        lastpos[X_AXIS]=current_position[X_AXIS];
-        lastpos[Y_AXIS]=current_position[Y_AXIS];
-        lastpos[Z_AXIS]=current_position[Z_AXIS];
-        lastpos[E_AXIS]=current_position[E_AXIS];
+    lastpos[X_AXIS] = current_position[X_AXIS];
+    lastpos[Y_AXIS] = current_position[Y_AXIS];
+    lastpos[Z_AXIS] = current_position[Z_AXIS];
+    lastpos[E_AXIS] = current_position[E_AXIS];
 
-		//Retract E
-        current_position[E_AXIS]+= e_shift;
-        plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], FILAMENTCHANGE_RFEED, active_extruder);
-		st_synchronize();
+    //Retract E
+    current_position[E_AXIS] += e_shift;
+    plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS],
+            current_position[E_AXIS], FILAMENTCHANGE_RFEED, active_extruder);
+    st_synchronize();
 
-        //Lift Z
-        current_position[Z_AXIS]+= z_shift;
-        plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], FILAMENTCHANGE_ZFEED, active_extruder);
-		st_synchronize();
-        
-		//Move XY to side
-        current_position[X_AXIS]= x_position;
-        current_position[Y_AXIS]= y_position;
-        plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], FILAMENTCHANGE_XYFEED, active_extruder);
-		st_synchronize();
-		
-		//Beep, manage nozzle heater and wait for user to start unload filament
-		if(!mmu_enabled) M600_wait_for_user();
-		
-		lcd_change_fil_state = 0;
-		
-		// Unload filament
-		if (mmu_enabled)
-			extr_unload(); //unload just current filament for multimaterial printers (used also in M702)
-		else
-			unload_filament(); //unload filament for single material (used also in M702)
-		//finish moves
-		st_synchronize();
+    //Lift Z
+    current_position[Z_AXIS] += z_shift;
+    plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS],
+            current_position[E_AXIS], FILAMENTCHANGE_ZFEED, active_extruder);
+    st_synchronize();
 
-		if (!mmu_enabled)
-		{
-			KEEPALIVE_STATE(PAUSED_FOR_USER);
-			lcd_change_fil_state = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Was filament unload successful?"), false, true);////MSG_UNLOAD_SUCCESSFUL c=20 r=2
-			if (lcd_change_fil_state == 0) lcd_show_fullscreen_message_and_wait_P(_i("Please open idler and remove filament manually."));////MSG_CHECK_IDLER c=20 r=4
-			lcd_update_enable(true);
-		}
+    //Move XY to side
+    current_position[X_AXIS] = x_position;
+    current_position[Y_AXIS] = y_position;
+    plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS],
+            current_position[E_AXIS], FILAMENTCHANGE_XYFEED, active_extruder);
+    st_synchronize();
 
-		if (mmu_enabled)
-		{
-			if (!automatic) {
-				if (saved_printing) mmu_eject_filament(mmu_extruder, false); //if M600 was invoked by filament senzor (FINDA) eject filament so user can easily remove it
-				mmu_M600_wait_and_beep();
-				if (saved_printing) {
+    //Beep, manage nozzle heater and wait for user to start unload filament
+    if(!mmu_enabled) M600_wait_for_user(HotendTempBckp);
 
-					lcd_clear();
-					lcd_set_cursor(0, 2);
-					lcd_puts_P(_T(MSG_PLEASE_WAIT));
+    lcd_change_fil_state = 0;
 
-					mmu_command(MMU_CMD_R0);
-					manage_response(false, false);
-				}
-			}
-			mmu_M600_load_filament(automatic);
-		}
-		else
-			M600_load_filament();
+    // Unload filament
+    if (mmu_enabled) extr_unload();	//unload just current filament for multimaterial printers (used also in M702)
+    else unload_filament(); //unload filament for single material (used also in M702)
+    //finish moves
+    st_synchronize();
+
+    if (!mmu_enabled)
+    {
+        KEEPALIVE_STATE(PAUSED_FOR_USER);
+        lcd_change_fil_state = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Was filament unload successful?"),
+                false, true); ////MSG_UNLOAD_SUCCESSFUL c=20 r=2
+        if (lcd_change_fil_state == 0)
+            lcd_show_fullscreen_message_and_wait_P(_i("Please open idler and remove filament manually."));////MSG_CHECK_IDLER c=20 r=4
+        lcd_update_enable(true);
+    }
+
+    if (mmu_enabled)
+    {
+        if (!automatic) {
+            if (saved_printing) mmu_eject_filament(mmu_extruder, false); //if M600 was invoked by filament senzor (FINDA) eject filament so user can easily remove it
+            mmu_M600_wait_and_beep();
+            if (saved_printing) {
+
+                lcd_clear();
+                lcd_set_cursor(0, 2);
+                lcd_puts_P(_T(MSG_PLEASE_WAIT));
+
+                mmu_command(MMU_CMD_R0);
+                manage_response(false, false);
+            }
+        }
+        mmu_M600_load_filament(automatic);
+    }
+    else
+        M600_load_filament();
 
-		if(!automatic) M600_check_state();
+    if (!automatic) M600_check_state();
 
 		lcd_update_enable(true);
 
-      //Not let's go back to print
-	  fanSpeed = fanSpeedBckp;
+    //Not let's go back to print
+    fanSpeed = fanSpeedBckp;
 
-      //Feed a little of filament to stabilize pressure
-	  if (!automatic) {
-		  current_position[E_AXIS] += FILAMENTCHANGE_RECFEED;
-		  plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], FILAMENTCHANGE_EXFEED, active_extruder);
-	  }
-      
-      //Move XY back
-      plan_buffer_line(lastpos[X_AXIS], lastpos[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], FILAMENTCHANGE_XYFEED, active_extruder);
-      st_synchronize();
-      //Move Z back
-      plan_buffer_line(lastpos[X_AXIS], lastpos[Y_AXIS], lastpos[Z_AXIS], current_position[E_AXIS], FILAMENTCHANGE_ZFEED, active_extruder);
-      st_synchronize();  
+    //Feed a little of filament to stabilize pressure
+    if (!automatic)
+    {
+        current_position[E_AXIS] += FILAMENTCHANGE_RECFEED;
+        plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS],
+                current_position[E_AXIS], FILAMENTCHANGE_EXFEED, active_extruder);
+    }
 
-      //Set E position to original  
-      plan_set_e_position(lastpos[E_AXIS]);
+    //Move XY back
+    plan_buffer_line(lastpos[X_AXIS], lastpos[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS],
+            FILAMENTCHANGE_XYFEED, active_extruder);
+    st_synchronize();
+    //Move Z back
+    plan_buffer_line(lastpos[X_AXIS], lastpos[Y_AXIS], lastpos[Z_AXIS], current_position[E_AXIS],
+            FILAMENTCHANGE_ZFEED, active_extruder);
+    st_synchronize();
 
-	  memcpy(current_position, lastpos, sizeof(lastpos));
-	  memcpy(destination, current_position, sizeof(current_position));
-       
-      //Recover feed rate 
-      feedmultiply=feedmultiplyBckp;
-      char cmd[9];
-      sprintf_P(cmd, PSTR("M220 S%i"), feedmultiplyBckp);
-      enquecommand(cmd);
-      
-	  lcd_setstatuspgm(_T(WELCOME_MSG));
-	  custom_message_type = CUSTOM_MSG_TYPE_STATUS;
-        
+    //Set E position to original
+    plan_set_e_position(lastpos[E_AXIS]);
+
+    memcpy(current_position, lastpos, sizeof(lastpos));
+    memcpy(destination, current_position, sizeof(current_position));
+
+    //Recover feed rate
+    feedmultiply = feedmultiplyBckp;
+    char cmd[9];
+    sprintf_P(cmd, PSTR("M220 S%i"), feedmultiplyBckp);
+    enquecommand(cmd);
+
+    lcd_setstatuspgm(_T(WELCOME_MSG));
+    custom_message_type = CUSTOM_MSG_TYPE_STATUS;
 }
 
 
@@ -3289,7 +3155,136 @@ extern uint8_t st_backlash_x;
 extern uint8_t st_backlash_y;
 #endif //BACKLASH_Y
 
-
+//! @brief Parse and process commands
+//!
+//! look here for descriptions of G-codes: http://linuxcnc.org/handbook/gcode/g-code.html
+//! http://objects.reprap.org/wiki/Mendel_User_Manual:_RepRapGCodes
+//!
+//! Implemented Codes
+//! -------------------
+//!
+//!@n PRUSA CODES
+//!@n P F - Returns FW versions
+//!@n P R - Returns revision of printer
+//!
+//!@n G0  -> G1
+//!@n G1  - Coordinated Movement X Y Z E
+//!@n G2  - CW ARC
+//!@n G3  - CCW ARC
+//!@n G4  - Dwell S<seconds> or P<milliseconds>
+//!@n G10 - retract filament according to settings of M207
+//!@n G11 - retract recover filament according to settings of M208
+//!@n G28 - Home all Axis
+//!@n G29 - Detailed Z-Probe, probes the bed at 3 or more points.  Will fail if you haven't homed yet.
+//!@n G30 - Single Z Probe, probes bed at current XY location.
+//!@n G31 - Dock sled (Z_PROBE_SLED only)
+//!@n G32 - Undock sled (Z_PROBE_SLED only)
+//!@n G80 - Automatic mesh bed leveling
+//!@n G81 - Print bed profile
+//!@n G90 - Use Absolute Coordinates
+//!@n G91 - Use Relative Coordinates
+//!@n G92 - Set current position to coordinates given
+//!
+//!@n M Codes
+//!@n M0   - Unconditional stop - Wait for user to press a button on the LCD
+//!@n M1   - Same as M0
+//!@n M17  - Enable/Power all stepper motors
+//!@n M18  - Disable all stepper motors; same as M84
+//!@n M20  - List SD card
+//!@n M21  - Init SD card
+//!@n M22  - Release SD card
+//!@n M23  - Select SD file (M23 filename.g)
+//!@n M24  - Start/resume SD print
+//!@n M25  - Pause SD print
+//!@n M26  - Set SD position in bytes (M26 S12345)
+//!@n M27  - Report SD print status
+//!@n M28  - Start SD write (M28 filename.g)
+//!@n M29  - Stop SD write
+//!@n M30  - Delete file from SD (M30 filename.g)
+//!@n M31  - Output time since last M109 or SD card start to serial
+//!@n M32  - Select file and start SD print (Can be used _while_ printing from SD card files):
+//!          syntax "M32 /path/filename#", or "M32 S<startpos bytes> !filename#"
+//!          Call gcode file : "M32 P !filename#" and return to caller file after finishing (similar to #include).
+//!          The '#' is necessary when calling from within sd files, as it stops buffer prereading
+//!@n M42  - Change pin status via gcode Use M42 Px Sy to set pin x to value y, when omitting Px the onboard led will be used.
+//!@n M73  - Show percent done and print time remaining
+//!@n M80  - Turn on Power Supply
+//!@n M81  - Turn off Power Supply
+//!@n M82  - Set E codes absolute (default)
+//!@n M83  - Set E codes relative while in Absolute Coordinates (G90) mode
+//!@n M84  - Disable steppers until next move,
+//!          or use S<seconds> to specify an inactivity timeout, after which the steppers will be disabled.  S0 to disable the timeout.
+//!@n M85  - Set inactivity shutdown timer with parameter S<seconds>. To disable set zero (default)
+//!@n M86  - Set safety timer expiration time with parameter S<seconds>; M86 S0 will disable safety timer
+//!@n M92  - Set axis_steps_per_unit - same syntax as G92
+//!@n M104 - Set extruder target temp
+//!@n M105 - Read current temp
+//!@n M106 - Fan on
+//!@n M107 - Fan off
+//!@n M109 - Sxxx Wait for extruder current temp to reach target temp. Waits only when heating
+//!          Rxxx Wait for extruder current temp to reach target temp. Waits when heating and cooling
+//!        IF AUTOTEMP is enabled, S<mintemp> B<maxtemp> F<factor>. Exit autotemp by any M109 without F
+//!@n M112 - Emergency stop
+//!@n M113 - Get or set the timeout interval for Host Keepalive "busy" messages
+//!@n M114 - Output current position to serial port
+//!@n M115 - Capabilities string
+//!@n M117 - display message
+//!@n M119 - Output Endstop status to serial port
+//!@n M126 - Solenoid Air Valve Open (BariCUDA support by jmil)
+//!@n M127 - Solenoid Air Valve Closed (BariCUDA vent to atmospheric pressure by jmil)
+//!@n M128 - EtoP Open (BariCUDA EtoP = electricity to air pressure transducer by jmil)
+//!@n M129 - EtoP Closed (BariCUDA EtoP = electricity to air pressure transducer by jmil)
+//!@n M140 - Set bed target temp
+//!@n M150 - Set BlinkM Color Output R: Red<0-255> U(!): Green<0-255> B: Blue<0-255> over i2c, G for green does not work.
+//!@n M190 - Sxxx Wait for bed current temp to reach target temp. Waits only when heating
+//!          Rxxx Wait for bed current temp to reach target temp. Waits when heating and cooling
+//!@n M200 D<millimeters>- set filament diameter and set E axis units to cubic millimeters (use S0 to set back to millimeters).
+//!@n M201 - Set max acceleration in units/s^2 for print moves (M201 X1000 Y1000)
+//!@n M202 - Set max acceleration in units/s^2 for travel moves (M202 X1000 Y1000) Unused in Marlin!!
+//!@n M203 - Set maximum feedrate that your machine can sustain (M203 X200 Y200 Z300 E10000) in mm/sec
+//!@n M204 - Set default acceleration: S normal moves T filament only moves (M204 S3000 T7000) in mm/sec^2  also sets minimum segment time in ms (B20000) to prevent buffer under-runs and M20 minimum feedrate
+//!@n M205 -  advanced settings:  minimum travel speed S=while printing T=travel only,  B=minimum segment time X= maximum xy jerk, Z=maximum Z jerk, E=maximum E jerk
+//!@n M206 - set additional homing offset
+//!@n M207 - set retract length S[positive mm] F[feedrate mm/min] Z[additional zlift/hop], stays in mm regardless of M200 setting
+//!@n M208 - set recover=unretract length S[positive mm surplus to the M207 S*] F[feedrate mm/sec]
+//!@n M209 - S<1=true/0=false> enable automatic retract detect if the slicer did not support G10/11: every normal extrude-only move will be classified as retract depending on the direction.
+//!@n M218 - set hotend offset (in mm): T<extruder_number> X<offset_on_X> Y<offset_on_Y>
+//!@n M220 S<factor in percent>- set speed factor override percentage
+//!@n M221 S<factor in percent>- set extrude factor override percentage
+//!@n M226 P<pin number> S<pin state>- Wait until the specified pin reaches the state required
+//!@n M240 - Trigger a camera to take a photograph
+//!@n M250 - Set LCD contrast C<contrast value> (value 0..63)
+//!@n M280 - set servo position absolute. P: servo index, S: angle or microseconds
+//!@n M300 - Play beep sound S<frequency Hz> P<duration ms>
+//!@n M301 - Set PID parameters P I and D
+//!@n M302 - Allow cold extrudes, or set the minimum extrude S<temperature>.
+//!@n M303 - PID relay autotune S<temperature> sets the target temperature. (default target temperature = 150C)
+//!@n M304 - Set bed PID parameters P I and D
+//!@n M400 - Finish all moves
+//!@n M401 - Lower z-probe if present
+//!@n M402 - Raise z-probe if present
+//!@n M404 - N<dia in mm> Enter the nominal filament width (3mm, 1.75mm ) or will display nominal filament width without parameters
+//!@n M405 - Turn on Filament Sensor extrusion control.  Optional D<delay in cm> to set delay in centimeters between sensor and extruder
+//!@n M406 - Turn off Filament Sensor extrusion control
+//!@n M407 - Displays measured filament diameter
+//!@n M500 - stores parameters in EEPROM
+//!@n M501 - reads parameters from EEPROM (if you need reset them after you changed them temporarily).
+//!@n M502 - reverts to the default "factory settings".  You still need to store them in EEPROM afterwards if you want to.
+//!@n M503 - print the current settings (from memory not from EEPROM)
+//!@n M509 - force language selection on next restart
+//!@n M540 - Use S[0|1] to enable or disable the stop SD card print on endstop hit (requires ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED)
+//!@n M600 - Pause for filament change X[pos] Y[pos] Z[relative lift] E[initial retract] L[later retract distance for removal]
+//!@n M605 - Set dual x-carriage movement mode: S<mode> [ X<duplication x-offset> R<duplication temp offset> ]
+//!@n M860 - Wait for PINDA thermistor to reach target temperature.
+//!@n M861 - Set / Read PINDA temperature compensation offsets
+//!@n M900 - Set LIN_ADVANCE options, if enabled. See Configuration_adv.h for details.
+//!@n M907 - Set digital trimpot motor current using axis codes.
+//!@n M908 - Control digital trimpot directly.
+//!@n M350 - Set microstepping mode.
+//!@n M351 - Toggle MS1 MS2 pins directly.
+//!
+//!@n M928 - Start SD logging (M928 filename.g) - ended by M29
+//!@n M999 - Restart after being stopped by error
 void process_commands()
 {
 	if (!buflen) return; //empty command
@@ -3331,21 +3326,21 @@ void process_commands()
 #ifdef TMC2130
 	else if (strncmp_P(CMDBUFFER_CURRENT_STRING, PSTR("CRASH_"), 6) == 0)
 	{
-	  if(code_seen("CRASH_DETECTED"))
+	  if(code_seen("CRASH_DETECTED")) //! CRASH_DETECTED
 	  {
 		  uint8_t mask = 0;
 		  if (code_seen('X')) mask |= X_AXIS_MASK;
 		  if (code_seen('Y')) mask |= Y_AXIS_MASK;
 		  crashdet_detected(mask);
 	  }
-	  else if(code_seen("CRASH_RECOVER"))
+	  else if(code_seen("CRASH_RECOVER")) //! CRASH_RECOVER
 		  crashdet_recover();
-	  else if(code_seen("CRASH_CANCEL"))
+	  else if(code_seen("CRASH_CANCEL")) //! CRASH_CANCEL
 		  crashdet_cancel();
 	}
 	else if (strncmp_P(CMDBUFFER_CURRENT_STRING, PSTR("TMC_"), 4) == 0)
 	{
-		if (strncmp_P(CMDBUFFER_CURRENT_STRING + 4, PSTR("SET_WAVE_"), 9) == 0)
+		if (strncmp_P(CMDBUFFER_CURRENT_STRING + 4, PSTR("SET_WAVE_"), 9) == 0) //! TMC_SET_WAVE_
 		{
 			uint8_t axis = *(CMDBUFFER_CURRENT_STRING + 13);
 			axis = (axis == 'E')?3:(axis - 'X');
@@ -3355,7 +3350,7 @@ void process_commands()
 				tmc2130_set_wave(axis, 247, fac);
 			}
 		}
-		else if (strncmp_P(CMDBUFFER_CURRENT_STRING + 4, PSTR("SET_STEP_"), 9) == 0)
+		else if (strncmp_P(CMDBUFFER_CURRENT_STRING + 4, PSTR("SET_STEP_"), 9) == 0) //! TMC_SET_STEP_
 		{
 			uint8_t axis = *(CMDBUFFER_CURRENT_STRING + 13);
 			axis = (axis == 'E')?3:(axis - 'X');
@@ -3366,7 +3361,7 @@ void process_commands()
 				tmc2130_goto_step(axis, step & (4*res - 1), 2, 1000, res);
 			}
 		}
-		else if (strncmp_P(CMDBUFFER_CURRENT_STRING + 4, PSTR("SET_CHOP_"), 9) == 0)
+		else if (strncmp_P(CMDBUFFER_CURRENT_STRING + 4, PSTR("SET_CHOP_"), 9) == 0) //! TMC_SET_CHOP_
 		{
 			uint8_t axis = *(CMDBUFFER_CURRENT_STRING + 13);
 			axis = (axis == 'E')?3:(axis - 'X');
@@ -3417,22 +3412,22 @@ void process_commands()
 	}
 #endif //BACKLASH_Y
 #endif //TMC2130
-	else if (code_seen("FSENSOR_RECOVER")) {
+	else if (code_seen("FSENSOR_RECOVER")) { //! FSENSOR_RECOVER
 		fsensor_restore_print_and_continue();
   }
   else if(code_seen("PRUSA")){
-		if (code_seen("Ping")) {  //PRUSA Ping
+		if (code_seen("Ping")) {  //! PRUSA Ping
 			if (farm_mode) {
 				PingTime = millis();
 				//MYSERIAL.print(farm_no); MYSERIAL.println(": OK");
 			}	  
 		}
-		else if (code_seen("PRN")) {
+		else if (code_seen("PRN")) { //! PRUSA PRN
 		  printf_P(_N("%d"), status_number);
 
-        }else if (code_seen("FAN")) {
+        }else if (code_seen("FAN")) { //! PRUSA FAN
 			printf_P(_N("E0:%d RPM\nPRN0:%d RPM\n"), 60*fan_speed[0], 60*fan_speed[1]);
-		}else if (code_seen("fn")) {
+		}else if (code_seen("fn")) { //! PRUSA fn
 		  if (farm_mode) {
 			printf_P(_N("%d"), farm_no);
 		  }
@@ -3441,20 +3436,20 @@ void process_commands()
 		  }
 		  
 		}
-		else if (code_seen("thx"))
+		else if (code_seen("thx")) //! PRUSA thx
 		{
 			no_response = false;
 		}	
-		else if (code_seen("uvlo"))
+		else if (code_seen("uvlo")) //! PRUSA uvlo
 		{
                eeprom_update_byte((uint8_t*)EEPROM_UVLO,0); 
                enquecommand_P(PSTR("M24")); 
 		}	
-		else if (code_seen("MMURES"))
+		else if (code_seen("MMURES")) //! PRUSA MMURES
 		{
 			mmu_reset();
 		}
-		else if (code_seen("RESET")) {
+		else if (code_seen("RESET")) { //! PRUSA RESET
             // careful!
             if (farm_mode) {
 #ifdef WATCHDOG
@@ -3470,7 +3465,7 @@ void process_commands()
             else {
                 MYSERIAL.println("Not in farm mode.");
             }
-		}else if (code_seen("fv")) {
+		}else if (code_seen("fv")) { //! PRUSA fv
         // get file version
         #ifdef SDSUPPORT
         card.openFile(strchr_pointer + 3,true);
@@ -3485,35 +3480,35 @@ void process_commands()
 
         #endif // SDSUPPORT
 
-    } else if (code_seen("M28")) {
+    } else if (code_seen("M28")) { //! PRUSA M28
         trace();
         prusa_sd_card_upload = true;
         card.openFile(strchr_pointer+4,false);
 
-	} else if (code_seen("SN")) { 
+	} else if (code_seen("SN")) { //! PRUSA SN
         gcode_PRUSA_SN();
 
-	} else if(code_seen("Fir")){
+	} else if(code_seen("Fir")){ //! PRUSA Fir
 
       SERIAL_PROTOCOLLN(FW_VERSION_FULL);
 
-    } else if(code_seen("Rev")){
+    } else if(code_seen("Rev")){ //! PRUSA Rev
 
       SERIAL_PROTOCOLLN(FILAMENT_SIZE "-" ELECTRONICS "-" NOZZLE_TYPE );
 
-    } else if(code_seen("Lang")) {
+    } else if(code_seen("Lang")) { //! PRUSA Lang
 	  lang_reset();
 
-	} else if(code_seen("Lz")) {
+	} else if(code_seen("Lz")) { //! PRUSA Lz
       EEPROM_save_B(EEPROM_BABYSTEP_Z,0);
 
-	} else if(code_seen("Beat")) {
+	} else if(code_seen("Beat")) { //! PRUSA Beat
         // Kick farm link timer
         kicktime = millis();
 
-    } else if(code_seen("FR")) {
+    } else if(code_seen("FR")) { //! PRUSA FR
         // Factory full reset
-        factory_reset(0,true);        
+        factory_reset(0);
     }
     //else if (code_seen('Cal')) {
 		//  lcd_calibration();
@@ -3536,7 +3531,7 @@ void process_commands()
             
             if(READ(FR_SENS)){
 
-                        feedmultiplyBckp=feedmultiply;
+                        int feedmultiplyBckp=feedmultiply;
                         float target[4];
                         float lastpos[4];
                         target[X_AXIS]=current_position[X_AXIS];
@@ -3818,7 +3813,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
             current_position[Y_AXIS] = uncorrected_position.y;
             current_position[Z_AXIS] = uncorrected_position.z;
             plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
-            setup_for_endstop_move();
+            int l_feedmultiply = setup_for_endstop_move();
 
             feedrate = homing_feedrate[Z_AXIS];
 #ifdef AUTO_BED_LEVELING_GRID
@@ -3884,7 +3879,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
                 xProbe += xInc;
               }
             }
-            clean_up_after_endstop_move();
+            clean_up_after_endstop_move(l_feedmultiply);
 
             // solve lsq problem
             double *plane_equation_coefficients = qr_solve(AUTO_BED_LEVELING_GRID_POINTS*AUTO_BED_LEVELING_GRID_POINTS, 3, eqnAMatrix, eqnBVector);
@@ -3913,7 +3908,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
             // probe 3
             float z_at_pt_3 = probe_pt(ABL_PROBE_PT_3_X, ABL_PROBE_PT_3_Y, current_position[Z_AXIS] + Z_RAISE_BETWEEN_PROBINGS);
 
-            clean_up_after_endstop_move();
+            clean_up_after_endstop_move(l_feedmultiply);
 
             set_bed_level_equation_3pts(z_at_pt_1, z_at_pt_2, z_at_pt_3);
 
@@ -3939,7 +3934,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
         {
             st_synchronize();
             // TODO: make sure the bed_level_rotation_matrix is identity or the planner will get set incorectly
-            setup_for_endstop_move();
+            int l_feedmultiply = setup_for_endstop_move();
 
             feedrate = homing_feedrate[Z_AXIS];
 
@@ -3953,7 +3948,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
             SERIAL_PROTOCOL(current_position[Z_AXIS]);
             SERIAL_PROTOCOLPGM("\n");
 
-            clean_up_after_endstop_move();
+            clean_up_after_endstop_move(l_feedmultiply);
         }
         break;
 #else
@@ -3971,7 +3966,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
         {
             st_synchronize();
             // TODO: make sure the bed_level_rotation_matrix is identity or the planner will get set incorectly
-            setup_for_endstop_move();
+            int l_feedmultiply = setup_for_endstop_move();
 
             feedrate = homing_feedrate[Z_AXIS];
 
@@ -3979,7 +3974,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 
 			printf_P(_N("%S X: %.5f Y: %.5f Z: %.5f\n"), _T(MSG_BED), _x, _y, _z);
 
-            clean_up_after_endstop_move();
+            clean_up_after_endstop_move(l_feedmultiply);
         }
         break;
 	
@@ -3991,7 +3986,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 	}
 	break;
 
-	case 76: //PINDA probe temperature calibration
+	case 76: //! G76 - PINDA probe temperature calibration
 	{
 #ifdef PINDA_THERMISTOR
 		if (true)
@@ -4250,12 +4245,9 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 #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 
+		//! 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;
@@ -4294,12 +4286,12 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 	*      mesh to compensate for variable bed height
 	*
 	* The S0 report the points as below
-	*
+	* @code{.unparsed}
 	*  +----> X-axis
 	*  |
 	*  |
 	*  v Y-axis
-	*
+	* @endcode
 	*/
 
 	case 80:
@@ -4404,7 +4396,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 			has_z ? SERIAL_PROTOCOLPGM("Z jitter data from Z cal. valid.\n") : SERIAL_PROTOCOLPGM("Z jitter data from Z cal. not valid.\n");
 		}
 		#endif // SUPPORT_VERBOSITY
-		setup_for_endstop_move(false); //save feedrate and feedmultiply, sets feedmultiply to 100
+		int l_feedmultiply = setup_for_endstop_move(false); //save feedrate and feedmultiply, sets feedmultiply to 100
 		const char *kill_message = NULL;
 		while (mesh_point != MESH_MEAS_NUM_X_POINTS * MESH_MEAS_NUM_Y_POINTS) {
 			// Get coords of a measuring point.
@@ -4511,7 +4503,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 			kill(kill_message);
 			SERIAL_ECHOLNPGM("killed");
 		}
-		clean_up_after_endstop_move();
+		clean_up_after_endstop_move(l_feedmultiply);
 //		SERIAL_ECHOLNPGM("clean up finished ");
 
 		bool apply_temp_comp = true;
@@ -4635,9 +4627,9 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
          */
         case 82:
             SERIAL_PROTOCOLLNPGM("Finding bed ");
-            setup_for_endstop_move();
+            int l_feedmultiply = setup_for_endstop_move();
             find_bed_induction_sensor_point_z();
-            clean_up_after_endstop_move();
+            clean_up_after_endstop_move(l_feedmultiply);
             SERIAL_PROTOCOLPGM("Bed found at: ");
             SERIAL_PROTOCOL_F(current_position[Z_AXIS], 5);
             SERIAL_PROTOCOLPGM("\n");
@@ -4732,7 +4724,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
       }
       break;
 
-	case 98: // G98 (activate farm mode)
+	case 98: //! G98 (activate farm mode)
 		farm_mode = 1;
 		PingTime = millis();
 		eeprom_update_byte((unsigned char *)EEPROM_FARM_MODE, farm_mode);
@@ -4741,7 +4733,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
           eeprom_update_byte((unsigned char *)EEPROM_SILENT, SilentModeMenu);
 		break;
 
-	case 99: // G99 (deactivate farm mode)
+	case 99: //! G99 (deactivate farm mode)
 		farm_mode = 0;
 		lcd_printer_connected();
 		eeprom_update_byte((unsigned char *)EEPROM_FARM_MODE, farm_mode);
@@ -4987,7 +4979,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
         }
       }
      break;
-    case 44: // M44: Prusa3D: Reset the bed skew and offset calibration.
+    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);
@@ -5001,7 +4993,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
         world2machine_revert_to_uncorrected();
         break;
 
-    case 45: // M45: Prusa3D: bed skew and offset with manual Z up
+    case 45: //! M45: Prusa3D: bed skew and offset with manual Z up
     {
 		int8_t verbosity_level = 0;
 		bool only_Z = code_seen('Z');
@@ -5041,14 +5033,14 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
     */
 
     case 47:
-        // M47: Prusa3D: Show end stops dialog on the display.
+        //! M47: Prusa3D: Show end stops dialog on the display.
 		KEEPALIVE_STATE(PAUSED_FOR_USER);
         lcd_diag_show_end_stops();
 		KEEPALIVE_STATE(IN_HANDLER);
         break;
 
 #if 0
-    case 48: // M48: scan the bed induction sensor points, print the sensor trigger coordinates to the serial line for visualization on the PC.
+    case 48: //! M48: scan the bed induction sensor points, print the sensor trigger coordinates to the serial line for visualization on the PC.
     {
         // Disable the default update procedure of the display. We will do a modal dialog.
         lcd_update_enable(false);
@@ -5064,7 +5056,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
         st_synchronize();
         // Home in the XY plane.
         set_destination_to_current();
-        setup_for_endstop_move();
+        int l_feedmultiply = setup_for_endstop_move();
         home_xy();
         int8_t verbosity_level = 0;
         if (code_seen('V')) {
@@ -5073,7 +5065,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
             verbosity_level = (c == ' ' || c == '\t' || c == 0) ? 1 : code_value_short();
         }
         bool success = scan_bed_induction_points(verbosity_level);
-        clean_up_after_endstop_move();
+        clean_up_after_endstop_move(l_feedmultiply);
         // Print head up.
         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]/40, active_extruder);
@@ -5083,23 +5075,22 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
     }
 #endif
 
-// M48 Z-Probe repeatability measurement function.
-//
-// Usage:   M48 <n #_samples> <X X_position_for_samples> <Y Y_position_for_samples> <V Verbose_Level> <L legs_of_movement_prior_to_doing_probe>
-//	
-// This function assumes the bed has been homed.  Specificaly, that a G28 command
-// as been issued prior to invoking the M48 Z-Probe repeatability measurement function.
-// Any information generated by a prior G29 Bed leveling command will be lost and need to be
-// regenerated.
-//
-// The number of samples will default to 10 if not specified.  You can use upper or lower case
-// letters for any of the options EXCEPT n.  n must be in lower case because Marlin uses a capital
-// N for its communication protocol and will get horribly confused if you send it a capital N.
-//
 
 #ifdef ENABLE_AUTO_BED_LEVELING
 #ifdef Z_PROBE_REPEATABILITY_TEST 
-
+    //! M48 Z-Probe repeatability measurement function.
+    //!
+    //! Usage:   M48 <n #_samples> <X X_position_for_samples> <Y Y_position_for_samples> <V Verbose_Level> <L legs_of_movement_prior_to_doing_probe>
+    //!
+    //! This function assumes the bed has been homed.  Specificaly, that a G28 command
+    //! as been issued prior to invoking the M48 Z-Probe repeatability measurement function.
+    //! Any information generated by a prior G29 Bed leveling command will be lost and need to be
+    //! regenerated.
+    //!
+    //! The number of samples will default to 10 if not specified.  You can use upper or lower case
+    //! letters for any of the options EXCEPT n.  n must be in lower case because Marlin uses a capital
+    //! N for its communication protocol and will get horribly confused if you send it a capital N.
+    //!
     case 48: // M48 Z-Probe repeatability
         {
             #if Z_MIN_PIN == -1
@@ -5203,7 +5194,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 // Then retrace the right amount and use that in subsequent probes
 //
 
-	setup_for_endstop_move();
+	int l_feedmultiply = setup_for_endstop_move();
 	run_z_probe();
 
 	current_position[Z_AXIS] = Z_current = st_get_position_mm(Z_AXIS);
@@ -5267,7 +5258,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 			do_blocking_move_to( X_probe_location, Y_probe_location, Z_start_location); // Go back to the probe location
 		}
 
-		setup_for_endstop_move();
+		int l_feedmultiply = setup_for_endstop_move();
                 run_z_probe();
 
 		sample_set[n] = current_position[Z_AXIS];
@@ -5318,9 +5309,9 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 
 	delay(1000);
 
-        clean_up_after_endstop_move();
+    clean_up_after_endstop_move(l_feedmultiply);
 
-//      enable_endstops(true);
+//  enable_endstops(true);
 
 	if (verbose_level > 0) {
 		SERIAL_PROTOCOLPGM("Mean: ");
@@ -5565,7 +5556,7 @@ Sigma_Exit:
         break;
 
     #if defined(FAN_PIN) && FAN_PIN > -1
-      case 106: //M106 Fan On
+      case 106: //!M106 Sxxx Fan On S<speed> 0 .. 255
         if (code_seen('S')){
            fanSpeed=constrain(code_value(),0,255);
         }
@@ -5694,7 +5685,7 @@ Sigma_Exit:
         }
       }
       break;
-    case 110:   // M110 - reset line pos
+    case 110:   //! M110 N<line number> - reset line pos
       if (code_seen('N'))
 	    gcode_LastN = code_value_long();
     break;
@@ -5741,10 +5732,10 @@ Sigma_Exit:
     case 114: // M114
 		gcode_M114();
       break;
-    case 120: // M120
+    case 120: //! M120 - Disable endstops
       enable_endstops(false) ;
       break;
-    case 121: // M121
+    case 121: //! M121 - Enable endstops
       enable_endstops(true) ;
       break;
     case 119: // M119
@@ -5915,9 +5906,9 @@ Sigma_Exit:
 		}
 		break;
     case 204:
-      // M204 acclereration settings.
-      // Supporting old format: M204 S[normal moves] T[filmanent only moves]
-      // and new format:        M204 P[printing moves] R[filmanent only moves] T[travel moves] (as of now T is ignored)
+      //! M204 acclereration settings.
+      //!@n Supporting old format: M204 S[normal moves] T[filmanent only moves]
+      //!@n and new format:        M204 P[printing moves] R[filmanent only moves] T[travel moves] (as of now T is ignored)
       {
         if(code_seen('S')) {
           // Legacy acceleration format. This format is used by the legacy Marlin, MK2 or MK3 firmware,
@@ -6301,15 +6292,15 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
     }
     break;
 
-	case 403: //M403 set filament type (material) for particular extruder and send this information to mmu
+	case 403: //! M403 set filament type (material) for particular extruder and send this information to mmu
 	{
-		//currently three different materials are needed (default, flex and PVA) 
-		//add storing this information for different load/unload profiles etc. in the future
-		//firmware does not wait for "ok" from mmu
+		//! currently three different materials are needed (default, flex and PVA)
+		//! add storing this information for different load/unload profiles etc. in the future
+		//!firmware does not wait for "ok" from mmu
 		if (mmu_enabled)
 		{
-			uint8_t extruder;
-			uint8_t filament;
+			uint8_t extruder = 255;
+			uint8_t filament = FILAMENT_UNDEFINED;
 			if(code_seen('E')) extruder = code_value();
 			if(code_seen('F')) filament = code_value();
 			mmu_set_filament_type(extruder, filament);
@@ -6466,13 +6457,14 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 	}
     break;
     #endif //FILAMENTCHANGEENABLE
-	case 601: {
-		if(lcd_commands_type == 0)  lcd_commands_type = LCD_COMMAND_LONG_PAUSE;
+	case 601: //! M601 - Pause print
+	{
+		lcd_pause_print();
 	}
 	break;
 
-	case 602: {
-		if(lcd_commands_type == 0)	lcd_commands_type = LCD_COMMAND_LONG_PAUSE_RESUME;
+	case 602: { //! M602 - Resume print
+		lcd_resume_print();
 	}
 	break;
 
@@ -6564,8 +6556,8 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 		else if (code_seen('S')) { // Sxxx Iyyy - Set compensation ustep value S for compensation table index I
 			int16_t usteps = code_value();
 			if (code_seen('I')) {
-				byte index = code_value();
-				if ((index >= 0) && (index < 5)) {
+			    uint8_t index = code_value();
+				if (index < 5) {
 					EEPROM_save_B(EEPROM_PROBE_TEMP_SHIFT + index * 2, &usteps);
 					SERIAL_PROTOCOLLN("OK");
 					SERIAL_PROTOCOLLN("index, temp, ustep, um");
@@ -6630,13 +6622,13 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 
 #ifdef TMC2130
 
-	case 910: // M910 TMC2130 init
+	case 910: //! M910 - TMC2130 init
     {
 		tmc2130_init();
     }
     break;
 
-	case 911: // M911 Set TMC2130 holding currents
+	case 911: //! M911 - Set TMC2130 holding currents
     {
 		if (code_seen('X')) tmc2130_set_current_h(0, code_value());
 		if (code_seen('Y')) tmc2130_set_current_h(1, code_value());
@@ -6645,7 +6637,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
     }
     break;
 
-	case 912: // M912 Set TMC2130 running currents
+	case 912: //! M912 - Set TMC2130 running currents
     {
 		if (code_seen('X')) tmc2130_set_current_r(0, code_value());
 		if (code_seen('Y')) tmc2130_set_current_r(1, code_value());
@@ -6654,13 +6646,13 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
     }
     break;
 
-	case 913: // M913 Print TMC2130 currents
+	case 913: //! M913 - Print TMC2130 currents
     {
 		tmc2130_print_currents();
     }
     break;
 
-	case 914: // M914 Set normal mode
+	case 914: //! M914 - Set normal mode
     {
 		tmc2130_mode = TMC2130_MODE_NORMAL;
 		update_mode_profile();
@@ -6668,7 +6660,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
     }
     break;
 
-	case 915: // M915 Set silent mode
+	case 915: //! M915 - Set silent mode
     {
 		tmc2130_mode = TMC2130_MODE_SILENT;
 		update_mode_profile();
@@ -6676,7 +6668,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
     }
     break;
 
-	case 916: // M916 Set sg_thrs
+	case 916: //! M916 - Set sg_thrs
     {
 		if (code_seen('X')) tmc2130_sg_thr[X_AXIS] = code_value();
 		if (code_seen('Y')) tmc2130_sg_thr[Y_AXIS] = code_value();
@@ -6687,7 +6679,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
     }
     break;
 
-	case 917: // M917 Set TMC2130 pwm_ampl
+	case 917: //! M917 - Set TMC2130 pwm_ampl
     {
 		if (code_seen('X')) tmc2130_set_pwm_ampl(0, code_value());
 		if (code_seen('Y')) tmc2130_set_pwm_ampl(1, code_value());
@@ -6696,7 +6688,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
     }
     break;
 
-	case 918: // M918 Set TMC2130 pwm_grad
+	case 918: //! M918 - Set TMC2130 pwm_grad
     {
 		if (code_seen('X')) tmc2130_set_pwm_grad(0, code_value());
 		if (code_seen('Y')) tmc2130_set_pwm_grad(1, code_value());
@@ -6707,7 +6699,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 
 #endif //TMC2130
 
-    case 350: // M350 Set microstepping mode. Warning: Steps per unit remains unchanged. S code sets stepping mode for all drivers.
+    case 350: //! M350 - Set microstepping mode. Warning: Steps per unit remains unchanged. S code sets stepping mode for all drivers.
     {
 	#ifdef TMC2130
 		if(code_seen('E'))
@@ -6743,7 +6735,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 	#endif //TMC2130
     }
     break;
-    case 351: // M351 Toggle MS1 MS2 pins directly, S# determines MS1 or MS2, X# sets the pin high/low.
+    case 351: //! M351 - Toggle MS1 MS2 pins directly, S# determines MS1 or MS2, X# sets the pin high/low.
     {
       #if defined(X_MS1_PIN) && X_MS1_PIN > -1
       if(code_seen('S')) switch((int)code_value())
@@ -6761,23 +6753,23 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
       #endif
     }
     break;
-	case 701: //M701: load filament
+	case 701: //! M701 - load filament
 	{
 		if (mmu_enabled && code_seen('E'))
 			tmp_extruder = code_value();
 		gcode_M701();
 	}
 	break;
-	case 702:
+	case 702: //! M702 [U C] -
 	{
 		if (mmu_enabled)
 		{
 			if (code_seen('U'))
-				extr_unload_used(); //unload all filaments which were used in current print
+				extr_unload_used(); //! if "U" unload all filaments which were used in current print
 			else if (code_seen('C'))
-				extr_unload(); //unload just current filament 
+				extr_unload(); //! if "C" unload just current filament
 			else
-				extr_unload_all(); //unload all filaments
+				extr_unload_all(); //! otherwise unload all filaments
 		}
 		else
 			unload_filament();
@@ -6797,7 +6789,13 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 	mcode_in_progress = 0;
 	}
   } // end if(code_seen('M')) (end of M codes)
-
+  //! T<extruder nr.> - select extruder in case of multi extruder printer
+  //! select filament in case of MMU_V2
+  //! if extruder is "?", open menu to let the user select extruder/filament
+  //!
+  //!  For MMU_V2:
+  //! @n T<n> Gcode to extrude must follow immediately to load to extruder wheels
+  //! @n T? Gcode to extrude doesn't have to follow, load to extruder wheels is done automatically
   else if(code_seen('T'))
   {
       int index;
@@ -6808,8 +6806,15 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
           SERIAL_ECHOLNPGM("Invalid T code.");
       }
       else {
-          if (*(strchr_pointer + index) == '?') {
-              tmp_extruder = choose_extruder_menu();
+          if (*(strchr_pointer + index) == '?')
+          {
+              if(mmu_enabled)
+              {
+                  tmp_extruder = choose_menu_P(_T(MSG_CHOOSE_FILAMENT), _T(MSG_FILAMENT));
+              } else
+              {
+                  tmp_extruder = choose_menu_P(_T(MSG_CHOOSE_EXTRUDER), _T(MSG_EXTRUDER));
+              }
           }
           else {
               tmp_extruder = code_value();
@@ -6933,45 +6938,45 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
     switch((int)code_value())
     {
 #ifdef DEBUG_DCODES
-	case -1: // D-1 - Endless loop
+	case -1: //! D-1 - Endless loop
 		dcode__1(); break;
-	case 0: // D0 - Reset
+	case 0: //! D0 - Reset
 		dcode_0(); break;
-	case 1: // D1 - Clear EEPROM
+	case 1: //! D1 - Clear EEPROM
 		dcode_1(); break;
-	case 2: // D2 - Read/Write RAM
+	case 2: //! D2 - Read/Write RAM
 		dcode_2(); break;
 #endif //DEBUG_DCODES
 #ifdef DEBUG_DCODE3
-	case 3: // D3 - Read/Write EEPROM
+	case 3: //! D3 - Read/Write EEPROM
 		dcode_3(); break;
 #endif //DEBUG_DCODE3
 #ifdef DEBUG_DCODES
-	case 4: // D4 - Read/Write PIN
+	case 4: //! D4 - Read/Write PIN
 		dcode_4(); break;
-	case 5: // D5 - Read/Write FLASH
+	case 5: //! D5 - Read/Write FLASH
 //		dcode_5(); break;
 		break;
-	case 6: // D6 - Read/Write external FLASH
+	case 6: //! D6 - Read/Write external FLASH
 		dcode_6(); break;
-	case 7: // D7 - Read/Write Bootloader
+	case 7: //! D7 - Read/Write Bootloader
 		dcode_7(); break;
-	case 8: // D8 - Read/Write PINDA
+	case 8: //! D8 - Read/Write PINDA
 		dcode_8(); break;
-	case 9: // D9 - Read/Write ADC
+	case 9: //! D9 - Read/Write ADC
 		dcode_9(); break;
 
-	case 10: // D10 - XYZ calibration = OK
+	case 10: //! D10 - XYZ calibration = OK
 		dcode_10(); break;
     
 
 #ifdef TMC2130
-	case 2130: // D9125 - TMC2130
+	case 2130: //! D2130 - TMC2130
 		dcode_2130(); break;
 #endif //TMC2130
 
 #ifdef FILAMENT_SENSOR
-	case 9125: // D9125 - FILAMENT_SENSOR
+	case 9125: //! D9125 - FILAMENT_SENSOR
 		dcode_9125(); break;
 #endif //FILAMENT_SENSOR
 
@@ -7843,7 +7848,7 @@ void bed_analysis(float x_dimension, float y_dimension, int x_points_num, int y_
 	int XY_AXIS_FEEDRATE = homing_feedrate[X_AXIS] / 20;
 	int Z_LIFT_FEEDRATE = homing_feedrate[Z_AXIS] / 40;
 
-	setup_for_endstop_move(false);
+	int l_feedmultiply = setup_for_endstop_move(false);
 
 	SERIAL_PROTOCOLPGM("Num X,Y: ");
 	SERIAL_PROTOCOL(x_points_num);
@@ -7972,7 +7977,7 @@ void bed_analysis(float x_dimension, float y_dimension, int x_points_num, int y_
 
 	}
 	card.closefile();
-
+	clean_up_after_endstop_move(l_feedmultiply);
 }
 #endif
 
@@ -8106,18 +8111,7 @@ void long_pause() //long pause print
 {
 	st_synchronize();
 	
-	//save currently set parameters to global variables
-	saved_feedmultiply = feedmultiply; 
-	HotendTempBckp = degTargetHotend(active_extruder);
-	fanSpeedBckp = fanSpeed;
 	start_pause_print = millis();
-		
-
-	//save position
-	pause_lastpos[X_AXIS] = current_position[X_AXIS];
-	pause_lastpos[Y_AXIS] = current_position[Y_AXIS];
-	pause_lastpos[Z_AXIS] = current_position[Z_AXIS];
-	pause_lastpos[E_AXIS] = current_position[E_AXIS];
 
 	//retract
 	current_position[E_AXIS] -= default_retraction;
@@ -8128,9 +8122,6 @@ void long_pause() //long pause print
 	if (current_position[Z_AXIS] > Z_MAX_POS) current_position[Z_AXIS] = Z_MAX_POS;
 	plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 15, active_extruder);
 
-	//set nozzle target temperature to 0
-	setAllTargetHotends(0);
-
 	//Move XY to side
 	current_position[X_AXIS] = X_PAUSE_POS;
 	current_position[Y_AXIS] = Y_PAUSE_POS;
@@ -8593,9 +8584,14 @@ void restore_print_from_eeprom() {
 #endif //UVLO_SUPPORT
 
 
-////////////////////////////////////////////////////////////////////////////////
-// save/restore printing
-
+//! @brief Immediately stop print moves
+//!
+//! Immediately stop print moves, save current extruder temperature and position to RAM.
+//! If printing from sd card, position in file is saved.
+//! If printing from USB, line number is saved.
+//!
+//! @param z_move
+//! @param e_move
 void stop_and_save_print_to_ram(float z_move, float e_move)
 {
 	if (saved_printing) return;
@@ -8731,9 +8727,11 @@ void stop_and_save_print_to_ram(float z_move, float e_move)
 	planner_abort_hard(); //abort printing
 	memcpy(saved_pos, current_position, sizeof(saved_pos));
 	saved_active_extruder = active_extruder; //save active_extruder
+	saved_extruder_temperature = degTargetHotend(active_extruder);
 
 	saved_extruder_under_pressure = extruder_under_pressure; //extruder under pressure flag - currently unused
 	saved_extruder_relative_mode = axis_relative_modes[E_AXIS];
+	saved_fanSpeed = fanSpeed;
 	cmdqueue_reset(); //empty cmdqueue
 	card.sdprinting = false;
 //	card.closefile();
@@ -8778,14 +8776,27 @@ void stop_and_save_print_to_ram(float z_move, float e_move)
   }
 }
 
+//! @brief Restore print from ram
+//!
+//! Restore print saved by stop_and_save_print_to_ram(). Is blocking,
+//! waits for extruder temperature restore, then restores position and continues
+//! print moves.
+//! Internaly lcd_update() is called by wait_for_heater().
+//!
+//! @param e_move
 void restore_print_from_ram_and_continue(float e_move)
 {
 	if (!saved_printing) return;
 //	for (int axis = X_AXIS; axis <= E_AXIS; axis++)
 //	    current_position[axis] = st_get_position_mm(axis);
 	active_extruder = saved_active_extruder; //restore active_extruder
+	setTargetHotendSafe(saved_extruder_temperature,saved_active_extruder);
+	heating_status = 1;
+	wait_for_heater(millis(),saved_active_extruder);
+	heating_status = 2;
 	feedrate = saved_feedrate2; //restore feedrate
 	axis_relative_modes[E_AXIS] = saved_extruder_relative_mode;
+	fanSpeed = saved_fanSpeed;
 	float e = saved_pos[E_AXIS] - e_move;
 	plan_set_e_position(e);
 	//first move print head in XY to the saved position:
@@ -8881,7 +8892,6 @@ static void print_time_remaining_init()
 	print_percent_done_silent = PRINT_PERCENT_DONE_INIT;
 }
 
-
 void M600_check_state()
 {
 		//Wait for user to check the state
@@ -8915,8 +8925,13 @@ void M600_check_state()
 		}
 }
 
-void M600_wait_for_user() {
-		//Beep, manage nozzle heater and wait for user to start unload filament
+//! @brief Wait for user action
+//!
+//! Beep, manage nozzle heater and wait for user to start unload filament
+//! If times out, active extruder temperature is set to 0.
+//!
+//! @param HotendTempBckp Temperature to be restored for active extruder, after user resolves MMU problem.
+void M600_wait_for_user(float HotendTempBckp) {
 
 		KEEPALIVE_STATE(PAUSED_FOR_USER);
 
@@ -8956,9 +8971,7 @@ void M600_wait_for_user() {
 				if (millis() > waiting_start_time + (unsigned long)M600_TIMEOUT * 1000) {
 					lcd_display_message_fullscreen_P(_i("Press knob to preheat nozzle and continue."));////MSG_PRESS_TO_PREHEAT c=20 r=4
 					wait_for_user_state = 1;
-					setTargetHotend(0, 0);
-					setTargetHotend(0, 1);
-					setTargetHotend(0, 2);
+					setAllTargetHotends(0);
 					st_synchronize();
 					disable_e0();
 					disable_e1();

+ 80 - 100
Firmware/cardreader.cpp

@@ -288,6 +288,76 @@ void CardReader::getAbsFilename(char *t)
   else
     t[0]=0;
 }
+/**
+ * @brief Dive into subfolder
+ *
+ * Method sets curDir to point to root, in case fileName is null.
+ * Method sets curDir to point to workDir, in case fileName path is relative
+ * (doesn't start with '/')
+ * Method sets curDir to point to dir, which is specified by absolute path
+ * specified by fileName. In such case fileName is updated so it points to
+ * file name without the path.
+ *
+ * @param[in,out] fileName
+ *  expects file name including path
+ *  in case of absolute path, file name without path is returned
+ * @param[in,out] dir SdFile object to operate with,
+ *  in case of absolute path, curDir is modified to point to dir,
+ *  so it is not possible to create on stack inside this function,
+ *  as curDir would point to destroyed object.
+ */
+void CardReader::diveSubfolder (const char *fileName, SdFile& dir)
+{
+    curDir=&root;
+    if (!fileName) return;
+
+    const char *dirname_start, *dirname_end;
+    if (fileName[0] == '/') // absolute path
+    {
+        dirname_start = fileName + 1;
+        while (*dirname_start)
+        {
+            dirname_end = strchr(dirname_start, '/');
+            //SERIAL_ECHO("start:");SERIAL_ECHOLN((int)(dirname_start-name));
+            //SERIAL_ECHO("end  :");SERIAL_ECHOLN((int)(dirname_end-name));
+            if (dirname_end && dirname_end > dirname_start)
+            {
+                const size_t maxLen = 12;
+                char subdirname[maxLen+1];
+                subdirname[maxLen] = 0;
+                const size_t len = ((static_cast<size_t>(dirname_end-dirname_start))>maxLen) ? maxLen : (dirname_end-dirname_start);
+                strncpy(subdirname, dirname_start, len);
+                SERIAL_ECHOLN(subdirname);
+                if (!dir.open(curDir, subdirname, O_READ))
+                {
+                    SERIAL_PROTOCOLRPGM(_T(MSG_SD_OPEN_FILE_FAIL));
+                    SERIAL_PROTOCOL(subdirname);
+                    SERIAL_PROTOCOLLNPGM(".");
+                    return;
+                }
+                else
+                {
+                    //SERIAL_ECHOLN("dive ok");
+                }
+
+                curDir = &dir;
+                dirname_start = dirname_end + 1;
+            }
+            else // the reminder after all /fsa/fdsa/ is the filename
+            {
+                fileName = dirname_start;
+                //SERIAL_ECHOLN("remaider");
+                //SERIAL_ECHOLN(fname);
+                break;
+            }
+
+        }
+    }
+    else //relative path
+    {
+        curDir = &workDir;
+    }
+}
 
 void CardReader::openFile(const char* name,bool read, bool replace_current/*=true*/)
 {
@@ -340,53 +410,9 @@ void CardReader::openFile(const char* name,bool read, bool replace_current/*=tru
   
  
   SdFile myDir;
-  curDir=&root;
   const char *fname=name;
-  
-  char *dirname_start,*dirname_end;
-  if(name[0]=='/')
-  {
-    dirname_start=strchr(name,'/')+1;
-    while(dirname_start>0)
-    {
-      dirname_end=strchr(dirname_start,'/');
-      //SERIAL_ECHO("start:");SERIAL_ECHOLN((int)(dirname_start-name));
-      //SERIAL_ECHO("end  :");SERIAL_ECHOLN((int)(dirname_end-name));
-      if(dirname_end>0 && dirname_end>dirname_start)
-      {
-        char subdirname[13];
-        strncpy(subdirname, dirname_start, dirname_end-dirname_start);
-        subdirname[dirname_end-dirname_start]=0;
-        SERIAL_ECHOLN(subdirname);
-        if(!myDir.open(curDir,subdirname,O_READ))
-        {
-          SERIAL_PROTOCOLRPGM(_T(MSG_SD_OPEN_FILE_FAIL));
-          SERIAL_PROTOCOL(subdirname);
-          SERIAL_PROTOCOLLNPGM(".");
-          return;
-        }
-        else
-        {
-          //SERIAL_ECHOLN("dive ok");
-        }
-          
-        curDir=&myDir; 
-        dirname_start=dirname_end+1;
-      }
-      else // the reminder after all /fsa/fdsa/ is the filename
-      {
-        fname=dirname_start;
-        //SERIAL_ECHOLN("remaider");
-        //SERIAL_ECHOLN(fname);
-        break;
-      }
-      
-    }
-  }
-  else //relative path
-  {
-    curDir=&workDir;
-  }
+  diveSubfolder(fname,myDir);
+
   if(read)
   {
     if (file.open(curDir, fname, O_READ)) 
@@ -431,60 +457,14 @@ void CardReader::openFile(const char* name,bool read, bool replace_current/*=tru
 
 void CardReader::removeFile(const char* name)
 {
-  if(!cardOK)
-    return;
-  file.close();
-  sdprinting = false;
-  
-  
-  SdFile myDir;
-  curDir=&root;
-  const char *fname=name;
-  
-  char *dirname_start,*dirname_end;
-  if(name[0]=='/')
-  {
-    dirname_start=strchr(name,'/')+1;
-    while(dirname_start>0)
-    {
-      dirname_end=strchr(dirname_start,'/');
-      //SERIAL_ECHO("start:");SERIAL_ECHOLN((int)(dirname_start-name));
-      //SERIAL_ECHO("end  :");SERIAL_ECHOLN((int)(dirname_end-name));
-      if(dirname_end>0 && dirname_end>dirname_start)
-      {
-        char subdirname[13];
-        strncpy(subdirname, dirname_start, dirname_end-dirname_start);
-        subdirname[dirname_end-dirname_start]=0;
-        SERIAL_ECHOLN(subdirname);
-        if(!myDir.open(curDir,subdirname,O_READ))
-        {
-          SERIAL_PROTOCOLRPGM("open failed, File: ");
-          SERIAL_PROTOCOL(subdirname);
-          SERIAL_PROTOCOLLNPGM(".");
-          return;
-        }
-        else
-        {
-          //SERIAL_ECHOLN("dive ok");
-        }
-          
-        curDir=&myDir; 
-        dirname_start=dirname_end+1;
-      }
-      else // the reminder after all /fsa/fdsa/ is the filename
-      {
-        fname=dirname_start;
-        //SERIAL_ECHOLN("remaider");
-        //SERIAL_ECHOLN(fname);
-        break;
-      }
-      
-    }
-  }
-  else //relative path
-  {
-    curDir=&workDir;
-  }
+    if(!cardOK) return;
+    file.close();
+    sdprinting = false;
+
+    SdFile myDir;
+    const char *fname=name;
+    diveSubfolder(fname,myDir);
+
     if (file.remove(curDir, fname)) 
     {
       SERIAL_PROTOCOLPGM("File deleted:");

+ 2 - 0
Firmware/cardreader.h

@@ -154,6 +154,8 @@ private:
   LsAction lsAction; //stored for recursion.
   int16_t nrFiles; //counter for the files in the current directory and recycled as position counter for getting the nrFiles'th name in the directory.
   char* diveDirName;
+
+  void diveSubfolder (const char *fileName, SdFile& dir);
   void lsDive(const char *prepend, SdFile parent, const char * const match=NULL);
 #ifdef SDCARD_SORT_ALPHA
   void flush_presort();

+ 2 - 2
Firmware/doxyfile

@@ -453,7 +453,7 @@ EXTRACT_PACKAGE        = NO
 # included in the documentation.
 # The default value is: NO.
 
-EXTRACT_STATIC         = NO
+EXTRACT_STATIC         = YES
 
 # If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
 # locally in source files will be included in the documentation. If set to NO,
@@ -2421,7 +2421,7 @@ DIAFILE_DIRS           =
 # generate a warning when it encounters a \startuml command in this case and
 # will not generate output for the diagram.
 
-PLANTUML_JAR_PATH      =
+PLANTUML_JAR_PATH      = /usr/share/plantuml/
 
 # When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
 # configuration file for plantuml.

+ 15 - 22
Firmware/fsensor.cpp

@@ -7,6 +7,7 @@
 #include "planner.h"
 #include "fastio.h"
 #include "cmdqueue.h"
+#include "ultralcd.h"
 #include "ConfigurationStore.h"
 
 //Basic params
@@ -28,10 +29,6 @@ const char ERRMSG_PAT9125_NOT_RESP[] PROGMEM = "PAT9125 not responding (%d)!\n";
 #define FSENSOR_INT_PIN         63  //filament sensor interrupt pin PK1
 #define FSENSOR_INT_PIN_MSK   0x02  //filament sensor interrupt pin mask (bit1)
 
-extern void stop_and_save_print_to_ram(float z_move, float e_move);
-extern void restore_print_from_ram_and_continue(float e_move);
-extern int8_t FSensorStateMenu;
-
 void fsensor_stop_and_save_print(void)
 {
 	printf_P(PSTR("fsensor_stop_and_save_print\n"));
@@ -102,9 +99,9 @@ uint16_t fsensor_oq_er_sum;
 //max error counter value durring meassurement
 uint8_t  fsensor_oq_er_max;
 //minimum delta value
-uint16_t fsensor_oq_yd_min;
+int16_t fsensor_oq_yd_min;
 //maximum delta value
-uint16_t fsensor_oq_yd_max;
+int16_t fsensor_oq_yd_max;
 //sum of shutter value
 uint16_t fsensor_oq_sh_sum;
 
@@ -219,7 +216,9 @@ bool fsensor_check_autoload(void)
 		fsensor_autoload_check_start();
 		return false;
 	}
+#if 0
 	uint8_t fsensor_autoload_c_old = fsensor_autoload_c;
+#endif
 	if ((millis() - fsensor_autoload_last_millis) < 25) return false;
 	fsensor_autoload_last_millis = millis();
 	if (!pat9125_update_y()) //update sensor
@@ -244,9 +243,11 @@ bool fsensor_check_autoload(void)
 	else if (fsensor_autoload_c > 0)
 		fsensor_autoload_c--;
 	if (fsensor_autoload_c == 0) fsensor_autoload_sum = 0;
-//	puts_P(_N("fsensor_check_autoload\n"));
-//	if (fsensor_autoload_c != fsensor_autoload_c_old)
-//		printf_P(PSTR("fsensor_check_autoload dy=%d c=%d sum=%d\n"), dy, fsensor_autoload_c, fsensor_autoload_sum);
+#if 0
+  	puts_P(_N("fsensor_check_autoload\n"));
+  	if (fsensor_autoload_c != fsensor_autoload_c_old)
+  		printf_P(PSTR("fsensor_check_autoload dy=%d c=%d sum=%d\n"), dy, fsensor_autoload_c, fsensor_autoload_sum);
+#endif
 //	if ((fsensor_autoload_c >= 15) && (fsensor_autoload_sum > 30))
 	if ((fsensor_autoload_c >= 12) && (fsensor_autoload_sum > 20))
 	{
@@ -427,6 +428,11 @@ void fsensor_st_block_chunk(block_t* bl, int cnt)
 	}
 }
 
+//! update (perform M600 on filament runout)
+//!
+//! Works only if filament sensor is enabled.
+//! When the filament sensor error count is larger then FSENSOR_ERR_MAX, pauses print, tries to move filament back and forth.
+//! If there is still no plausible signal from filament sensor plans M600 (Filament change).
 void fsensor_update(void)
 {
 	if (fsensor_enabled)
@@ -449,19 +455,6 @@ void fsensor_update(void)
 			fsensor_err_cnt = 0;
 			fsensor_oq_meassure_start(0);
 
-//			st_synchronize();
-//			for (int axis = X_AXIS; axis <= E_AXIS; axis++)
-//				current_position[axis] = st_get_position_mm(axis);
-/*
-			current_position[E_AXIS] -= 3;
-			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 200 / 60, active_extruder);
-			st_synchronize();
-
-			current_position[E_AXIS] += 3;
-			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 200 / 60, active_extruder);
-			st_synchronize();
-*/
-
 			enquecommand_front_P((PSTR("G1 E-3 F200")));
 			process_commands();
 			cmdqueue_pop_front();

+ 0 - 1
Firmware/fsensor.h

@@ -27,7 +27,6 @@ extern void fsensor_disable(void);
 extern bool fsensor_autoload_enabled;
 extern void fsensor_autoload_set(bool State);
 
-//update (perform M600 on filament runout)
 extern void fsensor_update(void);
 
 //setup pin-change interrupt

+ 57 - 60
Firmware/lcd.cpp

@@ -56,7 +56,7 @@
 #define LCD_5x8DOTS 0x00
 
 
-FILE _lcdout = {0};
+FILE _lcdout; // = {0}; Global variable is always zero initialized, no need to explicitly state that.
 
 
 uint8_t lcd_rs_pin; // LOW: command.  HIGH: character.
@@ -157,7 +157,7 @@ uint8_t lcd_write(uint8_t value)
 	return 1; // assume sucess
 }
 
-void lcd_begin(uint8_t cols, uint8_t lines, uint8_t dotsize, uint8_t clear)
+static void lcd_begin(uint8_t lines, uint8_t dotsize, uint8_t clear)
 {
 	if (lines > 1) lcd_displayfunction |= LCD_2LINE;
 	lcd_numlines = lines;
@@ -221,7 +221,7 @@ void lcd_begin(uint8_t cols, uint8_t lines, uint8_t dotsize, uint8_t clear)
 	lcd_escape[0] = 0;
 }
 
-int lcd_putchar(char c, FILE *stream)
+int lcd_putchar(char c, FILE *)
 {
 	lcd_write(c);
 	return 0;
@@ -247,20 +247,20 @@ void lcd_init(void)
 	pinMode(lcd_enable_pin, OUTPUT);
 	if (fourbitmode) lcd_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
 	else lcd_displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS;
-	lcd_begin(LCD_WIDTH, LCD_HEIGHT, LCD_5x8DOTS, 1);
+	lcd_begin(LCD_HEIGHT, LCD_5x8DOTS, 1);
 	//lcd_clear();
 	fdev_setup_stream(lcdout, lcd_putchar, NULL, _FDEV_SETUP_WRITE); //setup lcdout stream
 }
 
 void lcd_refresh(void)
 {
-    lcd_begin(LCD_WIDTH, LCD_HEIGHT, LCD_5x8DOTS, 1);
+    lcd_begin(LCD_HEIGHT, LCD_5x8DOTS, 1);
     lcd_set_custom_characters();
 }
 
 void lcd_refresh_noclear(void)
 {
-    lcd_begin(LCD_WIDTH, LCD_HEIGHT, LCD_5x8DOTS, 0);
+    lcd_begin(LCD_HEIGHT, LCD_5x8DOTS, 0);
     lcd_set_custom_characters();
 }
 
@@ -506,7 +506,6 @@ uint8_t lcd_escape_write(uint8_t chr)
 		break;
 	}
 	escape_cnt = 0; // reset escape
-end:
 	return 1; // assume sucess
 }
 
@@ -684,10 +683,22 @@ ShortTimer longPressTimer;
 LongTimer lcd_timeoutToStatus;
 
 
+//! @brief Was button clicked?
+//!
+//! Consume click event, following call would return 0.
+//! See #LCD_CLICKED macro for version not consuming the event.
+//!
+//! Generally is used in modal dialogs.
+//!
+//! @retval 0 not clicked
+//! @retval nonzero clicked
 uint8_t lcd_clicked(void)
 {
 	bool clicked = LCD_CLICKED;
-	if(clicked) lcd_button_pressed = 0;
+	if(clicked)
+	{
+	    lcd_consume_click();
+	}
     return clicked;
 }
 
@@ -695,7 +706,7 @@ void lcd_beeper_quick_feedback(void)
 {
 	SET_OUTPUT(BEEPER);
 //-//
-Sound_MakeSound(e_SOUND_CLASS_Echo,e_SOUND_TYPE_ButtonEcho);
+Sound_MakeSound(e_SOUND_TYPE_ButtonEcho);
 /*
 	for(int8_t i = 0; i < 10; i++)
 	{
@@ -710,7 +721,7 @@ Sound_MakeSound(e_SOUND_CLASS_Echo,e_SOUND_TYPE_ButtonEcho);
 void lcd_quick_feedback(void)
 {
   lcd_draw_update = 2;
-  lcd_button_pressed = false;  
+  lcd_button_pressed = false;
   lcd_beeper_quick_feedback();
 }
 
@@ -727,7 +738,6 @@ void lcd_update(uint8_t lcdDrawUpdateOverride)
 		lcd_draw_update = lcdDrawUpdateOverride;
 	if (!lcd_update_enabled)
 		return;
-	lcd_buttons_update();
 	if (lcd_lcdupdate_func)
 		lcd_lcdupdate_func();
 }
@@ -761,57 +771,45 @@ void lcd_update_enable(uint8_t enabled)
 extern LongTimer safetyTimer;
 void lcd_buttons_update(void)
 {
-	static bool _lock = false;
-	if (_lock) return;
-	_lock = true;
 	uint8_t newbutton = 0;
 	if (READ(BTN_EN1) == 0)  newbutton |= EN_A;
 	if (READ(BTN_EN2) == 0)  newbutton |= EN_B;
-	if (lcd_update_enabled)
-	{ //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	  
-			lcd_timeoutToStatus.start();
-			if (!buttonBlanking.running() || buttonBlanking.expired(BUTTON_BLANKING_TIME)) {
-				buttonBlanking.start();
-		        safetyTimer.start();
-				if ((lcd_button_pressed == 0) && (lcd_long_press_active == 0))
-				{
-					longPressTimer.start();
-					lcd_button_pressed = 1;
-				}
-				else
-				{
-					if (longPressTimer.expired(LONG_PRESS_TIME))
-					{
-						lcd_long_press_active = 1;
-						if (lcd_longpress_func)
-							lcd_longpress_func();
-					}
-				}
-			}
-		}
-		else
-		{ //button not pressed
-			if (lcd_button_pressed)
-			{ //button was released
-				buttonBlanking.start();
-				if (lcd_long_press_active == 0)
-				{ //button released before long press gets activated
-					newbutton |= EN_C;
-				}
-				//else if (menu_menu == lcd_move_z) lcd_quick_feedback(); 
-				//lcd_button_pressed is set back to false via lcd_quick_feedback function
-			}
-			else
-				lcd_long_press_active = 0;
-		}
-	}
-	else
-	{ //we are in modal mode
-		if (READ(BTN_ENC) == 0)
-			newbutton |= EN_C; 
-	}
+
+    if (READ(BTN_ENC) == 0)
+    { //button is pressed
+        lcd_timeoutToStatus.start();
+        if (!buttonBlanking.running() || buttonBlanking.expired(BUTTON_BLANKING_TIME)) {
+            buttonBlanking.start();
+            safetyTimer.start();
+            if ((lcd_button_pressed == 0) && (lcd_long_press_active == 0))
+            {
+                //long press is not possible in modal mode
+                if (lcd_update_enabled) longPressTimer.start();
+                lcd_button_pressed = 1;
+            }
+            else if (longPressTimer.expired(LONG_PRESS_TIME))
+            {
+                lcd_long_press_active = 1;
+                if (lcd_longpress_func)
+                    lcd_longpress_func();
+            }
+        }
+    }
+    else
+    { //button not pressed
+        if (lcd_button_pressed)
+        { //button was released
+            buttonBlanking.start();
+            if (lcd_long_press_active == 0)
+            { //button released before long press gets activated
+                newbutton |= EN_C;
+            }
+            //else if (menu_menu == lcd_move_z) lcd_quick_feedback();
+            //lcd_button_pressed is set back to false via lcd_quick_feedback function
+        }
+        else
+            lcd_long_press_active = 0;
+    }
 
 	lcd_buttons = newbutton;
 	//manage encoder rotation
@@ -849,7 +847,6 @@ void lcd_buttons_update(void)
 		}
 	}
 	lcd_encoder_bits = enc;
-	_lock = false;
 }
 
 

+ 40 - 3
Firmware/lcd.h

@@ -1,4 +1,4 @@
-//lcd.h
+//! @file
 #ifndef _LCD_H
 #define _LCD_H
 
@@ -131,7 +131,6 @@ extern lcd_lcdupdate_func_t lcd_lcdupdate_func;
 
 extern uint8_t lcd_clicked(void);
 
-
 extern void lcd_beeper_quick_feedback(void);
 
 //Cause an LCD refresh, and give the user visual or audible feedback that something has happened
@@ -150,6 +149,29 @@ extern void lcd_update_enable(uint8_t enabled);
 
 extern void lcd_buttons_update(void);
 
+//! @brief Helper class to temporarily disable LCD updates
+//!
+//! When constructed (on stack), original state state of lcd_update_enabled is stored
+//! and LCD updates are disabled.
+//! When destroyed (gone out of scope), original state of LCD update is restored.
+//! It has zero overhead compared to storing bool saved = lcd_update_enabled
+//! and calling lcd_update_enable(false) and lcd_update_enable(saved).
+class LcdUpdateDisabler
+{
+public:
+    LcdUpdateDisabler(): m_updateEnabled(lcd_update_enabled)
+    {
+        lcd_update_enable(false);
+    }
+    ~LcdUpdateDisabler()
+    {
+        lcd_update_enable(m_updateEnabled);
+    }
+
+private:
+    bool m_updateEnabled;
+};
+
 
 
 
@@ -187,7 +209,16 @@ extern void lcd_buttons_update(void);
 #define EN_A (1<<BLEN_A)
 #define BLEN_C 2 
 #define EN_C (1<<BLEN_C) 
-  
+
+//! @brief Was button clicked?
+//!
+//! Doesn't consume button click event. See lcd_clicked()
+//! for function consuming the event.
+//!
+//! Generally is used in non-modal menus.
+//!
+//! @retval 0 button was not clicked
+//! @retval 1 button was clicked
 #define LCD_CLICKED (lcd_buttons&EN_C)
 
 ////////////////////////
@@ -221,6 +252,12 @@ extern void lcd_set_custom_characters_progress(void);
 extern void lcd_set_custom_characters_nextpage(void);
 extern void lcd_set_custom_characters_degree(void);
 
+//! @brief Consume click event
+inline void lcd_consume_click()
+{
+    lcd_button_pressed = 0;
+    lcd_buttons &= 0xff^EN_C;
+}
 
 
 #endif //_LCD_H

+ 1 - 0
Firmware/menu.cpp

@@ -236,6 +236,7 @@ uint8_t menu_item_function_P(const char* str, menu_func_t func)
 		if (menu_clicked && (lcd_encoder == menu_item))
 		{
 			menu_clicked = false;
+			lcd_consume_click();
 			lcd_update_enabled = 0;
 			if (func) func();
 			lcd_update_enabled = 1;

+ 24 - 13
Firmware/mesh_bed_calibration.cpp

@@ -132,7 +132,7 @@ const float bed_ref_points[] PROGMEM = {
 static inline float sqr(float x) { return x * x; }
 
 #ifdef HEATBED_V2
-static inline bool point_on_1st_row(const uint8_t i)
+static inline bool point_on_1st_row(const uint8_t /*i*/)
 {
 	return false;
 }
@@ -147,7 +147,7 @@ static inline bool point_on_1st_row(const uint8_t i)
 // The first row of points may not be fully reachable
 // and the y values may be shortened a bit by the bed carriage
 // pulling the belt up.
-static inline float point_weight_x(const uint8_t i, const uint8_t npts, const float &y)
+static inline float point_weight_x(const uint8_t i, const float &y)
 {
     float w = 1.f;
     if (point_on_1st_row(i)) {
@@ -169,7 +169,7 @@ static inline float point_weight_x(const uint8_t i, const uint8_t npts, const fl
 // The first row of points may not be fully reachable
 // and the y values may be shortened a bit by the bed carriage
 // pulling the belt up.
-static inline float point_weight_y(const uint8_t i, const uint8_t npts, const float &y)
+static inline float point_weight_y(const uint8_t i, const float &y)
 {
     float w = 1.f;
     if (point_on_1st_row(i)) {
@@ -209,7 +209,10 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS(
     float        *vec_x,
     float        *vec_y,
     float        *cntr,
-    int8_t        verbosity_level
+    int8_t
+#ifdef SUPPORT_VERBOSITY
+    verbosity_level
+#endif //SUPPORT_VERBOSITY
     )
 {
 	float angleDiff;
@@ -291,7 +294,7 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS(
                              (c == 0) ? 1.f :
                             ((c == 2) ? (-s1 * measured_pts[2 * i]) :
                                         (-c2 * measured_pts[2 * i + 1]));
-                        float w = point_weight_x(i, npts, measured_pts[2 * i + 1]);
+                        float w = point_weight_x(i, measured_pts[2 * i + 1]);
                         acc += a * b * w;
                     }
                     // Second for the residuum in the y axis. 
@@ -306,7 +309,7 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS(
                              (c == 1) ? 1.f :
                             ((c == 2) ? ( c1 * measured_pts[2 * i]) :
                                         (-s2 * measured_pts[2 * i + 1]));
-                        float w = point_weight_y(i, npts, measured_pts[2 * i + 1]);
+                        float w = point_weight_y(i, measured_pts[2 * i + 1]);
                         acc += a * b * w;
                     }
                 }
@@ -322,7 +325,7 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS(
                         ((r == 2) ? (-s1 * measured_pts[2 * i]) :
                                     (-c2 * measured_pts[2 * i + 1])));
                     float fx = c1 * measured_pts[2 * i] - s2 * measured_pts[2 * i + 1] + cntr[0] - pgm_read_float(true_pts + i * 2);
-                    float w = point_weight_x(i, npts, measured_pts[2 * i + 1]);
+                    float w = point_weight_x(i, measured_pts[2 * i + 1]);
                     acc += j * fx * w;
                 }
                 {
@@ -332,7 +335,7 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS(
                         ((r == 2) ? ( c1 * measured_pts[2 * i]) :
                                     (-s2 * measured_pts[2 * i + 1])));
                     float fy = s1 * measured_pts[2 * i] + c2 * measured_pts[2 * i + 1] + cntr[1] - pgm_read_float(true_pts + i * 2 + 1);
-                    float w = point_weight_y(i, npts, measured_pts[2 * i + 1]);
+                    float w = point_weight_y(i, measured_pts[2 * i + 1]);
                     acc += j * fy * w;
                 }
             }
@@ -453,7 +456,7 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS(
 				#ifdef SUPPORT_VERBOSITY
 				if(verbosity_level >= 20) SERIAL_ECHOPGM("Point on first row");
 				#endif // SUPPORT_VERBOSITY
-				float w = point_weight_y(i, npts, measured_pts[2 * i + 1]);
+				float w = point_weight_y(i, measured_pts[2 * i + 1]);
 				if (sqrt(errX) > BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_X ||
 					(w != 0.f && sqrt(errY) > BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_Y)) {
 					result = BED_SKEW_OFFSET_DETECTION_FITTING_FAILED;
@@ -550,7 +553,7 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS(
         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, npts, y);
+            float w = point_weight_x(i, y);
 			cntr[0] += w * (pgm_read_float(true_pts + i * 2) - x);
 			wx += w;
 			#ifdef SUPPORT_VERBOSITY
@@ -567,7 +570,7 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS(
 				MYSERIAL.print(wx);
 			}
 			#endif // SUPPORT_VERBOSITY
-            w = point_weight_y(i, npts, y);
+            w = point_weight_y(i, y);
 			cntr[1] += w * (pgm_read_float(true_pts + i * 2 + 1) - y);
 			wy += w;
 			#ifdef SUPPORT_VERBOSITY
@@ -960,7 +963,11 @@ static inline void update_current_position_z()
 }
 
 // At the current position, find the Z stop.
-inline bool find_bed_induction_sensor_point_z(float minimum_z, uint8_t n_iter, int verbosity_level)
+inline bool find_bed_induction_sensor_point_z(float minimum_z, uint8_t n_iter, int
+#ifdef SUPPORT_VERBOSITY
+    verbosity_level
+#endif //SUPPORT_VERBOSITY
+        )
 {
 #ifdef TMC2130
 	FORCE_HIGH_POWER_START;
@@ -1047,7 +1054,11 @@ extern bool xyzcal_find_bed_induction_sensor_point_xy();
 #endif //HEATBED_V2
 
 #ifdef HEATBED_V2
-inline bool find_bed_induction_sensor_point_xy(int verbosity_level)
+inline bool find_bed_induction_sensor_point_xy(int
+#if !defined (NEW_XYZCAL) && defined (SUPPORT_VERBOSITY)
+        verbosity_level
+#endif
+        )
 {
 #ifdef NEW_XYZCAL
 	return xyzcal_find_bed_induction_sensor_point_xy();

+ 1 - 1
Firmware/mesh_bed_leveling.cpp

@@ -21,7 +21,7 @@ static inline bool vec_undef(const float v[2])
     return vx[0] == 0x0FFFFFFFF || vx[1] == 0x0FFFFFFFF;
 }
 
-void mesh_bed_leveling::get_meas_xy(int ix, int iy, float &x, float &y, bool use_default)
+void mesh_bed_leveling::get_meas_xy(int ix, int iy, float &x, float &y, bool /*use_default*/)
 {
 #if 0
     float cntr[2] = {

+ 24 - 22
Firmware/mmu.cpp

@@ -29,12 +29,13 @@ bool mmu_enabled = false;
 
 bool mmu_ready = false;
 
-int8_t mmu_state = 0;
+static int8_t mmu_state = 0;
 
 uint8_t mmu_cmd = 0;
 
 uint8_t mmu_extruder = 0;
 
+//! This variable probably has no meaning and is planed to be removed
 uint8_t tmp_extruder = 0;
 
 int8_t mmu_finda = -1;
@@ -494,15 +495,11 @@ void mmu_M600_wait_and_beep() {
 void mmu_M600_load_filament(bool automatic)
 { 
 	//load filament for mmu v2
-
-		  bool response = false;
-		  bool yes = false;
 		  tmp_extruder = mmu_extruder;
 		  if (!automatic) {
 #ifdef MMU_M600_SWITCH_EXTRUDER
-			  yes = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Do you want to switch extruder?"), false);
+		      bool yes = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Do you want to switch extruder?"), false);
 			  if(yes) tmp_extruder = choose_extruder_menu();
-			  else tmp_extruder = mmu_extruder;
 #endif //MMU_M600_SWITCH_EXTRUDER
 		  }
 		  else {
@@ -541,7 +538,11 @@ void extr_mov(float shift, float feed_rate)
 }
 
 
-void change_extr(int extr) { //switches multiplexer for extruders
+void change_extr(int
+#ifdef SNMM
+        extr
+#endif //SNMM
+        ) { //switches multiplexer for extruders
 #ifdef SNMM
 	st_synchronize();
 	delay(100);
@@ -1011,23 +1012,24 @@ void mmu_eject_filament(uint8_t filament, bool recover)
 		if (degHotend0() > EXTRUDE_MINTEMP)
 		{
 			st_synchronize();
-			lcd_update_enable(false);
-			lcd_clear();
-			lcd_set_cursor(0, 1); lcd_puts_P(_i("Ejecting filament"));
-			current_position[E_AXIS] -= 80;
-			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2500 / 60, active_extruder);
-			st_synchronize();
 
-			lcd_update_enable(true);
-
-			mmu_command(MMU_CMD_E0 + filament);
-			manage_response(false, false);
-			if (recover)
 			{
-				lcd_show_fullscreen_message_and_wait_P(_i("Please remove filament and then press the knob."));
-				mmu_command(MMU_CMD_R0);
-				manage_response(false, false);
-			}
+			    LcdUpdateDisabler disableLcdUpdate;
+                lcd_clear();
+                lcd_set_cursor(0, 1); lcd_puts_P(_i("Ejecting filament"));
+                current_position[E_AXIS] -= 80;
+                plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 2500 / 60, active_extruder);
+                st_synchronize();
+                mmu_command(MMU_CMD_E0 + filament);
+                manage_response(false, false);
+                if (recover)
+                {
+                    lcd_show_fullscreen_message_and_wait_P(_i("Please remove filament and then press the knob."));
+                    mmu_command(MMU_CMD_R0);
+                    manage_response(false, false);
+                }
+
+            }
 		}
 		else
 		{

+ 0 - 2
Firmware/mmu.h

@@ -5,8 +5,6 @@
 
 extern bool mmu_enabled;
 
-extern int8_t mmu_state;
-
 extern uint8_t mmu_extruder;
 
 extern uint8_t tmp_extruder;

+ 2 - 3
Firmware/optiboot_w25x20cl.cpp

@@ -272,7 +272,6 @@ void optiboot_w25x20cl_enter()
     /* Read memory block mode, length is big endian.  */
     else if(ch == STK_READ_PAGE) {
       uint32_t addr = (((uint32_t)rampz) << 16) | address;
-      uint8_t desttype;
       register pagelen_t i;
       // Read the page length, with the length transferred each nibble separately to work around
       // the Prusa's USB to serial infamous semicolon issue.
@@ -280,8 +279,8 @@ void optiboot_w25x20cl_enter()
       length |= ((pagelen_t)getch()) << 8;
       length |= getch();
       length |= getch();
-      // Read the destination type. It should always be 'F' as flash.
-      desttype = getch();
+      // Read the destination type. It should always be 'F' as flash. It is not checked.
+      (void)getch();
       verifySpace();
       w25x20cl_wait_busy();
       w25x20cl_rd_data(addr, buff, length);

+ 6 - 6
Firmware/planner.cpp

@@ -872,22 +872,22 @@ block->steps_y.wide = labs((target[X_AXIS]-position[X_AXIS]) - (target[Y_AXIS]-p
           enable_e0(); 
           g_uc_extruder_last_move[0] = BLOCK_BUFFER_SIZE*2;
           
-          if(g_uc_extruder_last_move[1] == 0) disable_e1(); 
-          if(g_uc_extruder_last_move[2] == 0) disable_e2(); 
+          if(g_uc_extruder_last_move[1] == 0) {disable_e1();}
+          if(g_uc_extruder_last_move[2] == 0) {disable_e2();}
         break;
         case 1:
           enable_e1(); 
           g_uc_extruder_last_move[1] = BLOCK_BUFFER_SIZE*2;
           
-          if(g_uc_extruder_last_move[0] == 0) disable_e0(); 
-          if(g_uc_extruder_last_move[2] == 0) disable_e2(); 
+          if(g_uc_extruder_last_move[0] == 0) {disable_e0();}
+          if(g_uc_extruder_last_move[2] == 0) {disable_e2();}
         break;
         case 2:
           enable_e2(); 
           g_uc_extruder_last_move[2] = BLOCK_BUFFER_SIZE*2;
           
-          if(g_uc_extruder_last_move[0] == 0) disable_e0(); 
-          if(g_uc_extruder_last_move[1] == 0) disable_e1(); 
+          if(g_uc_extruder_last_move[0] == 0) {disable_e0();}
+          if(g_uc_extruder_last_move[1] == 0) {disable_e1();}
         break;        
       }
     }

+ 4 - 4
Firmware/sm4.c

@@ -85,8 +85,8 @@ void sm4_set_dir(uint8_t axis, uint8_t dir)
 
 uint8_t sm4_get_dir_bits(void)
 {
-	uint8_t register dir_bits = 0;
-	uint8_t register portL = PORTL;
+    register uint8_t dir_bits = 0;
+    register uint8_t portL = PORTL;
 	//TODO -optimize in asm
 #if ((MOTHERBOARD == BOARD_RAMBO_MINI_1_0) || (MOTHERBOARD == BOARD_RAMBO_MINI_1_3))
 	if (portL & 2) dir_bits |= 1;
@@ -106,7 +106,7 @@ uint8_t sm4_get_dir_bits(void)
 
 void sm4_set_dir_bits(uint8_t dir_bits)
 {
-	uint8_t register portL = PORTL;
+    register uint8_t portL = PORTL;
 	portL &= 0xb8; //set direction bits to zero
 	//TODO -optimize in asm
 #if ((MOTHERBOARD == BOARD_RAMBO_MINI_1_0) || (MOTHERBOARD == BOARD_RAMBO_MINI_1_3))
@@ -129,7 +129,7 @@ void sm4_set_dir_bits(uint8_t dir_bits)
 void sm4_do_step(uint8_t axes_mask)
 {
 #if ((MOTHERBOARD == BOARD_RAMBO_MINI_1_0) || (MOTHERBOARD == BOARD_RAMBO_MINI_1_3) || (MOTHERBOARD == BOARD_EINSY_1_0a))
-	uint8_t register portC = PORTC & 0xf0;
+    register uint8_t portC = PORTC & 0xf0;
 	PORTC = portC | (axes_mask & 0x0f); //set step signals by mask
 	asm("nop");
 	PORTC = portC; //set step signals to zero

+ 1 - 1
Firmware/sound.cpp

@@ -59,7 +59,7 @@ switch(eSoundMode)
 Sound_SaveMode();
 }
 
-void Sound_MakeSound(eSOUND_CLASS eSoundClass,eSOUND_TYPE eSoundType)
+void Sound_MakeSound(eSOUND_TYPE eSoundType)
 {
 switch(eSoundMode)
      {

+ 1 - 1
Firmware/sound.h

@@ -26,7 +26,7 @@ extern void Sound_Init(void);
 extern void Sound_Default(void);
 extern void Sound_Save(void);
 extern void Sound_CycleState(void);
-extern void Sound_MakeSound(eSOUND_CLASS eSoundClass,eSOUND_TYPE eSoundType);
+extern void Sound_MakeSound(eSOUND_TYPE eSoundType);
 
 //static void Sound_DoSound_Echo(void);
 //static void Sound_DoSound_Prompt(void);

+ 11 - 30
Firmware/stepper.cpp

@@ -107,8 +107,6 @@ static bool z_endstop_invert = false;
 volatile long count_position[NUM_AXIS] = { 0, 0, 0, 0};
 volatile signed char count_direction[NUM_AXIS] = { 1, 1, 1, 1};
 
-uint8_t LastStepMask = 0;
-
 #ifdef LIN_ADVANCE
 
   static uint16_t nextMainISR = 0;
@@ -720,7 +718,6 @@ FORCE_INLINE void stepper_tick_lowres()
     counter_x.lo += current_block->steps_x.lo;
     if (counter_x.lo > 0) {
       WRITE_NC(X_STEP_PIN, !INVERT_X_STEP_PIN);
-      LastStepMask |= X_AXIS_MASK;
 #ifdef DEBUG_XSTEP_DUP_PIN
       WRITE_NC(DEBUG_XSTEP_DUP_PIN,!INVERT_X_STEP_PIN);
 #endif //DEBUG_XSTEP_DUP_PIN
@@ -735,7 +732,6 @@ FORCE_INLINE void stepper_tick_lowres()
     counter_y.lo += current_block->steps_y.lo;
     if (counter_y.lo > 0) {
       WRITE_NC(Y_STEP_PIN, !INVERT_Y_STEP_PIN);
-      LastStepMask |= Y_AXIS_MASK;
 #ifdef DEBUG_YSTEP_DUP_PIN
       WRITE_NC(DEBUG_YSTEP_DUP_PIN,!INVERT_Y_STEP_PIN);
 #endif //DEBUG_YSTEP_DUP_PIN
@@ -750,7 +746,6 @@ FORCE_INLINE void stepper_tick_lowres()
     counter_z.lo += current_block->steps_z.lo;
     if (counter_z.lo > 0) {
       WRITE_NC(Z_STEP_PIN, !INVERT_Z_STEP_PIN);
-      LastStepMask |= Z_AXIS_MASK;
       counter_z.lo -= current_block->step_event_count.lo;
       count_position[Z_AXIS]+=count_direction[Z_AXIS];
       WRITE_NC(Z_STEP_PIN, INVERT_Z_STEP_PIN);
@@ -785,7 +780,6 @@ FORCE_INLINE void stepper_tick_highres()
     counter_x.wide += current_block->steps_x.wide;
     if (counter_x.wide > 0) {
       WRITE_NC(X_STEP_PIN, !INVERT_X_STEP_PIN);
-      LastStepMask |= X_AXIS_MASK;
 #ifdef DEBUG_XSTEP_DUP_PIN
       WRITE_NC(DEBUG_XSTEP_DUP_PIN,!INVERT_X_STEP_PIN);
 #endif //DEBUG_XSTEP_DUP_PIN
@@ -800,7 +794,6 @@ FORCE_INLINE void stepper_tick_highres()
     counter_y.wide += current_block->steps_y.wide;
     if (counter_y.wide > 0) {
       WRITE_NC(Y_STEP_PIN, !INVERT_Y_STEP_PIN);
-      LastStepMask |= Y_AXIS_MASK;
 #ifdef DEBUG_YSTEP_DUP_PIN
       WRITE_NC(DEBUG_YSTEP_DUP_PIN,!INVERT_Y_STEP_PIN);
 #endif //DEBUG_YSTEP_DUP_PIN
@@ -815,7 +808,6 @@ FORCE_INLINE void stepper_tick_highres()
     counter_z.wide += current_block->steps_z.wide;
     if (counter_z.wide > 0) {
       WRITE_NC(Z_STEP_PIN, !INVERT_Z_STEP_PIN);
-      LastStepMask |= Z_AXIS_MASK;
       counter_z.wide -= current_block->step_event_count.wide;
       count_position[Z_AXIS]+=count_direction[Z_AXIS];
       WRITE_NC(Z_STEP_PIN, INVERT_Z_STEP_PIN);
@@ -853,8 +845,6 @@ FORCE_INLINE void isr() {
   if (current_block == NULL)
     stepper_next_block();
 
-	LastStepMask = 0;
-
   if (current_block != NULL) 
   {
     stepper_check_endstops();
@@ -1079,7 +1069,7 @@ FORCE_INLINE void isr() {
   }
 
 #ifdef TMC2130
-	tmc2130_st_isr(LastStepMask);
+	tmc2130_st_isr();
 #endif //TMC2130
 
   //WRITE_NC(LOGIC_ANALYZER_CH0, false);
@@ -1434,13 +1424,10 @@ void babystep(const uint8_t axis,const bool direction)
     
     //perform step 
     WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN); 
-	LastStepMask |= X_AXIS_MASK;
 #ifdef DEBUG_XSTEP_DUP_PIN
     WRITE(DEBUG_XSTEP_DUP_PIN,!INVERT_X_STEP_PIN);
 #endif //DEBUG_XSTEP_DUP_PIN
-    {
-    volatile float x=1./float(axis+1)/float(axis+2); //wait a tiny bit
-    }
+    delayMicroseconds(1);
     WRITE(X_STEP_PIN, INVERT_X_STEP_PIN);
 #ifdef DEBUG_XSTEP_DUP_PIN
     WRITE(DEBUG_XSTEP_DUP_PIN,INVERT_X_STEP_PIN);
@@ -1460,13 +1447,10 @@ void babystep(const uint8_t axis,const bool direction)
     
     //perform step 
     WRITE(Y_STEP_PIN, !INVERT_Y_STEP_PIN); 
-	LastStepMask |= Y_AXIS_MASK;
 #ifdef DEBUG_YSTEP_DUP_PIN
     WRITE(DEBUG_YSTEP_DUP_PIN,!INVERT_Y_STEP_PIN);
 #endif //DEBUG_YSTEP_DUP_PIN
-    {
-    volatile float x=1./float(axis+1)/float(axis+2); //wait a tiny bit
-    }
+    delayMicroseconds(1);
     WRITE(Y_STEP_PIN, INVERT_Y_STEP_PIN);
 #ifdef DEBUG_YSTEP_DUP_PIN
     WRITE(DEBUG_YSTEP_DUP_PIN,INVERT_Y_STEP_PIN);
@@ -1489,14 +1473,10 @@ void babystep(const uint8_t axis,const bool direction)
     #endif
     //perform step 
     WRITE(Z_STEP_PIN, !INVERT_Z_STEP_PIN); 
-	LastStepMask |= Z_AXIS_MASK;
     #ifdef Z_DUAL_STEPPER_DRIVERS
       WRITE(Z2_STEP_PIN, !INVERT_Z_STEP_PIN);
     #endif
-    //wait a tiny bit
-    {
-    volatile float x=1./float(axis+1); //absolutely useless
-    }
+    delayMicroseconds(1);
     WRITE(Z_STEP_PIN, INVERT_Z_STEP_PIN);
     #ifdef Z_DUAL_STEPPER_DRIVERS
       WRITE(Z2_STEP_PIN, INVERT_Z_STEP_PIN);
@@ -1516,16 +1496,16 @@ void babystep(const uint8_t axis,const bool direction)
 }
 #endif //BABYSTEPPING
 
+#if defined(DIGIPOTSS_PIN) && DIGIPOTSS_PIN > -1
 void digitalPotWrite(int address, int value) // From Arduino DigitalPotControl example
 {
-  #if defined(DIGIPOTSS_PIN) && DIGIPOTSS_PIN > -1
     digitalWrite(DIGIPOTSS_PIN,LOW); // take the SS pin low to select the chip
     SPI.transfer(address); //  send in the address and value via SPI:
     SPI.transfer(value);
     digitalWrite(DIGIPOTSS_PIN,HIGH); // take the SS pin high to de-select the chip:
     //delay(10);
-  #endif
 }
+#endif
 
 void EEPROM_read_st(int pos, uint8_t* value, uint8_t size)
 {
@@ -1569,19 +1549,19 @@ uint8_t SilentMode = eeprom_read_byte((uint8_t*)EEPROM_SILENT);
 
 
 
-
+#ifdef MOTOR_CURRENT_PWM_XY_PIN
 void st_current_set(uint8_t driver, int current)
 {
-  #ifdef MOTOR_CURRENT_PWM_XY_PIN
   if (driver == 0) analogWrite(MOTOR_CURRENT_PWM_XY_PIN, (long)current * 255L / (long)MOTOR_CURRENT_PWM_RANGE);
   if (driver == 1) analogWrite(MOTOR_CURRENT_PWM_Z_PIN, (long)current * 255L / (long)MOTOR_CURRENT_PWM_RANGE);
   if (driver == 2) analogWrite(MOTOR_CURRENT_PWM_E_PIN, (long)current * 255L / (long)MOTOR_CURRENT_PWM_RANGE);
-  #endif
 }
+#else //MOTOR_CURRENT_PWM_XY_PIN
+void st_current_set(uint8_t, int ){}
+#endif //MOTOR_CURRENT_PWM_XY_PIN
 
 void microstep_init()
 {
-  const uint8_t microstep_modes[] = MICROSTEP_MODES;
 
   #if defined(E1_MS1_PIN) && E1_MS1_PIN > -1
   pinMode(E1_MS1_PIN,OUTPUT);
@@ -1589,6 +1569,7 @@ void microstep_init()
   #endif
 
   #if defined(X_MS1_PIN) && X_MS1_PIN > -1
+  const uint8_t microstep_modes[] = MICROSTEP_MODES;
   pinMode(X_MS1_PIN,OUTPUT);
   pinMode(X_MS2_PIN,OUTPUT);  
   pinMode(Y_MS1_PIN,OUTPUT);

+ 3 - 1
Firmware/stepper.h

@@ -90,10 +90,12 @@ extern bool x_min_endstop;
 extern bool x_max_endstop;
 extern bool y_min_endstop;
 extern bool y_max_endstop;
+extern volatile long count_position[NUM_AXIS];
 
 void quickStop();
-
+#if defined(DIGIPOTSS_PIN) && DIGIPOTSS_PIN > -1
 void digitalPotWrite(int address, int value);
+#endif //defined(DIGIPOTSS_PIN) && DIGIPOTSS_PIN > -1
 void microstep_ms(uint8_t driver, int8_t ms1, int8_t ms2);
 void microstep_mode(uint8_t driver, uint8_t stepping);
 void st_current_init();

+ 1 - 35
Firmware/temperature.cpp

@@ -175,7 +175,6 @@ static int bed_maxttemp_raw = HEATER_BED_RAW_HI_TEMP;
 static float analog2temp(int raw, uint8_t e);
 static float analog2tempBed(int raw);
 static float analog2tempAmbient(int raw);
-static float analog2tempPINDA(int raw);
 static void updateTemperaturesFromRawValues();
 
 enum TempRunawayStates
@@ -493,9 +492,6 @@ void checkFanSpeed()
 	}
 }
 
-extern void stop_and_save_print_to_ram(float z_move, float e_move);
-extern void restore_print_from_ram_and_continue(float e_move);
-
 void fanSpeedError(unsigned char _fan) {
 	if (get_message_level() != 0 && isPrintPaused) return; 
 	//to ensure that target temp. is not set to zero in case taht we are resuming print 
@@ -504,8 +500,7 @@ void fanSpeedError(unsigned char _fan) {
 			lcd_print_stop();
 		}
 		else {
-			isPrintPaused = true;
-			lcd_sdcard_pause();
+			lcd_pause_print();
 		}
 	}
 	else {
@@ -928,35 +923,6 @@ static float analog2tempBed(int raw) {
   #endif
 }
 
-#ifdef PINDA_THERMISTOR
-
-static float analog2tempPINDA(int raw) {
-
-	float celsius = 0;
-	byte i;
-
-	for (i = 1; i<BEDTEMPTABLE_LEN; i++)
-	{
-		if (PGM_RD_W(BEDTEMPTABLE[i][0]) > raw)
-		{
-			celsius = PGM_RD_W(BEDTEMPTABLE[i - 1][1]) +
-				(raw - PGM_RD_W(BEDTEMPTABLE[i - 1][0])) *
-				(float)(PGM_RD_W(BEDTEMPTABLE[i][1]) - PGM_RD_W(BEDTEMPTABLE[i - 1][1])) /
-				(float)(PGM_RD_W(BEDTEMPTABLE[i][0]) - PGM_RD_W(BEDTEMPTABLE[i - 1][0]));
-			break;
-		}
-	}
-
-	// Overflow: Set to last value in the table
-	if (i == BEDTEMPTABLE_LEN) celsius = PGM_RD_W(BEDTEMPTABLE[i - 1][1]);
-
-	return celsius;
-}
-
-
-#endif //PINDA_THERMISTOR
-
-
 #ifdef AMBIENT_THERMISTOR
 static float analog2tempAmbient(int raw)
 {

+ 6 - 11
Firmware/tmc2130.cpp

@@ -13,12 +13,6 @@
 #define TMC2130_GCONF_SGSENS 0x00003180 // spreadCycle with stallguard (stall activates DIAG0 and DIAG1 [pushpull])
 #define TMC2130_GCONF_SILENT 0x00000004 // stealthChop
 
-//externals for debuging
-extern float current_position[4];
-extern void st_get_position_xy(long &x, long &y);
-extern long st_get_position(uint8_t axis);
-extern void crashdet_stop_and_save_print();
-extern void crashdet_stop_and_save_print2();
 
 //mode
 uint8_t tmc2130_mode = TMC2130_MODE_NORMAL;
@@ -236,7 +230,7 @@ uint8_t tmc2130_sample_diag()
 
 extern bool is_usb_printing;
 
-void tmc2130_st_isr(uint8_t last_step_mask)
+void tmc2130_st_isr()
 {
 	if (tmc2130_mode == TMC2130_MODE_SILENT || tmc2130_sg_stop_on_crash == false) return;
 	uint8_t crash = 0;
@@ -793,7 +787,7 @@ void tmc2130_do_steps(uint8_t axis, uint16_t steps, uint8_t dir, uint16_t delay_
 void tmc2130_goto_step(uint8_t axis, uint8_t step, uint8_t dir, uint16_t delay_us, uint16_t microstep_resolution)
 {
 	printf_P(PSTR("tmc2130_goto_step %d %d %d %d \n"), axis, step, dir, delay_us, microstep_resolution);
-	uint8_t shift; for (shift = 0; shift < 8; shift++) if (microstep_resolution == (256 >> shift)) break;
+	uint8_t shift; for (shift = 0; shift < 8; shift++) if (microstep_resolution == (256u >> shift)) break;
 	uint16_t cnt = 4 * (1 << (8 - shift));
 	uint16_t mscnt = tmc2130_rd_MSCNT(axis);
 	if (dir == 2)
@@ -805,7 +799,7 @@ void tmc2130_goto_step(uint8_t axis, uint8_t step, uint8_t dir, uint16_t delay_u
 			dir ^= 1;
 			steps = -steps;
 		}
-		if (steps > (cnt / 2))
+		if (steps > static_cast<int>(cnt / 2))
 		{
 			dir ^= 1;
 			steps = cnt - steps;
@@ -830,7 +824,7 @@ void tmc2130_get_wave(uint8_t axis, uint8_t* data, FILE* stream)
 	tmc2130_setup_chopper(axis, tmc2130_usteps2mres(256), tmc2130_current_h[axis], tmc2130_current_r[axis]);
 	tmc2130_goto_step(axis, 0, 2, 100, 256);
 	tmc2130_set_dir(axis, tmc2130_get_inv(axis)?0:1);
-	for (int i = 0; i <= 255; i++)
+	for (unsigned int i = 0; i <= 255; i++)
 	{
 		uint32_t val = tmc2130_rd_MSCURACT(axis);
 		uint16_t mscnt = tmc2130_rd_MSCNT(axis);
@@ -847,6 +841,7 @@ void tmc2130_get_wave(uint8_t axis, uint8_t* data, FILE* stream)
 		delayMicroseconds(100);
 	}
 	tmc2130_setup_chopper(axis, tmc2130_mres[axis], tmc2130_current_h[axis], tmc2130_current_r[axis]);
+	tmc2130_set_pwr(axis, pwr);
 }
 
 void tmc2130_set_wave(uint8_t axis, uint8_t amp, uint8_t fac1000)
@@ -869,7 +864,7 @@ void tmc2130_set_wave(uint8_t axis, uint8_t amp, uint8_t fac1000)
 	int8_t b;                      //encoded bit value
     int8_t dA;                     //delta value
 	int i;                         //microstep index
-	uint32_t reg;                  //tmc2130 register
+	uint32_t reg = 0;              //tmc2130 register
 	tmc2130_wr_MSLUTSTART(axis, 0, amp);
 	for (i = 0; i < 256; i++)
 	{

+ 1 - 1
Firmware/tmc2130.h

@@ -53,7 +53,7 @@ extern tmc2130_chopper_config_t tmc2130_chopper_config[4];
 //initialize tmc2130
 extern void tmc2130_init();
 //check diag pins (called from stepper isr)
-extern void tmc2130_st_isr(uint8_t last_step_mask);
+extern void tmc2130_st_isr();
 //update stall guard (called from st_synchronize inside the loop)
 extern bool tmc2130_update_sg();
 //temperature watching (called from )

+ 2 - 2
Firmware/uart2.c

@@ -16,7 +16,7 @@ uint8_t uart2_ibuf[14] = {0, 0};
 FILE _uart2io = {0};
 
 
-int uart2_putchar(char c, FILE *stream)
+int uart2_putchar(char c, FILE *stream __attribute__((unused)))
 {
 	while (!uart2_txready);
 	UDR2 = c; // transmit byte
@@ -25,7 +25,7 @@ int uart2_putchar(char c, FILE *stream)
 	return 0;
 }
 
-int uart2_getchar(FILE *stream)
+int uart2_getchar(FILE *stream __attribute__((unused)))
 {
 	if (rbuf_empty(uart2_ibuf)) return -1;
 	return rbuf_get(uart2_ibuf);

+ 423 - 395
Firmware/ultralcd.cpp

@@ -1,3 +1,5 @@
+//! @file
+
 #include "temperature.h"
 #include "ultralcd.h"
 #include "fsensor.h"
@@ -44,8 +46,6 @@ char longFilenameOLD[LONG_FILENAME_LENGTH];
 
 static void lcd_sd_updir();
 
-
-
 int8_t ReInitLCD = 0;
 
 
@@ -111,20 +111,20 @@ static const char* lcd_display_message_fullscreen_nonBlocking_P(const char *msg,
 static void lcd_status_screen();
 static void lcd_language_menu();
 
-extern bool powersupply;
 static void lcd_main_menu();
 static void lcd_tune_menu();
-static void lcd_prepare_menu();
 //static void lcd_move_menu();
 static void lcd_settings_menu();
 static void lcd_calibration_menu();
+#ifdef LINEARITY_CORRECTION
+static void lcd_settings_menu_back();
+#endif //LINEARITY_CORRECTION
 static void lcd_control_temperature_menu();
 static void lcd_control_temperature_preheat_pla_settings_menu();
 static void lcd_control_temperature_preheat_abs_settings_menu();
 static void lcd_control_motion_menu();
 static void lcd_control_volumetric_menu();
 static void lcd_settings_linearity_correction_menu_save();
-
 static void prusa_stat_printerstatus(int _status);
 static void prusa_stat_farm_number();
 static void prusa_stat_temperatures();
@@ -139,11 +139,10 @@ static void lcd_menu_fails_stats();
 #endif //TMC2130 or FILAMENT_SENSOR
 
 static void lcd_selftest_v();
-static bool lcd_selfcheck_endstops();
 
 #ifdef TMC2130
-static void reset_crash_det(char axis);
-static bool lcd_selfcheck_axis_sg(char axis);
+static void reset_crash_det(unsigned char axis);
+static bool lcd_selfcheck_axis_sg(unsigned char axis);
 static bool lcd_selfcheck_axis(int _axis, int _travel);
 #else
 static bool lcd_selfcheck_endstops();
@@ -159,8 +158,13 @@ static bool lcd_selftest_fan_dialog(int _fan);
 static bool lcd_selftest_fsensor();
 static void lcd_selftest_error(int _error_no, const char *_error_1, const char *_error_2);
 static void lcd_colorprint_change();
+#ifdef SNMM
+static int get_ext_nr();
+#endif //SNMM
+#if defined (SNMM) || defined(SNMM_V2)
 static void fil_load_menu();
 static void fil_unload_menu();
+#endif // SNMM || SNMM_V2
 static void lcd_disable_farm_mode();
 static void lcd_set_fan_check();
 static char snmm_stop_print_menu();
@@ -170,11 +174,12 @@ static char snmm_stop_print_menu();
 static float count_e(float layer_heigth, float extrusion_width, float extrusion_length);
 static void lcd_babystep_z();
 static void lcd_send_status();
+#ifdef FARM_CONNECT_MESSAGE
 static void lcd_connect_printer();
+#endif //FARM_CONNECT_MESSAGE
 
 void lcd_finishstatus();
 
-static void lcd_control_retract_menu();
 static void lcd_sdcard_menu();
 
 #ifdef DELTA_CALIBRATION_MENU
@@ -183,8 +188,8 @@ static void lcd_delta_calibrate_menu();
 
 
 /* Different types of actions that can be used in menu items. */
-void menu_action_sdfile(const char* filename, char* longFilename);
-void menu_action_sddirectory(const char* filename, char* longFilename);
+static void menu_action_sdfile(const char* filename);
+static void menu_action_sddirectory(const char* filename);
 
 #define ENCODER_FEEDRATE_DEADZONE 10
 
@@ -227,7 +232,7 @@ bool wait_for_unclick;
 const char STR_SEPARATOR[] PROGMEM = "------------";
 
 
-void lcd_implementation_drawmenu_sdfile_selected(uint8_t row, const char* pstr, const char* filename, char* longFilename)
+static void lcd_implementation_drawmenu_sdfile_selected(uint8_t row, char* longFilename)
 {
     char c;
     int enc_dif = lcd_encoder_diff;
@@ -279,8 +284,7 @@ void lcd_implementation_drawmenu_sdfile_selected(uint8_t row, const char* pstr,
     while(n--)
         lcd_print(' ');
 }
-
-void lcd_implementation_drawmenu_sdfile(uint8_t row, const char* pstr, const char* filename, char* longFilename)
+static void lcd_implementation_drawmenu_sdfile(uint8_t row, const char* filename, char* longFilename)
 {
     char c;
     uint8_t n = LCD_WIDTH - 1;
@@ -300,7 +304,7 @@ void lcd_implementation_drawmenu_sdfile(uint8_t row, const char* pstr, const cha
     while(n--)
         lcd_print(' ');
 }
-void lcd_implementation_drawmenu_sddirectory_selected(uint8_t row, const char* pstr, const char* filename, char* longFilename)
+static void lcd_implementation_drawmenu_sddirectory_selected(uint8_t row, const char* filename, char* longFilename)
 {
     char c;
     uint8_t n = LCD_WIDTH - 2;
@@ -321,7 +325,7 @@ void lcd_implementation_drawmenu_sddirectory_selected(uint8_t row, const char* p
     while(n--)
         lcd_print(' ');
 }
-void lcd_implementation_drawmenu_sddirectory(uint8_t row, const char* pstr, const char* filename, char* longFilename)
+static void lcd_implementation_drawmenu_sddirectory(uint8_t row, const char* filename, char* longFilename)
 {
     char c;
     uint8_t n = LCD_WIDTH - 2;
@@ -345,7 +349,7 @@ void lcd_implementation_drawmenu_sddirectory(uint8_t row, const char* pstr, cons
 
 
 
-#define MENU_ITEM_SDDIR(str, str_fn, str_fnl) do { if (menu_item_sddir(str, str_fn, str_fnl)) return; } while (0)
+#define MENU_ITEM_SDDIR(str_fn, str_fnl) do { if (menu_item_sddir(str_fn, str_fnl)) return; } while (0)
 //#define MENU_ITEM_SDDIR(str, str_fn, str_fnl) MENU_ITEM(sddirectory, str, str_fn, str_fnl)
 //extern uint8_t menu_item_sddir(const char* str, const char* str_fn, char* str_fnl);
 
@@ -354,7 +358,7 @@ void lcd_implementation_drawmenu_sddirectory(uint8_t row, const char* pstr, cons
 //extern uint8_t menu_item_sdfile(const char* str, const char* str_fn, char* str_fnl);
 
 
-uint8_t menu_item_sddir(const char* str, const char* str_fn, char* str_fnl)
+uint8_t menu_item_sddir(const char* str_fn, char* str_fnl)
 {
 #ifdef NEW_SD_MENU
 //	str_fnl[18] = 0;
@@ -385,15 +389,15 @@ uint8_t menu_item_sddir(const char* str, const char* str_fn, char* str_fnl)
 		if (lcd_draw_update)
 		{
 			if (lcd_encoder == menu_item)
-				lcd_implementation_drawmenu_sddirectory_selected(menu_row, str, str_fn, str_fnl);
+				lcd_implementation_drawmenu_sddirectory_selected(menu_row, str_fn, str_fnl);
 			else
-				lcd_implementation_drawmenu_sddirectory(menu_row, str, str_fn, str_fnl);
+				lcd_implementation_drawmenu_sddirectory(menu_row, str_fn, str_fnl);
 		}
 		if (menu_clicked && (lcd_encoder == menu_item))
 		{
 			menu_clicked = false;
 			lcd_update_enabled = 0;
-			menu_action_sddirectory(str_fn, str_fnl);
+			menu_action_sddirectory(str_fn);
 			lcd_update_enabled = 1;
 			return menu_item_ret();
 		}
@@ -404,7 +408,11 @@ uint8_t menu_item_sddir(const char* str, const char* str_fn, char* str_fnl)
 #endif //NEW_SD_MENU
 }
 
-uint8_t menu_item_sdfile(const char* str, const char* str_fn, char* str_fnl)
+static uint8_t menu_item_sdfile(const char*
+#ifdef NEW_SD_MENU
+        str
+#endif //NEW_SD_MENU
+         ,const char* str_fn, char* str_fnl)
 {
 #ifdef NEW_SD_MENU
 //	printf_P(PSTR("menu sdfile\n"));
@@ -451,13 +459,14 @@ uint8_t menu_item_sdfile(const char* str, const char* str_fn, char* str_fnl)
 		if (lcd_draw_update)
 		{
 			if (lcd_encoder == menu_item)
-				lcd_implementation_drawmenu_sdfile_selected(menu_row, str, str_fn, str_fnl);
+				lcd_implementation_drawmenu_sdfile_selected(menu_row, str_fnl);
 			else
-				lcd_implementation_drawmenu_sdfile(menu_row, str, str_fn, str_fnl);
+				lcd_implementation_drawmenu_sdfile(menu_row, str_fn, str_fnl);
 		}
 		if (menu_clicked && (lcd_encoder == menu_item))
 		{
-			menu_action_sdfile(str_fn, str_fnl);
+		    lcd_consume_click();
+			menu_action_sdfile(str_fn);
 			return menu_item_ret();
 		}
 	}
@@ -476,12 +485,10 @@ void lcdui_print_temp(char type, int val_current, int val_target)
 // Print Z-coordinate (8 chars total)
 void lcdui_print_Z_coord(void)
 {
-	int chars = 8;
     if (custom_message_type == CUSTOM_MSG_TYPE_MESHBL)
         lcd_puts_P(_N("Z   --- "));
     else
-		chars = lcd_printf_P(_N("Z%6.2f "), current_position[Z_AXIS]);
-//	lcd_space(8 - chars);
+		lcd_printf_P(_N("Z%6.2f "), current_position[Z_AXIS]);
 }
 
 #ifdef PLANNER_DIAGNOSTICS
@@ -521,8 +528,7 @@ void lcdui_print_percent_done(void)
 	char per[4];
 	bool num = IS_SD_PRINTING || (PRINTER_ACTIVE && (print_percent_done_normal != PRINT_PERCENT_DONE_INIT));
 	sprintf_P(per, num?_N("%3hhd"):_N("---"), calc_percent_done());
-	int chars = lcd_printf_P(_N("%3S%3s%%"), src, per);
-//	lcd_space(7 - chars);
+	lcd_printf_P(_N("%3S%3s%%"), src, per);
 }
 
 // Print extruder status (5 chars total)
@@ -968,86 +974,15 @@ void lcd_commands()
 {	
 	if (lcd_commands_type == LCD_COMMAND_LONG_PAUSE)
 	{
-		if(lcd_commands_step == 0) {
-			if (card.sdprinting) {
-				card.pauseSDPrint();
-				lcd_setstatuspgm(_T(MSG_FINISHING_MOVEMENTS));
-				lcd_draw_update = 3;
-				lcd_commands_step = 1;
-			}
-			else {
-				lcd_commands_type = 0;
-			}
-		}
-		if (lcd_commands_step == 1 && !blocks_queued() && !homing_flag) {
+		if (!blocks_queued() && !homing_flag)
+		{
 			lcd_setstatuspgm(_i("Print paused"));////MSG_PRINT_PAUSED c=20 r=1
-			isPrintPaused = true;
 			long_pause();
 			lcd_commands_type = 0;
 			lcd_commands_step = 0;
 		}
-
 	}
 
-	if (lcd_commands_type == LCD_COMMAND_LONG_PAUSE_RESUME) {
-		char cmd1[30];
-		if (lcd_commands_step == 0) {
-
-			lcd_draw_update = 3;
-			lcd_commands_step = 4;
-		}
-		if (lcd_commands_step == 1 && !blocks_queued() && cmd_buffer_empty()) {	//recover feedmultiply; cmd_buffer_empty() ensures that card.sdprinting is synchronized with buffered commands and thus print cant be paused until resume is finished
-			
-			sprintf_P(cmd1, PSTR("M220 S%d"), saved_feedmultiply);
-			enquecommand(cmd1);
-			isPrintPaused = false;
-			pause_time += (millis() - start_pause_print); //accumulate time when print is paused for correct statistics calculation
-			card.startFileprint();
-			lcd_commands_step = 0;
-			lcd_commands_type = 0;
-		}
-		if (lcd_commands_step == 2 && !blocks_queued()) {	//turn on fan, move Z and unretract
-			
-			sprintf_P(cmd1, PSTR("M106 S%d"), fanSpeedBckp);
-			enquecommand(cmd1);
-			strcpy(cmd1, "G1 Z");
-			strcat(cmd1, ftostr32(pause_lastpos[Z_AXIS]));
-			enquecommand(cmd1);
-			
-			if (axis_relative_modes[3] == false) {
-				enquecommand_P(PSTR("M83")); // set extruder to relative mode
-			enquecommand_P(PSTR("G1 E"  STRINGIFY(default_retraction))); //unretract
-				enquecommand_P(PSTR("M82")); // set extruder to absolute mode
-			}
-			else {
-				enquecommand_P(PSTR("G1 E"  STRINGIFY(default_retraction))); //unretract
-			}
-			
-			lcd_commands_step = 1;
-		}
-		if (lcd_commands_step == 3 && !blocks_queued()) {	//wait for nozzle to reach target temp
-			
-			strcpy(cmd1, "M109 S");
-			strcat(cmd1, ftostr3(HotendTempBckp));
-			enquecommand(cmd1);			
-			lcd_commands_step = 2;
-		}
-		if (lcd_commands_step == 4 && !blocks_queued()) {	//set temperature back and move xy
-			
-			strcpy(cmd1, "M104 S");
-			strcat(cmd1, ftostr3(HotendTempBckp));
-			enquecommand(cmd1);
-			enquecommand_P(PSTR("G90")); //absolute positioning
-			strcpy(cmd1, "G1 X");
-			strcat(cmd1, ftostr32(pause_lastpos[X_AXIS]));
-			strcat(cmd1, " Y");
-			strcat(cmd1, ftostr32(pause_lastpos[Y_AXIS]));
-			enquecommand(cmd1);
-			
-			lcd_setstatuspgm(_T(MSG_RESUMING_PRINT));
-			lcd_commands_step = 3;
-		}
-	}
 
 #ifdef SNMM
 	if (lcd_commands_type == LCD_COMMAND_V2_CAL)
@@ -1307,7 +1242,7 @@ void lcd_commands()
 			lcd_commands_step = 0;
 			lcd_commands_type = 0;
 			if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE) == 1) {
-				lcd_wizard(10);
+				lcd_wizard(WizState::RepeatLay1Cal);
 			}
 		}
 
@@ -1318,43 +1253,101 @@ void lcd_commands()
 	if (lcd_commands_type == LCD_COMMAND_V2_CAL)
 	{
 		char cmd1[30];
+		uint8_t filament = 0;
 		float width = 0.4;
 		float length = 20 - width;
 		float extr = count_e(0.2, width, length);
 		float extr_short_segment = count_e(0.2, width, width);
 		if(lcd_commands_step>1) lcd_timeoutToStatus.start(); //if user dont confirm live adjust Z value by pressing the knob, we are saving last value by timeout to status screen
-		if (lcd_commands_step == 0)
+
+		if (lcd_commands_step == 0 && !blocks_queued() && cmd_buffer_empty())
 		{
-			lcd_commands_step = 9;
+			lcd_commands_step = 10;
 		}
-		if (lcd_commands_step == 9 && !blocks_queued() && cmd_buffer_empty())
+		if (lcd_commands_step == 20 && !blocks_queued() && cmd_buffer_empty())
+		{
+            filament = 0;
+            lcd_commands_step = 10;
+		}
+        if (lcd_commands_step == 21 && !blocks_queued() && cmd_buffer_empty())
+        {
+            filament = 1;
+            lcd_commands_step = 10;
+        }
+        if (lcd_commands_step == 22 && !blocks_queued() && cmd_buffer_empty())
+        {
+            filament = 2;
+            lcd_commands_step = 10;
+        }
+        if (lcd_commands_step == 23 && !blocks_queued() && cmd_buffer_empty())
+        {
+            filament = 3;
+            lcd_commands_step = 10;
+        }
+        if (lcd_commands_step == 24 && !blocks_queued() && cmd_buffer_empty())
+        {
+            filament = 4;
+            lcd_commands_step = 10;
+        }
+
+		if (lcd_commands_step == 10)
 		{
 			enquecommand_P(PSTR("M107"));
 			enquecommand_P(PSTR("M104 S" STRINGIFY(PLA_PREHEAT_HOTEND_TEMP)));
 			enquecommand_P(PSTR("M140 S" STRINGIFY(PLA_PREHEAT_HPB_TEMP)));
+            if (mmu_enabled)
+            {
+                strcpy(cmd1, "T");
+                strcat(cmd1, itostr3left(filament));
+                enquecommand(cmd1);
+            }
 			enquecommand_P(PSTR("M190 S" STRINGIFY(PLA_PREHEAT_HPB_TEMP)));
 			enquecommand_P(PSTR("M109 S" STRINGIFY(PLA_PREHEAT_HOTEND_TEMP)));
 			enquecommand_P(_T(MSG_M117_V2_CALIBRATION));
-			if (mmu_enabled)
-				enquecommand_P(PSTR("T?"));
 			enquecommand_P(PSTR("G28"));
 			enquecommand_P(PSTR("G92 E0.0"));
-			lcd_commands_step = 8;
+
+            lcd_commands_step = 9;
 		}
+        if (lcd_commands_step == 9 && !blocks_queued() && cmd_buffer_empty())
+        {
+            lcd_clear();
+            menu_depth = 0;
+            menu_submenu(lcd_babystep_z);
+
+            if (mmu_enabled)
+            {
+                enquecommand_P(PSTR("M83")); //intro line
+                enquecommand_P(PSTR("G1 Y-3.0 F1000.0")); //intro line
+                enquecommand_P(PSTR("G1 Z0.4 F1000.0")); //intro line
+                enquecommand_P(PSTR("G1 X55.0 E32.0 F1073.0")); //intro line
+                enquecommand_P(PSTR("G1 X5.0 E32.0 F1800.0")); //intro line
+                enquecommand_P(PSTR("G1 X55.0 E8.0 F2000.0")); //intro line
+                enquecommand_P(PSTR("G1 Z0.3 F1000.0")); //intro line
+                enquecommand_P(PSTR("G92 E0.0")); //intro line
+                enquecommand_P(PSTR("G1 X240.0 E25.0  F2200.0")); //intro line
+                enquecommand_P(PSTR("G1 Y-2.0 F1000.0")); //intro line
+                enquecommand_P(PSTR("G1 X55.0 E25 F1400.0")); //intro line
+                enquecommand_P(PSTR("G1 Z0.20 F1000.0")); //intro line
+                enquecommand_P(PSTR("G1 X5.0 E4.0 F1000.0")); //intro line
+
+            } else
+            {
+                enquecommand_P(PSTR("G1 X60.0 E9.0 F1000.0")); //intro line
+                enquecommand_P(PSTR("G1 X100.0 E12.5 F1000.0")); //intro line
+            }
+
+            lcd_commands_step = 8;
+        }
 		if (lcd_commands_step == 8 && !blocks_queued() && cmd_buffer_empty())
 		{
 
-			lcd_clear();
-			menu_depth = 0;
-			menu_submenu(lcd_babystep_z);
-			enquecommand_P(PSTR("G1 X60.0 E9.0 F1000.0")); //intro line
-			enquecommand_P(PSTR("G1 X100.0 E12.5 F1000.0")); //intro line			
 			enquecommand_P(PSTR("G92 E0.0"));
 			enquecommand_P(PSTR("G21")); //set units to millimeters
 			enquecommand_P(PSTR("G90")); //use absolute coordinates
 			enquecommand_P(PSTR("M83")); //use relative distances for extrusion
 			enquecommand_P(PSTR("G1 E-1.50000 F2100.00000"));
-			enquecommand_P(PSTR("G1 Z0.150 F7200.000"));
+			enquecommand_P(PSTR("G1 Z5 F7200.000"));
 			enquecommand_P(PSTR("M204 S1000")); //set acceleration
 			enquecommand_P(PSTR("G1 F4000"));
 			lcd_commands_step = 7;
@@ -1384,6 +1377,7 @@ void lcd_commands()
 
 
 			enquecommand_P(PSTR("G1 X50 Y155"));
+			enquecommand_P(PSTR("G1 Z0.150 F7200.000"));
 			enquecommand_P(PSTR("G1 F1080"));
 			enquecommand_P(PSTR("G1 X75 Y155 E2.5"));
 			enquecommand_P(PSTR("G1 X100 Y155 E2"));
@@ -1544,7 +1538,7 @@ void lcd_commands()
 			lcd_commands_step = 0;
 			lcd_commands_type = 0;			
 			if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE) == 1) {
-				lcd_wizard(10);
+				lcd_wizard(WizState::RepeatLay1Cal);
 			}
 		}
 
@@ -1752,18 +1746,19 @@ void lcd_return_to_status()
 	menu_depth = 0;
 }
 
-
-void lcd_sdcard_pause() {
-	lcd_return_to_status();
-	lcd_commands_type = LCD_COMMAND_LONG_PAUSE;
-
+//! @brief Pause print, disable nozzle heater, move to park position
+void lcd_pause_print()
+{
+    lcd_return_to_status();
+    stop_and_save_print_to_ram(0.0,0.0);
+    setAllTargetHotends(0);
+    isPrintPaused = true;
+    if (LCD_COMMAND_IDLE == lcd_commands_type)
+    {
+        lcd_commands_type = LCD_COMMAND_LONG_PAUSE;
+    }
 }
 
-static void lcd_sdcard_resume() {
-	lcd_return_to_status();
-	lcd_reset_alert_level(); //for fan speed error
-	lcd_commands_type = LCD_COMMAND_LONG_PAUSE_RESUME;
-}
 
 float move_menu_scale;
 static void lcd_move_menu_axis();
@@ -1793,55 +1788,61 @@ void lcd_preheat_farm_nozzle()
 void lcd_preheat_pla()
 {
   setTargetHotend0(PLA_PREHEAT_HOTEND_TEMP);
-  setTargetBed(PLA_PREHEAT_HPB_TEMP);
+  if (!wizard_active) setTargetBed(PLA_PREHEAT_HPB_TEMP);
   fanSpeed = 0;
   lcd_return_to_status();
   setWatch(); // heater sanity check timer
+  if (wizard_active) lcd_wizard(WizState::Unload);
 }
 
 void lcd_preheat_abs()
 {
   setTargetHotend0(ABS_PREHEAT_HOTEND_TEMP);
-  setTargetBed(ABS_PREHEAT_HPB_TEMP);
+  if (!wizard_active) setTargetBed(ABS_PREHEAT_HPB_TEMP);
   fanSpeed = 0;
   lcd_return_to_status();
   setWatch(); // heater sanity check timer
+  if (wizard_active) lcd_wizard(WizState::Unload);
 }
 
 void lcd_preheat_pp()
 {
   setTargetHotend0(PP_PREHEAT_HOTEND_TEMP);
-  setTargetBed(PP_PREHEAT_HPB_TEMP);
+  if (!wizard_active) setTargetBed(PP_PREHEAT_HPB_TEMP);
   fanSpeed = 0;
   lcd_return_to_status();
   setWatch(); // heater sanity check timer
+  if (wizard_active) lcd_wizard(WizState::Unload);
 }
 
 void lcd_preheat_pet()
 {
   setTargetHotend0(PET_PREHEAT_HOTEND_TEMP);
-  setTargetBed(PET_PREHEAT_HPB_TEMP);
+  if (!wizard_active) setTargetBed(PET_PREHEAT_HPB_TEMP);
   fanSpeed = 0;
   lcd_return_to_status();
   setWatch(); // heater sanity check timer
+  if (wizard_active) lcd_wizard(WizState::Unload);
 }
 
 void lcd_preheat_hips()
 {
   setTargetHotend0(HIPS_PREHEAT_HOTEND_TEMP);
-  setTargetBed(HIPS_PREHEAT_HPB_TEMP);
+  if (!wizard_active) setTargetBed(HIPS_PREHEAT_HPB_TEMP);
   fanSpeed = 0;
   lcd_return_to_status();
   setWatch(); // heater sanity check timer
+  if (wizard_active) lcd_wizard(WizState::Unload);
 }
 
 void lcd_preheat_flex()
 {
   setTargetHotend0(FLEX_PREHEAT_HOTEND_TEMP);
-  setTargetBed(FLEX_PREHEAT_HPB_TEMP);
+  if (!wizard_active) setTargetBed(FLEX_PREHEAT_HPB_TEMP);
   fanSpeed = 0;
   lcd_return_to_status();
   setWatch(); // heater sanity check timer
+  if (wizard_active) lcd_wizard(WizState::Unload);
 }
 
 
@@ -2067,7 +2068,7 @@ static void lcd_preheat_menu()
 {
   MENU_BEGIN();
 
-  MENU_ITEM_BACK_P(_T(MSG_MAIN));
+  if (!wizard_active) MENU_ITEM_BACK_P(_T(MSG_MAIN));
 
   if (farm_mode) {
 	  MENU_ITEM_FUNCTION_P(PSTR("farm   -  " STRINGIFY(FARM_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(FARM_PREHEAT_HPB_TEMP)), lcd_preheat_farm);
@@ -2081,7 +2082,7 @@ static void lcd_preheat_menu()
 	  MENU_ITEM_FUNCTION_P(PSTR("HIPS -  " STRINGIFY(HIPS_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(HIPS_PREHEAT_HPB_TEMP)), lcd_preheat_hips);
 	  MENU_ITEM_FUNCTION_P(PSTR("PP   -  " STRINGIFY(PP_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(PP_PREHEAT_HPB_TEMP)), lcd_preheat_pp);
 	  MENU_ITEM_FUNCTION_P(PSTR("FLEX -  " STRINGIFY(FLEX_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(FLEX_PREHEAT_HPB_TEMP)), lcd_preheat_flex);
-	  MENU_ITEM_FUNCTION_P(_T(MSG_COOLDOWN), lcd_cooldown);
+	  if (!wizard_active) MENU_ITEM_FUNCTION_P(_T(MSG_COOLDOWN), lcd_cooldown);
   }
   
 
@@ -2467,7 +2468,6 @@ void lcd_menu_statistics()
 	if (IS_SD_PRINTING)
 	{
 		float _met = ((float)total_filament_used) / (100000.f);
-		int _cm = (total_filament_used - (_met * 100000)) / 10;
 		int _t = (millis() - starttime) / 1000;
 		int _h = _t / 3600;
 		int _m = (_t - (_h * 3600)) / 60;
@@ -2810,15 +2810,6 @@ static void _lcd_babystep(int axis, const char *msg)
 	if (LCD_CLICKED) menu_back();
 }
 
-static void lcd_babystep_x()
-{
-  _lcd_babystep(X_AXIS, (_i("Babystepping X")));////MSG_BABYSTEPPING_X c=0 r=0
-}
-
-static void lcd_babystep_y()
-{
-  _lcd_babystep(Y_AXIS, (_i("Babystepping Y")));////MSG_BABYSTEPPING_Y c=0 r=0
-}
 
 static void lcd_babystep_z()
 {
@@ -3254,6 +3245,7 @@ const char* lcd_display_message_fullscreen_P(const char *msg)
  */
 void lcd_show_fullscreen_message_and_wait_P(const char *msg)
 {
+    LcdUpdateDisabler lcdUpdateDisabler;
     const char *msg_next = lcd_display_message_fullscreen_P(msg);
     bool multi_screen = msg_next != NULL;
 	lcd_set_custom_characters_nextpage();
@@ -3269,9 +3261,6 @@ void lcd_show_fullscreen_message_and_wait_P(const char *msg)
         for (uint8_t i = 0; i < 100; ++ i) {
             delay_keep_alive(50);
             if (lcd_clicked()) {
-                while (lcd_clicked()) ;
-                delay(10);
-                while (lcd_clicked()) ;
 				if (msg_next == NULL) {
 					KEEPALIVE_STATE(IN_HANDLER);
 					lcd_set_custom_characters();
@@ -3305,20 +3294,38 @@ void lcd_wait_for_click()
         manage_heater();
         manage_inactivity(true);
         if (lcd_clicked()) {
-            while (lcd_clicked()) ;
-            delay(10);
-            while (lcd_clicked()) ;
 			KEEPALIVE_STATE(IN_HANDLER);
             return;
         }
     }
 }
 
+//! @brief Show multiple screen message with yes and no possible choices and wait with possible timeout
+//! @param msg Message to show
+//! @param allow_timeouting if true, allows time outing of the screen
+//! @param default_yes if true, yes choice is selected by default, otherwise no choice is preselected
+//! @retval 1 yes choice selected by user
+//! @retval 0 no choice selected by user
+//! @retval -1 screen timed out
 int8_t lcd_show_multiscreen_message_yes_no_and_wait_P(const char *msg, bool allow_timeouting, bool default_yes) //currently just max. n*4 + 3 lines supported (set in language header files)
+{
+    return lcd_show_multiscreen_message_two_choices_and_wait_P(msg, allow_timeouting, default_yes, _T(MSG_YES), _T(MSG_NO));
+}
+//! @brief Show multiple screen message with two possible choices and wait with possible timeout
+//! @param msg Message to show
+//! @param allow_timeouting if true, allows time outing of the screen
+//! @param default_first if true, fist choice is selected by default, otherwise second choice is preselected
+//! @param first_choice text caption of first possible choice
+//! @param second_choice text caption of second possible choice
+//! @retval 1 first choice selected by user
+//! @retval 0 second choice selected by user
+//! @retval -1 screen timed out
+int8_t lcd_show_multiscreen_message_two_choices_and_wait_P(const char *msg, bool allow_timeouting, bool default_first,
+        const char *first_choice, const char *second_choice)
 {
 	const char *msg_next = lcd_display_message_fullscreen_P(msg);
 	bool multi_screen = msg_next != NULL;
-	bool yes = default_yes ? true : false;
+	bool yes = default_first ? true : false;
 
 	// Wait for user confirmation or a timeout.
 	unsigned long previous_millis_cmd = millis();
@@ -3354,9 +3361,6 @@ int8_t lcd_show_multiscreen_message_yes_no_and_wait_P(const char *msg, bool allo
 				}
 			}
 			if (lcd_clicked()) {
-				while (lcd_clicked());
-				delay(10);
-				while (lcd_clicked());
 				if (msg_next == NULL) {
 					//KEEPALIVE_STATE(IN_HANDLER);
 					lcd_set_custom_characters();
@@ -3375,15 +3379,22 @@ int8_t lcd_show_multiscreen_message_yes_no_and_wait_P(const char *msg, bool allo
 			lcd_set_cursor(0, 3);
 			if (yes) lcd_puts_P(PSTR(">"));
 			lcd_set_cursor(1, 3);
-			lcd_puts_P(_T(MSG_YES));
+			lcd_puts_P(first_choice);
 			lcd_set_cursor(7, 3);
 			if (!yes) lcd_puts_P(PSTR(">"));
 			lcd_set_cursor(8, 3);
-			lcd_puts_P(_T(MSG_NO));
+			lcd_puts_P(second_choice);
 		}
 	}
 }
 
+//! @brief Show single screen message with yes and no possible choices and wait with possible timeout
+//! @param msg Message to show
+//! @param allow_timeouting if true, allows time outing of the screen
+//! @param default_yes if true, yes choice is selected by default, otherwise no choice is preselected
+//! @retval 1 yes choice selected by user
+//! @retval 0 no choice selected by user
+//! @retval -1 screen timed out
 int8_t lcd_show_fullscreen_message_yes_no_and_wait_P(const char *msg, bool allow_timeouting, bool default_yes)
 {
 
@@ -3431,16 +3442,13 @@ int8_t lcd_show_fullscreen_message_yes_no_and_wait_P(const char *msg, bool allow
 				enc_dif = lcd_encoder_diff;
 		}
 		if (lcd_clicked()) {
-			while (lcd_clicked());
-			delay(10);
-			while (lcd_clicked());
 			KEEPALIVE_STATE(IN_HANDLER);
 			return yes;
 		}
 	}
 }
 
-void lcd_bed_calibration_show_result(uint8_t result, uint8_t point_too_far_mask)
+void lcd_bed_calibration_show_result(BedSkewOffsetDetectionResultType result, uint8_t point_too_far_mask)
 {
     const char *msg = NULL;
     if (result == BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND) {
@@ -3532,26 +3540,24 @@ static void lcd_show_end_stops() {
 	lcd_puts_P((READ(Z_MIN_PIN) ^ (bool)Z_MIN_ENDSTOP_INVERTING) ? (PSTR("Z1")) : (PSTR("Z0")));
 }
 
+#ifndef TMC2130
 static void menu_show_end_stops() {
     lcd_show_end_stops();
     if (LCD_CLICKED) menu_back();
 }
+#endif // not defined TMC2130
 
 // 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.
 void lcd_diag_show_end_stops()
 {
-    int enc_dif = lcd_encoder_diff;
     lcd_clear();
     for (;;) {
         manage_heater();
         manage_inactivity(true);
         lcd_show_end_stops();
         if (lcd_clicked()) {
-            while (lcd_clicked()) ;
-            delay(10);
-            while (lcd_clicked()) ;
             break;
         }
     }
@@ -4295,7 +4301,14 @@ void lcd_toshiba_flash_air_compatibility_toggle()
 void lcd_v2_calibration()
 {
 	if (mmu_enabled)
-		lcd_commands_type = LCD_COMMAND_V2_CAL;
+	{
+	    const uint8_t filament = choose_menu_P(_i("Select PLA filament:"),_T(MSG_FILAMENT),_i("Cancel")); ////c=20 r=1  ////c=19 r=1
+	    if (filament < 5)
+	    {
+	        lcd_commands_step = 20 + filament;
+	        lcd_commands_type = LCD_COMMAND_V2_CAL;
+	    }
+	}
 	else
 	{
 		bool loaded = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Is PLA filament loaded?"), false, true);////MSG_PLA_FILAMENT_LOADED c=20 r=2
@@ -4307,9 +4320,6 @@ void lcd_v2_calibration()
 			for (int i = 0; i < 20; i++) { //wait max. 2s
 				delay_keep_alive(100);
 				if (lcd_clicked()) {
-					while (lcd_clicked());
-					delay(10);
-					while (lcd_clicked());
 					break;
 				}
 			}
@@ -4326,7 +4336,7 @@ void lcd_wizard() {
 	}
 	if (result) {
 		calibration_status_store(CALIBRATION_STATUS_ASSEMBLED);
-		lcd_wizard(0);
+		lcd_wizard(WizState::Run);
 	}
 	else {
 		lcd_return_to_status();
@@ -4355,19 +4365,67 @@ void lcd_language()
 		lang_select(LANG_ID_PRI);
 }
 
-void lcd_wizard(int state) {
+static void wait_preheat()
+{
+    current_position[Z_AXIS] = 100; //move in z axis to make space for loading filament
+    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);
+    delay_keep_alive(2000);
+    lcd_display_message_fullscreen_P(_T(MSG_WIZARD_HEATING));
+    while (abs(degHotend(0) - degTargetHotend(0)) > 3) {
+        lcd_display_message_fullscreen_P(_T(MSG_WIZARD_HEATING));
 
+        lcd_set_cursor(0, 4);
+        lcd_print(LCD_STR_THERMOMETER[0]);
+        lcd_print(ftostr3(degHotend(0)));
+        lcd_print("/");
+        lcd_print(degTargetHotend(0));
+        lcd_print(LCD_STR_DEGREE);
+        lcd_set_custom_characters();
+        delay_keep_alive(1000);
+    }
+}
+
+//! @brief Printer first run wizard (Selftest and calibration)
+//!
+//!
+//! First layer calibration with MMU state diagram
+//!
+//! @startuml
+//! [*] --> IsFil
+//! IsFil : Is filament 1 loaded?
+//! isPLA : Is filament 1 PLA?
+//! unload : Eject or Unload?
+//! load : Push the button to start loading PLA Filament 1
+//!
+//! IsFil --> isPLA   : yes
+//! IsFil --> load    : no
+//! isPLA --> unload     : no
+//! unload --> load      : eject
+//! unload --> load      : unload
+//! load --> calibration : click
+//! isPLA --> calibration : yes
+//! @enduml
+//!
+//! @param state Entry point of the wizard
+//!
+//!   state                 | description
+//!  ---------------------- | ----------------
+//! WizState::Run           | Main entry point
+//! WizState::RepeatLay1Cal | Entry point after passing 1st layer calibration
+void lcd_wizard(WizState state)
+{
+    using S = WizState;
 	bool end = false;
 	int wizard_event;
 	const char *msg = NULL;
 	while (!end) {
 		printf_P(PSTR("Wizard state: %d"), state);
 		switch (state) {
-		case 0: // run wizard?
+		case S::Run: //Run wizard?
 			wizard_active = true;
 			wizard_event = lcd_show_multiscreen_message_yes_no_and_wait_P(_i("Hi, I am your Original Prusa i3 printer. Would you like me to guide you through the setup process?"), false, true);////MSG_WIZARD_WELCOME c=20 r=7
 			if (wizard_event) {
-				state = 1;
+				state = S::Restore;
 				eeprom_write_byte((uint8_t*)EEPROM_WIZARD_ACTIVE, 1);
 			}
 			else {
@@ -4375,72 +4433,97 @@ void lcd_wizard(int state) {
 				end = true;
 			}
 			break;
-		case 1: // restore calibration status
+		case S::Restore: // restore calibration status
 			switch (calibration_status()) {
-			case CALIBRATION_STATUS_ASSEMBLED: state = 2; break; //run selftest
-			case CALIBRATION_STATUS_XYZ_CALIBRATION: state = 3; break; //run xyz cal.
-			case CALIBRATION_STATUS_Z_CALIBRATION: state = 4; break; //run z cal.
-			case CALIBRATION_STATUS_LIVE_ADJUST: state = 5; break; //run live adjust
+			case CALIBRATION_STATUS_ASSEMBLED: state = S::Selftest; break; //run selftest
+			case CALIBRATION_STATUS_XYZ_CALIBRATION: state = S::Xyz; break; //run xyz cal.
+			case CALIBRATION_STATUS_Z_CALIBRATION: state = S::Z; break; //run z cal.
+			case CALIBRATION_STATUS_LIVE_ADJUST: state = S::IsFil; break; //run live adjust
 			case CALIBRATION_STATUS_CALIBRATED: end = true; eeprom_write_byte((uint8_t*)EEPROM_WIZARD_ACTIVE, 0); break;
-			default: state = 2; break; //if calibration status is unknown, run wizard from the beginning
+			default: state = S::Selftest; break; //if calibration status is unknown, run wizard from the beginning
 			}
 			break; 
-		case 2: //selftest
+		case S::Selftest:
 			lcd_show_fullscreen_message_and_wait_P(_i("First, I will run the selftest to check most common assembly problems."));////MSG_WIZARD_SELFTEST c=20 r=8
 			wizard_event = lcd_selftest();
 			if (wizard_event) {
 				calibration_status_store(CALIBRATION_STATUS_XYZ_CALIBRATION);
-				state = 3;
+				state = S::Xyz;
 			}
 			else end = true;
 			break;
-		case 3: //xyz cal.
+		case S::Xyz: //xyz calibration
 			lcd_show_fullscreen_message_and_wait_P(_i("I will run xyz calibration now. It will take approx. 12 mins."));////MSG_WIZARD_XYZ_CAL c=20 r=8
 			wizard_event = gcode_M45(false, 0);
-			if (wizard_event) state = 5;
+			if (wizard_event) state = S::IsFil;
 			else end = true;
 			break;
-		case 4: //z cal.
+		case S::Z: //z calibration
 			lcd_show_fullscreen_message_and_wait_P(_i("I will run z calibration now."));////MSG_WIZARD_Z_CAL c=20 r=8
 			wizard_event = lcd_show_fullscreen_message_yes_no_and_wait_P(_T(MSG_STEEL_SHEET_CHECK), false, false);
 			if (!wizard_event) lcd_show_fullscreen_message_and_wait_P(_T(MSG_PLACE_STEEL_SHEET));
 			wizard_event = gcode_M45(true, 0);
-			if (wizard_event) state = 11; //shipped, no need to set first layer, go to final message directly
+			if (wizard_event) state = S::Finish; //shipped, no need to set first layer, go to final message directly
 			else end = true;
 			break;
-		case 5: //is filament loaded?
+		case S::IsFil: //is filament loaded?
 				//start to preheat nozzle and bed to save some time later
 			setTargetHotend(PLA_PREHEAT_HOTEND_TEMP, 0);
 			setTargetBed(PLA_PREHEAT_HPB_TEMP);
-			wizard_event = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Is filament loaded?"), false);////MSG_WIZARD_FILAMENT_LOADED c=20 r=2
-			if (wizard_event) state = 8;
-			else state = 6;
-
+			if (mmu_enabled)
+			{
+			    wizard_event = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Is filament 1 loaded?"), false);////c=20 r=2
+			} else
+			{
+			    wizard_event = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Is filament loaded?"), false);////MSG_WIZARD_FILAMENT_LOADED c=20 r=2
+			}
+			if (wizard_event) state = S::IsPla;
+			else
+			{
+			    if(mmu_enabled) state = S::LoadFil;
+			    else state = S::PreheatPla;
+			}
 			break;
-		case 6: //waiting for preheat nozzle for PLA;
+		case S::PreheatPla:
 #ifndef SNMM
-			lcd_display_message_fullscreen_P(_i("Now I will preheat nozzle for PLA."));////MSG_WIZARD_WILL_PREHEAT c=20 r=4
-			current_position[Z_AXIS] = 100; //move in z axis to make space for loading filament
-			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);
-			delay_keep_alive(2000);
-			lcd_display_message_fullscreen_P(_T(MSG_WIZARD_HEATING));
-			while (abs(degHotend(0) - PLA_PREHEAT_HOTEND_TEMP) > 3) {
-				lcd_display_message_fullscreen_P(_T(MSG_WIZARD_HEATING));
-
-				lcd_set_cursor(0, 4);
-				lcd_print(LCD_STR_THERMOMETER[0]);
-				lcd_print(ftostr3(degHotend(0)));
-				lcd_print("/");
-				lcd_print(PLA_PREHEAT_HOTEND_TEMP);
-				lcd_print(LCD_STR_DEGREE);
-				lcd_set_custom_characters();
-				delay_keep_alive(1000);
-			}
+		    lcd_display_message_fullscreen_P(_i("Now I will preheat nozzle for PLA."));////MSG_WIZARD_WILL_PREHEAT c=20 r=4
+		    wait_preheat();
 #endif //not SNMM
-			state = 7;
+			state = S::LoadFil;
 			break;
-		case 7: //load filament 
-			lcd_show_fullscreen_message_and_wait_P(_i("Please insert PLA filament to the extruder, then press knob to load it."));////MSG_WIZARD_LOAD_FILAMENT c=20 r=8
+		case S::Preheat:
+		    menu_goto(lcd_preheat_menu,0,false,true);
+		    lcd_show_fullscreen_message_and_wait_P(_i("Select nozzle preheat temperature which matches your material."));
+		    end = true; // Leave wizard temporarily for lcd_preheat_menu
+		    break;
+		case S::Unload:
+		    wait_preheat();
+            if(mmu_enabled)
+            {
+                int8_t unload = lcd_show_multiscreen_message_two_choices_and_wait_P(
+                        _i("Use unload to remove filament 1 if it protrudes outside of the rear MMU tube. Use eject if it is hidden in tube.")
+                        ,false, true, _i("Unload"), _i("Eject"));
+                if (unload)
+                {
+                    extr_unload_0();
+                } else
+                {
+                    mmu_eject_fil_0();
+                }
+            } else
+            {
+                unload_filament();
+            }
+            state = S::LoadFil;
+            break;
+		case S::LoadFil: //load filament
+		    if (mmu_enabled)
+		    {
+		        lcd_show_fullscreen_message_and_wait_P(_i("Please insert PLA filament to the first tube of MMU, then press the knob to load it."));////c=20 r=8
+		    } else
+		    {
+			    lcd_show_fullscreen_message_and_wait_P(_i("Please insert PLA filament to the extruder, then press knob to load it."));////MSG_WIZARD_LOAD_FILAMENT c=20 r=8
+		    }
 			lcd_update_enable(false);
 			lcd_clear();
 			lcd_puts_at_P(0, 2, _T(MSG_LOADING_FILAMENT));
@@ -4449,30 +4532,31 @@ void lcd_wizard(int state) {
 #endif
             loading_flag = true;
 			gcode_M701();
-			state = 9;
+			state = S::Lay1Cal;
 			break;
-		case 8:
+		case S::IsPla:
 			wizard_event = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Is it PLA filament?"), false, true);////MSG_WIZARD_PLA_FILAMENT c=20 r=2
-			if (wizard_event) state = 9;
-			else end = true;
+			if (wizard_event) state = S::Lay1Cal;
+			else state = S::Preheat;
 			break;
-		case 9:
+		case S::Lay1Cal:
 			lcd_show_fullscreen_message_and_wait_P(_i("Now I will calibrate distance between tip of the nozzle and heatbed surface."));////MSG_WIZARD_V2_CAL c=20 r=8
 			lcd_show_fullscreen_message_and_wait_P(_i("I will start to print line and you will gradually lower the nozzle by rotating the knob, until you reach optimal height. Check the pictures in our handbook in chapter Calibration."));////MSG_WIZARD_V2_CAL_2 c=20 r=12
 			lcd_commands_type = LCD_COMMAND_V2_CAL;
+			lcd_return_to_status();
 			end = true;
 			break;
-		case 10: //repeat first layer cal.?
+		case S::RepeatLay1Cal: //repeat first layer cal.?
 			wizard_event = lcd_show_multiscreen_message_yes_no_and_wait_P(_i("Do you want to repeat last step to readjust distance between nozzle and heatbed?"), false);////MSG_WIZARD_REPEAT_V2_CAL c=20 r=7
 			if (wizard_event) {
 				lcd_show_fullscreen_message_and_wait_P(_i("Please clean heatbed and then press the knob."));////MSG_WIZARD_CLEAN_HEATBED c=20 r=8
-				state = 9;
+				state = S::Lay1Cal;
 			}
 			else {
-				state = 11;
+				state = S::Finish;
 			}
 			break;
-		case 11: //we are finished
+		case S::Finish: //we are finished
 			eeprom_write_byte((uint8_t*)EEPROM_WIZARD_ACTIVE, 0);
 			end = true;
 			break;
@@ -4483,27 +4567,15 @@ void lcd_wizard(int state) {
 
 	printf_P(_N("Wizard end state: %d\n"), state);
 	switch (state) { //final message
-	case 0: //user dont want to use wizard
-		msg = _T(MSG_WIZARD_QUIT);
-		break;
-
-	case 1: //printer was already calibrated
+	case S::Restore: //printer was already calibrated
 		msg = _T(MSG_WIZARD_DONE);
 		break;
-	case 2: //selftest
-		msg = _T(MSG_WIZARD_CALIBRATION_FAILED);
-		break;
-	case 3: //xyz cal.
-		msg = _T(MSG_WIZARD_CALIBRATION_FAILED);
-		break;
-	case 4: //z cal.
+	case S::Selftest: //selftest
+	case S::Xyz: //xyz cal.
+	case S::Z: //z cal.
 		msg = _T(MSG_WIZARD_CALIBRATION_FAILED);
 		break;
-	case 8:
-		msg = _i("Please load PLA filament and then resume Wizard by rebooting the printer.");////MSG_WIZARD_INSERT_CORRECT_FILAMENT c=20 r=8
-		break;
-	case 9: break; //exit wizard for v2 calibration, which is implemted in lcd_commands (we need lcd_update running)
-	case 11: //we are finished
+	case S::Finish: //we are finished
 
 		msg = _T(MSG_WIZARD_DONE);
 		lcd_reset_alert_level();
@@ -4515,12 +4587,11 @@ void lcd_wizard(int state) {
 		break;
 
 	}
-	if (state != 9) {
+	if (!((S::Lay1Cal == state) || (S::Preheat == state))) {
 		lcd_show_fullscreen_message_and_wait_P(msg);
 		wizard_active = false;
 	}
 	lcd_update_enable(true);
-	lcd_return_to_status();
 	lcd_update(2);
 }
 
@@ -4698,6 +4769,7 @@ static void auto_deplete_switch()
     lcd_autoDeplete = !lcd_autoDeplete;
     eeprom_update_byte((unsigned char *)EEPROM_AUTO_DEPLETE, lcd_autoDeplete);
 }
+
 static void lcd_settings_menu()
 {
 	EEPROM_read(EEPROM_SILENT, (uint8_t*)&SilentModeMenu, sizeof(SilentModeMenu));
@@ -4760,11 +4832,6 @@ static void lcd_settings_menu()
 	MENU_END();
 }
 
-static void lcd_selftest_()
-{
-	lcd_selftest();
-}
-
 #ifdef TMC2130
 static void lcd_ustep_linearity_menu_save()
 {
@@ -4898,9 +4965,6 @@ void bowden_menu() {
 		}
 
 		if (lcd_clicked()) {
-			while (lcd_clicked());
-			delay(10);
-			while (lcd_clicked());
 
 			lcd_clear();
 			while (1) {
@@ -4932,9 +4996,6 @@ void bowden_menu() {
 				}
 				delay(100);
 				if (lcd_clicked()) {
-					while (lcd_clicked());
-					delay(10);
-					while (lcd_clicked());
 					EEPROM_save_B(EEPROM_BOWDEN_LENGTH + cursor_pos * 2, &bowden_length[cursor_pos]);
 					if (lcd_show_fullscreen_message_yes_no_and_wait_P(PSTR("Continue with another bowden?"))) {
 						lcd_update_enable(true);
@@ -4995,9 +5056,6 @@ static char snmm_stop_print_menu() { //menu for choosing which filaments will be
 			}
 		}
 		if (lcd_clicked()) {
-			while (lcd_clicked());
-			delay(10);
-			while (lcd_clicked());
 			KEEPALIVE_STATE(IN_HANDLER);
 			return(cursor_pos - 1);
 		}
@@ -5005,95 +5063,104 @@ static char snmm_stop_print_menu() { //menu for choosing which filaments will be
 	
 }
 
-char choose_extruder_menu()
-{
-	int items_no = mmu_enabled?5:4;
-	int first = 0;
-	int enc_dif = 0;
-	char cursor_pos = 1;
+//! @brief Select one of numbered items
+//!
+//! Create list of items with header. Header can not be selected.
+//! Each item has text description passed by function parameter and
+//! number. There are 5 numbered items, if mmu_enabled, 4 otherwise.
+//! Items are numbered from 1 to 4 or 5. But index returned starts at 0.
+//! There can be last item with different text and no number.
+//!
+//! @param header Header text
+//! @param item Item text
+//! @param last_item Last item text, or nullptr if there is no Last item
+//! @return selected item index, first item index is 0
+uint8_t choose_menu_P(const char *header, const char *item, const char *last_item)
+{
+    //following code should handle 3 to 127 number of items well
+    const int8_t items_no = last_item?(mmu_enabled?6:5):(mmu_enabled?5:4);
+    const uint8_t item_len = item?strlen_P(item):0;
+	int8_t first = 0;
+	int8_t enc_dif = lcd_encoder_diff;
+	int8_t cursor_pos = 1;
 	
-	enc_dif = lcd_encoder_diff;
 	lcd_clear();
-	if (mmu_enabled) lcd_puts_P(_T(MSG_CHOOSE_FILAMENT));
-	else lcd_puts_P(_T(MSG_CHOOSE_EXTRUDER));
-	lcd_set_cursor(0, 1);
-	lcd_print(">");
-	for (int i = 0; i < 3; i++) {
-		lcd_puts_at_P(1, i + 1, mmu_enabled ? _T(MSG_FILAMENT) : _T(MSG_EXTRUDER));
-	}
+
 	KEEPALIVE_STATE(PAUSED_FOR_USER);
-	while (1) {
+	while (1)
+	{
+		manage_heater();
+		manage_inactivity(true);
 
-		for (int i = 0; i < 3; i++) {
-			lcd_set_cursor(2 + strlen_P( mmu_enabled ? _T(MSG_FILAMENT) : _T(MSG_EXTRUDER)), i+1);
-			lcd_print(first + i + 1);
+		if (abs((enc_dif - lcd_encoder_diff)) > 4)
+		{
+            if (enc_dif > lcd_encoder_diff)
+            {
+                cursor_pos--;
+            }
+
+            if (enc_dif < lcd_encoder_diff)
+            {
+                cursor_pos++;
+            }
+            enc_dif = lcd_encoder_diff;
 		}
 
-		manage_heater();
-		manage_inactivity(true);
+		if (cursor_pos > 3)
+		{
+            cursor_pos = 3;
+            if (first < items_no - 3)
+            {
+                first++;
+                lcd_clear();
+            }
+        }
 
-		if (abs((enc_dif - lcd_encoder_diff)) > 4) {
+        if (cursor_pos < 1)
+        {
+            cursor_pos = 1;
+            if (first > 0)
+            {
+                first--;
+                lcd_clear();
+            }
+        }
 
-			if ((abs(enc_dif - lcd_encoder_diff)) > 1) {
-				if (enc_dif > lcd_encoder_diff) {
-					cursor_pos--;
-				}
+        if (header) lcd_puts_at_P(0,0,header);
 
-				if (enc_dif < lcd_encoder_diff) {
-					cursor_pos++;
-				}
+        const bool last_visible = (first == items_no - 3);
+        const int8_t ordinary_items = (last_item&&last_visible)?2:3;
 
-				if (cursor_pos > 3) {
-					cursor_pos = 3;
-					if (first < items_no - 3) {
-						first++;
-						lcd_clear();
-						if (mmu_enabled) lcd_puts_P(_T(MSG_CHOOSE_FILAMENT));
-						else lcd_puts_P(_T(MSG_CHOOSE_EXTRUDER));
-						for (int i = 0; i < 3; i++) {
-							lcd_puts_at_P(1, i + 1,  mmu_enabled ? _T(MSG_FILAMENT) : _T(MSG_EXTRUDER));
-						}
-					}
-				}
+        for (int i = 0; i < ordinary_items; i++)
+        {
+            if (item) lcd_puts_at_P(1, i + 1, item);
+        }
 
-				if (cursor_pos < 1) {
-					cursor_pos = 1;
-					if (first > 0) {
-						first--;
-						lcd_clear();
-						if (mmu_enabled) lcd_puts_P(_T(MSG_CHOOSE_FILAMENT));
-						else lcd_puts_P(_T(MSG_CHOOSE_EXTRUDER));
-						for (int i = 0; i < 3; i++) {
-							lcd_puts_at_P(1, i + 1, mmu_enabled ? _T(MSG_FILAMENT) : _T(MSG_EXTRUDER));
-						}
-					}
-				}
-				lcd_set_cursor(0, 1);
-				lcd_print(" ");
-				lcd_set_cursor(0, 2);
-				lcd_print(" ");
-				lcd_set_cursor(0, 3);
-				lcd_print(" ");
-				lcd_set_cursor(0, cursor_pos);
-				lcd_print(">");
-				enc_dif = lcd_encoder_diff;
-				delay(100);
-			}
+        for (int i = 0; i < ordinary_items; i++)
+        {
+            lcd_set_cursor(2 + item_len, i+1);
+            lcd_print(first + i + 1);
+        }
 
-		}
+        if (last_item&&last_visible) lcd_puts_at_P(1, 3, last_item);
 
-		if (lcd_clicked()) {
-			lcd_update(2);
-			while (lcd_clicked());
-			delay(10);
-			while (lcd_clicked());
-			KEEPALIVE_STATE(IN_HANDLER);
+        lcd_set_cursor(0, 1);
+        lcd_print(" ");
+        lcd_set_cursor(0, 2);
+        lcd_print(" ");
+        lcd_set_cursor(0, 3);
+        lcd_print(" ");
+        lcd_set_cursor(0, cursor_pos);
+        lcd_print(">");
+
+        delay(100);
+
+		if (lcd_clicked())
+		{
+		    KEEPALIVE_STATE(IN_HANDLER);
 			return(cursor_pos + first - 1);
-			
 		}
-
 	}
-
 }
 
 //#endif
@@ -5175,9 +5242,6 @@ char reset_menu() {
 		}
 
 		if (lcd_clicked()) {
-			while (lcd_clicked());
-			delay(10);
-			while (lcd_clicked());
 			return(cursor_pos + first);
 		}
 
@@ -5198,7 +5262,6 @@ static void lcd_disable_farm_mode()
 	
 }
 
-
 static void fil_load_menu()
 {
 	MENU_BEGIN();
@@ -5282,7 +5345,7 @@ void unload_filament()
 	disable_e2();
 	delay(100);
 
-	Sound_MakeSound(e_SOUND_CLASS_Prompt, e_SOUND_TYPE_StandardPrompt);
+	Sound_MakeSound(e_SOUND_TYPE_StandardPrompt);
 	uint8_t counterBeep = 0;
 	while (!lcd_clicked() && (counterBeep < 50)) {
 		delay_keep_alive(100);
@@ -5435,9 +5498,6 @@ unsigned char lcd_choose_color() {
 		}
 
 		if (lcd_clicked()) {
-			while (lcd_clicked());
-			delay(10);
-			while (lcd_clicked());
 			switch(cursor_pos + first - 1) {
 			case 0: return 1; break;
 			case 1: return 0; break;
@@ -5529,6 +5589,7 @@ void lcd_confirm_print()
 
 #include "w25x20cl.h"
 
+#ifdef LCD_TEST
 static void lcd_test_menu()
 {
 	W25X20CL_SPI_ENTER();
@@ -5536,6 +5597,20 @@ static void lcd_test_menu()
 	w25x20cl_chip_erase();
 	w25x20cl_disable_wr();
 }
+#endif //LCD_TEST
+
+//! @brief Resume paused print
+//! @todo It is not good to call restore_print_from_ram_and_continue() from function called by lcd_update(),
+//! as restore_print_from_ram_and_continue() calls lcd_update() internally.
+void lcd_resume_print()
+{
+    lcd_return_to_status();
+    lcd_setstatuspgm(_T(MSG_RESUMING_PRINT));
+    lcd_reset_alert_level(); //for fan speed error
+    restore_print_from_ram_and_continue(0.0);
+    pause_time += (millis() - start_pause_print); //accumulate time when print is paused for correct statistics calculation
+    isPrintPaused = false;
+}
 
 static void lcd_main_menu()
 {
@@ -5630,11 +5705,11 @@ static void lcd_main_menu()
 		if (mesh_bed_leveling_flag == false && homing_flag == false) {
 			if (card.sdprinting)
 			{
-				MENU_ITEM_FUNCTION_P(_i("Pause print"), lcd_sdcard_pause);////MSG_PAUSE_PRINT c=0 r=0
+				MENU_ITEM_FUNCTION_P(_i("Pause print"), lcd_pause_print);////MSG_PAUSE_PRINT c=0 r=0
 			}
 			else
 			{
-				MENU_ITEM_FUNCTION_P(_i("Resume print"), lcd_sdcard_resume);////MSG_RESUME_PRINT c=0 r=0
+			    MENU_ITEM_SUBMENU_P(_i("Resume print"), lcd_resume_print);////MSG_RESUME_PRINT c=0 r=0
 			}
 			MENU_ITEM_SUBMENU_P(_T(MSG_STOP_PRINT), lcd_sdcard_stop);
 		}
@@ -5710,8 +5785,9 @@ static void lcd_main_menu()
 #endif
 
   MENU_ITEM_SUBMENU_P(_i("Support"), lcd_support_menu);////MSG_SUPPORT c=0 r=0
-
-//  MENU_ITEM_SUBMENU_P(_i("W25x20CL init"), lcd_test_menu);////MSG_SUPPORT c=0 r=0
+#ifdef LCD_TEST
+    MENU_ITEM_SUBMENU_P(_i("W25x20CL init"), lcd_test_menu);////MSG_SUPPORT c=0 r=0
+#endif //LCD_TEST
 
   MENU_END();
 
@@ -5748,34 +5824,6 @@ void stepper_timer_overflow() {
 }
 #endif /* DEBUG_STEPPER_TIMER_MISSED */
 
-#ifdef SDSUPPORT
-static void lcd_autostart_sd()
-{
-  card.lastnr = 0;
-  card.setroot();
-  card.checkautostart(true);
-}
-#endif
-
-
-
-static void lcd_silent_mode_set_tune() {
-  switch (SilentModeMenu) {
-#ifdef TMC2130
-	case SILENT_MODE_NORMAL: SilentModeMenu = SILENT_MODE_STEALTH; break;
-	case SILENT_MODE_STEALTH: SilentModeMenu = SILENT_MODE_NORMAL; break;
-	default: SilentModeMenu = SILENT_MODE_NORMAL; break; // (probably) not needed
-#else
-	case SILENT_MODE_POWER: SilentModeMenu = SILENT_MODE_SILENT; break;
-	case SILENT_MODE_SILENT: SilentModeMenu = SILENT_MODE_AUTO; break;
-	case SILENT_MODE_AUTO: SilentModeMenu = SILENT_MODE_POWER; break;
-	default: SilentModeMenu = SILENT_MODE_POWER; break; // (probably) not needed
-#endif //TMC2130
-  }
-  eeprom_update_byte((unsigned char *)EEPROM_SILENT, SilentModeMenu);
-  st_current_init();
-  menu_back();
-}
 
 static void lcd_colorprint_change() {
 	
@@ -5883,12 +5931,6 @@ static void lcd_tune_menu()
 	MENU_END();
 }
 
-static void lcd_move_menu_01mm()
-{
-  move_menu_scale = 0.1;
-  lcd_move_menu_axis();
-}
-
 static void lcd_control_temperature_menu()
 {
 #ifdef PIDTEMP
@@ -6005,7 +6047,7 @@ void lcd_sdcard_stop()
 void lcd_sdcard_menu()
 {
   uint8_t sdSort = eeprom_read_byte((uint8_t*)EEPROM_SD_SORT);
-  int tempScrool = 0;
+
   if (presort_flag == true) {
 	  presort_flag = false;
 	  card.presort();
@@ -6047,7 +6089,7 @@ void lcd_sdcard_menu()
 		#endif
 			
 		if (card.filenameIsDir)
-			MENU_ITEM_SDDIR(_T(MSG_CARD_MENU), card.filename, card.longFilename);
+			MENU_ITEM_SDDIR(card.filename, card.longFilename);
 		else
 			MENU_ITEM_SDFILE(_T(MSG_CARD_MENU), card.filename, card.longFilename);
     } else {
@@ -6250,14 +6292,14 @@ bool lcd_selftest()
 
 #ifdef TMC2130
 
-static void reset_crash_det(char axis) {
+static void reset_crash_det(unsigned char axis) {
 	current_position[axis] += 10;
 	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 (eeprom_read_byte((uint8_t*)EEPROM_CRASH_DET)) tmc2130_sg_stop_on_crash = true;
 }
 
-static bool lcd_selfcheck_axis_sg(char axis) {
+static bool lcd_selfcheck_axis_sg(unsigned char axis) {
 // each axis length is measured twice	
 	float axis_length, current_position_init, current_position_final;
 	float measured_axis_length[2];
@@ -6544,7 +6586,6 @@ static bool lcd_selfcheck_pulleys(int axis)
 	}
 	return(true);
 }
-#endif //TMC2130
 
 
 static bool lcd_selfcheck_endstops()
@@ -6577,7 +6618,7 @@ static bool lcd_selfcheck_endstops()
 	manage_inactivity(true);
 	return _result;
 }
-//#endif //not defined TMC2130
+#endif //not defined TMC2130
 
 static bool lcd_selfcheck_check_heater(bool _isbed)
 {
@@ -7060,7 +7101,7 @@ static bool check_file(const char* filename) {
 	
 }
 
-void menu_action_sdfile(const char* filename, char* longFilename)
+static void menu_action_sdfile(const char* filename)
 {
   loading_flag = false;
   char cmd[30];
@@ -7105,7 +7146,7 @@ void menu_action_sdfile(const char* filename, char* longFilename)
   lcd_return_to_status();
 }
 
-void menu_action_sddirectory(const char* filename, char* longFilename)
+void menu_action_sddirectory(const char* filename)
 {
 	uint8_t depth = (uint8_t)card.getWorkDirDepth();
 
@@ -7147,7 +7188,6 @@ void ultralcd_init()
   WRITE(SDCARDDETECT, HIGH);
   lcd_oldcardstatus = IS_SD_INSERTED;
 #endif//(SDCARDDETECT > 0)
-  lcd_buttons_update();
   lcd_encoder_diff = 0;
 }
 
@@ -7170,11 +7210,11 @@ static void lcd_send_status() {
 	}
 }
 
+#ifdef FARM_CONNECT_MESSAGE
 static void lcd_connect_printer() {
 	lcd_update_enable(false);
 	lcd_clear();
 	
-	bool pressed = false;
 	int i = 0;
 	int t = 0;
 	lcd_set_custom_characters_progress();
@@ -7203,6 +7243,7 @@ static void lcd_connect_printer() {
 	lcd_update_enable(true);
 	lcd_update(2);
 }
+#endif //FARM_CONNECT_MESSAGE
 
 void lcd_ping() { //chceck if printer is connected to monitoring when in farm mode
 	if (farm_mode) {
@@ -7266,19 +7307,6 @@ uint8_t get_message_level()
 }
 
 
-
-
-
-
-
-
-
-
-
-
-
-
-
 void menu_lcd_longpress_func(void)
 {
 	move_menu_scale = 1.0;

+ 29 - 5
Firmware/ultralcd.h

@@ -5,6 +5,7 @@
 #include "lcd.h"
 #include "conv2str.h"
 #include "menu.h"
+#include "mesh_bed_calibration.h"
 
 extern int lcd_puts_P(const char* str);
 extern int lcd_printf_P(const char* format, ...);
@@ -31,7 +32,8 @@ void lcd_loading_filament();
 void lcd_change_success();
 void lcd_loading_color();
 void lcd_sdcard_stop();
-void lcd_sdcard_pause();
+void lcd_pause_print();
+void lcd_resume_print();
 void lcd_print_stop();
 void prusa_statistics(int _message, uint8_t _col_nr = 0);
 void lcd_confirm_print();
@@ -50,6 +52,8 @@ 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, bool default_yes = false);
+extern int8_t lcd_show_multiscreen_message_two_choices_and_wait_P(const char *msg, bool allow_timeouting, bool default_yes,
+        const char *first_choice, const char *second_choice);
 extern int8_t lcd_show_multiscreen_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.
@@ -59,7 +63,7 @@ extern bool lcd_calibrate_z_end_stop_manual(bool only_z);
 #endif
 
 // Show the result of the calibration process on the LCD screen.
-extern void lcd_bed_calibration_show_result(uint8_t result, uint8_t point_too_far_mask);
+  extern void lcd_bed_calibration_show_result(BedSkewOffsetDetectionResultType result, uint8_t point_too_far_mask);
 
 extern void lcd_diag_show_end_stops();
 
@@ -76,11 +80,11 @@ extern void lcd_diag_show_end_stops();
 #define LCD_COMMAND_STOP_PRINT 2
 #define LCD_COMMAND_FARM_MODE_CONFIRM 4
 #define LCD_COMMAND_LONG_PAUSE 5
-#define LCD_COMMAND_LONG_PAUSE_RESUME 6
 #define LCD_COMMAND_PID_EXTRUDER 7 
 #define LCD_COMMAND_V2_CAL 8
 
 extern int lcd_commands_type;
+extern int8_t FSensorStateMenu;
 
 #define CUSTOM_MSG_TYPE_STATUS 0 // status message from lcd_status_message variable
 #define CUSTOM_MSG_TYPE_MESHBL 1 // Mesh bed leveling in progress
@@ -150,7 +154,7 @@ bool lcd_wait_for_pinda(float temp);
 
 void bowden_menu();
 char reset_menu();
-char choose_extruder_menu();
+uint8_t choose_menu_P(const char *header, const char *item, const char *last_item = nullptr);
 
 void lcd_pinda_calibration_menu();
 void lcd_calibrate_pinda();
@@ -166,6 +170,26 @@ void lcd_set_progress();
 void lcd_language();
 
 void lcd_wizard();
-void lcd_wizard(int state);
+
+//! @brief Wizard state
+enum class WizState : uint8_t
+{
+    Run,            //!< run wizard? Entry point.
+    Restore,        //!< restore calibration status
+    Selftest,
+    Xyz,            //!< xyz calibration
+    Z,              //!< z calibration
+    IsFil,          //!< Is filament loaded? Entry point for 1st layer calibration
+    PreheatPla,     //!< waiting for preheat nozzle for PLA
+    Preheat,        //!< Preheat for any material
+    Unload,         //!< Unload filament
+    LoadFil,        //!< Load filament
+    IsPla,          //!< Is PLA filament?
+    Lay1Cal,        //!< First layer calibration
+    RepeatLay1Cal,  //!< Repeat first layer calibration?
+    Finish,         //!< Deactivate wizard
+};
+
+void lcd_wizard(WizState state);
 
 #endif //ULTRALCD_H

+ 10 - 10
Firmware/xyzcal.cpp

@@ -32,8 +32,6 @@
 
 #define _PI 3.14159265F
 
-extern volatile long count_position[NUM_AXIS];
-
 uint8_t check_pinda_0();
 uint8_t check_pinda_1();
 void xyzcal_update_pos(uint16_t dx, uint16_t dy, uint16_t dz, uint16_t de);
@@ -87,7 +85,7 @@ uint8_t check_pinda_1()
 
 uint8_t xyzcal_dm = 0;
 
-void xyzcal_update_pos(uint16_t dx, uint16_t dy, uint16_t dz, uint16_t de)
+void xyzcal_update_pos(uint16_t dx, uint16_t dy, uint16_t dz, uint16_t)
 {
 //	DBG(_n("xyzcal_update_pos dx=%d dy=%d dz=%d dir=%02x\n"), dx, dy, dz, xyzcal_dm);
 	if (xyzcal_dm&1) count_position[0] -= dx; else count_position[0] += dx;
@@ -108,11 +106,9 @@ uint16_t xyzcal_sm4_ac2 = (uint32_t)xyzcal_sm4_ac * 1024 / 10000;
 //float xyzcal_sm4_vm = 10000;
 #endif //SM4_ACCEL_TEST
 
+#ifdef SM4_ACCEL_TEST
 uint16_t xyzcal_calc_delay(uint16_t nd, uint16_t dd)
 {
-	return xyzcal_sm4_delay;
-#ifdef SM4_ACCEL_TEST
-
 	uint16_t del_us = 0;
 	if (xyzcal_sm4_v & 0xf000) //>=4096
 	{
@@ -138,9 +134,13 @@ uint16_t xyzcal_calc_delay(uint16_t nd, uint16_t dd)
 //	return xyzcal_sm4_delay;
 //	DBG(_n("xyzcal_calc_delay nd=%d dd=%d v=%d  del_us=%d\n"), nd, dd, xyzcal_sm4_v, del_us);
 	return 0;
-#endif //SM4_ACCEL_TEST
 }
-
+#else //SM4_ACCEL_TEST
+uint16_t xyzcal_calc_delay(uint16_t, uint16_t)
+{
+    return xyzcal_sm4_delay;
+}
+#endif //SM4_ACCEL_TEST
 
 bool xyzcal_lineXYZ_to(int16_t x, int16_t y, int16_t z, uint16_t delay_us, int8_t check_pinda)
 {
@@ -285,7 +285,7 @@ void xyzcal_scan_pixels_32x32(int16_t cx, int16_t cy, int16_t min_z, int16_t max
 	xyzcal_lineXYZ_to(cx, cy, z, 2*delay_us, 0);
 	for (uint8_t r = 0; r < 32; r++)
 	{
-		int8_t _pinda = _PINDA;
+//		int8_t _pinda = _PINDA;
 		xyzcal_lineXYZ_to((r&1)?(cx+1024):(cx-1024), cy - 1024 + r*64, z, 2*delay_us, 0);
 		xyzcal_lineXYZ_to(_X, _Y, min_z, delay_us, 1);
 		xyzcal_lineXYZ_to(_X, _Y, max_z, delay_us, -1);
@@ -330,7 +330,7 @@ void xyzcal_scan_pixels_32x32(int16_t cx, int16_t cy, int16_t min_z, int16_t max
 				}
 				sm4_do_step(X_AXIS_MASK);
 				delayMicroseconds(600);
-				_pinda = pinda;
+//				_pinda = pinda;
 			}
 			sum >>= 6; //div 64
 			if (z_sum < 0)

+ 5 - 4
README.md

@@ -2,8 +2,7 @@
 
    1. install `"Arduino Software IDE"` for your preferred operating system  
 `https://www.arduino.cc -> Software->Downloads`  
-it is strongly recommended to use older version `"1.6.9"`, by which we can assure correct compilation results  
-_note: in versions `1.7.x` and `1.8.x` there are known some C/C++ compilator disasters, which disallow correct source code compilation (you can obtain `"... internal compiler error: in extract_insn, at ..."` error message, for example); we are not able to affect this situation afraid_  
+it is recommended to use older version `"1.6.9"`, as it is used on out build server to produce official builds.  
 _note: in the case of persistent compilation problems, check the version of the currently used C/C++ compiler (GCC) - should be `4.8.1`; version can be verified by entering the command  
 `avr-gcc --version`  
 if you are not sure where the file is placed (depends on how `"Arduino Software IDE"` was installed), you can use the search feature within the file system_  
@@ -26,8 +25,10 @@ _note: select this item for any variant of board used in printers `'Prusa i3 MKx
 'clicking' the item will display the installation button; select choice `"1.0.1"` from the list(last known version as of the date of issue of this document)  
 _(after installation, the item is labeled as `"INSTALLED"` and can then be used for target board selection)_  
 
-   3. modify platform.txt to enable float printf support:
-   `"compiler.c.elf.flags=-w -Os -Wl,-u,vfprintf -lprintf_flt -lm -Wl,--gc-sections"`
+   3. modify platform.txt to enable float printf support:  
+add "-Wl,-u,vfprintf -lprintf_flt -lm" to "compiler.c.elf.flags=" before existing flag "-Wl,--gc-sections"  
+example:  
+`"compiler.c.elf.flags=-w -Os -Wl,-u,vfprintf -lprintf_flt -lm -Wl,--gc-sections"`
 
 # 2. Source code compilation
 

+ 5 - 2
README_cz.md

@@ -2,8 +2,7 @@
 
    1. nainstalujte vývojové prostředí `"Arduino Software IDE"` pro operační prostředí, které jste zvyklí používat  
 `https://www.arduino.cc -> Software->Downloads`  
-důrazně doporučujeme použít starší verzi `"1.6.8"`, u které jsme schopni garantovat bezproblémový překlad a správné výsledky  
-_pozn.: ve verzích `1.7.x` a `1.8.x` jsou k datu vydání tohoto dokumentu evidovány chyby v překladači jazyka C/C++, které znemožňují překlad zdrojového kódu (můžete např. obdržet chybové hlášení `"... internal compiler error: in extract_insn, at ..."`); tuto nepříjemnou situaci bohužel nedokážeme nijak ovlivnit_  
+doporučujeme použít starší verzi `"1.6.9"`, kterou používáme na našem build serveru pro překlad oficiálních buildů 
 _pozn.: v případě přetrvávajících potíží s překladem zkontrolujte verzi aktuálně použitého překladače jazyka C/C++ (GCC) - měla by být `4.8.1`; verzi ověříte zadáním příkazu  
 `avr-gcc --version`  
 pokud si nejste jisti umístěním souboru (závisí na způsobu, jakým bylo `"Arduino Software IDE"` nainstalováno), použijte funkci vyhledání v rámci systému souborů_  
@@ -26,6 +25,10 @@ _pozn.: tuto položku zvolte pro všechny varianty desek použitých v tiskárn
 'kliknutím' na položku se zobrazí tlačítko pro instalaci; ve výběrovém seznamu zvolte verzi `"1.0.1"` (poslední známá verze k datu vydání tohoto dokumentu)  
 _(po provedení instalace je položka označena poznámkou `"INSTALLED"` a lze ji následně použít při výběru cílové desky)_  
 
+   3. modify platform.txt to enable float printf support:  
+add "-Wl,-u,vfprintf -lprintf_flt -lm" to "compiler.c.elf.flags=" before existing flag "-Wl,--gc-sections"  
+example:  
+`"compiler.c.elf.flags=-w -Os -Wl,-u,vfprintf -lprintf_flt -lm -Wl,--gc-sections"`
 
 # 2. Překlad zdrojoveho kódu