Browse Source

merge MK3_dev into MK3

PavelSindler 5 years ago
parent
commit
940f436a5f

+ 159 - 297
Firmware/ConfigurationStore.cpp

@@ -1,3 +1,5 @@
+//! @file
+
 #include "Marlin.h"
 #include "planner.h"
 #include "temperature.h"
@@ -9,149 +11,71 @@
 #include "mesh_bed_leveling.h"
 #endif
 
+M500_conf cs;
+
+//! @brief Write data to EEPROM
+//! @param pos destination in EEPROM, 0 is start
+//! @param value value to be written
+//! @param size size of type pointed by value
+//! @param name name of variable written, used only for debug input if DEBUG_EEPROM_WRITE defined
+//! @retval true success
+//! @retval false failed
 #ifdef DEBUG_EEPROM_WRITE
-#define EEPROM_WRITE_VAR(pos, value) _EEPROM_writeData(pos, (uint8_t*)&value, sizeof(value), #value)
+static bool EEPROM_writeData(uint8_t* pos, uint8_t* value, uint8_t size, const char* name)
 #else //DEBUG_EEPROM_WRITE
-#define EEPROM_WRITE_VAR(pos, value) _EEPROM_writeData(pos, (uint8_t*)&value, sizeof(value), 0)
+static bool EEPROM_writeData(uint8_t* pos, uint8_t* value, uint8_t size, const char*)
 #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);
 #endif //DEBUG_EEPROM_WRITE
-	while (size--) {
-		uint8_t * const p = (uint8_t * const)pos;
-		uint8_t v = *value;
-		// EEPROM has only ~100,000 write cycles,
-		// so only write bytes that have changed!
-		if (v != eeprom_read_byte(p)) {
-			eeprom_write_byte(p, v);
-			if (eeprom_read_byte(p) != v) {
-				SERIAL_ECHOLNPGM("EEPROM Error");
-				return;
-			}
-		}
+	while (size--)
+	{
+
+        eeprom_update_byte(pos, *value);
+        if (eeprom_read_byte(pos) != *value) {
+            SERIAL_ECHOLNPGM("EEPROM Error");
+            return false;
+        }
+
 		pos++;
 		value++;
-	};
-
+	}
+    return true;
 }
 
 #ifdef DEBUG_EEPROM_READ
-#define EEPROM_READ_VAR(pos, value) _EEPROM_readData(pos, (uint8_t*)&value, sizeof(value), #value)
+static void EEPROM_readData(uint8_t* pos, uint8_t* value, uint8_t size, const char* name)
 #else //DEBUG_EEPROM_READ
-#define EEPROM_READ_VAR(pos, value) _EEPROM_readData(pos, (uint8_t*)&value, sizeof(value), 0)
+static void EEPROM_readData(uint8_t* pos, uint8_t* value, uint8_t size, const char*)
 #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);
 #endif //DEBUG_EEPROM_READ
-    do
+    while(size--)
     {
-        *value = eeprom_read_byte((unsigned char*)pos);
+        *value = eeprom_read_byte(pos);
         pos++;
         value++;
-    }while(--size);
+    }
 }
 
-//======================================================================================
-// IMPORTANT:  Whenever there are changes made to the variables stored in EEPROM
-// in the functions below, also increment the version number and update EEPROM_M500_SIZE. This makes sure that
-// the default values are used whenever there is a change to the data, to prevent
-// wrong data being written to the variables.
-// ALSO:  always make sure the variables in the Store and retrieve sections are in the same order.
-
 #define EEPROM_VERSION "V2"
 
 #ifdef EEPROM_SETTINGS
-void Config_StoreSettings(uint16_t offset) 
+void Config_StoreSettings()
 {
-  char ver[4]= "000";
-  int i = offset;
-  EEPROM_WRITE_VAR(i,ver); // invalidate data first 
-  EEPROM_WRITE_VAR(i,axis_steps_per_unit);
-  EEPROM_WRITE_VAR(i,max_feedrate_normal);
-  EEPROM_WRITE_VAR(i,max_acceleration_units_per_sq_second_normal);
-  EEPROM_WRITE_VAR(i,acceleration);
-  EEPROM_WRITE_VAR(i,retract_acceleration);
-  EEPROM_WRITE_VAR(i,minimumfeedrate);
-  EEPROM_WRITE_VAR(i,mintravelfeedrate);
-  EEPROM_WRITE_VAR(i,minsegmenttime);
-  EEPROM_WRITE_VAR(i,max_jerk[X_AXIS]);
-  EEPROM_WRITE_VAR(i,max_jerk[Y_AXIS]);
-  EEPROM_WRITE_VAR(i,max_jerk[Z_AXIS]);
-  EEPROM_WRITE_VAR(i,max_jerk[E_AXIS]);
-  EEPROM_WRITE_VAR(i,add_homing);
-/*  EEPROM_WRITE_VAR(i,plaPreheatHotendTemp);
-  EEPROM_WRITE_VAR(i,plaPreheatHPBTemp);
-  EEPROM_WRITE_VAR(i,plaPreheatFanSpeed);
-  EEPROM_WRITE_VAR(i,absPreheatHotendTemp);
-  EEPROM_WRITE_VAR(i,absPreheatHPBTemp);
-  EEPROM_WRITE_VAR(i,absPreheatFanSpeed);
-*/
+  strcpy(cs.version,"000"); //!< invalidate data first @TODO use erase to save one erase cycle
   
-  EEPROM_WRITE_VAR(i,zprobe_zoffset);
-  #ifdef PIDTEMP
-    EEPROM_WRITE_VAR(i,Kp);
-    EEPROM_WRITE_VAR(i,Ki);
-    EEPROM_WRITE_VAR(i,Kd);
-  #else
-		float dummy = 3000.0f;
-    EEPROM_WRITE_VAR(i,dummy);
-		dummy = 0.0f;
-    EEPROM_WRITE_VAR(i,dummy);
-    EEPROM_WRITE_VAR(i,dummy);
-  #endif
-  #ifdef PIDTEMPBED
-	EEPROM_WRITE_VAR(i, bedKp);
-	EEPROM_WRITE_VAR(i, bedKi);
-	EEPROM_WRITE_VAR(i, bedKd);
-  #endif
-
-  int lcd_contrast = 0;
-  EEPROM_WRITE_VAR(i,lcd_contrast);
-
-  #ifdef FWRETRACT
-  EEPROM_WRITE_VAR(i,autoretract_enabled);
-  EEPROM_WRITE_VAR(i,retract_length);
-  #if EXTRUDERS > 1
-  EEPROM_WRITE_VAR(i,retract_length_swap);
-  #endif
-  EEPROM_WRITE_VAR(i,retract_feedrate);
-  EEPROM_WRITE_VAR(i,retract_zlift);
-  EEPROM_WRITE_VAR(i,retract_recover_length);
-  #if EXTRUDERS > 1
-  EEPROM_WRITE_VAR(i,retract_recover_length_swap);
-  #endif
-  EEPROM_WRITE_VAR(i,retract_recover_feedrate);
-  #endif
-
-  // Save filament sizes
-  EEPROM_WRITE_VAR(i, volumetric_enabled);
-  EEPROM_WRITE_VAR(i, filament_size[0]);
-  #if EXTRUDERS > 1
-  EEPROM_WRITE_VAR(i, filament_size[1]);
-  #if EXTRUDERS > 2
-  EEPROM_WRITE_VAR(i, filament_size[2]);
-  #endif
-  #endif
-
-
-
-  EEPROM_WRITE_VAR(i,max_feedrate_silent);
-  EEPROM_WRITE_VAR(i,max_acceleration_units_per_sq_second_silent);
-  if (EEPROM_M500_SIZE + EEPROM_OFFSET == i) {
-	  char ver2[4] = EEPROM_VERSION;
-	  i = offset;
-	  EEPROM_WRITE_VAR(i, ver2); // validate data
-	  SERIAL_ECHO_START;
-	  SERIAL_ECHOLNPGM("Settings Stored");
-  }
-  else { //size of eeprom M500 section probably changed by mistake and data are not valid; do not validate data by storing eeprom version
-	  //M500 EEPROM section will be erased on next printer reboot and default vaules will be used
-	  puts_P(PSTR("Data stored to EEPROM not valid."));
+  if (EEPROM_writeData(reinterpret_cast<uint8_t*>(EEPROM_M500_base),reinterpret_cast<uint8_t*>(&cs),sizeof(cs),0), "cs, invalid version")
+  {
+      strcpy(cs.version,EEPROM_VERSION); //!< validate data if write succeed
+      EEPROM_writeData(reinterpret_cast<uint8_t*>(EEPROM_M500_base->version), reinterpret_cast<uint8_t*>(cs.version), sizeof(cs.version), "cs.version valid");
   }
+
+  SERIAL_ECHO_START;
+  SERIAL_ECHOLNPGM("Settings Stored");
 }
 #endif //EEPROM_SETTINGS
 
@@ -170,14 +94,14 @@ void Config_PrintSettings(uint8_t level)
 		"%SAdvanced variables: S=Min feedrate (mm/s), T=Min travel feedrate (mm/s), B=minimum segment time (ms), X=maximum XY jerk (mm/s),  Z=maximum Z jerk (mm/s),  E=maximum E jerk (mm/s)\n%S  M205 S%.2f T%.2f B%.2f X%.2f Y%.2f Z%.2f E%.2f\n"
 		"%SHome offset (mm):\n%S  M206 X%.2f Y%.2f Z%.2f\n"
 		),
-		echomagic, echomagic, axis_steps_per_unit[X_AXIS], axis_steps_per_unit[Y_AXIS], axis_steps_per_unit[Z_AXIS], axis_steps_per_unit[E_AXIS],
-		echomagic, echomagic, max_feedrate_normal[X_AXIS], max_feedrate_normal[Y_AXIS], max_feedrate_normal[Z_AXIS], max_feedrate_normal[E_AXIS],
-		echomagic, echomagic, max_feedrate_silent[X_AXIS], max_feedrate_silent[Y_AXIS], max_feedrate_silent[Z_AXIS], max_feedrate_silent[E_AXIS],
-		echomagic, echomagic, max_acceleration_units_per_sq_second_normal[X_AXIS], max_acceleration_units_per_sq_second_normal[Y_AXIS], max_acceleration_units_per_sq_second_normal[Z_AXIS], max_acceleration_units_per_sq_second_normal[E_AXIS],
-		echomagic, echomagic, max_acceleration_units_per_sq_second_silent[X_AXIS], max_acceleration_units_per_sq_second_silent[Y_AXIS], max_acceleration_units_per_sq_second_silent[Z_AXIS], max_acceleration_units_per_sq_second_silent[E_AXIS],
-		echomagic, echomagic, acceleration, retract_acceleration,
-		echomagic, echomagic, minimumfeedrate, mintravelfeedrate, minsegmenttime, max_jerk[X_AXIS], max_jerk[Y_AXIS], max_jerk[Z_AXIS], max_jerk[E_AXIS],
-		echomagic, echomagic, add_homing[X_AXIS], add_homing[Y_AXIS], add_homing[Z_AXIS]
+		echomagic, echomagic, cs.axis_steps_per_unit[X_AXIS], cs.axis_steps_per_unit[Y_AXIS], cs.axis_steps_per_unit[Z_AXIS], cs.axis_steps_per_unit[E_AXIS],
+		echomagic, echomagic, cs.max_feedrate_normal[X_AXIS], cs.max_feedrate_normal[Y_AXIS], cs.max_feedrate_normal[Z_AXIS], cs.max_feedrate_normal[E_AXIS],
+		echomagic, echomagic, cs.max_feedrate_silent[X_AXIS], cs.max_feedrate_silent[Y_AXIS], cs.max_feedrate_silent[Z_AXIS], cs.max_feedrate_silent[E_AXIS],
+		echomagic, echomagic, cs.max_acceleration_units_per_sq_second_normal[X_AXIS], cs.max_acceleration_units_per_sq_second_normal[Y_AXIS], cs.max_acceleration_units_per_sq_second_normal[Z_AXIS], cs.max_acceleration_units_per_sq_second_normal[E_AXIS],
+		echomagic, echomagic, cs.max_acceleration_units_per_sq_second_silent[X_AXIS], cs.max_acceleration_units_per_sq_second_silent[Y_AXIS], cs.max_acceleration_units_per_sq_second_silent[Z_AXIS], cs.max_acceleration_units_per_sq_second_silent[E_AXIS],
+		echomagic, echomagic, cs.acceleration, cs.retract_acceleration,
+		echomagic, echomagic, cs.minimumfeedrate, cs.mintravelfeedrate, cs.minsegmenttime, cs.max_jerk[X_AXIS], cs.max_jerk[Y_AXIS], cs.max_jerk[Z_AXIS], cs.max_jerk[E_AXIS],
+		echomagic, echomagic, cs.add_homing[X_AXIS], cs.add_homing[Y_AXIS], cs.add_homing[Z_AXIS]
 #else //TMC2130
 	printf_P(PSTR(
 		"%SSteps per unit:\n%S  M92 X%.2f Y%.2f Z%.2f E%.2f\n"
@@ -187,21 +111,21 @@ void Config_PrintSettings(uint8_t level)
 		"%SAdvanced variables: S=Min feedrate (mm/s), T=Min travel feedrate (mm/s), B=minimum segment time (ms), X=maximum XY jerk (mm/s),  Z=maximum Z jerk (mm/s),  E=maximum E jerk (mm/s)\n%S  M205 S%.2f T%.2f B%.2f X%.2f Y%.2f Z%.2f E%.2f\n"
 		"%SHome offset (mm):\n%S  M206 X%.2f Y%.2f Z%.2f\n"
 		),
-		echomagic, echomagic, axis_steps_per_unit[X_AXIS], axis_steps_per_unit[Y_AXIS], axis_steps_per_unit[Z_AXIS], axis_steps_per_unit[E_AXIS],
+		echomagic, echomagic, cs.axis_steps_per_unit[X_AXIS], cs.axis_steps_per_unit[Y_AXIS], cs.axis_steps_per_unit[Z_AXIS], cs.axis_steps_per_unit[E_AXIS],
 		echomagic, echomagic, max_feedrate[X_AXIS], max_feedrate[Y_AXIS], max_feedrate[Z_AXIS], max_feedrate[E_AXIS],
 		echomagic, echomagic, max_acceleration_units_per_sq_second[X_AXIS], max_acceleration_units_per_sq_second[Y_AXIS], max_acceleration_units_per_sq_second[Z_AXIS], max_acceleration_units_per_sq_second[E_AXIS],
-		echomagic, echomagic, acceleration, retract_acceleration,
-		echomagic, echomagic, minimumfeedrate, mintravelfeedrate, minsegmenttime, max_jerk[X_AXIS], max_jerk[Y_AXIS], max_jerk[Z_AXIS], max_jerk[E_AXIS],
-		echomagic, echomagic, add_homing[X_AXIS], add_homing[Y_AXIS], add_homing[Z_AXIS]
+		echomagic, echomagic, cs.acceleration, cs.retract_acceleration,
+		echomagic, echomagic, cs.minimumfeedrate, cs.mintravelfeedrate, cs.minsegmenttime, cs.max_jerk[X_AXIS], cs.max_jerk[Y_AXIS], cs.max_jerk[Z_AXIS], cs.max_jerk[E_AXIS],
+		echomagic, echomagic, cs.add_homing[X_AXIS], cs.add_homing[Y_AXIS], cs.add_homing[Z_AXIS]
 #endif //TMC2130
 	);
 #ifdef PIDTEMP
 	printf_P(PSTR("%SPID settings:\n%S   M301 P%.2f I%.2f D%.2f\n"),
-		echomagic, echomagic, Kp, unscalePID_i(Ki), unscalePID_d(Kd));
+		echomagic, echomagic, cs.Kp, unscalePID_i(cs.Ki), unscalePID_d(cs.Kd));
 #endif
 #ifdef PIDTEMPBED
 	printf_P(PSTR("%SPID heatbed settings:\n%S   M304 P%.2f I%.2f D%.2f\n"),
-		echomagic, echomagic, bedKp, unscalePID_i(bedKi), unscalePID_d(bedKd));
+		echomagic, echomagic, cs.bedKp, unscalePID_i(cs.bedKi), unscalePID_d(cs.bedKd));
 #endif
 #ifdef FWRETRACT
 	printf_P(PSTR(
@@ -209,23 +133,23 @@ void Config_PrintSettings(uint8_t level)
 		"%SRecover: S=Extra length (mm) F:Speed (mm/m)\n%S   M208 S%.2f F%.2f\n"
 		"%SAuto-Retract: S=0 to disable, 1 to interpret extrude-only moves as retracts or recoveries\n%S   M209 S%d\n"
 		),
-		echomagic, echomagic, retract_length, retract_feedrate*60, retract_zlift,
-		echomagic, echomagic, retract_recover_length, retract_recover_feedrate*60,
-		echomagic, echomagic, (autoretract_enabled ? 1 : 0)
+		echomagic, echomagic, cs.retract_length, cs.retract_feedrate*60, cs.retract_zlift,
+		echomagic, echomagic, cs.retract_recover_length, cs.retract_recover_feedrate*60,
+		echomagic, echomagic, (cs.autoretract_enabled ? 1 : 0)
 	);
 #if EXTRUDERS > 1
 	printf_P(PSTR("%SMulti-extruder settings:\n%S   Swap retract length (mm):    %.2f\n%S   Swap rec. addl. length (mm): %.2f\n"),
 		echomagic, echomagic, retract_length_swap, echomagic, retract_recover_length_swap);
 #endif
-	if (volumetric_enabled) {
+	if (cs.volumetric_enabled) {
 		printf_P(PSTR("%SFilament settings:\n%S   M200 D%.2f\n"),
-			echomagic, echomagic, filament_size[0]);
+			echomagic, echomagic, cs.filament_size[0]);
 #if EXTRUDERS > 1
 		printf_P(PSTR("%S   M200 T1 D%.2f\n"),
-			echomagic, echomagic, filament_size[1]);
+			echomagic, echomagic, cs.filament_size[1]);
 #if EXTRUDERS > 2
 		printf_P(PSTR("%S   M200 T1 D%.2f\n"),
-			echomagic, echomagic, filament_size[2]);
+			echomagic, echomagic, cs.filament_size[2]);
 #endif
 #endif
     } else {
@@ -243,110 +167,112 @@ void Config_PrintSettings(uint8_t level)
 
 
 #ifdef EEPROM_SETTINGS
-bool Config_RetrieveSettings(uint16_t offset)
-{
-    int i=offset;
-	bool previous_settings_retrieved = true;
-    char stored_ver[4];
-    char ver[4]=EEPROM_VERSION;
-    EEPROM_READ_VAR(i,stored_ver); //read stored version
-    //  SERIAL_ECHOLN("Version: [" << ver << "] Stored version: [" << stored_ver << "]");
-    if (strncmp(ver,stored_ver,3) == 0)
-    {
-        // version number match
-        EEPROM_READ_VAR(i,axis_steps_per_unit);
-        EEPROM_READ_VAR(i,max_feedrate_normal);
-        EEPROM_READ_VAR(i,max_acceleration_units_per_sq_second_normal);
-        
-        // steps per sq second need to be updated to agree with the units per sq second (as they are what is used in the planner)
-        
-        EEPROM_READ_VAR(i,acceleration);
-        EEPROM_READ_VAR(i,retract_acceleration);
-        EEPROM_READ_VAR(i,minimumfeedrate);
-        EEPROM_READ_VAR(i,mintravelfeedrate);
-        EEPROM_READ_VAR(i,minsegmenttime);
-        EEPROM_READ_VAR(i,max_jerk[X_AXIS]);
-        EEPROM_READ_VAR(i,max_jerk[Y_AXIS]);
-		EEPROM_READ_VAR(i,max_jerk[Z_AXIS]);
-		EEPROM_READ_VAR(i,max_jerk[E_AXIS]);
-		if (max_jerk[X_AXIS] > DEFAULT_XJERK) max_jerk[X_AXIS] = DEFAULT_XJERK;
-		if (max_jerk[Y_AXIS] > DEFAULT_YJERK) max_jerk[Y_AXIS] = DEFAULT_YJERK;
-        EEPROM_READ_VAR(i,add_homing);
-	/*
-        EEPROM_READ_VAR(i,plaPreheatHotendTemp);
-        EEPROM_READ_VAR(i,plaPreheatHPBTemp);
-        EEPROM_READ_VAR(i,plaPreheatFanSpeed);
-        EEPROM_READ_VAR(i,absPreheatHotendTemp);
-        EEPROM_READ_VAR(i,absPreheatHPBTemp);
-        EEPROM_READ_VAR(i,absPreheatFanSpeed);
-        */
 
-        
-        EEPROM_READ_VAR(i,zprobe_zoffset);
-        #ifndef PIDTEMP
-        float Kp,Ki,Kd;
-        #endif
-        // do not need to scale PID values as the values in EEPROM are already scaled		
-        EEPROM_READ_VAR(i,Kp);
-        EEPROM_READ_VAR(i,Ki);
-        EEPROM_READ_VAR(i,Kd);
-		#ifdef PIDTEMPBED
-		EEPROM_READ_VAR(i, bedKp);
-		EEPROM_READ_VAR(i, bedKi);
-		EEPROM_READ_VAR(i, bedKd);
-		#endif
-
-		int lcd_contrast;
-		EEPROM_READ_VAR(i,lcd_contrast);
+static_assert (EXTRUDERS == 1, "ConfigurationStore M500_conf not implemented for more extruders, fix filament_size array size.");
+static_assert (NUM_AXIS == 4, "ConfigurationStore M500_conf not implemented for more axis."
+        "Fix axis_steps_per_unit max_feedrate_normal max_acceleration_units_per_sq_second_normal max_jerk max_feedrate_silent"
+        " max_acceleration_units_per_sq_second_silent array size.");
+#ifdef ENABLE_AUTO_BED_LEVELING
+static_assert (false, "zprobe_zoffset was not initialized in printers in field to -(Z_PROBE_OFFSET_FROM_EXTRUDER), so it contains"
+        "0.0, if this is not acceptable, increment EEPROM_VERSION to force use default_conf");
+#endif
 
-		#ifdef FWRETRACT
-		EEPROM_READ_VAR(i,autoretract_enabled);
-		EEPROM_READ_VAR(i,retract_length);
-		#if EXTRUDERS > 1
-		EEPROM_READ_VAR(i,retract_length_swap);
-		#endif
-		EEPROM_READ_VAR(i,retract_feedrate);
-		EEPROM_READ_VAR(i,retract_zlift);
-		EEPROM_READ_VAR(i,retract_recover_length);
-		#if EXTRUDERS > 1
-		EEPROM_READ_VAR(i,retract_recover_length_swap);
-		#endif
-		EEPROM_READ_VAR(i,retract_recover_feedrate);
-		#endif
+static_assert (sizeof(M500_conf) == 188, "sizeof(M500_conf) has changed, ensure that EEPROM_VERSION has been incremented, "
+        "or if you added members in the end of struct, ensure that historically uninitialized values will be initialized."
+        "If this is caused by change to more then 8bit processor, decide whether make this struct packed to save EEPROM,"
+        "leave as it is to keep fast code, or reorder struct members to pack more tightly.");
 
-		EEPROM_READ_VAR(i, volumetric_enabled);
-		EEPROM_READ_VAR(i, filament_size[0]);
+static const M500_conf default_conf PROGMEM =
+{
+    EEPROM_VERSION,
+    DEFAULT_AXIS_STEPS_PER_UNIT,
+    DEFAULT_MAX_FEEDRATE,
+    DEFAULT_MAX_ACCELERATION,
+    DEFAULT_ACCELERATION,
+    DEFAULT_RETRACT_ACCELERATION,
+    DEFAULT_MINIMUMFEEDRATE,
+    DEFAULT_MINTRAVELFEEDRATE,
+    DEFAULT_MINSEGMENTTIME,
+    {DEFAULT_XJERK, DEFAULT_YJERK, DEFAULT_ZJERK, DEFAULT_EJERK},
+    {0,0,0},
+    -(Z_PROBE_OFFSET_FROM_EXTRUDER),
+    DEFAULT_Kp,
+    DEFAULT_Ki*PID_dT,
+    DEFAULT_Kd/PID_dT,
+    DEFAULT_bedKp,
+    DEFAULT_bedKi*PID_dT,
+    DEFAULT_bedKd/PID_dT,
+    0,
+    false,
+    RETRACT_LENGTH,
+    RETRACT_FEEDRATE,
+    RETRACT_ZLIFT,
+    RETRACT_RECOVER_LENGTH,
+    RETRACT_RECOVER_FEEDRATE,
+    false,
+    {DEFAULT_NOMINAL_FILAMENT_DIA,
 #if EXTRUDERS > 1
-		EEPROM_READ_VAR(i, filament_size[1]);
+    DEFAULT_NOMINAL_FILAMENT_DIA,
 #if EXTRUDERS > 2
-		EEPROM_READ_VAR(i, filament_size[2]);
+    DEFAULT_NOMINAL_FILAMENT_DIA,
 #endif
 #endif
+    },
+    DEFAULT_MAX_FEEDRATE_SILENT,
+    DEFAULT_MAX_ACCELERATION_SILENT,
+};
+
+//! @brief Read M500 configuration
+//! @retval true Succeeded. Stored settings retrieved or default settings retrieved in case EEPROM has been erased.
+//! @retval false Failed. Default settings has been retrieved, because of older version or corrupted data.
+bool Config_RetrieveSettings()
+{
+	bool previous_settings_retrieved = true;
+    char ver[4]=EEPROM_VERSION;
+    EEPROM_readData(reinterpret_cast<uint8_t*>(EEPROM_M500_base->version), reinterpret_cast<uint8_t*>(cs.version), sizeof(cs.version), "cs.version"); //read stored version
+    //  SERIAL_ECHOLN("Version: [" << ver << "] Stored version: [" << cs.version << "]");
+    if (strncmp(ver,cs.version,3) == 0)  // version number match
+    {
+
+        EEPROM_readData(reinterpret_cast<uint8_t*>(EEPROM_M500_base), reinterpret_cast<uint8_t*>(&cs), sizeof(cs), "cs");
+
+        
+		if (cs.max_jerk[X_AXIS] > DEFAULT_XJERK) cs.max_jerk[X_AXIS] = DEFAULT_XJERK;
+		if (cs.max_jerk[Y_AXIS] > DEFAULT_YJERK) cs.max_jerk[Y_AXIS] = DEFAULT_YJERK;
+        calculate_extruder_multipliers();
 
-		calculate_extruder_multipliers();
-		int max_feedrate_silent_address = i;
-        EEPROM_READ_VAR(i,max_feedrate_silent);  
-        EEPROM_READ_VAR(i,max_acceleration_units_per_sq_second_silent);
 
 		//if max_feedrate_silent and max_acceleration_units_per_sq_second_silent were never stored to eeprom, use default values:
-	    float tmp_feedrate[]=DEFAULT_MAX_FEEDRATE_SILENT;
-		unsigned long tmp_acceleration[]=DEFAULT_MAX_ACCELERATION_SILENT;
-		for (uint8_t axis = X_AXIS; axis <= E_AXIS; axis++) {
-			if (eeprom_read_dword((uint32_t*)(max_feedrate_silent_address + axis * 4)) == 0xffffffff) max_feedrate_silent[axis] = tmp_feedrate[axis];
-			if (max_acceleration_units_per_sq_second_silent[axis] == 0xffffffff) max_acceleration_units_per_sq_second_silent[axis] = tmp_acceleration[axis];
-		}
+        {
+            const uint32_t erased = 0xffffffff;
+            bool initialized = false;
+            for (uint8_t i = 0; i < (sizeof(cs.max_feedrate_silent)/sizeof(cs.max_feedrate_silent[0])); ++i)
+            {
+                for(uint8_t j = 0; j < sizeof(float); ++j)
+                {
+                    if(0xff != reinterpret_cast<uint8_t*>(&(cs.max_feedrate_silent[i]))[j]) initialized = true;
+                }
+                if(erased != cs.max_acceleration_units_per_sq_second_silent[i]) initialized = true;
+            }
+            if (!initialized)
+            {
+                memcpy_P(&cs.max_feedrate_silent,&default_conf.max_feedrate_silent, sizeof(cs.max_feedrate_silent));
+                memcpy_P(&cs.max_acceleration_units_per_sq_second_silent,&default_conf.max_acceleration_units_per_sq_second_silent,
+                        sizeof(cs.max_acceleration_units_per_sq_second_silent));
+            }
+        }
 
 #ifdef TMC2130
 		for (uint8_t j = X_AXIS; j <= Y_AXIS; j++)
 		{
-			if (max_feedrate_normal[j] > NORMAL_MAX_FEEDRATE_XY)
-				max_feedrate_normal[j] = NORMAL_MAX_FEEDRATE_XY;
-			if (max_feedrate_silent[j] > SILENT_MAX_FEEDRATE_XY)
-				max_feedrate_silent[j] = SILENT_MAX_FEEDRATE_XY;
-			if (max_acceleration_units_per_sq_second_normal[j] > NORMAL_MAX_ACCEL_XY)
-				max_acceleration_units_per_sq_second_normal[j] = NORMAL_MAX_ACCEL_XY;
-			if (max_acceleration_units_per_sq_second_silent[j] > SILENT_MAX_ACCEL_XY)
-				max_acceleration_units_per_sq_second_silent[j] = SILENT_MAX_ACCEL_XY;
+			if (cs.max_feedrate_normal[j] > NORMAL_MAX_FEEDRATE_XY)
+				cs.max_feedrate_normal[j] = NORMAL_MAX_FEEDRATE_XY;
+			if (cs.max_feedrate_silent[j] > SILENT_MAX_FEEDRATE_XY)
+				cs.max_feedrate_silent[j] = SILENT_MAX_FEEDRATE_XY;
+			if (cs.max_acceleration_units_per_sq_second_normal[j] > NORMAL_MAX_ACCEL_XY)
+				cs.max_acceleration_units_per_sq_second_normal[j] = NORMAL_MAX_ACCEL_XY;
+			if (cs.max_acceleration_units_per_sq_second_silent[j] > SILENT_MAX_ACCEL_XY)
+				cs.max_acceleration_units_per_sq_second_silent[j] = SILENT_MAX_ACCEL_XY;
 		}
 #endif //TMC2130
 
@@ -354,27 +280,18 @@ bool Config_RetrieveSettings(uint16_t offset)
 
 		// Call updatePID (similar to when we have processed M301)
 		updatePID();
-
-		if (EEPROM_M500_SIZE + EEPROM_OFFSET == i) {
-			SERIAL_ECHO_START;
-			SERIAL_ECHOLNPGM("Stored settings retrieved");
-
-		}
-		else { //size of eeprom M500 section probably changed by mistake and data are not valid; default values will be used
-			puts_P(PSTR("Data read from EEPROM not valid."));
-			Config_ResetDefault();
-			previous_settings_retrieved = false;
-		}
-
+        SERIAL_ECHO_START;
+        SERIAL_ECHOLNPGM("Stored settings retrieved");
     }
     else
     {
         Config_ResetDefault();
 		//Return false to inform user that eeprom version was changed and firmware is using default hardcoded settings now.
 		//In case that storing to eeprom was not used yet, do not inform user that hardcoded settings are used.
-		if (eeprom_read_byte((uint8_t *)offset) != 0xFF ||
-			eeprom_read_byte((uint8_t *)offset + 1) != 0xFF ||
-			eeprom_read_byte((uint8_t *)offset + 2) != 0xFF) {
+		if (eeprom_read_byte(reinterpret_cast<uint8_t*>(&(EEPROM_M500_base->version[0]))) != 0xFF ||
+			eeprom_read_byte(reinterpret_cast<uint8_t*>(&(EEPROM_M500_base->version[1]))) != 0xFF ||
+			eeprom_read_byte(reinterpret_cast<uint8_t*>(&(EEPROM_M500_base->version[2]))) != 0xFF)
+		{
 			previous_settings_retrieved = false;
 		}
     }
@@ -387,73 +304,18 @@ bool Config_RetrieveSettings(uint16_t offset)
 
 void Config_ResetDefault()
 {
-    float tmp1[]=DEFAULT_AXIS_STEPS_PER_UNIT;
-    float tmp2[]=DEFAULT_MAX_FEEDRATE;
-    long tmp3[]=DEFAULT_MAX_ACCELERATION;
-    float tmp4[]=DEFAULT_MAX_FEEDRATE_SILENT;
-    long tmp5[]=DEFAULT_MAX_ACCELERATION_SILENT;
-    for (short i=0;i<4;i++) 
-    {
-        axis_steps_per_unit[i]=tmp1[i];  
-        max_feedrate_normal[i]=tmp2[i];  
-        max_acceleration_units_per_sq_second_normal[i]=tmp3[i];
-        max_feedrate_silent[i]=tmp4[i];  
-        max_acceleration_units_per_sq_second_silent[i]=tmp5[i];
-    }
+    memcpy_P(&cs,&default_conf, sizeof(cs));
 
 	// steps per sq second need to be updated to agree with the units per sq second
     reset_acceleration_rates();
     
-    acceleration=DEFAULT_ACCELERATION;
-    retract_acceleration=DEFAULT_RETRACT_ACCELERATION;
-    minimumfeedrate=DEFAULT_MINIMUMFEEDRATE;
-    minsegmenttime=DEFAULT_MINSEGMENTTIME;       
-    mintravelfeedrate=DEFAULT_MINTRAVELFEEDRATE;
-    max_jerk[X_AXIS] = DEFAULT_XJERK;
-    max_jerk[Y_AXIS] = DEFAULT_YJERK;
-    max_jerk[Z_AXIS] = DEFAULT_ZJERK;
-    max_jerk[E_AXIS] = DEFAULT_EJERK;
-    add_homing[X_AXIS] = add_homing[Y_AXIS] = add_homing[Z_AXIS] = 0;
-
-#ifdef ENABLE_AUTO_BED_LEVELING
-    zprobe_zoffset = -Z_PROBE_OFFSET_FROM_EXTRUDER;
-#endif
 #ifdef PIDTEMP
-    Kp = DEFAULT_Kp;
-    Ki = scalePID_i(DEFAULT_Ki);
-    Kd = scalePID_d(DEFAULT_Kd);
-    
-    // call updatePID (similar to when we have processed M301)
     updatePID();
-    
 #ifdef PID_ADD_EXTRUSION_RATE
-    Kc = DEFAULT_Kc;
+    Kc = DEFAULT_Kc; //this is not stored by Config_StoreSettings
 #endif//PID_ADD_EXTRUSION_RATE
 #endif//PIDTEMP
 
-#ifdef FWRETRACT
-	autoretract_enabled = false;
-	retract_length = RETRACT_LENGTH;
-#if EXTRUDERS > 1
-	retract_length_swap = RETRACT_LENGTH_SWAP;
-#endif
-	retract_feedrate = RETRACT_FEEDRATE;
-	retract_zlift = RETRACT_ZLIFT;
-	retract_recover_length = RETRACT_RECOVER_LENGTH;
-#if EXTRUDERS > 1
-	retract_recover_length_swap = RETRACT_RECOVER_LENGTH_SWAP;
-#endif
-	retract_recover_feedrate = RETRACT_RECOVER_FEEDRATE;
-#endif
-
-	volumetric_enabled = false;
-	filament_size[0] = DEFAULT_NOMINAL_FILAMENT_DIA;
-#if EXTRUDERS > 1
-	filament_size[1] = DEFAULT_NOMINAL_FILAMENT_DIA;
-#if EXTRUDERS > 2
-	filament_size[2] = DEFAULT_NOMINAL_FILAMENT_DIA;
-#endif
-#endif
 	calculate_extruder_multipliers();
 
 SERIAL_ECHO_START;

+ 39 - 2
Firmware/ConfigurationStore.h

@@ -3,6 +3,43 @@
 #define EEPROM_SETTINGS
 
 #include "Configuration.h"
+#include <stdint.h>
+#include <avr/eeprom.h>
+
+typedef struct
+{
+    char version[4];
+    float axis_steps_per_unit[4];
+    float max_feedrate_normal[4];
+    unsigned long max_acceleration_units_per_sq_second_normal[4];
+    float acceleration; //!< Normal acceleration mm/s^2  THIS IS THE DEFAULT ACCELERATION for all moves. M204 SXXXX
+    float retract_acceleration; //!< mm/s^2 filament pull-pack and push-forward while standing still in the other axis M204 TXXXX
+    float minimumfeedrate;
+    float mintravelfeedrate;
+    unsigned long minsegmenttime;
+    float max_jerk[4]; //!< Jerk is a maximum immediate velocity change.
+    float add_homing[3];
+    float zprobe_zoffset;
+    float Kp;
+    float Ki;
+    float Kd;
+    float bedKp;
+    float bedKi;
+    float bedKd;
+    int lcd_contrast; //!< unused
+    bool autoretract_enabled;
+    float retract_length;
+    float retract_feedrate;
+    float retract_zlift;
+    float retract_recover_length;
+    float retract_recover_feedrate;
+    bool volumetric_enabled;
+    float filament_size[1]; //!< cross-sectional area of filament (in millimeters), typically around 1.75 or 2.85, 0 disables the volumetric calculations for the extruder.
+    float max_feedrate_silent[4]; //!< max speeds for silent mode
+    unsigned long max_acceleration_units_per_sq_second_silent[4];
+} M500_conf;
+
+extern M500_conf cs;
 
 void Config_ResetDefault();
 
@@ -13,8 +50,8 @@ FORCE_INLINE void Config_PrintSettings() {}
 #endif
 
 #ifdef EEPROM_SETTINGS
-void Config_StoreSettings(uint16_t offset);
-bool Config_RetrieveSettings(uint16_t offset);
+void Config_StoreSettings();
+bool Config_RetrieveSettings();
 #else
 FORCE_INLINE void Config_StoreSettings() {}
 FORCE_INLINE void Config_RetrieveSettings() { Config_ResetDefault(); Config_PrintSettings(); }

+ 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');

+ 14 - 17
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
 
 
@@ -269,19 +269,16 @@ extern float homing_feedrate[];
 extern bool axis_relative_modes[];
 extern int feedmultiply;
 extern int extrudemultiply; // Sets extrude multiply factor (in percent) for all extruders
-extern bool volumetric_enabled;
 extern int extruder_multiply[EXTRUDERS]; // sets extrude multiply factor (in percent) for each extruder individually
-extern float filament_size[EXTRUDERS]; // cross-sectional area of filament (in millimeters), typically around 1.75 or 2.85, 0 disables the volumetric calculations for the extruder.
 extern float volumetric_multiplier[EXTRUDERS]; // reciprocal of cross-sectional area of filament (in square millimeters), stored this way to reduce computational burden in planner
 extern float current_position[NUM_AXIS] ;
 extern float destination[NUM_AXIS] ;
-extern float add_homing[3];
 extern float min_pos[3];
 extern float max_pos[3];
 extern bool axis_known_position[3];
-extern float zprobe_zoffset;
 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
@@ -289,10 +286,9 @@ extern unsigned char fanSpeedSoftPwm;
 #endif
 
 #ifdef FWRETRACT
-extern bool autoretract_enabled;
 extern bool retracted[EXTRUDERS];
-extern float retract_length, retract_length_swap, retract_feedrate, retract_zlift;
-extern float retract_recover_length, retract_recover_length_swap, retract_recover_feedrate;
+extern float retract_length_swap;
+extern float retract_recover_length_swap;
 #endif
 
 #ifdef HOST_KEEPALIVE_FEATURE
@@ -333,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;
@@ -360,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)
 
@@ -378,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
 
@@ -390,7 +385,6 @@ float temp_comp_interpolation(float temperature);
 void temp_compensation_apply();
 void temp_compensation_start();
 void show_fw_version_warnings();
-void erase_eeprom_section(uint16_t offset, uint16_t bytes);
 uint8_t check_printer_version();
 
 #ifdef PINDA_THERMISTOR
@@ -418,6 +412,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();
@@ -472,5 +469,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();

+ 544 - 554
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();
@@ -368,15 +235,7 @@ char dir_names[3][9];
 
 bool sortAlpha = false;
 
-bool volumetric_enabled = false;
-float filament_size[EXTRUDERS] = { DEFAULT_NOMINAL_FILAMENT_DIA
-  #if EXTRUDERS > 1
-      , DEFAULT_NOMINAL_FILAMENT_DIA
-    #if EXTRUDERS > 2
-       , DEFAULT_NOMINAL_FILAMENT_DIA
-    #endif
-  #endif
-};
+
 float extruder_multiplier[EXTRUDERS] = {1.0
   #if EXTRUDERS > 1
     , 1.0
@@ -393,13 +252,9 @@ float current_position[NUM_AXIS] = { 0.0, 0.0, 0.0, 0.0 };
 #define _z current_position[Z_AXIS]
 #define _e current_position[E_AXIS]
 
-
-float add_homing[3]={0,0,0};
-
 float min_pos[3] = { X_MIN_POS, Y_MIN_POS, Z_MIN_POS };
 float max_pos[3] = { X_MAX_POS, Y_MAX_POS, Z_MAX_POS };
 bool axis_known_position[3] = {false, false, false};
-float zprobe_zoffset;
 
 // Extruder offset
 #if EXTRUDERS > 1
@@ -415,7 +270,6 @@ uint8_t active_extruder = 0;
 int fanSpeed=0;
 
 #ifdef FWRETRACT
-  bool autoretract_enabled=false;
   bool retracted[EXTRUDERS]={false
     #if EXTRUDERS > 1
     , false
@@ -433,13 +287,8 @@ int fanSpeed=0;
   #endif
   };
 
-  float retract_length = RETRACT_LENGTH;
   float retract_length_swap = RETRACT_LENGTH_SWAP;
-  float retract_feedrate = RETRACT_FEEDRATE;
-  float retract_zlift = RETRACT_ZLIFT;
-  float retract_recover_length = RETRACT_RECOVER_LENGTH;
   float retract_recover_length_swap = RETRACT_RECOVER_LENGTH_SWAP;
-  float retract_recover_feedrate = RETRACT_RECOVER_FEEDRATE;
 #endif
 
   #ifdef PS_DEFAULT_OFF
@@ -468,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;
@@ -530,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======================================
@@ -650,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;
 
 
@@ -748,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
@@ -804,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) {
@@ -895,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++;
@@ -921,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;
@@ -968,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;
@@ -1023,11 +866,6 @@ uint8_t check_printer_version()
 	return version_changed;
 }
 
-void erase_eeprom_section(uint16_t offset, uint16_t bytes)
-{
-	for (unsigned int i = offset; i < (offset+bytes); i++) eeprom_write_byte((uint8_t*)i, 0xFF);
-}
-
 #ifdef BOOTAPP
 #include "bootapp.h" //bootloader support
 #endif //BOOTAPP
@@ -1343,7 +1181,7 @@ void setup()
 	bool previous_settings_retrieved = false; 
 	uint8_t hw_changed = check_printer_version();
 	if (!(hw_changed & 0b10)) { //if printer version wasn't changed, check for eeprom version and retrieve settings from eeprom in case that version wasn't changed
-		previous_settings_retrieved = Config_RetrieveSettings(EEPROM_OFFSET);
+		previous_settings_retrieved = Config_RetrieveSettings();
 	} 
 	else { //printer version was changed so use default settings 
 		Config_ResetDefault();
@@ -1641,10 +1479,10 @@ void setup()
 
   if (!previous_settings_retrieved) {
 	  lcd_show_fullscreen_message_and_wait_P(_i("Old settings found. Default PID, Esteps etc. will be set.")); //if EEPROM version or printer type was changed, inform user that default setting were loaded////MSG_DEFAULT_SETTINGS_LOADED c=20 r=4
-	  erase_eeprom_section(EEPROM_OFFSET, EEPROM_M500_SIZE); 							   //erase M500 part of eeprom
+	  Config_StoreSettings();
   }
   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 ||
@@ -2005,32 +1843,34 @@ XYZ_CONSTS_FROM_CONFIG(float, home_retract_mm, HOME_RETRACT_MM);
 XYZ_CONSTS_FROM_CONFIG(signed char, home_dir,  HOME_DIR);
 
 static void axis_is_at_home(int axis) {
-  current_position[axis] = base_home_pos(axis) + add_homing[axis];
-  min_pos[axis] =          base_min_pos(axis) + add_homing[axis];
-  max_pos[axis] =          base_max_pos(axis) + add_homing[axis];
+  current_position[axis] = base_home_pos(axis) + cs.add_homing[axis];
+  min_pos[axis] =          base_min_pos(axis) + cs.add_homing[axis];
+  max_pos[axis] =          base_max_pos(axis) + cs.add_homing[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();
 }
 
@@ -2056,7 +1896,7 @@ static void set_bed_level_equation_lsq(double *plane_equation_coefficients)
     current_position[Z_AXIS] = corrected_position.z;
 
     // put the bed at 0 so we don't go below it.
-    current_position[Z_AXIS] = zprobe_zoffset; // in the lsq we reach here after raising the extruder due to the loop structure
+    current_position[Z_AXIS] = cs.zprobe_zoffset; // in the lsq we reach here after raising the extruder due to the loop structure
 
     plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
 }
@@ -2084,7 +1924,7 @@ static void set_bed_level_equation_3pts(float z_at_pt_1, float z_at_pt_2, float
     current_position[Z_AXIS] = corrected_position.z;
 
     // put the bed at 0 so we don't go below it.
-    current_position[Z_AXIS] = zprobe_zoffset;
+    current_position[Z_AXIS] = cs.zprobe_zoffset;
 
     plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
 
@@ -2263,43 +2103,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
@@ -2323,10 +2163,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
 
@@ -2334,9 +2174,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]);
@@ -2416,13 +2256,13 @@ void refresh_cmd_timeout(void)
       destination[Y_AXIS]=current_position[Y_AXIS];
       destination[Z_AXIS]=current_position[Z_AXIS];
       destination[E_AXIS]=current_position[E_AXIS];
-      current_position[E_AXIS]+=(swapretract?retract_length_swap:retract_length)*float(extrudemultiply)*0.01f;
+      current_position[E_AXIS]+=(swapretract?retract_length_swap:cs.retract_length)*float(extrudemultiply)*0.01f;
       plan_set_e_position(current_position[E_AXIS]);
       float oldFeedrate = feedrate;
-      feedrate=retract_feedrate*60;
+      feedrate=cs.retract_feedrate*60;
       retracted[active_extruder]=true;
       prepare_move();
-      current_position[Z_AXIS]-=retract_zlift;
+      current_position[Z_AXIS]-=cs.retract_zlift;
       plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
       prepare_move();
       feedrate = oldFeedrate;
@@ -2431,12 +2271,12 @@ void refresh_cmd_timeout(void)
       destination[Y_AXIS]=current_position[Y_AXIS];
       destination[Z_AXIS]=current_position[Z_AXIS];
       destination[E_AXIS]=current_position[E_AXIS];
-      current_position[Z_AXIS]+=retract_zlift;
+      current_position[Z_AXIS]+=cs.retract_zlift;
       plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
-      current_position[E_AXIS]-=(swapretract?(retract_length_swap+retract_recover_length_swap):(retract_length+retract_recover_length))*float(extrudemultiply)*0.01f;
+      current_position[E_AXIS]-=(swapretract?(retract_length_swap+retract_recover_length_swap):(cs.retract_length+cs.retract_recover_length))*float(extrudemultiply)*0.01f;
       plan_set_e_position(current_position[E_AXIS]);
       float oldFeedrate = feedrate;
-      feedrate=retract_recover_feedrate*60;
+      feedrate=cs.retract_recover_feedrate*60;
       retracted[active_extruder]=false;
       prepare_move();
       feedrate = oldFeedrate;
@@ -2615,7 +2455,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();
 
@@ -2686,10 +2526,10 @@ void gcode_G28(bool home_x_axis, long home_x_value, bool home_y_axis, long home_
 
 
       if(home_x_axis && home_x_value != 0)
-        current_position[X_AXIS]=home_x_value+add_homing[X_AXIS];
+        current_position[X_AXIS]=home_x_value+cs.add_homing[X_AXIS];
 
       if(home_y_axis && home_y_value != 0)
-        current_position[Y_AXIS]=home_y_value+add_homing[Y_AXIS];
+        current_position[Y_AXIS]=home_y_value+cs.add_homing[Y_AXIS];
 
       #if Z_HOME_DIR < 0                      // If homing towards BED do Z last
         #ifndef Z_SAFE_HOMING
@@ -2785,10 +2625,10 @@ void gcode_G28(bool home_x_axis, long home_x_value, bool home_y_axis, long home_
       #endif // Z_HOME_DIR < 0
 
       if(home_z_axis && home_z_value != 0)
-        current_position[Z_AXIS]=home_z_value+add_homing[Z_AXIS];
+        current_position[Z_AXIS]=home_z_value+cs.add_homing[Z_AXIS];
       #ifdef ENABLE_AUTO_BED_LEVELING
         if(home_z)
-          current_position[Z_AXIS] += zprobe_zoffset;  //Add Z_Probe offset (the distance is negative)
+          current_position[Z_AXIS] += cs.zprobe_zoffset;  //Add Z_Probe offset (the distance is negative)
       #endif
       
       // Set the planner and stepper routine positions.
@@ -2801,7 +2641,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
@@ -2852,6 +2692,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;
@@ -2881,7 +2726,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();
 
@@ -2939,18 +2784,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();
@@ -2975,7 +2811,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);
@@ -2992,10 +2828,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);
@@ -3049,128 +2885,135 @@ void gcode_M114()
 	SERIAL_PROTOCOL(current_position[E_AXIS]);
 
 	SERIAL_PROTOCOLRPGM(_n(" Count X: "));////MSG_COUNT_X c=0 r=0
-	SERIAL_PROTOCOL(float(st_get_position(X_AXIS)) / axis_steps_per_unit[X_AXIS]);
+	SERIAL_PROTOCOL(float(st_get_position(X_AXIS)) / cs.axis_steps_per_unit[X_AXIS]);
 	SERIAL_PROTOCOLPGM(" Y:");
-	SERIAL_PROTOCOL(float(st_get_position(Y_AXIS)) / axis_steps_per_unit[Y_AXIS]);
+	SERIAL_PROTOCOL(float(st_get_position(Y_AXIS)) / cs.axis_steps_per_unit[Y_AXIS]);
 	SERIAL_PROTOCOLPGM(" Z:");
-	SERIAL_PROTOCOL(float(st_get_position(Z_AXIS)) / axis_steps_per_unit[Z_AXIS]);
+	SERIAL_PROTOCOL(float(st_get_position(Z_AXIS)) / cs.axis_steps_per_unit[Z_AXIS]);
 	SERIAL_PROTOCOLPGM(" E:");
-	SERIAL_PROTOCOL(float(st_get_position(E_AXIS)) / axis_steps_per_unit[E_AXIS]);
+	SERIAL_PROTOCOL(float(st_get_position(E_AXIS)) / cs.axis_steps_per_unit[E_AXIS]);
 
 	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(!automatic) M600_check_state();
+    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();
 
 		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);
+    }
+
+    //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();
 
-      //Set E position to original  
-      plan_set_e_position(lastpos[E_AXIS]);
+    //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;
-        
+    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;
 }
 
 
@@ -3299,7 +3142,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
@@ -3341,21 +3313,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');
@@ -3365,7 +3337,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');
@@ -3376,7 +3348,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');
@@ -3427,22 +3399,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);
 		  }
@@ -3451,20 +3423,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
@@ -3480,7 +3452,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);
@@ -3495,35 +3467,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();
@@ -3546,7 +3518,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];
@@ -3717,7 +3689,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 			total_filament_used = total_filament_used + ((destination[E_AXIS] - current_position[E_AXIS]) * 100);
 		}
           #ifdef FWRETRACT
-            if(autoretract_enabled)
+            if(cs.autoretract_enabled)
             if( !(code_seen('X') || code_seen('Y') || code_seen('Z')) && code_seen('E')) {
               float echange=destination[E_AXIS]-current_position[E_AXIS];
 
@@ -3828,7 +3800,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
@@ -3894,7 +3866,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);
@@ -3923,7 +3895,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);
 
@@ -3934,7 +3906,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
             // The following code correct the Z height difference from z-probe position and hotend tip position.
             // The Z height on homing is measured by Z-Probe, but the probe is quite far from the hotend.
             // When the bed is uneven, this height must be corrected.
-            real_z = float(st_get_position(Z_AXIS))/axis_steps_per_unit[Z_AXIS];  //get the real Z (since the auto bed leveling is already correcting the plane)
+            real_z = float(st_get_position(Z_AXIS))/cs.axis_steps_per_unit[Z_AXIS];  //get the real Z (since the auto bed leveling is already correcting the plane)
             x_tmp = current_position[X_AXIS] + X_PROBE_OFFSET_FROM_EXTRUDER;
             y_tmp = current_position[Y_AXIS] + Y_PROBE_OFFSET_FROM_EXTRUDER;
             z_tmp = current_position[Z_AXIS];
@@ -3949,7 +3921,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];
 
@@ -3963,7 +3935,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
@@ -3981,7 +3953,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];
 
@@ -3989,7 +3961,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;
 	
@@ -4001,7 +3973,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)
@@ -4140,7 +4112,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 					lcd_temp_cal_show_result(find_z_result);
 					break;
 				}
-				z_shift = (int)((current_position[Z_AXIS] - zero_z)*axis_steps_per_unit[Z_AXIS]);
+				z_shift = (int)((current_position[Z_AXIS] - zero_z)*cs.axis_steps_per_unit[Z_AXIS]);
 
 				printf_P(_N("\nPINDA temperature: %.1f Z shift (mm): %.3f"), current_temperature_pinda, current_position[Z_AXIS] - zero_z);
 
@@ -4227,7 +4199,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder);
 			st_synchronize();
 			find_bed_induction_sensor_point_z(-1.f);
-			z_shift = (int)((current_position[Z_AXIS] - zero_z)*axis_steps_per_unit[Z_AXIS]);
+			z_shift = (int)((current_position[Z_AXIS] - zero_z)*cs.axis_steps_per_unit[Z_AXIS]);
 
 			printf_P(_N("\nTemperature: %d  Z shift (mm): %.3f\n"), t_c, current_position[Z_AXIS] - zero_z);
 
@@ -4260,12 +4232,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;
@@ -4304,12 +4273,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:
@@ -4414,7 +4383,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.
@@ -4521,7 +4490,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;
@@ -4645,9 +4614,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");
@@ -4735,14 +4704,14 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
              plan_set_e_position(current_position[E_AXIS]);
            }
            else {
-		current_position[i] = code_value()+add_homing[i];
+		current_position[i] = code_value()+cs.add_homing[i];
             plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
            }
         }
       }
       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);
@@ -4751,7 +4720,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);
@@ -4997,7 +4966,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);
@@ -5011,7 +4980,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');
@@ -5051,14 +5020,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);
@@ -5074,7 +5043,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')) {
@@ -5083,7 +5052,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);
@@ -5093,23 +5062,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
@@ -5213,7 +5181,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);
@@ -5277,7 +5245,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];
@@ -5328,9 +5296,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: ");
@@ -5575,7 +5543,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);
         }
@@ -5691,20 +5659,20 @@ Sigma_Exit:
           if(i == 3) { // E
             float value = code_value();
             if(value < 20.0) {
-              float factor = axis_steps_per_unit[i] / value; // increase e constants if M92 E14 is given for netfab.
-              max_jerk[E_AXIS] *= factor;
+              float factor = cs.axis_steps_per_unit[i] / value; // increase e constants if M92 E14 is given for netfab.
+              cs.max_jerk[E_AXIS] *= factor;
               max_feedrate[i] *= factor;
               axis_steps_per_sqr_second[i] *= factor;
             }
-            axis_steps_per_unit[i] = value;
+            cs.axis_steps_per_unit[i] = value;
           }
           else {
-            axis_steps_per_unit[i] = code_value();
+            cs.axis_steps_per_unit[i] = code_value();
           }
         }
       }
       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;
@@ -5751,10 +5719,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
@@ -5849,18 +5817,18 @@ Sigma_Exit:
 			// setting any extruder filament size disables volumetric on the assumption that
 			// slicers either generate in extruder values as cubic mm or as as filament feeds
 			// for all extruders
-		    volumetric_enabled = false;
+		    cs.volumetric_enabled = false;
 		  } else {
-            filament_size[extruder] = (float)code_value();
+            cs.filament_size[extruder] = (float)code_value();
 			// make sure all extruders have some sane value for the filament size
-			filament_size[0] = (filament_size[0] == 0.0 ? DEFAULT_NOMINAL_FILAMENT_DIA : filament_size[0]);
+			cs.filament_size[0] = (cs.filament_size[0] == 0.0 ? DEFAULT_NOMINAL_FILAMENT_DIA : cs.filament_size[0]);
             #if EXTRUDERS > 1
-			filament_size[1] = (filament_size[1] == 0.0 ? DEFAULT_NOMINAL_FILAMENT_DIA : filament_size[1]);
+			cs.filament_size[1] = (cs.filament_size[1] == 0.0 ? DEFAULT_NOMINAL_FILAMENT_DIA : cs.filament_size[1]);
             #if EXTRUDERS > 2
-			filament_size[2] = (filament_size[2] == 0.0 ? DEFAULT_NOMINAL_FILAMENT_DIA : filament_size[2]);
+			cs.filament_size[2] = (cs.filament_size[2] == 0.0 ? DEFAULT_NOMINAL_FILAMENT_DIA : cs.filament_size[2]);
             #endif
             #endif
-			volumetric_enabled = true;
+			cs.volumetric_enabled = true;
 		  }
         } else {
           //reserved for setting filament diameter via UFID or filament measuring device
@@ -5884,8 +5852,8 @@ Sigma_Exit:
 					if (val_silent > SILENT_MAX_ACCEL_XY)
 						val_silent = SILENT_MAX_ACCEL_XY;
 				}
-				max_acceleration_units_per_sq_second_normal[i] = val;
-				max_acceleration_units_per_sq_second_silent[i] = val_silent;
+				cs.max_acceleration_units_per_sq_second_normal[i] = val;
+				cs.max_acceleration_units_per_sq_second_silent[i] = val_silent;
 #else //TMC2130
 				max_acceleration_units_per_sq_second[i] = val;
 #endif //TMC2130
@@ -5897,7 +5865,7 @@ Sigma_Exit:
     #if 0 // Not used for Sprinter/grbl gen6
     case 202: // M202
       for(int8_t i=0; i < NUM_AXIS; i++) {
-        if(code_seen(axis_codes[i])) axis_travel_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i];
+        if(code_seen(axis_codes[i])) axis_travel_steps_per_sqr_second[i] = code_value() * cs.axis_steps_per_unit[i];
       }
       break;
     #endif
@@ -5916,8 +5884,8 @@ Sigma_Exit:
 					if (val_silent > SILENT_MAX_FEEDRATE_XY)
 						val_silent = SILENT_MAX_FEEDRATE_XY;
 				}
-				max_feedrate_normal[i] = val;
-				max_feedrate_silent[i] = val_silent;
+				cs.max_feedrate_normal[i] = val;
+				cs.max_feedrate_silent[i] = val_silent;
 #else //TMC2130
 				max_feedrate[i] = val;
 #endif //TMC2130
@@ -5925,24 +5893,24 @@ 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,
           // and it is also generated by Slic3r to control acceleration per extrusion type
           // (there is a separate acceleration settings in Slicer for perimeter, first layer etc).
-          acceleration = code_value();
+          cs.acceleration = code_value();
           // Interpret the T value as retract acceleration in the old Marlin format.
           if(code_seen('T'))
-            retract_acceleration = code_value();
+            cs.retract_acceleration = code_value();
         } else {
           // New acceleration format, compatible with the upstream Marlin.
           if(code_seen('P'))
-            acceleration = code_value();
+            cs.acceleration = code_value();
           if(code_seen('R'))
-            retract_acceleration = code_value();
+            cs.retract_acceleration = code_value();
           if(code_seen('T')) {
             // Interpret the T value as the travel acceleration in the new Marlin format.
             //FIXME Prusa3D firmware currently does not support travel acceleration value independent from the extruding acceleration value.
@@ -5953,21 +5921,21 @@ Sigma_Exit:
       break;
     case 205: //M205 advanced settings:  minimum travel speed S=while printing T=travel only,  B=minimum segment time X= maximum xy jerk, Z=maximum Z jerk
     {
-      if(code_seen('S')) minimumfeedrate = code_value();
-      if(code_seen('T')) mintravelfeedrate = code_value();
-      if(code_seen('B')) minsegmenttime = code_value() ;
-      if(code_seen('X')) max_jerk[X_AXIS] = max_jerk[Y_AXIS] = code_value();
-      if(code_seen('Y')) max_jerk[Y_AXIS] = code_value();
-      if(code_seen('Z')) max_jerk[Z_AXIS] = code_value();
-      if(code_seen('E')) max_jerk[E_AXIS] = code_value();
-		if (max_jerk[X_AXIS] > DEFAULT_XJERK) max_jerk[X_AXIS] = DEFAULT_XJERK;
-		if (max_jerk[Y_AXIS] > DEFAULT_YJERK) max_jerk[Y_AXIS] = DEFAULT_YJERK;
+      if(code_seen('S')) cs.minimumfeedrate = code_value();
+      if(code_seen('T')) cs.mintravelfeedrate = code_value();
+      if(code_seen('B')) cs.minsegmenttime = code_value() ;
+      if(code_seen('X')) cs.max_jerk[X_AXIS] = cs.max_jerk[Y_AXIS] = code_value();
+      if(code_seen('Y')) cs.max_jerk[Y_AXIS] = code_value();
+      if(code_seen('Z')) cs.max_jerk[Z_AXIS] = code_value();
+      if(code_seen('E')) cs.max_jerk[E_AXIS] = code_value();
+		if (cs.max_jerk[X_AXIS] > DEFAULT_XJERK) cs.max_jerk[X_AXIS] = DEFAULT_XJERK;
+		if (cs.max_jerk[Y_AXIS] > DEFAULT_YJERK) cs.max_jerk[Y_AXIS] = DEFAULT_YJERK;
     }
     break;
     case 206: // M206 additional homing offset
       for(int8_t i=0; i < 3; i++)
       {
-        if(code_seen(axis_codes[i])) add_homing[i] = code_value();
+        if(code_seen(axis_codes[i])) cs.add_homing[i] = code_value();
       }
       break;
     #ifdef FWRETRACT
@@ -5975,26 +5943,26 @@ Sigma_Exit:
     {
       if(code_seen('S'))
       {
-        retract_length = code_value() ;
+        cs.retract_length = code_value() ;
       }
       if(code_seen('F'))
       {
-        retract_feedrate = code_value()/60 ;
+        cs.retract_feedrate = code_value()/60 ;
       }
       if(code_seen('Z'))
       {
-        retract_zlift = code_value() ;
+        cs.retract_zlift = code_value() ;
       }
     }break;
     case 208: // M208 - set retract recover length S[positive mm surplus to the M207 S*] F[feedrate mm/min]
     {
       if(code_seen('S'))
       {
-        retract_recover_length = code_value() ;
+        cs.retract_recover_length = code_value() ;
       }
       if(code_seen('F'))
       {
-        retract_recover_feedrate = code_value()/60 ;
+        cs.retract_recover_feedrate = code_value()/60 ;
       }
     }break;
     case 209: // 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.
@@ -6006,7 +5974,7 @@ Sigma_Exit:
         {
           case 0: 
           {
-            autoretract_enabled=false;
+            cs.autoretract_enabled=false;
             retracted[0]=false;
             #if EXTRUDERS > 1
               retracted[1]=false;
@@ -6017,7 +5985,7 @@ Sigma_Exit:
           }break;
           case 1: 
           {
-            autoretract_enabled=true;
+            cs.autoretract_enabled=true;
             retracted[0]=false;
             #if EXTRUDERS > 1
               retracted[1]=false;
@@ -6208,9 +6176,9 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
     #ifdef PIDTEMP
     case 301: // M301
       {
-        if(code_seen('P')) Kp = code_value();
-        if(code_seen('I')) Ki = scalePID_i(code_value());
-        if(code_seen('D')) Kd = scalePID_d(code_value());
+        if(code_seen('P')) cs.Kp = code_value();
+        if(code_seen('I')) cs.Ki = scalePID_i(code_value());
+        if(code_seen('D')) cs.Kd = scalePID_d(code_value());
 
         #ifdef PID_ADD_EXTRUSION_RATE
         if(code_seen('C')) Kc = code_value();
@@ -6219,11 +6187,11 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
         updatePID();
         SERIAL_PROTOCOLRPGM(_T(MSG_OK));
         SERIAL_PROTOCOL(" p:");
-        SERIAL_PROTOCOL(Kp);
+        SERIAL_PROTOCOL(cs.Kp);
         SERIAL_PROTOCOL(" i:");
-        SERIAL_PROTOCOL(unscalePID_i(Ki));
+        SERIAL_PROTOCOL(unscalePID_i(cs.Ki));
         SERIAL_PROTOCOL(" d:");
-        SERIAL_PROTOCOL(unscalePID_d(Kd));
+        SERIAL_PROTOCOL(unscalePID_d(cs.Kd));
         #ifdef PID_ADD_EXTRUSION_RATE
         SERIAL_PROTOCOL(" c:");
         //Kc does not have scaling applied above, or in resetting defaults
@@ -6236,18 +6204,18 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
     #ifdef PIDTEMPBED
     case 304: // M304
       {
-        if(code_seen('P')) bedKp = code_value();
-        if(code_seen('I')) bedKi = scalePID_i(code_value());
-        if(code_seen('D')) bedKd = scalePID_d(code_value());
+        if(code_seen('P')) cs.bedKp = code_value();
+        if(code_seen('I')) cs.bedKi = scalePID_i(code_value());
+        if(code_seen('D')) cs.bedKd = scalePID_d(code_value());
 
         updatePID();
        	SERIAL_PROTOCOLRPGM(_T(MSG_OK));
         SERIAL_PROTOCOL(" p:");
-        SERIAL_PROTOCOL(bedKp);
+        SERIAL_PROTOCOL(cs.bedKp);
         SERIAL_PROTOCOL(" i:");
-        SERIAL_PROTOCOL(unscalePID_i(bedKi));
+        SERIAL_PROTOCOL(unscalePID_i(cs.bedKi));
         SERIAL_PROTOCOL(" d:");
-        SERIAL_PROTOCOL(unscalePID_d(bedKd));
+        SERIAL_PROTOCOL(unscalePID_d(cs.bedKd));
         SERIAL_PROTOCOLLN("");
       }
       break;
@@ -6311,15 +6279,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);
@@ -6329,12 +6297,12 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 
     case 500: // M500 Store settings in EEPROM
     {
-        Config_StoreSettings(EEPROM_OFFSET);
+        Config_StoreSettings();
     }
     break;
     case 501: // M501 Read settings from EEPROM
     {
-        Config_RetrieveSettings(EEPROM_OFFSET);
+        Config_RetrieveSettings();
     }
     break;
     case 502: // M502 Revert to default settings
@@ -6371,7 +6339,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
         value = code_value();
         if ((Z_PROBE_OFFSET_RANGE_MIN <= value) && (value <= Z_PROBE_OFFSET_RANGE_MAX))
         {
-          zprobe_zoffset = -value; // compare w/ line 278 of ConfigurationStore.cpp
+          cs.zprobe_zoffset = -value; // compare w/ line 278 of ConfigurationStore.cpp
           SERIAL_ECHO_START;
           SERIAL_ECHOLNRPGM(CAT4(MSG_ZPROBE_ZOFFSET, " ", _T(MSG_OK),PSTR("")));
           SERIAL_PROTOCOLLN("");
@@ -6391,7 +6359,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
       {
           SERIAL_ECHO_START;
           SERIAL_ECHOLNRPGM(CAT2(MSG_ZPROBE_ZOFFSET, PSTR(" : ")));
-          SERIAL_ECHO(-zprobe_zoffset);
+          SERIAL_ECHO(-cs.zprobe_zoffset);
           SERIAL_PROTOCOLLN("");
       }
       break;
@@ -6476,13 +6444,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;
 
@@ -6540,7 +6509,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 			for (uint8_t i = 0; i < 6; i++)
 			{
 				if(i>0) EEPROM_read_B(EEPROM_PROBE_TEMP_SHIFT + (i-1) * 2, &usteps);
-				float mm = ((float)usteps) / axis_steps_per_unit[Z_AXIS];
+				float mm = ((float)usteps) / cs.axis_steps_per_unit[Z_AXIS];
 				i == 0 ? SERIAL_PROTOCOLPGM("n/a") : SERIAL_PROTOCOL(i - 1);
 				SERIAL_PROTOCOLPGM(", ");
 				SERIAL_PROTOCOL(35 + (i * 5));
@@ -6574,8 +6543,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");
@@ -6583,7 +6552,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 					{
 						usteps = 0;
 						if (i>0) EEPROM_read_B(EEPROM_PROBE_TEMP_SHIFT + (i - 1) * 2, &usteps);
-						float mm = ((float)usteps) / axis_steps_per_unit[Z_AXIS];
+						float mm = ((float)usteps) / cs.axis_steps_per_unit[Z_AXIS];
 						i == 0 ? SERIAL_PROTOCOLPGM("n/a") : SERIAL_PROTOCOL(i - 1);
 						SERIAL_PROTOCOLPGM(", ");
 						SERIAL_PROTOCOL(35 + (i * 5));
@@ -6640,13 +6609,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());
@@ -6655,7 +6624,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());
@@ -6664,13 +6633,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();
@@ -6678,7 +6647,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();
@@ -6686,7 +6655,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();
@@ -6697,7 +6666,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());
@@ -6706,7 +6675,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());
@@ -6717,7 +6686,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'))
@@ -6732,13 +6701,13 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 				if (res_new > res)
 				{
 					uint16_t fac = (res_new / res);
-					axis_steps_per_unit[axis] *= fac;
+					cs.axis_steps_per_unit[axis] *= fac;
 					position[E_AXIS] *= fac;
 				}
 				else
 				{
 					uint16_t fac = (res / res_new);
-					axis_steps_per_unit[axis] /= fac;
+					cs.axis_steps_per_unit[axis] /= fac;
 					position[E_AXIS] /= fac;
 				}
 			}
@@ -6753,7 +6722,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())
@@ -6771,23 +6740,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();
@@ -6807,7 +6776,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;
@@ -6818,8 +6793,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();
@@ -6943,45 +6925,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
 
@@ -7134,7 +7116,7 @@ void clamp_to_software_endstops(float target[3])
         float negative_z_offset = 0;
         #ifdef ENABLE_AUTO_BED_LEVELING
             if (Z_PROBE_OFFSET_FROM_EXTRUDER < 0) negative_z_offset = negative_z_offset + Z_PROBE_OFFSET_FROM_EXTRUDER;
-            if (add_homing[Z_AXIS] < 0) negative_z_offset = negative_z_offset + add_homing[Z_AXIS];
+            if (cs.add_homing[Z_AXIS] < 0) negative_z_offset = negative_z_offset + cs.add_homing[Z_AXIS];
         #endif
         if (target[Z_AXIS] < min_pos[Z_AXIS]+negative_z_offset) target[Z_AXIS] = min_pos[Z_AXIS]+negative_z_offset;
     }
@@ -7445,8 +7427,8 @@ void manage_inactivity(bool ignore_stepper_queue/*=false*/) //default argument s
      float oldepos=current_position[E_AXIS];
      float oldedes=destination[E_AXIS];
      plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS],
-                      destination[E_AXIS]+EXTRUDER_RUNOUT_EXTRUDE*EXTRUDER_RUNOUT_ESTEPS/axis_steps_per_unit[E_AXIS],
-                      EXTRUDER_RUNOUT_SPEED/60.*EXTRUDER_RUNOUT_ESTEPS/axis_steps_per_unit[E_AXIS], active_extruder);
+                      destination[E_AXIS]+EXTRUDER_RUNOUT_EXTRUDE*EXTRUDER_RUNOUT_ESTEPS/cs.axis_steps_per_unit[E_AXIS],
+                      EXTRUDER_RUNOUT_SPEED/60.*EXTRUDER_RUNOUT_ESTEPS/cs.axis_steps_per_unit[E_AXIS], active_extruder);
      current_position[E_AXIS]=oldepos;
      destination[E_AXIS]=oldedes;
      plan_set_e_position(oldepos);
@@ -7651,7 +7633,7 @@ void save_statistics(unsigned long _total_filament_used, unsigned long _total_pr
 
 float calculate_extruder_multiplier(float diameter) {
   float out = 1.f;
-  if (volumetric_enabled && diameter > 0.f) {
+  if (cs.volumetric_enabled && diameter > 0.f) {
     float area = M_PI * diameter * diameter * 0.25;
     out = 1.f / area;
   }
@@ -7661,11 +7643,11 @@ float calculate_extruder_multiplier(float diameter) {
 }
 
 void calculate_extruder_multipliers() {
-	extruder_multiplier[0] = calculate_extruder_multiplier(filament_size[0]);
+	extruder_multiplier[0] = calculate_extruder_multiplier(cs.filament_size[0]);
 #if EXTRUDERS > 1
-	extruder_multiplier[1] = calculate_extruder_multiplier(filament_size[1]);
+	extruder_multiplier[1] = calculate_extruder_multiplier(cs.filament_size[1]);
 #if EXTRUDERS > 2
-	extruder_multiplier[2] = calculate_extruder_multiplier(filament_size[2]);
+	extruder_multiplier[2] = calculate_extruder_multiplier(cs.filament_size[2]);
 #endif
 #endif
 }
@@ -7856,7 +7838,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);
@@ -7985,7 +7967,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
 
@@ -8025,10 +8007,10 @@ void temp_compensation_apply() {
 		if (target_temperature_bed % 10 == 0 && target_temperature_bed >= 60 && target_temperature_bed <= 100) {
 			i_add = (target_temperature_bed - 60) / 10;
 			EEPROM_read_B(EEPROM_PROBE_TEMP_SHIFT + i_add * 2, &z_shift);
-			z_shift_mm = z_shift / axis_steps_per_unit[Z_AXIS];
+			z_shift_mm = z_shift / cs.axis_steps_per_unit[Z_AXIS];
 		}else {
 			//interpolation
-			z_shift_mm = temp_comp_interpolation(target_temperature_bed) / axis_steps_per_unit[Z_AXIS];
+			z_shift_mm = temp_comp_interpolation(target_temperature_bed) / cs.axis_steps_per_unit[Z_AXIS];
 		}
 		printf_P(_N("\nZ shift applied:%.3f\n"), z_shift_mm);
 		plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] - z_shift_mm, current_position[E_AXIS], homing_feedrate[Z_AXIS] / 40, active_extruder);
@@ -8111,7 +8093,7 @@ float temp_compensation_pinda_thermistor_offset(float temperature_pinda)
 {
 	if (!temp_cal_active) return 0;
 	if (!calibration_status_pinda()) return 0;
-	return temp_comp_interpolation(temperature_pinda) / axis_steps_per_unit[Z_AXIS];
+	return temp_comp_interpolation(temperature_pinda) / cs.axis_steps_per_unit[Z_AXIS];
 }
 #endif //PINDA_THERMISTOR
 
@@ -8119,18 +8101,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;
@@ -8141,9 +8112,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;
@@ -8241,7 +8209,7 @@ void uvlo_()
 		plan_buffer_line(
       current_position[X_AXIS], 
       current_position[Y_AXIS], 
-      current_position[Z_AXIS] + UVLO_Z_AXIS_SHIFT + float((1024 - z_microsteps + 7) >> 4) / axis_steps_per_unit[Z_AXIS], 
+      current_position[Z_AXIS] + UVLO_Z_AXIS_SHIFT + float((1024 - z_microsteps + 7) >> 4) / cs.axis_steps_per_unit[Z_AXIS], 
       current_position[E_AXIS] - default_retraction,
       40, active_extruder);
     
@@ -8251,7 +8219,7 @@ void uvlo_()
     plan_buffer_line(
                      current_position[X_AXIS],
                      current_position[Y_AXIS],
-                     current_position[Z_AXIS] + UVLO_Z_AXIS_SHIFT + float((1024 - z_microsteps + 7) >> 4) / axis_steps_per_unit[Z_AXIS],
+                     current_position[Z_AXIS] + UVLO_Z_AXIS_SHIFT + float((1024 - z_microsteps + 7) >> 4) / cs.axis_steps_per_unit[Z_AXIS],
                      current_position[E_AXIS] - default_retraction,
                      40, active_extruder);
     st_synchronize();
@@ -8343,7 +8311,7 @@ plan_buffer_line(
      current_position[X_AXIS], 
      current_position[Y_AXIS], 
 //     current_position[Z_AXIS]+float((1024-z_microsteps+7)>>4)/axis_steps_per_unit[Z_AXIS], 
-     current_position[Z_AXIS]+UVLO_Z_AXIS_SHIFT+float((1024-z_microsteps+7)>>4)/axis_steps_per_unit[Z_AXIS], 
+     current_position[Z_AXIS]+UVLO_Z_AXIS_SHIFT+float((1024-z_microsteps+7)>>4)/cs.axis_steps_per_unit[Z_AXIS], 
      current_position[E_AXIS],
      40, active_extruder);
 st_synchronize();
@@ -8467,10 +8435,10 @@ void recover_machine_state_after_power_panic(bool bTiny)
   // The current position after power panic is moved to the next closest 0th full step.
   if(bTiny)
     current_position[Z_AXIS] = eeprom_read_float((float*)(EEPROM_UVLO_TINY_CURRENT_POSITION_Z)) + 
-    UVLO_Z_AXIS_SHIFT + float((1024 - eeprom_read_word((uint16_t*)(EEPROM_UVLO_TINY_Z_MICROSTEPS)) + 7) >> 4) / axis_steps_per_unit[Z_AXIS];
+    UVLO_Z_AXIS_SHIFT + float((1024 - eeprom_read_word((uint16_t*)(EEPROM_UVLO_TINY_Z_MICROSTEPS)) + 7) >> 4) / cs.axis_steps_per_unit[Z_AXIS];
   else
     current_position[Z_AXIS] = eeprom_read_float((float*)(EEPROM_UVLO_CURRENT_POSITION_Z)) + 
-    UVLO_Z_AXIS_SHIFT + float((1024 - eeprom_read_word((uint16_t*)(EEPROM_UVLO_Z_MICROSTEPS)) + 7) >> 4) / axis_steps_per_unit[Z_AXIS];
+    UVLO_Z_AXIS_SHIFT + float((1024 - eeprom_read_word((uint16_t*)(EEPROM_UVLO_Z_MICROSTEPS)) + 7) >> 4) / cs.axis_steps_per_unit[Z_AXIS];
   if (eeprom_read_byte((uint8_t*)EEPROM_UVLO_E_ABS)) {
 	  current_position[E_AXIS] = eeprom_read_float((float*)(EEPROM_UVLO_CURRENT_POSITION_E));
 	  sprintf_P(cmd, PSTR("G92 E"));
@@ -8606,9 +8574,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;
@@ -8744,9 +8717,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();
@@ -8791,14 +8766,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:
@@ -8894,7 +8882,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
@@ -8928,8 +8915,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);
 
@@ -8969,9 +8961,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.

+ 5 - 2
Firmware/eeprom.h

@@ -184,7 +184,10 @@
 // Magic string, indicating that the current or the previous firmware running was the Prusa3D firmware.
 #define EEPROM_FIRMWARE_PRUSA_MAGIC 0
 
-#define EEPROM_OFFSET 20 //offset for storing settings using M500
-#define EEPROM_M500_SIZE 188 //size of M500 eeprom section in bytes; if EEPROM_M500_SIZE increases it is necessary to update also EEPROM_VERSION
+#ifdef __cplusplus
+#include "ConfigurationStore.h"
+static M500_conf * const EEPROM_M500_base = reinterpret_cast<M500_conf*>(20); //offset for storing settings using M500
+#endif
+
 
 #endif // EEPROM_H

+ 84 - 65
Firmware/fsensor.cpp

@@ -1,3 +1,5 @@
+//! @file
+
 #include "Marlin.h"
 
 #include "fsensor.h"
@@ -7,61 +9,79 @@
 #include "planner.h"
 #include "fastio.h"
 #include "cmdqueue.h"
-
-//Basic params
-#define FSENSOR_CHUNK_LEN    0.64F  //filament sensor chunk length 0.64mm
-#define FSENSOR_ERR_MAX         17  //filament sensor maximum error count for runout detection
-
-//Optical quality meassurement params
-#define FSENSOR_OQ_MAX_ES      6    //maximum error sum while loading (length ~64mm = 100chunks)
-#define FSENSOR_OQ_MAX_EM      2    //maximum error counter value while loading
-#define FSENSOR_OQ_MIN_YD      2    //minimum yd per chunk (applied to avg value)
-#define FSENSOR_OQ_MAX_YD      200  //maximum yd per chunk (applied to avg value)
-#define FSENSOR_OQ_MAX_PD      4    //maximum positive deviation (= yd_max/yd_avg)
-#define FSENSOR_OQ_MAX_ND      5    //maximum negative deviation (= yd_avg/yd_min)
-#define FSENSOR_OQ_MAX_SH      13   //maximum shutter value
-
+#include "ultralcd.h"
+#include "ConfigurationStore.h"
+
+//! @name Basic parameters
+//! @{
+#define FSENSOR_CHUNK_LEN    0.64F  //!< filament sensor chunk length 0.64mm
+#define FSENSOR_ERR_MAX         17  //!< filament sensor maximum error count for runout detection
+//! @}
+
+//! @name Optical quality measurement parameters
+//! @{
+#define FSENSOR_OQ_MAX_ES      6    //!< maximum error sum while loading (length ~64mm = 100chunks)
+#define FSENSOR_OQ_MAX_EM      2    //!< maximum error counter value while loading
+#define FSENSOR_OQ_MIN_YD      2    //!< minimum yd per chunk (applied to avg value)
+#define FSENSOR_OQ_MAX_YD      200  //!< maximum yd per chunk (applied to avg value)
+#define FSENSOR_OQ_MAX_PD      4    //!< maximum positive deviation (= yd_max/yd_avg)
+#define FSENSOR_OQ_MAX_ND      5    //!< maximum negative deviation (= yd_avg/yd_min)
+#define FSENSOR_OQ_MAX_SH      13   //!< maximum shutter value
+//! @}
 
 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)
+#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"));
+	stop_and_save_print_to_ram(0, 0); //XYZE - no change	
+}
+
+void fsensor_restore_print_and_continue(void)
+{
+	printf_P(PSTR("fsensor_restore_print_and_continue\n"));
+	restore_print_from_ram_and_continue(0); //XYZ = orig, E - no change
+}
 
 //uint8_t fsensor_int_pin = FSENSOR_INT_PIN;
 uint8_t fsensor_int_pin_old = 0;
 int16_t fsensor_chunk_len = 0;
 
-//enabled = initialized and sampled every chunk event
+//! enabled = initialized and sampled every chunk event
 bool fsensor_enabled = true;
-//runout watching is done in fsensor_update (called from main loop)
+//! runout watching is done in fsensor_update (called from main loop)
 bool fsensor_watch_runout = true;
-//not responding - is set if any communication error occured durring initialization or readout
+//! not responding - is set if any communication error occurred during initialization or readout
 bool fsensor_not_responding = false;
-//enable/disable quality meassurement
+//! printing saved
+bool fsensor_printing_saved = false;
+//! enable/disable quality meassurement
 bool fsensor_oq_meassure_enabled = false;
 
-//number of errors, updated in ISR
+//! number of errors, updated in ISR
 uint8_t fsensor_err_cnt = 0;
-//variable for accumolating step count (updated callbacks from stepper and ISR)
+//! variable for accumulating step count (updated callbacks from stepper and ISR)
 int16_t fsensor_st_cnt = 0;
-//last dy value from pat9125 sensor (used in ISR)
+//! last dy value from pat9125 sensor (used in ISR)
 int16_t fsensor_dy_old = 0;
 
-//log flag: 0=log disabled, 1=log enabled
+//! log flag: 0=log disabled, 1=log enabled
 uint8_t fsensor_log = 1;
 
-////////////////////////////////////////////////////////////////////////////////
-//filament autoload variables
 
-//autoload feature enabled
-bool fsensor_autoload_enabled = true;
+//! @name filament autoload variables
+//! @{
 
-//autoload watching enable/disable flag
+//! autoload feature enabled
+bool fsensor_autoload_enabled = true;
+//! autoload watching enable/disable flag
 bool fsensor_watch_autoload = false;
 //
 uint16_t fsensor_autoload_y;
@@ -71,30 +91,33 @@ uint8_t fsensor_autoload_c;
 uint32_t fsensor_autoload_last_millis;
 //
 uint8_t fsensor_autoload_sum;
+//! @}
+
 
-////////////////////////////////////////////////////////////////////////////////
-//filament optical quality meassurement variables
+//! @name filament optical quality measurement variables
+//! @{
 
-//meassurement enable/disable flag
+//! Measurement enable/disable flag
 bool fsensor_oq_meassure = false;
-//skip-chunk counter, for accurate meassurement is necesary to skip first chunk...
+//! skip-chunk counter, for accurate measurement is necessary to skip first chunk...
 uint8_t  fsensor_oq_skipchunk;
-//number of samples from start of meassurement
+//! number of samples from start of measurement
 uint8_t fsensor_oq_samples;
-//sum of steps in positive direction movements
+//! sum of steps in positive direction movements
 uint16_t fsensor_oq_st_sum;
-//sum of deltas in positive direction movements
+//! sum of deltas in positive direction movements
 uint16_t fsensor_oq_yd_sum;
-//sum of errors durring meassurement
+//! sum of errors during measurement
 uint16_t fsensor_oq_er_sum;
-//max error counter value durring meassurement
+//! max error counter value during measurement
 uint8_t  fsensor_oq_er_max;
-//minimum delta value
-uint16_t fsensor_oq_yd_min;
-//maximum delta value
-uint16_t fsensor_oq_yd_max;
-//sum of shutter value
+//! minimum delta value
+int16_t fsensor_oq_yd_min;
+//! maximum delta value
+int16_t fsensor_oq_yd_max;
+//! sum of shutter value
 uint16_t fsensor_oq_sh_sum;
+//! @}
 
 void fsensor_stop_and_save_print(void)
 {
@@ -118,7 +141,7 @@ void fsensor_init(void)
 	fsensor_autoload_enabled=eeprom_read_byte((uint8_t*)EEPROM_FSENS_AUTOLOAD_ENABLED);
 	uint8_t oq_meassure_enabled = eeprom_read_byte((uint8_t*)EEPROM_FSENS_OQ_MEASS_ENABLED);
 	fsensor_oq_meassure_enabled = (oq_meassure_enabled == 1)?true:false;
-	fsensor_chunk_len = (int16_t)(FSENSOR_CHUNK_LEN * axis_steps_per_unit[E_AXIS]);
+	fsensor_chunk_len = (int16_t)(FSENSOR_CHUNK_LEN * cs.axis_steps_per_unit[E_AXIS]);
 
 	if (!pat9125)
 	{
@@ -222,7 +245,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
@@ -247,9 +272,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))
 	{
@@ -440,6 +467,11 @@ void fsensor_st_block_chunk(block_t* bl, int cnt)
 	}
 }
 
+//! @brief filament sensor 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 && fsensor_watch_runout && (fsensor_err_cnt > FSENSOR_ERR_MAX))
@@ -454,24 +486,11 @@ 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();
-		KEEPALIVE_STATE(IN_HANDLER);
-        cmdqueue_pop_front();
-        st_synchronize();
+			enquecommand_front_P((PSTR("G1 E-3 F200")));
+			process_commands();
+			KEEPALIVE_STATE(IN_HANDLER);
+			cmdqueue_pop_front();
+			st_synchronize();
 
         enquecommand_front_P((PSTR("G1 E3 F200")));
         process_commands();

+ 22 - 12
Firmware/fsensor.h

@@ -1,55 +1,65 @@
+//! @file
 #ifndef FSENSOR_H
 #define FSENSOR_H
 
 #include <inttypes.h>
 
 
-//minimum meassured chunk length in steps
+//! minimum meassured chunk length in steps
 extern int16_t fsensor_chunk_len;
-//enable/disable flag
+// enable/disable flag
 extern bool fsensor_enabled;
-//not responding flag
+// not responding flag
 extern bool fsensor_not_responding;
 //enable/disable quality meassurement
 extern bool fsensor_oq_meassure_enabled;
 
 
-//save restore printing
+//! @name save restore printing
+//! @{
 extern void fsensor_stop_and_save_print(void);
 extern void fsensor_restore_print_and_continue(void);
+//! @}
 
-//initialize
+//! initialize
 extern void fsensor_init(void);
 
-//enable/disable
+//! @name enable/disable
+//! @{
 extern bool fsensor_enable(void);
 extern void fsensor_disable(void);
+//! @}
 
 //autoload feature enabled
 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
+//! setup pin-change interrupt
 extern void fsensor_setup_interrupt(void);
 
-//autoload support
+//! @name autoload support
+//! @{
 extern void fsensor_autoload_check_start(void);
 extern void fsensor_autoload_check_stop(void);
 extern bool fsensor_check_autoload(void);
+//! @}
 
-//optical quality meassurement support
+//! @name optical quality measurement support
+//! @{
 extern void fsensor_oq_meassure_set(bool State);
 extern void fsensor_oq_meassure_start(uint8_t skip);
 extern void fsensor_oq_meassure_stop(void);
 extern bool fsensor_oq_result(void);
+//! @}
+
 
-//callbacks from stepper
 #include "planner.h"
+//! @name callbacks from stepper
+//! @{
 extern void fsensor_st_block_begin(block_t* bl);
 extern void fsensor_st_block_chunk(block_t* bl, int cnt);
-
+//! @}
 
 #endif //FSENSOR_H

+ 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

@@ -237,6 +237,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;

+ 26 - 15
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();
@@ -3009,7 +3020,7 @@ void babystep_apply()
 {
     babystep_load();
 #ifdef BABYSTEP_LOADZ_BY_PLANNER
-    shift_z(- float(babystepLoadZ) / float(axis_steps_per_unit[Z_AXIS]));
+    shift_z(- float(babystepLoadZ) / float(cs.axis_steps_per_unit[Z_AXIS]));
 #else
     babystepsTodoZadd(babystepLoadZ);
 #endif /* BABYSTEP_LOADZ_BY_PLANNER */
@@ -3018,7 +3029,7 @@ void babystep_apply()
 void babystep_undo()
 {
 #ifdef BABYSTEP_LOADZ_BY_PLANNER
-      shift_z(float(babystepLoadZ) / float(axis_steps_per_unit[Z_AXIS]));
+      shift_z(float(babystepLoadZ) / float(cs.axis_steps_per_unit[Z_AXIS]));
 #else
       babystepsTodoZsubtract(babystepLoadZ);
 #endif /* BABYSTEP_LOADZ_BY_PLANNER */

+ 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);

+ 52 - 66
Firmware/planner.cpp

@@ -57,6 +57,7 @@
 #include "temperature.h"
 #include "ultralcd.h"
 #include "language.h"
+#include "ConfigurationStore.h"
 
 #ifdef MESH_BED_LEVELING
 #include "mesh_bed_leveling.h"
@@ -71,27 +72,12 @@
 //=============================public variables ============================
 //===========================================================================
 
-unsigned long minsegmenttime;
-
 // Use M203 to override by software
-float max_feedrate_normal[NUM_AXIS];       // max speeds for normal mode
-float max_feedrate_silent[NUM_AXIS];       // max speeds for silent mode
-float* max_feedrate = max_feedrate_normal;
+float* max_feedrate = cs.max_feedrate_normal;
 
-// Use M92 to override by software
-float axis_steps_per_unit[NUM_AXIS];
 
 // Use M201 to override by software
-unsigned long max_acceleration_units_per_sq_second_normal[NUM_AXIS];
-unsigned long max_acceleration_units_per_sq_second_silent[NUM_AXIS];
-unsigned long* max_acceleration_units_per_sq_second = max_acceleration_units_per_sq_second_normal;
-
-float minimumfeedrate;
-float acceleration;         // Normal acceleration mm/s^2  THIS IS THE DEFAULT ACCELERATION for all moves. M204 SXXXX
-float retract_acceleration; //  mm/s^2   filament pull-pack and push-forward  while standing still in the other axis M204 TXXXX
-// Jerk is a maximum immediate velocity change.
-float max_jerk[NUM_AXIS];
-float mintravelfeedrate;
+unsigned long* max_acceleration_units_per_sq_second = cs.max_acceleration_units_per_sq_second_normal;
 unsigned long axis_steps_per_sqr_second[NUM_AXIS];
 
 #ifdef ENABLE_AUTO_BED_LEVELING
@@ -623,9 +609,9 @@ void planner_abort_hard()
         else {
             float t = float(step_events_completed) / float(current_block->step_event_count);
             float vec[3] = { 
-              current_block->steps_x / axis_steps_per_unit[X_AXIS],
-              current_block->steps_y / axis_steps_per_unit[Y_AXIS],
-              current_block->steps_z / axis_steps_per_unit[Z_AXIS]
+              current_block->steps_x / cs.axis_steps_per_unit[X_AXIS],
+              current_block->steps_y / cs.axis_steps_per_unit[Y_AXIS],
+              current_block->steps_z / cs.axis_steps_per_unit[Z_AXIS]
             };
             float pos1[3], pos2[3];
             for (int8_t i = 0; i < 3; ++ i) {
@@ -743,18 +729,18 @@ void plan_buffer_line(float x, float y, float z, const float &e, float feed_rate
   // Calculate target position in absolute steps
   //this should be done after the wait, because otherwise a M92 code within the gcode disrupts this calculation somehow
   long target[4];
-  target[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]);
-  target[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]);
+  target[X_AXIS] = lround(x*cs.axis_steps_per_unit[X_AXIS]);
+  target[Y_AXIS] = lround(y*cs.axis_steps_per_unit[Y_AXIS]);
 #ifdef MESH_BED_LEVELING
     if (mbl.active){
-        target[Z_AXIS] = lround((z+mbl.get_z(x, y))*axis_steps_per_unit[Z_AXIS]);
+        target[Z_AXIS] = lround((z+mbl.get_z(x, y))*cs.axis_steps_per_unit[Z_AXIS]);
     }else{
-        target[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]);
+        target[Z_AXIS] = lround(z*cs.axis_steps_per_unit[Z_AXIS]);
     }
 #else
-    target[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]);
+    target[Z_AXIS] = lround(z*cs.axis_steps_per_unit[Z_AXIS]);
 #endif // ENABLE_MESH_BED_LEVELING
-  target[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]);
+  target[E_AXIS] = lround(e*cs.axis_steps_per_unit[E_AXIS]);
   
 #ifdef LIN_ADVANCE
     const float mm_D_float = sqrt(sq(x - position_float[X_AXIS]) + sq(y - position_float[Y_AXIS]));
@@ -776,7 +762,7 @@ void plan_buffer_line(float x, float y, float z, const float &e, float feed_rate
     }
     
     #ifdef PREVENT_LENGTHY_EXTRUDE
-    if(labs(target[E_AXIS]-position[E_AXIS])>axis_steps_per_unit[E_AXIS]*EXTRUDE_MAXLENGTH)
+    if(labs(target[E_AXIS]-position[E_AXIS])>cs.axis_steps_per_unit[E_AXIS]*EXTRUDE_MAXLENGTH)
     {
       position[E_AXIS]=target[E_AXIS]; //behave as if the move really took place, but ignore E part
 #ifdef LIN_ADVANCE
@@ -886,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;        
       }
     }
@@ -915,11 +901,11 @@ block->steps_y.wide = labs((target[X_AXIS]-position[X_AXIS]) - (target[Y_AXIS]-p
 
   if (block->steps_e.wide == 0)
   {
-    if(feed_rate<mintravelfeedrate) feed_rate=mintravelfeedrate;
+    if(feed_rate<cs.mintravelfeedrate) feed_rate=cs.mintravelfeedrate;
   }
   else
   {
-    if(feed_rate<minimumfeedrate) feed_rate=minimumfeedrate;
+    if(feed_rate<cs.minimumfeedrate) feed_rate=cs.minimumfeedrate;
   } 
 
 /* This part of the code calculates the total length of the movement. 
@@ -931,17 +917,17 @@ Having the real displacement of the head, we can calculate the total movement le
 */ 
   #ifndef COREXY
     float delta_mm[4];
-    delta_mm[X_AXIS] = (target[X_AXIS]-position[X_AXIS])/axis_steps_per_unit[X_AXIS];
-    delta_mm[Y_AXIS] = (target[Y_AXIS]-position[Y_AXIS])/axis_steps_per_unit[Y_AXIS];
+    delta_mm[X_AXIS] = (target[X_AXIS]-position[X_AXIS])/cs.axis_steps_per_unit[X_AXIS];
+    delta_mm[Y_AXIS] = (target[Y_AXIS]-position[Y_AXIS])/cs.axis_steps_per_unit[Y_AXIS];
   #else
     float delta_mm[6];
-    delta_mm[X_HEAD] = (target[X_AXIS]-position[X_AXIS])/axis_steps_per_unit[X_AXIS];
-    delta_mm[Y_HEAD] = (target[Y_AXIS]-position[Y_AXIS])/axis_steps_per_unit[Y_AXIS];
-    delta_mm[X_AXIS] = ((target[X_AXIS]-position[X_AXIS]) + (target[Y_AXIS]-position[Y_AXIS]))/axis_steps_per_unit[X_AXIS];
-    delta_mm[Y_AXIS] = ((target[X_AXIS]-position[X_AXIS]) - (target[Y_AXIS]-position[Y_AXIS]))/axis_steps_per_unit[Y_AXIS];
+    delta_mm[X_HEAD] = (target[X_AXIS]-position[X_AXIS])/cs.axis_steps_per_unit[X_AXIS];
+    delta_mm[Y_HEAD] = (target[Y_AXIS]-position[Y_AXIS])/cs.axis_steps_per_unit[Y_AXIS];
+    delta_mm[X_AXIS] = ((target[X_AXIS]-position[X_AXIS]) + (target[Y_AXIS]-position[Y_AXIS]))/cs.axis_steps_per_unit[X_AXIS];
+    delta_mm[Y_AXIS] = ((target[X_AXIS]-position[X_AXIS]) - (target[Y_AXIS]-position[Y_AXIS]))/cs.axis_steps_per_unit[Y_AXIS];
   #endif
-  delta_mm[Z_AXIS] = (target[Z_AXIS]-position[Z_AXIS])/axis_steps_per_unit[Z_AXIS];
-  delta_mm[E_AXIS] = (target[E_AXIS]-position[E_AXIS])/axis_steps_per_unit[E_AXIS];
+  delta_mm[Z_AXIS] = (target[Z_AXIS]-position[Z_AXIS])/cs.axis_steps_per_unit[Z_AXIS];
+  delta_mm[E_AXIS] = (target[E_AXIS]-position[E_AXIS])/cs.axis_steps_per_unit[E_AXIS];
   if ( block->steps_x.wide <=dropsegments && block->steps_y.wide <=dropsegments && block->steps_z.wide <=dropsegments )
   {
     block->millimeters = fabs(delta_mm[E_AXIS]);
@@ -968,9 +954,9 @@ Having the real displacement of the head, we can calculate the total movement le
   if (moves_queued > 1 && moves_queued < (BLOCK_BUFFER_SIZE >> 1)) {
       // segment time in micro seconds
       unsigned long segment_time = lround(1000000.0/inverse_second);
-      if (segment_time < minsegmenttime)
+      if (segment_time < cs.minsegmenttime)
           // buffer is draining, add extra time.  The amount of time added increases if the buffer is still emptied more.
-          inverse_second=1000000.0/(segment_time+lround(2*(minsegmenttime-segment_time)/moves_queued));
+          inverse_second=1000000.0/(segment_time+lround(2*(cs.minsegmenttime-segment_time)/moves_queued));
   }
 #endif // SLOWDOWN
 
@@ -1008,11 +994,11 @@ Having the real displacement of the head, we can calculate the total movement le
   float steps_per_mm = block->step_event_count.wide/block->millimeters;
   if(block->steps_x.wide == 0 && block->steps_y.wide == 0 && block->steps_z.wide == 0)
   {
-    block->acceleration_st = ceil(retract_acceleration * steps_per_mm); // convert to: acceleration steps/sec^2
+    block->acceleration_st = ceil(cs.retract_acceleration * steps_per_mm); // convert to: acceleration steps/sec^2
   }
   else
   {
-    block->acceleration_st = ceil(acceleration * steps_per_mm); // convert to: acceleration steps/sec^2
+    block->acceleration_st = ceil(cs.acceleration * steps_per_mm); // convert to: acceleration steps/sec^2
     // Limit acceleration per axis
     //FIXME Vojtech: One shall rather limit a projection of the acceleration vector instead of using the limit.
     if(((float)block->acceleration_st * (float)block->steps_x.wide / (float)block->step_event_count.wide) > axis_steps_per_sqr_second[X_AXIS])
@@ -1051,20 +1037,20 @@ Having the real displacement of the head, we can calculate the total movement le
   bool  limited = false;
   for (uint8_t axis = 0; axis < 4; ++ axis) {
       float jerk = fabs(current_speed[axis]);
-      if (jerk > max_jerk[axis]) {
+      if (jerk > cs.max_jerk[axis]) {
           // The actual jerk is lower, if it has been limited by the XY jerk.
           if (limited) {
               // Spare one division by a following gymnastics:
               // Instead of jerk *= safe_speed / block->nominal_speed,
               // multiply max_jerk[axis] by the divisor.
               jerk *= safe_speed;
-              float mjerk = max_jerk[axis] * block->nominal_speed;
+              float mjerk = cs.max_jerk[axis] * block->nominal_speed;
               if (jerk > mjerk) {
                   safe_speed *= mjerk / jerk;
                   limited = true;
               }
           } else {
-              safe_speed = max_jerk[axis];
+              safe_speed = cs.max_jerk[axis];
               limited = true;
           }
       }
@@ -1117,8 +1103,8 @@ Having the real displacement of the head, we can calculate the total movement le
                       (v_entry - v_exit) :
                       // axis reversal
                       max(- v_exit, v_entry));
-          if (jerk > max_jerk[axis]) {
-              v_factor *= max_jerk[axis] / jerk;
+          if (jerk > cs.max_jerk[axis]) {
+              v_factor *= cs.max_jerk[axis] / jerk;
               limited = true;
           }
       }
@@ -1188,7 +1174,7 @@ Having the real displacement of the head, we can calculate the total movement le
                           extruder_advance_k
                           * ((advance_ed_ratio < 0.000001) ? de_float / mm_D_float : advance_ed_ratio) // Use the fixed ratio, if set
                           * (block->nominal_speed / (float)block->nominal_rate)
-                          * axis_steps_per_unit[E_AXIS] * 256.0
+                          * cs.axis_steps_per_unit[E_AXIS] * 256.0
                           );
 #endif
     
@@ -1263,16 +1249,16 @@ void plan_set_position(float x, float y, float z, const float &e)
         y = world2machine_rotation_and_skew[1][0] * tmpx + world2machine_rotation_and_skew[1][1] * tmpy + world2machine_shift[1];
     }
 
-  position[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]);
-  position[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]);
+  position[X_AXIS] = lround(x*cs.axis_steps_per_unit[X_AXIS]);
+  position[Y_AXIS] = lround(y*cs.axis_steps_per_unit[Y_AXIS]);
 #ifdef MESH_BED_LEVELING
   position[Z_AXIS] = mbl.active ? 
-    lround((z+mbl.get_z(x, y))*axis_steps_per_unit[Z_AXIS]) :
-    lround(z*axis_steps_per_unit[Z_AXIS]);
+    lround((z+mbl.get_z(x, y))*cs.axis_steps_per_unit[Z_AXIS]) :
+    lround(z*cs.axis_steps_per_unit[Z_AXIS]);
 #else
-  position[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]);
+  position[Z_AXIS] = lround(z*cs.axis_steps_per_unit[Z_AXIS]);
 #endif // ENABLE_MESH_BED_LEVELING
-  position[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]);
+  position[E_AXIS] = lround(e*cs.axis_steps_per_unit[E_AXIS]);
 #ifdef LIN_ADVANCE
   position_float[X_AXIS] = x;
   position_float[Y_AXIS] = y;
@@ -1293,7 +1279,7 @@ void plan_set_z_position(const float &z)
 	#ifdef LIN_ADVANCE
 	position_float[Z_AXIS] = z;
 	#endif
-    position[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]);
+    position[Z_AXIS] = lround(z*cs.axis_steps_per_unit[Z_AXIS]);
     st_set_position(position[X_AXIS], position[Y_AXIS], position[Z_AXIS], position[E_AXIS]);
 }
 
@@ -1302,7 +1288,7 @@ void plan_set_e_position(const float &e)
   #ifdef LIN_ADVANCE
   position_float[E_AXIS] = e;
   #endif
-  position[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]);  
+  position[E_AXIS] = lround(e*cs.axis_steps_per_unit[E_AXIS]);  
   st_set_e_position(position[E_AXIS]);
 }
 
@@ -1317,7 +1303,7 @@ void set_extrude_min_temp(float temp)
 void reset_acceleration_rates()
 {
 	for(int8_t i=0; i < NUM_AXIS; i++)
-        axis_steps_per_sqr_second[i] = max_acceleration_units_per_sq_second[i] * axis_steps_per_unit[i];
+        axis_steps_per_sqr_second[i] = max_acceleration_units_per_sq_second[i] * cs.axis_steps_per_unit[i];
 }
 
 #ifdef TMC2130
@@ -1325,13 +1311,13 @@ void update_mode_profile()
 {
 	if (tmc2130_mode == TMC2130_MODE_NORMAL)
 	{
-		max_feedrate = max_feedrate_normal;
-		max_acceleration_units_per_sq_second = max_acceleration_units_per_sq_second_normal;
+		max_feedrate = cs.max_feedrate_normal;
+		max_acceleration_units_per_sq_second = cs.max_acceleration_units_per_sq_second_normal;
 	}
 	else if (tmc2130_mode == TMC2130_MODE_SILENT)
 	{
-		max_feedrate = max_feedrate_silent;
-		max_acceleration_units_per_sq_second = max_acceleration_units_per_sq_second_silent;
+		max_feedrate = cs.max_feedrate_silent;
+		max_acceleration_units_per_sq_second = cs.max_acceleration_units_per_sq_second_silent;
 	}
 	reset_acceleration_rates();
 }

+ 0 - 15
Firmware/planner.h

@@ -158,27 +158,12 @@ extern bool e_active();
 
 void check_axes_activity();
 
-extern unsigned long minsegmenttime;
-
 // Use M203 to override by software
-extern float max_feedrate_normal[NUM_AXIS];
-extern float max_feedrate_silent[NUM_AXIS];
 extern float* max_feedrate;
 
-// Use M92 to override by software
-extern float axis_steps_per_unit[NUM_AXIS];
 
 // Use M201 to override by software
-extern unsigned long max_acceleration_units_per_sq_second_normal[NUM_AXIS];
-extern unsigned long max_acceleration_units_per_sq_second_silent[NUM_AXIS];
 extern unsigned long* max_acceleration_units_per_sq_second; 
-
-extern float minimumfeedrate;
-extern float acceleration;         // Normal acceleration mm/s^2  THIS IS THE DEFAULT ACCELERATION for all moves. M204 SXXXX
-extern float retract_acceleration; //  mm/s^2   filament pull-pack and push-forward  while standing still in the other axis M204 TXXXX
-// Jerk is a maximum immediate velocity change.
-extern float max_jerk[NUM_AXIS];
-extern float mintravelfeedrate;
 extern unsigned long axis_steps_per_sqr_second[NUM_AXIS];
 
 extern long position[NUM_AXIS];

+ 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);

+ 16 - 34
Firmware/stepper.cpp

@@ -42,6 +42,7 @@ int fsensor_counter = 0; //counter for e-steps
 #endif //FILAMENT_SENSOR
 
 #include "mmu.h"
+#include "ConfigurationStore.h"
 
 #ifdef DEBUG_STACK_MONITOR
 uint16_t SP_min = 0x21FF;
@@ -106,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;
@@ -231,15 +230,15 @@ void checkHitEndstops()
    SERIAL_ECHO_START;
    SERIAL_ECHORPGM(_T(MSG_ENDSTOPS_HIT));
    if(endstop_x_hit) {
-     SERIAL_ECHOPAIR(" X:",(float)endstops_trigsteps[X_AXIS]/axis_steps_per_unit[X_AXIS]);
+     SERIAL_ECHOPAIR(" X:",(float)endstops_trigsteps[X_AXIS]/cs.axis_steps_per_unit[X_AXIS]);
 //     LCD_MESSAGERPGM(CAT2(_T(MSG_ENDSTOPS_HIT), PSTR("X")));
    }
    if(endstop_y_hit) {
-     SERIAL_ECHOPAIR(" Y:",(float)endstops_trigsteps[Y_AXIS]/axis_steps_per_unit[Y_AXIS]);
+     SERIAL_ECHOPAIR(" Y:",(float)endstops_trigsteps[Y_AXIS]/cs.axis_steps_per_unit[Y_AXIS]);
 //     LCD_MESSAGERPGM(CAT2(_T(MSG_ENDSTOPS_HIT), PSTR("Y")));
    }
    if(endstop_z_hit) {
-     SERIAL_ECHOPAIR(" Z:",(float)endstops_trigsteps[Z_AXIS]/axis_steps_per_unit[Z_AXIS]);
+     SERIAL_ECHOPAIR(" Z:",(float)endstops_trigsteps[Z_AXIS]/cs.axis_steps_per_unit[Z_AXIS]);
 //     LCD_MESSAGERPGM(CAT2(_T(MSG_ENDSTOPS_HIT),PSTR("Z")));
    }
    SERIAL_ECHOLN("");
@@ -734,7 +733,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
@@ -749,7 +747,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
@@ -764,7 +761,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);
@@ -799,7 +795,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
@@ -814,7 +809,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
@@ -829,7 +823,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);
@@ -867,8 +860,6 @@ FORCE_INLINE void isr() {
   if (current_block == NULL)
     stepper_next_block();
 
-	LastStepMask = 0;
-
   if (current_block != NULL) 
   {
     stepper_check_endstops();
@@ -1112,7 +1103,7 @@ FORCE_INLINE void isr() {
   }
 
 #ifdef TMC2130
-	tmc2130_st_isr(LastStepMask);
+	tmc2130_st_isr();
 #endif //TMC2130
 
   //WRITE_NC(LOGIC_ANALYZER_CH0, false);
@@ -1424,7 +1415,7 @@ void st_get_position_xy(long &x, long &y)
 float st_get_position_mm(uint8_t axis)
 {
   float steper_position_in_steps = st_get_position(axis);
-  return steper_position_in_steps / axis_steps_per_unit[axis];
+  return steper_position_in_steps / cs.axis_steps_per_unit[axis];
 }
 
 
@@ -1467,13 +1458,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);
@@ -1493,13 +1481,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);
@@ -1522,14 +1507,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);
@@ -1549,16 +1530,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)
 {
@@ -1602,19 +1583,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);
@@ -1622,6 +1603,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();

+ 12 - 54
Firmware/temperature.cpp

@@ -39,6 +39,7 @@
 
 #include <avr/wdt.h>
 #include "adc.h"
+#include "ConfigurationStore.h"
 
 
 //===========================================================================
@@ -79,19 +80,10 @@ float current_temperature_bed = 0.0;
   float _Kp, _Ki, _Kd;
   int pid_cycle, pid_number_of_cycles;
   bool pid_tuning_finished = false;
-  float Kp=DEFAULT_Kp;
-  float Ki=(DEFAULT_Ki*PID_dT);
-  float Kd=(DEFAULT_Kd/PID_dT);
   #ifdef PID_ADD_EXTRUSION_RATE
     float Kc=DEFAULT_Kc;
   #endif
 #endif //PIDTEMP
-
-#ifdef PIDTEMPBED
-  float bedKp=DEFAULT_bedKp;
-  float bedKi=(DEFAULT_bedKi*PID_dT);
-  float bedKd=(DEFAULT_bedKd/PID_dT);
-#endif //PIDTEMPBED
   
 #ifdef FAN_SOFT_PWM
   unsigned char fanSpeedSoftPwm;
@@ -183,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
@@ -422,11 +413,11 @@ void updatePID()
 {
 #ifdef PIDTEMP
   for(int e = 0; e < EXTRUDERS; e++) { 
-     temp_iState_max[e] = PID_INTEGRAL_DRIVE_MAX / Ki;  
+     temp_iState_max[e] = PID_INTEGRAL_DRIVE_MAX / cs.Ki;  
   }
 #endif
 #ifdef PIDTEMPBED
-  temp_iState_max_bed = PID_INTEGRAL_DRIVE_MAX / bedKi;  
+  temp_iState_max_bed = PID_INTEGRAL_DRIVE_MAX / cs.bedKi;  
 #endif
 }
   
@@ -501,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 
@@ -512,8 +500,7 @@ void fanSpeedError(unsigned char _fan) {
 			lcd_print_stop();
 		}
 		else {
-			isPrintPaused = true;
-			lcd_sdcard_pause();
+			lcd_pause_print();
 		}
 	}
 	else {
@@ -638,14 +625,14 @@ void manage_heater()
             temp_iState[e] = 0.0;
             pid_reset[e] = false;
           }
-          pTerm[e] = Kp * pid_error[e];
+          pTerm[e] = cs.Kp * pid_error[e];
           temp_iState[e] += pid_error[e];
           temp_iState[e] = constrain(temp_iState[e], temp_iState_min[e], temp_iState_max[e]);
-          iTerm[e] = Ki * temp_iState[e];
+          iTerm[e] = cs.Ki * temp_iState[e];
 
           //K1 defined in Configuration.h in the PID settings
           #define K2 (1.0-K1)
-          dTerm[e] = (Kd * (pid_input - temp_dState[e]))*K2 + (K1 * dTerm[e]);
+          dTerm[e] = (cs.Kd * (pid_input - temp_dState[e]))*K2 + (K1 * dTerm[e]);
           pid_output = pTerm[e] + iTerm[e] - dTerm[e];
           if (pid_output > PID_MAX) {
             if (pid_error[e] > 0 )  temp_iState[e] -= pid_error[e]; // conditional un-integration
@@ -753,14 +740,14 @@ void manage_heater()
 
     #ifndef PID_OPENLOOP
 		  pid_error_bed = target_temperature_bed - pid_input;
-		  pTerm_bed = bedKp * pid_error_bed;
+		  pTerm_bed = cs.bedKp * pid_error_bed;
 		  temp_iState_bed += pid_error_bed;
 		  temp_iState_bed = constrain(temp_iState_bed, temp_iState_min_bed, temp_iState_max_bed);
-		  iTerm_bed = bedKi * temp_iState_bed;
+		  iTerm_bed = cs.bedKi * temp_iState_bed;
 
 		  //K1 defined in Configuration.h in the PID settings
 		  #define K2 (1.0-K1)
-		  dTerm_bed= (bedKd * (pid_input - temp_dState_bed))*K2 + (K1 * dTerm_bed);
+		  dTerm_bed= (cs.bedKd * (pid_input - temp_dState_bed))*K2 + (K1 * dTerm_bed);
 		  temp_dState_bed = pid_input;
 
 		  pid_output = pTerm_bed + iTerm_bed - dTerm_bed;
@@ -936,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)
 {
@@ -1040,11 +998,11 @@ void tp_init()
     maxttemp[e] = maxttemp[0];
 #ifdef PIDTEMP
     temp_iState_min[e] = 0.0;
-    temp_iState_max[e] = PID_INTEGRAL_DRIVE_MAX / Ki;
+    temp_iState_max[e] = PID_INTEGRAL_DRIVE_MAX / cs.Ki;
 #endif //PIDTEMP
 #ifdef PIDTEMPBED
     temp_iState_min_bed = 0.0;
-    temp_iState_max_bed = PID_INTEGRAL_DRIVE_MAX / bedKi;
+    temp_iState_max_bed = PID_INTEGRAL_DRIVE_MAX / cs.bedKi;
 #endif //PIDTEMPBED
   }
 

+ 1 - 4
Firmware/temperature.h

@@ -73,7 +73,7 @@ extern int current_voltage_raw_bed;
 
 #ifdef PIDTEMP
   extern int pid_cycle, pid_number_of_cycles;
-  extern float Kp,Ki,Kd,Kc,_Kp,_Ki,_Kd;
+  extern float Kc,_Kp,_Ki,_Kd;
   extern bool pid_tuning_finished;
   float scalePID_i(float i);
   float scalePID_d(float d);
@@ -81,9 +81,6 @@ extern int current_voltage_raw_bed;
   float unscalePID_d(float d);
 
 #endif
-#ifdef PIDTEMPBED
-  extern float bedKp,bedKi,bedKd;
-#endif
   
   
 #ifdef BABYSTEPPING

+ 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);

+ 425 - 398
Firmware/ultralcd.cpp

@@ -49,8 +49,6 @@ char longFilenameOLD[LONG_FILENAME_LENGTH];
 
 static void lcd_sd_updir();
 
-
-
 int8_t ReInitLCD = 0;
 
 
@@ -116,20 +114,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();
@@ -144,11 +142,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();
@@ -164,8 +161,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();
@@ -175,11 +177,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
@@ -188,8 +191,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
 
@@ -232,7 +235,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;
@@ -284,8 +287,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;
@@ -305,7 +307,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;
@@ -326,7 +328,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;
@@ -350,7 +352,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);
 
@@ -359,7 +361,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;
@@ -390,15 +392,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();
 		}
@@ -409,7 +411,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"));
@@ -456,13 +462,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();
 		}
 	}
@@ -481,12 +488,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
@@ -526,8 +531,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)
@@ -973,86 +977,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)
@@ -1312,7 +1245,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);
 			}
 		}
 
@@ -1323,43 +1256,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;
@@ -1389,6 +1380,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"));
@@ -1549,7 +1541,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);
 			}
 		}
 
@@ -1757,18 +1749,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();
@@ -1798,55 +1791,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);
 }
 
 
@@ -2072,7 +2071,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);
@@ -2086,7 +2085,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);
   }
   
 
@@ -2787,9 +2786,9 @@ static void _lcd_babystep(int axis, const char *msg)
 	    if (calibration_status() >= CALIBRATION_STATUS_LIVE_ADJUST)
 			_md->babystepMem[2] = 0;
 
-		_md->babystepMemMM[0] = _md->babystepMem[0]/axis_steps_per_unit[X_AXIS];
-		_md->babystepMemMM[1] = _md->babystepMem[1]/axis_steps_per_unit[Y_AXIS];
-		_md->babystepMemMM[2] = _md->babystepMem[2]/axis_steps_per_unit[Z_AXIS];
+		_md->babystepMemMM[0] = _md->babystepMem[0]/cs.axis_steps_per_unit[X_AXIS];
+		_md->babystepMemMM[1] = _md->babystepMem[1]/cs.axis_steps_per_unit[Y_AXIS];
+		_md->babystepMemMM[2] = _md->babystepMem[2]/cs.axis_steps_per_unit[Z_AXIS];
 		lcd_draw_update = 1;
 		//SERIAL_ECHO("Z baby step: ");
 		//SERIAL_ECHO(_md->babystepMem[2]);
@@ -2812,7 +2811,7 @@ static void _lcd_babystep(int axis, const char *msg)
 				CRITICAL_SECTION_END		
 			}
 		}
-		_md->babystepMemMM[axis] = _md->babystepMem[axis]/axis_steps_per_unit[axis]; 
+		_md->babystepMemMM[axis] = _md->babystepMem[axis]/cs.axis_steps_per_unit[axis]; 
 		delay(50);
 		lcd_encoder = 0;
 		lcd_draw_update = 1;
@@ -2833,15 +2832,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()
 {
@@ -3277,6 +3267,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();
@@ -3292,9 +3283,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();
@@ -3328,20 +3316,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();
@@ -3377,9 +3383,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();
@@ -3398,15 +3401,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)
 {
 
@@ -3454,16 +3464,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) {
@@ -3555,26 +3562,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;
         }
     }
@@ -4318,7 +4323,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
@@ -4330,9 +4342,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;
 				}
 			}
@@ -4349,7 +4358,7 @@ void lcd_wizard() {
 	}
 	if (result) {
 		calibration_status_store(CALIBRATION_STATUS_ASSEMBLED);
-		lcd_wizard(0);
+		lcd_wizard(WizState::Run);
 	}
 	else {
 		lcd_return_to_status();
@@ -4378,19 +4387,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 {
@@ -4398,72 +4455,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));
@@ -4472,30 +4554,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;
@@ -4506,27 +4589,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();
@@ -4538,12 +4609,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);
 }
 
@@ -4725,6 +4795,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));
@@ -4787,11 +4858,6 @@ static void lcd_settings_menu()
 	MENU_END();
 }
 
-static void lcd_selftest_()
-{
-	lcd_selftest();
-}
-
 #ifdef TMC2130
 static void lcd_ustep_linearity_menu_save()
 {
@@ -4925,9 +4991,6 @@ void bowden_menu() {
 		}
 
 		if (lcd_clicked()) {
-			while (lcd_clicked());
-			delay(10);
-			while (lcd_clicked());
 
 			lcd_clear();
 			while (1) {
@@ -4959,9 +5022,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);
@@ -5022,9 +5082,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);
 		}
@@ -5032,95 +5089,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
@@ -5202,9 +5268,6 @@ char reset_menu() {
 		}
 
 		if (lcd_clicked()) {
-			while (lcd_clicked());
-			delay(10);
-			while (lcd_clicked());
 			return(cursor_pos + first);
 		}
 
@@ -5225,7 +5288,6 @@ static void lcd_disable_farm_mode()
 	
 }
 
-
 static void fil_load_menu()
 {
 	MENU_BEGIN();
@@ -5309,7 +5371,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);
@@ -5462,9 +5524,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;
@@ -5556,6 +5615,7 @@ void lcd_confirm_print()
 
 #include "w25x20cl.h"
 
+#ifdef LCD_TEST
 static void lcd_test_menu()
 {
 	W25X20CL_SPI_ENTER();
@@ -5563,6 +5623,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()
 {
@@ -5657,11 +5731,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);
 		}
@@ -5737,8 +5811,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();
 
@@ -5775,34 +5850,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() {
 	
@@ -5910,12 +5957,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
@@ -6032,7 +6073,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();
@@ -6074,7 +6115,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 {
@@ -6277,14 +6318,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];
@@ -6571,7 +6612,6 @@ static bool lcd_selfcheck_pulleys(int axis)
 	}
 	return(true);
 }
-#endif //TMC2130
 
 
 static bool lcd_selfcheck_endstops()
@@ -6604,7 +6644,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)
 {
@@ -7087,7 +7127,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];
@@ -7132,7 +7172,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();
 
@@ -7174,7 +7214,6 @@ void ultralcd_init()
   WRITE(SDCARDDETECT, HIGH);
   lcd_oldcardstatus = IS_SD_INSERTED;
 #endif//(SDCARDDETECT > 0)
-  lcd_buttons_update();
   lcd_encoder_diff = 0;
 }
 
@@ -7197,11 +7236,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();
@@ -7230,6 +7269,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) {
@@ -7293,19 +7333,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

@@ -11,8 +11,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_  
@@ -35,8 +34,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