瀏覽代碼

Merge branch 'MK3' into MK3_LA15

Marek Bel 5 年之前
父節點
當前提交
6717590631

+ 11 - 1
Firmware/Marlin.h

@@ -214,6 +214,9 @@ void manage_inactivity(bool ignore_stepper_queue=false);
 #endif
 
 
+#define FARM_FILAMENT_COLOR_NONE 99;
+
+
 enum AxisEnum {X_AXIS=0, Y_AXIS=1, Z_AXIS=2, E_AXIS=3, X_HEAD=4, Y_HEAD=5};
 #define X_AXIS_MASK  1
 #define Y_AXIS_MASK  2
@@ -389,7 +392,14 @@ extern bool wizard_active; //autoload temporarily disabled during wizard
 extern LongTimer safetyTimer;
 
 #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)
+#define PRINTER_ACTIVE (IS_SD_PRINTING || is_usb_printing || isPrintPaused || (custom_message_type == CustomMsg::TempCal) || saved_printing || (lcd_commands_type == LcdCommands::Layer1Cal) || card.paused || mmu_print_saved)
+//! Beware - mcode_in_progress is set as soon as the command gets really processed,
+//! which is not the same as posting the M600 command into the command queue
+//! There can be a considerable lag between posting M600 and its real processing which might result
+//! in posting multiple M600's into the command queue
+//! Instead, the fsensor uses another state variable :( , which is set to true, when the M600 command is enqued
+//! and is reset to false when the fsensor returns into its filament runout finished handler
+//! I'd normally change this macro, but who knows what would happen in the MMU :)
 #define CHECK_FSENSOR ((IS_SD_PRINTING || is_usb_printing) && (mcode_in_progress != 600) && !saved_printing && e_active())
 
 extern void calculate_extruder_multipliers();

+ 191 - 117
Firmware/Marlin_main.cpp

@@ -214,8 +214,6 @@ static LongTimer crashDetTimer;
 bool mesh_bed_leveling_flag = false;
 bool mesh_bed_run_from_menu = false;
 
-int8_t FarmMode = 0;
-
 bool prusa_sd_card_upload = false;
 
 unsigned int status_number = 0;
@@ -1004,7 +1002,7 @@ static void w25x20cl_err_msg()
 void setup()
 {
 	mmu_init();
-	
+
 	ultralcd_init();
 
 #if (LCD_BL_PIN != -1) && defined (LCD_BL_PIN)
@@ -1060,6 +1058,9 @@ void setup()
 		//disabled filament autoload (PFW360)
 		fsensor_autoload_set(false);
 #endif //FILAMENT_SENSOR
+          // ~ FanCheck -> on
+          if(!(eeprom_read_byte((uint8_t*)EEPROM_FAN_CHECK_ENABLED)))
+               eeprom_update_byte((unsigned char *)EEPROM_FAN_CHECK_ENABLED,true);
 	}
 	MYSERIAL.begin(BAUDRATE);
 	fdev_setup_stream(uartout, uart_putchar, NULL, _FDEV_SETUP_WRITE); //setup uart out stream
@@ -1293,8 +1294,11 @@ void setup()
 
 #endif //TMC2130
 
-
 	st_init();    // Initialize stepper, this enables interrupts!
+  
+#ifdef UVLO_SUPPORT
+    setup_uvlo_interrupt();
+#endif //UVLO_SUPPORT
 
 #ifdef TMC2130
 	tmc2130_mode = silentMode?TMC2130_MODE_SILENT:TMC2130_MODE_NORMAL;
@@ -1497,10 +1501,6 @@ void setup()
 	}
 	check_babystep(); //checking if Z babystep is in allowed range
 
-#ifdef UVLO_SUPPORT
-	setup_uvlo_interrupt();
-#endif //UVLO_SUPPORT
-
 #if !defined(DEBUG_DISABLE_FANCHECK) && defined(FANCHECK) && defined(TACH_1) && TACH_1 >-1
 	setup_fan_interrupt();
 #endif //DEBUG_DISABLE_FANCHECK
@@ -1640,6 +1640,7 @@ void setup()
 	   
   }
 #endif //UVLO_SUPPORT
+  fCheckModeInit();
   KEEPALIVE_STATE(NOT_BUSY);
 #ifdef WATCHDOG
   wdt_enable(WDTO_4S);
@@ -2985,6 +2986,32 @@ void gcode_M114()
 	SERIAL_PROTOCOLLN("");
 }
 
+//! extracted code to compute z_shift for M600 in case of filament change operation 
+//! requested from fsensors.
+//! The function ensures, that the printhead lifts to at least 25mm above the heat bed
+//! unlike the previous implementation, which was adding 25mm even when the head was
+//! printing at e.g. 24mm height.
+//! A safety margin of FILAMENTCHANGE_ZADD is added in all cases to avoid touching
+//! the printout.
+//! This function is templated to enable fast change of computation data type.
+//! @return new z_shift value
+template<typename T>
+static T gcode_M600_filament_change_z_shift()
+{
+#ifdef FILAMENTCHANGE_ZADD
+	static_assert(Z_MAX_POS < (255 - FILAMENTCHANGE_ZADD), "Z-range too high, change the T type from uint8_t to uint16_t");
+	// avoid floating point arithmetics when not necessary - results in shorter code
+	T ztmp = T( current_position[Z_AXIS] );
+	T z_shift = 0;
+	if(ztmp < T(25)){
+		z_shift = T(25) - ztmp; // make sure to be at least 25mm above the heat bed
+	} 
+	return z_shift + T(FILAMENTCHANGE_ZADD); // always move above printout
+#else
+	return T(0);
+#endif
+}	
+
 static void gcode_M600(bool automatic, float x_position, float y_position, float z_shift, float e_shift, float /*e_shift_late*/)
 {
     st_synchronize();
@@ -3115,10 +3142,9 @@ static void gcode_M600(bool automatic, float x_position, float y_position, float
 #endif //IR_SENSOR
 
     lcd_setstatuspgm(_T(WELCOME_MSG));
-    custom_message_type = CUSTOM_MSG_TYPE_STATUS;
+    custom_message_type = CustomMsg::Status;
 }
 
-
 //! @brief Rise Z if too low to avoid blob/jam before filament loading
 //!
 //! It doesn't plan_buffer_line(), as it expects plan_buffer_line() to be called after
@@ -3140,7 +3166,7 @@ void gcode_M701()
 	else
 	{
 		enable_z();
-		custom_message_type = CUSTOM_MSG_TYPE_F_LOAD;
+		custom_message_type = CustomMsg::FilamentLoading;
 
 #ifdef FSENSOR_QUALITY
 		fsensor_oq_meassure_start(40);
@@ -3170,7 +3196,7 @@ void gcode_M701()
 		lcd_setstatuspgm(_T(WELCOME_MSG));
 		disable_z();
 		loading_flag = false;
-		custom_message_type = CUSTOM_MSG_TYPE_STATUS;
+		custom_message_type = CustomMsg::Status;
 
 #ifdef FSENSOR_QUALITY
         fsensor_oq_meassure_stop();
@@ -3375,8 +3401,10 @@ void process_commands()
 {
   #ifdef FANCHECK
   if (fan_check_error){
-    fan_check_error = false;
-    lcd_pause_print();
+	if( fan_check_error == EFCE_DETECTED ){
+		fan_check_error = EFCE_REPORTED;
+		lcd_pause_print();
+	} // otherwise it has already been reported, so just ignore further processing
     return;
   }
   #endif
@@ -3606,7 +3634,39 @@ void process_commands()
     } else if(code_seen("FR")) { //! PRUSA FR
         // Factory full reset
         factory_reset(0);
-    }
+
+//-//
+/*
+    } else if(code_seen("qqq")) {
+MYSERIAL.println("=== checking ===");
+MYSERIAL.println(eeprom_read_byte((uint8_t*)EEPROM_CHECK_MODE),DEC);
+MYSERIAL.println(eeprom_read_byte((uint8_t*)EEPROM_NOZZLE_DIAMETER),DEC);
+MYSERIAL.println(eeprom_read_word((uint16_t*)EEPROM_NOZZLE_DIAMETER_uM),DEC);
+MYSERIAL.println(farm_mode,DEC);
+MYSERIAL.println(eCheckMode,DEC);
+    } else if(code_seen("www")) {
+MYSERIAL.println("=== @ FF ===");
+eeprom_update_byte((uint8_t*)EEPROM_CHECK_MODE,0xFF);
+eeprom_update_byte((uint8_t*)EEPROM_NOZZLE_DIAMETER,0xFF);
+eeprom_update_word((uint16_t*)EEPROM_NOZZLE_DIAMETER_uM,0xFFFF);
+*/
+    } else if (code_seen("nozzle")) { //! PRUSA nozzle
+          uint16_t nDiameter;
+          if(code_seen('D'))
+               {
+               nDiameter=(uint16_t)(code_value()*1000.0+0.5); // [,um]
+               nozzle_diameter_check(nDiameter);
+               }
+          else if(code_seen("set") && farm_mode)
+               {
+               strchr_pointer++;                  // skip 2nd char (~ 'e')
+               strchr_pointer++;                  // skip 3rd char (~ 't')
+               nDiameter=(uint16_t)(code_value()*1000.0+0.5); // [,um]
+               eeprom_update_byte((uint8_t*)EEPROM_NOZZLE_DIAMETER,(uint8_t)e_NOZZLE_DIAMETER_NULL); // for correct synchronization after farm-mode exiting
+               eeprom_update_word((uint16_t*)EEPROM_NOZZLE_DIAMETER_uM,nDiameter);
+               }
+          else SERIAL_PROTOCOLLN((float)eeprom_read_word((uint16_t*)EEPROM_NOZZLE_DIAMETER_uM)/1000.0);
+	}	
     //else if (code_seen('Cal')) {
 		//  lcd_calibration();
 	  // }
@@ -4151,7 +4211,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 //			setTargetHotend(200, 0);
 			setTargetBed(70 + (start_temp - 30));
 
-			custom_message_type = CUSTOM_MSG_TYPE_TEMCAL;
+			custom_message_type = CustomMsg::TempCal;
 			custom_message_state = 1;
 			lcd_setstatuspgm(_T(MSG_TEMP_CALIBRATION));
 			current_position[Z_AXIS] = MESH_HOME_Z_SEARCH;
@@ -4253,7 +4313,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 			break;
 		}
 		puts_P(_N("PINDA probe calibration start"));
-		custom_message_type = CUSTOM_MSG_TYPE_TEMCAL;
+		custom_message_type = CustomMsg::TempCal;
 		custom_message_state = 1;
 		lcd_setstatuspgm(_T(MSG_TEMP_CALIBRATION));
 		current_position[X_AXIS] = PINDA_PREHEAT_X;
@@ -4321,7 +4381,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 			
 		
 		}
-		custom_message_type = CUSTOM_MSG_TYPE_STATUS;
+		custom_message_type = CustomMsg::Status;
 
 		eeprom_update_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, 1);
 		puts_P(_N("Temperature calibration done."));
@@ -4381,7 +4441,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 			// We don't know where we are! HOME!
 			// Push the commands to the front of the message queue in the reverse order!
 			// There shall be always enough space reserved for these commands.
-			if (lcd_commands_type != LCD_COMMAND_STOP_PRINT) {
+			if (lcd_commands_type != LcdCommands::StopPrint) {
 				repeatcommand_front(); // repeat G80 with all its parameters
 				enquecommand_front_P((PSTR("G28 W0")));
 			}
@@ -4421,7 +4481,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 
 		if (temp_comp_start)
 		if (run == false && temp_cal_active == true && calibration_status_pinda() == true && target_temperature_bed >= 50) {
-			if (lcd_commands_type != LCD_COMMAND_STOP_PRINT) {
+			if (lcd_commands_type != LcdCommands::StopPrint) {
 				temp_compensation_start();
 				run = true;
 				repeatcommand_front(); // repeat G80 with all its parameters
@@ -4433,14 +4493,14 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 			break;
 		}
 		run = false;
-		if (lcd_commands_type == LCD_COMMAND_STOP_PRINT) {
+		if (lcd_commands_type == LcdCommands::StopPrint) {
 			mesh_bed_leveling_flag = false;
 			break;
 		}
 		// Save custom message state, set a new custom message state to display: Calibrating point 9.
-		unsigned int custom_message_type_old = custom_message_type;
+		CustomMsg custom_message_type_old = custom_message_type;
 		unsigned int custom_message_state_old = custom_message_state;
-		custom_message_type = CUSTOM_MSG_TYPE_MESHBL;
+		custom_message_type = CustomMsg::MeshBedLeveling;
 		custom_message_state = (nMeasPoints * nMeasPoints) + 10;
 		lcd_update(1);
 
@@ -4640,7 +4700,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
                     enable_z_endstop(bState);
                     } while (st_get_position_mm(Z_AXIS) > MESH_HOME_Z_SEARCH); // i.e. Z-leveling not o.k.
 //               plan_set_z_position(MESH_HOME_Z_SEARCH); // is not necessary ('do-while' loop always ends at the expected Z-position)
-               custom_message_type=CUSTOM_MSG_TYPE_STATUS; // display / status-line recovery
+               custom_message_type=CustomMsg::Status; // display / status-line recovery
                lcd_update_enable(true);           // display / status-line recovery
                gcode_G28(true, true, true);       // X & Y & Z-homing (must be after individual Z-homing (problem with spool-holder)!)
                repeatcommand_front();             // re-run (i.e. of "G80")
@@ -4916,6 +4976,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 		EEPROM_save_B(EEPROM_FARM_NUMBER, &farm_no);
           SilentModeMenu = SILENT_MODE_OFF;
           eeprom_update_byte((unsigned char *)EEPROM_SILENT, SilentModeMenu);
+          fCheckModeInit();                       // alternatively invoke printer reset
 		break;
 
 	case 99: //! G99 (deactivate farm mode)
@@ -4923,6 +4984,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 		lcd_printer_connected();
 		eeprom_update_byte((unsigned char *)EEPROM_FARM_MODE, farm_mode);
 		lcd_update(2);
+          fCheckModeInit();                       // alternatively invoke printer reset
 		break;
 	default:
 		printf_P(PSTR("Unknown G code: %s \n"), cmdbuffer + bufindr + CMDHDRSIZE);
@@ -6571,7 +6633,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
 
 		float x_position = current_position[X_AXIS];
 		float y_position = current_position[Y_AXIS];
-		float z_shift = 0;
+		float z_shift = 0; // is it necessary to be a float?
 		float e_shift_init = 0;
 		float e_shift_late = 0;
 		bool automatic = false;
@@ -6607,10 +6669,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
         }
         else
         {
-          #ifdef FILAMENTCHANGE_ZADD
-            z_shift= FILAMENTCHANGE_ZADD ;
-            if(current_position[Z_AXIS] < 25) z_shift+= 25 ;
-          #endif
+			z_shift = gcode_M600_filament_change_z_shift<uint8_t>();
         }
 		//Move XY to side
         if(code_seen('X'))
@@ -7070,8 +7129,14 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE))
               }
 			  else
 			  {
+#if defined(MMU_HAS_CUTTER) && defined(MMU_ALWAYS_CUT)
+			      if (EEPROM_MMU_CUTTER_ENABLED_always == eeprom_read_byte((uint8_t*)EEPROM_MMU_CUTTER_ENABLED))
+                  {
+                      mmu_command(MmuCmd::K0 + tmp_extruder);
+                      manage_response(true, true, MMU_UNLOAD_MOVE);
+                  }
+#endif //defined(MMU_HAS_CUTTER) && defined(MMU_ALWAYS_CUT)
 				  mmu_command(MmuCmd::T0 + tmp_extruder);
-
 				  manage_response(true, true, MMU_TCODE_MOVE);
 		          mmu_continue_loading(is_usb_printing);
 
@@ -7618,7 +7683,7 @@ static void handleSafetyTimer()
     {
         safetyTimer.start();
     }
-    else if (safetyTimer.expired(safetytimer_inactive_time))
+    else if (safetyTimer.expired(farm_mode?FARM_DEFAULT_SAFETYTIMER_TIME_ms:safetytimer_inactive_time))
     {
         setTargetBed(0);
         setAllTargetHotends(0);
@@ -7640,9 +7705,9 @@ bool bInhibitFlag;
 #ifdef IR_SENSOR
           bInhibitFlag=(menu_menu==lcd_menu_show_sensors_state); // Support::SensorInfo menu active
 #endif // IR_SENSOR
-          if ((mcode_in_progress != 600) && (eFilamentAction != e_FILAMENT_ACTION_autoLoad) && (!bInhibitFlag)) //M600 not in progress, preHeat @ autoLoad menu not active, Support::ExtruderInfo/SensorInfo menu not active
+          if ((mcode_in_progress != 600) && (eFilamentAction != FilamentAction::AutoLoad) && (!bInhibitFlag)) //M600 not in progress, preHeat @ autoLoad menu not active, Support::ExtruderInfo/SensorInfo menu not active
 		{
-			if (!moves_planned() && !IS_SD_PRINTING && !is_usb_printing && (lcd_commands_type != LCD_COMMAND_V2_CAL) && !wizard_active)
+			if (!moves_planned() && !IS_SD_PRINTING && !is_usb_printing && (lcd_commands_type != LcdCommands::Layer1Cal) && !wizard_active)
 			{
 				if (fsensor_check_autoload())
 				{
@@ -7666,7 +7731,7 @@ if(0)
 						show_preheat_nozzle_warning();
 						lcd_update_enable(true);
 */
-                              eFilamentAction=e_FILAMENT_ACTION_autoLoad;
+                              eFilamentAction=FilamentAction::AutoLoad;
                               bFilamentFirstRun=false;
                               if(target_temperature[0]>=EXTRUDE_MINTEMP)
                               {
@@ -8140,7 +8205,7 @@ void bed_check(float x_dimension, float y_dimension, int x_points_num, int y_poi
 	float bed_zero_ref_y = (-0.6f + Y_PROBE_OFFSET_FROM_EXTRUDER);
 
 	float mesh_home_z_search = 4;
-	float measure_z_heigth = 0.2f;
+	float measure_z_height = 0.2f;
 	float row[x_points_num];
 	int ix = 0;
 	int iy = 0;
@@ -8157,7 +8222,7 @@ void bed_check(float x_dimension, float y_dimension, int x_points_num, int y_poi
 
 	unsigned int custom_message_type_old = custom_message_type;
 	unsigned int custom_message_state_old = custom_message_state;
-	custom_message_type = CUSTOM_MSG_TYPE_MESHBL;
+	custom_message_type = CustomMsg::MeshBedLeveling;
 	custom_message_state = (x_points_num * y_points_num) + 10;
 	lcd_update(1);
 
@@ -8175,7 +8240,7 @@ void bed_check(float x_dimension, float y_dimension, int x_points_num, int y_poi
 	}
 	st_synchronize();
 	*/
-		destination[Z_AXIS] = measure_z_heigth;
+		destination[Z_AXIS] = measure_z_height;
 		plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], Z_LIFT_FEEDRATE, active_extruder);
 		for(int8_t i=0; i < NUM_AXIS; i++) {
 			current_position[i] = destination[i];
@@ -8355,7 +8420,7 @@ void bed_analysis(float x_dimension, float y_dimension, int x_points_num, int y_
 	}
 	unsigned int custom_message_type_old = custom_message_type;
 	unsigned int custom_message_state_old = custom_message_state;
-	custom_message_type = CUSTOM_MSG_TYPE_MESHBL;
+	custom_message_type = CustomMsg::MeshBedLeveling;
 	custom_message_state = (x_points_num * y_points_num) + 10;
 	lcd_update(1);
 
@@ -8505,7 +8570,7 @@ void bed_analysis(float x_dimension, float y_dimension, int x_points_num, int y_
 
 void temp_compensation_start() {
 	
-	custom_message_type = CUSTOM_MSG_TYPE_TEMPRE;
+	custom_message_type = CustomMsg::TempCompPreheat;
 	custom_message_state = PINDA_HEAT_T + 1;
 	lcd_update(2);
 	if (degHotend(active_extruder) > EXTRUDE_MINTEMP) {
@@ -8526,7 +8591,7 @@ void temp_compensation_start() {
 		if (custom_message_state == 99 || custom_message_state == 9) lcd_update(2); //force whole display redraw if number of digits changed
 		else lcd_update(1);
 	}	
-	custom_message_type = CUSTOM_MSG_TYPE_STATUS;
+	custom_message_type = CustomMsg::Status;
 	custom_message_state = 0;
 }
 
@@ -8665,12 +8730,10 @@ void serialecho_temperatures() {
 	SERIAL_PROTOCOL_F(degBed(), 1);
 	SERIAL_PROTOCOLLN("");
 }
-
 extern uint32_t sdpos_atomic;
-
 #ifdef UVLO_SUPPORT
 
-void uvlo_() 
+void uvlo_()
 {
 	unsigned long time_start = _millis();
 	bool sd_print = card.sdprinting;
@@ -8717,12 +8780,10 @@ void uvlo_()
 	// Store the current extruder position.
 	eeprom_update_float((float*)(EEPROM_UVLO_CURRENT_POSITION_E), st_get_position_mm(E_AXIS));
 	eeprom_update_byte((uint8_t*)EEPROM_UVLO_E_ABS, axis_relative_modes[3]?0:1);
-
     // Clean the input command queue.
     cmdqueue_reset();
     card.sdprinting = false;
-//    card.closefile();
-
+//    card.closefile();    
     // Enable stepper driver interrupt to move Z axis.
     // This should be fine as the planner and command queues are empty and the SD card printing is disabled.
     //FIXME one may want to disable serial lines at this point of time to avoid interfering with the command queue,
@@ -8738,26 +8799,25 @@ void uvlo_()
         st_synchronize();
         disable_e0();
     
-		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) / cs.axis_steps_per_unit[Z_AXIS], 
+    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) / cs.axis_steps_per_unit[Z_AXIS],
       current_position[E_AXIS] - default_retraction,
       40, active_extruder);
-    
     st_synchronize();
     disable_e0();
-    
+
     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) / cs.axis_steps_per_unit[Z_AXIS],
-                     current_position[E_AXIS] - default_retraction,
-                     40, active_extruder);
+      current_position[X_AXIS],
+      current_position[Y_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();
+
     disable_e0();
     disable_z();
-    
     // Move Z up to the next 0th full step.
     // Write the file position.
     eeprom_update_dword((uint32_t*)(EEPROM_FILE_POSITION), sd_position);
@@ -8773,9 +8833,10 @@ void uvlo_()
     // for reaching the zero full step before powering off.
     eeprom_update_word((uint16_t*)(EEPROM_UVLO_Z_MICROSTEPS), z_microsteps);
     // Store the current position.
+
     eeprom_update_float((float*)(EEPROM_UVLO_CURRENT_POSITION + 0), current_position[X_AXIS]);
     eeprom_update_float((float*)(EEPROM_UVLO_CURRENT_POSITION + 4), current_position[Y_AXIS]);
-    eeprom_update_float((float*)(EEPROM_UVLO_CURRENT_POSITION_Z), current_position[Z_AXIS]);
+    eeprom_update_float((float*)EEPROM_UVLO_CURRENT_POSITION_Z , current_position[Z_AXIS]);
     // Store the current feed rate, temperatures, fan speed and extruder multipliers (flow rates)
     EEPROM_save_B(EEPROM_UVLO_FEEDRATE, &feedrate_bckp);
     eeprom_update_byte((uint8_t*)EEPROM_UVLO_TARGET_HOTEND, target_temperature[active_extruder]);
@@ -8804,16 +8865,14 @@ void uvlo_()
     // Increment power failure counter
 	eeprom_update_byte((uint8_t*)EEPROM_POWER_COUNT, eeprom_read_byte((uint8_t*)EEPROM_POWER_COUNT) + 1);
 	eeprom_update_word((uint16_t*)EEPROM_POWER_COUNT_TOT, eeprom_read_word((uint16_t*)EEPROM_POWER_COUNT_TOT) + 1);
-    
-		printf_P(_N("UVLO - end %d\n"), _millis() - time_start);
-    
+      printf_P(_N("UVLO - end %d\n"), _millis() - time_start);
+
 #if 0
     // Move the print head to the side of the print until all the power stored in the power supply capacitors is depleted.
     current_position[X_AXIS] = (current_position[X_AXIS] < 0.5f * (X_MIN_POS + X_MAX_POS)) ? X_MIN_POS : X_MAX_POS;
     plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 500, active_extruder);
     st_synchronize();
 #endif
-    
 wdt_enable(WDTO_500MS);
 WRITE(BEEPER,HIGH);
 while(1)
@@ -8839,30 +8898,29 @@ tmc2130_set_current_r(Z_AXIS, 20);
 #ifdef TMC2130
 z_microsteps=tmc2130_rd_MSCNT(Z_TMC2130_CS);
 #endif //TMC2130
-
 planner_abort_hard();
-sei();
-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)/cs.axis_steps_per_unit[Z_AXIS], 
-     current_position[E_AXIS],
-     40, active_extruder);
-st_synchronize();
 disable_z();
 
-// Finaly store the "power outage" flag.
-//if(sd_print)
-     eeprom_update_byte((uint8_t*)EEPROM_UVLO,2);
+//save current position only in case, where the printer is moving on Z axis, which is only when EEPROM_UVLO is 1
+//EEPROM_UVLO is 1 after normal uvlo or after recover_print(), when the extruder is moving on Z axis after rehome
+if(eeprom_read_byte((uint8_t*)EEPROM_UVLO)!=2){
+  eeprom_update_float((float*)(EEPROM_UVLO_TINY_CURRENT_POSITION_Z), current_position[Z_AXIS]);
+  eeprom_update_word((uint16_t*)(EEPROM_UVLO_TINY_Z_MICROSTEPS),z_microsteps);
+}
 
-eeprom_update_word((uint16_t*)(EEPROM_UVLO_TINY_Z_MICROSTEPS),z_microsteps);
-eeprom_update_float((float*)(EEPROM_UVLO_TINY_CURRENT_POSITION_Z), current_position[Z_AXIS]);
+//after multiple power panics current Z axis is unknow
+//in this case we set EEPROM_UVLO_TINY_CURRENT_POSITION_Z to last know position which is EEPROM_UVLO_CURRENT_POSITION_Z 
+if(eeprom_read_float((float*)EEPROM_UVLO_TINY_CURRENT_POSITION_Z) < 0.001f){
+  eeprom_update_float((float*)(EEPROM_UVLO_TINY_CURRENT_POSITION_Z), eeprom_read_float((float*)EEPROM_UVLO_CURRENT_POSITION_Z));
+  eeprom_update_word((uint16_t*)(EEPROM_UVLO_TINY_Z_MICROSTEPS), eeprom_read_word((uint16_t*)EEPROM_UVLO_Z_MICROSTEPS));
+}
+
+// Finaly store the "power outage" flag.
+eeprom_update_byte((uint8_t*)EEPROM_UVLO,2);
 
 // Increment power failure counter
 eeprom_update_byte((uint8_t*)EEPROM_POWER_COUNT, eeprom_read_byte((uint8_t*)EEPROM_POWER_COUNT) + 1);
 eeprom_update_word((uint16_t*)EEPROM_POWER_COUNT_TOT, eeprom_read_word((uint16_t*)EEPROM_POWER_COUNT_TOT) + 1);
-
 wdt_enable(WDTO_500MS);
 WRITE(BEEPER,HIGH);
 while(1)
@@ -8924,7 +8982,9 @@ void setup_uvlo_interrupt() {
 ISR(INT4_vect) {
 	EIMSK &= ~(1 << 4); //disable INT4 interrupt to make sure that this code will be executed just once 
 	SERIAL_ECHOLNPGM("INT4");
-     if(IS_SD_PRINTING && (!(eeprom_read_byte((uint8_t*)EEPROM_UVLO))) ) uvlo_();
+    //fire normal uvlo only in case where EEPROM_UVLO is 0 or if IS_SD_PRINTING is 1. 
+    //Don't change || to && because in some case the printer can be moving although IS_SD_PRINTING is zero
+     if((IS_SD_PRINTING ) || (!(eeprom_read_byte((uint8_t*)EEPROM_UVLO)))) uvlo_();
      if(eeprom_read_byte((uint8_t*)EEPROM_UVLO)) uvlo_tiny();
 }
 
@@ -8932,14 +8992,14 @@ void recover_print(uint8_t automatic) {
 	char cmd[30];
 	lcd_update_enable(true);
 	lcd_update(2);
-	lcd_setstatuspgm(_i("Recovering print    "));////MSG_RECOVERING_PRINT c=20 r=1
-
-     bool bTiny=(eeprom_read_byte((uint8_t*)EEPROM_UVLO)==2);
-     recover_machine_state_after_power_panic(bTiny); //recover position, temperatures and extrude_multipliers
+  lcd_setstatuspgm(_i("Recovering print    "));////MSG_RECOVERING_PRINT c=20 r=1
 
+      bool bTiny=(eeprom_read_byte((uint8_t*)EEPROM_UVLO)==2);
+      recover_machine_state_after_power_panic(bTiny); //recover position, temperatures and extrude_multipliers
   // Lift the print head, so one may remove the excess priming material.
-     if(!bTiny&&(current_position[Z_AXIS]<25))
+      if(!bTiny&&(current_position[Z_AXIS]<25))
           enquecommand_P(PSTR("G1 Z25 F800"));
+
   // Home X and Y axes. Homing just X and Y shall not touch the babystep and the world2machine transformation status.
 	enquecommand_P(PSTR("G28 X Y"));
   // Set the target bed and nozzle temperatures and wait.
@@ -8959,8 +9019,7 @@ void recover_print(uint8_t automatic) {
 
   // Restart the print.
 	restore_print_from_eeprom();
-
-	printf_P(_N("Current pos Z_AXIS:%.3f\nCurrent pos E_AXIS:%.3f\n"), current_position[Z_AXIS], current_position[E_AXIS]);
+  printf_P(_N("Current pos Z_AXIS:%.3f\nCurrent pos E_AXIS:%.3f\n"), current_position[Z_AXIS], current_position[E_AXIS]);
 }
 
 void recover_machine_state_after_power_panic(bool bTiny)
@@ -8970,14 +9029,36 @@ void recover_machine_state_after_power_panic(bool bTiny)
   // The logical XY coordinates are needed to recover the machine Z coordinate corrected by the mesh bed leveling.
   current_position[X_AXIS] = eeprom_read_float((float*)(EEPROM_UVLO_CURRENT_POSITION + 0));
   current_position[Y_AXIS] = eeprom_read_float((float*)(EEPROM_UVLO_CURRENT_POSITION + 4));
+
+  // 2) Restore the mesh bed leveling offsets. This is 2*7*7=98 bytes, which takes 98*3.4us=333us in worst case.
+  mbl.active = false;
+  for (int8_t mesh_point = 0; mesh_point < MESH_NUM_X_POINTS * MESH_NUM_Y_POINTS; ++ mesh_point) {
+    uint8_t ix = mesh_point % MESH_NUM_X_POINTS; // from 0 to MESH_NUM_X_POINTS - 1
+    uint8_t iy = mesh_point / MESH_NUM_X_POINTS;
+    // Scale the z value to 10u resolution.
+    int16_t v;
+    eeprom_read_block(&v, (void*)(EEPROM_UVLO_MESH_BED_LEVELING_FULL+2*mesh_point), 2);
+    if (v != 0)
+      mbl.active = true;
+    mbl.z_values[iy][ix] = float(v) * 0.001f;
+  }
+
   // Recover the logical coordinate of the Z axis at the time of the power panic.
   // 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) / cs.axis_steps_per_unit[Z_AXIS];
-  else
+  if(bTiny){    
+    current_position[Z_AXIS] = eeprom_read_float((float*)(EEPROM_UVLO_TINY_CURRENT_POSITION_Z))
+     + float((1024 - eeprom_read_word((uint16_t*)(EEPROM_UVLO_TINY_Z_MICROSTEPS)) 
+    + 7) >> 4) / cs.axis_steps_per_unit[Z_AXIS];
+
+    //after multiple power panics the print is slightly in the air so get it little bit down. 
+    //Not exactly sure why is this happening, but it has something to do with bed leveling and world2machine coordinates 
+    current_position[Z_AXIS] -= 0.4*mbl.get_z(current_position[X_AXIS], current_position[Y_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) / cs.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"));
@@ -8990,21 +9071,8 @@ void recover_machine_state_after_power_panic(bool bTiny)
   SERIAL_ECHOPGM("recover_machine_state_after_power_panic, initial ");
   print_world_coordinates();
 
-  // 2) Initialize the logical to physical coordinate system transformation.
+  // 3) Initialize the logical to physical coordinate system transformation.
   world2machine_initialize();
-
-  // 3) Restore the mesh bed leveling offsets. This is 2*7*7=98 bytes, which takes 98*3.4us=333us in worst case.
-  mbl.active = false;
-  for (int8_t mesh_point = 0; mesh_point < MESH_NUM_X_POINTS * MESH_NUM_Y_POINTS; ++ mesh_point) {
-    uint8_t ix = mesh_point % MESH_NUM_X_POINTS; // from 0 to MESH_NUM_X_POINTS - 1
-    uint8_t iy = mesh_point / MESH_NUM_X_POINTS;
-    // Scale the z value to 10u resolution.
-    int16_t v;
-    eeprom_read_block(&v, (void*)(EEPROM_UVLO_MESH_BED_LEVELING_FULL+2*mesh_point), 2);
-    if (v != 0)
-      mbl.active = true;
-    mbl.z_values[iy][ix] = float(v) * 0.001f;
-  }
 //  SERIAL_ECHOPGM("recover_machine_state_after_power_panic, initial ");
 //  print_mesh_bed_leveling_table();
 
@@ -9020,7 +9088,7 @@ void recover_machine_state_after_power_panic(bool bTiny)
   axis_known_position[X_AXIS] = true; enable_x();
   axis_known_position[Y_AXIS] = true; enable_y();
   axis_known_position[Z_AXIS] = true; enable_z();
-
+  
   SERIAL_ECHOPGM("recover_machine_state_after_power_panic, initial ");
   print_physical_coordinates();
 
@@ -9087,6 +9155,8 @@ void restore_print_from_eeprom() {
 	strcat_P(cmd, PSTR(" Y"));   strcat(cmd, ftostr32(eeprom_read_float((float*)(EEPROM_UVLO_CURRENT_POSITION + 4))));
 	strcat_P(cmd, PSTR(" F2000"));
 	enquecommand(cmd);
+  //moving on Z axis ahead, set EEPROM_UVLO to 1, so normal uvlo can fire
+  eeprom_update_byte((uint8_t*)EEPROM_UVLO,1);
   // Move the Z axis down to the print, in logical coordinates.
 	strcpy_P(cmd, PSTR("G1 Z")); strcat(cmd, ftostr32(eeprom_read_float((float*)(EEPROM_UVLO_CURRENT_POSITION_Z))));
 	enquecommand(cmd);
@@ -9274,22 +9344,20 @@ void stop_and_save_print_to_ram(float z_move, float e_move)
 
 	// First unretract (relative extrusion)
 	if(!saved_extruder_relative_mode){
-	  strcpy_P(buf, PSTR("M83"));
-	  enquecommand(buf, false);
+		enquecommand(PSTR("M83"), true);
 	}
 	
 	//retract 45mm/s
-	strcpy_P(buf, PSTR("G1 E"));
-	dtostrf(e_move, 6, 3, buf + strlen(buf));
-	strcat_P(buf, PSTR(" F"));
-	dtostrf(2700, 8, 3, buf + strlen(buf));
+	// A single sprintf may not be faster, but is definitely 20B shorter
+	// than a sequence of commands building the string piece by piece
+	// A snprintf would have been a safer call, but since it is not used
+	// in the whole program, its implementation would bring more bytes to the total size
+	// The behavior of dtostrf 8,3 should be roughly the same as %-0.3
+	sprintf_P(buf, PSTR("G1 E%-0.3f F2700"), e_move);
 	enquecommand(buf, false);
 
 	// Then lift Z axis
-    strcpy_P(buf, PSTR("G1 Z"));
-    dtostrf(saved_pos[Z_AXIS] + z_move, 8, 3, buf + strlen(buf));
-    strcat_P(buf, PSTR(" F"));
-    dtostrf(homing_feedrate[Z_AXIS], 8, 3, buf + strlen(buf));
+	sprintf_P(buf, PSTR("G1 Z%-0.3f F%-0.3f"), saved_pos[Z_AXIS] + z_move, homing_feedrate[Z_AXIS]); 
     // At this point the command queue is empty.
     enquecommand(buf, false);
     // If this call is invoked from the main Arduino loop() function, let the caller know that the command
@@ -9315,6 +9383,12 @@ void stop_and_save_print_to_ram(float z_move, float e_move)
 void restore_print_from_ram_and_continue(float e_move)
 {
 	if (!saved_printing) return;
+	
+#ifdef FANCHECK
+	// Do not allow resume printing if fans are still not ok
+	if( fan_check_error != EFCE_OK )return;
+#endif
+	
 //	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

+ 1 - 1
Firmware/cmdqueue.cpp

@@ -598,7 +598,7 @@ void get_command()
         if (farm_mode)
         {
             prusa_statistics(6);
-            lcd_commands_type = LCD_COMMAND_FARM_MODE_CONFIRM;
+            lcd_commands_type = LcdCommands::FarmModeConfirm;
         }
 
       }

+ 13 - 1
Firmware/eeprom.h

@@ -155,13 +155,19 @@
 #define EEPROM_MMU_LOAD_FAIL (EEPROM_MMU_LOAD_FAIL_TOT - 1) //uint8_t
 #define EEPROM_MMU_CUTTER_ENABLED (EEPROM_MMU_LOAD_FAIL - 1)
 #define EEPROM_UVLO_MESH_BED_LEVELING_FULL     (EEPROM_MMU_CUTTER_ENABLED - 12*12*2) //allow 12 calibration points for future expansion
+
 #define EEPROM_MBL_TYPE	(EEPROM_UVLO_MESH_BED_LEVELING_FULL-1) //uint8_t for mesh bed leveling precision
 #define EEPROM_MBL_MAGNET_ELIMINATION (EEPROM_MBL_TYPE -1)  
 #define EEPROM_MBL_POINTS_NR (EEPROM_MBL_MAGNET_ELIMINATION -1) //uint8_t number of points in one exis for mesh bed leveling
 #define EEPROM_MBL_PROBE_NR (EEPROM_MBL_POINTS_NR-1) //number of measurements for each point
+
 #define EEPROM_MMU_STEALTH (EEPROM_MBL_PROBE_NR-1)
 
-#define EEPROM_UVLO_LA_K (EEPROM_MMU_STEALTH-4) // float
+#define EEPROM_CHECK_MODE (EEPROM_MMU_STEALTH-1) // uint8
+#define EEPROM_NOZZLE_DIAMETER (EEPROM_CHECK_MODE-1) // uint8
+#define EEPROM_NOZZLE_DIAMETER_uM (EEPROM_NOZZLE_DIAMETER-2) // uint16
+#define EEPROM_UVLO_LA_K (EEPROM_NOZZLE_DIAMETER_uM-4) // float
+
 // !!!!!
 // !!!!! this is end of EEPROM section ... all updates MUST BE inserted before this mark !!!!!
 // !!!!!
@@ -203,5 +209,11 @@
 static M500_conf * const EEPROM_M500_base = reinterpret_cast<M500_conf*>(20); //offset for storing settings using M500
 #endif
 
+enum
+{
+    EEPROM_MMU_CUTTER_ENABLED_enabled = 1,
+    EEPROM_MMU_CUTTER_ENABLED_always = 2,
+};
+
 
 #endif // EEPROM_H

+ 214 - 0
Firmware/first_lay_cal.cpp

@@ -0,0 +1,214 @@
+//! @file
+//! @date Jun 10, 2019
+//! @author Marek Bel
+//! @brief First layer (Z offset) calibration
+
+#include "first_lay_cal.h"
+#include "Configuration_prusa.h"
+#include "language.h"
+#include "Marlin.h"
+#include "mmu.h"
+#include <avr/pgmspace.h>
+
+//! @brief Preheat
+void lay1cal_preheat()
+{
+    static const char cmd_preheat_0[] PROGMEM = "M107";
+    static const char cmd_preheat_1[] PROGMEM = "M104 S" STRINGIFY(PLA_PREHEAT_HOTEND_TEMP);
+    static const char cmd_preheat_2[] PROGMEM = "M140 S" STRINGIFY(PLA_PREHEAT_HPB_TEMP);
+    static const char cmd_preheat_3[] PROGMEM = "M190 S" STRINGIFY(PLA_PREHEAT_HPB_TEMP);
+    static const char cmd_preheat_4[] PROGMEM = "M109 S" STRINGIFY(PLA_PREHEAT_HOTEND_TEMP);
+    static const char cmd_preheat_5[] PROGMEM = "G28";
+    static const char cmd_preheat_6[] PROGMEM = "G92 E0.0";
+
+    static const char * const preheat_cmd[] PROGMEM =
+    {
+        cmd_preheat_0,
+        cmd_preheat_1,
+        cmd_preheat_2,
+        cmd_preheat_3,
+        cmd_preheat_4,
+        cmd_preheat_5, //call MSG_M117_V2_CALIBRATION before
+        cmd_preheat_6,
+    };
+
+    for (uint8_t i = 0; i < (sizeof(preheat_cmd)/sizeof(preheat_cmd[0])); ++i)
+    {
+        if (5 == i)  enquecommand_P(_T(MSG_M117_V2_CALIBRATION));
+        enquecommand_P(static_cast<char*>(pgm_read_ptr(&preheat_cmd[i])));
+    }
+
+}
+
+//! @brief Print intro line
+//! @param cmd_buffer character buffer needed to format gcodes
+//! @param filament filament to use (applies for MMU only)
+void lay1cal_intro_line(char *cmd_buffer, uint8_t filament)
+{
+    static const char cmd_intro_mmu_0[] PROGMEM = "M83";
+    static const char cmd_intro_mmu_1[] PROGMEM = "G1 Y-3.0 F1000.0";
+    static const char cmd_intro_mmu_2[] PROGMEM = "G1 Z0.4 F1000.0";
+    static const char cmd_intro_mmu_3[] PROGMEM = "G1 X55.0 E32.0 F1073.0"; // call T code before
+    static const char cmd_intro_mmu_4[] PROGMEM = "G1 X5.0 E32.0 F1800.0";
+    static const char cmd_intro_mmu_5[] PROGMEM = "G1 X55.0 E8.0 F2000.0";
+    static const char cmd_intro_mmu_6[] PROGMEM = "G1 Z0.3 F1000.0";
+    static const char cmd_intro_mmu_7[] PROGMEM = "G92 E0.0";
+    static const char cmd_intro_mmu_8[] PROGMEM = "G1 X240.0 E25.0  F2200.0";
+    static const char cmd_intro_mmu_9[] PROGMEM = "G1 Y-2.0 F1000.0";
+    static const char cmd_intro_mmu_10[] PROGMEM = "G1 X55.0 E25 F1400.0";
+    static const char cmd_intro_mmu_11[] PROGMEM = "G1 Z0.20 F1000.0";
+    static const char cmd_intro_mmu_12[] PROGMEM = "G1 X5.0 E4.0 F1000.0";
+
+    static const char * const intro_mmu_cmd[] PROGMEM =
+    {
+        cmd_intro_mmu_0,
+        cmd_intro_mmu_1,
+        cmd_intro_mmu_2,
+        cmd_intro_mmu_3, // call T code before
+        cmd_intro_mmu_4,
+        cmd_intro_mmu_5,
+        cmd_intro_mmu_6,
+        cmd_intro_mmu_7,
+        cmd_intro_mmu_8,
+        cmd_intro_mmu_9,
+        cmd_intro_mmu_10,
+        cmd_intro_mmu_11,
+        cmd_intro_mmu_12,
+    };
+
+    if (mmu_enabled)
+    {
+        for (uint8_t i = 0; i < (sizeof(intro_mmu_cmd)/sizeof(intro_mmu_cmd[0])); ++i)
+        {
+            if (3 == i)
+                {
+                    sprintf_P(cmd_buffer, PSTR("T%d"), filament);
+                    enquecommand(cmd_buffer);
+                }
+            enquecommand_P(static_cast<char*>(pgm_read_ptr(&intro_mmu_cmd[i])));
+        }
+    }
+    else
+    {
+        enquecommand_P(PSTR("G1 X60.0 E9.0 F1000.0"));
+        enquecommand_P(PSTR("G1 X100.0 E12.5 F1000.0"));
+    }
+}
+
+//! @brief Setup for printing meander
+void lay1cal_before_meander()
+{
+    static const char cmd_pre_meander_0[] PROGMEM = "G92 E0.0";
+    static const char cmd_pre_meander_1[] PROGMEM = "G21"; //set units to millimeters TODO unsupported command
+    static const char cmd_pre_meander_2[] PROGMEM = "G90"; //use absolute coordinates
+    static const char cmd_pre_meander_3[] PROGMEM = "M83"; //use relative distances for extrusion TODO: duplicate
+    static const char cmd_pre_meander_4[] PROGMEM = "G1 E-1.50000 F2100.00000";
+    static const char cmd_pre_meander_5[] PROGMEM = "G1 Z5 F7200.000";
+    static const char cmd_pre_meander_6[] PROGMEM = "M204 S1000"; //set acceleration
+    static const char cmd_pre_meander_7[] PROGMEM = "G1 F4000";
+
+    static const char * const cmd_pre_meander[] PROGMEM =
+    {
+            cmd_pre_meander_0,
+            cmd_pre_meander_1,
+            cmd_pre_meander_2,
+            cmd_pre_meander_3,
+            cmd_pre_meander_4,
+            cmd_pre_meander_5,
+            cmd_pre_meander_6,
+            cmd_pre_meander_7,
+    };
+
+    for (uint8_t i = 0; i < (sizeof(cmd_pre_meander)/sizeof(cmd_pre_meander[0])); ++i)
+    {
+        enquecommand_P(static_cast<char*>(pgm_read_ptr(&cmd_pre_meander[i])));
+    }
+}
+
+
+//! @brief Count extrude length
+//!
+//! @param layer_height layer height in mm
+//! @param extrusion_width extrusion width in mm
+//! @param extrusion_length extrusion length in mm
+//! @return filament length in mm which needs to be extruded to form line
+static constexpr float count_e(float layer_height, float extrusion_width, float extrusion_length)
+{
+    return (extrusion_length * layer_height * extrusion_width / (M_PI * pow(1.75, 2) / 4));
+}
+
+static const float width = 0.4; //!< line width
+static const float length = 20 - width; //!< line length
+static const float height = 0.2; //!< layer height TODO This is wrong, as current Z height is 0.15 mm
+static const float extr = count_e(height, width, length); //!< E axis movement needed to print line
+
+//! @brief Print meander
+//! @param cmd_buffer character buffer needed to format gcodes
+void lay1cal_meander(char *cmd_buffer)
+{
+    static const char cmd_meander_0[] PROGMEM = "G1 X50 Y155";
+    static const char cmd_meander_1[] PROGMEM = "G1 Z0.150 F7200.000";
+    static const char cmd_meander_2[] PROGMEM = "G1 F1080";
+    static const char cmd_meander_3[] PROGMEM = "G1 X75 Y155 E2.5";
+    static const char cmd_meander_4[] PROGMEM = "G1 X100 Y155 E2";
+    static const char cmd_meander_5[] PROGMEM = "G1 X200 Y155 E2.62773";
+    static const char cmd_meander_6[] PROGMEM = "G1 X200 Y135 E0.66174";
+    static const char cmd_meander_7[] PROGMEM = "G1 X50 Y135 E3.62773";
+    static const char cmd_meander_8[] PROGMEM = "G1 X50 Y115 E0.49386";
+    static const char cmd_meander_9[] PROGMEM = "G1 X200 Y115 E3.62773";
+    static const char cmd_meander_10[] PROGMEM = "G1 X200 Y95 E0.49386";
+    static const char cmd_meander_11[] PROGMEM = "G1 X50 Y95 E3.62773";
+    static const char cmd_meander_12[] PROGMEM = "G1 X50 Y75 E0.49386";
+    static const char cmd_meander_13[] PROGMEM = "G1 X200 Y75 E3.62773";
+    static const char cmd_meander_14[] PROGMEM = "G1 X200 Y55 E0.49386";
+    static const char cmd_meander_15[] PROGMEM = "G1 X50 Y55 E3.62773";
+
+    static const char * const cmd_meander[] PROGMEM =
+    {
+        cmd_meander_0,
+        cmd_meander_1,
+        cmd_meander_2,
+        cmd_meander_3,
+        cmd_meander_4,
+        cmd_meander_5,
+        cmd_meander_6,
+        cmd_meander_7,
+        cmd_meander_8,
+        cmd_meander_9,
+        cmd_meander_10,
+        cmd_meander_11,
+        cmd_meander_12,
+        cmd_meander_13,
+        cmd_meander_14,
+        cmd_meander_15,
+    };
+
+    for (uint8_t i = 0; i < (sizeof(cmd_meander)/sizeof(cmd_meander[0])); ++i)
+    {
+        enquecommand_P(static_cast<char*>(pgm_read_ptr(&cmd_meander[i])));
+    }
+    sprintf_P(cmd_buffer, PSTR("G1 X50 Y35 E%-.3f"), extr);
+    enquecommand(cmd_buffer);
+}
+
+//! @brief Print square
+//!
+//! This function needs to be called 16 times for i from 0 to 15.
+//!
+//! @param cmd_buffer character buffer needed to format gcodes
+//! @param i iteration
+void lay1cal_square(char *cmd_buffer, uint8_t i)
+{
+    const float extr_short_segment = count_e(height, width, width);
+
+    static const char fmt1[] PROGMEM = "G1 X%d Y%-.2f E%-.3f";
+    static const char fmt2[] PROGMEM = "G1 Y%-.2f E%-.3f";
+    sprintf_P(cmd_buffer, fmt1, 70, (35 - i*width * 2), extr);
+    enquecommand(cmd_buffer);
+    sprintf_P(cmd_buffer, fmt2, (35 - (2 * i + 1)*width), extr_short_segment);
+    enquecommand(cmd_buffer);
+    sprintf_P(cmd_buffer, fmt1, 50, (35 - (2 * i + 1)*width), extr);
+    enquecommand(cmd_buffer);
+    sprintf_P(cmd_buffer, fmt2, (35 - (i + 1)*width * 2), extr_short_segment);
+    enquecommand(cmd_buffer);
+}

+ 15 - 0
Firmware/first_lay_cal.h

@@ -0,0 +1,15 @@
+//! @file
+//! @date Jun 10, 2019
+//! @author Marek Bel
+
+#ifndef FIRMWARE_FIRST_LAY_CAL_H_
+#define FIRMWARE_FIRST_LAY_CAL_H_
+#include <stdint.h>
+
+void lay1cal_preheat();
+void lay1cal_intro_line(char *cmd_buffer, uint8_t filament);
+void lay1cal_before_meander();
+void lay1cal_meander(char *cmd_buffer);
+void lay1cal_square(char *cmd_buffer, uint8_t i);
+
+#endif /* FIRMWARE_FIRST_LAY_CAL_H_ */

+ 53 - 14
Firmware/fsensor.cpp

@@ -54,6 +54,11 @@ bool fsensor_not_responding = false;
 bool fsensor_printing_saved = false;
 //! enable/disable quality meassurement
 bool fsensor_oq_meassure_enabled = false;
+//! as explained in the CHECK_FSENSOR macro: this flag is set to true when fsensor posts
+//! the M600 into the command queue, which elliminates the hazard of having posted multiple M600's
+//! before the first one gets read and started processing.
+//! Btw., the IR fsensor could do up to 6 posts before the command queue managed to start processing the first M600 ;)
+static bool fsensor_m600_enqueued = false;
 
 //! number of errors, updated in ISR
 uint8_t fsensor_err_cnt = 0;
@@ -120,6 +125,7 @@ void fsensor_restore_print_and_continue(void)
     printf_P(PSTR("fsensor_restore_print_and_continue\n"));
 	fsensor_watch_runout = true;
 	fsensor_err_cnt = 0;
+	fsensor_m600_enqueued = false;
     restore_print_from_ram_and_continue(0); //XYZ = orig, E - no change
 }
 
@@ -501,6 +507,47 @@ void fsensor_st_block_chunk(int cnt)
 	}
 }
 
+//! This ensures generating z-position at least 25mm above the heat bed.
+//! Making this a template enables changing the computation data type easily at all spots where necessary.
+//! @param current_z current z-position
+//! @return z-position at least 25mm above the heat bed plus FILAMENTCHANGE_ZADD 
+template <typename T>
+inline T fsensor_clamp_z(float current_z){
+	T z( current_z );
+	if(z < T(25)){ // make sure the compiler understands, that the constant 25 is of correct type
+		// - necessary for uint8_t -> results in shorter code
+		z = T(25); // move to at least 25mm above heat bed
+	}
+	return z + T(FILAMENTCHANGE_ZADD); // always move above the printout by FILAMENTCHANGE_ZADD (default 2mm)	
+}
+
+//! Common code for enqueing M600 and supplemental codes into the command queue.
+//! Used both for the IR sensor and the PAT9125
+void fsensor_enque_M600(){
+	printf_P(PSTR("fsensor_update - M600\n"));
+	eeprom_update_byte((uint8_t*)EEPROM_FERROR_COUNT, eeprom_read_byte((uint8_t*)EEPROM_FERROR_COUNT) + 1);
+	eeprom_update_word((uint16_t*)EEPROM_FERROR_COUNT_TOT, eeprom_read_word((uint16_t*)EEPROM_FERROR_COUNT_TOT) + 1);
+	enquecommand_front_P(PSTR("PRUSA fsensor_recover"));
+	fsensor_m600_enqueued = true;
+	enquecommand_front_P((PSTR("M600")));
+#define xstr(a) str(a)
+#define str(a) #a
+	static const char gcodeMove[] PROGMEM = 
+			"G1 X" xstr(FILAMENTCHANGE_XPOS) 
+			" Y" xstr(FILAMENTCHANGE_YPOS) 
+			" Z%u";
+#undef str
+#undef xstr
+	char buf[32];
+	// integer arithmetics is far shorter, I don't need a precise float position here, just move a bit above
+	// 8bit arithmetics in fsensor_clamp_z is 10B shorter than 16bit (not talking about float ;) ) 
+	// The compile-time static_assert here ensures, that the computation gets enough bits in case of Z-range too high,
+	// i.e. makes the user change the data type, which also results in larger code
+	static_assert(Z_MAX_POS < (255 - FILAMENTCHANGE_ZADD), "Z-range too high, change fsensor_clamp_z<uint8_t> to <uint16_t>");
+	sprintf_P(buf, gcodeMove, fsensor_clamp_z<uint8_t>(current_position[Z_AXIS]) );
+	enquecommand_front(buf, false);
+}
+
 //! @brief filament sensor update (perform M600 on filament runout)
 //!
 //! Works only if filament sensor is enabled.
@@ -509,7 +556,7 @@ void fsensor_st_block_chunk(int cnt)
 void fsensor_update(void)
 {
 #ifdef PAT9125
-		if (fsensor_enabled && fsensor_watch_runout && (fsensor_err_cnt > FSENSOR_ERR_MAX))
+		if (fsensor_enabled && fsensor_watch_runout && (fsensor_err_cnt > FSENSOR_ERR_MAX) && ( ! fsensor_m600_enqueued) )
 		{
 			bool autoload_enabled_tmp = fsensor_autoload_enabled;
 			fsensor_autoload_enabled = false;
@@ -549,25 +596,17 @@ void fsensor_update(void)
 			}
 			else
 			{
-				printf_P(PSTR("fsensor_update - M600\n"));
-				eeprom_update_byte((uint8_t*)EEPROM_FERROR_COUNT, eeprom_read_byte((uint8_t*)EEPROM_FERROR_COUNT) + 1);
-				eeprom_update_word((uint16_t*)EEPROM_FERROR_COUNT_TOT, eeprom_read_word((uint16_t*)EEPROM_FERROR_COUNT_TOT) + 1);
-				enquecommand_front_P(PSTR("PRUSA fsensor_recover"));
-				enquecommand_front_P((PSTR("M600")));
+				fsensor_enque_M600();
 				fsensor_watch_runout = false;
 			}
 			fsensor_autoload_enabled = autoload_enabled_tmp;
 			fsensor_oq_meassure_enabled = oq_meassure_enabled_tmp;
 		}
 #else //PAT9125
-		if ((digitalRead(IR_SENSOR_PIN) == 1) && CHECK_FSENSOR && fsensor_enabled && ir_sensor_detected)
-		{
-			fsensor_stop_and_save_print();
-			printf_P(PSTR("fsensor_update - M600\n"));
-			eeprom_update_byte((uint8_t*)EEPROM_FERROR_COUNT, eeprom_read_byte((uint8_t*)EEPROM_FERROR_COUNT) + 1);
-			eeprom_update_word((uint16_t*)EEPROM_FERROR_COUNT_TOT, eeprom_read_word((uint16_t*)EEPROM_FERROR_COUNT_TOT) + 1);
-			enquecommand_front_P(PSTR("PRUSA fsensor_recover"));
-			enquecommand_front_P((PSTR("M600")));
+		if ((digitalRead(IR_SENSOR_PIN) == 1) && CHECK_FSENSOR && fsensor_enabled && ir_sensor_detected && ( ! fsensor_m600_enqueued) )
+		{
+			fsensor_stop_and_save_print();
+			fsensor_enque_M600();
 		}
 #endif //PAT9125
 }

+ 1 - 0
Firmware/fsensor.h

@@ -18,6 +18,7 @@ extern bool fsensor_oq_meassure_enabled;
 //! @name save restore printing
 //! @{
 extern void fsensor_stop_and_save_print(void);
+//! restore print - restore position and heatup to original temperature
 extern void fsensor_restore_print_and_continue(void);
 //! @}
 

+ 1 - 1
Firmware/menu.cpp

@@ -26,7 +26,7 @@ uint8_t menu_data[MENU_DATA_SIZE];
 #endif
 
 uint8_t menu_depth = 0;
-
+uint8_t menu_block_entering_on_serious_errors = SERIOUS_ERR_NONE;
 uint8_t menu_line = 0;
 uint8_t menu_item = 0;
 uint8_t menu_row = 0;

+ 21 - 0
Firmware/menu.h

@@ -28,6 +28,27 @@ extern uint8_t menu_data[MENU_DATA_SIZE];
 
 extern uint8_t menu_depth;
 
+//! definition of serious errors possibly blocking the main menu
+//! Use them as bit mask, so that the code may set various errors at the same time
+enum ESeriousErrors {
+	SERIOUS_ERR_NONE            = 0,
+	SERIOUS_ERR_MINTEMP_HEATER  = 0x01,
+	SERIOUS_ERR_MINTEMP_BED     = 0x02
+}; // and possibly others in the future.
+
+//! this is a flag for disabling entering the main menu. If this is set
+//! to anything != 0, the only the main status screen will be shown on the
+//! LCD and the user will be prevented from entering the menu.
+//! Now used only to block doing anything with the printer when there is
+//! the infamous MINTEMP error (SERIOUS_ERR_MINTEMP).
+extern uint8_t menu_block_entering_on_serious_errors;
+
+//! a pair of macros for manipulating the serious errors
+//! a c++ class would have been better
+#define menu_set_serious_error(x) menu_block_entering_on_serious_errors |= x;
+#define menu_unset_serious_error(x) menu_block_entering_on_serious_errors &= ~x;
+#define menu_is_serious_error(x) (menu_block_entering_on_serious_errors & x) != 0
+
 extern uint8_t menu_line;
 extern uint8_t menu_item;
 extern uint8_t menu_row;

+ 12 - 12
Firmware/mmu.cpp

@@ -1076,7 +1076,7 @@ if(0)
      extr_unload();
      }
 else	{
-     eFilamentAction=e_FILAMENT_ACTION_mmuUnLoad;
+     eFilamentAction=FilamentAction::MmuUnLoad;
      bFilamentFirstRun=false;
      if(target_temperature[0]>=EXTRUDE_MINTEMP)
           {
@@ -1372,13 +1372,13 @@ void lcd_mmu_load_to_nozzle(uint8_t filament_nr)
         mmu_load_to_nozzle();
         load_filament_final_feed();
         st_synchronize();
-        custom_message_type = CUSTOM_MSG_TYPE_F_LOAD;
+        custom_message_type = CustomMsg::FilamentLoading;
         lcd_setstatuspgm(_T(MSG_LOADING_FILAMENT));
         lcd_return_to_status();
         lcd_update_enable(true);
         lcd_load_filament_color_check();
         lcd_setstatuspgm(_T(WELCOME_MSG));
-        custom_message_type = CUSTOM_MSG_TYPE_STATUS;
+        custom_message_type = CustomMsg::Status;
     }
     else
     {
@@ -1511,20 +1511,20 @@ void mmu_continue_loading(bool blocking)
 
     enum class Ls : uint_least8_t
     {
-        enter,
-        retry,
-        unload,
+        Enter,
+        Retry,
+        Unload,
     };
-    Ls state = Ls::enter;
+    Ls state = Ls::Enter;
 
     while (PIN_GET(IR_SENSOR_PIN) != 0)
     {
         switch (state)
         {
-        case Ls::enter:
+        case Ls::Enter:
             increment_load_fail();
             // no break
-        case Ls::retry:
+        case Ls::Retry:
 #ifdef MMU_HAS_CUTTER
             if (1 == eeprom_read_byte((uint8_t*)EEPROM_MMU_CUTTER_ENABLED))
             {
@@ -1535,9 +1535,9 @@ void mmu_continue_loading(bool blocking)
             mmu_command(MmuCmd::T0 + tmp_extruder);
             manage_response(true, true, MMU_TCODE_MOVE);
             load_more();
-            state = Ls::unload;
+            state = Ls::Unload;
             break;
-        case Ls::unload:
+        case Ls::Unload:
             stop_and_save_print_to_ram(0, 0);
 
             //lift z
@@ -1562,7 +1562,7 @@ void mmu_continue_loading(bool blocking)
             {
                 marlin_wait_for_click();
                 restore_print_from_ram_and_continue(0);
-                state = Ls::retry;
+                state = Ls::Retry;
             }
             else
             {

+ 0 - 0
Firmware/pins_Einsy_1_0.h


+ 124 - 24
Firmware/temperature.cpp

@@ -95,7 +95,7 @@ float current_temperature_bed = 0.0;
 #endif
 
 #ifdef FANCHECK
-  volatile bool fan_check_error = false;
+  volatile uint8_t fan_check_error = EFCE_OK;
 #endif
 
 unsigned char soft_pwm_bed;
@@ -434,7 +434,7 @@ static void temp_runaway_stop(bool isPreheat, bool isBed);
 void updatePID()
 {
 #ifdef PIDTEMP
-  for(int e = 0; e < EXTRUDERS; e++) { 
+  for(uint_least8_t e = 0; e < EXTRUDERS; e++) {
      iState_sum_max[e] = PID_INTEGRAL_DRIVE_MAX / cs.Ki;  
   }
 #endif
@@ -512,6 +512,12 @@ void checkFanSpeed()
 	else fan_speed_errors[1] = 0;
 #endif
 
+	// drop the fan_check_error flag when both fans are ok
+	if( fan_speed_errors[0] == 0 && fan_speed_errors[1] == 0 && fan_check_error == EFCE_REPORTED){
+		// we may even send some info to the LCD from here
+		fan_check_error = EFCE_OK;
+	}
+
 	if ((fan_speed_errors[0] > max_extruder_fan_errors) && fans_check_enabled) {
 		fan_speed_errors[0] = 0;
 		fanSpeedError(0); //extruder fan
@@ -522,6 +528,23 @@ void checkFanSpeed()
 	}
 }
 
+//! Prints serialMsg to serial port, displays lcdMsg onto the LCD and beeps.
+//! Extracted from fanSpeedError to save some space.
+//! @param serialMsg pointer into PROGMEM, this text will be printed to the serial port
+//! @param lcdMsg pointer into PROGMEM, this text will be printed onto the LCD
+static void fanSpeedErrorBeep(const char *serialMsg, const char *lcdMsg){
+	SERIAL_ECHOLNRPGM(serialMsg);
+	if (get_message_level() == 0) {
+		if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)||(eSoundMode==e_SOUND_MODE_SILENT)){
+			WRITE(BEEPER, HIGH);
+			delayMicroseconds(200);
+			WRITE(BEEPER, LOW);
+			delayMicroseconds(100); // what is this wait for?
+		}
+		LCD_ALERTMESSAGERPGM(lcdMsg);
+	}
+}
+
 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 
@@ -530,7 +553,8 @@ void fanSpeedError(unsigned char _fan) {
 			lcd_print_stop();
 		}
 		else {
-			fan_check_error = true;
+			fan_check_error = EFCE_DETECTED;
+
 		}
 	}
 	else {
@@ -538,27 +562,11 @@ void fanSpeedError(unsigned char _fan) {
 			SERIAL_ECHOLNPGM("// action:pause"); //for octoprint
 	}
 	switch (_fan) {
-	case 0:
-			SERIAL_ECHOLNPGM("Extruder fan speed is lower then expected");
-			if (get_message_level() == 0) {
-if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)||(eSoundMode==e_SOUND_MODE_SILENT))
-				WRITE(BEEPER, HIGH);
-				delayMicroseconds(200);
-				WRITE(BEEPER, LOW);
-				delayMicroseconds(100);
-				LCD_ALERTMESSAGEPGM("Err: EXTR. FAN ERROR");
-			}
+	case 0:	// extracting the same code from case 0 and case 1 into a function saves 72B
+		fanSpeedErrorBeep(PSTR("Extruder fan speed is lower than expected"), PSTR("Err: EXTR. FAN ERROR") );
 		break;
 	case 1:
-			SERIAL_ECHOLNPGM("Print fan speed is lower then expected");
-			if (get_message_level() == 0) {
-if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)||(eSoundMode==e_SOUND_MODE_SILENT))
-				WRITE(BEEPER, HIGH);
-				delayMicroseconds(200);
-				WRITE(BEEPER, LOW);
-				delayMicroseconds(100);
-				LCD_ALERTMESSAGEPGM("Err: PRINT FAN ERROR");
-			}
+		fanSpeedErrorBeep(PSTR("Print fan speed is lower than expected"), PSTR("Err: PRINT FAN ERROR") );
 		break;
 	}
 }
@@ -1469,6 +1477,15 @@ void disable_heater()
     #endif
   #endif 
 }
+//! codes of alert messages for the LCD - it is shorter to compare an uin8_t
+//! than raw const char * of the messages themselves.
+//! Could be used for MAXTEMP situations too - after reaching MAXTEMP and turning off the heater automagically
+//! the heater/bed may cool down and a similar alert message like "MAXTERM fixed..." may be displayed.
+enum { LCDALERT_NONE = 0, LCDALERT_HEATERMINTEMP, LCDALERT_BEDMINTEMP, LCDALERT_MINTEMPFIXED, LCDALERT_PLEASERESTART };
+
+//! remember the last alert message sent to the LCD
+//! to prevent flicker and improve speed
+uint8_t last_alert_sent_to_lcd = LCDALERT_NONE;
 
 void max_temp_error(uint8_t e) {
   disable_heater();
@@ -1502,13 +1519,23 @@ void min_temp_error(uint8_t e) {
 #endif
 //if (current_temperature_ambient < MINTEMP_MINAMBIENT) return;
   disable_heater();
+	static const char err[] PROGMEM = "Err: MINTEMP";
   if(IsStopped() == false) {
     SERIAL_ERROR_START;
     SERIAL_ERRORLN((int)e);
     SERIAL_ERRORLNPGM(": Extruder switched off. MINTEMP triggered !");
-    LCD_ALERTMESSAGEPGM("Err: MINTEMP");
+    lcd_setalertstatuspgm(err);
+    last_alert_sent_to_lcd = LCDALERT_HEATERMINTEMP;
+  } else if( last_alert_sent_to_lcd != LCDALERT_HEATERMINTEMP ){ // only update, if the lcd message is to be changed (i.e. not the same as last time)
+	// we are already stopped due to some error, only update the status message without flickering
+	lcd_updatestatuspgm(err);
+	last_alert_sent_to_lcd = LCDALERT_HEATERMINTEMP;
   }
   #ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE
+//	if( last_alert_sent_to_lcd != LCDALERT_HEATERMINTEMP ){
+//		last_alert_sent_to_lcd = LCDALERT_HEATERMINTEMP;
+//		lcd_print_stop();
+//	}
   Stop();
   #endif
   if (farm_mode) { prusa_statistics(92); }
@@ -1538,10 +1565,16 @@ void bed_min_temp_error(void) {
 #if HEATER_BED_PIN > -1
     WRITE(HEATER_BED_PIN, 0);
 #endif
+	static const char err[] PROGMEM = "Err: MINTEMP BED";
     if(IsStopped() == false) {
         SERIAL_ERROR_START;
         SERIAL_ERRORLNPGM("Temperature heated bed switched off. MINTEMP triggered !");
-        LCD_ALERTMESSAGEPGM("Err: MINTEMP BED");
+		lcd_setalertstatuspgm(err);
+		last_alert_sent_to_lcd = LCDALERT_BEDMINTEMP;
+	} else if( last_alert_sent_to_lcd != LCDALERT_BEDMINTEMP ){ // only update, if the lcd message is to be changed (i.e. not the same as last time)
+		// we are already stopped due to some error, only update the status message without flickering
+		lcd_updatestatuspgm(err);
+		last_alert_sent_to_lcd = LCDALERT_BEDMINTEMP;
     }
 #ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE
     Stop();
@@ -2015,6 +2048,58 @@ void check_max_temp()
 #endif
 
 }
+//! number of repeating the same state with consecutive step() calls
+//! used to slow down text switching
+struct alert_automaton_mintemp {
+private:
+	enum { ALERT_AUTOMATON_SPEED_DIV = 5 };
+	enum class States : uint8_t { Init = 0, TempAboveMintemp, ShowPleaseRestart, ShowMintemp };
+	States state = States::Init;
+	uint8_t repeat = ALERT_AUTOMATON_SPEED_DIV;
+
+	void substep(States next_state){
+		if( repeat == 0 ){
+			state = next_state; // advance to the next state
+			repeat = ALERT_AUTOMATON_SPEED_DIV; // and prepare repeating for it too
+		} else {
+			--repeat;
+		}
+	}
+public:
+	//! brief state automaton step routine
+	//! @param current_temp current hotend/bed temperature (for computing simple hysteresis)
+	//! @param mintemp minimal temperature including hysteresis to check current_temp against
+	void step(float current_temp, float mintemp){
+		static const char m2[] PROGMEM = "MINTEMP fixed";
+		static const char m1[] PROGMEM = "Please restart";
+		switch(state){
+		case States::Init: // initial state - check hysteresis
+			if( current_temp > mintemp ){
+				state = States::TempAboveMintemp;
+			}
+			// otherwise keep the Err MINTEMP alert message on the display,
+			// i.e. do not transfer to state 1
+			break;
+		case States::TempAboveMintemp: // the temperature has risen above the hysteresis check
+			lcd_setalertstatuspgm(m2);
+			substep(States::ShowMintemp);
+			last_alert_sent_to_lcd = LCDALERT_MINTEMPFIXED;
+			break;
+		case States::ShowPleaseRestart: // displaying "Please restart"
+			lcd_updatestatuspgm(m1);
+			substep(States::ShowMintemp);
+			last_alert_sent_to_lcd = LCDALERT_PLEASERESTART;
+			break;
+		case States::ShowMintemp: // displaying "MINTEMP fixed"
+			lcd_updatestatuspgm(m2);
+			substep(States::ShowPleaseRestart);
+			last_alert_sent_to_lcd = LCDALERT_MINTEMPFIXED;
+			break;
+		}
+	}
+};
+
+static alert_automaton_mintemp alert_automaton_hotend, alert_automaton_bed;
 
 void check_min_temp_heater0()
 {
@@ -2024,7 +2109,17 @@ void check_min_temp_heater0()
 #else
 	if (current_temperature_raw[0] <= minttemp_raw[0]) {
 #endif
+		menu_set_serious_error(SERIOUS_ERR_MINTEMP_HEATER);
 		min_temp_error(0);
+	} else if( menu_is_serious_error(SERIOUS_ERR_MINTEMP_HEATER) ) {
+		// no recovery, just force the user to restart the printer
+		// which is a safer variant than just continuing printing
+		// The automaton also checks for hysteresis - the temperature must have reached a few degrees above the MINTEMP, before
+		// we shall signalize, that MINTEMP has been fixed
+		// Code notice: normally the alert_automaton instance would have been placed here 
+		// as static alert_automaton_mintemp alert_automaton_hotend, but
+		// due to stupid compiler that takes 16 more bytes.
+		alert_automaton_hotend.step(current_temperature[0], minttemp[0] + TEMP_HYSTERESIS);
 	}
 }
 
@@ -2035,7 +2130,12 @@ void check_min_temp_bed()
 #else
 	if (current_temperature_bed_raw <= bed_minttemp_raw) {
 #endif
+		menu_set_serious_error(SERIOUS_ERR_MINTEMP_BED);
 		bed_min_temp_error();
+	} else if( menu_is_serious_error(SERIOUS_ERR_MINTEMP_BED) ){
+		// no recovery, just force the user to restart the printer
+		// which is a safer variant than just continuing printing
+		alert_automaton_bed.step(current_temperature_bed, BED_MINTEMP + TEMP_HYSTERESIS);
 	}
 }
 

+ 6 - 1
Firmware/temperature.h

@@ -238,7 +238,12 @@ void checkExtruderAutoFans();
 
 #if (defined(FANCHECK) && defined(TACH_0) && (TACH_0 > -1))
 
-extern volatile bool fan_check_error;
+enum { 
+	EFCE_OK = 0,   //!< normal operation, both fans are ok
+	EFCE_DETECTED, //!< fan error detected, but not reported yet
+	EFCE_REPORTED  //!< fan error detected and reported to LCD and serial
+};
+extern volatile uint8_t fan_check_error;
 
 void countFanSpeed();
 void checkFanSpeed();

+ 5 - 5
Firmware/tmc2130.cpp

@@ -158,7 +158,7 @@ void tmc2130_init()
 	SET_INPUT(Y_TMC2130_DIAG);
 	SET_INPUT(Z_TMC2130_DIAG);
 	SET_INPUT(E0_TMC2130_DIAG);
-	for (int axis = 0; axis < 2; axis++) // X Y axes
+	for (uint_least8_t axis = 0; axis < 2; axis++) // X Y axes
 	{
 		tmc2130_setup_chopper(axis, tmc2130_mres[axis], tmc2130_current_h[axis], tmc2130_current_r[axis]);
 		tmc2130_wr(axis, TMC2130_REG_TPOWERDOWN, 0x00000000);
@@ -169,7 +169,7 @@ void tmc2130_init()
 		tmc2130_wr_TPWMTHRS(axis, TMC2130_TPWMTHRS);
 		//tmc2130_wr_THIGH(axis, TMC2130_THIGH);
 	}
-	for (int axis = 2; axis < 3; axis++) // Z axis
+	for (uint_least8_t axis = 2; axis < 3; axis++) // Z axis
 	{
 		tmc2130_setup_chopper(axis, tmc2130_mres[axis], tmc2130_current_h[axis], tmc2130_current_r[axis]);
 		tmc2130_wr(axis, TMC2130_REG_TPOWERDOWN, 0x00000000);
@@ -183,7 +183,7 @@ void tmc2130_init()
 		tmc2130_wr_TPWMTHRS(axis, TMC2130_TPWMTHRS);
 #endif //TMC2130_STEALTH_Z
 	}
-	for (int axis = 3; axis < 4; axis++) // E axis
+	for (uint_least8_t axis = 3; axis < 4; axis++) // E axis
 	{
 		tmc2130_setup_chopper(axis, tmc2130_mres[axis], tmc2130_current_h[axis], tmc2130_current_r[axis]);
 		tmc2130_wr(axis, TMC2130_REG_TPOWERDOWN, 0x00000000);
@@ -383,7 +383,7 @@ void tmc2130_check_overtemp()
 	static uint32_t checktime = 0;
 	if (_millis() - checktime > 1000 )
 	{
-		for (int i = 0; i < 4; i++)
+		for (uint_least8_t i = 0; i < 4; i++)
 		{
 			uint32_t drv_status = 0;
 			skip_debug_msg = true;
@@ -392,7 +392,7 @@ void tmc2130_check_overtemp()
 			{ // BIT 26 - over temp prewarning ~120C (+-20C)
 				SERIAL_ERRORRPGM(MSG_TMC_OVERTEMP);
 				SERIAL_ECHOLN(i);
-				for (int j = 0; j < 4; j++)
+				for (uint_least8_t j = 0; j < 4; j++)
 					tmc2130_wr(j, TMC2130_REG_CHOPCONF, 0x00010000);
 				kill(MSG_TMC_OVERTEMP);
 			}

+ 513 - 564
Firmware/ultralcd.cpp

@@ -40,6 +40,7 @@
 
 #include "static_assert.h"
 #include "io_atmega2560.h"
+#include "first_lay_cal.h"
 
 
 int scrollstuff = 0;
@@ -73,10 +74,10 @@ extern void crashdet_disable();
 bool presort_flag = false;
 #endif
 
-int lcd_commands_type = LCD_COMMAND_IDLE;
-int lcd_commands_step = 0;
+LcdCommands lcd_commands_type = LcdCommands::Idle;
+static uint8_t lcd_commands_step = 0;
 
-unsigned int custom_message_type = CUSTOM_MSG_TYPE_STATUS;
+CustomMsg custom_message_type = CustomMsg::Status;
 unsigned int custom_message_state = 0;
 
 
@@ -84,7 +85,7 @@ bool isPrintPaused = false;
 uint8_t farm_mode = 0;
 int farm_no = 0;
 int farm_timer = 8;
-int farm_status = 0;
+uint8_t farm_status = 0;
 bool printer_connected = true;
 
 unsigned long display_time; //just timer for showing pid finished message on lcd;
@@ -130,6 +131,7 @@ 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_diameter();
 static void prusa_stat_temperatures();
 static void prusa_stat_printinfo();
 static void lcd_farm_no();
@@ -165,42 +167,42 @@ static bool lcd_selfcheck_pulleys(int axis);
 #endif //TMC2130
 
 static bool lcd_selfcheck_check_heater(bool _isbed);
-enum class testScreen : uint_least8_t
-{
-    extruderFan,
-    printFan,
-    fansOk,
-    endStops,
-    axisX,
-    axisY,
-    axisZ,
-    bed,
-    hotend,
-    hotendOk,
-    fsensor,
-    fsensorOk,
-    allCorrect,
-    failed,
-    home,
+enum class TestScreen : uint_least8_t
+{
+    ExtruderFan,
+    PrintFan,
+    FansOk,
+    EndStops,
+    AxisX,
+    AxisY,
+    AxisZ,
+    Bed,
+    Hotend,
+    HotendOk,
+    Fsensor,
+    FsensorOk,
+    AllCorrect,
+    Failed,
+    Home,
 };
 
 enum class TestError : uint_least8_t
 {
-    heater,
-    bed,
-    endstops,
-    motor,
-    endstop,
-    printFan,
-    extruderFan,
-    pulley,
-    axis,
-    swappedFan,
-    wiringFsensor,
-    triggeringFsensor,
+    Heater,
+    Bed,
+    Endstops,
+    Motor,
+    Endstop,
+    PrintFan,
+    ExtruderFan,
+    Pulley,
+    Axis,
+    SwappedFan,
+    WiringFsensor,
+    TriggeringFsensor,
 };
 
-static int  lcd_selftest_screen(testScreen screen, int _progress, int _progress_scale, bool _clear, int _delay);
+static int  lcd_selftest_screen(TestScreen screen, int _progress, int _progress_scale, bool _clear, int _delay);
 static void lcd_selftest_screen_step(int _row, int _col, int _state, const char *_name, const char *_indicator);
 static bool lcd_selftest_manual_fan_check(int _fan, bool check_opposite,
 	bool _default=false);
@@ -209,10 +211,10 @@ static bool lcd_selftest_manual_fan_check(int _fan, bool check_opposite,
 /** Enumerate for lcd_selftest_fan_auto function.
  */
 enum class FanCheck : uint_least8_t {
-    success,
-    printFan = TestError::printFan,
-    extruderFan = TestError::extruderFan,
-    swappedFan = TestError::swappedFan,
+    Success,
+    PrintFan,
+    ExtruderFan,
+    SwappedFan,
 };
 
 /**
@@ -245,13 +247,13 @@ static char snmm_stop_print_menu();
 #ifdef SDCARD_SORT_ALPHA
  static void lcd_sort_type_set();
 #endif
-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
 
+//! Beware: has side effects - forces lcd_draw_update to 2, which means clear the display
 void lcd_finishstatus();
 
 static void lcd_sdcard_menu();
@@ -316,7 +318,7 @@ static void lcd_implementation_drawmenu_sdfile_selected(uint8_t row, char* longF
     char c;
     int enc_dif = lcd_encoder_diff;
     uint8_t n = LCD_WIDTH - 1;
-    for(int g = 0; g<4;g++){
+    for(uint_least8_t g = 0; g<4;g++){
       lcd_set_cursor(0, g);
     lcd_print(' ');
     }
@@ -564,7 +566,7 @@ void lcdui_print_temp(char type, int val_current, int val_target)
 // Print Z-coordinate (8 chars total)
 void lcdui_print_Z_coord(void)
 {
-    if (custom_message_type == CUSTOM_MSG_TYPE_MESHBL)
+    if (custom_message_type == CustomMsg::MeshBedLeveling)
         lcd_puts_P(_N("Z   --- "));
     else
 		lcd_printf_P(_N("Z%6.2f "), current_position[Z_AXIS]);
@@ -759,7 +761,7 @@ void lcdui_print_status_line(void)
 			break;
 		}
 	}
-	else if ((IS_SD_PRINTING) && (custom_message_type == CUSTOM_MSG_TYPE_STATUS))
+	else if ((IS_SD_PRINTING) && (custom_message_type == CustomMsg::Status))
 	{ // If printing from SD, show what we are printing
 		if(strlen(card.longFilename) > LCD_WIDTH)
 		{
@@ -793,10 +795,10 @@ void lcdui_print_status_line(void)
 	{ // Otherwise check for other special events
    		switch (custom_message_type)
 		{
-		case CUSTOM_MSG_TYPE_STATUS: // Nothing special, print status message normally
+		case CustomMsg::Status: // Nothing special, print status message normally
 			lcd_print(lcd_status_message);
 			break;
-		case CUSTOM_MSG_TYPE_MESHBL: // If mesh bed leveling in progress, show the status
+		case CustomMsg::MeshBedLeveling: // If mesh bed leveling in progress, show the status
 			if (custom_message_state > 10)
 			{
 				lcd_set_cursor(0, 3);
@@ -812,7 +814,7 @@ void lcdui_print_status_line(void)
 				{
 					lcd_puts_P(_T(WELCOME_MSG));
 					lcd_setstatuspgm(_T(WELCOME_MSG));
-					custom_message_type = CUSTOM_MSG_TYPE_STATUS;
+					custom_message_type = CustomMsg::Status;
 				}
 				if (custom_message_state > 3 && custom_message_state <= 10 )
 				{
@@ -824,10 +826,10 @@ void lcdui_print_status_line(void)
 				}
 			}
 			break;
-		case CUSTOM_MSG_TYPE_F_LOAD: // If loading filament, print status
+		case CustomMsg::FilamentLoading: // If loading filament, print status
 			lcd_print(lcd_status_message);
 			break;
-		case CUSTOM_MSG_TYPE_PIDCAL: // PID tuning in progress
+		case CustomMsg::PidCal: // PID tuning in progress
 			lcd_print(lcd_status_message);
 			if (pid_cycle <= pid_number_of_cycles && custom_message_state > 0)
 			{
@@ -837,7 +839,7 @@ void lcdui_print_status_line(void)
 				lcd_print(itostr3left(pid_number_of_cycles));
 			}
 			break;
-		case CUSTOM_MSG_TYPE_TEMCAL: // PINDA temp calibration in progress
+		case CustomMsg::TempCal: // PINDA temp calibration in progress
 			{
 				char progress[4];
 				lcd_set_cursor(0, 3);
@@ -847,7 +849,7 @@ void lcdui_print_status_line(void)
 				lcd_print(progress);
 			}
 			break;
-		case CUSTOM_MSG_TYPE_TEMPRE: // temp compensation preheat
+		case CustomMsg::TempCompPreheat: // temp compensation preheat
 			lcd_set_cursor(0, 3);
 			lcd_puts_P(_i("PINDA Heating"));////MSG_PINDA_PREHEAT c=20 r=1
 			if (custom_message_state <= PINDA_HEAT_T)
@@ -995,7 +997,7 @@ static void lcd_status_screen()
 		} // end of farm_mode
 
 		lcd_status_update_delay = 10;   /* redraw the main screen every second. This is easier then trying keep track of all things that change on the screen */
-		if (lcd_commands_type != LCD_COMMAND_IDLE)
+		if (lcd_commands_type != LcdCommands::Idle)
 			lcd_commands();
 	} // end of lcd_draw_update
 
@@ -1018,7 +1020,10 @@ static void lcd_status_screen()
 		}
 	}
 
-	if (current_click && (lcd_commands_type != LCD_COMMAND_STOP_PRINT)) //click is aborted unless stop print finishes
+	if (current_click
+		&& (lcd_commands_type != LcdCommands::StopPrint) //click is aborted unless stop print finishes
+		&& ( menu_block_entering_on_serious_errors == SERIOUS_ERR_NONE ) // or a serious error blocks entering the menu
+	)
 	{
 		menu_depth = 0; //redundant, as already done in lcd_return_to_status(), just to be sure
 		menu_submenu(lcd_main_menu);
@@ -1056,18 +1061,17 @@ static void lcd_status_screen()
 		feedmultiply = 999;
 }
 
-
 void lcd_commands()
 {	
-	if (lcd_commands_type == LCD_COMMAND_LONG_PAUSE)
+	if (lcd_commands_type == LcdCommands::LongPause)
 	{
 		if (!blocks_queued() && !homing_flag)
 		{
 			lcd_setstatuspgm(_i("Print paused"));////MSG_PRINT_PAUSED c=20 r=1
 			long_pause();
-               if (lcd_commands_type == LCD_COMMAND_LONG_PAUSE) // !!! because "lcd_commands_type" can be changed during/inside "long_pause()"
+               if (lcd_commands_type == LcdCommands::LongPause) // !!! because "lcd_commands_type" can be changed during/inside "long_pause()"
                {
-                    lcd_commands_type = 0;
+                    lcd_commands_type = LcdCommands::Idle;
                     lcd_commands_step = 0;
                }
 		}
@@ -1075,7 +1079,7 @@ void lcd_commands()
 
 
 #ifdef SNMM
-	if (lcd_commands_type == LCD_COMMAND_V2_CAL)
+	if (lcd_commands_type == LcdCommands::Layer1Cal)
 	{
 		char cmd1[30];
 		float width = 0.4;
@@ -1340,300 +1344,115 @@ void lcd_commands()
 
 #else //if not SNMM
 
-	if (lcd_commands_type == LCD_COMMAND_V2_CAL)
+	if (lcd_commands_type == LcdCommands::Layer1Cal)
 	{
 		char cmd1[30];
 		static 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 && !blocks_queued() && cmd_buffer_empty())
-		{
-			lcd_commands_step = 10;
-		}
-		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)));
-			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));
-			enquecommand_P(PSTR("G28"));
-			enquecommand_P(PSTR("G92 E0.0"));
+		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
 
-            lcd_commands_step = 9;
-		}
-        if (lcd_commands_step == 9 && !blocks_queued() && cmd_buffer_empty())
+        if (!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
-                strcpy(cmd1, "T");
-                strcat(cmd1, itostr3left(filament));
-                enquecommand(cmd1);
-                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
+            switch(lcd_commands_step)
             {
-                enquecommand_P(PSTR("G1 X60.0 E9.0 F1000.0")); //intro line
-                enquecommand_P(PSTR("G1 X100.0 E12.5 F1000.0")); //intro line
+            case 0:
+                lcd_commands_step = 10;
+                break;
+            case 20:
+                filament = 0;
+                lcd_commands_step = 10;
+                break;
+            case 21:
+                filament = 1;
+                lcd_commands_step = 10;
+                break;
+            case 22:
+                filament = 2;
+                lcd_commands_step = 10;
+                break;
+            case 23:
+                filament = 3;
+                lcd_commands_step = 10;
+                break;
+            case 24:
+                filament = 4;
+                lcd_commands_step = 10;
+                break;
+            case 10:
+                lay1cal_preheat();
+                lcd_commands_step = 9;
+                break;
+            case 9:
+                lcd_clear();
+                menu_depth = 0;
+                menu_submenu(lcd_babystep_z);
+                lay1cal_intro_line(cmd1, filament);
+                lcd_commands_step = 8;
+                break;
+            case 8:
+                lay1cal_before_meander();
+                lcd_commands_step = 7;
+                break;
+            case 7:
+                lay1cal_meander(cmd1);
+                lcd_commands_step = 6;
+                break;
+            case 6:
+                for (uint8_t i = 0; i < 4; i++)
+                {
+                    lay1cal_square(cmd1, i);
+                }
+                lcd_commands_step = 5;
+                break;
+            case 5:
+                for (uint8_t i = 4; i < 8; i++)
+                {
+                    lay1cal_square(cmd1, i);
+                }
+                lcd_commands_step = 4;
+                break;
+            case 4:
+                for (uint8_t i = 8; i < 12; i++)
+                {
+                    lay1cal_square(cmd1, i);
+                }
+                lcd_commands_step = 3;
+                break;
+            case 3:
+                for (uint8_t i = 12; i < 16; i++)
+                {
+                    lay1cal_square(cmd1, i);
+                }
+                lcd_commands_step = 2;
+                break;
+            case 2:
+                enquecommand_P(PSTR("M107")); //turn off printer fan
+                enquecommand_P(PSTR("G1 E-0.07500 F2100.00000")); //retract
+                enquecommand_P(PSTR("M104 S0")); // turn off temperature
+                enquecommand_P(PSTR("M140 S0")); // turn off heatbed
+                enquecommand_P(PSTR("G1 Z10 F1300.000")); //lift Z
+                enquecommand_P(PSTR("G1 X10 Y180 F4000")); //Go to parking position
+                if (mmu_enabled) enquecommand_P(PSTR("M702 C")); //unload from nozzle
+                enquecommand_P(PSTR("M84"));// disable motors
+                forceMenuExpire = true; //if user dont confirm live adjust Z value by pressing the knob, we are saving last value by timeout to status screen
+                lcd_commands_step = 1;
+                break;
+            case 1:
+                lcd_setstatuspgm(_T(WELCOME_MSG));
+                lcd_commands_step = 0;
+                lcd_commands_type = LcdCommands::Idle;
+                if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE) == 1)
+                {
+                    lcd_wizard(WizState::RepeatLay1Cal);
+                }
+                break;
             }
-
-            lcd_commands_step = 8;
         }
-		if (lcd_commands_step == 8 && !blocks_queued() && cmd_buffer_empty())
-		{
-
-			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 Z5 F7200.000"));
-			enquecommand_P(PSTR("M204 S1000")); //set acceleration
-			enquecommand_P(PSTR("G1 F4000"));
-			lcd_commands_step = 7;
-		}
-		if (lcd_commands_step == 7 && !blocks_queued() && cmd_buffer_empty()) //draw meander
-		{
-			lcd_timeoutToStatus.start();
-
-
-			//just opposite direction
-			/*enquecommand_P(PSTR("G1 X50 Y55"));
-			enquecommand_P(PSTR("G1 F1080"));
-			enquecommand_P(PSTR("G1 X200 Y55 E3.62773"));
-			enquecommand_P(PSTR("G1 X200 Y75 E0.49386"));
-			enquecommand_P(PSTR("G1 X50 Y75 E3.62773"));
-			enquecommand_P(PSTR("G1 X50 Y95 E0.49386"));
-			enquecommand_P(PSTR("G1 X200 Y95 E3.62773"));
-			enquecommand_P(PSTR("G1 X200 Y115 E0.49386"));
-			enquecommand_P(PSTR("G1 X50 Y115 E3.62773"));
-			enquecommand_P(PSTR("G1 X50 Y135 E0.49386"));
-			enquecommand_P(PSTR("G1 X200 Y135 E3.62773"));
-			enquecommand_P(PSTR("G1 X200 Y155 E0.66174"));
-			enquecommand_P(PSTR("G1 X100 Y155 E2.62773"));
-			enquecommand_P(PSTR("G1 X75 Y155 E2"));
-			enquecommand_P(PSTR("G1 X50 Y155 E2.5"));
-			enquecommand_P(PSTR("G1 E - 0.07500 F2100.00000"));*/
-
-
-			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"));
-			enquecommand_P(PSTR("G1 X200 Y155 E2.62773"));
-			enquecommand_P(PSTR("G1 X200 Y135 E0.66174"));
-			enquecommand_P(PSTR("G1 X50 Y135 E3.62773"));
-			enquecommand_P(PSTR("G1 X50 Y115 E0.49386"));
-			enquecommand_P(PSTR("G1 X200 Y115 E3.62773"));
-			enquecommand_P(PSTR("G1 X200 Y95 E0.49386"));
-			enquecommand_P(PSTR("G1 X50 Y95 E3.62773"));
-			enquecommand_P(PSTR("G1 X50 Y75 E0.49386"));
-			enquecommand_P(PSTR("G1 X200 Y75 E3.62773"));
-			enquecommand_P(PSTR("G1 X200 Y55 E0.49386"));
-			enquecommand_P(PSTR("G1 X50 Y55 E3.62773"));
-
-			strcpy(cmd1, "G1 X50 Y35 E");
-			strcat(cmd1, ftostr43(extr));
-			enquecommand(cmd1);
-
-			lcd_commands_step = 6;
-		}
-
-		if (lcd_commands_step == 6 && !blocks_queued() && cmd_buffer_empty())
-		{
-
-			lcd_timeoutToStatus.start();
-
-			for (int i = 0; i < 4; i++) {
-				strcpy(cmd1, "G1 X70 Y");
-				strcat(cmd1, ftostr32(35 - i*width * 2));
-				strcat(cmd1, " E");
-				strcat(cmd1, ftostr43(extr));
-				enquecommand(cmd1);
-				strcpy(cmd1, "G1 Y");
-				strcat(cmd1, ftostr32(35 - (2 * i + 1)*width));
-				strcat(cmd1, " E");
-				strcat(cmd1, ftostr43(extr_short_segment));
-				enquecommand(cmd1);
-				strcpy(cmd1, "G1 X50 Y");
-				strcat(cmd1, ftostr32(35 - (2 * i + 1)*width));
-				strcat(cmd1, " E");
-				strcat(cmd1, ftostr43(extr));
-				enquecommand(cmd1);
-				strcpy(cmd1, "G1 Y");
-				strcat(cmd1, ftostr32(35 - (i + 1)*width * 2));
-				strcat(cmd1, " E");
-				strcat(cmd1, ftostr43(extr_short_segment));
-				enquecommand(cmd1);
-			}
-
-			lcd_commands_step = 5;
-		}
-
-		if (lcd_commands_step == 5 && !blocks_queued() && cmd_buffer_empty())
-		{
-			lcd_timeoutToStatus.start();
-			for (int i = 4; i < 8; i++) {
-				strcpy(cmd1, "G1 X70 Y");
-				strcat(cmd1, ftostr32(35 - i*width * 2));
-				strcat(cmd1, " E");
-				strcat(cmd1, ftostr43(extr));
-				enquecommand(cmd1);
-				strcpy(cmd1, "G1 Y");
-				strcat(cmd1, ftostr32(35 - (2 * i + 1)*width));
-				strcat(cmd1, " E");
-				strcat(cmd1, ftostr43(extr_short_segment));
-				enquecommand(cmd1);
-				strcpy(cmd1, "G1 X50 Y");
-				strcat(cmd1, ftostr32(35 - (2 * i + 1)*width));
-				strcat(cmd1, " E");
-				strcat(cmd1, ftostr43(extr));
-				enquecommand(cmd1);
-				strcpy(cmd1, "G1 Y");
-				strcat(cmd1, ftostr32(35 - (i + 1)*width * 2));
-				strcat(cmd1, " E");
-				strcat(cmd1, ftostr43(extr_short_segment));
-				enquecommand(cmd1);
-			}
-
-			lcd_commands_step = 4;
-		}
-
-		if (lcd_commands_step == 4 && !blocks_queued() && cmd_buffer_empty())
-		{
-			lcd_timeoutToStatus.start();
-			for (int i = 8; i < 12; i++) {
-				strcpy(cmd1, "G1 X70 Y");
-				strcat(cmd1, ftostr32(35 - i*width * 2));
-				strcat(cmd1, " E");
-				strcat(cmd1, ftostr43(extr));
-				enquecommand(cmd1);
-				strcpy(cmd1, "G1 Y");
-				strcat(cmd1, ftostr32(35 - (2 * i + 1)*width));
-				strcat(cmd1, " E");
-				strcat(cmd1, ftostr43(extr_short_segment));
-				enquecommand(cmd1);
-				strcpy(cmd1, "G1 X50 Y");
-				strcat(cmd1, ftostr32(35 - (2 * i + 1)*width));
-				strcat(cmd1, " E");
-				strcat(cmd1, ftostr43(extr));
-				enquecommand(cmd1);
-				strcpy(cmd1, "G1 Y");
-				strcat(cmd1, ftostr32(35 - (i + 1)*width * 2));
-				strcat(cmd1, " E");
-				strcat(cmd1, ftostr43(extr_short_segment));
-				enquecommand(cmd1);
-			}
-
-			lcd_commands_step = 3;
-		}
-
-		if (lcd_commands_step == 3 && !blocks_queued() && cmd_buffer_empty())
-		{
-			lcd_timeoutToStatus.start();
-			for (int i = 12; i < 16; i++) {
-				strcpy(cmd1, "G1 X70 Y");
-				strcat(cmd1, ftostr32(35 - i*width * 2));
-				strcat(cmd1, " E");
-				strcat(cmd1, ftostr43(extr));
-				enquecommand(cmd1);
-				strcpy(cmd1, "G1 Y");
-				strcat(cmd1, ftostr32(35 - (2 * i + 1)*width));
-				strcat(cmd1, " E");
-				strcat(cmd1, ftostr43(extr_short_segment));
-				enquecommand(cmd1);
-				strcpy(cmd1, "G1 X50 Y");
-				strcat(cmd1, ftostr32(35 - (2 * i + 1)*width));
-				strcat(cmd1, " E");
-				strcat(cmd1, ftostr43(extr));
-				enquecommand(cmd1);
-				strcpy(cmd1, "G1 Y");
-				strcat(cmd1, ftostr32(35 - (i + 1)*width * 2));
-				strcat(cmd1, " E");
-				strcat(cmd1, ftostr43(extr_short_segment));
-				enquecommand(cmd1);
-			}
-
-			lcd_commands_step = 2;
-		}
-
-		if (lcd_commands_step == 2 && !blocks_queued() && cmd_buffer_empty())
-		{
-			lcd_timeoutToStatus.start();
-			enquecommand_P(PSTR("M107")); //turn off printer fan			
-			enquecommand_P(PSTR("G1 E-0.07500 F2100.00000")); //retract
-			enquecommand_P(PSTR("M104 S0")); // turn off temperature
-			enquecommand_P(PSTR("M140 S0")); // turn off heatbed
-			enquecommand_P(PSTR("G1 Z10 F1300.000")); //lift Z
-			enquecommand_P(PSTR("G1 X10 Y180 F4000")); //Go to parking position
-			if (mmu_enabled) enquecommand_P(PSTR("M702 C")); //unload from nozzle
-			enquecommand_P(PSTR("M84"));// disable motors
-			forceMenuExpire = true; //if user dont confirm live adjust Z value by pressing the knob, we are saving last value by timeout to status screen
-			lcd_commands_step = 1;
-		}
-		if (lcd_commands_step == 1 && !blocks_queued() && cmd_buffer_empty())
-		{
-			lcd_setstatuspgm(_T(WELCOME_MSG));
-			lcd_commands_step = 0;
-			lcd_commands_type = 0;			
-			if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE) == 1) {
-				lcd_wizard(WizState::RepeatLay1Cal);
-			}
-		}
-
 	}
 
 #endif // not SNMM
 
-	if (lcd_commands_type == LCD_COMMAND_STOP_PRINT)   /// stop print
+	if (lcd_commands_type == LcdCommands::StopPrint)   /// stop print
 	{
 		
 
@@ -1645,9 +1464,9 @@ void lcd_commands()
 		if (lcd_commands_step == 1 && !blocks_queued())
 		{
 			lcd_commands_step = 0;
-			lcd_commands_type = 0;
+			lcd_commands_type = LcdCommands::Idle;
 			lcd_setstatuspgm(_T(WELCOME_MSG));
-			custom_message_type = CUSTOM_MSG_TYPE_STATUS;
+			custom_message_type = CustomMsg::Status;
 			isPrintPaused = false;
 		}
 		if (lcd_commands_step == 2 && !blocks_queued())
@@ -1703,7 +1522,7 @@ void lcd_commands()
 			if (mmu_enabled)
 				setAllTargetHotends(0);
 			manage_heater();
-			custom_message_type = CUSTOM_MSG_TYPE_F_LOAD;
+			custom_message_type = CustomMsg::FilamentLoading;
 			lcd_commands_step = 5;
 		}
 		if (lcd_commands_step == 7 && !blocks_queued())
@@ -1725,12 +1544,7 @@ void lcd_commands()
 		}
 	}
 
-	if (lcd_commands_type == 3)
-	{
-		lcd_commands_type = 0;
-	}
-
-	if (lcd_commands_type == LCD_COMMAND_FARM_MODE_CONFIRM)   /// farm mode confirm
+	if (lcd_commands_type == LcdCommands::FarmModeConfirm)   /// farm mode confirm
 	{
 
 		if (lcd_commands_step == 0) { lcd_commands_step = 6; }
@@ -1739,7 +1553,7 @@ void lcd_commands()
 		{
 			lcd_confirm_print();
 			lcd_commands_step = 0;
-			lcd_commands_type = 0;
+			lcd_commands_type = LcdCommands::Idle;
 		}
 		if (lcd_commands_step == 2 && !blocks_queued())
 		{
@@ -1772,11 +1586,11 @@ void lcd_commands()
 		}
 
 	}
-	if (lcd_commands_type == LCD_COMMAND_PID_EXTRUDER) {
+	if (lcd_commands_type == LcdCommands::PidExtruder) {
 		char cmd1[30];
 		
 		if (lcd_commands_step == 0) {
-			custom_message_type = CUSTOM_MSG_TYPE_PIDCAL;
+			custom_message_type = CustomMsg::PidCal;
 			custom_message_state = 1;
 			lcd_draw_update = 3;
 			lcd_commands_step = 3;
@@ -1812,28 +1626,22 @@ void lcd_commands()
 		}
 		if ((lcd_commands_step == 1) && ((_millis()- display_time)>2000)) { //calibration finished message
 			lcd_setstatuspgm(_T(WELCOME_MSG));
-			custom_message_type = CUSTOM_MSG_TYPE_STATUS;
+			custom_message_type = CustomMsg::Status;
 			pid_temp = DEFAULT_PID_TEMP;
 			lcd_commands_step = 0;
-			lcd_commands_type = 0;
+			lcd_commands_type = LcdCommands::Idle;
 		}
 	}
 
 
 }
 
-static float count_e(float layer_heigth, float extrusion_width, float extrusion_length) {
-	//returns filament length in mm which needs to be extrude to form line with extrusion_length * extrusion_width * layer heigth dimensions
-	float extr = extrusion_length * layer_heigth * extrusion_width / (M_PI * pow(1.75, 2) / 4);
-	return extr;
-}
-
 void lcd_return_to_status()
 {
 	lcd_refresh(); // to maybe revive the LCD if static electricity killed it.
 	menu_goto(lcd_status_screen, 0, false, true);
 	menu_depth = 0;
-     eFilamentAction=e_FILAMENT_ACTION_none; // i.e. non-autoLoad
+     eFilamentAction=FilamentAction::None; // i.e. non-autoLoad
 }
 
 //! @brief Pause print, disable nozzle heater, move to park position
@@ -1843,9 +1651,9 @@ void lcd_pause_print()
     stop_and_save_print_to_ram(0.0,0.0);
     setAllTargetHotends(0);
     isPrintPaused = true;
-    if (LCD_COMMAND_IDLE == lcd_commands_type)
+    if (LcdCommands::Idle == lcd_commands_type)
     {
-        lcd_commands_type = LCD_COMMAND_LONG_PAUSE;
+        lcd_commands_type = LcdCommands::LongPause;
     }
 }
 
@@ -1986,7 +1794,7 @@ void lcd_menu_extruder_info()                     // NOT static due to using ins
 			lcd_puts_P(_N("Filament sensor\n" "is disabled."));
 		else
 		{
-			if (!moves_planned() && !IS_SD_PRINTING && !is_usb_printing && (lcd_commands_type != LCD_COMMAND_V2_CAL))
+			if (!moves_planned() && !IS_SD_PRINTING && !is_usb_printing && (lcd_commands_type != LcdCommands::Layer1Cal))
 				pat9125_update();
 			lcd_printf_P(_N(
 				"Fil. Xd:%3d Yd:%3d\n"
@@ -2211,7 +2019,6 @@ static void lcd_preheat_menu()
 	  MENU_ITEM_FUNCTION_P(PSTR("farm   -  " STRINGIFY(FARM_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(FARM_PREHEAT_HPB_TEMP)), lcd_preheat_farm);
 	  MENU_ITEM_FUNCTION_P(PSTR("nozzle -  " STRINGIFY(FARM_PREHEAT_HOTEND_TEMP) "/0"), lcd_preheat_farm_nozzle);
 	  MENU_ITEM_FUNCTION_P(_T(MSG_COOLDOWN), lcd_cooldown);
-	  MENU_ITEM_FUNCTION_P(PSTR("ABS    -  " STRINGIFY(ABS_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(ABS_PREHEAT_HPB_TEMP)), lcd_preheat_abs);
   } else {
 	  MENU_ITEM_FUNCTION_P(PSTR("PLA  -  " STRINGIFY(PLA_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(PLA_PREHEAT_HPB_TEMP)), lcd_preheat_pla);
 	  MENU_ITEM_FUNCTION_P(PSTR("PET  -  " STRINGIFY(PET_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(PET_PREHEAT_HPB_TEMP)), lcd_preheat_pet);
@@ -2342,13 +2149,22 @@ void lcd_set_fan_check() {
 #ifdef MMU_HAS_CUTTER
 void lcd_cutter_enabled()
 {
-    if (1 == eeprom_read_byte((uint8_t*)EEPROM_MMU_CUTTER_ENABLED))
+    if (EEPROM_MMU_CUTTER_ENABLED_enabled == eeprom_read_byte((uint8_t*)EEPROM_MMU_CUTTER_ENABLED))
     {
+#ifndef MMU_ALWAYS_CUT
         eeprom_update_byte((uint8_t*)EEPROM_MMU_CUTTER_ENABLED, 0);
     }
+#else //MMU_ALWAYS_CUT
+        eeprom_update_byte((uint8_t*)EEPROM_MMU_CUTTER_ENABLED, EEPROM_MMU_CUTTER_ENABLED_always);
+    }
+    else if (EEPROM_MMU_CUTTER_ENABLED_always == eeprom_read_byte((uint8_t*)EEPROM_MMU_CUTTER_ENABLED))
+    {
+        eeprom_update_byte((uint8_t*)EEPROM_MMU_CUTTER_ENABLED, 0);
+    }
+#endif //MMU_ALWAYS_CUT
     else
     {
-        eeprom_update_byte((uint8_t*)EEPROM_MMU_CUTTER_ENABLED, 1);
+        eeprom_update_byte((uint8_t*)EEPROM_MMU_CUTTER_ENABLED, EEPROM_MMU_CUTTER_ENABLED_enabled);
     }
 }
 #endif //MMU_HAS_CUTTER
@@ -2363,7 +2179,7 @@ void lcd_set_filament_oq_meass()
 }
 
 
-eFILAMENT_ACTION eFilamentAction=e_FILAMENT_ACTION_none; // must be initialized as 'non-autoLoad'
+FilamentAction eFilamentAction=FilamentAction::None; // must be initialized as 'non-autoLoad'
 bool bFilamentFirstRun;
 bool bFilamentPreheatState;
 bool bFilamentAction=false;
@@ -2380,18 +2196,18 @@ lcd_puts_P(_i("Press the knob"));                 ////MSG_ c=20 r=1
 lcd_set_cursor(0,3);
 switch(eFilamentAction)
      {
-     case e_FILAMENT_ACTION_Load:
-     case e_FILAMENT_ACTION_autoLoad:
-     case e_FILAMENT_ACTION_mmuLoad:
+     case FilamentAction::Load:
+     case FilamentAction::AutoLoad:
+     case FilamentAction::MmuLoad:
           lcd_puts_P(_i("to load filament"));     ////MSG_ c=20 r=1
           break;
-     case e_FILAMENT_ACTION_unLoad:
-     case e_FILAMENT_ACTION_mmuUnLoad:
+     case FilamentAction::UnLoad:
+     case FilamentAction::MmuUnLoad:
           lcd_puts_P(_i("to unload filament"));   ////MSG_ c=20 r=1
           break;
-     case e_FILAMENT_ACTION_mmuEject:
-     case e_FILAMENT_ACTION_mmuCut:
-     case e_FILAMENT_ACTION_none:
+     case FilamentAction::MmuEject:
+     case FilamentAction::MmuCut:
+     case FilamentAction::None:
           break;
      }
 if(lcd_clicked())
@@ -2405,21 +2221,21 @@ if(lcd_clicked())
      menu_back(nLevel);
      switch(eFilamentAction)
           {
-          case e_FILAMENT_ACTION_autoLoad:
-               eFilamentAction=e_FILAMENT_ACTION_none; // i.e. non-autoLoad
+          case FilamentAction::AutoLoad:
+               eFilamentAction=FilamentAction::None; // i.e. non-autoLoad
                // no break
-          case e_FILAMENT_ACTION_Load:
+          case FilamentAction::Load:
                loading_flag=true;
                enquecommand_P(PSTR("M701"));      // load filament
                break;
-          case e_FILAMENT_ACTION_unLoad:
+          case FilamentAction::UnLoad:
                enquecommand_P(PSTR("M702"));      // unload filament
                break;
-          case e_FILAMENT_ACTION_mmuLoad:
-          case e_FILAMENT_ACTION_mmuUnLoad:
-          case e_FILAMENT_ACTION_mmuEject:
-          case e_FILAMENT_ACTION_mmuCut:
-          case e_FILAMENT_ACTION_none:
+          case FilamentAction::MmuLoad:
+          case FilamentAction::MmuUnLoad:
+          case FilamentAction::MmuEject:
+          case FilamentAction::MmuCut:
+          case FilamentAction::None:
                break;
           }
      }
@@ -2443,19 +2259,19 @@ lcdui_print_temp(LCD_STR_THERMOMETER[0],(int)degHotend(0),(int)degTargetHotend(0
 lcd_set_cursor(0,1);
 switch(eFilamentAction)
      {
-     case e_FILAMENT_ACTION_Load:
-     case e_FILAMENT_ACTION_autoLoad:
-     case e_FILAMENT_ACTION_mmuLoad:
+     case eFILAMENT_ACTION::load:
+     case eFILAMENT_ACTION::autoLoad:
+     case eFILAMENT_ACTION::mmuLoad:
           lcd_puts_P(_i("Preheating to load"));   ////MSG_ c=20 r=1
           break;
-     case e_FILAMENT_ACTION_unLoad:
-     case e_FILAMENT_ACTION_mmuUnLoad:
+     case eFILAMENT_ACTION::unLoad:
+     case eFILAMENT_ACTION::mmuUnLoad:
           lcd_puts_P(_i("Preheating to unload")); ////MSG_ c=20 r=1
           break;
-     case e_FILAMENT_ACTION_mmuEject:
+     case eFILAMENT_ACTION::mmuEject:
           lcd_puts_P(_i("Preheating to eject"));  ////MSG_ c=20 r=1
           break;
-     case e_FILAMENT_ACTION_mmuCut:
+     case eFILAMENT_ACTION::mmuCut:
           lcd_puts_P(_i("Preheating to cut"));  ////MSG_ c=20 r=1
           break;
      }
@@ -2474,20 +2290,20 @@ if(lcd_clicked())
           setTargetBed((float)nTargetBedOld);
           }
      menu_back();
-     if(eFilamentAction==e_FILAMENT_ACTION_autoLoad)
-          eFilamentAction=e_FILAMENT_ACTION_none; // i.e. non-autoLoad
+     if(eFilamentAction==eFILAMENT_ACTION::autoLoad)
+          eFilamentAction=eFILAMENT_ACTION::none; // i.e. non-autoLoad
      }
 else {
      if(current_temperature[0]>(target_temperature[0]*0.95))
           {
           switch(eFilamentAction)
                {
-               case e_FILAMENT_ACTION_Load:
-               case e_FILAMENT_ACTION_autoLoad:
-               case e_FILAMENT_ACTION_unLoad:
+               case eFILAMENT_ACTION::load:
+               case eFILAMENT_ACTION::autoLoad:
+               case eFILAMENT_ACTION::unLoad:
                     menu_submenu(mFilamentPrompt);
                     break;
-               case e_FILAMENT_ACTION_mmuLoad:
+               case eFILAMENT_ACTION::mmuLoad:
                     nLevel=1;
                     if(!bFilamentPreheatState)
                          nLevel++;
@@ -2495,7 +2311,7 @@ else {
                     menu_back(nLevel);
                     menu_submenu(mmu_load_to_nozzle_menu);
                     break;
-               case e_FILAMENT_ACTION_mmuUnLoad:
+               case eFILAMENT_ACTION::mmuUnLoad:
                     nLevel=1;
                     if(!bFilamentPreheatState)
                          nLevel++;
@@ -2503,7 +2319,7 @@ else {
                     menu_back(nLevel);
                     extr_unload();
                     break;
-               case e_FILAMENT_ACTION_mmuEject:
+               case eFILAMENT_ACTION::mmuEject:
                     nLevel=1;
                     if(!bFilamentPreheatState)
                          nLevel++;
@@ -2511,7 +2327,7 @@ else {
                     menu_back(nLevel);
                     menu_submenu(mmu_fil_eject_menu);
                     break;
-               case e_FILAMENT_ACTION_mmuCut:
+               case eFILAMENT_ACTION::mmuCut:
                     nLevel=1;
                     if(!bFilamentPreheatState)
                          nLevel++;
@@ -2544,44 +2360,44 @@ if(current_temperature[0]>(target_temperature[0]*0.95))
      {
      switch(eFilamentAction)
           {
-          case e_FILAMENT_ACTION_Load:
-          case e_FILAMENT_ACTION_autoLoad:
-          case e_FILAMENT_ACTION_unLoad:
+          case FilamentAction::Load:
+          case FilamentAction::AutoLoad:
+          case FilamentAction::UnLoad:
                if(bFilamentWaitingFlag)
                     menu_submenu(mFilamentPrompt);
                else {
                     nLevel=bFilamentPreheatState?1:2;
                     menu_back(nLevel);
-                    if((eFilamentAction==e_FILAMENT_ACTION_Load)||(eFilamentAction==e_FILAMENT_ACTION_autoLoad))
+                    if((eFilamentAction==FilamentAction::Load)||(eFilamentAction==FilamentAction::AutoLoad))
                          {
                          loading_flag=true;
                          enquecommand_P(PSTR("M701")); // load filament
-                         if(eFilamentAction==e_FILAMENT_ACTION_autoLoad)
-                              eFilamentAction=e_FILAMENT_ACTION_none; // i.e. non-autoLoad
+                         if(eFilamentAction==FilamentAction::AutoLoad)
+                              eFilamentAction=FilamentAction::None; // i.e. non-autoLoad
                          }
-                    if(eFilamentAction==e_FILAMENT_ACTION_unLoad)
+                    if(eFilamentAction==FilamentAction::UnLoad)
                          enquecommand_P(PSTR("M702")); // unload filament
                     }
                break;
-          case e_FILAMENT_ACTION_mmuLoad:
+          case FilamentAction::MmuLoad:
                nLevel=bFilamentPreheatState?1:2;
                bFilamentAction=true;
                menu_back(nLevel);
                menu_submenu(mmu_load_to_nozzle_menu);
                break;
-          case e_FILAMENT_ACTION_mmuUnLoad:
+          case FilamentAction::MmuUnLoad:
                nLevel=bFilamentPreheatState?1:2;
                bFilamentAction=true;
                menu_back(nLevel);
                extr_unload();
                break;
-          case e_FILAMENT_ACTION_mmuEject:
+          case FilamentAction::MmuEject:
                nLevel=bFilamentPreheatState?1:2;
                bFilamentAction=true;
                menu_back(nLevel);
                menu_submenu(mmu_fil_eject_menu);
                break;
-          case e_FILAMENT_ACTION_mmuCut:
+          case FilamentAction::MmuCut:
 #ifdef MMU_HAS_CUTTER
                nLevel=bFilamentPreheatState?1:2;
                bFilamentAction=true;
@@ -2589,7 +2405,7 @@ if(current_temperature[0]>(target_temperature[0]*0.95))
                menu_submenu(mmu_cut_filament_menu);
 #endif //MMU_HAS_CUTTER
                break;
-          case e_FILAMENT_ACTION_none:
+          case FilamentAction::None:
                break;
           }
      if(bFilamentWaitingFlag)
@@ -2603,22 +2419,22 @@ else {
      lcd_set_cursor(0,1);
      switch(eFilamentAction)
           {
-          case e_FILAMENT_ACTION_Load:
-          case e_FILAMENT_ACTION_autoLoad:
-          case e_FILAMENT_ACTION_mmuLoad:
+          case FilamentAction::Load:
+          case FilamentAction::AutoLoad:
+          case FilamentAction::MmuLoad:
                lcd_puts_P(_i("Preheating to load")); ////MSG_ c=20 r=1
                break;
-          case e_FILAMENT_ACTION_unLoad:
-          case e_FILAMENT_ACTION_mmuUnLoad:
+          case FilamentAction::UnLoad:
+          case FilamentAction::MmuUnLoad:
                lcd_puts_P(_i("Preheating to unload")); ////MSG_ c=20 r=1
                break;
-          case e_FILAMENT_ACTION_mmuEject:
+          case FilamentAction::MmuEject:
                lcd_puts_P(_i("Preheating to eject")); ////MSG_ c=20 r=1
                break;
-          case e_FILAMENT_ACTION_mmuCut:
+          case FilamentAction::MmuCut:
                lcd_puts_P(_i("Preheating to cut")); ////MSG_ c=20 r=1
                break;
-          case e_FILAMENT_ACTION_none:
+          case FilamentAction::None:
                break;
           }
      lcd_set_cursor(0,3);
@@ -2637,8 +2453,8 @@ else {
                setTargetBed((float)nTargetBedOld);
                }
           menu_back();
-          if(eFilamentAction==e_FILAMENT_ACTION_autoLoad)
-               eFilamentAction=e_FILAMENT_ACTION_none; // i.e. non-autoLoad
+          if(eFilamentAction==FilamentAction::AutoLoad)
+               eFilamentAction=FilamentAction::None; // i.e. non-autoLoad
           }
      }
 }
@@ -2683,8 +2499,8 @@ mFilamentItem(FLEX_PREHEAT_HOTEND_TEMP,FLEX_PREHEAT_HPB_TEMP);
 void mFilamentBack()
 {
 menu_back();
-if(eFilamentAction==e_FILAMENT_ACTION_autoLoad)
-     eFilamentAction=e_FILAMENT_ACTION_none; // i.e. non-autoLoad
+if(eFilamentAction==FilamentAction::AutoLoad)
+     eFilamentAction=FilamentAction::None; // i.e. non-autoLoad
 }
 
 void mFilamentMenu()
@@ -2715,7 +2531,7 @@ if(0)
      enquecommand_P(PSTR("M702"));                // unload filament
      }
 else {
-     eFilamentAction=e_FILAMENT_ACTION_unLoad;
+     eFilamentAction=FilamentAction::UnLoad;
      bFilamentFirstRun=false;
      if(target_temperature[0]>=EXTRUDE_MINTEMP)
           {
@@ -2757,11 +2573,11 @@ void lcd_change_success() {
 
 static void lcd_loading_progress_bar(uint16_t loading_time_ms) { 
 	
-	for (int i = 0; i < 20; i++) {
+	for (uint_least8_t i = 0; i < 20; i++) {
 		lcd_set_cursor(i, 3);
 		lcd_print(".");
 		//loading_time_ms/20 delay
-		for (int j = 0; j < 5; j++) {
+		for (uint_least8_t j = 0; j < 5; j++) {
 			delay_keep_alive(loading_time_ms / 100);
 		}
 	}
@@ -2942,7 +2758,7 @@ static void lcd_LoadFilament()
 if(0)
   {
 //      menu_back();                                // not necessary (see "lcd_return_to_status()" below)
-      custom_message_type = CUSTOM_MSG_TYPE_F_LOAD;
+      custom_message_type = CustomMsg::FilamentLoading;
       loading_flag = true;
       enquecommand_P(PSTR("M701")); //load filament
       SERIAL_ECHOLN("Loading filament");
@@ -2950,7 +2766,7 @@ if(0)
   }
   else
   {
-     eFilamentAction=e_FILAMENT_ACTION_Load;
+     eFilamentAction=FilamentAction::Load;
      bFilamentFirstRun=false;
      if(target_temperature[0]>=EXTRUDE_MINTEMP)
           {
@@ -3203,7 +3019,7 @@ static void lcd_menu_xyz_offset()
     float cntr[2];
     world2machine_read_valid(vec_x, vec_y, cntr);
 
-    for (int i = 0; i < 2; i++)
+    for (uint_least8_t i = 0; i < 2; i++)
     {
         lcd_puts_at_P(11, i + 2, PSTR(""));
         lcd_print(cntr[i]);
@@ -3399,7 +3215,7 @@ void pid_extruder()
 	lcd_set_cursor(1, 2);
 	lcd_print(ftostr3(pid_temp));
 	if (lcd_clicked()) {
-		lcd_commands_type = LCD_COMMAND_PID_EXTRUDER;
+		lcd_commands_type = LcdCommands::PidExtruder;
 		lcd_return_to_status();
 		lcd_update(2);
 	}
@@ -4001,7 +3817,7 @@ void lcd_bed_calibration_show_result(BedSkewOffsetDetectionResultType result, ui
 
 void lcd_temp_cal_show_result(bool result) {
 	
-	custom_message_type = CUSTOM_MSG_TYPE_STATUS;
+	custom_message_type = CustomMsg::Status;
 	disable_x();
 	disable_y();
 	disable_z();
@@ -4159,6 +3975,7 @@ void prusa_statistics(int _message, uint8_t _fil_nr) {
 			SERIAL_ECHO("{");
 			prusa_stat_printerstatus(1);
 			prusa_stat_farm_number();
+			prusa_stat_diameter();
 			SERIAL_ECHOLN("}");
 			status_number = 1;
 		}
@@ -4313,6 +4130,12 @@ static void prusa_stat_farm_number() {
 	SERIAL_ECHO("]");
 }
 
+static void prusa_stat_diameter() {
+	SERIAL_ECHO("[DIA:");
+	SERIAL_ECHO(eeprom_read_word((uint16_t*)EEPROM_NOZZLE_DIAMETER_uM));
+	SERIAL_ECHO("]");
+}
+
 static void prusa_stat_temperatures()
 {
 	SERIAL_ECHO("[ST0:");
@@ -4348,6 +4171,7 @@ static void prusa_stat_printinfo()
 	SERIAL_ECHO("][FWR:");
 	SERIAL_ECHO(FW_VERSION);
 	SERIAL_ECHO("]");
+     prusa_stat_diameter();
 }
 
 /*
@@ -4622,7 +4446,7 @@ static void lcd_crash_mode_set()
     }else{
         crashdet_enable();
     }
-	if (IS_SD_PRINTING || is_usb_printing || (lcd_commands_type == LCD_COMMAND_V2_CAL)) menu_goto(lcd_tune_menu, 9, true, true);
+	if (IS_SD_PRINTING || is_usb_printing || (lcd_commands_type == LcdCommands::Layer1Cal)) menu_goto(lcd_tune_menu, 9, true, true);
 	else menu_goto(lcd_settings_menu, 9, true, true);
     
 }
@@ -4859,19 +4683,19 @@ void lcd_v2_calibration()
 	    if (filament < 5)
 	    {
 	        lcd_commands_step = 20 + filament;
-	        lcd_commands_type = LCD_COMMAND_V2_CAL;
+	        lcd_commands_type = LcdCommands::Layer1Cal;
 	    }
 	}
 	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
 		if (loaded) {
-			lcd_commands_type = LCD_COMMAND_V2_CAL;
+			lcd_commands_type = LcdCommands::Layer1Cal;
 		}
 		else {
 			lcd_display_message_fullscreen_P(_i("Please load PLA filament first."));////MSG_PLEASE_LOAD_PLA c=20 r=4
 			lcd_consume_click();
-			for (int i = 0; i < 20; i++) { //wait max. 2s
+			for (uint_least8_t i = 0; i < 20; i++) { //wait max. 2s
 				delay_keep_alive(100);
 				if (lcd_clicked()) {
 					break;
@@ -5126,7 +4950,7 @@ void lcd_wizard(WizState state)
 		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_commands_type = LcdCommands::Layer1Cal;
 			lcd_return_to_status();
 			end = true;
 			break;
@@ -5283,10 +5107,16 @@ static bool settingsCutter()
 {
     if (mmu_enabled)
     {
-        if (1 == eeprom_read_byte((uint8_t*)EEPROM_MMU_CUTTER_ENABLED))
+        if (EEPROM_MMU_CUTTER_ENABLED_enabled == eeprom_read_byte((uint8_t*)EEPROM_MMU_CUTTER_ENABLED))
         {
             if (menu_item_function_P(_i("Cutter       [on]"), lcd_cutter_enabled)) return true;//// c=17 r=1
         }
+#ifdef MMU_ALWAYS_CUT
+        else if (EEPROM_MMU_CUTTER_ENABLED_always == eeprom_read_byte((uint8_t*)EEPROM_MMU_CUTTER_ENABLED))
+        {
+            if (menu_item_function_P(_i("Cutter   [always]"), lcd_cutter_enabled)) return true;//// c=17 r=1
+        }
+#endif
         else
         {
             if (menu_item_function_P(_i("Cutter      [off]"), lcd_cutter_enabled)) return true;//// c=17 r=1
@@ -5450,6 +5280,101 @@ do\
 }\
 while (0)
 
+//-//
+static void lcd_check_mode_set(void)
+{
+switch(eCheckMode)
+     {
+     case e_CHECK_MODE_none:
+          eCheckMode=e_CHECK_MODE_warn;
+          break;
+     case e_CHECK_MODE_warn:
+          eCheckMode=e_CHECK_MODE_strict;
+          break;
+     case e_CHECK_MODE_strict:
+          eCheckMode=e_CHECK_MODE_none;
+          break;
+     default:
+          eCheckMode=e_CHECK_MODE_none;
+     }
+eeprom_update_byte((uint8_t*)EEPROM_CHECK_MODE,(uint8_t)eCheckMode);
+}
+
+static void lcd_nozzle_diameter_set(void)
+{
+uint16_t nDiameter;
+
+switch(eNozzleDiameter)
+     {
+     case e_NOZZLE_DIAMETER_250:
+          eNozzleDiameter=e_NOZZLE_DIAMETER_400;
+          nDiameter=400;
+          break;
+     case e_NOZZLE_DIAMETER_400:
+          eNozzleDiameter=e_NOZZLE_DIAMETER_600;
+          nDiameter=600;
+          break;
+     case e_NOZZLE_DIAMETER_600:
+          eNozzleDiameter=e_NOZZLE_DIAMETER_250;
+          nDiameter=250;
+          break;
+     default:
+          eNozzleDiameter=e_NOZZLE_DIAMETER_400;
+          nDiameter=400;
+     }
+eeprom_update_byte((uint8_t*)EEPROM_NOZZLE_DIAMETER,(uint8_t)eNozzleDiameter);
+eeprom_update_word((uint16_t*)EEPROM_NOZZLE_DIAMETER_uM,nDiameter);
+}
+
+#define SETTINGS_MODE \
+do\
+{\
+    switch(eCheckMode)\
+         {\
+         case e_CHECK_MODE_none:\
+              MENU_ITEM_FUNCTION_P(_i("Action     [none]"),lcd_check_mode_set);\
+              break;\
+         case e_CHECK_MODE_warn:\
+              MENU_ITEM_FUNCTION_P(_i("Action     [warn]"),lcd_check_mode_set);\
+              break;\
+         case e_CHECK_MODE_strict:\
+              MENU_ITEM_FUNCTION_P(_i("Action   [strict]"),lcd_check_mode_set);\
+              break;\
+         default:\
+              MENU_ITEM_FUNCTION_P(_i("Action     [none]"),lcd_check_mode_set);\
+         }\
+}\
+while (0)
+
+#define SETTINGS_NOZZLE \
+do\
+{\
+    switch(eNozzleDiameter)\
+         {\
+         case e_NOZZLE_DIAMETER_250:\
+              MENU_ITEM_FUNCTION_P(_i("Nozzle     [0.25]"),lcd_nozzle_diameter_set);\
+              break;\
+         case e_NOZZLE_DIAMETER_400:\
+              MENU_ITEM_FUNCTION_P(_i("Nozzle     [0.40]"),lcd_nozzle_diameter_set);\
+              break;\
+         case e_NOZZLE_DIAMETER_600:\
+              MENU_ITEM_FUNCTION_P(_i("Nozzle     [0.60]"),lcd_nozzle_diameter_set);\
+              break;\
+         default:\
+              MENU_ITEM_FUNCTION_P(_i("Nozzle     [0.40]"),lcd_nozzle_diameter_set);\
+         }\
+}\
+while (0)
+
+static void lcd_checking_menu()
+{
+MENU_BEGIN();
+MENU_ITEM_BACK_P(_T(MSG_SETTINGS));
+SETTINGS_MODE;
+SETTINGS_NOZZLE;
+MENU_END();
+}
+
 static void lcd_settings_menu()
 {
 	EEPROM_read(EEPROM_SILENT, (uint8_t*)&SilentModeMenu, sizeof(SilentModeMenu));
@@ -5501,6 +5426,9 @@ static void lcd_settings_menu()
 	MENU_ITEM_SUBMENU_P(_i("Select language"), lcd_language_menu);////MSG_LANGUAGE_SELECT
 #endif //(LANG_MODE != 0)
 
+	if (!farm_mode)
+          MENU_ITEM_SUBMENU_P(_i("Print checking"), lcd_checking_menu);
+
 	SETTINGS_SD;
 	SETTINGS_SOUND;
 
@@ -5592,7 +5520,7 @@ void bowden_menu() {
 	lcd_clear();
 	lcd_set_cursor(0, 0);
 	lcd_print(">");
-	for (int i = 0; i < 4; i++) {
+	for (uint_least8_t i = 0; i < 4; i++) {
 		lcd_set_cursor(1, i);
 		lcd_print("Extruder ");
 		lcd_print(i);
@@ -5680,7 +5608,7 @@ void bowden_menu() {
 						enc_dif = lcd_encoder_diff;
 						lcd_set_cursor(0, cursor_pos);
 						lcd_print(">");
-						for (int i = 0; i < 4; i++) {
+						for (uint_least8_t i = 0; i < 4; i++) {
 							lcd_set_cursor(1, i);
 							lcd_print("Extruder ");
 							lcd_print(i);
@@ -5807,14 +5735,14 @@ uint8_t choose_menu_P(const char *header, const char *item, const char *last_ite
         if (header) lcd_puts_at_P(0,0,header);
 
         const bool last_visible = (first == items_no - 3);
-        const int8_t ordinary_items = (last_item&&last_visible)?2:3;
+        const uint_least8_t ordinary_items = (last_item&&last_visible)?2:3;
 
-        for (int i = 0; i < ordinary_items; i++)
+        for (uint_least8_t i = 0; i < ordinary_items; i++)
         {
             if (item) lcd_puts_at_P(1, i + 1, item);
         }
 
-        for (int i = 0; i < ordinary_items; i++)
+        for (uint_least8_t i = 0; i < ordinary_items; i++)
         {
             lcd_set_cursor(2 + item_len, i+1);
             lcd_print(first + i + 1);
@@ -5868,7 +5796,7 @@ char reset_menu() {
 	lcd_consume_click();
 	while (1) {		
 
-		for (int i = 0; i < 4; i++) {
+		for (uint_least8_t i = 0; i < 4; i++) {
 			lcd_set_cursor(1, i);
 			lcd_print(item[first + i]);
 		}
@@ -5953,7 +5881,7 @@ static void fil_load_menu()
 
     if (mmu_enabled)
     {
-        MENU_ITEM_FUNCTION_NR_P(_T(MSG_LOAD_FILAMENT), '5', extr_adj, 3);
+        MENU_ITEM_FUNCTION_NR_P(_T(MSG_LOAD_FILAMENT), '5', extr_adj, 4);
     }
     MENU_END();
 }
@@ -5973,7 +5901,7 @@ static void mmu_load_to_nozzle_menu()
     }
     else
     {
-        eFilamentAction = e_FILAMENT_ACTION_mmuLoad;
+        eFilamentAction = FilamentAction::MmuLoad;
         bFilamentFirstRun = false;
         if (target_temperature[0] >= EXTRUDE_MINTEMP)
         {
@@ -6005,7 +5933,7 @@ static void mmu_fil_eject_menu()
     }
     else
     {
-        eFilamentAction = e_FILAMENT_ACTION_mmuEject;
+        eFilamentAction = FilamentAction::MmuEject;
         bFilamentFirstRun = false;
         if (target_temperature[0] >= EXTRUDE_MINTEMP)
         {
@@ -6024,16 +5952,16 @@ static void mmu_cut_filament_menu()
     {
         MENU_BEGIN();
         MENU_ITEM_BACK_P(_T(MSG_MAIN));
-        MENU_ITEM_FUNCTION_NR_P(_T(MSG_EJECT_FILAMENT), '1', mmu_cut_filament, 0);
-        MENU_ITEM_FUNCTION_NR_P(_T(MSG_EJECT_FILAMENT), '2', mmu_cut_filament, 1);
-        MENU_ITEM_FUNCTION_NR_P(_T(MSG_EJECT_FILAMENT), '3', mmu_cut_filament, 2);
-        MENU_ITEM_FUNCTION_NR_P(_T(MSG_EJECT_FILAMENT), '4', mmu_cut_filament, 3);
-        MENU_ITEM_FUNCTION_NR_P(_T(MSG_EJECT_FILAMENT), '5', mmu_cut_filament, 4);
+        MENU_ITEM_FUNCTION_NR_P(_T(MSG_CUT_FILAMENT), '1', mmu_cut_filament, 0);
+        MENU_ITEM_FUNCTION_NR_P(_T(MSG_CUT_FILAMENT), '2', mmu_cut_filament, 1);
+        MENU_ITEM_FUNCTION_NR_P(_T(MSG_CUT_FILAMENT), '3', mmu_cut_filament, 2);
+        MENU_ITEM_FUNCTION_NR_P(_T(MSG_CUT_FILAMENT), '4', mmu_cut_filament, 3);
+        MENU_ITEM_FUNCTION_NR_P(_T(MSG_CUT_FILAMENT), '5', mmu_cut_filament, 4);
         MENU_END();
     }
     else
     {
-        eFilamentAction=e_FILAMENT_ACTION_mmuCut;
+        eFilamentAction=FilamentAction::MmuCut;
         bFilamentFirstRun=false;
         if(target_temperature[0]>=EXTRUDE_MINTEMP)
         {
@@ -6078,7 +6006,7 @@ static void change_extr_menu(){
 //unload filament for single material printer (used in M702 gcode)
 void unload_filament()
 {
-	custom_message_type = CUSTOM_MSG_TYPE_F_LOAD;
+	custom_message_type = CustomMsg::FilamentLoading;
 	lcd_setstatuspgm(_T(MSG_UNLOADING_FILAMENT));
 
 	//		extr_unload2();
@@ -6113,7 +6041,7 @@ void unload_filament()
 	lcd_update_enable(true);
 
 	lcd_setstatuspgm(_T(WELCOME_MSG));
-	custom_message_type = CUSTOM_MSG_TYPE_STATUS;
+	custom_message_type = CustomMsg::Status;
 
 }
 
@@ -6194,7 +6122,7 @@ unsigned char lcd_choose_color() {
 	item[0] = "Orange";
 	item[1] = "Black";
 	//-----------------------------------------------------
-	unsigned char active_rows;
+	uint_least8_t active_rows;
 	static int first = 0;
 	int enc_dif = 0;
 	unsigned char cursor_pos = 1;
@@ -6207,7 +6135,7 @@ unsigned char lcd_choose_color() {
 	lcd_consume_click();
 	while (1) {
 		lcd_puts_at_P(0, 0, PSTR("Choose color:"));
-		for (int i = 0; i < active_rows; i++) {
+		for (uint_least8_t i = 0; i < active_rows; i++) {
 			lcd_set_cursor(1, i+1);
 			lcd_print(item[first + i]);
 		}
@@ -6313,10 +6241,11 @@ void lcd_confirm_print()
 		}
 		if (lcd_clicked())
 		{
+               filament_type = FARM_FILAMENT_COLOR_NONE;
 			if (cursor_pos == 1)
 			{
 				_ret = 1;
-				filament_type = lcd_choose_color();
+//				filament_type = lcd_choose_color();
 				prusa_statistics(4, filament_type);
 				no_response = true; //we need confirmation by recieving PRUSA thx
 				important_status = 4;
@@ -6326,7 +6255,7 @@ void lcd_confirm_print()
 			if (cursor_pos == 2)
 			{
 				_ret = 2;
-				filament_type = lcd_choose_color();
+//				filament_type = lcd_choose_color();
 				prusa_statistics(5, filament_type);
 				no_response = true; //we need confirmation by recieving PRUSA thx
 				important_status = 5;				
@@ -6440,13 +6369,13 @@ static void lcd_main_menu()
         
     }*/
  
-  if ( ( IS_SD_PRINTING || is_usb_printing || (lcd_commands_type == LCD_COMMAND_V2_CAL)) && (current_position[Z_AXIS] < Z_HEIGHT_HIDE_LIVE_ADJUST_MENU) && !homing_flag && !mesh_bed_leveling_flag)
+  if ( ( IS_SD_PRINTING || is_usb_printing || (lcd_commands_type == LcdCommands::Layer1Cal)) && (current_position[Z_AXIS] < Z_HEIGHT_HIDE_LIVE_ADJUST_MENU) && !homing_flag && !mesh_bed_leveling_flag)
   {
 	MENU_ITEM_SUBMENU_P(_T(MSG_BABYSTEP_Z), lcd_babystep_z);//8
   }
 
 
-  if ( moves_planned() || IS_SD_PRINTING || is_usb_printing || (lcd_commands_type == LCD_COMMAND_V2_CAL))
+  if ( moves_planned() || IS_SD_PRINTING || is_usb_printing || (lcd_commands_type == LcdCommands::Layer1Cal))
   {
     MENU_ITEM_SUBMENU_P(_i("Tune"), lcd_tune_menu);////MSG_TUNE
   } else 
@@ -6455,7 +6384,7 @@ static void lcd_main_menu()
   }
 
 #ifdef SDSUPPORT
-  if (card.cardOK || lcd_commands_type == LCD_COMMAND_V2_CAL)
+  if (card.cardOK || lcd_commands_type == LcdCommands::Layer1Cal)
   {
     if (card.isFileOpen())
     {
@@ -6471,12 +6400,12 @@ static void lcd_main_menu()
 			MENU_ITEM_SUBMENU_P(_T(MSG_STOP_PRINT), lcd_sdcard_stop);
 		}
 	}
-	else if (lcd_commands_type == LCD_COMMAND_V2_CAL && mesh_bed_leveling_flag == false && homing_flag == false) {
+	else if (lcd_commands_type == LcdCommands::Layer1Cal && mesh_bed_leveling_flag == false && homing_flag == false) {
 		//MENU_ITEM_SUBMENU_P(_T(MSG_STOP_PRINT), lcd_sdcard_stop);
 	}
 	else
 	{
-		if (!is_usb_printing && (lcd_commands_type != LCD_COMMAND_V2_CAL))
+		if (!is_usb_printing && (lcd_commands_type != LcdCommands::Layer1Cal))
 		{
 			//if (farm_mode) MENU_ITEM_SUBMENU_P(MSG_FARM_CARD_MENU, lcd_farm_sdcard_menu);
 			/*else*/ {
@@ -6500,7 +6429,7 @@ static void lcd_main_menu()
 #endif
 
 
-  if (IS_SD_PRINTING || is_usb_printing || (lcd_commands_type == LCD_COMMAND_V2_CAL))
+  if (IS_SD_PRINTING || is_usb_printing || (lcd_commands_type == LcdCommands::Layer1Cal))
   {
 	  if (farm_mode)
 	  {
@@ -6544,7 +6473,7 @@ static void lcd_main_menu()
 
   }
 
-  if (!is_usb_printing && (lcd_commands_type != LCD_COMMAND_V2_CAL))
+  if (!is_usb_printing && (lcd_commands_type != LcdCommands::Layer1Cal))
   {
 	  MENU_ITEM_SUBMENU_P(_i("Statistics  "), lcd_menu_statistics);////MSG_STATISTICS
   }
@@ -6600,7 +6529,7 @@ static void lcd_colorprint_change() {
 	
 	enquecommand_P(PSTR("M600"));
 	
-	custom_message_type = CUSTOM_MSG_TYPE_F_LOAD; //just print status message
+	custom_message_type = CustomMsg::FilamentLoading; //just print status message
 	lcd_setstatuspgm(_T(MSG_FINISHING_MOVEMENTS));
 	lcd_return_to_status();
 	lcd_draw_update = 3;
@@ -6718,6 +6647,14 @@ static void lcd_tune_menu()
 
 	SETTINGS_CUTTER;
 
+     if(farm_mode)
+     {
+          if (fans_check_enabled == true)
+               MENU_ITEM_FUNCTION_P(_i("Fans check   [on]"), lcd_set_fan_check);////MSG_FANS_CHECK_ON c=17 r=1
+          else
+               MENU_ITEM_FUNCTION_P(_i("Fans check  [off]"), lcd_set_fan_check);////MSG_FANS_CHECK_OFF c=17 r=1
+     }
+
 #ifdef TMC2130
      if(!farm_mode)
      {
@@ -6861,6 +6798,12 @@ static void lcd_sd_updir()
 
 void lcd_print_stop()
 {
+//-//
+     if(!card.sdprinting)
+          {
+          SERIAL_ECHOLNPGM("// action:cancel");   // for Octoprint
+          return;
+          }
 	saved_printing = false;
 	cancel_heatup = true;
 #ifdef MESH_BED_LEVELING
@@ -6886,7 +6829,7 @@ void lcd_print_stop()
 	lcd_return_to_status();
 	lcd_ignore_click(true);
 	lcd_commands_step = 0;
-	lcd_commands_type = LCD_COMMAND_STOP_PRINT;
+	lcd_commands_type = LcdCommands::StopPrint;
 	// Turn off the print fan
 	SET_OUTPUT(FAN_PIN);
 	WRITE(FAN_PIN, 0);
@@ -6999,13 +6942,13 @@ bool lcd_selftest()
 	_delay(2000);
 	KEEPALIVE_STATE(IN_HANDLER);
 
-	_progress = lcd_selftest_screen(testScreen::extruderFan, _progress, 3, true, 2000);
+	_progress = lcd_selftest_screen(TestScreen::ExtruderFan, _progress, 3, true, 2000);
 #if (defined(FANCHECK) && defined(TACH_0))
 	switch (lcd_selftest_fan_auto(0)){		// check extruder Fan
-		case FanCheck::extruderFan:
+		case FanCheck::ExtruderFan:
 			_result = false;
 			break;
-		case FanCheck::swappedFan:
+		case FanCheck::SwappedFan:
 			_swapped_fan = true;
 			// no break
 		default:
@@ -7017,18 +6960,18 @@ bool lcd_selftest()
 #endif //defined(TACH_0)
 	if (!_result)
 	{
-		lcd_selftest_error(TestError::extruderFan, "", "");
+		lcd_selftest_error(TestError::ExtruderFan, "", "");
 	}
 
 	if (_result)
 	{
-		_progress = lcd_selftest_screen(testScreen::printFan, _progress, 3, true, 2000);
+		_progress = lcd_selftest_screen(TestScreen::PrintFan, _progress, 3, true, 2000);
 #if (defined(FANCHECK) && defined(TACH_1))
 	switch (lcd_selftest_fan_auto(1)){		// check print fan
-		case FanCheck::printFan:
+		case FanCheck::PrintFan:
 			_result = false;
 			break;
-		case FanCheck::swappedFan:
+		case FanCheck::SwappedFan:
 			_swapped_fan = true;
 			// no break
 		default:
@@ -7040,7 +6983,7 @@ bool lcd_selftest()
 #endif //defined(TACH_1)
 		if (!_result)
 		{
-			lcd_selftest_error(TestError::printFan, "", ""); //print fan not spinning
+			lcd_selftest_error(TestError::PrintFan, "", ""); //print fan not spinning
 		}
 	}
 
@@ -7051,18 +6994,18 @@ bool lcd_selftest()
 			//print fan is stil turned on; check that it is spinning
 			_result = lcd_selftest_manual_fan_check(1, false, true);
 			if (!_result){
-				lcd_selftest_error(TestError::printFan, "", "");
+				lcd_selftest_error(TestError::PrintFan, "", "");
 			}
 		}
 		else {
 			// fans are swapped
-			lcd_selftest_error(TestError::swappedFan, "", "");
+			lcd_selftest_error(TestError::SwappedFan, "", "");
 		}
 	}
 
 	if (_result)
 	{
-		_progress = lcd_selftest_screen(testScreen::fansOk, _progress, 3, true, 2000);
+		_progress = lcd_selftest_screen(TestScreen::FansOk, _progress, 3, true, 2000);
 #ifndef TMC2130
 		_result = lcd_selfcheck_endstops();
 #else
@@ -7073,7 +7016,7 @@ bool lcd_selftest()
 	if (_result)
 	{
 		//current_position[Z_AXIS] += 15;									//move Z axis higher to avoid false triggering of Z end stop in case that we are very low - just above heatbed
-		_progress = lcd_selftest_screen(testScreen::axisX, _progress, 3, true, 2000);
+		_progress = lcd_selftest_screen(TestScreen::AxisX, _progress, 3, true, 2000);
 #ifdef TMC2130
         _result = lcd_selfcheck_axis_sg(X_AXIS);
 #else
@@ -7086,7 +7029,7 @@ bool lcd_selftest()
 
 	if (_result)
 	{
-		_progress = lcd_selftest_screen(testScreen::axisX, _progress, 3, true, 0);
+		_progress = lcd_selftest_screen(TestScreen::AxisX, _progress, 3, true, 0);
 
 #ifndef TMC2130
 		_result = lcd_selfcheck_pulleys(X_AXIS);
@@ -7096,7 +7039,7 @@ bool lcd_selftest()
 
 	if (_result)
 	{
-		_progress = lcd_selftest_screen(testScreen::axisY, _progress, 3, true, 1500);
+		_progress = lcd_selftest_screen(TestScreen::AxisY, _progress, 3, true, 1500);
 #ifdef TMC2130
 		_result = lcd_selfcheck_axis_sg(Y_AXIS);
 #else
@@ -7106,7 +7049,7 @@ bool lcd_selftest()
 
 	if (_result)
 	{
-		_progress = lcd_selftest_screen(testScreen::axisZ, _progress, 3, true, 0);
+		_progress = lcd_selftest_screen(TestScreen::AxisZ, _progress, 3, true, 0);
 #ifndef TMC2130
 		_result = lcd_selfcheck_pulleys(Y_AXIS);
 #endif // TMC2130
@@ -7127,7 +7070,7 @@ bool lcd_selftest()
 		current_position[Z_AXIS] = current_position[Z_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();
-		_progress = lcd_selftest_screen(testScreen::axisZ, _progress, 3, true, 1500);
+		_progress = lcd_selftest_screen(TestScreen::AxisZ, _progress, 3, true, 1500);
 		_result = lcd_selfcheck_axis(2, Z_MAX_POS);
 		if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE) != 1) {
 			enquecommand_P(PSTR("G28 W"));
@@ -7141,11 +7084,11 @@ bool lcd_selftest()
 		current_position[Z_AXIS] = current_position[Z_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();
-		_progress = lcd_selftest_screen(testScreen::home, 0, 2, true, 0);
+		_progress = lcd_selftest_screen(TestScreen::Home, 0, 2, true, 0);
 		bool bres = tmc2130_home_calibrate(X_AXIS);
-		_progress = lcd_selftest_screen(testScreen::home, 1, 2, true, 0);
+		_progress = lcd_selftest_screen(TestScreen::Home, 1, 2, true, 0);
 		bres &= tmc2130_home_calibrate(Y_AXIS);
-		_progress = lcd_selftest_screen(testScreen::home, 2, 2, true, 0);
+		_progress = lcd_selftest_screen(TestScreen::Home, 2, 2, true, 0);
 		if (bres)
 			eeprom_update_byte((uint8_t*)EEPROM_TMC2130_HOME_ENABLED, 1);
 		_result = bres;
@@ -7154,18 +7097,18 @@ bool lcd_selftest()
 
 	if (_result)
 	{
-		_progress = lcd_selftest_screen(testScreen::bed, _progress, 3, true, 2000);
+		_progress = lcd_selftest_screen(TestScreen::Bed, _progress, 3, true, 2000);
 		_result = lcd_selfcheck_check_heater(true);
 	}
 
     if (_result)
     {
-        _progress = lcd_selftest_screen(testScreen::hotend, _progress, 3, true, 1000);
+        _progress = lcd_selftest_screen(TestScreen::Hotend, _progress, 3, true, 1000);
         _result = lcd_selfcheck_check_heater(false);
     }
 	if (_result)
 	{
-		_progress = lcd_selftest_screen(testScreen::hotendOk, _progress, 3, true, 2000); //nozzle ok
+		_progress = lcd_selftest_screen(TestScreen::HotendOk, _progress, 3, true, 2000); //nozzle ok
 	}
 #ifdef FILAMENT_SENSOR
     if (_result)
@@ -7173,20 +7116,20 @@ bool lcd_selftest()
 
         if (mmu_enabled)
         {        
-			_progress = lcd_selftest_screen(testScreen::fsensor, _progress, 3, true, 2000); //check filaments sensor
+			_progress = lcd_selftest_screen(TestScreen::Fsensor, _progress, 3, true, 2000); //check filaments sensor
             _result = selftest_irsensor();
 		    if (_result)
 			{
-				_progress = lcd_selftest_screen(testScreen::fsensorOk, _progress, 3, true, 2000); //fil sensor OK
+				_progress = lcd_selftest_screen(TestScreen::FsensorOk, _progress, 3, true, 2000); //fil sensor OK
 			}
         } else
         {
 #ifdef PAT9125
-			_progress = lcd_selftest_screen(testScreen::fsensor, _progress, 3, true, 2000); //check filaments sensor
+			_progress = lcd_selftest_screen(TestScreen::Fsensor, _progress, 3, true, 2000); //check filaments sensor
             _result = lcd_selftest_fsensor();
 			if (_result)
 			{
-				_progress = lcd_selftest_screen(testScreen::fsensorOk, _progress, 3, true, 2000); //fil sensor OK
+				_progress = lcd_selftest_screen(TestScreen::FsensorOk, _progress, 3, true, 2000); //fil sensor OK
 			}
 #endif //PAT9125
         }
@@ -7194,11 +7137,11 @@ bool lcd_selftest()
 #endif //FILAMENT_SENSOR
 	if (_result)
 	{
-		_progress = lcd_selftest_screen(testScreen::allCorrect, _progress, 3, true, 5000); //all correct
+		_progress = lcd_selftest_screen(TestScreen::AllCorrect, _progress, 3, true, 5000); //all correct
 	}
 	else
 	{
-		_progress = lcd_selftest_screen(testScreen::failed, _progress, 3, true, 5000);
+		_progress = lcd_selftest_screen(TestScreen::Failed, _progress, 3, true, 5000);
 	}
 	lcd_reset_alert_level();
 	enquecommand_P(PSTR("M84"));
@@ -7301,7 +7244,7 @@ static bool lcd_selfcheck_axis_sg(unsigned char axis) {
 
 //end of second measurement, now check for possible errors:
 
-	for(int i = 0; i < 2; i++){ //check if measured axis length corresponds to expected length
+	for(uint_least8_t i = 0; i < 2; i++){ //check if measured axis length corresponds to expected length
 		printf_P(_N("Measured axis length:%.3f\n"), measured_axis_length[i]);
 		if (abs(measured_axis_length[i] - axis_length) > max_error_mm) {
 			enable_endstops(false);
@@ -7312,7 +7255,7 @@ static bool lcd_selfcheck_axis_sg(unsigned char axis) {
 			if (axis == Y_AXIS) _error_1 = "Y";
 			if (axis == Z_AXIS) _error_1 = "Z";
 
-			lcd_selftest_error(TestError::axis, _error_1, "");
+			lcd_selftest_error(TestError::Axis, _error_1, "");
 			current_position[axis] = 0;
 			plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
 			reset_crash_det(axis);
@@ -7330,7 +7273,7 @@ static bool lcd_selfcheck_axis_sg(unsigned char axis) {
 			if (axis == Y_AXIS) _error_1 = "Y";
 			if (axis == Z_AXIS) _error_1 = "Z";
 
-			lcd_selftest_error(TestError::pulley, _error_1, "");
+			lcd_selftest_error(TestError::Pulley, _error_1, "");
 			current_position[axis] = 0;
 			plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
 			reset_crash_det(axis);
@@ -7405,7 +7348,7 @@ static bool lcd_selfcheck_axis(int _axis, int _travel)
 		}
 		else
 		{
-			_progress = lcd_selftest_screen(static_cast<testScreen>(static_cast<int>(testScreen::axisX) + _axis), _progress, 3, false, 0);
+			_progress = lcd_selftest_screen(static_cast<TestScreen>(static_cast<int>(TestScreen::AxisX) + _axis), _progress, 3, false, 0);
 			_lcd_refresh = 0;
 		}
 
@@ -7437,11 +7380,11 @@ static bool lcd_selfcheck_axis(int _axis, int _travel)
 
 		if (_travel_done >= _travel)
 		{
-			lcd_selftest_error(TestError::endstop, _error_1, _error_2);
+			lcd_selftest_error(TestError::Endstop, _error_1, _error_2);
 		}
 		else
 		{
-			lcd_selftest_error(TestError::motor, _error_1, _error_2);
+			lcd_selftest_error(TestError::Motor, _error_1, _error_2);
 		}
 	}
 
@@ -7481,7 +7424,7 @@ static bool lcd_selfcheck_pulleys(int axis)
 		st_synchronize();
 		if (((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING) == 1) ||
 			((READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING) == 1)) {
-			lcd_selftest_error(TestError::pulley, (axis == 0) ? "X" : "Y", "");
+			lcd_selftest_error(TestError::Pulley, (axis == 0) ? "X" : "Y", "");
 			return(false);
 		}
 	}
@@ -7499,7 +7442,7 @@ static bool lcd_selfcheck_pulleys(int axis)
 				return(true);
 			}
 			else {
-				lcd_selftest_error(TestError::pulley, (axis == 0) ? "X" : "Y", "");
+				lcd_selftest_error(TestError::Pulley, (axis == 0) ? "X" : "Y", "");
 				return(false);
 			}
 		}
@@ -7508,7 +7451,7 @@ static bool lcd_selfcheck_pulleys(int axis)
 			plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder);
 			st_synchronize();
 			if (_millis() > timeout_counter) {
-				lcd_selftest_error(TestError::pulley, (axis == 0) ? "X" : "Y", "");
+				lcd_selftest_error(TestError::Pulley, (axis == 0) ? "X" : "Y", "");
 				return(false);
 			}
 		}
@@ -7541,7 +7484,7 @@ static bool lcd_selfcheck_endstops()
 		if ((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING) == 1) strcat(_error, "X");
 		if ((READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING) == 1) strcat(_error, "Y");
 		if ((READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING) == 1) strcat(_error, "Z");
-		lcd_selftest_error(TestError::endstops, _error, "");
+		lcd_selftest_error(TestError::Endstops, _error, "");
 	}
 	manage_heater();
 	manage_inactivity(true);
@@ -7572,7 +7515,7 @@ static bool lcd_selfcheck_check_heater(bool _isbed)
 
 		manage_heater();
 		manage_inactivity(true);
-		_progress = (_isbed) ? lcd_selftest_screen(testScreen::bed, _progress, 2, false, 400) : lcd_selftest_screen(testScreen::hotend, _progress, 2, false, 400);
+		_progress = (_isbed) ? lcd_selftest_screen(TestScreen::Bed, _progress, 2, false, 400) : lcd_selftest_screen(TestScreen::Hotend, _progress, 2, false, 400);
 		/*if (_isbed) {
 			MYSERIAL.print("Bed temp:");
 			MYSERIAL.println(degBed());
@@ -7607,12 +7550,12 @@ static bool lcd_selfcheck_check_heater(bool _isbed)
 		}
 		else
 		{
-			lcd_selftest_error(TestError::heater, "", "");
+			lcd_selftest_error(TestError::Heater, "", "");
 		}
 	}
 	else
 	{
-		lcd_selftest_error(TestError::bed, "", "");
+		lcd_selftest_error(TestError::Bed, "", "");
 	}
 
 	manage_heater();
@@ -7639,19 +7582,19 @@ static void lcd_selftest_error(TestError testError, const char *_error_1, const
 
 	switch (testError)
 	{
-	case TestError::heater:
+	case TestError::Heater:
 		lcd_set_cursor(0, 2);
 		lcd_puts_P(_i("Heater/Thermistor"));////MSG_SELFTEST_HEATERTHERMISTOR
 		lcd_set_cursor(0, 3);
 		lcd_puts_P(_i("Not connected"));////MSG_SELFTEST_NOTCONNECTED
 		break;
-	case TestError::bed:
+	case TestError::Bed:
 		lcd_set_cursor(0, 2);
 		lcd_puts_P(_i("Bed / Heater"));////MSG_SELFTEST_BEDHEATER
 		lcd_set_cursor(0, 3);
 		lcd_puts_P(_T(MSG_SELFTEST_WIRINGERROR));
 		break;
-	case TestError::endstops:
+	case TestError::Endstops:
 		lcd_set_cursor(0, 2);
 		lcd_puts_P(_i("Endstops"));////MSG_SELFTEST_ENDSTOPS
 		lcd_set_cursor(0, 3);
@@ -7659,7 +7602,7 @@ static void lcd_selftest_error(TestError testError, const char *_error_1, const
 		lcd_set_cursor(17, 3);
 		lcd_print(_error_1);
 		break;
-	case TestError::motor:
+	case TestError::Motor:
 		lcd_set_cursor(0, 2);
 		lcd_puts_P(_T(MSG_SELFTEST_MOTOR));
 		lcd_set_cursor(18, 2);
@@ -7669,7 +7612,7 @@ static void lcd_selftest_error(TestError testError, const char *_error_1, const
 		lcd_set_cursor(18, 3);
 		lcd_print(_error_2);
 		break;
-	case TestError::endstop:
+	case TestError::Endstop:
 		lcd_set_cursor(0, 2);
 		lcd_puts_P(_i("Endstop not hit"));////MSG_SELFTEST_ENDSTOP_NOTHIT c=20 r=1
 		lcd_set_cursor(0, 3);
@@ -7677,7 +7620,7 @@ static void lcd_selftest_error(TestError testError, const char *_error_1, const
 		lcd_set_cursor(18, 3);
 		lcd_print(_error_1);
 		break;
-	case TestError::printFan:
+	case TestError::PrintFan:
 		lcd_set_cursor(0, 2);
 		lcd_puts_P(_T(MSG_SELFTEST_COOLING_FAN));
 		lcd_set_cursor(0, 3);
@@ -7685,7 +7628,7 @@ static void lcd_selftest_error(TestError testError, const char *_error_1, const
 		lcd_set_cursor(18, 3);
 		lcd_print(_error_1);
 		break;
-	case TestError::extruderFan:
+	case TestError::ExtruderFan:
 		lcd_set_cursor(0, 2);
 		lcd_puts_P(_T(MSG_SELFTEST_EXTRUDER_FAN));
 		lcd_set_cursor(0, 3);
@@ -7693,7 +7636,7 @@ static void lcd_selftest_error(TestError testError, const char *_error_1, const
 		lcd_set_cursor(18, 3);
 		lcd_print(_error_1);
 		break;
-	case TestError::pulley:
+	case TestError::Pulley:
 		lcd_set_cursor(0, 2);
 		lcd_puts_P(_i("Loose pulley"));////MSG_LOOSE_PULLEY c=20 r=1
 		lcd_set_cursor(0, 3);
@@ -7701,7 +7644,7 @@ static void lcd_selftest_error(TestError testError, const char *_error_1, const
 		lcd_set_cursor(18, 3);
 		lcd_print(_error_1);
 		break;
-	case TestError::axis:
+	case TestError::Axis:
 		lcd_set_cursor(0, 2);
 		lcd_puts_P(_i("Axis length"));////MSG_SELFTEST_AXIS_LENGTH
 		lcd_set_cursor(0, 3);
@@ -7709,7 +7652,7 @@ static void lcd_selftest_error(TestError testError, const char *_error_1, const
 		lcd_set_cursor(18, 3);
 		lcd_print(_error_1);
 		break;
-	case TestError::swappedFan:
+	case TestError::SwappedFan:
 		lcd_set_cursor(0, 2);
 		lcd_puts_P(_i("Front/left fans"));////MSG_SELFTEST_FANS
 		lcd_set_cursor(0, 3);
@@ -7717,13 +7660,13 @@ static void lcd_selftest_error(TestError testError, const char *_error_1, const
 		lcd_set_cursor(18, 3);
 		lcd_print(_error_1);
 		break;
-	case TestError::wiringFsensor:
+	case TestError::WiringFsensor:
 		lcd_set_cursor(0, 2);
 		lcd_puts_P(_T(MSG_SELFTEST_FILAMENT_SENSOR));
 		lcd_set_cursor(0, 3);
 		lcd_puts_P(_T(MSG_SELFTEST_WIRINGERROR));
 		break;
-	case TestError::triggeringFsensor:
+	case TestError::TriggeringFsensor:
 	    lcd_set_cursor(0, 2);
         lcd_puts_P(_T(MSG_SELFTEST_FILAMENT_SENSOR));
         lcd_set_cursor(0, 3);
@@ -7752,7 +7695,7 @@ static bool lcd_selftest_fsensor(void)
 	fsensor_init();
 	if (fsensor_not_responding)
 	{
-		lcd_selftest_error(TestError::wiringFsensor, "", "");
+		lcd_selftest_error(TestError::WiringFsensor, "", "");
 	}
 	return (!fsensor_not_responding);
 }
@@ -7790,23 +7733,23 @@ static bool selftest_irsensor()
         TempBackup tempBackup;
         setTargetHotend(ABS_PREHEAT_HOTEND_TEMP,active_extruder);
         mmu_wait_for_heater_blocking();
-        progress = lcd_selftest_screen(testScreen::fsensor, 0, 1, true, 0);
+        progress = lcd_selftest_screen(TestScreen::Fsensor, 0, 1, true, 0);
         mmu_filament_ramming();
     }
-    progress = lcd_selftest_screen(testScreen::fsensor, progress, 1, true, 0);
+    progress = lcd_selftest_screen(TestScreen::Fsensor, progress, 1, true, 0);
     mmu_command(MmuCmd::U0);
     manage_response(false, false);
 
     for(uint_least8_t i = 0; i < 200; ++i)
     {
-        if (0 == (i % 32)) progress = lcd_selftest_screen(testScreen::fsensor, progress, 1, true, 0);
+        if (0 == (i % 32)) progress = lcd_selftest_screen(TestScreen::Fsensor, progress, 1, true, 0);
 
         mmu_load_step(false);
         while (blocks_queued())
         {
             if (PIN_GET(IR_SENSOR_PIN) == 0)
             {
-                lcd_selftest_error(TestError::triggeringFsensor, "", "");
+                lcd_selftest_error(TestError::TriggeringFsensor, "", "");
                 return false;
             }
 #ifdef TMC2130
@@ -7951,11 +7894,11 @@ static FanCheck lcd_selftest_fan_auto(int _fan)
 		printf_P(PSTR("Extr fan speed: %d \n"), fan_speed[0]);
 
 		if (!fan_speed[0]) {
-			return FanCheck::extruderFan;
+			return FanCheck::ExtruderFan;
 		}
 #ifdef FAN_SOFT_PWM
 		else if (fan_speed[0] > 50 ) { // printerFan is faster
-			return FanCheck::swappedFan;
+			return FanCheck::SwappedFan;
 		}
 		break;
 #endif
@@ -7990,7 +7933,7 @@ static FanCheck lcd_selftest_fan_auto(int _fan)
 		printf_P(PSTR("Print fan speed: %d \n"), fan_speed[1]);
 		printf_P(PSTR("Extr fan speed: %d \n"), fan_speed[0]);
 		if (!fan_speed[1]) {
-			return FanCheck::printFan;
+			return FanCheck::PrintFan;
 		}
 
 #ifdef FAN_SOFT_PWM
@@ -8009,23 +7952,23 @@ static FanCheck lcd_selftest_fan_auto(int _fan)
 
 		// noctua speed is between 17 and 24, turbine more then 30
 		if (fan_speed[1] < 30) {
-			return FanCheck::swappedFan;
+			return FanCheck::SwappedFan;
 		}
 #else
 		// fan is spinning, but measured RPM are too low for print fan, it must
 		// be left extruder fan
 		else if (fan_speed[1] < 34) {
-			return FanCheck::swappedFan;
+			return FanCheck::SwappedFan;
 		}
 #endif //FAN_SOFT_PWM
 		break;
 	}
-	return FanCheck::success;
+	return FanCheck::Success;
 }
 
 #endif //FANCHECK
 
-static int lcd_selftest_screen(testScreen screen, int _progress, int _progress_scale, bool _clear, int _delay)
+static int lcd_selftest_screen(TestScreen screen, int _progress, int _progress_scale, bool _clear, int _delay)
 {
 
     lcd_update_enable(false);
@@ -8037,58 +7980,58 @@ static int lcd_selftest_screen(testScreen screen, int _progress, int _progress_s
 
 	lcd_set_cursor(0, 0);
 
-	if (screen == testScreen::extruderFan) lcd_puts_P(_T(MSG_SELFTEST_FAN));
-	if (screen == testScreen::printFan) lcd_puts_P(_T(MSG_SELFTEST_FAN));
-	if (screen == testScreen::fansOk) lcd_puts_P(_T(MSG_SELFTEST_FAN));
-	if (screen == testScreen::endStops) lcd_puts_P(_i("Checking endstops"));////MSG_SELFTEST_CHECK_ENDSTOPS c=20
-	if (screen == testScreen::axisX) lcd_puts_P(_i("Checking X axis  "));////MSG_SELFTEST_CHECK_X c=20
-	if (screen == testScreen::axisY) lcd_puts_P(_i("Checking Y axis  "));////MSG_SELFTEST_CHECK_Y c=20
-	if (screen == testScreen::axisZ) lcd_puts_P(_i("Checking Z axis  "));////MSG_SELFTEST_CHECK_Z c=20
-	if (screen == testScreen::bed) lcd_puts_P(_T(MSG_SELFTEST_CHECK_BED));
-	if (screen == testScreen::hotend
-	    || screen == testScreen::hotendOk) lcd_puts_P(_i("Checking hotend  "));////MSG_SELFTEST_CHECK_HOTEND c=20
-	if (screen == testScreen::fsensor) lcd_puts_P(_T(MSG_SELFTEST_CHECK_FSENSOR));
-	if (screen == testScreen::fsensorOk) lcd_puts_P(_T(MSG_SELFTEST_CHECK_FSENSOR));
-	if (screen == testScreen::allCorrect) lcd_puts_P(_i("All correct      "));////MSG_SELFTEST_CHECK_ALLCORRECT c=20
-	if (screen == testScreen::failed) lcd_puts_P(_T(MSG_SELFTEST_FAILED));
-	if (screen == testScreen::home) lcd_puts_P(_i("Calibrating home"));////c=20 r=1
+	if (screen == TestScreen::ExtruderFan) lcd_puts_P(_T(MSG_SELFTEST_FAN));
+	if (screen == TestScreen::PrintFan) lcd_puts_P(_T(MSG_SELFTEST_FAN));
+	if (screen == TestScreen::FansOk) lcd_puts_P(_T(MSG_SELFTEST_FAN));
+	if (screen == TestScreen::EndStops) lcd_puts_P(_i("Checking endstops"));////MSG_SELFTEST_CHECK_ENDSTOPS c=20
+	if (screen == TestScreen::AxisX) lcd_puts_P(_i("Checking X axis  "));////MSG_SELFTEST_CHECK_X c=20
+	if (screen == TestScreen::AxisY) lcd_puts_P(_i("Checking Y axis  "));////MSG_SELFTEST_CHECK_Y c=20
+	if (screen == TestScreen::AxisZ) lcd_puts_P(_i("Checking Z axis  "));////MSG_SELFTEST_CHECK_Z c=20
+	if (screen == TestScreen::Bed) lcd_puts_P(_T(MSG_SELFTEST_CHECK_BED));
+	if (screen == TestScreen::Hotend
+	    || screen == TestScreen::HotendOk) lcd_puts_P(_i("Checking hotend  "));////MSG_SELFTEST_CHECK_HOTEND c=20
+	if (screen == TestScreen::Fsensor) lcd_puts_P(_T(MSG_SELFTEST_CHECK_FSENSOR));
+	if (screen == TestScreen::FsensorOk) lcd_puts_P(_T(MSG_SELFTEST_CHECK_FSENSOR));
+	if (screen == TestScreen::AllCorrect) lcd_puts_P(_i("All correct      "));////MSG_SELFTEST_CHECK_ALLCORRECT c=20
+	if (screen == TestScreen::Failed) lcd_puts_P(_T(MSG_SELFTEST_FAILED));
+	if (screen == TestScreen::Home) lcd_puts_P(_i("Calibrating home"));////c=20 r=1
 
 	lcd_set_cursor(0, 1);
 	lcd_puts_P(separator);
-	if ((screen >= testScreen::extruderFan) && (screen <= testScreen::fansOk))
+	if ((screen >= TestScreen::ExtruderFan) && (screen <= TestScreen::FansOk))
 	{
 		//SERIAL_ECHOLNPGM("Fan test");
 		lcd_puts_at_P(0, 2, _i("Extruder fan:"));////MSG_SELFTEST_EXTRUDER_FAN_SPEED c=18
 		lcd_set_cursor(18, 2);
-		(screen < testScreen::printFan) ? lcd_print(_indicator) : lcd_print("OK");
+		(screen < TestScreen::PrintFan) ? lcd_print(_indicator) : lcd_print("OK");
 		lcd_puts_at_P(0, 3, _i("Print fan:"));////MSG_SELFTEST_PRINT_FAN_SPEED c=18
 		lcd_set_cursor(18, 3);
-		(screen < testScreen::fansOk) ? lcd_print(_indicator) : lcd_print("OK");
+		(screen < TestScreen::FansOk) ? lcd_print(_indicator) : lcd_print("OK");
 	}
-	else if (screen >= testScreen::fsensor && screen <= testScreen::fsensorOk)
+	else if (screen >= TestScreen::Fsensor && screen <= TestScreen::FsensorOk)
 	{
 		lcd_puts_at_P(0, 2, _T(MSG_SELFTEST_FILAMENT_SENSOR));
 		lcd_putc(':');
 		lcd_set_cursor(18, 2);
-		(screen == testScreen::fsensor) ? lcd_print(_indicator) : lcd_print("OK");
+		(screen == TestScreen::Fsensor) ? lcd_print(_indicator) : lcd_print("OK");
 	}
-	else if (screen < testScreen::fsensor)
+	else if (screen < TestScreen::Fsensor)
 	{
 		//SERIAL_ECHOLNPGM("Other tests");
 
-	    testScreen _step_block = testScreen::axisX;
+	    TestScreen _step_block = TestScreen::AxisX;
 		lcd_selftest_screen_step(2, 2, ((screen == _step_block) ? 1 : (screen < _step_block) ? 0 : 2), "X", _indicator);
 
-		_step_block = testScreen::axisY;
+		_step_block = TestScreen::AxisY;
 		lcd_selftest_screen_step(2, 8, ((screen == _step_block) ? 1 : (screen < _step_block) ? 0 : 2), "Y", _indicator);
 
-		_step_block = testScreen::axisZ;
+		_step_block = TestScreen::AxisZ;
 		lcd_selftest_screen_step(2, 14, ((screen == _step_block) ? 1 : (screen < _step_block) ? 0 : 2), "Z", _indicator);
 
-		_step_block = testScreen::bed;
+		_step_block = TestScreen::Bed;
 		lcd_selftest_screen_step(3, 0, ((screen == _step_block) ? 1 : (screen < _step_block) ? 0 : 2), "Bed", _indicator);
 
-        _step_block = testScreen::hotend;
+        _step_block = TestScreen::Hotend;
         lcd_selftest_screen_step(3, 9, ((screen == _step_block) ? 1 : (screen < _step_block) ? 0 : 2), "Hotend", _indicator);
 	}
 
@@ -8165,7 +8108,7 @@ static void menu_action_sdfile(const char* filename)
   const char end[5] = ".gco";
 
   //we are storing just first 8 characters of 8.3 filename assuming that extension is always ".gco"
-  for (int i = 0; i < 8; i++) {
+  for (uint_least8_t i = 0; i < 8; i++) {
 	  if (strcmp((cmd + i + 4), end) == 0) { 
 		  //filename is shorter then 8.3, store '\0' character on position where ".gco" string was found to terminate stored string properly
  		  eeprom_write_byte((uint8_t*)EEPROM_FILENAME + i, '\0');
@@ -8179,8 +8122,8 @@ static void menu_action_sdfile(const char* filename)
   uint8_t depth = (uint8_t)card.getWorkDirDepth();
   eeprom_write_byte((uint8_t*)EEPROM_DIR_DEPTH, depth);
 
-  for (uint8_t i = 0; i < depth; i++) {
-	  for (int j = 0; j < 8; j++) {
+  for (uint_least8_t i = 0; i < depth; i++) {
+	  for (uint_least8_t j = 0; j < 8; j++) {
 		  eeprom_write_byte((uint8_t*)EEPROM_DIRS + j + 8 * i, dir_names[i][j]);
 	  }
   }
@@ -8333,13 +8276,19 @@ void lcd_setstatus(const char* message)
   strncpy(lcd_status_message, message, LCD_WIDTH);
   lcd_finishstatus();
 }
+void lcd_updatestatuspgm(const char *message){
+	strncpy_P(lcd_status_message, message, LCD_WIDTH);
+	lcd_status_message[LCD_WIDTH] = 0;
+	lcd_finishstatus();
+	// hack lcd_draw_update to 1, i.e. without clear
+	lcd_draw_update = 1;
+}
+
 void lcd_setstatuspgm(const char* message)
 {
   if (lcd_status_message_level > 0)
     return;
-  strncpy_P(lcd_status_message, message, LCD_WIDTH);
-  lcd_status_message[LCD_WIDTH] = 0;
-  lcd_finishstatus();
+  lcd_updatestatuspgm(message);
 }
 void lcd_setalertstatuspgm(const char* message)
 {
@@ -8453,5 +8402,5 @@ void menu_lcd_lcdupdate_func(void)
 	if (!SdFatUtil::test_stack_integrity()) stack_error();
 	lcd_ping(); //check that we have received ping command if we are in farm mode
 	lcd_send_status();
-	if (lcd_commands_type == LCD_COMMAND_V2_CAL) lcd_commands();
+	if (lcd_commands_type == LcdCommands::Layer1Cal) lcd_commands();
 }

+ 44 - 28
Firmware/ultralcd.h

@@ -18,7 +18,16 @@ extern void menu_lcd_lcdupdate_func(void);
 void ultralcd_init();
 void lcd_setstatus(const char* message);
 void lcd_setstatuspgm(const char* message);
+//! return to the main status screen and display the alert message
+//! Beware - it has sideeffects:
+//! - always returns the display to the main status screen
+//! - always makes lcd_reset (which is slow and causes flicker)
+//! - does not update the message if there is already one (i.e. lcd_status_message_level > 0)
 void lcd_setalertstatuspgm(const char* message);
+//! only update the alert message on the main status screen
+//! has no sideeffects, may be called multiple times
+void lcd_updatestatuspgm(const char *message);
+
 void lcd_reset_alert_level();
 uint8_t get_message_level();
 void lcd_adjust_z();
@@ -80,31 +89,37 @@ extern void lcd_diag_show_end_stops();
 
 
 // To be used in lcd_commands_type.
-#define LCD_COMMAND_IDLE 0
-#define LCD_COMMAND_LOAD_FILAMENT 1
-#define LCD_COMMAND_STOP_PRINT 2
-#define LCD_COMMAND_FARM_MODE_CONFIRM 4
-#define LCD_COMMAND_LONG_PAUSE 5
-#define LCD_COMMAND_PID_EXTRUDER 7 
-#define LCD_COMMAND_V2_CAL 8
-
-extern int lcd_commands_type;
+enum class LcdCommands : uint_least8_t
+{
+	Idle,
+	LoadFilament,
+	StopPrint,
+	FarmModeConfirm,
+	LongPause,
+	PidExtruder,
+	Layer1Cal,
+};
+
+extern LcdCommands 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
-#define CUSTOM_MSG_TYPE_F_LOAD 2 // Loading filament in progress
-#define CUSTOM_MSG_TYPE_PIDCAL 3 // PID tuning in progress
-#define CUSTOM_MSG_TYPE_TEMCAL 4 // PINDA temp calibration
-#define CUSTOM_MSG_TYPE_TEMPRE 5 // Temp compensation preheat
+enum class CustomMsg : uint_least8_t
+{
+	Status,          //!< status message from lcd_status_message variable
+	MeshBedLeveling, //!< Mesh bed leveling in progress
+	FilamentLoading, //!< Loading filament in progress
+	PidCal,          //!< PID tuning in progress
+	TempCal,         //!< PINDA temperature calibration
+	TempCompPreheat, //!< Temperature compensation preheat
+};
 
-extern unsigned int custom_message_type;
+extern CustomMsg custom_message_type;
 extern unsigned int custom_message_state;
 
 extern uint8_t farm_mode;
 extern int farm_no;
 extern int farm_timer;
-extern int farm_status;
+extern uint8_t farm_status;
 
 #ifdef TMC2130
 #define SILENT_MODE_NORMAL 0
@@ -136,18 +151,19 @@ void extr_unload_used();
 #endif //SNMM
 void extr_unload();
 
-typedef enum
+enum class FilamentAction : uint_least8_t
 {
-    e_FILAMENT_ACTION_none, //!< 'none' state is used as flag for (filament) autoLoad (i.e. opposite for 'autoLoad' state)
-    e_FILAMENT_ACTION_Load,
-    e_FILAMENT_ACTION_autoLoad,
-    e_FILAMENT_ACTION_unLoad,
-    e_FILAMENT_ACTION_mmuLoad,
-    e_FILAMENT_ACTION_mmuUnLoad,
-    e_FILAMENT_ACTION_mmuEject,
-    e_FILAMENT_ACTION_mmuCut,
-} eFILAMENT_ACTION;
-extern eFILAMENT_ACTION eFilamentAction;
+    None, //!< 'none' state is used as flag for (filament) autoLoad (i.e. opposite for 'autoLoad' state)
+    Load,
+    AutoLoad,
+    UnLoad,
+    MmuLoad,
+    MmuUnLoad,
+    MmuEject,
+    MmuCut,
+};
+
+extern FilamentAction eFilamentAction;
 extern bool bFilamentFirstRun;
 extern bool bFilamentPreheatState;
 extern bool bFilamentAction;

+ 43 - 0
Firmware/util.cpp

@@ -327,3 +327,46 @@ void update_current_firmware_version_to_eeprom()
         eeprom_update_word((uint16_t*)EEPROM_FIRMWARE_VERSION_FLAVOR,   ver_current[3]);
     }
 }
+
+
+//-//
+eNOZZLE_DIAMETER eNozzleDiameter=e_NOZZLE_DIAMETER_400;
+eCHECK_MODE eCheckMode=e_CHECK_MODE_none;
+
+void fCheckModeInit()
+{
+eCheckMode=(eCHECK_MODE)eeprom_read_byte((uint8_t*)EEPROM_CHECK_MODE);
+if(eCheckMode==e_CHECK_MODE_NULL)
+     {
+     eCheckMode=e_CHECK_MODE_warn;
+     eeprom_update_byte((uint8_t*)EEPROM_CHECK_MODE,(uint8_t)eCheckMode);
+     }
+if(farm_mode)
+     eCheckMode=e_CHECK_MODE_strict;
+eNozzleDiameter=(eNOZZLE_DIAMETER)eeprom_read_byte((uint8_t*)EEPROM_NOZZLE_DIAMETER);
+if((eNozzleDiameter==e_NOZZLE_DIAMETER_NULL)&& !farm_mode)
+     {
+     eNozzleDiameter=e_NOZZLE_DIAMETER_400;
+     eeprom_update_byte((uint8_t*)EEPROM_NOZZLE_DIAMETER,(uint8_t)eNozzleDiameter);
+     eeprom_update_word((uint16_t*)EEPROM_NOZZLE_DIAMETER_uM,400);
+     }
+}
+
+void nozzle_diameter_check(uint16_t nDiameter)
+{
+uint16_t nDiameter_um;
+
+nDiameter_um=eeprom_read_word((uint16_t*)EEPROM_NOZZLE_DIAMETER_uM);
+if(nDiameter==nDiameter_um)
+     return;
+switch(eCheckMode)
+     {
+     case e_CHECK_MODE_warn:
+          lcd_show_fullscreen_message_and_wait_P(_i("Nozzle diameter doesn't match! Press the knob to continue."));
+          break;
+     case e_CHECK_MODE_strict:
+          lcd_show_fullscreen_message_and_wait_P(_i("Nozzle diameter doesn't match! Print is aborted, press the knob."));
+          lcd_print_stop();
+          break;
+     }
+}

+ 25 - 0
Firmware/util.h

@@ -33,4 +33,29 @@ inline void eeprom_update_int8(unsigned char* addr, int8_t v) {
 	eeprom_update_byte(addr, *reinterpret_cast<uint8_t*>(&v));
 }
 
+
+//-//
+#define e_CHECK_MODE_NULL 0xFF
+#define e_NOZZLE_DIAMETER_NULL 0xFF
+
+typedef enum
+{
+    e_NOZZLE_DIAMETER_250,
+    e_NOZZLE_DIAMETER_400,
+    e_NOZZLE_DIAMETER_600
+} eNOZZLE_DIAMETER;
+
+typedef enum
+{
+    e_CHECK_MODE_none,
+    e_CHECK_MODE_warn,
+    e_CHECK_MODE_strict
+} eCHECK_MODE;
+
+extern eNOZZLE_DIAMETER eNozzleDiameter;
+extern eCHECK_MODE eCheckMode;
+
+void fCheckModeInit();
+void nozzle_diameter_check(uint16_t nDiameter);
+
 #endif /* UTIL_H */

+ 2 - 1
Firmware/variants/1_75mm_MK2-RAMBo10a-E3Dv6full.h

@@ -315,7 +315,7 @@ PREHEAT SETTINGS
 *------------------------------------*/
 
 #define FARM_PREHEAT_HOTEND_TEMP 250
-#define FARM_PREHEAT_HPB_TEMP 40
+#define FARM_PREHEAT_HPB_TEMP 80
 #define FARM_PREHEAT_FAN_SPEED 0
 
 #define PLA_PREHEAT_HOTEND_TEMP 215
@@ -438,6 +438,7 @@ THERMISTORS SETTINGS
 // Safety timer
 #define SAFETYTIMER
 #define DEFAULT_SAFETYTIMER_TIME_MINS 30
+#define FARM_DEFAULT_SAFETYTIMER_TIME_ms (45*60*1000ul)
 
 #define M600_TIMEOUT 600  //seconds
 

+ 2 - 1
Firmware/variants/1_75mm_MK2-RAMBo13a-E3Dv6full.h

@@ -314,7 +314,7 @@ PREHEAT SETTINGS
 *------------------------------------*/
 
 #define FARM_PREHEAT_HOTEND_TEMP 250
-#define FARM_PREHEAT_HPB_TEMP 40
+#define FARM_PREHEAT_HPB_TEMP 80
 #define FARM_PREHEAT_FAN_SPEED 0
 
 #define PLA_PREHEAT_HOTEND_TEMP 215
@@ -437,6 +437,7 @@ THERMISTORS SETTINGS
 // Safety timer
 #define SAFETYTIMER
 #define DEFAULT_SAFETYTIMER_TIME_MINS 30
+#define FARM_DEFAULT_SAFETYTIMER_TIME_ms (45*60*1000ul)
 
 #define M600_TIMEOUT 600  //seconds
 

+ 2 - 1
Firmware/variants/1_75mm_MK25-RAMBo10a-E3Dv6full.h

@@ -112,6 +112,7 @@
 // Safety timer
 #define SAFETYTIMER
 #define DEFAULT_SAFETYTIMER_TIME_MINS 30
+#define FARM_DEFAULT_SAFETYTIMER_TIME_ms (45*60*1000ul)
 
 // Filament sensor
 #define FILAMENT_SENSOR
@@ -371,7 +372,7 @@
  *------------------------------------*/
 
 #define FARM_PREHEAT_HOTEND_TEMP 250
-#define FARM_PREHEAT_HPB_TEMP 40
+#define FARM_PREHEAT_HPB_TEMP 80
 #define FARM_PREHEAT_FAN_SPEED 0
 
 #define PLA_PREHEAT_HOTEND_TEMP 215

+ 2 - 1
Firmware/variants/1_75mm_MK25-RAMBo13a-E3Dv6full.h

@@ -113,6 +113,7 @@
 // Safety timer
 #define SAFETYTIMER
 #define DEFAULT_SAFETYTIMER_TIME_MINS 30
+#define FARM_DEFAULT_SAFETYTIMER_TIME_ms (45*60*1000ul)
 
 // Filament sensor
 #define FILAMENT_SENSOR
@@ -372,7 +373,7 @@
  *------------------------------------*/
 
 #define FARM_PREHEAT_HOTEND_TEMP 250
-#define FARM_PREHEAT_HPB_TEMP 40
+#define FARM_PREHEAT_HPB_TEMP 80
 #define FARM_PREHEAT_FAN_SPEED 0
 
 #define PLA_PREHEAT_HOTEND_TEMP 215

+ 9 - 1
Firmware/variants/1_75mm_MK25S-RAMBo10a-E3Dv6full.h

@@ -112,6 +112,7 @@
 // Safety timer
 #define SAFETYTIMER
 #define DEFAULT_SAFETYTIMER_TIME_MINS 30
+#define FARM_DEFAULT_SAFETYTIMER_TIME_ms (45*60*1000ul)
 
 // Filament sensor
 #define FILAMENT_SENSOR
@@ -371,7 +372,7 @@
  *------------------------------------*/
 
 #define FARM_PREHEAT_HOTEND_TEMP 250
-#define FARM_PREHEAT_HPB_TEMP 40
+#define FARM_PREHEAT_HPB_TEMP 80
 #define FARM_PREHEAT_FAN_SPEED 0
 
 #define PLA_PREHEAT_HOTEND_TEMP 215
@@ -505,6 +506,13 @@
 #define MMU_DEBUG //print communication between MMU2 and printer on serial
 //#define MMU_HAS_CUTTER
 
+// This is experimental feature requested by our test department.
+// There is no known use for ordinary user. If enabled by this macro
+// and enabled from printer menu (not enabled by default). It cuts filament
+// every time when switching filament from gcode. MMU_HAS_CUTTER needs to be
+// defined.
+
+//#define MMU_ALWAYS_CUT
 #define MMU_IDLER_SENSOR_ATTEMPTS_NR 21 //max. number of attempts to load filament if first load failed; value for max bowden length and case when loading fails right at the beginning
 
 #endif //__CONFIGURATION_PRUSA_H

+ 9 - 1
Firmware/variants/1_75mm_MK25S-RAMBo13a-E3Dv6full.h

@@ -113,6 +113,7 @@
 // Safety timer
 #define SAFETYTIMER
 #define DEFAULT_SAFETYTIMER_TIME_MINS 30
+#define FARM_DEFAULT_SAFETYTIMER_TIME_ms (45*60*1000ul)
 
 // Filament sensor
 #define FILAMENT_SENSOR
@@ -372,7 +373,7 @@
  *------------------------------------*/
 
 #define FARM_PREHEAT_HOTEND_TEMP 250
-#define FARM_PREHEAT_HPB_TEMP 40
+#define FARM_PREHEAT_HPB_TEMP 80
 #define FARM_PREHEAT_FAN_SPEED 0
 
 #define PLA_PREHEAT_HOTEND_TEMP 215
@@ -506,6 +507,13 @@
 #define MMU_DEBUG //print communication between MMU2 and printer on serial
 //#define MMU_HAS_CUTTER
 
+// This is experimental feature requested by our test department.
+// There is no known use for ordinary user. If enabled by this macro
+// and enabled from printer menu (not enabled by default). It cuts filament
+// every time when switching filament from gcode. MMU_HAS_CUTTER needs to be
+// defined.
+
+//#define MMU_ALWAYS_CUT
 #define MMU_IDLER_SENSOR_ATTEMPTS_NR 21 //max. number of attempts to load filament if first load failed; value for max bowden length and case when loading fails right at the beginning
 
 #endif //__CONFIGURATION_PRUSA_H

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

@@ -131,6 +131,7 @@
 // Safety timer
 #define SAFETYTIMER
 #define DEFAULT_SAFETYTIMER_TIME_MINS 30
+#define FARM_DEFAULT_SAFETYTIMER_TIME_ms (45*60*1000ul)
 
 // Filament sensor
 #define FILAMENT_SENSOR
@@ -480,7 +481,7 @@
  *------------------------------------*/
 
 #define FARM_PREHEAT_HOTEND_TEMP 250
-#define FARM_PREHEAT_HPB_TEMP 60
+#define FARM_PREHEAT_HPB_TEMP 80
 #define FARM_PREHEAT_FAN_SPEED 0
 
 #define PLA_PREHEAT_HOTEND_TEMP 215

+ 10 - 1
Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h

@@ -131,6 +131,7 @@
 // Safety timer
 #define SAFETYTIMER
 #define DEFAULT_SAFETYTIMER_TIME_MINS 30
+#define FARM_DEFAULT_SAFETYTIMER_TIME_ms (45*60*1000ul)
 
 // Filament sensor
 #define FILAMENT_SENSOR
@@ -480,7 +481,7 @@
  *------------------------------------*/
 
 #define FARM_PREHEAT_HOTEND_TEMP 250
-#define FARM_PREHEAT_HPB_TEMP 60
+#define FARM_PREHEAT_HPB_TEMP 80
 #define FARM_PREHEAT_FAN_SPEED 0
 
 #define PLA_PREHEAT_HOTEND_TEMP 215
@@ -627,6 +628,14 @@
 #define MMU_HWRESET
 #define MMU_DEBUG //print communication between MMU2 and printer on serial
 //#define MMU_HAS_CUTTER
+
+// This is experimental feature requested by our test department.
+// There is no known use for ordinary user. If enabled by this macro
+// and enabled from printer menu (not enabled by default). It cuts filament
+// every time when switching filament from gcode. MMU_HAS_CUTTER needs to be
+// defined.
+
+//#define MMU_ALWAYS_CUT
 #define MMU_IDLER_SENSOR_ATTEMPTS_NR 21 //max. number of attempts to load filament if first load failed; value for max bowden length and case when loading fails right at the beginning
 
 #endif //__CONFIGURATION_PRUSA_H