Browse Source

Merge branch 'MK3' into MK3_fix_selftest_Z_crash2

Alex Voinea 4 years ago
parent
commit
2e50954710
64 changed files with 5126 additions and 3398 deletions
  1. 14 0
      .editorconfig
  2. 31 0
      .github/ISSUE_TEMPLATE/bug_report.md
  3. 20 0
      .github/ISSUE_TEMPLATE/enhancement.md
  4. 20 0
      .github/ISSUE_TEMPLATE/feature_request.md
  5. 12 0
      .github/ISSUE_TEMPLATE/question.md
  6. 9 3
      Firmware/Configuration.h
  7. 2 2
      Firmware/ConfigurationStore.cpp
  8. 20 34
      Firmware/Configuration_adv.h
  9. 144 0
      Firmware/Dcodes.cpp
  10. 7 5
      Firmware/Marlin.h
  11. 1778 750
      Firmware/Marlin_main.cpp
  12. 16 0
      Firmware/Sd2Card.cpp
  13. 2 0
      Firmware/Sd2Card.h
  14. 3 2
      Firmware/adc.c
  15. 120 0
      Firmware/backlight.cpp
  16. 32 0
      Firmware/backlight.h
  17. 41 52
      Firmware/cardreader.cpp
  18. 3 5
      Firmware/cardreader.h
  19. 33 24
      Firmware/cmdqueue.cpp
  20. 13 4
      Firmware/config.h
  21. 14 2
      Firmware/eeprom.h
  22. 138 57
      Firmware/fsensor.cpp
  23. 36 6
      Firmware/fsensor.h
  24. 48 0
      Firmware/la10compat.cpp
  25. 39 0
      Firmware/la10compat.h
  26. 3 3
      Firmware/language.c
  27. 48 10
      Firmware/menu.cpp
  28. 6 1
      Firmware/menu.h
  29. 51 14
      Firmware/messages.c
  30. 48 13
      Firmware/messages.h
  31. 19 23
      Firmware/mmu.cpp
  32. 1 0
      Firmware/mmu.h
  33. 2 2
      Firmware/optiboot_w25x20cl.cpp
  34. 3 2
      Firmware/pins_Einsy_1_0.h
  35. 170 70
      Firmware/planner.cpp
  36. 19 6
      Firmware/planner.h
  37. 7 0
      Firmware/sound.cpp
  38. 0 6
      Firmware/sound.h
  39. 147 0
      Firmware/speed_lookuptable.cpp
  40. 112 139
      Firmware/speed_lookuptable.h
  41. 289 384
      Firmware/stepper.cpp
  42. 1 15
      Firmware/stepper.h
  43. 15 3
      Firmware/temperature.cpp
  44. 5 0
      Firmware/temperature.h
  45. 8 8
      Firmware/tmc2130.cpp
  46. 594 353
      Firmware/ultralcd.cpp
  47. 14 0
      Firmware/ultralcd.h
  48. 1 1
      Firmware/variants/1_75mm_MK25-RAMBo10a-E3Dv6full.h
  49. 1 1
      Firmware/variants/1_75mm_MK25-RAMBo13a-E3Dv6full.h
  50. 1 1
      Firmware/variants/1_75mm_MK25S-RAMBo10a-E3Dv6full.h
  51. 1 1
      Firmware/variants/1_75mm_MK25S-RAMBo13a-E3Dv6full.h
  52. 4 2
      Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h
  53. 4 2
      Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h
  54. 61 56
      PF-build.sh
  55. 1 0
      README.md
  56. 2 3
      Tests/PrusaStatistics_test.cpp
  57. 1 1
      lang/lang-add.sh
  58. 92 141
      lang/lang_en.txt
  59. 132 196
      lang/lang_en_cz.txt
  60. 136 201
      lang/lang_en_de.txt
  61. 135 199
      lang/lang_en_es.txt
  62. 131 199
      lang/lang_en_fr.txt
  63. 132 197
      lang/lang_en_it.txt
  64. 134 199
      lang/lang_en_pl.txt

+ 14 - 0
.editorconfig

@@ -0,0 +1,14 @@
+#-*-mode:conf-*-
+# editorconfig file (see EditorConfig.org)
+
+root                        = true
+
+[*]
+end_of_line                 = lf
+insert_final_newline        = true
+charset                     = utf-8
+trim_trailing_whitespace    = true
+indent_style                = space
+indent_size                 = 4
+tab_width                   = 4
+max_line_length             = 100

+ 31 - 0
.github/ISSUE_TEMPLATE/bug_report.md

@@ -0,0 +1,31 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: "[BUG]<Enter comprehensive title>"
+labels: bug
+assignees: ''
+
+---
+
+Please, before you create a new bug report, please make sure you searched in open and closed issues and couldn't find anything that matches.
+
+**Printer type** - [e.g. MK3S, MK3, MK2.5S, MK2.5, MK2S, MK2]
+**Printer firmware version**-  [e.g. 3.8.1, 3.8.1-RC1, ...]
+
+**MMU Upgrade** - [e.g. MMU2S, MMU2, MMU1]
+**MMU upgrade firmware version [e.g. 1.0.6, 1.0.6-RC2, ...]
+
+**Describe the bug**
+  A clear and concise description of what the bug is.
+  
+**To Reproduce**
+  Please describe steps to reproduce the behavior.
+  
+**Expected behavior**
+  A clear and concise description of what you expected to happen.
+  
+**G-code**
+  Please attach a G-code. This will make it easier for us to replicate the error.
+
+**Video**
+  Please attach a video. It usually helps to solve the problem.

+ 20 - 0
.github/ISSUE_TEMPLATE/enhancement.md

@@ -0,0 +1,20 @@
+---
+name: Enhancement
+about: Suggest an idea for this project
+title: "  [ENHANCEMENT]<Enter comprehensive title>"
+labels: enhancement
+assignees: ''
+
+---
+
+Please, before you create a new feature request, please make sure you searched in open and closed issues and couldn't find anything that matches.
+
+Enter what type of printer or upgrade the enhancement applies to.
+**Printer type** - [e.g. MK3S, MK3, MK2.5S, MK2.5, MK2S, MK2]
+**MMU Upgrade** - [e.g. MMU2S, MMU2, MMU1]
+
+**Is your enhancement related to a problem? Please describe.**
+  A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+  
+**Describe the solution you'd like**
+  A clear and concise description of what you want to happen.

+ 20 - 0
.github/ISSUE_TEMPLATE/feature_request.md

@@ -0,0 +1,20 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: "[FEATURE REQUEST]<Enter comprehensive title>"
+labels: feature request
+assignees: ''
+
+---
+
+Please, before you create a new feature request, please make sure you searched in open and closed issues and couldn't find anything that matches.
+
+If it makes sense, enter what type of printer or upgrade the feature request applies to.
+**Printer type** - [e.g. MK3S, MK3, MK2.5S, MK2.5, MK2S, MK2]
+**MMU Upgrade** - [e.g. MMU2S, MMU2, MMU1]
+
+**Is your feature request related to a problem? Please describe.**
+  A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+  
+**Describe the solution you'd like**
+  A clear and concise description of what you want to happen.

+ 12 - 0
.github/ISSUE_TEMPLATE/question.md

@@ -0,0 +1,12 @@
+---
+name: Question
+about: What do you want to know?
+title: "[QUESTION]<Enter comprehensive title>"
+labels: question
+assignees: ''
+
+---
+
+Please, before you create a new question, please make sure you searched in open and closed issues and couldn't find anything that matches.
+
+**What is your question?**

+ 9 - 3
Firmware/Configuration.h

@@ -16,8 +16,8 @@ extern uint16_t nPrinterType;
 extern PGM_P sPrinterName;
 
 // Firmware version
-#define FW_VERSION "3.8.1-RC1"
-#define FW_COMMIT_NR   2851
+#define FW_VERSION "3.9.0"
+#define FW_COMMIT_NR   3175
 // FW_VERSION_UNKNOWN means this is an unofficial build.
 // The firmware should only be checked into github with this symbol.
 #define FW_DEV_VERSION FW_VERSION_UNKNOWN
@@ -345,7 +345,7 @@ your extruder heater takes 2 minutes to hit the target on heating.
   #define Y_PROBE_OFFSET_FROM_EXTRUDER -29
   #define Z_PROBE_OFFSET_FROM_EXTRUDER -12.35
 
-  #define Z_RAISE_BEFORE_HOMING 4       // (in mm) Raise Z before homing (G28) for Probe Clearance.
+  #define Z_RAISE_BEFORE_HOMING 5       // (in mm) Raise Z before homing (G28) for Probe Clearance.
                                         // Be sure you have this distance over your Z_MAX_POS in case
 
   #define XY_TRAVEL_SPEED 8000         // X and Y axis travel speed between probes, in mm/min
@@ -549,6 +549,12 @@ enum CalibrationStatus
     CALIBRATION_STATUS_UNKNOWN = 0,
 };
 
+// Try to maintain a minimum distance from the bed even when Z is
+// unknown when doing the following operations
+#define MIN_Z_FOR_LOAD    50
+#define MIN_Z_FOR_UNLOAD  20
+#define MIN_Z_FOR_PREHEAT 10
+
 #include "Configuration_adv.h"
 #include "thermistortables.h"
 

+ 2 - 2
Firmware/ConfigurationStore.cpp

@@ -165,8 +165,8 @@ void Config_PrintSettings(uint8_t level)
 #endif
 	if (level >= 10) {
 #ifdef LIN_ADVANCE
-		printf_P(PSTR("%SLinear advance settings:\n   M900 K%.2f   E/D = %.2f\n"),
-			echomagic, extruder_advance_k, advance_ed_ratio);
+		printf_P(PSTR("%SLinear advance settings:%S   M900 K%.2f\n"),
+                 echomagic, echomagic, extruder_advance_K);
 #endif //LIN_ADVANCE
 	}
 }

+ 20 - 34
Firmware/Configuration_adv.h

@@ -268,43 +268,29 @@
 #endif
 
 /**
-    * Implementation of linear pressure control
-    *
-    * Assumption: advance = k * (delta velocity)
-    * K=0 means advance disabled.
-    * See Marlin documentation for calibration instructions.
-    */
+ * Linear Pressure Control v1.5
+ *
+ * Assumption: advance [steps] = k * (delta velocity [steps/s])
+ * K=0 means advance disabled.
+ *
+ * NOTE: K values for LIN_ADVANCE 1.5 differs from earlier versions!
+ *
+ * Set K around 0.22 for 3mm PLA Direct Drive with ~6.5cm between the drive gear and heatbreak.
+ * Larger K values will be needed for flexible filament and greater distances.
+ * If this algorithm produces a higher speed offset than the extruder can handle (compared to E jerk)
+ * print acceleration will be reduced during the affected moves to keep within the limit.
+ *
+ * See http://marlinfw.org/docs/features/lin_advance.html for full instructions.
+ * Mention @Sebastianv650 on GitHub to alert the author of any issues.
+ */
 #define LIN_ADVANCE
 
 #ifdef LIN_ADVANCE
-  #define LIN_ADVANCE_K 0 //Try around 45 for PLA, around 25 for ABS.
-
- /**
-        * Some Slicers produce Gcode with randomly jumping extrusion widths occasionally.
-        * For example within a 0.4mm perimeter it may produce a single segment of 0.05mm width.
-        * While this is harmless for normal printing (the fluid nature of the filament will
-        * close this very, very tiny gap), it throws off the LIN_ADVANCE pressure adaption.
-        *
-        * For this case LIN_ADVANCE_E_D_RATIO can be used to set the extrusion:distance ratio
-        * to a fixed value. Note that using a fixed ratio will lead to wrong nozzle pressures
-        * if the slicer is using variable widths or layer heights within one print!
-        *
-        * This option sets the default E:D ratio at startup. Use `M900` to override this value.
-        *
-        * Example: `M900 W0.4 H0.2 D1.75`, where:
-        *   - W is the extrusion width in mm
-        *   - H is the layer height in mm
-        *   - D is the filament diameter in mm
-        *
-        * Example: `M900 R0.0458` to set the ratio directly.
-        *
-        * Set to 0 to auto-detect the ratio based on given Gcode G1 print moves.
-        *
-        * Slic3r (including Prusa Slic3r) produces Gcode compatible with the automatic mode.
-        * Cura (as of this writing) may produce Gcode incompatible with the automatic mode.
-        */
-#define LIN_ADVANCE_E_D_RATIO 0 // The calculated ratio (or 0) according to the formula W * H / ((D / 2) ^ 2 * PI)
-                                // Example: 0.4 * 0.2 / ((1.75 / 2) ^ 2 * PI) = 0.033260135
+  #define LIN_ADVANCE_K 0  // Unit: mm compression per 1mm/s extruder speed
+  //#define LA_NOCOMPAT    // Disable Linear Advance 1.0 compatibility
+  //#define LA_LIVE_K      // Allow adjusting K in the Tune menu
+  //#define LA_DEBUG       // If enabled, this will generate debug information output over USB.
+  //#define LA_DEBUG_LOGIC // @wavexx: setup logic channels for isr debugging
 #endif
 
 // Arc interpretation settings:

+ 144 - 0
Firmware/Dcodes.cpp

@@ -99,6 +99,18 @@ void print_mem(uint32_t address, uint16_t count, uint8_t type, uint8_t countperl
 
 #ifdef DEBUG_DCODE3
 #define EEPROM_SIZE 0x1000
+    /*!
+    *
+    ### D3 - Read/Write EEPROM <a href="https://reprap.org/wiki/G-code#D3:_Read.2FWrite_EEPROM">D3: Read/Write EEPROM</a>
+    This command can be used without any additional parameters. It will read the entire eeprom.
+      
+          D3 [ A | C | X ]
+      
+      - `A` - Address (0x0000-0x0fff)
+      - `C` - Count (0x0001-0x1000)
+      - `X` - Data
+    *
+    */
 void dcode_3()
 {
 	DBG(_N("D3 - Read/Write EEPROM\n"));
@@ -176,6 +188,14 @@ extern float axis_steps_per_unit[NUM_AXIS];
 #endif //0
 #define LOG(args...)
 
+    /*!
+    *
+    ### D-1 - Endless Loop <a href="https://reprap.org/wiki/G-code#G28:_Move_to_Origin_.28Home.29">D-1: Endless Loop</a>
+      
+          D-1
+      
+    *
+    */
 void dcode__1()
 {
 	printf_P(PSTR("D-1 - Endless loop\n"));
@@ -185,6 +205,15 @@ void dcode__1()
 
 #ifdef DEBUG_DCODES
 
+    /*!
+    *
+    ### D0 - Reset <a href="https://reprap.org/wiki/G-code#D0:_Reset">D0: Reset</a>
+      
+          D0 [ B ]
+      
+      - `B` - Bootloader
+    *
+    */
 void dcode_0()
 {
 	if (*(strchr_pointer + 1) == 0) return;
@@ -203,6 +232,14 @@ void dcode_0()
 	}
 }
 
+    /*!
+    *
+    ### D1 - Clear EEPROM and RESET <a href="https://reprap.org/wiki/G-code#D1:_Clear_EEPROM_and_RESET">D1: Clear EEPROM and RESET</a>
+      
+          D1
+      
+    *
+    */
 void dcode_1()
 {
 	LOG("D1 - Clear EEPROM and RESET\n");
@@ -213,6 +250,18 @@ void dcode_1()
 	while(1);
 }
 
+    /*!
+    *
+    ### D2 - Read/Write RAM <a href="https://reprap.org/wiki/G-code#D2:_Read.2FWrite_RAM">D3: Read/Write RAM</a>
+    This command can be used without any additional parameters. It will read the entire RAM.
+      
+          D3 [ A | C | X ]
+      
+      - `A` - Address (0x0000-0x1fff)
+      - `C` - Count (0x0001-0x2000)
+      - `X` - Data
+    *
+    */
 void dcode_2()
 {
 	LOG("D2 - Read/Write RAM\n");
@@ -256,6 +305,19 @@ void dcode_2()
 	}*/
 }
 
+    /*!
+    *
+    ### D4 - Read/Write PIN <a href="https://reprap.org/wiki/G-code#D4:_Read.2FWrite_PIN">D4: Read/Write PIN</a>
+    
+    To read the digital value of a pin you need only to define the pin number.
+      
+          D4 [ P | F | V ]
+      
+      - `P` - Pin (0-255)
+      - `F` - Function in/out (0/1)
+      - `V` - Value (0/1)
+    *
+    */
 void dcode_4()
 {
 	LOG("D4 - Read/Write PIN\n");
@@ -288,6 +350,19 @@ void dcode_4()
 
 #ifdef DEBUG_DCODE5
 
+    /*!
+    *
+    ### D5 - Read/Write FLASH <a href="https://reprap.org/wiki/G-code#D5:_Read.2FWrite_FLASH">D5: Read/Write Flash</a>
+    This command can be used without any additional parameters. It will read the 1kb FLASH.
+      
+          D3 [ A | C | X | E ]
+      
+      - `A` - Address (0x00000-0x3ffff)
+      - `C` - Count (0x0001-0x2000)
+      - `X` - Data
+      - `E` - Erase
+    *
+    */
 void dcode_5()
 {
 	printf_P(PSTR("D5 - Read/Write FLASH\n"));
@@ -351,11 +426,25 @@ void dcode_5()
 
 #ifdef DEBUG_DCODES
 
+    /*!
+    *
+    ### D6 - Read/Write external FLASH <a href="https://reprap.org/wiki/G-code#D6:_Read.2FWrite_external_FLASH">D6: Read/Write external Flash</a>
+    
+    Reserved
+   *
+   */
 void dcode_6()
 {
 	LOG("D6 - Read/Write external FLASH\n");
 }
 
+    /*!
+    *
+    ### D7 - Read/Write Bootloader <a href="https://reprap.org/wiki/G-code#D7:_Read.2FWrite_Bootloader">D7: Read/Write Bootloader</a>
+    
+    Reserved
+   *
+   */
 void dcode_7()
 {
 	LOG("D7 - Read/Write Bootloader\n");
@@ -371,6 +460,18 @@ void dcode_7()
 */
 }
 
+    /*!
+    *
+    ### D8 - Read/Write PINDA <a href="https://reprap.org/wiki/G-code#D8:_Read.2FWrite_PINDA">D8: Read/Write PINDA</a>
+      
+          D8 [ ? | ! | P | Z ]
+      
+      - `?` - Read PINDA temperature shift values
+      - `!` - Reset PINDA temperature shift values to default
+      - `P` - Pinda temperature [C]
+      - `Z` - Z Offset [mm]
+    *
+    */
 void dcode_8()
 {
 	printf_P(PSTR("D8 - Read/Write PINDA\n"));
@@ -412,6 +513,23 @@ void dcode_8()
 	printf_P(PSTR("temp_pinda=%d offset_z=%d.%03d\n"), (int)temp_pinda, (int)offset_z, ((int)(1000 * offset_z) % 1000));
 }
 
+    /*!
+    *
+    ### D9 - Read ADC <a href="https://reprap.org/wiki/G-code#D9:_Read.2FWrite_ADC">D9: Read ADC</a>
+      
+          D9 [ I | V ]
+      
+      - `I` - ADC channel index 
+         - `0` - Heater 0 temperature
+         - `1` - Heater 1 temperature
+         - `2` - Bed temperature
+         - `3` - PINDA temperature
+         - `4` - PWR voltage
+         - `5` - Ambient temperature
+         - `6` - BED voltage
+      - `V` Value to be written as simulated
+    *
+    */
 const char* dcode_9_ADC_name(uint8_t i)
 {
 	switch (i)
@@ -485,12 +603,24 @@ void dcode_9()
 	}
 }
 
+    /*!
+    *
+    ### D10 - Set XYZ calibration = OK <a href="https://reprap.org/wiki/G-code#D10:_Set_XYZ_calibration_.3D_OK">D10: Set XYZ calibration = OK</a>
+    
+   *
+   */
 void dcode_10()
 {//Tell the printer that XYZ calibration went OK
 	LOG("D10 - XYZ calibration = OK\n");
 	calibration_status_store(CALIBRATION_STATUS_LIVE_ADJUST); 
 }
 
+    /*!
+    *
+    ### D12 - Time <a href="https://reprap.org/wiki/G-code#D12:_Time">D12: Time</a>
+    
+   *
+   */
 void dcode_12()
 {//Time
 	LOG("D12 - Time\n");
@@ -636,6 +766,20 @@ void dcode_2130()
 #endif //TMC2130
 
 #ifdef PAT9125
+    /*!
+    *
+    ### D9125 - PAT9125 filament sensor <a href="https://reprap.org/wiki/G-code#D9:_Read.2FWrite_ADC">D9125: PAT9125 filament sensor</a>
+      
+          D9125 [ ? | ! | R | X | Y | L ]
+      
+      - `?` - Print values
+      - `!` - Print values
+      - `R` - Resolution. Not active in code
+      - `X` - X values
+      - `Y` - Y values
+      - `L` - Activate filament sensor log
+    *
+    */
 void dcode_9125()
 {
 	LOG("D9125 - PAT9125\n");

+ 7 - 5
Firmware/Marlin.h

@@ -296,6 +296,7 @@ void setPwmFrequency(uint8_t pin, int val);
 extern bool fans_check_enabled;
 extern float homing_feedrate[];
 extern bool axis_relative_modes[];
+extern float feedrate;
 extern int feedmultiply;
 extern int extrudemultiply; // Sets extrude multiply factor (in percent) for all extruders
 extern int extruder_multiply[EXTRUDERS]; // sets extrude multiply factor (in percent) for each extruder individually
@@ -307,6 +308,7 @@ extern float max_pos[3];
 extern bool axis_known_position[3];
 extern int fanSpeed;
 extern int8_t lcd_change_fil_state;
+extern float default_retraction;
 
 #ifdef TMC2130
 bool homeaxis(int axis, bool doError = 1, uint8_t cnt = 1, uint8_t* pstep = 0);
@@ -358,9 +360,6 @@ extern int fan_speed[2];
 // Handling multiple extruders pins
 extern uint8_t active_extruder;
 
-
-#endif
-
 //Long pause
 extern unsigned long pause_time;
 extern unsigned long start_pause_print;
@@ -398,7 +397,7 @@ extern uint16_t gcode_in_progress;
 extern LongTimer safetyTimer;
 
 #define PRINT_PERCENT_DONE_INIT   0xff
-#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)
+#define PRINTER_ACTIVE (IS_SD_PRINTING || is_usb_printing || isPrintPaused || (custom_message_type == CustomMsg::TempCal) || saved_printing || (lcd_commands_type == LcdCommands::Layer1Cal) || 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
@@ -457,6 +456,7 @@ extern void print_mesh_bed_leveling_table();
 
 extern void stop_and_save_print_to_ram(float z_move, float e_move);
 extern void restore_print_from_ram_and_continue(float e_move);
+extern void cancel_saved_printing();
 
 
 //estimated time to end of the print
@@ -513,4 +513,6 @@ void M600_wait_for_user(float HotendTempBckp);
 void M600_check_state(float nozzle_temp);
 void load_filament_final_feed();
 void marlin_wait_for_click();
-void marlin_rise_z(void);
+void raise_z_above(float target, bool plan=true);
+
+#endif

+ 1778 - 750
Firmware/Marlin_main.cpp

@@ -63,6 +63,7 @@
 
 #include "menu.h"
 #include "ultralcd.h"
+#include "backlight.h"
 
 #include "planner.h"
 #include "stepper.h"
@@ -82,6 +83,9 @@
 #include "Dcodes.h"
 #include "AutoDeplete.h"
 
+#ifndef LA_NOCOMPAT
+#include "la10compat.h"
+#endif
 
 #ifdef SWSPI
 #include "swspi.h"
@@ -309,6 +313,8 @@ bool no_response = false;
 uint8_t important_status;
 uint8_t saved_filament_type;
 
+#define SAVED_TARGET_UNSET (X_MIN_POS-1)
+float saved_target[NUM_AXIS] = {SAVED_TARGET_UNSET, 0, 0, 0};
 
 // save/restore printing in case that mmu was not responding 
 bool mmu_print_saved = false;
@@ -329,11 +335,15 @@ float destination[NUM_AXIS] = {  0.0, 0.0, 0.0, 0.0};
 
 // For tracing an arc
 static float offset[3] = {0.0, 0.0, 0.0};
-static float feedrate = 1500.0, next_feedrate, saved_feedrate;
 
-// Determines Absolute or Relative Coordinates.
-// Also there is bool axis_relative_modes[] per axis flag.
-static bool relative_mode = false;  
+// Current feedrate
+float feedrate = 1500.0;
+
+// Feedrate for the next move
+static float next_feedrate;
+
+// Original feedrate saved during homing moves
+static float saved_feedrate;
 
 const int sensitive_pins[] = SENSITIVE_PINS; // Sensitive pin list for M42
 
@@ -350,9 +360,6 @@ unsigned long starttime=0;
 unsigned long stoptime=0;
 unsigned long _usb_timer = 0;
 
-bool extruder_under_pressure = true;
-
-
 bool Stopped=false;
 
 #if NUM_SERVOS > 0
@@ -373,11 +380,10 @@ bool saved_printing = false; //!< Print is paused and saved in RAM
 static uint32_t saved_sdpos = 0; //!< SD card position, or line number in case of USB printing
 uint8_t saved_printing_type = PRINTING_TYPE_SD;
 static float saved_pos[4] = { 0, 0, 0, 0 };
-//! Feedrate hopefully derived from an active block of the planner at the time the print has been canceled, in mm/min.
-static float saved_feedrate2 = 0;
+static uint16_t saved_feedrate2 = 0; //!< Default feedrate (truncated from float)
+static int saved_feedmultiply2 = 0;
 static uint8_t saved_active_extruder = 0;
 static float saved_extruder_temperature = 0.0; //!< Active extruder temperature
-static bool saved_extruder_under_pressure = false;
 static bool saved_extruder_relative_mode = false;
 static int saved_fanSpeed = 0; //!< Print fan speed
 //! @}
@@ -989,10 +995,6 @@ void setup()
 
 	ultralcd_init();
 
-#if (LCD_BL_PIN != -1) && defined (LCD_BL_PIN)
-	analogWrite(LCD_BL_PIN, 255); //set full brightnes
-#endif //(LCD_BL_PIN != -1) && defined (LCD_BL_PIN)
-
 	spi_init();
 
 	lcd_splash();
@@ -1242,8 +1244,8 @@ void setup()
         // Once a firmware boots up, it forces at least a language selection, which changes
         // EEPROM_LANG to number lower than 0x0ff.
         // 1) Set a high power mode.
+	    eeprom_update_byte((uint8_t*)EEPROM_SILENT, SILENT_MODE_OFF);
 #ifdef TMC2130
-        eeprom_write_byte((uint8_t*)EEPROM_SILENT, 0);
         tmc2130_mode = TMC2130_MODE_NORMAL;
 #endif //TMC2130
         eeprom_write_byte((uint8_t*)EEPROM_WIZARD_ACTIVE, 1); //run wizard
@@ -2055,35 +2057,36 @@ static float probe_pt(float x, float y, float z_before) {
 
 #ifdef LIN_ADVANCE
    /**
-    * M900: Set and/or Get advance K factor and WH/D ratio
+    * M900: Set and/or Get advance K factor
     *
     *  K<factor>                  Set advance K factor
-    *  R<ratio>                   Set ratio directly (overrides WH/D)
-    *  W<width> H<height> D<diam> Set ratio from WH/D
     */
 inline void gcode_M900() {
-    st_synchronize();
-    
-    const float newK = code_seen('K') ? code_value_float() : -1;
-    if (newK >= 0) extruder_advance_k = newK;
-    
-    float newR = code_seen('R') ? code_value_float() : -1;
-    if (newR < 0) {
-        const float newD = code_seen('D') ? code_value_float() : -1,
-        newW = code_seen('W') ? code_value_float() : -1,
-        newH = code_seen('H') ? code_value_float() : -1;
-        if (newD >= 0 && newW >= 0 && newH >= 0)
-            newR = newD ? (newW * newH) / (sq(newD * 0.5) * M_PI) : 0;
+    float newK = code_seen('K') ? code_value_float() : -2;
+#ifdef LA_NOCOMPAT
+    if (newK >= 0 && newK < 10)
+        extruder_advance_K = newK;
+    else
+        SERIAL_ECHOLNPGM("K out of allowed range!");
+#else
+    if (newK == 0)
+        extruder_advance_K = 0;
+    else if (newK == -1)
+        la10c_reset();
+    else
+    {
+        newK = la10c_value(newK);
+        if (newK < 0)
+            SERIAL_ECHOLNPGM("K out of allowed range!");
+        else
+            extruder_advance_K = newK;
     }
-    if (newR >= 0) advance_ed_ratio = newR;
-    
+#endif
+
     SERIAL_ECHO_START;
     SERIAL_ECHOPGM("Advance K=");
-    SERIAL_ECHOLN(extruder_advance_k);
-    SERIAL_ECHOPGM(" E/D=");
-    const float ratio = advance_ed_ratio;
-    if (ratio) SERIAL_ECHOLN(ratio); else SERIAL_ECHOLNPGM("Auto");
-    }
+    SERIAL_ECHOLN(extruder_advance_K);
+}
 #endif // LIN_ADVANCE
 
 bool check_commands() {
@@ -2100,6 +2103,58 @@ bool check_commands() {
 	
 }
 
+
+// raise_z_above: slowly raise Z to the requested height
+//
+// contrarily to a simple move, this function will carefully plan a move
+// when the current Z position is unknown. In such cases, stallguard is
+// enabled and will prevent prolonged pushing against the Z tops
+void raise_z_above(float target, bool plan)
+{
+    if (current_position[Z_AXIS] >= target)
+        return;
+
+    // Z needs raising
+    current_position[Z_AXIS] = target;
+
+#if defined(Z_MIN_PIN) && (Z_MIN_PIN > -1) && !defined(DEBUG_DISABLE_ZMINLIMIT)
+    bool z_min_endstop = (READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING);
+#else
+    bool z_min_endstop = false;
+#endif
+
+    if (axis_known_position[Z_AXIS] || z_min_endstop)
+    {
+        // current position is known or very low, it's safe to raise Z
+        if(plan) plan_buffer_line_curposXYZE(max_feedrate[Z_AXIS], active_extruder);
+        return;
+    }
+
+    // ensure Z is powered in normal mode to overcome initial load
+    enable_z();
+    st_synchronize();
+
+    // rely on crashguard to limit damage
+    bool z_endstop_enabled = enable_z_endstop(true);
+#ifdef TMC2130
+    tmc2130_home_enter(Z_AXIS_MASK);
+#endif //TMC2130
+    plan_buffer_line_curposXYZE(homing_feedrate[Z_AXIS] / 60, active_extruder);
+    st_synchronize();
+#ifdef TMC2130
+    if (endstop_z_hit_on_purpose())
+    {
+        // not necessarily exact, but will avoid further vertical moves
+        current_position[Z_AXIS] = max_pos[Z_AXIS];
+        plan_set_position(current_position[X_AXIS], current_position[Y_AXIS],
+                          current_position[Z_AXIS], current_position[E_AXIS]);
+    }
+    tmc2130_home_exit();
+#endif //TMC2130
+    enable_z_endstop(z_endstop_enabled);
+}
+
+
 #ifdef TMC2130
 bool calibrate_z_auto()
 {
@@ -2434,6 +2489,9 @@ void ramming() {
 
 #ifdef TMC2130
 void force_high_power_mode(bool start_high_power_section) {
+#ifdef PSU_Delta
+	if (start_high_power_section == true) enable_force_z();
+#endif //PSU_Delta
 	uint8_t silent;
 	silent = eeprom_read_byte((uint8_t*)EEPROM_SILENT);
 	if (silent == 1) {
@@ -2482,9 +2540,7 @@ static void gcode_G28(bool home_x_axis, long home_x_value, bool home_y_axis, lon
 
 	//if we are homing all axes, first move z higher to protect heatbed/steel sheet
 	if (home_all_axes) {
-		current_position[Z_AXIS] += MESH_HOME_Z_SEARCH;
-		feedrate = homing_feedrate[Z_AXIS];
-		plan_buffer_line_curposXYZE(feedrate / 60, active_extruder);
+        raise_z_above(MESH_HOME_Z_SEARCH);
 		st_synchronize();
 	}
 #ifdef ENABLE_AUTO_BED_LEVELING
@@ -2595,26 +2651,21 @@ static void gcode_G28(bool home_x_axis, long home_x_value, bool home_y_axis, lon
         #ifndef Z_SAFE_HOMING
           if(home_z) {
             #if defined (Z_RAISE_BEFORE_HOMING) && (Z_RAISE_BEFORE_HOMING > 0)
-              destination[Z_AXIS] = Z_RAISE_BEFORE_HOMING * home_dir(Z_AXIS) * (-1);    // Set destination away from bed
-              feedrate = max_feedrate[Z_AXIS];
-              plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate, active_extruder);
+              raise_z_above(Z_RAISE_BEFORE_HOMING);
               st_synchronize();
             #endif // defined (Z_RAISE_BEFORE_HOMING) && (Z_RAISE_BEFORE_HOMING > 0)
             #if (defined(MESH_BED_LEVELING) && !defined(MK1BP))  // If Mesh bed leveling, move X&Y to safe position for home
-      			  if (!(axis_known_position[X_AXIS] && axis_known_position[Y_AXIS] )) 
-      			  {
-                homeaxis(X_AXIS);
-                homeaxis(Y_AXIS);
-      			  } 
+              raise_z_above(MESH_HOME_Z_SEARCH);
+              st_synchronize();
+              if (!axis_known_position[X_AXIS]) homeaxis(X_AXIS);
+              if (!axis_known_position[Y_AXIS]) homeaxis(Y_AXIS);
               // 1st mesh bed leveling measurement point, corrected.
               world2machine_initialize();
               world2machine(pgm_read_float(bed_ref_points_4), pgm_read_float(bed_ref_points_4+1), destination[X_AXIS], destination[Y_AXIS]);
               world2machine_reset();
               if (destination[Y_AXIS] < Y_MIN_POS)
                   destination[Y_AXIS] = Y_MIN_POS;
-              destination[Z_AXIS] = MESH_HOME_Z_SEARCH;    // Set destination away from bed
-              feedrate = homing_feedrate[Z_AXIS]/10;
-              current_position[Z_AXIS] = 0;
+              feedrate = homing_feedrate[X_AXIS] / 20;
               enable_endstops(false);
 #ifdef DEBUG_BUILD
               SERIAL_ECHOLNPGM("plan_set_position()");
@@ -2773,7 +2824,10 @@ bool gcode_M45(bool onlyZ, int8_t verbosity_level)
 	#ifdef TMC2130
 	FORCE_HIGH_POWER_START;
 	#endif // TMC2130
-	// Only Z calibration?
+    
+    FORCE_BL_ON_START;
+	
+    // Only Z calibration?
 	if (!onlyZ)
 	{
 		setTargetBed(0);
@@ -2961,6 +3015,9 @@ bool gcode_M45(bool onlyZ, int8_t verbosity_level)
 #ifdef TMC2130
 	FORCE_HIGH_POWER_END;
 #endif // TMC2130
+    
+    FORCE_BL_ON_END;
+    
 	return final_result;
 }
 
@@ -3141,15 +3198,6 @@ static void gcode_M600(bool automatic, float x_position, float y_position, float
     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
-//! during extruding (loading) filament.
-void marlin_rise_z(void)
-{
-    if (current_position[Z_AXIS] < 20) current_position[Z_AXIS] += 30;
-}
-
 void gcode_M701()
 {
 	printf_P(PSTR("gcode_M701 begin\n"));
@@ -3178,7 +3226,7 @@ void gcode_M701()
 		plan_buffer_line_curposXYZE(400 / 60, active_extruder); //fast sequence
 		st_synchronize();
 
-		marlin_rise_z();
+        raise_z_above(MIN_Z_FOR_LOAD, false);
 		current_position[E_AXIS] += 30;
 		plan_buffer_line_curposXYZE(400 / 60, active_extruder); //fast sequence
 		
@@ -3309,6 +3357,49 @@ static void gcode_PRUSA_BadRAMBoFanTest(){
 #endif
 }
 
+
+// G92 - Set current position to coordinates given
+static void gcode_G92()
+{
+    bool codes[NUM_AXIS];
+    float values[NUM_AXIS];
+
+    // Check which axes need to be set
+    for(uint8_t i = 0; i < NUM_AXIS; ++i)
+    {
+        codes[i] = code_seen(axis_codes[i]);
+        if(codes[i])
+            values[i] = code_value();
+    }
+
+    if((codes[E_AXIS] && values[E_AXIS] == 0) &&
+       (!codes[X_AXIS] && !codes[Y_AXIS] && !codes[Z_AXIS]))
+    {
+        // As a special optimization, when _just_ clearing the E position
+        // we schedule a flag asynchronously along with the next block to
+        // reset the starting E position instead of stopping the planner
+        current_position[E_AXIS] = 0;
+        plan_reset_next_e();
+    }
+    else
+    {
+        // In any other case we're forced to synchronize
+        st_synchronize();
+        for(uint8_t i = 0; i < 3; ++i)
+        {
+            if(codes[i])
+                current_position[i] = values[i] + cs.add_homing[i];
+        }
+        if(codes[E_AXIS])
+            current_position[E_AXIS] = values[E_AXIS];
+
+        // Set all at once
+        plan_set_position(current_position[X_AXIS], current_position[Y_AXIS],
+                          current_position[Z_AXIS], current_position[E_AXIS]);
+    }
+}
+
+
 #ifdef BACKLASH_X
 extern uint8_t st_backlash_x;
 #endif //BACKLASH_X
@@ -3320,8 +3411,7 @@ extern uint8_t st_backlash_y;
 
 //! @brief Parse and process commands
 //!
-//! look here for descriptions of G-codes: http://linuxcnc.org/handbook/gcode/g-code.html
-//! http://objects.reprap.org/wiki/Mendel_User_Manual:_RepRapGCodes
+//! look here for descriptions of G-codes: https://reprap.org/wiki/G-code
 //!
 //!
 //! Implemented Codes 
@@ -3340,7 +3430,7 @@ extern uint8_t st_backlash_y;
 //!@n G4  - Dwell S<seconds> or P<milliseconds>
 //!@n G10 - retract filament according to settings of M207
 //!@n G11 - retract recover filament according to settings of M208
-//!@n G28 - Home all Axis
+//!@n G28 - Home all Axes
 //!@n G29 - Detailed Z-Probe, probes the bed at 3 or more points.  Will fail if you haven't homed yet.
 //!@n G30 - Single Z Probe, probes bed at current XY location.
 //!@n G31 - Dock sled (Z_PROBE_SLED only)
@@ -3457,7 +3547,11 @@ extern uint8_t st_backlash_y;
 
 /** \ingroup GCodes */
 
-//! _This is a list of currently implemented G Codes in Prusa firmware (dynamically generated from doxygen)_
+//! _This is a list of currently implemented G Codes in Prusa firmware (dynamically generated from doxygen)._ 
+/**
+They are shown in order of appearance in the code.
+There are reasons why some G Codes aren't in numerical order.
+*/
 
 
 void process_commands()
@@ -3501,7 +3595,25 @@ void process_commands()
   float tmp_motor_loud[3] = DEFAULT_PWM_MOTOR_CURRENT_LOUD;
   int8_t SilentMode;
 #endif
+  /*!
+  
+  ---------------------------------------------------------------------------------
+  ### M117 - Display Message <a href="https://reprap.org/wiki/G-code#M117:_Display_Message">M117: Display Message</a>
+  This causes the given message to be shown in the status line on an attached LCD.
+  It is processed early as to allow printing messages that contain G, M, N or T.
   
+  ---------------------------------------------------------------------------------
+  ### Special internal commands
+  These are used by internal functions to process certain actions in the right order. Some of these are also usable by the user.
+  They are processed early as the commands are complex (strings).
+  These are only available on the MK3(S) as these require TMC2130 drivers:
+    - CRASH DETECTED
+    - CRASH RECOVER
+    - CRASH_CANCEL
+    - TMC_SET_WAVE
+    - TMC_SET_STEP
+    - TMC_SET_CHOP
+ */
   if (code_seen("M117")) { //moved to highest priority place to be able to to print strings which includes "G", "PRUSA" and "^"
 	  starpos = (strchr(strchr_pointer + 5, '*'));
 	  if (starpos != NULL)
@@ -3513,7 +3625,7 @@ void process_commands()
 	else if (strncmp_P(CMDBUFFER_CURRENT_STRING, PSTR("CRASH_"), 6) == 0)
 	{
 
-    //! ### CRASH_DETECTED - TMC2130
+    // ### CRASH_DETECTED - TMC2130
     // ---------------------------------
 	  if(code_seen("CRASH_DETECTED"))
 	  {
@@ -3523,12 +3635,12 @@ void process_commands()
 		  crashdet_detected(mask);
 	  }
 
-    //! ### CRASH_RECOVER - TMC2130
+    // ### CRASH_RECOVER - TMC2130
     // ----------------------------------
 	  else if(code_seen("CRASH_RECOVER"))
 		  crashdet_recover();
 
-    //! ### CRASH_CANCEL - TMC2130
+    // ### CRASH_CANCEL - TMC2130
     // ----------------------------------
 	  else if(code_seen("CRASH_CANCEL"))
 		  crashdet_cancel();
@@ -3536,7 +3648,7 @@ void process_commands()
 	else if (strncmp_P(CMDBUFFER_CURRENT_STRING, PSTR("TMC_"), 4) == 0)
 	{
     
-    //! ### TMC_SET_WAVE_ 
+    // ### TMC_SET_WAVE_ 
     // --------------------
 		if (strncmp_P(CMDBUFFER_CURRENT_STRING + 4, PSTR("SET_WAVE_"), 9) == 0)
 		{
@@ -3549,7 +3661,7 @@ void process_commands()
 			}
 		}
     
-    //! ### TMC_SET_STEP_
+    // ### TMC_SET_STEP_
     //  ------------------
 		else if (strncmp_P(CMDBUFFER_CURRENT_STRING + 4, PSTR("SET_STEP_"), 9) == 0)
 		{
@@ -3563,7 +3675,7 @@ void process_commands()
 			}
 		}
 
-    //! ### TMC_SET_CHOP_
+    // ### TMC_SET_CHOP_
     //  -------------------
 		else if (strncmp_P(CMDBUFFER_CURRENT_STRING + 4, PSTR("SET_CHOP_"), 9) == 0)
 		{
@@ -3618,20 +3730,20 @@ void process_commands()
 #endif //TMC2130
   else if(code_seen("PRUSA")){ 
     /*!
-    *
-    ### PRUSA - Internal command set
+    ---------------------------------------------------------------------------------
+    ### PRUSA - Internal command set <a href="https://reprap.org/wiki/G-code#G98:_Activate_farm_mode">G98: Activate farm mode - Notes</a>
     
     Set of internal PRUSA commands
-      
-          PRUSA [ Ping | PRN | FAN | fn | thx | uvlo | fsensor_recover | MMURES | RESET | fv | M28 | SN | Fir | Rev | Lang | Lz | Beat | FR ]
-      
+    #### Usage
+         PRUSA [ Ping | PRN | FAN | fn | thx | uvlo | MMURES | RESET | fv | M28 | SN | Fir | Rev | Lang | Lz | Beat | FR ]
+    
+    #### Parameters
       - `Ping` 
       - `PRN` - Prints revision of the printer
       - `FAN` - Prints fan details
       - `fn` - Prints farm no.
       - `thx` 
       - `uvlo` 
-      - `fsensor_recover` - Filament sensor recover - restore print and continue
       - `MMURES` - Reset MMU
       - `RESET` - (Careful!)
       - `fv`  - ?
@@ -3646,7 +3758,6 @@ void process_commands()
       - `nozzle set <diameter>` - set nozzle diameter (farm mode only), e.g. `PRUSA nozzle set 0.4`
       - `nozzle D<diameter>` - check the nozzle diameter (farm mode only), works like M862.1 P, e.g. `PRUSA nozzle D0.4`
       - `nozzle` - prints nozzle diameter (farm mode only), works like M862.1 P, e.g. `PRUSA nozzle`
-    *
     */
 
 
@@ -3661,7 +3772,7 @@ void process_commands()
 
         } else if( code_seen("FANPINTST") ){
             gcode_PRUSA_BadRAMBoFanTest();
-        }else if (code_seen("FAN")) { //! PRUSA FAN
+        }else if (code_seen("FAN")) { // PRUSA FAN
 			printf_P(_N("E0:%d RPM\nPRN0:%d RPM\n"), 60*fan_speed[0], 60*fan_speed[1]);
 		}else if (code_seen("fn")) { // PRUSA fn
 		  if (farm_mode) {
@@ -3681,12 +3792,6 @@ void process_commands()
                eeprom_update_byte((uint8_t*)EEPROM_UVLO,0); 
                enquecommand_P(PSTR("M24")); 
 		}	
-#ifdef FILAMENT_SENSOR
-		else if (code_seen("fsensor_recover")) // PRUSA fsensor_recover
-		{
-               fsensor_restore_print_and_continue();
-		}	
-#endif //FILAMENT_SENSOR
 		else if (code_seen("MMURES")) // PRUSA MMURES
 		{
 			mmu_reset();
@@ -3836,8 +3941,24 @@ eeprom_update_word((uint16_t*)EEPROM_NOZZLE_DIAMETER_uM,0xFFFF);
     switch (gcode_in_progress)
     {
 
-    //! ### G0, G1 - Coordinated movement X Y Z E
-    // --------------------------------------      
+    /*!
+    ---------------------------------------------------------------------------------
+	 # G Codes
+	### G0, G1 - Coordinated movement X Y Z E <a href="https://reprap.org/wiki/G-code#G0_.26_G1:_Move">G0 & G1: Move</a> 
+	In Prusa Firmware G0 and G1 are the same.
+	#### Usage
+	
+	      G0 [ X | Y | Z | E | F | S ]
+		  G1 [ X | Y | Z | E | F | S ]
+	
+	#### Parameters
+	  - `X` - The position to move to on the X axis
+	  - `Y` - The position to move to on the Y axis
+	  - `Z` - The position to move to on the Z axis
+	  - `E` - The amount to extrude between the starting point and ending point
+	  - `F` - The feedrate per minute of the move between the starting point and ending point (if supplied)
+	  
+    */
     case 0: // G0 -> G1
     case 1: // G1
       if(Stopped == false) {
@@ -4011,8 +4132,19 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
 
         #endif
 
+            get_coordinates(); // For X Y Z E F
+
+            // When recovering from a previous print move, restore the originally
+            // calculated target position on the first USB/SD command. This accounts
+            // properly for relative moves
+            if ((saved_target[0] != SAVED_TARGET_UNSET) &&
+                ((CMDBUFFER_CURRENT_TYPE == CMDBUFFER_CURRENT_TYPE_SDCARD) ||
+                 (CMDBUFFER_CURRENT_TYPE == CMDBUFFER_CURRENT_TYPE_USB_WITH_LINENR)))
+            {
+                memcpy(destination, saved_target, sizeof(destination));
+                saved_target[0] = SAVED_TARGET_UNSET;
+            }
 
-        get_coordinates(); // For X Y Z E F
 		if (total_filament_used > ((current_position[E_AXIS] - destination[E_AXIS]) * 100)) { //protection against total_filament_used overflow
 			total_filament_used = total_filament_used + ((destination[E_AXIS] - current_position[E_AXIS]) * 100);
 		}
@@ -4036,8 +4168,25 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
       }
       break;
 
-    //! ### G2 - CW ARC
-    // ------------------------------     
+    /*!
+	### G2, G3 - Controlled Arc Move <a href="https://reprap.org/wiki/G-code#G2_.26_G3:_Controlled_Arc_Move">G2 & G3: Controlled Arc Move</a>
+	
+    These commands don't propperly work with MBL enabled. The compensation only happens at the end of the move, so avoid long arcs.
+    
+	#### Usage
+	
+	      G2 [ X | Y | I | E | F ] (Clockwise Arc)
+		  G3 [ X | Y | I | E | F ] (Counter-Clockwise Arc)
+	
+	#### Parameters
+	  - `X` - The position to move to on the X axis
+	  - `Y` - The position to move to on the Y axis
+	  - `I` - The point in X space from the current X position to maintain a constant distance from
+	  - `J` - The point in Y space from the current Y position to maintain a constant distance from
+	  - `E` - The amount to extrude between the starting point and ending point
+	  - `F` - The feedrate per minute of the move between the starting point and ending point (if supplied)
+	
+    */
     case 2: 
       if(Stopped == false) {
         get_arc_coordinates();
@@ -4045,8 +4194,6 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
       }
       break;
  
-
-    //! ### G3  - CCW ARC
     // -------------------------------
     case 3: 
       if(Stopped == false) {
@@ -4056,8 +4203,19 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
       break;
 
 
-    //! ### G4 - Dwell
-    // -------------------------------
+    /*!
+	### G4 - Dwell <a href="https://reprap.org/wiki/G-code#G4:_Dwell">G4: Dwell</a>
+	Pause the machine for a period of time.
+	
+	#### Usage
+	
+	    G4 [ P | S ]
+	
+	#### Parameters
+	  - `P` - Time to wait, in milliseconds
+	  - `S` - Time to wait, in seconds
+	
+    */
     case 4: 
       codenum = 0;
       if(code_seen('P')) codenum = code_value(); // milliseconds to wait
@@ -4075,8 +4233,10 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
       #ifdef FWRETRACT
       
 
-    //! ### G10 Retract
-    // ------------------------------
+    /*!
+	### G10 - Retract <a href="https://reprap.org/wiki/G-code#G10:_Retract">G10: Retract</a>
+	Retracts filament according to settings of `M207`
+    */
     case 10: 
        #if EXTRUDERS > 1
         retracted_swap[active_extruder]=(code_seen('S') && code_value_long() == 1); // checks for swap retract argument
@@ -4087,8 +4247,10 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
       break;
       
 
-    //! ### G11 - Retract recover
-    // ----------------------------- 
+    /*!
+	### G11 - Retract recover <a href="https://reprap.org/wiki/G-code#G11:_Unretract">G11: Unretract</a>
+	Unretracts/recovers filament according to settings of `M208`
+    */
     case 11: 
        #if EXTRUDERS > 1
         retract(false,retracted_swap[active_extruder]);
@@ -4099,8 +4261,20 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
       #endif //FWRETRACT
     
 
-    //! ### G28 - Home all Axis one at a time
-    // --------------------------------------------
+    /*!
+    ### G28 - Home all Axes one at a time <a href="https://reprap.org/wiki/G-code#G28:_Move_to_Origin_.28Home.29">G28: Move to Origin (Home)</a>
+    Using `G28` without any parameters will perfom homing of all axes AND mesh bed leveling, while `G28 W` will just home all axes (no mesh bed leveling).
+    #### Usage
+	
+         G28 [ X | Y | Z | W | C ]
+    
+	#### Parameters
+     - `X` - Flag to go back to the X axis origin
+     - `Y` - Flag to go back to the Y axis origin
+     - `Z` - Flag to go back to the Z axis origin
+     - `W` - Suppress mesh bed leveling if `X`, `Y` or `Z` are not provided
+     - `C` - Calibrate X and Y origin (home) - Only on MK3/s
+	*/
     case 28: 
     {
       long home_x_value = 0;
@@ -4132,8 +4306,12 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
 #ifdef ENABLE_AUTO_BED_LEVELING
     
 
-    //! ### G29 - Detailed Z-Probe
-    // --------------------------------    
+    /*!
+	### G29 - Detailed Z-Probe <a href="https://reprap.org/wiki/G-code#G29:_Detailed_Z-Probe">G29: Detailed Z-Probe</a>
+	In Prusa Firmware this G-code is deactivated by default, must be turned on in the source code.
+	
+	See `G81`
+    */
     case 29: 
         {
             #if Z_MIN_PIN == -1
@@ -4278,8 +4456,10 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
         break;
 #ifndef Z_PROBE_SLED
 
-    //! ### G30 - Single Z Probe
-    // ------------------------------------        
+    /*!
+	### G30 - Single Z Probe <a href="https://reprap.org/wiki/G-code#G30:_Single_Z-Probe">G30: Single Z-Probe</a>
+	In Prusa Firmware this G-code is deactivated by default, must be turned on in the source code.
+    */
     case 30: 
         {
             st_synchronize();
@@ -4303,15 +4483,19 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
         break;
 #else
 
-    //! ### G31 - Dock the sled
-    // ---------------------------
+    /*!
+	### G31 - Dock the sled <a href="https://reprap.org/wiki/G-code#G31:_Dock_Z_Probe_sled">G31: Dock Z Probe sled</a>
+	In Prusa Firmware this G-code is deactivated by default, must be turned on in the source code.
+    */
     case 31: 
         dock_sled(true);
         break;
 
 
-    //! ### G32 - Undock the sled
-    // ----------------------------     
+    /*!
+	### G32 - Undock the sled <a href="https://reprap.org/wiki/G-code#G32:_Undock_Z_Probe_sled">G32: Undock Z Probe sled</a>
+	In Prusa Firmware this G-code is deactivated by default, must be turned on in the source code.
+    */
     case 32: 
         dock_sled(false);
         break;
@@ -4320,8 +4504,11 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
             
 #ifdef MESH_BED_LEVELING
 
-    //! ### G30 - Single Z Probe
-    // ----------------------------    
+    /*!
+	### G30 - Single Z Probe <a href="https://reprap.org/wiki/G-code#G30:_Single_Z-Probe">G30: Single Z-Probe</a>
+    Sensor must be over the bed.
+    The maximum travel distance before an error is triggered is 10mm.
+    */
     case 30: 
         {
             st_synchronize();
@@ -4338,8 +4525,10 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
         }
         break;
 	
-  //! ### G75 - Print temperature interpolation
-  // ---------------------------------------------
+  /*!
+  ### G75 - Print temperature interpolation <a href="https://reprap.org/wiki/G-code#G75:_Print_temperature_interpolation">G75: Print temperature interpolation</a>
+  Show/print PINDA temperature interpolating.
+  */
 	case 75:
 	{
 		for (int i = 40; i <= 110; i++)
@@ -4347,9 +4536,26 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
 	}
 	break;
 
-  //! ### G76 - PINDA probe temperature calibration
-  // ------------------------------------------------
-	case 76: 
+  /*!
+  ### G76 - PINDA probe temperature calibration <a href="https://reprap.org/wiki/G-code#G76:_PINDA_probe_temperature_calibration">G76: PINDA probe temperature calibration</a>
+  This G-code is used to calibrate the temperature drift of the PINDA (inductive Sensor).
+  
+  The PINDAv2 sensor has a built-in thermistor which has the advantage that the calibration can be done once for all materials.
+  
+  The Original i3 Prusa MK2/s uses PINDAv1 and this calibration improves the temperature drift, but not as good as the PINDAv2.
+
+  #### Example
+  
+  ```
+  G76
+  
+  echo PINDA probe calibration start
+  echo start temperature: 35.0°
+  echo ...
+  echo PINDA temperature -- Z shift (mm): 0.---
+  ```
+  */
+  case 76: 
 	{
 #ifdef PINDA_THERMISTOR
 		if (true)
@@ -4606,11 +4812,28 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
 	break;
 
 
-	//! ### G80 - Mesh-based Z probe 
-  // -----------------------------------
+    /*!
+    ### G80 - Mesh-based Z probe <a href="https://reprap.org/wiki/G-code#G80:_Mesh-based_Z_probe">G80: Mesh-based Z probe</a>
+    Default 3x3 grid can be changed on MK2.5/s and MK3/s to 7x7 grid.
+    #### Usage
+	  
+          G80 [ N | R | V | L | R | F | B ]
+      
+	#### Parameters
+      - `N` - Number of mesh points on x axis. Default is 3. Valid values are 3 and 7.
+      - `R` - Probe retries. Default 3 max. 10
+      - `V` - Verbosity level 1=low, 10=mid, 20=high. It only can be used if the firmware has been compiled with SUPPORT_VERBOSITY active.
+      
+      Using the following parameters enables additional "manual" bed leveling correction. Valid values are -100 microns to 100 microns.
+    #### Additional Parameters
+      - `L` - Left Bed Level correct value in um.
+      - `R` - Right Bed Level correct value in um.
+      - `F` - Front Bed Level correct value in um.
+      - `B` - Back Bed Level correct value in um.
+    */
   
 	/*
-  * Probes a grid and produces a mesh to compensate for variable bed height
+    * Probes a grid and produces a mesh to compensate for variable bed height
 	* The S0 report the points as below
 	*  +----> X-axis
 	*  |
@@ -4626,6 +4849,11 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
 	case_G80:
 	{
 		mesh_bed_leveling_flag = true;
+#ifndef LA_NOCOMPAT
+        // When printing via USB there's no clear boundary between prints. Abuse MBL to indicate
+        // the beginning of a new print, allowing a new autodetected setting just after G80.
+        la10c_reset();
+#endif
 #ifndef PINDA_THERMISTOR
         static bool run = false; // thermistor-less PINDA temperature compensation is running
 #endif // ndef PINDA_THERMISTOR
@@ -4643,13 +4871,8 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
 			// 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 != LcdCommands::StopPrint) {
-				repeatcommand_front(); // repeat G80 with all its parameters
-				enquecommand_front_P((PSTR("G28 W0")));
-			}
-			else {
-				mesh_bed_leveling_flag = false;
-			}
+			repeatcommand_front(); // repeat G80 with all its parameters
+			enquecommand_front_P((PSTR("G28 W0")));
 			break;
 		} 
 		
@@ -4679,23 +4902,14 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
 #ifndef PINDA_THERMISTOR
 		if (run == false && temp_cal_active == true && calibration_status_pinda() == true && target_temperature_bed >= 50)
 		{
-			if (lcd_commands_type != LcdCommands::StopPrint) {
-				temp_compensation_start();
-				run = true;
-				repeatcommand_front(); // repeat G80 with all its parameters
-				enquecommand_front_P((PSTR("G28 W0")));
-			}
-			else {
-				mesh_bed_leveling_flag = false;
-			}
+			temp_compensation_start();
+			run = true;
+			repeatcommand_front(); // repeat G80 with all its parameters
+			enquecommand_front_P((PSTR("G28 W0")));
 			break;
 		}
         run = false;
 #endif //PINDA_THERMISTOR
-		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.
 		CustomMsg custom_message_type_old = custom_message_type;
 		unsigned int custom_message_state_old = custom_message_state;
@@ -5035,12 +5249,10 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
 	}
 	break;
 
-        //! ### G81 - Mesh bed leveling status
-        // -----------------------------------------
-
-         /*
-         * Prints mesh bed leveling status and bed profile if activated
-         */
+        /*!
+		### G81 - Mesh bed leveling status <a href="https://reprap.org/wiki/G-code#G81:_Mesh_bed_leveling_status">G81: Mesh bed leveling status</a>
+		Prints mesh bed leveling status and bed profile if activated.
+        */
         case 81:
             if (mbl.active) {
                 SERIAL_PROTOCOLPGM("Num X,Y: ");
@@ -5063,12 +5275,12 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
             break;
             
 #if 0
-        /*
-         * G82: Single Z probe at current location
-         *
-         * WARNING! USE WITH CAUTION! If you'll try to probe where is no leveling pad, nasty things can happen!
-         *
-         */
+        /*!
+        ### G82: Single Z probe at current location - Not active <a href="https://reprap.org/wiki/G-code#G82:_Single_Z_probe_at_current_location">G82: Single Z probe at current location</a>
+        
+        WARNING! USE WITH CAUTION! If you'll try to probe where is no leveling pad, nasty things can happen!
+		In Prusa Firmware this G-code is deactivated by default, must be turned on in the source code.
+		*/
         case 82:
             SERIAL_PROTOCOLLNPGM("Finding bed ");
             int l_feedmultiply = setup_for_endstop_move();
@@ -5079,9 +5291,10 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
             SERIAL_PROTOCOLPGM("\n");
             break;
 
-            /*
-             * G83: Prusa3D specific: Babystep in Z and store to EEPROM
-             */
+        /*!
+        ### G83: Babystep in Z and store to EEPROM - Not active <a href="https://reprap.org/wiki/G-code#G83:_Babystep_in_Z_and_store_to_EEPROM">G83: Babystep in Z and store to EEPROM</a>
+		In Prusa Firmware this G-code is deactivated by default, must be turned on in the source code.
+		*/
         case 83:
         {
             int babystepz = code_seen('S') ? code_value() : 0;
@@ -5104,50 +5317,50 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
             
         }
         break;
-            /*
-             * G84: Prusa3D specific: UNDO Babystep Z (move Z axis back)
-             */
+        /*!
+        ### G84: UNDO Babystep Z (move Z axis back) - Not active <a href="https://reprap.org/wiki/G-code#G84:_UNDO_Babystep_Z_.28move_Z_axis_back.29">G84: UNDO Babystep Z (move Z axis back)</a>
+		In Prusa Firmware this G-code is deactivated by default, must be turned on in the source code.
+		*/
         case 84:
             babystepsTodoZsubtract(babystepLoadZ);
             // babystepLoadZ = 0;
             break;
             
-            /*
-             * G85: Prusa3D specific: Pick best babystep
-             */
+        /*!
+        ### G85: Pick best babystep - Not active <a href="https://reprap.org/wiki/G-code#G85:_Pick_best_babystep">G85: Pick best babystep</a>
+		In Prusa Firmware this G-code is deactivated by default, must be turned on in the source code.
+		*/
         case 85:
             lcd_pick_babystep();
             break;
 #endif
             
-        /**
-         * ### G86 - Disable babystep correction after home
-         *
-         * This G-code will be performed at the start of a calibration script.
-         * (Prusa3D specific)
-         */
+        /*!
+        ### G86 - Disable babystep correction after home <a href="https://reprap.org/wiki/G-code#G86:_Disable_babystep_correction_after_home">G86: Disable babystep correction after home</a>
+        
+        This G-code will be performed at the start of a calibration script.
+        (Prusa3D specific)
+        */
         case 86:
             calibration_status_store(CALIBRATION_STATUS_LIVE_ADJUST);
             break;
            
 
-        /**
-         * ### G87 - Enable babystep correction after home
-         * 
-         *
-         * This G-code will be performed at the end of a calibration script.
-         * (Prusa3D specific)
-         */
+        /*!
+        ### G87 - Enable babystep correction after home <a href="https://reprap.org/wiki/G-code#G87:_Enable_babystep_correction_after_home">G87: Enable babystep correction after home</a>
+        
+		This G-code will be performed at the end of a calibration script.
+        (Prusa3D specific)
+        */
         case 87:
 			calibration_status_store(CALIBRATION_STATUS_CALIBRATED);
             break;
 
-
-        /**
-         * ### G88 - Reserved
-         *
-         * Currently has no effect. 
-         */
+        /*!
+        ### G88 - Reserved <a href="https://reprap.org/wiki/G-code#G88:_Reserved">G88: Reserved</a>
+        
+        Currently has no effect. 
+        */
 
         // Prusa3D specific: Don't know what it is for, it is in V2Calibration.gcode
 
@@ -5157,40 +5370,56 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
 
 #endif  // ENABLE_MESH_BED_LEVELING
             
-    //! ### G90 - Switch off relative mode
-    // -------------------------------
-    case 90:
-      relative_mode = false;
-      break;
 
-    //! ### G91 - Switch on relative mode
-    // -------------------------------
-    case 91:
-      relative_mode = true;
-      break;
+    /*!
+	### G90 - Switch off relative mode <a href="https://reprap.org/wiki/G-code#G90:_Set_to_Absolute_Positioning">G90: Set to Absolute Positioning</a>
+	All coordinates from now on are absolute relative to the origin of the machine. E axis is also switched to absolute mode.
+    */
+    case 90: {
+        for(uint8_t i = 0; i != NUM_AXIS; ++i)
+            axis_relative_modes[i] = false;
+    }
+    break;
 
-    //! ### G92 - Set position
-    // -----------------------------
-    case 92:
-      if(!code_seen(axis_codes[E_AXIS]))
-        st_synchronize();
-      for(int8_t i=0; i < NUM_AXIS; i++) {
-        if(code_seen(axis_codes[i])) {
-           if(i == E_AXIS) {
-             current_position[i] = code_value();
-             plan_set_e_position(current_position[E_AXIS]);
-           }
-           else {
-		current_position[i] = code_value()+cs.add_homing[i];
-            plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
-           }
-        }
-      }
-      break;
+    /*!
+	### G91 - Switch on relative mode <a href="https://reprap.org/wiki/G-code#G91:_Set_to_Relative_Positioning">G91: Set to Relative Positioning</a>
+    All coordinates from now on are relative to the last position. E axis is also switched to relative mode.
+	*/
+    case 91: {
+        for(uint8_t i = 0; i != NUM_AXIS; ++i)
+            axis_relative_modes[i] = true;
+    }
+    break;
 
+    /*!
+	### G92 - Set position <a href="https://reprap.org/wiki/G-code#G92:_Set_Position">G92: Set Position</a>
+    
+    It is used for setting the current position of each axis. The parameters are always absolute to the origin.
+    If a parameter is omitted, that axis will not be affected.
+    If `X`, `Y`, or `Z` axis are specified, the move afterwards might stutter because of Mesh Bed Leveling. `E` axis is not affected if the target position is 0 (`G92 E0`).
+	A G92 without coordinates will reset all axes to zero on some firmware. This is not the case for Prusa-Firmware!
+    
+    #### Usage
+	
+	      G92 [ X | Y | Z | E ]
+	
+	#### Parameters
+	  - `X` - new X axis position
+	  - `Y` - new Y axis position
+	  - `Z` - new Z axis position
+	  - `E` - new extruder position
+	
+    */
+    case 92: {
+        gcode_G92();
+    }
+    break;
 
-  //! ### G98 - Activate farm mode
-  // -----------------------------------    
+    /*!
+    ### G98 - Activate farm mode <a href="https://reprap.org/wiki/G-code#G98:_Activate_farm_mode">G98: Activate farm mode</a>
+	Enable Prusa-specific Farm functions and g-code.
+    See Internal Prusa commands.
+    */
 	case 98:
 		farm_mode = 1;
 		PingTime = _millis();
@@ -5201,8 +5430,9 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
           fCheckModeInit();                       // alternatively invoke printer reset
 		break;
 
-  //! ### G99 - Deactivate farm mode
-  // -------------------------------------
+    /*! ### G99 - Deactivate farm mode <a href="https://reprap.org/wiki/G-code#G99:_Deactivate_farm_mode">G99: Deactivate farm mode</a>
+ 	Disables Prusa-specific Farm functions and g-code.
+   */
 	case 99:
 		farm_mode = 0;
 		lcd_printer_connected();
@@ -5216,9 +5446,15 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
 //	printf_P(_N("END G-CODE=%u\n"), gcode_in_progress);
 	gcode_in_progress = 0;
   } // end if(code_seen('G'))
+  /*!
+  ### End of G-Codes
+  */
 
-
-  //! ---------------------------------------------------------------------------------
+  /*!
+  ---------------------------------------------------------------------------------
+  # M Commands
+  
+  */
 
   else if(code_seen('M'))
   {
@@ -5238,8 +5474,9 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
     switch(mcode_in_progress)
     {
 
-    //! ### M0, M1 - Stop the printer
-    // ---------------------------------------------------------------
+    /*!
+	### M0, M1 - Stop the printer <a href="https://reprap.org/wiki/G-code#M0:_Stop_or_Unconditional_stop">M0: Stop or Unconditional stop</a>
+    */
     case 0: // M0 - Unconditional stop - Wait for user button press on LCD
     case 1: // M1 - Conditional stop - Wait for user button press on LCD
     {
@@ -5288,8 +5525,9 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
     }
     break;
 
-    //! ### M17 - Enable axes
-    // ---------------------------------
+    /*!
+	### M17 - Enable all axes <a href="https://reprap.org/wiki/G-code#M17:_Enable.2FPower_all_stepper_motors">M17: Enable/Power all stepper motors</a>
+    */
     case 17:
         LCD_MESSAGERPGM(_i("No move."));////MSG_NO_MOVE
         enable_x();
@@ -5302,28 +5540,36 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
 
 #ifdef SDSUPPORT
 
-    //! ### M20 - SD Card file list
-    // -----------------------------------
+    /*!
+	### M20 - SD Card file list <a href="https://reprap.org/wiki/G-code#M20:_List_SD_card">M20: List SD card</a>
+    */
     case 20:
       SERIAL_PROTOCOLLNRPGM(_N("Begin file list"));////MSG_BEGIN_FILE_LIST
       card.ls();
       SERIAL_PROTOCOLLNRPGM(_N("End file list"));////MSG_END_FILE_LIST
       break;
 
-    //! ### M21 - Init SD card
-    // ------------------------------------
+    /*!
+	### M21 - Init SD card <a href="https://reprap.org/wiki/G-code#M21:_Initialize_SD_card">M21: Initialize SD card</a>
+    */
     case 21:
       card.initsd();
       break;
 
-    //! ### M22 - Release SD card
-    // -----------------------------------
+    /*!
+	### M22 - Release SD card <a href="https://reprap.org/wiki/G-code#M22:_Release_SD_card">M22: Release SD card</a>
+    */
     case 22: 
       card.release();
       break;
 
-    //! ### M23 - Select file
-    // -----------------------------------
+    /*!
+	### M23 - Select file <a href="https://reprap.org/wiki/G-code#M23:_Select_SD_file">M23: Select SD file</a>
+    #### Usage
+    
+        M23 [filename]
+    
+    */
     case 23: 
       starpos = (strchr(strchr_pointer + 4,'*'));
 	  if(starpos!=NULL)
@@ -5331,26 +5577,35 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
       card.openFile(strchr_pointer + 4,true);
       break;
 
-    //! ### M24 - Start SD print
-    // ----------------------------------
+    /*!
+	### M24 - Start SD print <a href="https://reprap.org/wiki/G-code#M24:_Start.2Fresume_SD_print">M24: Start/resume SD print</a>
+    */
     case 24:
-	  if (!card.paused) 
-		failstats_reset_print();
-      card.startFileprint();
-      starttime=_millis();
+	  if (isPrintPaused)
+          lcd_resume_print();
+      else
+      {
+          failstats_reset_print();
+#ifndef LA_NOCOMPAT
+          la10c_reset();
+#endif
+          card.startFileprint();
+          starttime=_millis();
+      }
 	  break;
 
-    //! ### M25 - Pause SD print
-    // ----------------------------------
-    case 25:
-      card.pauseSDPrint();
-      break;
-
-    //! ### M26 S\<index\> - Set SD index
-    //! Set position in SD card file to index in bytes.
-    //! This command is expected to be called after M23 and before M24.
-    //! Otherwise effect of this command is undefined.
-    // ----------------------------------
+    /*!
+	### M26 - Set SD index <a href="https://reprap.org/wiki/G-code#M26:_Set_SD_position">M26: Set SD position</a>
+    Set position in SD card file to index in bytes.
+    This command is expected to be called after M23 and before M24.
+    Otherwise effect of this command is undefined.
+    #### Usage
+	
+	      M26 [ S ]
+	
+	#### Parameters
+	  - `S` - Index in bytes
+    */
     case 26: 
       if(card.cardOK && code_seen('S')) {
         long index = code_value_long();
@@ -5361,14 +5616,16 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
       }
       break;
 
-    //! ### M27 - Get SD status
-    // ----------------------------------
+    /*!
+	### M27 - Get SD status <a href="https://reprap.org/wiki/G-code#M27:_Report_SD_print_status">M27: Report SD print status</a>
+    */
     case 27:
       card.getStatus();
       break;
 
-    //! ### M28 - Start SD write
-    // ---------------------------------  
+    /*!
+	### M28 - Start SD write <a href="https://reprap.org/wiki/G-code#M28:_Begin_write_to_SD_card">M28: Begin write to SD card</a>
+    */
     case 28: 
       starpos = (strchr(strchr_pointer + 4,'*'));
       if(starpos != NULL){
@@ -5379,16 +5636,21 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
       card.openFile(strchr_pointer+4,false);
       break;
 
-    //! ### M29 - Stop SD write
-    // -------------------------------------
-    //! Currently has no effect.
+    /*! ### M29 - Stop SD write <a href="https://reprap.org/wiki/G-code#M29:_Stop_writing_to_SD_card">M29: Stop writing to SD card</a>
+	Stops writing to the SD file signaling the end of the uploaded file. It is processed very early and it's not written to the card.
+    */
     case 29:
       //processed in write to file routine above
       //card,saving = false;
       break;
 
-    //! ### M30 - Delete file  <filename> 
-    // ----------------------------------
+    /*!
+	### M30 - Delete file <a href="https://reprap.org/wiki/G-code#M30:_Delete_a_file_on_the_SD_card">M30: Delete a file on the SD card</a>
+    #### Usage
+    
+        M30 [filename]
+    
+    */
     case 30:
       if (card.cardOK){
         card.closefile();
@@ -5402,8 +5664,10 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
       }
       break;
 
-    //! ### M32 - Select file and start SD print
-    // ------------------------------------
+    /*!
+	### M32 - Select file and start SD print <a href="https://reprap.org/wiki/G-code#M32:_Select_file_and_start_SD_print">M32: Select file and start SD print</a>
+	@todo What are the parameters P and S for in M32?
+    */
     case 32:
     {
       if(card.sdprinting) {
@@ -5434,14 +5698,22 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
         if(code_seen('S'))
           if(strchr_pointer<namestartpos) //only if "S" is occuring _before_ the filename
             card.setIndex(code_value_long());
+#ifndef LA_NOCOMPAT
+        la10c_reset();
+#endif
         card.startFileprint();
         if(!call_procedure)
           starttime=_millis(); //procedure calls count as normal print time.
       }
     } break;
 
-    //! ### M982 - Start SD write
-    // ---------------------------------
+    /*!
+	### M928 - Start SD logging <a href="https://reprap.org/wiki/G-code#M928:_Start_SD_logging">M928: Start SD logging</a>
+    #### Usage
+    
+        M928 [filename]
+    
+    */
     case 928: 
       starpos = (strchr(strchr_pointer + 5,'*'));
       if(starpos != NULL){
@@ -5454,8 +5726,9 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
 
 #endif //SDSUPPORT
 
-    //! ### M31 - Report current print time
-    // --------------------------------------------------
+    /*!
+	### M31 - Report current print time <a href="https://reprap.org/wiki/G-code#M31:_Output_time_since_last_M109_or_SD_card_start_to_serial">M31: Output time since last M109 or SD card start to serial</a>
+    */
     case 31: //M31 take time since the start of the SD print or an M109 command
       {
       stoptime=_millis();
@@ -5472,8 +5745,17 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
       }
       break;
 
-    //! ### M42 - Set pin state
-    // -----------------------------
+    /*!
+	### M42 - Set pin state <a href="https://reprap.org/wiki/G-code#M42:_Switch_I.2FO_pin">M42: Switch I/O pin</a>
+    #### Usage
+    
+        M42 [ P | S ]
+        
+    #### Parameters
+    - `P` - Pin number.
+    - `S` - Pin value. If the pin is analog, values are from 0 to 255. If the pin is digital, values are from 0 to 1.
+    
+    */
     case 42:
       if (code_seen('S'))
       {
@@ -5503,9 +5785,10 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
      break;
 
 
-    //! ### M44 - Reset the bed skew and offset calibration (Prusa specific)
-    // --------------------------------------------------------------------
-    case 44: // M44: Prusa3D: Reset the bed skew and offset calibration.
+    /*!
+	### M44 - Reset the bed skew and offset calibration <a href="https://reprap.org/wiki/G-code#M44:_Reset_the_bed_skew_and_offset_calibration">M44: Reset the bed skew and offset calibration</a>
+    */
+    case 44: // M44: Prusa3D: Reset the bed skew and offset calibration.
 
 		// Reset the baby step value and the baby step applied flag.
 		calibration_status_store(CALIBRATION_STATUS_ASSEMBLED);
@@ -5519,8 +5802,15 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
         world2machine_revert_to_uncorrected();
         break;
 
-    //! ### M45 - Bed skew and offset with manual Z up (Prusa specific)
-    // ------------------------------------------------------
+    /*!
+	### M45 - Bed skew and offset with manual Z up <a href="https://reprap.org/wiki/G-code#M45:_Bed_skew_and_offset_with_manual_Z_up">M45: Bed skew and offset with manual Z up</a>
+	#### Usage
+    
+        M45 [ V ]
+    #### Parameters
+	- `V` - Verbosity level 1, 10 and 20 (low, mid, high). Only when SUPPORT_VERBOSITY is defined. Optional.
+    - `Z` - If it is provided, only Z calibration will run. Otherwise full calibration is executed.
+    */
     case 45: // M45: Prusa3D: bed skew and offset with manual Z up
     {
 		int8_t verbosity_level = 0;
@@ -5537,8 +5827,11 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
     }
 	break;
 
+    /*!
+	### M46 - Show the assigned IP address <a href="https://reprap.org/wiki/G-code#M46:_Show_the_assigned_IP_address">M46: Show the assigned IP address.</a>
+    */
     /*
-    case 46:
+     case 46:
     {
         // M46: Prusa3D: Show the assigned IP address.
         uint8_t ip[4];
@@ -5560,8 +5853,9 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
     }
     */
 
-    //! ### M47 - Show end stops dialog on the display (Prusa specific)
-    // ---------------------------------------------------- 
+    /*!
+	### M47 - Show end stops dialog on the display <a href="https://reprap.org/wiki/G-code#M47:_Show_end_stops_dialog_on_the_display">M47: Show end stops dialog on the display</a>
+    */
     case 47:
         
 		KEEPALIVE_STATE(PAUSED_FOR_USER);
@@ -5609,22 +5903,25 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
 #ifdef ENABLE_AUTO_BED_LEVELING
 #ifdef Z_PROBE_REPEATABILITY_TEST 
 
-    //! ### M48 - Z-Probe repeatability measurement function.
-    // ------------------------------------------------------
-    //!
-    //! _Usage:_
-    //!    
-    //!     M48 <n #_samples> <X X_position_for_samples> <Y Y_position_for_samples> <V Verbose_Level> <L legs_of_movement_prior_to_doing_probe>
-    //! 
-    //! This function assumes the bed has been homed.  Specifically, that a G28 command
-    //! as been issued prior to invoking the M48 Z-Probe repeatability measurement function.
-    //! Any information generated by a prior G29 Bed leveling command will be lost and need to be
-    //! regenerated.
-    //!
-    //! The number of samples will default to 10 if not specified.  You can use upper or lower case
-    //! letters for any of the options EXCEPT n.  n must be in lower case because Marlin uses a capital
-    //! N for its communication protocol and will get horribly confused if you send it a capital N.
-    //!
+    /*!
+	### M48 - Z-Probe repeatability measurement function <a href="https://reprap.org/wiki/G-code#M48:_Measure_Z-Probe_repeatability">M48: Measure Z-Probe repeatability</a>
+    
+     This function assumes the bed has been homed.  Specifically, that a G28 command as been issued prior to invoking the M48 Z-Probe repeatability measurement function. Any information generated by a prior G29 Bed leveling command will be lost and needs to be regenerated.
+     
+     The number of samples will default to 10 if not specified.  You can use upper or lower case letters for any of the options EXCEPT n.  n must be in lower case because Marlin uses a capital N for its communication protocol and will get horribly confused if you send it a capital N.
+     @todo Why would you check for both uppercase and lowercase? Seems wasteful.
+	 
+     #### Usage
+     
+	     M48 [ n | X | Y | V | L ]
+     
+     #### Parameters
+       - `n` - Number of samples. Valid values 4-50
+	   - `X` - X position for samples
+	   - `Y` - Y position for samples
+	   - `V` - Verbose level. Valid values 1-4
+	   - `L` - Legs of movementprior to doing probe. Valid values 1-15
+    */
     case 48: // M48 Z-Probe repeatability
         {
             #if Z_MIN_PIN == -1
@@ -5863,12 +6160,18 @@ Sigma_Exit:
 #endif		// Z_PROBE_REPEATABILITY_TEST 
 #endif		// ENABLE_AUTO_BED_LEVELING
 
-  //! ### M73 - Set/get print progress 
-  // -------------------------------------
-  //! _Usage:_
-  //! 
-  //!     M73 P<percent> R<time_remaining> Q<percent_silent> S<time_remaining_silent>
-  //! 
+	/*!
+	### M73 - Set/get print progress <a href="https://reprap.org/wiki/G-code#M73:_Set.2FGet_build_percentage">M73: Set/Get build percentage</a>
+	#### Usage
+    
+	    M73 [ P | R | Q | S ]
+    
+	#### Parameters
+    - `P` - Percent in normal mode
+    - `R` - Time remaining in normal mode
+    - `Q` - Percent in silent mode
+    - `S` - Time in silent mode
+   */
 	case 73: //M73 show percent done and time remaining
 		if(code_seen('P')) print_percent_done_normal = code_value();
 		if(code_seen('R')) print_time_remaining_normal = code_value();
@@ -5882,8 +6185,15 @@ Sigma_Exit:
 		}
 		break;
 
-    //! ### M104 - Set hotend temperature
-    // -----------------------------------------
+    /*!
+	### M104 - Set hotend temperature <a href="https://reprap.org/wiki/G-code#M104:_Set_Extruder_Temperature">M104: Set Extruder Temperature</a>
+	#### Usage
+    
+	    M104 [ S ]
+    
+	#### Parameters
+       - `S` - Target temperature
+    */
     case 104: // M104
     {
           uint8_t extruder;
@@ -5897,20 +6207,44 @@ Sigma_Exit:
           break;
     }
 
-    //! ### M112 - Emergency stop
-    // -----------------------------------------
+    /*!
+	### M112 - Emergency stop <a href="https://reprap.org/wiki/G-code#M112:_Full_.28Emergency.29_Stop">M112: Full (Emergency) Stop</a>
+    It is processed much earlier as to bypass the cmdqueue.
+    */
     case 112: 
-      kill(_n(""), 3);
+      kill(MSG_M112_KILL, 3);
       break;
 
-    //! ### M140 - Set bed temperature
-    // -----------------------------------------
+    /*!
+	### M140 - Set bed temperature <a href="https://reprap.org/wiki/G-code#M140:_Set_Bed_Temperature_.28Fast.29">M140: Set Bed Temperature (Fast)</a>
+    #### Usage
+    
+	    M140 [ S ]
+    
+	#### Parameters
+       - `S` - Target temperature
+    */
     case 140: 
       if (code_seen('S')) setTargetBed(code_value());
       break;
 
-    //! ### M105 - Report temperatures
-    // ----------------------------------------- 
+    /*!
+	### M105 - Report temperatures <a href="https://reprap.org/wiki/G-code#M105:_Get_Extruder_Temperature">M105: Get Extruder Temperature</a>
+	Prints temperatures:
+	
+	  - `T:`  - Hotend (actual / target)
+	  - `B:`  - Bed (actual / target)
+	  - `Tx:` - x Tool (actual / target)
+	  - `@:`  - Hotend power
+	  - `B@:` - Bed power
+	  - `P:`  - PINDAv2 actual (only MK2.5/s and MK3/s)
+	  - `A:`  - Ambient actual (only MK3/s)
+	
+	_Example:_
+	
+	    ok T:20.2 /0.0 B:19.1 /0.0 T0:20.2 /0.0 @:0 B@:0 P:19.8 A:26.4
+	
+    */
     case 105:
     {
       uint8_t extruder;
@@ -6006,16 +6340,22 @@ Sigma_Exit:
       break;
     }
 
-    //! ### M109 - Wait for extruder temperature
-    //! Parameters (not mandatory):
-    //! * S \<temp\> set extruder temperature
-    //! * R \<temp\> set extruder temperature
-    //!
-    //! Parameters S and R are treated identically.
-    //! Command always waits for both cool down and heat up.
-    //! If no parameters are supplied waits for previously
-    //! set extruder temperature.
-    // -------------------------------------------------
+    /*!
+	### M109 - Wait for extruder temperature <a href="https://reprap.org/wiki/G-code#M109:_Set_Extruder_Temperature_and_Wait">M109: Set Extruder Temperature and Wait</a>
+    #### Usage
+    
+	    M104 [ B | R | S ]
+    
+    #### Parameters (not mandatory)
+     
+	  - `S` - Set extruder temperature
+      - `R` - Set extruder temperature
+	  - `B` - Set max. extruder temperature, while `S` is min. temperature. Not active in default, only if AUTOTEMP is defined in source code.
+    
+    Parameters S and R are treated identically.
+    Command always waits for both cool down and heat up.
+    If no parameters are supplied waits for previously set extruder temperature.
+    */
     case 109:
     {
       uint8_t extruder;
@@ -6065,12 +6405,19 @@ Sigma_Exit:
       }
       break;
 
-    //! ### M190 - Wait for bed temperature
-    //! Parameters (not mandatory):
-    //! * S \<temp\> set extruder temperature and wait for heating
-    //! * R \<temp\> set extruder temperature and wait for heating or cooling
-    //!
-    //! If no parameter is supplied, waits for heating or cooling to previously set temperature.
+    /*!
+	### M190 - Wait for bed temperature <a href="https://reprap.org/wiki/G-code#M190:_Wait_for_bed_temperature_to_reach_target_temp">M190: Wait for bed temperature to reach target temp</a>
+    #### Usage
+    
+        M190 [ R | S ]
+    
+    #### Parameters (not mandatory)
+    
+	  - `S` - Set extruder temperature and wait for heating
+      - `R` - Set extruder temperature and wait for heating or cooling
+    
+    If no parameter is supplied, waits for heating or cooling to previously set temperature.
+	*/
     case 190: 
     #if defined(TEMP_BED_PIN) && TEMP_BED_PIN > -1
     {
@@ -6125,8 +6472,15 @@ Sigma_Exit:
 
     #if defined(FAN_PIN) && FAN_PIN > -1
 
-      //! ### M106 - Set fan speed
-      // -------------------------------------------
+      /*!
+	  ### M106 - Set fan speed <a href="https://reprap.org/wiki/G-code#M106:_Fan_On">M106: Fan On</a>
+      #### Usage
+      
+        M106 [ S ]
+        
+      #### Parameters
+      - `S` - Specifies the duty cycle of the print fan. Allowed values are 0-255. If it's omitted, a value of 255 is used.
+      */
       case 106: // M106 Sxxx Fan On S<speed> 0 .. 255
         if (code_seen('S')){
            fanSpeed=constrain(code_value(),0,255);
@@ -6136,8 +6490,9 @@ Sigma_Exit:
         }
         break;
 
-      //! ### M107 - Fan off
-      // -------------------------------
+      /*!
+	  ### M107 - Fan off <a href="https://reprap.org/wiki/G-code#M107:_Fan_Off">M107: Fan Off</a>
+      */
       case 107:
         fanSpeed = 0;
         break;
@@ -6145,8 +6500,10 @@ Sigma_Exit:
 
     #if defined(PS_ON_PIN) && PS_ON_PIN > -1
 
-      //! ### M80 - Turn on the Power Supply
-      // -------------------------------
+      /*!
+	  ### M80 - Turn on the Power Supply <a href="https://reprap.org/wiki/G-code#M80:_ATX_Power_On">M80: ATX Power On</a>
+      Only works if the firmware is compiled with PS_ON_PIN defined.
+      */
       case 80:
         SET_OUTPUT(PS_ON_PIN); //GND
         WRITE(PS_ON_PIN, PS_ON_AWAKE);
@@ -6163,10 +6520,11 @@ Sigma_Exit:
           LCD_MESSAGERPGM(_T(WELCOME_MSG));
           lcd_update(0);
         break;
-      #endif
 
-      //! ### M81 - Turn off Power Supply
-      // --------------------------------------
+      /*!
+	  ### M81 - Turn off Power Supply <a href="https://reprap.org/wiki/G-code#M81:_ATX_Power_Off">M81: ATX Power Off</a>
+      Only works if the firmware is compiled with PS_ON_PIN defined.
+      */
       case 81: 
         disable_heater();
         st_synchronize();
@@ -6187,25 +6545,42 @@ Sigma_Exit:
         LCD_MESSAGERPGM(CAT4(CUSTOM_MENDEL_NAME,PSTR(" "),MSG_OFF,PSTR(".")));
         lcd_update(0);
 	  break;
+    #endif
 
-    //! ### M82 - Set E axis to absolute mode
-    // ---------------------------------------
+    /*!
+	### M82 - Set E axis to absolute mode <a href="https://reprap.org/wiki/G-code#M82:_Set_extruder_to_absolute_mode">M82: Set extruder to absolute mode</a>
+	Makes the extruder interpret extrusion as absolute positions.
+    */
     case 82:
-      axis_relative_modes[3] = false;
+      axis_relative_modes[E_AXIS] = false;
       break;
 
-    //! ### M83 - Set E axis to relative mode
-    // ---------------------------------------  
+    /*!
+	### M83 - Set E axis to relative mode <a href="https://reprap.org/wiki/G-code#M83:_Set_extruder_to_relative_mode">M83: Set extruder to relative mode</a>
+	Makes the extruder interpret extrusion values as relative positions.
+    */
     case 83:
-      axis_relative_modes[3] = true;
+      axis_relative_modes[E_AXIS] = true;
       break;
 
-    //! ### M84, M18 - Disable steppers
-    //---------------------------------------
-    //! This command can be used to set the stepper inactivity timeout (`S`) or to disable steppers (`X`,`Y`,`Z`,`E`)
-    //! 
-    //!     M84 [E<flag>] [S<seconds>] [X<flag>] [Y<flag>] [Z<flag>]  
-    //! 
+    /*!
+	### M84 - Disable steppers <a href="https://reprap.org/wiki/G-code#M84:_Stop_idle_hold">M84: Stop idle hold</a>
+    This command can be used to set the stepper inactivity timeout (`S`) or to disable steppers (`X`,`Y`,`Z`,`E`)
+	This command can be used without any additional parameters. In that case all steppers are disabled.
+    
+    The file completeness check uses this parameter to detect an incomplete file. It has to be present at the end of a file with no parameters.
+	
+        M84 [ S | X | Y | Z | E ]
+	
+	  - `S` - Seconds
+	  - `X` - X axis
+	  - `Y` - Y axis
+	  - `Z` - Z axis
+	  - `E` - Exruder
+
+	### M18 - Disable steppers <a href="https://reprap.org/wiki/G-code#M18:_Disable_all_stepper_motors">M18: Disable all stepper motors</a>
+	Equal to M84 (compatibility)
+    */
     case 18: //compatibility
     case 84: // M84
       if(code_seen('S')){
@@ -6242,8 +6617,15 @@ Sigma_Exit:
 	  snmm_filaments_used = 0;
       break;
 
-    //! ### M85 - Set max inactive time
-    // ---------------------------------------
+    /*!
+	### M85 - Set max inactive time <a href="https://reprap.org/wiki/G-code#M85:_Set_Inactivity_Shutdown_Timer">M85: Set Inactivity Shutdown Timer</a>
+    #### Usage
+    
+        M85 [ S ]
+    
+    #### Parameters
+    - `S` - specifies the time in seconds. If a value of 0 is specified, the timer is disabled.
+    */
     case 85: // M85
       if(code_seen('S')) {
         max_inactive_time = code_value() * 1000;
@@ -6251,13 +6633,16 @@ Sigma_Exit:
       break;
 #ifdef SAFETYTIMER
 
-  //! ### M86 - Set safety timer expiration time
-  //!
-  //! _Usage:_
-  //!     M86 S<seconds>
-  //! 
-  //! Sets the safety timer expiration time in seconds. M86 S0 will disable safety timer.
-  //! When safety timer expires, heatbed and nozzle target temperatures are set to zero.
+    /*!
+    ### M86 - Set safety timer expiration time <a href="https://reprap.org/wiki/G-code#M86:_Set_Safety_Timer_expiration_time">M86: Set Safety Timer expiration time</a>	
+    When safety timer expires, heatbed and nozzle target temperatures are set to zero.
+    #### Usage
+    
+        M86 [ S ]
+    
+    #### Parameters
+    - `S` - specifies the time in seconds. If a value of 0 is specified, the timer is disabled.
+    */
 	case 86: 
 	  if (code_seen('S')) {
 	    safetytimer_inactive_time = code_value() * 1000;
@@ -6266,9 +6651,19 @@ Sigma_Exit:
 	  break;
 #endif
 
-    //! ### M92 Set Axis steps-per-unit
-    // ---------------------------------------
-    //! Same syntax as G92
+    /*!
+	### M92 Set Axis steps-per-unit <a href="https://reprap.org/wiki/G-code#M92:_Set_axis_steps_per_unit">M92: Set axis_steps_per_unit</a>
+	Allows programming of steps per unit (usually mm) for motor drives. These values are reset to firmware defaults on power on, unless saved to EEPROM if available (M500 in Marlin)
+	#### Usage
+    
+	    M92 [ X | Y | Z | E ]
+	
+    #### Parameters
+	- `X` - Steps per unit for the X drive
+	- `Y` - Steps per unit for the Y drive
+	- `Z` - Steps per unit for the Z drive
+	- `E` - Steps per unit for the extruder drive
+    */
     case 92:
       for(int8_t i=0; i < NUM_AXIS; i++)
       {
@@ -6291,15 +6686,31 @@ Sigma_Exit:
       }
       break;
 
-    //! ### M110 - Set Line number
-    // ---------------------------------------
+    /*!
+	### M110 - Set Line number <a href="https://reprap.org/wiki/G-code#M110:_Set_Current_Line_Number">M110: Set Current Line Number</a>
+	Sets the line number in G-code
+	#### Usage
+    
+	    M110 [ N ]
+	
+    #### Parameters
+	- `N` - Line number
+    */
     case 110:
       if (code_seen('N'))
 	    gcode_LastN = code_value_long();
     break;
 
-  //! ### M113 - Get or set host keep-alive interval
-  // ------------------------------------------ 
+    /*!
+    ### M113 - Get or set host keep-alive interval <a href="https://reprap.org/wiki/G-code#M113:_Host_Keepalive">M113: Host Keepalive</a>
+    During some lengthy processes, such as G29, Marlin may appear to the host to have “gone away.” The “host keepalive” feature will send messages to the host when Marlin is busy or waiting for user response so the host won’t try to reconnect (or disconnect).
+    #### Usage
+    
+        M113 [ S ]
+	
+    #### Parameters
+	- `S` - Seconds. Default is 2 seconds between "busy" messages
+    */
 	case 113:
 		if (code_seen('S')) {
 			host_keepalive_interval = (uint8_t)code_value_short();
@@ -6312,16 +6723,34 @@ Sigma_Exit:
 		}
 		break;
 
-    //! ### M115 - Firmware info
-    // --------------------------------------
-    //! Print the firmware info and capabilities
-    //! 
-    //!     M115 [V] [U<version>] 
-    //! 
-    //! Without any arguments, prints Prusa firmware version number, machine type, extruder count and UUID.
-    //! `M115 U` Checks the firmware version provided. If the firmware version provided by the U code is higher than the currently running firmware,
-    //!  pause the print for 30s and ask the user to upgrade the firmware. 
-    case 115: // M115
+    /*!
+	### M115 - Firmware info <a href="https://reprap.org/wiki/G-code#M115:_Get_Firmware_Version_and_Capabilities">M115: Get Firmware Version and Capabilities</a>
+    Print the firmware info and capabilities
+    Without any arguments, prints Prusa firmware version number, machine type, extruder count and UUID.
+    `M115 U` Checks the firmware version provided. If the firmware version provided by the U code is higher than the currently running firmware, it will pause the print for 30s and ask the user to upgrade the firmware.
+	
+	_Examples:_
+	
+	`M115` results:
+	
+	`FIRMWARE_NAME:Prusa-Firmware 3.8.1 based on Marlin FIRMWARE_URL:https://github.com/prusa3d/Prusa-Firmware PROTOCOL_VERSION:1.0 MACHINE_TYPE:Prusa i3 MK3S EXTRUDER_COUNT:1 UUID:00000000-0000-0000-0000-000000000000`
+	
+	`M115 V` results:
+	
+	`3.8.1`
+	
+	`M115 U3.8.2-RC1` results on LCD display for 30s or user interaction:
+	
+	`New firmware version available: 3.8.2-RC1 Please upgrade.`
+    #### Usage
+    
+        M115 [ V | U ]
+	
+    #### Parameters
+	- V - Report current installed firmware version
+	- U - Firmware version provided by G-code to be compared to current one.  
+	*/
+	case 115: // M115
       if (code_seen('V')) {
           // Report the Prusa version number.
           SERIAL_PROTOCOLLNRPGM(FW_VERSION_STR_P());
@@ -6343,16 +6772,13 @@ Sigma_Exit:
       }
       break;
 
-    //! ### M114 - Get current position
-    // -------------------------------------
+    /*!
+	### M114 - Get current position <a href="https://reprap.org/wiki/G-code#M114:_Get_Current_Position">M114: Get Current Position</a>
+    */
     case 114:
 		gcode_M114();
       break;
 
-
-
-      //! ### M117 - Set LCD Message
-      // -------------------------------------- 
       
       /*
         M117 moved up to get the high priority
@@ -6364,20 +6790,24 @@ Sigma_Exit:
       lcd_setstatus(strchr_pointer + 5);
       break;*/
 
-    //! ### M120 - Disable endstops
-    // ----------------------------------------
+    /*!
+	### M120 - Enable endstops <a href="https://reprap.org/wiki/G-code#M120:_Enable_endstop_detection">M120: Enable endstop detection</a>
+    */
     case 120:
       enable_endstops(false) ;
       break;
 
-    //! ### M121 - Enable endstops
-    // ----------------------------------------
+    /*!
+	### M121 - Disable endstops <a href="https://reprap.org/wiki/G-code#M121:_Disable_endstop_detection">M121: Disable endstop detection</a>
+    */
     case 121:
       enable_endstops(true) ;
       break;
 
-    //! ### M119 - Get endstop states
-    // ----------------------------------------
+    /*!
+	### M119 - Get endstop states <a href="https://reprap.org/wiki/G-code#M119:_Get_Endstop_Status">M119: Get Endstop Status</a>
+	Returns the current state of the configured X, Y, Z endstops. Takes into account any 'inverted endstop' settings, so one can confirm that the machine is interpreting the endstops correctly.
+    */
     case 119:
     SERIAL_PROTOCOLRPGM(_N("Reporting endstop status"));////MSG_M119_REPORT
     SERIAL_PROTOCOLLN("");
@@ -6436,12 +6866,22 @@ Sigma_Exit:
         SERIAL_PROTOCOLLN("");
       #endif
       break;
-      //TODO: update for all axis, use for loop
+      //!@todo update for all axes, use for loop
     
-    #ifdef BLINKM
 
-    //! ### M150 - Set RGB(W) Color
-    // -------------------------------------------
+    #ifdef BLINKM
+    /*!
+	### M150 - Set RGB(W) Color <a href="https://reprap.org/wiki/G-code#M150:_Set_LED_color">M150: Set LED color</a>
+	In Prusa Firmware this G-code is deactivated by default, must be turned on in the source code by defining BLINKM and its dependencies.
+    #### Usage
+    
+        M150 [ R | U | B ]
+    
+    #### Parameters
+    - `R` - Red color value
+    - `U` - Green color value. It is NOT `G`!
+    - `B` - Blue color value
+    */
     case 150:
       {
         byte red;
@@ -6457,8 +6897,16 @@ Sigma_Exit:
       break;
     #endif //BLINKM
 
-    //! ### M200 - Set filament diameter
-    // ----------------------------------------
+    /*!
+	### M200 - Set filament diameter <a href="https://reprap.org/wiki/G-code#M200:_Set_filament_diameter">M200: Set filament diameter</a>
+	#### Usage
+    
+	    M200 [ D | T ]
+	
+    #### Parameters
+	  - `D` - Diameter in mm
+	  - `T` - Number of extruder (MMUs)
+    */
     case 200: // M200 D<millimeters> set filament diameter and set E axis units to cubic millimeters (use S0 to set back to millimeters).
       {
 
@@ -6483,10 +6931,10 @@ Sigma_Exit:
 			// make sure all extruders have some sane value for the filament size
 			cs.filament_size[0] = (cs.filament_size[0] == 0.0 ? DEFAULT_NOMINAL_FILAMENT_DIA : cs.filament_size[0]);
             #if EXTRUDERS > 1
-			cs.filament_size[1] = (cs.filament_size[1] == 0.0 ? DEFAULT_NOMINAL_FILAMENT_DIA : cs.filament_size[1]);
-            #if EXTRUDERS > 2
-			cs.filament_size[2] = (cs.filament_size[2] == 0.0 ? DEFAULT_NOMINAL_FILAMENT_DIA : cs.filament_size[2]);
-            #endif
+				cs.filament_size[1] = (cs.filament_size[1] == 0.0 ? DEFAULT_NOMINAL_FILAMENT_DIA : cs.filament_size[1]);
+				#if EXTRUDERS > 2
+					cs.filament_size[2] = (cs.filament_size[2] == 0.0 ? DEFAULT_NOMINAL_FILAMENT_DIA : cs.filament_size[2]);
+				#endif
             #endif
 			cs.volumetric_enabled = true;
 		  }
@@ -6498,8 +6946,10 @@ Sigma_Exit:
       }
       break;
 
-    //! ### M201 - Set Print Max Acceleration
-    // -------------------------------------------
+    /*!
+	### M201 - Set Print Max Acceleration <a href="https://reprap.org/wiki/G-code#M201:_Set_max_printing_acceleration">M201: Set max printing acceleration</a>
+    For each axis individually.
+    */
     case 201:
 		for (int8_t i = 0; i < NUM_AXIS; i++)
 		{
@@ -6533,8 +6983,10 @@ Sigma_Exit:
       break;
     #endif
 
-    //! ### M203 - Set Max Feedrate
-    // ---------------------------------------
+    /*!
+	### M203 - Set Max Feedrate <a href="https://reprap.org/wiki/G-code#M203:_Set_maximum_feedrate">M203: Set maximum feedrate</a>
+    For each axis individually.
+    */
     case 203: // M203 max feedrate mm/sec
 		for (int8_t i = 0; i < NUM_AXIS; i++)
 		{
@@ -6559,15 +7011,28 @@ Sigma_Exit:
 		}
 		break;
 
-    //! ### M204 - Acceleration settings
-    // ------------------------------------------
-    //! Supporting old format: 
-    //!
-    //!         M204 S[normal moves] T[filmanent only moves]
-    //!
-    //! and new format:        
-    //!
-    //!         M204 P[printing moves] R[filmanent only moves] T[travel moves] (as of now T is ignored)
+    /*!
+	### M204 - Acceleration settings <a href="https://reprap.org/wiki/G-code#M204:_Set_default_acceleration">M204: Set default acceleration</a>
+
+    #### Old format:
+    ##### Usage
+    
+        M204 [ S | T ]
+        
+    ##### Parameters
+    - `S` - normal moves
+    - `T` - filmanent only moves
+    
+    #### New format:
+    ##### Usage
+    
+        M204 [ P | R | T ]
+    
+    ##### Parameters
+    - `P` - printing moves
+    - `R` - filmanent only moves
+    - `T` - travel moves (as of now T is ignored)
+	*/
     case 204:
       {
         if(code_seen('S')) {
@@ -6586,23 +7051,30 @@ Sigma_Exit:
             cs.retract_acceleration = code_value();
           if(code_seen('T')) {
             // Interpret the T value as the travel acceleration in the new Marlin format.
-            //FIXME Prusa3D firmware currently does not support travel acceleration value independent from the extruding acceleration value.
+            /*!
+            @todo Prusa3D firmware currently does not support travel acceleration value independent from the extruding acceleration value.
+            */
             // travel_acceleration = code_value();
           }
         }
       }
       break;
 
-    //! ### M205 - Set advanced settings
-    // --------------------------------------------- 
-    //! Set some advanced settings related to movement.
-    //!
-    //!          M205 [S] [T] [B] [X] [Y] [Z] [E]
     /*!
+	### M205 - Set advanced settings <a href="https://reprap.org/wiki/G-code#M205:_Advanced_settings">M205: Advanced settings</a>
+    Set some advanced settings related to movement.
+    #### Usage
+    
+        M205 [ S | T | B | X | Y | Z | E ]
+        
+    #### Parameters
     - `S` - Minimum feedrate for print moves (unit/s)
     - `T` - Minimum feedrate for travel moves (units/s)
     - `B` - Minimum segment time (us)
-    - `X` - Maximum X jerk (units/s), similarly for other axes
+    - `X` - Maximum X jerk (units/s)
+    - `Y` - Maximum Y jerk (units/s)
+    - `Z` - Maximum Z jerk (units/s)
+    - `E` - Maximum E jerk (units/s)
     */
     case 205: 
     {
@@ -6618,8 +7090,17 @@ Sigma_Exit:
     }
     break;
 
-    //! ### M206 - Set additional homing offsets
-    // ----------------------------------------------
+    /*!
+	### M206 - Set additional homing offsets <a href="https://reprap.org/wiki/G-code#M206:_Offset_axes">M206: Offset axes</a>
+    #### Usage
+    
+        M206 [ X | Y | Z ]
+    
+    #### Parameters
+    - `X` - X axis offset
+    - `Y` - Y axis offset
+    - `Z` - Z axis offset
+	*/
     case 206:
       for(int8_t i=0; i < 3; i++)
       {
@@ -6628,8 +7109,17 @@ Sigma_Exit:
       break;
     #ifdef FWRETRACT
 
-    //! ### M207 - Set firmware retraction
-    // --------------------------------------------------
+    /*!
+	### M207 - Set firmware retraction <a href="https://reprap.org/wiki/G-code#M207:_Set_retract_length">M207: Set retract length</a>
+	#### Usage
+    
+        M207 [ S | F | Z ]
+    
+    #### Parameters
+    - `S` - positive length to retract, in mm
+    - `F` - retraction feedrate, in mm/min
+    - `Z` - additional zlift/hop
+    */
     case 207: //M207 - set retract length S[positive mm] F[feedrate mm/min] Z[additional zlift/hop]
     {
       if(code_seen('S'))
@@ -6646,8 +7136,16 @@ Sigma_Exit:
       }
     }break;
 
-    //! ### M208 - Set retract recover length
-    // --------------------------------------------
+    /*!
+	### M208 - Set retract recover length <a href="https://reprap.org/wiki/G-code#M208:_Set_unretract_length">M208: Set unretract length</a>
+	#### Usage
+    
+        M208 [ S | F ]
+    
+    #### Parameters
+    - `S` - positive length surplus to the M207 Snnn, in mm
+    - `F` - feedrate, in mm/sec
+    */
     case 208: // M208 - set retract recover length S[positive mm surplus to the M207 S*] F[feedrate mm/min]
     {
       if(code_seen('S'))
@@ -6660,8 +7158,16 @@ Sigma_Exit:
       }
     }break;
 
-    //! ### M209 - Enable/disable automatict retract
-    // ---------------------------------------------
+    /*!
+	### M209 - Enable/disable automatict retract <a href="https://reprap.org/wiki/G-code#M209:_Enable_automatic_retract">M209: Enable automatic retract</a>
+	This boolean value S 1=true or 0=false enables automatic retract detect if the slicer did not support G10/G11: every normal extrude-only move will be classified as retract depending on the direction.
+    #### Usage
+    
+        M209 [ S ]
+        
+    #### Parameters
+    - `S` - 1=true or 0=false
+    */
     case 209: // M209 - S<1=true/0=false> enable automatic retract detect if the slicer did not support G10/11: every normal extrude-only move will be classified as retract depending on the direction.
     {
       if(code_seen('S'))
@@ -6703,8 +7209,17 @@ Sigma_Exit:
     #endif // FWRETRACT
     #if EXTRUDERS > 1
 
-    // ### M218 - Set hotend offset
-    // ----------------------------------------
+    /*!
+	### M218 - Set hotend offset <a href="https://reprap.org/wiki/G-code#M218:_Set_Hotend_Offset">M218: Set Hotend Offset</a>
+	In Prusa Firmware this G-code is only active if `EXTRUDERS` is higher then 1 in the source code. On Original i3 Prusa MK2/s MK2.5/s MK3/s it is not active.
+    #### Usage
+    
+        M218 [ X | Y ]
+        
+    #### Parameters
+    - `X` - X offset
+    - `Y` - Y offset
+    */
     case 218: // M218 - set hotend offset (in mm), T<extruder_number> X<offset_on_X> Y<offset_on_Y>
     {
       uint8_t extruder;
@@ -6732,8 +7247,17 @@ Sigma_Exit:
     }break;
     #endif
 
-    //! ### M220 Set feedrate percentage
-    // -----------------------------------------------
+    /*!
+	### M220 Set feedrate percentage <a href="https://reprap.org/wiki/G-code#M220:_Set_speed_factor_override_percentage">M220: Set speed factor override percentage</a>
+	#### Usage
+    
+        M220 [ B | S | R ]
+    
+    #### Parameters
+    - `B` - Backup current speed factor
+	- `S` - Speed factor override percentage (0..100 or higher)
+	- `R` - Restore previous speed factor
+    */
     case 220: // M220 S<factor in percent>- set speed factor override percentage
     {
       if (code_seen('B')) //backup current speed factor
@@ -6750,8 +7274,16 @@ Sigma_Exit:
     }
     break;
 
-    //! ### M221 - Set extrude factor override percentage
-    // ----------------------------------------------------
+    /*!
+	### M221 - Set extrude factor override percentage <a href="https://reprap.org/wiki/G-code#M221:_Set_extrude_factor_override_percentage">M221: Set extrude factor override percentage</a>
+	#### Usage
+    
+        M221 [ S | T ]
+    
+    #### Parameters
+	- `S` - Extrude factor override percentage (0..100 or higher), default 100%
+	- `T` - Extruder drive number (Prusa Firmware only), default 0 if not set.
+    */
     case 221: // M221 S<factor in percent>- set extrude factor override percentage
     {
       if(code_seen('S'))
@@ -6774,8 +7306,17 @@ Sigma_Exit:
     }
     break;
 
-  //! ### M226 - Wait for Pin state
-  // ------------------------------------------
+    /*!
+    ### M226 - Wait for Pin state <a href="https://reprap.org/wiki/G-code#M226:_Wait_for_pin_state">M226: Wait for pin state</a>
+    Wait until the specified pin reaches the state required
+    #### Usage
+    
+        M226 [ P | S ]
+    
+    #### Parameters
+    - `P` - pin number
+    - `S` - pin state
+    */
 	case 226: // M226 P<pin number> S<pin state>- Wait until the specified pin reaches the state required
 	{
       if(code_seen('P')){
@@ -6830,8 +7371,17 @@ Sigma_Exit:
 
     #if NUM_SERVOS > 0
 
-    //! ### M280 - Set/Get servo position
-    // --------------------------------------------
+    /*!
+	### M280 - Set/Get servo position <a href="https://reprap.org/wiki/G-code#M280:_Set_servo_position">M280: Set servo position</a>
+	In Prusa Firmware this G-code is deactivated by default, must be turned on in the source code.
+    #### Usage
+    
+        M280 [ P | S ]
+    
+    #### Parameters
+    - `P` - Servo index (id)
+    - `S` - Target position
+    */
     case 280: // M280 - set servo position absolute. P: servo index, S: angle or microseconds
       {
         int servo_index = -1;
@@ -6871,8 +7421,17 @@ Sigma_Exit:
 
     #if (LARGE_FLASH == true && ( BEEPER > 0 || defined(ULTRALCD) || defined(LCD_USE_I2C_BUZZER)))
     
-    //! ### M300 - Play tone
-    // -----------------------
+    /*!
+	### M300 - Play tone <a href="https://reprap.org/wiki/G-code#M300:_Play_beep_sound">M300: Play beep sound</a>
+	In Prusa Firmware the defaults are `100Hz` and `1000ms`, so that `M300` without parameters will beep for a second.
+    #### Usage
+    
+        M300 [ S | P ]
+    
+    #### Parameters
+    - `S` - frequency in Hz. Not all firmware versions support this parameter
+    - `P` - duration in milliseconds
+    */
     case 300: // M300
     {
       int beepS = code_seen('S') ? code_value() : 110;
@@ -6893,8 +7452,20 @@ Sigma_Exit:
 
     #ifdef PIDTEMP
 
-    //! ### M301 - Set hotend PID
-    // ---------------------------------------
+    /*!
+	### M301 - Set hotend PID <a href="https://reprap.org/wiki/G-code#M301:_Set_PID_parameters">M301: Set PID parameters</a>
+	Sets Proportional (P), Integral (I) and Derivative (D) values for hot end.
+    See also <a href="https://reprap.org/wiki/PID_Tuning">PID Tuning.</a>
+    #### Usage
+    
+        M301 [ P | I | D | C ]
+    
+    #### Parameters
+    - `P` - proportional (Kp)
+    - `I` - integral (Ki)
+    - `D` - derivative (Kd)
+    - `C` - heating power=Kc*(e_speed0)  
+    */
     case 301:
       {
         if(code_seen('P')) cs.Kp = code_value();
@@ -6924,8 +7495,19 @@ Sigma_Exit:
     #endif //PIDTEMP
     #ifdef PIDTEMPBED
 
-    //! ### M304 - Set bed PID 
-    // --------------------------------------
+    /*!
+	### M304 - Set bed PID  <a href="https://reprap.org/wiki/G-code#M304:_Set_PID_parameters_-_Bed">M304: Set PID parameters - Bed</a>
+	Sets Proportional (P), Integral (I) and Derivative (D) values for bed.
+    See also <a href="https://reprap.org/wiki/PID_Tuning">PID Tuning.</a>
+    #### Usage
+    
+        M304 [ P | I | D ]
+    
+    #### Parameters
+    - `P` - proportional (Kp)
+    - `I` - integral (Ki)
+    - `D` - derivative (Kd)
+    */
     case 304:
       {
         if(code_seen('P')) cs.bedKp = code_value();
@@ -6945,8 +7527,13 @@ Sigma_Exit:
       break;
     #endif //PIDTEMP
 
-    //! ### M240 - Trigger camera
-    // --------------------------------------------
+    /*!
+	### M240 - Trigger camera <a href="https://reprap.org/wiki/G-code#M240:_Trigger_camera">M240: Trigger camera</a>
+	
+	In Prusa Firmware this G-code is deactivated by default, must be turned on in the source code.
+	
+	You need to (re)define and assign `CHDK` or `PHOTOGRAPH_PIN` the correct pin number to be able to use the feature.
+    */
     case 240: // M240  Triggers a camera by emulating a Canon RC-1 : http://www.doc-diy.net/photo/rc-1_hacked/
      {
      	#ifdef CHDK
@@ -6980,8 +7567,16 @@ Sigma_Exit:
     break;
     #ifdef PREVENT_DANGEROUS_EXTRUDE
 
-    //! ### M302 - Allow cold extrude, or set minimum extrude temperature
-    // -------------------------------------------------------------------
+    /*!
+	### M302 - Allow cold extrude, or set minimum extrude temperature <a href="https://reprap.org/wiki/G-code#M302:_Allow_cold_extrudes">M302: Allow cold extrudes</a>
+    This tells the printer to allow movement of the extruder motor above a certain temperature, or if disabled, to allow extruder movement when the hotend is below a safe printing temperature.
+    #### Usage
+    
+        M302 [ S ]
+    
+    #### Parameters
+    - `S` - Cold extrude minimum temperature
+    */
     case 302:
     {
 	  float temp = .0;
@@ -6991,8 +7586,18 @@ Sigma_Exit:
     break;
 	#endif
 
-    //! ### M303 - PID autotune
-    // -------------------------------------
+    /*!
+	### M303 - PID autotune <a href="https://reprap.org/wiki/G-code#M303:_Run_PID_tuning">M303: Run PID tuning</a>
+    PID Tuning refers to a control algorithm used in some repraps to tune heating behavior for hot ends and heated beds. This command generates Proportional (Kp), Integral (Ki), and Derivative (Kd) values for the hotend or bed. Send the appropriate code and wait for the output to update the firmware values.
+    #### Usage
+    
+        M303 [ E | S | C ]
+    
+    #### Parameters
+      - `E` - Extruder, default `E0`. Use `E-1` to calibrate the bed PID
+      - `S` - Target temperature, default `210°C` for hotend, 70 for bed
+      - `C` - Cycles, default `5`
+	*/
     case 303:
     {
       float temp = 150.0;
@@ -7007,17 +7612,30 @@ Sigma_Exit:
     }
     break;
     
-    //! ### M400 - Wait for all moves to finish
-    // -----------------------------------------
+    /*!
+	### M400 - Wait for all moves to finish <a href="https://reprap.org/wiki/G-code#M400:_Wait_for_current_moves_to_finish">M400: Wait for current moves to finish</a>
+	Finishes all current moves and and thus clears the buffer.
+    Equivalent to `G4` with no parameters.
+    */
     case 400:
     {
       st_synchronize();
     }
     break;
 
-  //! ### M403 - Set filament type (material) for particular extruder and notify the MMU
-	// ----------------------------------------------
-  case 403:
+    /*!
+	### M403 - Set filament type (material) for particular extruder and notify the MMU <a href="https://reprap.org/wiki/G-code#M403:_Set_filament_type_.28material.29_for_particular_extruder_and_notify_the_MMU.">M403 - Set filament type (material) for particular extruder and notify the MMU</a>
+    Currently three different materials are needed (default, flex and PVA).  
+    And storing this information for different load/unload profiles etc. in the future firmware does not have to wait for "ok" from MMU.
+    #### Usage
+    
+        M403 [ E | F ]
+    
+    #### Parameters
+    - `E` - Extruder number. 0-indexed.
+    - `F` - Filament type
+	*/
+    case 403:
 	{
 		// currently three different materials are needed (default, flex and PVA)
 		// add storing this information for different load/unload profiles etc. in the future
@@ -7033,40 +7651,51 @@ Sigma_Exit:
 	}
 	break;
 
-    //! ### M500 - Store settings in EEPROM
-    // -----------------------------------------
+    /*!
+	### M500 - Store settings in EEPROM <a href="https://reprap.org/wiki/G-code#M500:_Store_parameters_in_non-volatile_storage">M500: Store parameters in non-volatile storage</a>
+	Save current parameters to EEPROM.
+    */
     case 500:
     {
         Config_StoreSettings();
     }
     break;
 
-    //! ### M501 - Read settings from EEPROM
-    // ----------------------------------------
+    /*!
+	### M501 - Read settings from EEPROM <a href="https://reprap.org/wiki/G-code#M501:_Read_parameters_from_EEPROM">M501: Read parameters from EEPROM</a>
+	Set the active parameters to those stored in the EEPROM. This is useful to revert parameters after experimenting with them.
+    */
     case 501:
     {
         Config_RetrieveSettings();
     }
     break;
 
-    //! ### M502 - Revert all settings to factory default
-    // -------------------------------------------------
+    /*!
+	### M502 - Revert all settings to factory default <a href="https://reprap.org/wiki/G-code#M502:_Restore_Default_Settings">M502: Restore Default Settings</a>
+	This command resets all tunable parameters to their default values, as set in the firmware's configuration files. This doesn't reset any parameters stored in the EEPROM, so it must be followed by M500 to write the default settings.
+    */
     case 502:
     {
         Config_ResetDefault();
     }
     break;
 
-    //! ### M503 - Repport all settings currently in memory
-    // -------------------------------------------------
+    /*!
+	### M503 - Repport all settings currently in memory <a href="https://reprap.org/wiki/G-code#M503:_Report_Current_Settings">M503: Report Current Settings</a>
+	This command asks the firmware to reply with the current print settings as set in memory. Settings will differ from EEPROM contents if changed since the last load / save. The reply output includes the G-Code commands to produce each setting. For example, Steps-Per-Unit values are displayed as an M92 command.
+    */
     case 503:
     {
         Config_PrintSettings();
     }
     break;
 
-    //! ### M509 - Force language selection
-    // ------------------------------------------------
+    /*!
+	### M509 - Force language selection <a href="https://reprap.org/wiki/G-code#M509:_Force_language_selection">M509: Force language selection</a>
+	Resets the language to English.
+	Only on Original Prusa i3 MK2.5/s and MK3/s with multiple languages.
+	*/
     case 509:
     {
 		lang_reset();
@@ -7076,8 +7705,16 @@ Sigma_Exit:
     break;
     #ifdef ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED
 
-    //! ### M540 - Abort print on endstop hit (enable/disable)
-    // -----------------------------------------------------
+    /*!
+	### M540 - Abort print on endstop hit (enable/disable) <a href="https://reprap.org/wiki/G-code#M540_in_Marlin:_Enable.2FDisable_.22Stop_SD_Print_on_Endstop_Hit.22">M540 in Marlin: Enable/Disable "Stop SD Print on Endstop Hit"</a>
+	In Prusa Firmware this G-code is deactivated by default, must be turned on in the source code. You must define `ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED`.
+    #### Usage
+    
+        M540 [ S ]
+    
+    #### Parameters
+    - `S` - disabled=0, enabled=1
+	*/
     case 540:
     {
         if(code_seen('S')) abort_on_endstop_hit = code_value() > 0;
@@ -7085,6 +7722,17 @@ Sigma_Exit:
     break;
     #endif
 
+	/*!
+	### M851 - Set Z-Probe Offset <a href="https://reprap.org/wiki/G-code#M851:_Set_Z-Probe_Offset">M851: Set Z-Probe Offset"</a>
+    Sets the Z-probe Z offset. This offset is used to determine the actual Z position of the nozzle when using a probe to home Z with G28. This value may also be used by G81 (Prusa) / G29 (Marlin) to apply correction to the Z position.
+	This value represents the distance from nozzle to the bed surface at the point where the probe is triggered. This value will be negative for typical switch probes, inductive probes, and setups where the nozzle makes a circuit with a raised metal contact. This setting will be greater than zero on machines where the nozzle itself is used as the probe, pressing down on the bed to press a switch. (This is a common setup on delta machines.)
+    #### Usage
+    
+        M851 [ Z ]
+    
+    #### Parameters
+    - `Z` - Z offset probe to nozzle.
+	*/
     #ifdef CUSTOM_M_CODE_SET_Z_PROBE_OFFSET
     case CUSTOM_M_CODE_SET_Z_PROBE_OFFSET:
     {
@@ -7123,8 +7771,21 @@ Sigma_Exit:
 
     #ifdef FILAMENTCHANGEENABLE
 
-    //! ### M600 - Initiate Filament change procedure
-    // --------------------------------------
+    /*!
+	### M600 - Initiate Filament change procedure <a href="https://reprap.org/wiki/G-code#M600:_Filament_change_pause">M600: Filament change pause</a>
+    Initiates Filament change, it is also used during Filament Runout Sensor process.
+	If the `M600` is triggered under 25mm it will do a Z-lift of 25mm to prevent a filament blob.
+    #### Usage
+    
+        M600 [ X | Y | Z | E | L | AUTO ]
+      
+    - `X`    - X position, default 211
+    - `Y`    - Y position, default 0
+    - `Z`    - relative lift Z, default 2.
+    - `E`    - initial retract, default -2
+    - `L`    - later retract distance for removal, default -80
+    - `AUTO` - Automatically (only with MMU)
+    */
     case 600: //Pause for filament change X[pos] Y[pos] Z[relative lift] E[initial retract] L[later retract distance for removal]
 	{
 		st_synchronize();
@@ -7200,37 +7861,55 @@ Sigma_Exit:
     break;
     #endif //FILAMENTCHANGEENABLE
 
-  //! ### M601 - Pause print
-  // -------------------------------
+    /*!
+    ### M601 - Pause print <a href="https://reprap.org/wiki/G-code#M601:_Pause_print">M601: Pause print</a>
+    */
+    /*!
+    ### M125 - Pause print (TODO: not implemented)
+    */
+    /*!
+    ### M25 - Pause SD print <a href="https://reprap.org/wiki/G-code#M25:_Pause_SD_print">M25: Pause SD print</a>
+    */
+	case 25:
 	case 601:
 	{
-		cmdqueue_pop_front(); //trick because we want skip this command (M601) after restore
-		lcd_pause_print();
+        if (!isPrintPaused)
+        {
+            st_synchronize();
+            cmdqueue_pop_front(); //trick because we want skip this command (M601) after restore
+            lcd_pause_print();
+        }
 	}
 	break;
 
-  //! ### M602 - Resume print
-  // -------------------------------
+    /*!
+	### M602 - Resume print <a href="https://reprap.org/wiki/G-code#M602:_Resume_print">M602: Resume print</a>
+    */
 	case 602: {
-		lcd_resume_print();
+	  if (isPrintPaused)
+          lcd_resume_print();
 	}
 	break;
 
-  //! ### M603 - Stop print
-  // -------------------------------
-  case 603: {
+    /*!
+    ### M603 - Stop print <a href="https://reprap.org/wiki/G-code#M603:_Stop_print">M603: Stop print</a>
+    */
+	case 603: {
 		lcd_print_stop();
 	}
+	break;
 
 #ifdef PINDA_THERMISTOR
-  //! ### M860 - Wait for extruder temperature (PINDA)
-  // --------------------------------------------------------------
-  /*! 
-      Wait for PINDA thermistor to reach target temperature
-      
-                M860 [S<target_temperature>]
-      
-  */
+    /*!
+	### M860 - Wait for extruder temperature (PINDA) <a href="https://reprap.org/wiki/G-code#M860_Wait_for_Probe_Temperature">M860 Wait for Probe Temperature</a>
+    Wait for PINDA thermistor to reach target temperature
+    #### Usage
+    
+        M860 [ S ]
+    
+    #### Parameters
+    - `S` - Target temperature
+    */
 	case 860: 
 	{
 		int set_target_pinda = 0;
@@ -7275,17 +7954,20 @@ Sigma_Exit:
 		break;
 	}
  
-  //! ### M861 - Set/Get PINDA temperature compensation offsets
-  // -----------------------------------------------------------
-  /*!
-      
-        M861 [ ? | ! | Z | S<microsteps> [I<table_index>] ]
-      
-      - `?` - Print current EEPROM offset values
-      - `!` - Set factory default values
-      - `Z` - Set all values to 0 (effectively disabling PINDA temperature compensation)
-      - `S<microsteps>` `I<table_index>` - Set compensation ustep value S for compensation table index I
-  */
+    /*!
+    ### M861 - Set/Get PINDA temperature compensation offsets <a href="https://reprap.org/wiki/G-code#M861_Set_Probe_Thermal_Compensation">M861 Set Probe Thermal Compensation</a>
+    Set compensation ustep value `S` for compensation table index `I`.
+    #### Usage
+    
+        M861 [ ? | ! | Z | S | I ]
+    
+    #### Parameters
+    - `?` - Print current EEPROM offset values
+    - `!` - Set factory default values
+    - `Z` - Set all values to 0 (effectively disabling PINDA temperature compensation)
+    - `S` - Microsteps
+    - `I` - Table index
+    */
 	case 861:
 		if (code_seen('?')) { // ? - Print out current EEPROM offset values
 			uint8_t cal_status = calibration_status_pinda();
@@ -7358,38 +8040,40 @@ Sigma_Exit:
 
 #endif //PINDA_THERMISTOR
    
-    //! ### M862 - Print checking
-    // ----------------------------------------------
-    /*!     
-        Checks the parameters of the printer and gcode and performs compatibility check
-          - M862.1 { P<nozzle_diameter> | Q }
-          - M862.2 { P<model_code> | Q }
-          - M862.3 { P"<model_name>" | Q }
-          - M862.4 { P<fw_version> | Q }
-          - M862.5 { P<gcode_level> | Q }
-
-        When run with P<> argument, the check is performed against the input value.
-        When run with Q argument, the current value is shown.
-		  
-        M862.3 accepts text identifiers of printer types too.
-        The syntax of M862.3 is (note the quotes around the type):
-		
-                M862.3 P "MK3S"
-		  
-        Accepted printer type identifiers and their numeric counterparts:
-          - MK1         (100)
-          - MK2         (200)       
-          - MK2MM       (201)     
-          - MK2S        (202)      
-          - MK2SMM      (203)    
-          - MK2.5       (250)     
-          - MK2.5MMU2   (20250) 
-          - MK2.5S      (252)    
-          - MK2.5SMMU2S (20252)
-          - MK3         (300)
-          - MK3MMU2     (20300)
-          - MK3S        (302)
-          - MK3SMMU2S	(20302)
+    /*!
+	### M862 - Print checking <a href="https://reprap.org/wiki/G-code#M862:_Print_checking">M862: Print checking</a>
+    Checks the parameters of the printer and gcode and performs compatibility check
+	
+      - M862.1 { P<nozzle_diameter> | Q } 0.25/0.40/0.60
+      - M862.2 { P<model_code> | Q }
+      - M862.3 { P"<model_name>" | Q }
+      - M862.4 { P<fw_version> | Q }
+      - M862.5 { P<gcode_level> | Q }
+    
+    When run with P<> argument, the check is performed against the input value.
+    When run with Q argument, the current value is shown.
+	
+    M862.3 accepts text identifiers of printer types too.
+    The syntax of M862.3 is (note the quotes around the type):
+	  
+          M862.3 P "MK3S"
+	  
+    Accepted printer type identifiers and their numeric counterparts:
+	
+      - MK1         (100)
+      - MK2         (200)       
+      - MK2MM       (201)     
+      - MK2S        (202)      
+      - MK2SMM      (203)    
+      - MK2.5       (250)     
+      - MK2.5MMU2   (20250) 
+      - MK2.5S      (252)    
+      - MK2.5SMMU2S (20252)
+      - MK3         (300)
+      - MK3MMU2     (20300)
+      - MK3S        (302)
+      - MK3SMMU2S   (20302)
+	
     */
     case 862: // M862: print checking
           float nDummy;
@@ -7451,19 +8135,44 @@ Sigma_Exit:
     break;
 
 #ifdef LIN_ADVANCE
-    //! ### M900 - Set Linear advance options
-    // ----------------------------------------------
+    /*!
+	### M900 - Set Linear advance options <a href="https://reprap.org/wiki/G-code#M900_Set_Linear_Advance_Scaling_Factors">M900 Set Linear Advance Scaling Factors</a>
+	Sets the advance extrusion factors for Linear Advance. If any of the R, W, H, or D parameters are set to zero the ratio will be computed dynamically during printing.
+	#### Usage
+    
+        M900 [ K | R | W | H | D]
+    
+    #### Parameters
+    - `K` -  Advance K factor
+    - `R` - Set ratio directly (overrides WH/D)
+    - `W` - Width
+    - `H` - Height
+    - `D` - Diameter Set ratio from WH/D
+    */
     case 900:
         gcode_M900();
     break;
 #endif
 
-    //! ### M907 - Set digital trimpot motor current in mA using axis codes
-    // ---------------------------------------------------------------
+    /*!
+	### M907 - Set digital trimpot motor current in mA using axis codes <a href="https://reprap.org/wiki/G-code#M907:_Set_digital_trimpot_motor">M907: Set digital trimpot motor</a>
+	Set digital trimpot motor current using axis codes (X, Y, Z, E, B, S).
+	#### Usage
+    
+        M907 [ X | Y | Z | E | B | S ]
+	
+    #### Parameters
+    - `X` - X motor driver
+    - `Y` - Y motor driver
+    - `Z` - Z motor driver
+    - `E` - Extruder motor driver
+    - `B` - Second Extruder motor driver
+    - `S` - All motors
+    */
     case 907:
     {
 #ifdef TMC2130
-        //! See tmc2130_cur2val() for translation to 0 .. 63 range
+        // See tmc2130_cur2val() for translation to 0 .. 63 range
         for (int i = 0; i < NUM_AXIS; i++)
 			if(code_seen(axis_codes[i]))
 			{
@@ -7493,8 +8202,17 @@ Sigma_Exit:
     }
     break;
 
-    //! ### M908 - Control digital trimpot directly
-    // ---------------------------------------------------------
+    /*!
+	### M908 - Control digital trimpot directly <a href="https://reprap.org/wiki/G-code#M908:_Control_digital_trimpot_directly">M908: Control digital trimpot directly</a>
+	In Prusa Firmware this G-code is deactivated by default, must be turned on in the source code. Not usable on Prusa printers.
+    #### Usage
+    
+        M908 [ P | S ]
+    
+    #### Parameters
+    - `P` - channel
+    - `S` - current
+    */
     case 908:
     {
       #if defined(DIGIPOTSS_PIN) && DIGIPOTSS_PIN > -1
@@ -7508,16 +8226,30 @@ Sigma_Exit:
 
 #ifdef TMC2130_SERVICE_CODES_M910_M918
 
-  //! ### M910 - TMC2130 init
-  // -----------------------------------------------
+    /*!
+	### M910 - TMC2130 init <a href="https://reprap.org/wiki/G-code#M910:_TMC2130_init">M910: TMC2130 init</a>
+	Not active in default, only if `TMC2130_SERVICE_CODES_M910_M918` is defined in source code.
+	
+    */
 	case 910:
     {
 		tmc2130_init();
     }
     break;
 
-  //! ### M911 - Set TMC2130 holding currents
-  // -------------------------------------------------
+    /*!
+    ### M911 - Set TMC2130 holding currents <a href="https://reprap.org/wiki/G-code#M911:_Set_TMC2130_holding_currents">M911: Set TMC2130 holding currents</a>
+	Not active in default, only if `TMC2130_SERVICE_CODES_M910_M918` is defined in source code.
+    #### Usage
+    
+        M911 [ X | Y | Z | E ]
+    
+    #### Parameters
+    - `X` - X stepper driver holding current value
+    - `Y` - Y stepper driver holding current value
+    - `Z` - Z stepper driver holding current value
+    - `E` - Extruder stepper driver holding current value
+    */
 	case 911: 
     {
 		if (code_seen('X')) tmc2130_set_current_h(0, code_value());
@@ -7527,8 +8259,19 @@ Sigma_Exit:
     }
     break;
 
-  //! ### M912 - Set TMC2130 running currents
-  // -----------------------------------------------
+    /*!
+	### M912 - Set TMC2130 running currents <a href="https://reprap.org/wiki/G-code#M912:_Set_TMC2130_running_currents">M912: Set TMC2130 running currents</a>
+	Not active in default, only if `TMC2130_SERVICE_CODES_M910_M918` is defined in source code.
+    #### Usage
+    
+        M912 [ X | Y | Z | E ]
+    
+    #### Parameters
+    - `X` - X stepper driver running current value
+    - `Y` - Y stepper driver running current value
+    - `Z` - Z stepper driver running current value
+    - `E` - Extruder stepper driver running current value
+    */
 	case 912: 
     {
 		if (code_seen('X')) tmc2130_set_current_r(0, code_value());
@@ -7538,17 +8281,22 @@ Sigma_Exit:
     }
     break;
 
-  //! ### M913 - Print TMC2130 currents
-  // -----------------------------
+    /*!
+	### M913 - Print TMC2130 currents <a href="https://reprap.org/wiki/G-code#M913:_Print_TMC2130_currents">M913: Print TMC2130 currents</a>
+	Not active in default, only if `TMC2130_SERVICE_CODES_M910_M918` is defined in source code.
+	Shows TMC2130 currents.
+    */
 	case 913:
     {
 		tmc2130_print_currents();
     }
     break;
 
-  //! ### M914 - Set TMC2130 normal mode
-  // ------------------------------
-        case 914:
+    /*!
+	### M914 - Set TMC2130 normal mode <a href="https://reprap.org/wiki/G-code#M914:_Set_TMC2130_normal_mode">M914: Set TMC2130 normal mode</a>
+	Not active in default, only if `TMC2130_SERVICE_CODES_M910_M918` is defined in source code.
+    */
+    case 914:
     {
 		tmc2130_mode = TMC2130_MODE_NORMAL;
 		update_mode_profile();
@@ -7556,9 +8304,11 @@ Sigma_Exit:
     }
     break;
 
-  //! ### M95 - Set TMC2130 silent mode
-  // ------------------------------
-        case 915:
+    /*!
+	### M915 - Set TMC2130 silent mode <a href="https://reprap.org/wiki/G-code#M915:_Set_TMC2130_silent_mode">M915: Set TMC2130 silent mode</a>
+	Not active in default, only if `TMC2130_SERVICE_CODES_M910_M918` is defined in source code.
+    */
+    case 915:
     {
 		tmc2130_mode = TMC2130_MODE_SILENT;
 		update_mode_profile();
@@ -7566,8 +8316,19 @@ Sigma_Exit:
     }
     break;
 
-  //! ### M916 - Set TMC2130 Stallguard sensitivity threshold
-  // -------------------------------------------------------
+    /*!
+	### M916 - Set TMC2130 Stallguard sensitivity threshold <a href="https://reprap.org/wiki/G-code#M916:_Set_TMC2130_Stallguard_sensitivity_threshold">M916: Set TMC2130 Stallguard sensitivity threshold</a>
+	Not active in default, only if `TMC2130_SERVICE_CODES_M910_M918` is defined in source code.
+    #### Usage
+    
+        M916 [ X | Y | Z | E ]
+    
+    #### Parameters
+    - `X` - X stepper driver stallguard sensitivity threshold value
+    - `Y` - Y stepper driver stallguard sensitivity threshold value
+    - `Z` - Z stepper driver stallguard sensitivity threshold value
+    - `E` - Extruder stepper driver stallguard sensitivity threshold value
+    */
 	case 916:
     {
 		if (code_seen('X')) tmc2130_sg_thr[X_AXIS] = code_value();
@@ -7579,8 +8340,19 @@ Sigma_Exit:
     }
     break;
 
-  //! ### M917 - Set TMC2130 PWM amplitude offset (pwm_ampl)
-  // --------------------------------------------------------------
+    /*!
+	### M917 - Set TMC2130 PWM amplitude offset (pwm_ampl) <a href="https://reprap.org/wiki/G-code#M917:_Set_TMC2130_PWM_amplitude_offset_.28pwm_ampl.29">M917: Set TMC2130 PWM amplitude offset (pwm_ampl)</a>
+	Not active in default, only if `TMC2130_SERVICE_CODES_M910_M918` is defined in source code.
+    #### Usage
+    
+        M917 [ X | Y | Z | E ]
+    
+    #### Parameters
+    - `X` - X stepper driver PWM amplitude offset value
+    - `Y` - Y stepper driver PWM amplitude offset value
+    - `Z` - Z stepper driver PWM amplitude offset value
+    - `E` - Extruder stepper driver PWM amplitude offset value
+    */
 	case 917:
     {
 		if (code_seen('X')) tmc2130_set_pwm_ampl(0, code_value());
@@ -7590,8 +8362,19 @@ Sigma_Exit:
     }
     break;
 
-  //! ### M918 - Set TMC2130 PWM amplitude gradient (pwm_grad)
-  // -------------------------------------------------------------
+    /*!
+	### M918 - Set TMC2130 PWM amplitude gradient (pwm_grad) <a href="https://reprap.org/wiki/G-code#M918:_Set_TMC2130_PWM_amplitude_gradient_.28pwm_grad.29">M918: Set TMC2130 PWM amplitude gradient (pwm_grad)</a>
+	Not active in default, only if `TMC2130_SERVICE_CODES_M910_M918` is defined in source code.
+    #### Usage
+    
+        M918 [ X | Y | Z | E ]
+    
+    #### Parameters
+    - `X` - X stepper driver PWM amplitude gradient value
+    - `Y` - Y stepper driver PWM amplitude gradient value
+    - `Z` - Z stepper driver PWM amplitude gradient value
+    - `E` - Extruder stepper driver PWM amplitude gradient value
+    */
 	case 918:
     {
 		if (code_seen('X')) tmc2130_set_pwm_grad(0, code_value());
@@ -7603,33 +8386,54 @@ Sigma_Exit:
 
 #endif //TMC2130_SERVICE_CODES_M910_M918
 
-    //! ### M350 - Set microstepping mode
-    // ---------------------------------------------------
-    //!  Warning: Steps per unit remains unchanged. S code sets stepping mode for all drivers.
+    /*!
+	### M350 - Set microstepping mode <a href="https://reprap.org/wiki/G-code#M350:_Set_microstepping_mode">M350: Set microstepping mode</a>
+    Printers with TMC2130 drivers have `X`, `Y`, `Z` and `E` as options. The steps-per-unit value is updated accordingly. Not all resolutions are valid!
+    Printers without TMC2130 drivers also have `B` and `S` options. In this case, the steps-per-unit value in not changed!
+    #### Usage
+    
+        M350 [ X | Y | Z | E | B | S ]
+    
+    #### Parameters
+    - `X` - X new resolution
+    - `Y` - Y new resolution
+    - `Z` - Z new resolution
+    - `E` - E new resolution
+    
+    Only valid for MK2.5(S) or printers without TMC2130 drivers
+    - `B` - Second extruder new resolution
+    - `S` - All axes new resolution
+    */
     case 350: 
     {
 	#ifdef TMC2130
-		if(code_seen('E'))
+		for (int i=0; i<NUM_AXIS; i++) 
 		{
-			uint16_t res_new = code_value();
-			if ((res_new == 8) || (res_new == 16) || (res_new == 32) || (res_new == 64) || (res_new == 128))
+			if(code_seen(axis_codes[i]))
 			{
-				st_synchronize();
-				uint8_t axis = E_AXIS;
-				uint16_t res = tmc2130_get_res(axis);
-				tmc2130_set_res(axis, res_new);
-				cs.axis_ustep_resolution[axis] = res_new;
-				if (res_new > res)
-				{
-					uint16_t fac = (res_new / res);
-					cs.axis_steps_per_unit[axis] *= fac;
-					position[E_AXIS] *= fac;
-				}
-				else
+				uint16_t res_new = code_value();
+				bool res_valid = (res_new == 8) || (res_new == 16) || (res_new == 32); // resolutions valid for all axis
+				res_valid |= (i != E_AXIS) && ((res_new == 1) || (res_new == 2) || (res_new == 4)); // resolutions valid for X Y Z only
+				res_valid |= (i == E_AXIS) && ((res_new == 64) || (res_new == 128)); // resolutions valid for E only
+				if (res_valid)
 				{
-					uint16_t fac = (res / res_new);
-					cs.axis_steps_per_unit[axis] /= fac;
-					position[E_AXIS] /= fac;
+					
+					st_synchronize();
+					uint16_t res = tmc2130_get_res(i);
+					tmc2130_set_res(i, res_new);
+					cs.axis_ustep_resolution[i] = res_new;
+					if (res_new > res)
+					{
+						uint16_t fac = (res_new / res);
+						cs.axis_steps_per_unit[i] *= fac;
+						position[i] *= fac;
+					}
+					else
+					{
+						uint16_t fac = (res / res_new);
+						cs.axis_steps_per_unit[i] /= fac;
+						position[i] /= fac;
+					}
 				}
 			}
 		}
@@ -7644,11 +8448,21 @@ Sigma_Exit:
     }
     break;
 
-    //! ### M351 - Toggle Microstep Pins
-    // -----------------------------------
-    //! Toggle MS1 MS2 pins directly, S# determines MS1 or MS2, X# sets the pin high/low.
-    //!
-    //!         M351 [B<0|1>] [E<0|1>] S<1|2> [X<0|1>] [Y<0|1>] [Z<0|1>] 
+    /*!
+	### M351 - Toggle Microstep Pins <a href="https://reprap.org/wiki/G-code#M351:_Toggle_MS1_MS2_pins_directly">M351: Toggle MS1 MS2 pins directly</a>
+    Toggle MS1 MS2 pins directly.
+    #### Usage
+    
+        M351 [B<0|1>] [E<0|1>] S<1|2> [X<0|1>] [Y<0|1>] [Z<0|1>]
+    
+    #### Parameters
+    - `X` - Update X axis
+    - `Y` - Update Y axis
+    - `Z` - Update Z axis
+    - `E` - Update E axis
+    - `S` - which MSx pin to toggle
+    - `B` - new pin value
+    */
     case 351:
     {
       #if defined(X_MS1_PIN) && X_MS1_PIN > -1
@@ -7668,8 +8482,10 @@ Sigma_Exit:
     }
     break;
 
-  //! ### M701 - Load filament
-  // -------------------------
+  /*!
+  ### M701 - Load filament <a href="https://reprap.org/wiki/G-code#M701:_Load_filament">M701: Load filament</a>
+  
+  */
 	case 701:
 	{
 		if (mmu_enabled && code_seen('E'))
@@ -7678,16 +8494,17 @@ Sigma_Exit:
 	}
 	break;
 
-  //! ### M702 - Unload filament
-  // ------------------------
-  /*! 
-      
-          M702 [U C]
-      
-      - `U` Unload all filaments used in current print
-      - `C` Unload just current filament
-      - without any parameters unload all filaments
-  */
+    /*!
+    ### M702 - Unload filament <a href="https://reprap.org/wiki/G-code#M702:_Unload_filament">G32: Undock Z Probe sled</a>
+    #### Usage
+    
+        M702 [ U | C ]
+    
+    #### Parameters
+    - `U` - Unload all filaments used in current print
+    - `C` - Unload just current filament
+    - without any parameters unload all filaments
+    */
 	case 702:
 	{
 #ifdef SNMM
@@ -7710,14 +8527,19 @@ Sigma_Exit:
 	}
 	break;
 
-    //! ### M999 - Restart after being stopped
-    // ------------------------------------
+    /*!
+	### M999 - Restart after being stopped <a href="https://reprap.org/wiki/G-code#M999:_Restart_after_being_stopped_by_error">M999: Restart after being stopped by error</a>
+    @todo Usually doesn't work. Should be fixed or removed. Most of the time, if `Stopped` it set, the print fails and is unrecoverable.
+    */
     case 999:
       Stopped = false;
       lcd_reset_alert_level();
       gcode_LastN = Stopped_gcode_LastN;
       FlushSerialRequestResend();
     break;
+	/*!
+	#### End of M-Commands
+    */
 	default: 
 		printf_P(PSTR("Unknown M code: %s \n"), cmdbuffer + bufindr + CMDHDRSIZE);
     }
@@ -7726,19 +8548,16 @@ Sigma_Exit:
 	}
   }
   // end if(code_seen('M')) (end of M codes)
-
-  //! -----------------------------------------------------------------------------------------
-  //! T Codes
-  //! 
-  //! T<extruder nr.> - select extruder in case of multi extruder printer
-  //! select filament in case of MMU_V2
-  //! if extruder is "?", open menu to let the user select extruder/filament
-  //!
-  //!  For MMU_V2:
-  //! @n T<n> Gcode to extrude at least 38.10 mm at feedrate 19.02 mm/s must follow immediately to load to extruder wheels.
-  //! @n T? Gcode to extrude shouldn't have to follow, load to extruder wheels is done automatically
-  //! @n Tx Same as T?, except nozzle doesn't have to be preheated. Tc must be placed after extruder nozzle is preheated to finish filament load.
-  //! @n Tc Load to nozzle after filament was prepared by Tc and extruder nozzle is already heated.
+  /*!
+  -----------------------------------------------------------------------------------------
+  # T Codes
+  T<extruder nr.> - select extruder in case of multi extruder printer. select filament in case of MMU_V2.
+  #### For MMU_V2:
+  T<n> Gcode to extrude at least 38.10 mm at feedrate 19.02 mm/s must follow immediately to load to extruder wheels.
+  @n T? Gcode to extrude shouldn't have to follow, load to extruder wheels is done automatically
+  @n Tx Same as T?, except nozzle doesn't have to be preheated. Tc must be placed after extruder nozzle is preheated to finish filament load.
+  @n Tc Load to nozzle after filament was prepared by Tc and extruder nozzle is already heated.
+  */
   else if(code_seen('T'))
   {
       int index;
@@ -7827,15 +8646,8 @@ Sigma_Exit:
           else
           {
 #ifdef SNMM
-
-#ifdef LIN_ADVANCE
-              if (mmu_extruder != tmp_extruder)
-                  clear_current_adv_vars(); //Check if the selected extruder is not the active one and reset LIN_ADVANCE variables if so.
-#endif
-
               mmu_extruder = tmp_extruder;
 
-
               _delay(100);
 
               disable_e0();
@@ -7922,95 +8734,197 @@ Sigma_Exit:
           }
       }
   } // end if(code_seen('T')) (end of T codes)
+  /*!
+  #### End of T-Codes
+  */
 
-  //! ----------------------------------------------------------------------------------------------
-
+  /**
+  *---------------------------------------------------------------------------------
+  *# D codes
+  */
   else if (code_seen('D')) // D codes (debug)
   {
     switch((int)code_value())
     {
 
-  //! ### D-1 - Endless loop
-  // -------------------
+    /*!
+    ### D-1 - Endless Loop <a href="https://reprap.org/wiki/G-code#D-1:_Endless_Loop">D-1: Endless Loop</a>
+    */
 	case -1:
 		dcode__1(); break;
 #ifdef DEBUG_DCODES
 
-  //! ### D0 - Reset
-  // -------------- 
+    /*!
+    ### D0 - Reset <a href="https://reprap.org/wiki/G-code#D0:_Reset">D0: Reset</a>
+    #### Usage
+    
+        D0 [ B ]
+    
+    #### Parameters
+    - `B` - Bootloader
+    */
 	case 0:
 		dcode_0(); break;
 
-  //! ### D1 - Clear EEPROM
-  // ------------------
+    /*!
+    *
+    ### D1 - Clear EEPROM and RESET <a href="https://reprap.org/wiki/G-code#D1:_Clear_EEPROM_and_RESET">D1: Clear EEPROM and RESET</a>
+      
+          D1
+      
+    *
+    */
 	case 1:
 		dcode_1(); break;
 
-  //! ### D2 - Read/Write RAM
-  // --------------------
+    /*!
+    ### D2 - Read/Write RAM <a href="https://reprap.org/wiki/G-code#D2:_Read.2FWrite_RAM">D3: Read/Write RAM</a>
+    This command can be used without any additional parameters. It will read the entire RAM.
+    #### Usage
+    
+        D3 [ A | C | X ]
+    
+    #### Parameters
+    - `A` - Address (0x0000-0x1fff)
+    - `C` - Count (0x0001-0x2000)
+    - `X` - Data
+    */
 	case 2:
 		dcode_2(); break;
 #endif //DEBUG_DCODES
 #ifdef DEBUG_DCODE3
 
-  //! ### D3 - Read/Write EEPROM
-  // -----------------------
+    /*!
+    ### D3 - Read/Write EEPROM <a href="https://reprap.org/wiki/G-code#D3:_Read.2FWrite_EEPROM">D3: Read/Write EEPROM</a>
+    This command can be used without any additional parameters. It will read the entire eeprom.
+    #### Usage
+    
+        D3 [ A | C | X ]
+    
+    #### Parameters
+    - `A` - Address (0x0000-0x0fff)
+    - `C` - Count (0x0001-0x1000)
+    - `X` - Data
+    */
 	case 3:
 		dcode_3(); break;
 #endif //DEBUG_DCODE3
 #ifdef DEBUG_DCODES
 
-  //! ### D4 - Read/Write PIN
-  // ---------------------
+    /*!
+    
+    ### D4 - Read/Write PIN <a href="https://reprap.org/wiki/G-code#D4:_Read.2FWrite_PIN">D4: Read/Write PIN</a>
+    To read the digital value of a pin you need only to define the pin number.
+    #### Usage
+    
+        D4 [ P | F | V ]
+    
+    #### Parameters
+    - `P` - Pin (0-255)
+    - `F` - Function in/out (0/1)
+    - `V` - Value (0/1)
+    */
 	case 4:
 		dcode_4(); break;
 #endif //DEBUG_DCODES
 #ifdef DEBUG_DCODE5
 
-  //! ### D5 - Read/Write FLASH
-  // ------------------------
+    /*!
+    ### D5 - Read/Write FLASH <a href="https://reprap.org/wiki/G-code#D5:_Read.2FWrite_FLASH">D5: Read/Write Flash</a>
+    This command can be used without any additional parameters. It will read the 1kb FLASH.
+    #### Usage
+    
+        D3 [ A | C | X | E ]
+    
+    #### Parameters
+    - `A` - Address (0x00000-0x3ffff)
+    - `C` - Count (0x0001-0x2000)
+    - `X` - Data
+    - `E` - Erase
+    */
 	case 5:
 		dcode_5(); break;
 		break;
 #endif //DEBUG_DCODE5
 #ifdef DEBUG_DCODES
 
-  //! ### D6 - Read/Write external FLASH
-  // ---------------------------------------
+    /*!
+    ### D6 - Read/Write external FLASH <a href="https://reprap.org/wiki/G-code#D6:_Read.2FWrite_external_FLASH">D6: Read/Write external Flash</a>
+    Reserved
+    */
 	case 6:
 		dcode_6(); break;
 
-  //! ### D7 - Read/Write Bootloader
-  // -------------------------------
+    /*!
+    ### D7 - Read/Write Bootloader <a href="https://reprap.org/wiki/G-code#D7:_Read.2FWrite_Bootloader">D7: Read/Write Bootloader</a>
+    Reserved
+    */
 	case 7:
 		dcode_7(); break;
 
-  //! ### D8 - Read/Write PINDA
-  // ---------------------------
+    /*!
+    ### D8 - Read/Write PINDA <a href="https://reprap.org/wiki/G-code#D8:_Read.2FWrite_PINDA">D8: Read/Write PINDA</a>
+    #### Usage
+    
+        D8 [ ? | ! | P | Z ]
+    
+    #### Parameters
+    - `?` - Read PINDA temperature shift values
+    - `!` - Reset PINDA temperature shift values to default
+    - `P` - Pinda temperature [C]
+    - `Z` - Z Offset [mm]
+    */
 	case 8:
 		dcode_8(); break;
 
-  // ### D9 - Read/Write ADC
-  // ------------------------
+    /*!
+    ### D9 - Read ADC <a href="https://reprap.org/wiki/G-code#D9:_Read.2FWrite_ADC">D9: Read ADC</a>
+    #### Usage
+    
+        D9 [ I | V ]
+    
+    #### Parameters
+    - `I` - ADC channel index 
+        - `0` - Heater 0 temperature
+        - `1` - Heater 1 temperature
+        - `2` - Bed temperature
+        - `3` - PINDA temperature
+        - `4` - PWR voltage
+        - `5` - Ambient temperature
+        - `6` - BED voltage
+    - `V` Value to be written as simulated
+    */
 	case 9:
 		dcode_9(); break;
 
-  //! ### D10 - XYZ calibration = OK
-  // ------------------------------
+    /*!
+    ### D10 - Set XYZ calibration = OK <a href="https://reprap.org/wiki/G-code#D10:_Set_XYZ_calibration_.3D_OK">D10: Set XYZ calibration = OK</a>
+    */
 	case 10:
 		dcode_10(); break;
+
+    /*!
+    ### D12 - Time <a href="https://reprap.org/wiki/G-code#D12:_Time">D12: Time</a>
+    Writes the actual time in the log file.
+    */
+
 #endif //DEBUG_DCODES
 #ifdef HEATBED_ANALYSIS
 
-  //! ### D80 - Bed check
-  // ---------------------
-  /*! 
-    - `E` - dimension x
-    - `F` - dimention y
-    - `G` - points_x
-    - `H` - points_y
-    - `I` - offset_x
-    - `J` - offset_y
+    /*!
+    ### D80 - Bed check <a href="https://reprap.org/wiki/G-code#D80:_Bed_check">D80: Bed check</a>
+    This command will log data to SD card file "mesh.txt".
+    #### Usage
+    
+        D80 [ E | F | G | H | I | J ]
+    
+    #### Parameters
+    - `E` - Dimension X (default 40)
+    - `F` - Dimention Y (default 40)
+    - `G` - Points X (default 40)
+    - `H` - Points Y (default 40)
+    - `I` - Offset X (default 74)
+    - `J` - Offset Y (default 34)
   */
 	case 80:
 	{
@@ -8036,15 +8950,20 @@ Sigma_Exit:
  		bed_check(dimension_x,dimension_y,points_x,points_y,offset_x,offset_y);
 	}break;
 
-  //! ### D81 - Bed analysis
-  // -----------------------------
-  /*! 
-    - `E` - dimension x
-    - `F` - dimention y
-    - `G` - points_x
-    - `H` - points_y
-    - `I` - offset_x
-    - `J` - offset_y
+    /*!
+    ### D81 - Bed analysis <a href="https://reprap.org/wiki/G-code#D81:_Bed_analysis">D80: Bed analysis</a>
+    This command will log data to SD card file "wldsd.txt".
+    #### Usage
+    
+        D81 [ E | F | G | H | I | J ]
+    
+    #### Parameters
+    - `E` - Dimension X (default 40)
+    - `F` - Dimention Y (default 40)
+    - `G` - Points X (default 40)
+    - `H` - Points Y (default 40)
+    - `I` - Offset X (default 74)
+    - `J` - Offset Y (default 34)
   */
 	case 81:
 	{
@@ -8069,8 +8988,9 @@ Sigma_Exit:
 #endif //HEATBED_ANALYSIS
 #ifdef DEBUG_DCODES
 
-  //! ### D106 print measured fan speed for different pwm values
-  // --------------------------------------------------------------
+    /*!
+    ### D106 - Print measured fan speed for different pwm values <a href="https://reprap.org/wiki/G-code#D106:_Print_measured_fan_speed_for_different_pwm_values">D106: Print measured fan speed for different pwm values</a>
+    */
 	case 106:
 	{
 		for (int i = 255; i > 0; i = i - 5) {
@@ -8085,42 +9005,61 @@ Sigma_Exit:
 	}break;
 
 #ifdef TMC2130
-  //! ### D2130 - TMC2130 Trinamic stepper controller
-  // ---------------------------
-
-  
-  /*!
-  
-  
-        D2130<axis><command>[subcommand][value]
-
-   - <command>:
-       - '0' current off
-       - '1' current on
-       - '+' single step
-       - * value sereval steps
-       - '-' dtto oposite direction
-       - '?' read register
-       - * "mres"
-       - * "step"
-       - * "mscnt"
-       - * "mscuract"
-       - * "wave"
-       - '!' set register
-       - * "mres"
-       - * "step"
-       - * "wave"
-       - '@' home calibrate axis
-
-    Example:
-
-    D2130E?wave ...        print extruder microstep linearity compensation curve
-
-    D2130E!wave0 ...       disable extruder linearity compensation curve, (sine curve is used)
-
-    D2130E!wave220 ...    (sin(x))^1.1 extruder microstep compensation curve used
-  */
-
+    /*!
+    ### D2130 - Trinamic stepper controller <a href="https://reprap.org/wiki/G-code#D2130:_Trinamic_stepper_controller">D2130: Trinamic stepper controller</a>
+    @todo Please review by owner of the code. RepRap Wiki Gcode needs to be updated after review of owner as well.
+    
+    #### Usage
+    
+        D2130 [ Axis | Command | Subcommand | Value ]
+    
+    #### Parameters
+    - Axis
+      - `X` - X stepper driver
+      - `Y` - Y stepper driver
+      - `Z` - Z stepper driver
+      - `E` - Extruder stepper driver
+    - Commands
+      - `0`   - Current off
+      - `1`   - Current on
+      - `+`   - Single step
+      - `-`   - Single step oposite direction
+      - `NNN` - Value sereval steps
+      - `?`   - Read register
+      - Subcommands for read register
+        - `mres`     - Micro step resolution. More information in datasheet '5.5.2 CHOPCONF – Chopper Configuration'
+        - `step`     - Step
+        - `mscnt`    - Microstep counter. More information in datasheet '5.5 Motor Driver Registers'
+        - `mscuract` - Actual microstep current for motor. More information in datasheet '5.5 Motor Driver Registers'
+        - `wave`     - Microstep linearity compensation curve
+      - `!`   - Set register
+      - Subcommands for set register
+        - `mres`     - Micro step resolution
+        - `step`     - Step
+        - `wave`     - Microstep linearity compensation curve
+        - Values for set register
+          - `0, 180 --> 250` - Off
+          - `0.9 --> 1.25`   - Valid values (recommended is 1.1)
+      - `@`   - Home calibrate axis
+    
+    Examples:
+      
+          D2130E?wave
+      
+      Print extruder microstep linearity compensation curve
+      
+          D2130E!wave0
+      
+      Disable extruder linearity compensation curve, (sine curve is used)
+      
+          D2130E!wave220
+      
+      (sin(x))^1.1 extruder microstep compensation curve used
+    
+    Notes:
+      For more information see https://www.trinamic.com/fileadmin/assets/Products/ICs_Documents/TMC2130_datasheet.pdf
+    *
+	*/
 
 	case 2130:
 		dcode_2130(); break;
@@ -8128,8 +9067,20 @@ Sigma_Exit:
 
 #if (defined (FILAMENT_SENSOR) && defined(PAT9125))
 
-        //! ### D9125 - FILAMENT_SENSOR
-        // ---------------------------------
+    /*!
+    ### D9125 - PAT9125 filament sensor <a href="https://reprap.org/wiki/G-code#D9:_Read.2FWrite_ADC">D9125: PAT9125 filament sensor</a>
+    #### Usage
+    
+        D9125 [ ? | ! | R | X | Y | L ]
+    
+    #### Parameters
+    - `?` - Print values
+    - `!` - Print values
+    - `R` - Resolution. Not active in code
+    - `X` - X values
+    - `Y` - Y values
+    - `L` - Activate filament sensor log
+    */
 	case 9125:
 		dcode_9125(); break;
 #endif //FILAMENT_SENSOR
@@ -8149,7 +9100,9 @@ Sigma_Exit:
   ClearToSend();
 }
 
-
+/*!
+#### End of D-Codes
+*/
 
   /** @defgroup GCodes G-Code List 
   */
@@ -8217,7 +9170,7 @@ void get_coordinates()
   for(int8_t i=0; i < NUM_AXIS; i++) {
     if(code_seen(axis_codes[i]))
     {
-      bool relative = axis_relative_modes[i] || relative_mode;
+      bool relative = axis_relative_modes[i];
       destination[i] = (float)code_value();
       if (i == E_AXIS) {
         float emult = extruder_multiplier[active_extruder];
@@ -8300,38 +9253,43 @@ void clamp_to_software_endstops(float target[3])
 }
 
 #ifdef MESH_BED_LEVELING
-    void mesh_plan_buffer_line(const float &x, const float &y, const float &z, const float &e, const float &feed_rate, const uint8_t extruder) {
+void mesh_plan_buffer_line(const float &x, const float &y, const float &z, const float &e, const float &feed_rate, const uint8_t extruder) {
         float dx = x - current_position[X_AXIS];
         float dy = y - current_position[Y_AXIS];
-        float dz = z - current_position[Z_AXIS];
         int n_segments = 0;
-		
+
         if (mbl.active) {
             float len = abs(dx) + abs(dy);
             if (len > 0)
                 // Split to 3cm segments or shorter.
                 n_segments = int(ceil(len / 30.f));
         }
-        
+
         if (n_segments > 1) {
+            // In a multi-segment move explicitly set the final target in the plan
+            // as the move will be recalculated in it's entirety
+            float gcode_target[NUM_AXIS];
+            gcode_target[X_AXIS] = x;
+            gcode_target[Y_AXIS] = y;
+            gcode_target[Z_AXIS] = z;
+            gcode_target[E_AXIS] = e;
+
+            float dz = z - current_position[Z_AXIS];
             float de = e - current_position[E_AXIS];
+
             for (int i = 1; i < n_segments; ++ i) {
                 float t = float(i) / float(n_segments);
-                if (saved_printing || (mbl.active == false)) return;
-                plan_buffer_line(
-                                 current_position[X_AXIS] + t * dx,
+                plan_buffer_line(current_position[X_AXIS] + t * dx,
                                  current_position[Y_AXIS] + t * dy,
                                  current_position[Z_AXIS] + t * dz,
                                  current_position[E_AXIS] + t * de,
-                                 feed_rate, extruder);
+                                 feed_rate, extruder, gcode_target);
+                if (waiting_inside_plan_buffer_line_print_aborted)
+                    return;
             }
         }
         // The rest of the path.
         plan_buffer_line(x, y, z, e, feed_rate, extruder);
-        current_position[X_AXIS] = x;
-        current_position[Y_AXIS] = y;
-        current_position[Z_AXIS] = z;
-        current_position[E_AXIS] = e;
     }
 #endif  // MESH_BED_LEVELING
     
@@ -8352,9 +9310,7 @@ void prepare_move()
 #endif
   }
 
-  for(int8_t i=0; i < NUM_AXIS; i++) {
-    current_position[i] = destination[i];
-  }
+  set_current_to_destination();
 }
 
 void prepare_arc_move(char isclockwise) {
@@ -8562,7 +9518,7 @@ if(0)
 
   if( (_millis() - previous_millis_cmd) >  max_inactive_time )
     if(max_inactive_time)
-      kill(_n(""), 4);
+      kill(_n("Inactivity Shutdown"), 4);
   if(stepper_inactive_time)  {
     if( (_millis() - previous_millis_cmd) >  stepper_inactive_time )
     {
@@ -8603,7 +9559,7 @@ if(0)
     // ----------------------------------------------------------------
     if ( killCount >= KILL_DELAY)
     {
-       kill("", 5);
+       kill(NULL, 5);
     }
   #endif
     
@@ -8681,6 +9637,16 @@ void kill(const char *full_screen_message, unsigned char id)
   } // Wait for reset
 }
 
+// Stop: Emergency stop used by overtemp functions which allows recovery
+//
+//   In addition to stopping the print, this prevents subsequent G[0-3] commands to be
+//   processed via USB (using "Stopped") until the print is resumed via M999 or
+//   manually started from scratch with the LCD.
+//
+//   Note that the current instruction is completely discarded, so resuming from Stop()
+//   will introduce either over/under extrusion on the current segment, and will not
+//   survive a power panic. Switching Stop() to use the pause machinery instead (with
+//   the addition of disabling the headers) could allow true recovery in the future.
 void Stop()
 {
   disable_heater();
@@ -8865,12 +9831,15 @@ void delay_keep_alive(unsigned int ms)
 }
 
 static void wait_for_heater(long codenum, uint8_t extruder) {
+    if (!degTargetHotend(extruder))
+        return;
 
 #ifdef TEMP_RESIDENCY_TIME
 	long residencyStart;
 	residencyStart = -1;
 	/* continue to loop until we have reached the target temp
 	_and_ until TEMP_RESIDENCY_TIME hasn't passed since we reached it */
+    cancel_heatup = false;
 	while ((!cancel_heatup) && ((residencyStart == -1) ||
 		(residencyStart >= 0 && (((unsigned int)(_millis() - residencyStart)) < (TEMP_RESIDENCY_TIME * 1000UL))))) {
 #else
@@ -9073,10 +10042,8 @@ void bed_check(float x_dimension, float y_dimension, int x_points_num, int y_poi
 		destination[X_AXIS] = ix * (x_dimension / (x_points_num - 1)) + shift_x;
 		destination[Y_AXIS] = iy * (y_dimension / (y_points_num - 1)) + shift_y;
 
-		mesh_plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], XY_AXIS_FEEDRATE/6, active_extruder);
-		for(int8_t i=0; i < NUM_AXIS; i++) {
-			current_position[i] = destination[i];
-		}
+        mesh_plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], XY_AXIS_FEEDRATE/6, active_extruder);
+        set_current_to_destination();
 		st_synchronize();
 
 	//	printf_P(PSTR("X = %f; Y= %f \n"), current_position[X_AXIS], current_position[Y_AXIS]);
@@ -9491,12 +10458,10 @@ float temp_compensation_pinda_thermistor_offset(float temperature_pinda)
 void long_pause() //long pause print
 {
 	st_synchronize();
-	
 	start_pause_print = _millis();
 
-	//retract
-	current_position[E_AXIS] -= default_retraction;
-	plan_buffer_line_curposXYZE(400, active_extruder);
+    // Stop heaters
+    setAllTargetHotends(0);
 
 	//lift z
 	current_position[Z_AXIS] += Z_PAUSE_LIFT;
@@ -9510,8 +10475,6 @@ void long_pause() //long pause print
 
 	// Turn off the print fan
 	fanSpeed = 0;
-
-	st_synchronize();
 }
 
 void serialecho_temperatures() {
@@ -9532,6 +10495,11 @@ void uvlo_()
 	unsigned long time_start = _millis();
 	bool sd_print = card.sdprinting;
     // Conserve power as soon as possible.
+#ifdef LCD_BL_PIN
+    backlightMode = BACKLIGHT_MODE_DIM;
+    backlightLevel_LOW = 0;
+    backlight_update();
+#endif //LCD_BL_PIN
     disable_x();
     disable_y();
     
@@ -9563,8 +10531,18 @@ void uvlo_()
       if (sd_position < 0) sd_position = 0;
     }
 
-    // Backup the feedrate in mm/min.
-    int feedrate_bckp = blocks_queued() ? (block_buffer[block_buffer_tail].nominal_speed * 60.f) : feedrate;
+    // save the global state at planning time
+    uint16_t feedrate_bckp;
+    if (blocks_queued())
+    {
+        memcpy(saved_target, current_block->gcode_target, sizeof(saved_target));
+        feedrate_bckp = current_block->gcode_feedrate;
+    }
+    else
+    {
+        saved_target[0] = SAVED_TARGET_UNSET;
+        feedrate_bckp = feedrate;
+    }
 
     // After this call, the planner queue is emptied and the current_position is set to a current logical coordinate.
     // The logical coordinate will likely differ from the machine coordinate if the skew calibration and mesh bed leveling
@@ -9631,7 +10609,8 @@ void uvlo_()
     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]);
     // Store the current feed rate, temperatures, fan speed and extruder multipliers (flow rates)
-    EEPROM_save_B(EEPROM_UVLO_FEEDRATE, &feedrate_bckp);
+	eeprom_update_word((uint16_t*)EEPROM_UVLO_FEEDRATE, feedrate_bckp);
+    EEPROM_save_B(EEPROM_UVLO_FEEDMULTIPLY, &feedmultiply);
     eeprom_update_byte((uint8_t*)EEPROM_UVLO_TARGET_HOTEND, target_temperature[active_extruder]);
     eeprom_update_byte((uint8_t*)EEPROM_UVLO_TARGET_BED, target_temperature_bed);
     eeprom_update_byte((uint8_t*)EEPROM_UVLO_FAN_SPEED, fanSpeed);
@@ -9644,6 +10623,16 @@ void uvlo_()
 #endif
 	eeprom_update_word((uint16_t*)(EEPROM_EXTRUDEMULTIPLY), (uint16_t)extrudemultiply);
 
+    // Store the saved target
+    eeprom_update_float((float*)(EEPROM_UVLO_SAVED_TARGET+0*4), saved_target[X_AXIS]);
+    eeprom_update_float((float*)(EEPROM_UVLO_SAVED_TARGET+1*4), saved_target[Y_AXIS]);
+    eeprom_update_float((float*)(EEPROM_UVLO_SAVED_TARGET+2*4), saved_target[Z_AXIS]);
+    eeprom_update_float((float*)(EEPROM_UVLO_SAVED_TARGET+3*4), saved_target[E_AXIS]);
+
+#ifdef LIN_ADVANCE
+	eeprom_update_float((float*)(EEPROM_UVLO_LA_K), extruder_advance_K);
+#endif
+
     // Finaly store the "power outage" flag.
 	if(sd_print) eeprom_update_byte((uint8_t*)EEPROM_UVLO, 1);
 
@@ -9891,10 +10880,21 @@ void recover_machine_state_after_power_panic(bool bTiny)
 #endif
 #endif
   extrudemultiply = (int)eeprom_read_word((uint16_t*)(EEPROM_EXTRUDEMULTIPLY));
+
+  // 9) Recover the saved target
+  saved_target[X_AXIS] = eeprom_read_float((float*)(EEPROM_UVLO_SAVED_TARGET+0*4));
+  saved_target[Y_AXIS] = eeprom_read_float((float*)(EEPROM_UVLO_SAVED_TARGET+1*4));
+  saved_target[Z_AXIS] = eeprom_read_float((float*)(EEPROM_UVLO_SAVED_TARGET+2*4));
+  saved_target[E_AXIS] = eeprom_read_float((float*)(EEPROM_UVLO_SAVED_TARGET+3*4));
+
+#ifdef LIN_ADVANCE
+  extruder_advance_K = eeprom_read_float((float*)EEPROM_UVLO_LA_K);
+#endif
 }
 
 void restore_print_from_eeprom() {
 	int feedrate_rec;
+	int feedmultiply_rec;
 	uint8_t fan_speed_rec;
 	char cmd[30];
 	char filename[13];
@@ -9902,9 +10902,12 @@ void restore_print_from_eeprom() {
 	char dir_name[9];
 
 	fan_speed_rec = eeprom_read_byte((uint8_t*)EEPROM_UVLO_FAN_SPEED);
-	EEPROM_read_B(EEPROM_UVLO_FEEDRATE, &feedrate_rec);
+    feedrate_rec = eeprom_read_word((uint16_t*)EEPROM_UVLO_FEEDRATE);
+	EEPROM_read_B(EEPROM_UVLO_FEEDMULTIPLY, &feedmultiply_rec);
 	SERIAL_ECHOPGM("Feedrate:");
-	MYSERIAL.println(feedrate_rec);
+	MYSERIAL.print(feedrate_rec);
+	SERIAL_ECHOPGM(", feedmultiply:");
+	MYSERIAL.println(feedmultiply_rec);
 
 	depth = eeprom_read_byte((uint8_t*)EEPROM_DIR_DEPTH);
 	
@@ -9945,9 +10948,11 @@ void restore_print_from_eeprom() {
 	enquecommand(cmd);
   // Unretract.
 	enquecommand_P(PSTR("G1 E"  STRINGIFY(2*default_retraction)" F480"));
-  // Set the feedrate saved at the power panic.
+  // Set the feedrates saved at the power panic.
 	sprintf_P(cmd, PSTR("G1 F%d"), feedrate_rec);
 	enquecommand(cmd);
+	sprintf_P(cmd, PSTR("M220 S%d"), feedmultiply_rec);
+	enquecommand(cmd);
 	if (eeprom_read_byte((uint8_t*)EEPROM_UVLO_E_ABS))
 	{
 	  enquecommand_P(PSTR("M82")); //E axis abslute mode
@@ -10099,20 +11104,23 @@ void stop_and_save_print_to_ram(float z_move, float e_move)
   }
 #endif
 
-#if 0
-  saved_feedrate2 = feedrate; //save feedrate
-#else
-  // Try to deduce the feedrate from the first block of the planner.
-  // Speed is in mm/min.
-  saved_feedrate2 = blocks_queued() ? (block_buffer[block_buffer_tail].nominal_speed * 60.f) : feedrate;
-#endif
+  // save the global state at planning time
+  if (blocks_queued())
+  {
+      memcpy(saved_target, current_block->gcode_target, sizeof(saved_target));
+      saved_feedrate2 = current_block->gcode_feedrate;
+  }
+  else
+  {
+      saved_target[0] = SAVED_TARGET_UNSET;
+      saved_feedrate2 = feedrate;
+  }
 
 	planner_abort_hard(); //abort printing
 	memcpy(saved_pos, current_position, sizeof(saved_pos));
+    saved_feedmultiply2 = feedmultiply; //save feedmultiply
 	saved_active_extruder = active_extruder; //save active_extruder
 	saved_extruder_temperature = degTargetHotend(active_extruder);
-
-	saved_extruder_under_pressure = extruder_under_pressure; //extruder under pressure flag - currently unused
 	saved_extruder_relative_mode = axis_relative_modes[E_AXIS];
 	saved_fanSpeed = fanSpeed;
 	cmdqueue_reset(); //empty cmdqueue
@@ -10124,26 +11132,34 @@ void stop_and_save_print_to_ram(float z_move, float e_move)
 	sei();
 	if ((z_move != 0) || (e_move != 0)) { // extruder or z move
 #if 1
-    // Rather than calling plan_buffer_line directly, push the move into the command queue, 
+    // Rather than calling plan_buffer_line directly, push the move into the command queue so that
+    // the caller can continue processing. This is used during powerpanic to save the state as we
+    // move away from the print.
     char buf[48];
 
-	// First unretract (relative extrusion)
-	if(!saved_extruder_relative_mode){
-		enquecommand(PSTR("M83"), true);
-	}
-	//retract 45mm/s
-	// 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
-	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(e_move)
+    {
+        // First unretract (relative extrusion)
+        if(!saved_extruder_relative_mode){
+            enquecommand(PSTR("M83"), true);
+        }
+        //retract 45mm/s
+        // 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);
+    }
+
+    if(z_move)
+    {
+        // Then lift Z axis
+        sprintf_P(buf, PSTR("G1 Z%-0.3f F%-0.3f"), saved_pos[Z_AXIS] + z_move, homing_feedrate[Z_AXIS]);
+        enquecommand(buf, false);
+    }
+
     // If this call is invoked from the main Arduino loop() function, let the caller know that the command
     // in the command queue is not the original command, but a new one, so it should not be removed from the queue.
     repeatcommand_front();
@@ -10153,6 +11169,7 @@ void stop_and_save_print_to_ram(float z_move, float e_move)
     memcpy(current_position, saved_pos, sizeof(saved_pos));
     memcpy(destination, current_position, sizeof(destination));
 #endif
+    waiting_inside_plan_buffer_line_print_aborted = true; //unroll the stack
   }
 }
 
@@ -10186,7 +11203,6 @@ void restore_print_from_ram_and_continue(float e_move)
 		wait_for_heater(_millis(), saved_active_extruder);
 		heating_status = 2;
 	}
-	feedrate = saved_feedrate2; //restore feedrate
 	axis_relative_modes[E_AXIS] = saved_extruder_relative_mode;
 	float e = saved_pos[E_AXIS] - e_move;
 	plan_set_e_position(e);
@@ -10197,18 +11213,20 @@ void restore_print_from_ram_and_continue(float e_move)
 
 	//first move print head in XY to the saved position:
 	plan_buffer_line(saved_pos[X_AXIS], saved_pos[Y_AXIS], current_position[Z_AXIS], saved_pos[E_AXIS] - e_move, homing_feedrate[Z_AXIS]/13, active_extruder);
-	st_synchronize();
 	//then move Z
 	plan_buffer_line(saved_pos[X_AXIS], saved_pos[Y_AXIS], saved_pos[Z_AXIS], saved_pos[E_AXIS] - e_move, homing_feedrate[Z_AXIS]/13, active_extruder);
-	st_synchronize();
 	//and finaly unretract (35mm/s)
-	plan_buffer_line(saved_pos[X_AXIS], saved_pos[Y_AXIS], saved_pos[Z_AXIS], saved_pos[E_AXIS], 35, active_extruder);
+	plan_buffer_line(saved_pos[X_AXIS], saved_pos[Y_AXIS], saved_pos[Z_AXIS], saved_pos[E_AXIS], FILAMENTCHANGE_RFEED, active_extruder);
 	st_synchronize();
 
   #ifdef FANCHECK
     fans_check_enabled = true;
   #endif
 
+    // restore original feedrate/feedmultiply _after_ restoring the extruder position
+	feedrate = saved_feedrate2;
+	feedmultiply = saved_feedmultiply2;
+
 	memcpy(current_position, saved_pos, sizeof(saved_pos));
 	memcpy(destination, current_position, sizeof(destination));
 	if (saved_printing_type == PRINTING_TYPE_SD) { //was sd printing
@@ -10224,10 +11242,20 @@ void restore_print_from_ram_and_continue(float e_move)
 	else {
 		//not sd printing nor usb printing
 	}
+
 	SERIAL_PROTOCOLLNRPGM(MSG_OK); //dummy response because of octoprint is waiting for this
 	lcd_setstatuspgm(_T(WELCOME_MSG));
     saved_printing_type = PRINTING_TYPE_NONE;
 	saved_printing = false;
+    waiting_inside_plan_buffer_line_print_aborted = true; //unroll the stack
+}
+
+// Cancel the state related to a currently saved print
+void cancel_saved_printing()
+{
+    saved_target[0] = SAVED_TARGET_UNSET;
+    saved_printing_type = PRINTING_TYPE_NONE;
+    saved_printing = false;
 }
 
 void print_world_coordinates()

+ 16 - 0
Firmware/Sd2Card.cpp

@@ -319,6 +319,22 @@ bool Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) {
       goto fail;
     }
   }
+
+  // send 0xFF until 0xFF received to give card some clock cycles
+  t0 = (uint16_t)_millis();
+  SERIAL_ECHOLNRPGM(PSTR("Sending 0xFF"));
+  spiSend(0XFF);
+  while ((status_ = spiRec()) != 0xFF)
+  {
+    spiSend(0XFF);
+    if (((uint16_t)_millis() - t0) > SD_CARD_ERROR_FF_TIMEOUT)
+    {
+      error(SD_CARD_ERROR_CMD8);
+      SERIAL_ECHOLNRPGM(PSTR("No 0xFF received"));
+      goto fail;
+    }
+  }
+
   // check SD version
   if ((cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND)) {
     type(SD_CARD_TYPE_SD1);

+ 2 - 0
Firmware/Sd2Card.h

@@ -105,6 +105,8 @@ uint8_t const SD_CARD_ERROR_SCK_RATE = 0X18;
 uint8_t const SD_CARD_ERROR_INIT_NOT_CALLED = 0X19;
 /** crc check error */
 uint8_t const SD_CARD_ERROR_CRC = 0X20;
+/** no response to sent 0xFF */
+uint8_t const SD_CARD_ERROR_FF_TIMEOUT = 0X21;
 
 /** Toshiba FlashAir: iSDIO */
 uint8_t const SD_CARD_ERROR_CMD48 = 0x80;

+ 3 - 2
Firmware/adc.c

@@ -4,6 +4,7 @@
 #include <stdio.h>
 #include <avr/io.h>
 #include <avr/pgmspace.h>
+#include "pins.h"
 
 uint8_t adc_state;
 uint8_t adc_count;
@@ -24,8 +25,8 @@ void adc_init(void)
 	ADMUX |= (1 << REFS0);
 	ADCSRA |= (1 << ADEN);
 //	ADCSRA |= (1 << ADIF) | (1 << ADSC);
-	DIDR0 = (ADC_CHAN_MSK & 0xff);
-	DIDR2 = (ADC_CHAN_MSK >> 8);
+	DIDR0 = ((ADC_CHAN_MSK & ADC_DIDR_MSK) & 0xff);
+	DIDR2 = ((ADC_CHAN_MSK & ADC_DIDR_MSK) >> 8);
 	adc_reset();
 //	adc_sim_mask = 0b0101;
 //	adc_sim_mask = 0b100101;

+ 120 - 0
Firmware/backlight.cpp

@@ -0,0 +1,120 @@
+//backlight.cpp
+
+#include "backlight.h"
+#include <avr/eeprom.h>
+#include <Arduino.h>
+#include "eeprom.h"
+#include "Marlin.h"
+#include "pins.h"
+#include "fastio.h"
+#include "Timer.h"
+
+#ifdef LCD_BL_PIN
+
+#define BL_FLASH_DELAY_MS 25
+
+bool backlightSupport = 0; //only if it's true will any of the settings be visible to the user
+int16_t backlightLevel_HIGH = 0;
+int16_t backlightLevel_LOW = 0;
+uint8_t backlightMode = BACKLIGHT_MODE_BRIGHT;
+int16_t backlightTimer_period = 10;
+LongTimer backlightTimer;
+
+static void backlightTimer_reset() //used for resetting the timer and waking the display. Triggered on user interactions.
+{
+    if (!backlightSupport) return;
+    backlightTimer.start();
+    backlight_update();
+}
+
+void force_bl_on(bool section_start)
+{
+    if (section_start)
+    {
+        backlightMode = BACKLIGHT_MODE_BRIGHT;
+        if (backlightLevel_HIGH < 30) backlightLevel_HIGH = 30;
+    }
+    else
+    {
+        backlightMode = eeprom_read_byte((uint8_t *)EEPROM_BACKLIGHT_MODE);
+        backlightLevel_HIGH = eeprom_read_byte((uint8_t *)EEPROM_BACKLIGHT_LEVEL_HIGH);
+    }
+    backlight_update();
+}
+
+void backlight_wake(const uint8_t flashNo)
+{
+    if (!backlightSupport) return;
+    
+    if (flashNo)
+    {
+        uint8_t backlightMode_bck = backlightMode;
+        for (uint8_t i = 0; i < (((backlightMode_bck == BACKLIGHT_MODE_AUTO) && !backlightTimer.running()) + (flashNo * 2)); i++)
+        {
+            backlightMode = !backlightMode; //toggles between BACKLIGHT_MODE_BRIGHT and BACKLIGHT_MODE_DIM
+            backlight_update();
+            _delay(BL_FLASH_DELAY_MS);
+        }
+        backlightMode = backlightMode_bck;
+    }
+    backlightTimer_reset();
+}
+
+void backlight_save() //saves all backlight data to eeprom.
+{
+    eeprom_update_byte((uint8_t *)EEPROM_BACKLIGHT_LEVEL_HIGH, (uint8_t)backlightLevel_HIGH);
+    eeprom_update_byte((uint8_t *)EEPROM_BACKLIGHT_LEVEL_LOW, (uint8_t)backlightLevel_LOW);
+    eeprom_update_byte((uint8_t *)EEPROM_BACKLIGHT_MODE, backlightMode);
+    eeprom_update_word((uint16_t *)EEPROM_BACKLIGHT_TIMEOUT, backlightTimer_period);
+}
+
+void backlight_update()
+{
+    if (!backlightSupport) return;
+    
+    if (backlightMode == BACKLIGHT_MODE_AUTO)
+    {
+        if (backlightTimer.expired((uint32_t)backlightTimer_period * 1000ul)) analogWrite(LCD_BL_PIN, backlightLevel_LOW);
+        else if (backlightTimer.running()) analogWrite(LCD_BL_PIN, backlightLevel_HIGH);
+        else {/*do nothing*/;} //display is dimmed.
+    }
+    else if (backlightMode == BACKLIGHT_MODE_DIM) analogWrite(LCD_BL_PIN, backlightLevel_LOW);
+    else analogWrite(LCD_BL_PIN, backlightLevel_HIGH);
+}
+
+void backlight_init()
+{
+//check for backlight support on lcd
+    SET_INPUT(LCD_BL_PIN);
+    WRITE(LCD_BL_PIN,HIGH);
+    _delay(10);
+    backlightSupport = !READ(LCD_BL_PIN);
+    if (!backlightSupport) return;
+
+//initialize backlight
+    backlightMode = eeprom_read_byte((uint8_t *)EEPROM_BACKLIGHT_MODE);
+    if (backlightMode == 0xFF) //set default values
+    {
+        backlightMode = BACKLIGHT_MODE_AUTO;
+        backlightLevel_HIGH = 130;
+        backlightLevel_LOW = 50;
+        backlightTimer_period = 10; //in seconds
+        backlight_save();
+    }
+    backlightLevel_HIGH = eeprom_read_byte((uint8_t *)EEPROM_BACKLIGHT_LEVEL_HIGH);
+    backlightLevel_LOW = eeprom_read_byte((uint8_t *)EEPROM_BACKLIGHT_LEVEL_LOW);
+    backlightTimer_period = eeprom_read_word((uint16_t *)EEPROM_BACKLIGHT_TIMEOUT);
+    
+    SET_OUTPUT(LCD_BL_PIN);
+    backlightTimer_reset();
+}
+
+#else //LCD_BL_PIN
+
+void force_bl_on(__attribute__((unused)) bool section_start) {}
+void backlight_update() {}
+void backlight_init() {}
+void backlight_save() {}
+void backlight_wake(__attribute__((unused)) const uint8_t flashNo) {}
+
+#endif //LCD_BL_PIN

+ 32 - 0
Firmware/backlight.h

@@ -0,0 +1,32 @@
+//backlight.h
+#ifndef _BACKLIGHT_H
+#define _BACKLIGHT_H
+
+#include <inttypes.h>
+#include "Marlin.h"
+#include "pins.h"
+
+enum Backlight_Mode
+{
+	BACKLIGHT_MODE_DIM     = 0,
+	BACKLIGHT_MODE_BRIGHT  = 1,
+	BACKLIGHT_MODE_AUTO    = 2,
+};
+
+extern int16_t backlightLevel_HIGH;
+extern int16_t backlightLevel_LOW;
+extern uint8_t backlightMode;
+extern bool backlightSupport;
+extern int16_t backlightTimer_period;
+
+#define FORCE_BL_ON_START force_bl_on(true)
+#define FORCE_BL_ON_END force_bl_on(false)
+
+extern void force_bl_on(bool section_start);
+extern void backlight_update();
+extern void backlight_init();
+extern void backlight_save();
+extern void backlight_wake(const uint8_t flashNo = 0);
+
+
+#endif //_BACKLIGHT_H

+ 41 - 52
Firmware/cardreader.cpp

@@ -25,7 +25,6 @@ CardReader::CardReader()
    sdpos = 0;
    sdprinting = false;
    cardOK = false;
-   paused = false;
    saving = false;
    logging = false;
    autostart_atmillis=0;
@@ -137,8 +136,8 @@ void CardReader::lsDive(const char *prepend, SdFile parent, const char * const m
 						SERIAL_ECHOPGM("Access date: ");
 						MYSERIAL.println(p.lastAccessDate);
 						SERIAL_ECHOLNPGM("");*/
-						creationDate = p.creationDate;
-						creationTime = p.creationTime;
+						modificationDate = p.lastWriteDate;
+						modificationTime = p.lastWriteTime;
 						//writeDate = p.lastAccessDate;
 						if (match != NULL) {
 							if (strcasecmp(match, filename) == 0) return;
@@ -242,24 +241,13 @@ void CardReader::startFileprint()
   if(cardOK)
   {
     sdprinting = true;
-	paused = false;
-     Stopped = false;
+    Stopped = false;
 	#ifdef SDCARD_SORT_ALPHA
 		//flush_presort();
 	#endif
   }
 }
 
-void CardReader::pauseSDPrint()
-{
-  if(sdprinting)
-  {
-    sdprinting = false;
-	paused = true;
-  }
-}
-
-
 void CardReader::openLogFile(const char* name)
 {
   logging = true;
@@ -371,10 +359,10 @@ void CardReader::openFile(const char* name,bool read, bool replace_current/*=tru
     {
      if((int)file_subcall_ctr>(int)SD_PROCEDURE_DEPTH-1)
      {
-       SERIAL_ERROR_START;
-       SERIAL_ERRORPGM("trying to call sub-gcode files with too many levels. MAX level is:");
-       SERIAL_ERRORLN(SD_PROCEDURE_DEPTH);
-       kill("", 1);
+       // SERIAL_ERROR_START;
+       // SERIAL_ERRORPGM("trying to call sub-gcode files with too many levels. MAX level is:");
+       // SERIAL_ERRORLN(SD_PROCEDURE_DEPTH);
+       kill(_n("trying to call sub-gcode files with too many levels."), 1);
        return;
      }
      
@@ -408,9 +396,7 @@ void CardReader::openFile(const char* name,bool read, bool replace_current/*=tru
     SERIAL_ECHOLN(name);
   }
   sdprinting = false;
-  paused = false;
-  
- 
+
   SdFile myDir;
   const char *fname=name;
   diveSubfolder(fname,myDir);
@@ -492,24 +478,27 @@ uint32_t CardReader::getFileSize()
 
 void CardReader::getStatus()
 {
-  if(sdprinting){
-    SERIAL_PROTOCOL(longFilename);
-    SERIAL_PROTOCOLPGM("\n");
-    SERIAL_PROTOCOLRPGM(_N("SD printing byte "));////MSG_SD_PRINTING_BYTE
-    SERIAL_PROTOCOL(sdpos);
-    SERIAL_PROTOCOLPGM("/");
-    SERIAL_PROTOCOLLN(filesize);
-    uint16_t time = _millis()/60000 - starttime/60000;
-    SERIAL_PROTOCOL(itostr2(time/60));
-    SERIAL_PROTOCOL(':');
-    SERIAL_PROTOCOL(itostr2(time%60));
-    SERIAL_PROTOCOLPGM("\n");
-  }
-  else if (paused) {
-	SERIAL_PROTOCOLLNPGM("SD print paused");
-  }
-  else if (saved_printing) {
-	SERIAL_PROTOCOLLNPGM("Print saved");
+  if(sdprinting)
+  {
+      if (isPrintPaused) {
+          SERIAL_PROTOCOLLNPGM("SD print paused");
+      }
+      else if (saved_printing) {
+          SERIAL_PROTOCOLLNPGM("Print saved");
+      }
+      else {
+          SERIAL_PROTOCOL(longFilename);
+          SERIAL_PROTOCOLPGM("\n");
+          SERIAL_PROTOCOLRPGM(_N("SD printing byte "));////MSG_SD_PRINTING_BYTE
+          SERIAL_PROTOCOL(sdpos);
+          SERIAL_PROTOCOLPGM("/");
+          SERIAL_PROTOCOLLN(filesize);
+          uint16_t time = _millis()/60000 - starttime/60000;
+          SERIAL_PROTOCOL(itostr2(time/60));
+          SERIAL_PROTOCOL(':');
+          SERIAL_PROTOCOL(itostr2(time%60));
+          SERIAL_PROTOCOLPGM("\n");
+      }
   }
   else {
     SERIAL_PROTOCOLLNPGM("Not SD printing");
@@ -763,8 +752,8 @@ void CardReader::presort() {
 		#endif
 		#elif SDSORT_USES_STACK
 		char sortnames[fileCnt][LONG_FILENAME_LENGTH];
-		uint16_t creation_time[fileCnt];
-		uint16_t creation_date[fileCnt];
+		uint16_t modification_time[fileCnt];
+		uint16_t modification_date[fileCnt];
 		#endif
 
 		// Folder sorting needs 1 bit per entry for flags.
@@ -784,8 +773,8 @@ void CardReader::presort() {
 		// retaining only two filenames at a time. This is very
 		// slow but is safest and uses minimal RAM.
 		char name1[LONG_FILENAME_LENGTH + 1];
-		uint16_t creation_time_bckp;
-		uint16_t creation_date_bckp;
+		uint16_t modification_time_bckp;
+		uint16_t modification_date_bckp;
 
 		#endif
 		position = 0;
@@ -811,8 +800,8 @@ void CardReader::presort() {
 				#else
 				// Copy filenames into the static array
 				strcpy(sortnames[i], LONGEST_FILENAME);
-				creation_time[i] = creationTime;
-				creation_date[i] = creationDate;
+				modification_time[i] = modificationTime;
+				modification_date[i] = modificationDate;
 				#if SDSORT_CACHE_NAMES
 				strcpy(sortshort[i], filename);
 				#endif
@@ -837,12 +826,12 @@ void CardReader::presort() {
 			// Compare names from the array or just the two buffered names
 			#if SDSORT_USES_RAM
 			#define _SORT_CMP_NODIR() (strcasecmp(sortnames[o1], sortnames[o2]) > 0)
-			#define _SORT_CMP_TIME_NODIR() (((creation_date[o1] == creation_date[o2]) && (creation_time[o1] < creation_time[o2])) || \
-																	(creation_date[o1] < creation_date [o2]))
+			#define _SORT_CMP_TIME_NODIR() (((modification_date[o1] == modification_date[o2]) && (modification_time[o1] < modification_time[o2])) || \
+																	(modification_date[o1] < modification_date [o2]))
 			#else
 			#define _SORT_CMP_NODIR() (strcasecmp(name1, name2) > 0) //true if lowercase(name1) > lowercase(name2)
-			#define _SORT_CMP_TIME_NODIR() (((creation_date_bckp == creationDate) && (creation_time_bckp > creationTime)) || \
-																	(creation_date_bckp > creationDate))
+			#define _SORT_CMP_TIME_NODIR() (((modification_date_bckp == modificationDate) && (modification_time_bckp > modificationTime)) || \
+																	(modification_date_bckp > modificationDate))
 
 			#endif
 
@@ -893,8 +882,8 @@ void CardReader::presort() {
 					counter++;
 					getfilename_simple(positions[o1]);
 					strcpy(name1, LONGEST_FILENAME); // save (or getfilename below will trounce it)
-					creation_date_bckp = creationDate;
-					creation_time_bckp = creationTime;
+					modification_date_bckp = modificationDate;
+					modification_time_bckp = modificationTime;
 					#if HAS_FOLDER_SORTING
 					bool dir1 = filenameIsDir;
 					#endif

+ 3 - 5
Firmware/cardreader.h

@@ -25,7 +25,6 @@ public:
   void closefile(bool store_location=false);
   void release();
   void startFileprint();
-  void pauseSDPrint();
   uint32_t getFileSize();
   void getStatus();
   void printingHasFinished();
@@ -75,9 +74,8 @@ public:
   bool logging;
   bool sdprinting ;  
   bool cardOK ;
-  bool paused ;
   char filename[13];
-  uint16_t creationTime, creationDate;
+  uint16_t modificationTime, modificationDate;
   uint32_t cluster, position;
   char longFilename[LONG_FILENAME_LENGTH];
   bool filenameIsDir;
@@ -114,8 +112,8 @@ private:
     #endif
   #elif !SDSORT_USES_STACK
     char sortnames[SDSORT_LIMIT][FILENAME_LENGTH];
-    uint16_t creation_time[SDSORT_LIMIT];
-    uint16_t creation_date[SDSORT_LIMIT];
+    uint16_t modification_time[SDSORT_LIMIT];
+    uint16_t modification_date[SDSORT_LIMIT];
   #endif
 
   // Folder sorting uses an isDir array when caching items.

+ 33 - 24
Firmware/cmdqueue.cpp

@@ -500,7 +500,7 @@ void get_command()
 
         //If command was e-stop process now
         if(strcmp(cmdbuffer+bufindw+CMDHDRSIZE, "M112") == 0)
-          kill("", 2);
+          kill(MSG_M112_KILL, 2);
         
         // Store the current line into buffer, move to the next line.
 		// Store type of entry
@@ -582,30 +582,8 @@ void get_command()
        ((serial_char == '#' || serial_char == ':') && comment_mode == false) ||
        serial_count >= (MAX_CMD_SIZE - 1) || n==-1)
     {
-      if(card.eof()){
-        SERIAL_PROTOCOLLNRPGM(_n("Done printing file"));////MSG_FILE_PRINTED
-        stoptime=_millis();
-        char time[30];
-        unsigned long t=(stoptime-starttime-pause_time)/1000;
-        pause_time = 0;
-        int hours, minutes;
-        minutes=(t/60)%60;
-        hours=t/60/60;
-        save_statistics(total_filament_used, t);
-        sprintf_P(time, PSTR("%i hours %i minutes"),hours, minutes);
-        SERIAL_ECHO_START;
-        SERIAL_ECHOLN(time);
-        lcd_setstatus(time);
-        card.printingHasFinished();
-        card.checkautostart(true);
-
-        if (farm_mode)
-        {
-            prusa_statistics(6);
-            lcd_commands_type = LcdCommands::FarmModeConfirm;
-        }
+      if(card.eof()) break;
 
-      }
       if(serial_char=='#')
         stop_buffering=true;
 
@@ -663,6 +641,37 @@ void get_command()
       else if(!comment_mode) cmdbuffer[bufindw+CMDHDRSIZE+serial_count++] = serial_char;
     }
   }
+  if(card.eof())
+  {
+      // file was fully buffered, but commands might still need to be planned!
+      // do *not* clear sdprinting until all SD commands are consumed to ensure
+      // SD state can be resumed from a saved printing state. sdprinting is only
+      // cleared by printingHasFinished after peforming all remaining moves.
+      if(!cmdqueue_calc_sd_length())
+      {
+          SERIAL_PROTOCOLLNRPGM(_n("Done printing file"));////MSG_FILE_PRINTED
+          stoptime=_millis();
+          char time[30];
+          unsigned long t=(stoptime-starttime-pause_time)/1000;
+          pause_time = 0;
+          int hours, minutes;
+          minutes=(t/60)%60;
+          hours=t/60/60;
+          save_statistics(total_filament_used, t);
+          sprintf_P(time, PSTR("%i hours %i minutes"),hours, minutes);
+          SERIAL_ECHO_START;
+          SERIAL_ECHOLN(time);
+          lcd_setstatus(time);
+          card.printingHasFinished();
+          card.checkautostart(true);
+
+          if (farm_mode)
+          {
+              prusa_statistics(6);
+              lcd_commands_type = LcdCommands::FarmModeConfirm;
+          }
+      }
+  }
 
   #endif //SDSUPPORT
 }

+ 13 - 4
Firmware/config.h

@@ -2,9 +2,21 @@
 #define _CONFIG_H
 
 
+#include "Configuration_prusa.h"
+#include "pins.h"
+
+#define IR_SENSOR_ANALOG (defined(VOLT_IR_PIN) && defined(IR_SENSOR))
+
 //ADC configuration
+#if !IR_SENSOR_ANALOG
 #define ADC_CHAN_MSK      0b0000001001011111 //used AD channels bit mask (0,1,2,3,4,6,9)
+#define ADC_DIDR_MSK      0b0000001001011111 //AD channels DIDR mask (1 ~ disabled digital input)
 #define ADC_CHAN_CNT      7         //number of used channels)
+#else //!IR_SENSOR_ANALOG
+#define ADC_CHAN_MSK      0b0000001101011111 //used AD channels bit mask (0,1,2,3,4,6,8,9)
+#define ADC_DIDR_MSK      0b0000001001011111 //AD channels DIDR mask (1 ~ disabled digital input)
+#define ADC_CHAN_CNT      8         //number of used channels)
+#endif //!IR_SENSOR_ANALOG
 #define ADC_OVRSAMPL      16        //oversampling multiplier
 #define ADC_CALLBACK      adc_ready //callback function ()
 
@@ -42,11 +54,8 @@
 #define W25X20CL_SPCR          SPI_SPCR(W25X20CL_SPI_RATE, 1, 1, 1, 0)
 #define W25X20CL_SPSR          SPI_SPSR(W25X20CL_SPI_RATE)
 
-#include "boards.h"
-#include "Configuration_prusa.h"
-
 //LANG - Multi-language support
-//#define LANG_MODE              0 // primary language only
+//define LANG_MODE              0 // primary language only
 #define LANG_MODE              1 // sec. language support
 
 #define LANG_SIZE_RESERVED     0x3000 // reserved space for secondary language (12288 bytes)

+ 14 - 2
Firmware/eeprom.h

@@ -74,7 +74,7 @@ static_assert(sizeof(Sheets) == EEPROM_SHEETS_SIZEOF, "Sizeof(Sheets) is not EEP
 #define EEPROM_UVLO_CURRENT_POSITION_Z	(EEPROM_FILE_POSITION - 4) //float for current position in Z
 #define EEPROM_UVLO_TARGET_HOTEND		(EEPROM_UVLO_CURRENT_POSITION_Z - 1)
 #define EEPROM_UVLO_TARGET_BED			(EEPROM_UVLO_TARGET_HOTEND - 1)
-#define EEPROM_UVLO_FEEDRATE			(EEPROM_UVLO_TARGET_BED - 2)
+#define EEPROM_UVLO_FEEDRATE			(EEPROM_UVLO_TARGET_BED - 2) //uint16_t
 #define EEPROM_UVLO_FAN_SPEED			(EEPROM_UVLO_FEEDRATE - 1) 
 #define EEPROM_FAN_CHECK_ENABLED		(EEPROM_UVLO_FAN_SPEED - 1)
 #define EEPROM_UVLO_MESH_BED_LEVELING     (EEPROM_FAN_CHECK_ENABLED - 9*2)
@@ -201,9 +201,21 @@ static_assert(sizeof(Sheets) == EEPROM_SHEETS_SIZEOF, "Sizeof(Sheets) is not EEP
 #define EEPROM_SHEETS_BASE (EEPROM_CHECK_GCODE - EEPROM_SHEETS_SIZEOF) // Sheets
 static Sheets * const EEPROM_Sheets_base = (Sheets*)(EEPROM_SHEETS_BASE);
 
+#define EEPROM_FSENSOR_PCB (EEPROM_SHEETS_BASE-1) // uint8
+#define EEPROM_FSENSOR_ACTION_NA (EEPROM_FSENSOR_PCB-1) // uint8
+
+#define EEPROM_UVLO_SAVED_TARGET (EEPROM_FSENSOR_ACTION_NA - 4*4) // 4 x float for saved target for all axes
+#define EEPROM_UVLO_FEEDMULTIPLY (EEPROM_UVLO_SAVED_TARGET - 2) // uint16_t for feedmultiply
+
+#define EEPROM_BACKLIGHT_LEVEL_HIGH (EEPROM_UVLO_FEEDMULTIPLY-1) // uint8
+#define EEPROM_BACKLIGHT_LEVEL_LOW (EEPROM_BACKLIGHT_LEVEL_HIGH-1) // uint8
+#define EEPROM_BACKLIGHT_MODE (EEPROM_BACKLIGHT_LEVEL_LOW-1) // uint8
+#define EEPROM_BACKLIGHT_TIMEOUT (EEPROM_BACKLIGHT_MODE-2) // uint16
+
+#define EEPROM_UVLO_LA_K (EEPROM_BACKLIGHT_TIMEOUT-4) // float
 
 //This is supposed to point to last item to allow EEPROM overrun check. Please update when adding new items.
-#define EEPROM_LAST_ITEM EEPROM_SHEETS_BASE
+#define EEPROM_LAST_ITEM EEPROM_UVLO_LA_K
 // !!!!!
 // !!!!! this is end of EEPROM section ... all updates MUST BE inserted before this mark !!!!!
 // !!!!!

+ 138 - 57
Firmware/fsensor.cpp

@@ -6,15 +6,16 @@
 #include <avr/pgmspace.h>
 #include "pat9125.h"
 #include "stepper.h"
-#include "planner.h"
-#include "fastio.h"
 #include "io_atmega2560.h"
 #include "cmdqueue.h"
 #include "ultralcd.h"
-#include "ConfigurationStore.h"
 #include "mmu.h"
 #include "cardreader.h"
 
+#include "adc.h"
+#include "temperature.h"
+#include "config.h"
+
 //! @name Basic parameters
 //! @{
 #define FSENSOR_CHUNK_LEN    0.64F  //!< filament sensor chunk length 0.64mm
@@ -53,15 +54,8 @@ bool fsensor_enabled = true;
 bool fsensor_watch_runout = true;
 //! not responding - is set if any communication error occurred during initialization or readout
 bool fsensor_not_responding = false;
-//! printing saved
-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;
@@ -117,6 +111,13 @@ int16_t fsensor_oq_yd_max;
 uint16_t fsensor_oq_sh_sum;
 //! @}
 
+#if IR_SENSOR_ANALOG
+ClFsensorPCB oFsensorPCB;
+ClFsensorActionNA oFsensorActionNA;
+bool bIRsensorStateFlag=false;
+unsigned long nIRsensorLastTime;
+#endif //IR_SENSOR_ANALOG
+
 void fsensor_stop_and_save_print(void)
 {
     printf_P(PSTR("fsensor_stop_and_save_print\n"));
@@ -126,20 +127,28 @@ void fsensor_stop_and_save_print(void)
 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
 }
 
+// fsensor_checkpoint_print cuts the current print job at the current position,
+// allowing new instructions to be inserted in the middle
+void fsensor_checkpoint_print(void)
+{
+    printf_P(PSTR("fsensor_checkpoint_print\n"));
+    stop_and_save_print_to_ram(0, 0);
+    restore_print_from_ram_and_continue(0);
+}
+
 void fsensor_init(void)
 {
 #ifdef PAT9125
 	uint8_t pat9125 = pat9125_init();
-    printf_P(PSTR("PAT9125_init:%hhu\n"), pat9125);
+     printf_P(PSTR("PAT9125_init:%hhu\n"), pat9125);
 #endif //PAT9125
 	uint8_t fsensor = eeprom_read_byte((uint8_t*)EEPROM_FSENSOR);
 	fsensor_autoload_enabled=eeprom_read_byte((uint8_t*)EEPROM_FSENS_AUTOLOAD_ENABLED);
+     fsensor_not_responding = false;
 #ifdef PAT9125
 	uint8_t oq_meassure_enabled = eeprom_read_byte((uint8_t*)EEPROM_FSENS_OQ_MEASS_ENABLED);
 	fsensor_oq_meassure_enabled = (oq_meassure_enabled == 1)?true:false;
@@ -150,19 +159,27 @@ void fsensor_init(void)
 		fsensor = 0; //disable sensor
 		fsensor_not_responding = true;
 	}
-	else
-		fsensor_not_responding = false;
 #endif //PAT9125
+#if IR_SENSOR_ANALOG
+     bIRsensorStateFlag=false;
+     oFsensorPCB=(ClFsensorPCB)eeprom_read_byte((uint8_t*)EEPROM_FSENSOR_PCB);
+     oFsensorActionNA=(ClFsensorActionNA)eeprom_read_byte((uint8_t*)EEPROM_FSENSOR_ACTION_NA);
+#endif //IR_SENSOR_ANALOG
 	if (fsensor)
-		fsensor_enable();
+		fsensor_enable(false);                  // (in this case) EEPROM update is not necessary
 	else
-		fsensor_disable();
-	printf_P(PSTR("FSensor %S\n"), (fsensor_enabled?PSTR("ENABLED"):PSTR("DISABLED\n")));
+		fsensor_disable(false);                 // (in this case) EEPROM update is not necessary
+	printf_P(PSTR("FSensor %S"), (fsensor_enabled?PSTR("ENABLED"):PSTR("DISABLED")));
+#if IR_SENSOR_ANALOG
+     printf_P(PSTR(" (sensor board revision: %S)\n"),(oFsensorPCB==ClFsensorPCB::_Rev03b)?PSTR("03b or newer"):PSTR("03 or older"));
+#else //IR_SENSOR_ANALOG
+     printf_P(PSTR("\n"));
+#endif //IR_SENSOR_ANALOG
 	if (check_for_ir_sensor()) ir_sensor_detected = true;
 
 }
 
-bool fsensor_enable(void)
+bool fsensor_enable(bool bUpdateEEPROM)
 {
 #ifdef PAT9125
 	if (mmu_enabled == false) { //filament sensor is pat9125, enable only if it is working
@@ -187,18 +204,34 @@ bool fsensor_enable(void)
 		FSensorStateMenu = 1;
 	}
 #else // PAT9125
-	fsensor_enabled = true;
-	eeprom_update_byte((uint8_t*)EEPROM_FSENSOR, 0x01);
-	FSensorStateMenu = 1;
-#endif // PAT9125
+#if IR_SENSOR_ANALOG
+     if(!fsensor_IR_check())
+          {
+          bUpdateEEPROM=true;
+          fsensor_enabled=false;
+          fsensor_not_responding=true;
+          FSensorStateMenu=0;
+          }
+     else {
+#endif //IR_SENSOR_ANALOG
+     fsensor_enabled=true;
+     fsensor_not_responding=false;
+     FSensorStateMenu=1;
+#if IR_SENSOR_ANALOG
+          }
+#endif //IR_SENSOR_ANALOG
+     if(bUpdateEEPROM)
+          eeprom_update_byte((uint8_t*)EEPROM_FSENSOR, FSensorStateMenu);
+#endif //PAT9125
 	return fsensor_enabled;
 }
 
-void fsensor_disable(void)
-{
+void fsensor_disable(bool bUpdateEEPROM)
+{ 
 	fsensor_enabled = false;
-	eeprom_update_byte((uint8_t*)EEPROM_FSENSOR, 0x00); 
 	FSensorStateMenu = 0;
+     if(bUpdateEEPROM)
+          eeprom_update_byte((uint8_t*)EEPROM_FSENSOR, 0x00); 
 }
 
 void fsensor_autoload_set(bool State)
@@ -225,7 +258,7 @@ void fsensor_autoload_check_start(void)
 	if (!fsensor_enabled) return;
 	if (!fsensor_autoload_enabled) return;
 	if (fsensor_watch_autoload) return;
-	if (!pat9125_update_y()) //update sensor
+	if (!pat9125_update()) //update sensor
 	{
 		fsensor_disable();
 		fsensor_not_responding = true;
@@ -498,23 +531,11 @@ void fsensor_setup_interrupt(void)
 
 #endif //PAT9125
 
-void fsensor_st_block_begin(block_t* bl)
+void fsensor_st_block_chunk(int cnt)
 {
 	if (!fsensor_enabled) return;
-	if (((fsensor_st_cnt > 0) && (bl->direction_bits & 0x8)) || 
-		((fsensor_st_cnt < 0) && !(bl->direction_bits & 0x8)))
-	{
-// !!! bit toggling (PINxn <- 1) (for PinChangeInterrupt) does not work for some MCU pins
-		if (PIN_GET(FSENSOR_INT_PIN)) {PIN_VAL(FSENSOR_INT_PIN, LOW);}
-		else {PIN_VAL(FSENSOR_INT_PIN, HIGH);}
-	}
-}
-
-void fsensor_st_block_chunk(block_t* bl, int cnt)
-{
-	if (!fsensor_enabled) return;
-	fsensor_st_cnt += (bl->direction_bits & 0x8)?-cnt:cnt;
-	if ((fsensor_st_cnt >= fsensor_chunk_len) || (fsensor_st_cnt <= -fsensor_chunk_len))
+	fsensor_st_cnt += cnt;
+	if (abs(fsensor_st_cnt) >= fsensor_chunk_len)
 	{
 // !!! bit toggling (PINxn <- 1) (for PinChangeInterrupt) does not work for some MCU pins
 		if (PIN_GET(FSENSOR_INT_PIN)) {PIN_VAL(FSENSOR_INT_PIN, LOW);}
@@ -529,8 +550,6 @@ 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")));
 }
 
@@ -542,7 +561,7 @@ void fsensor_enque_M600(){
 void fsensor_update(void)
 {
 #ifdef PAT9125
-		if (fsensor_enabled && fsensor_watch_runout && (fsensor_err_cnt > FSENSOR_ERR_MAX) && ( ! fsensor_m600_enqueued) )
+		if (fsensor_enabled && fsensor_watch_runout && (fsensor_err_cnt > FSENSOR_ERR_MAX))
 		{
 			bool autoload_enabled_tmp = fsensor_autoload_enabled;
 			fsensor_autoload_enabled = false;
@@ -575,24 +594,86 @@ void fsensor_update(void)
 			err |= (fsensor_oq_er_sum > 2);
 			err |= (fsensor_oq_yd_sum < (4 * FSENSOR_OQ_MIN_YD));
 
+            fsensor_restore_print_and_continue();
+			fsensor_autoload_enabled = autoload_enabled_tmp;
+			fsensor_oq_meassure_enabled = oq_meassure_enabled_tmp;
+
 			if (!err)
-			{
 				printf_P(PSTR("fsensor_err_cnt = 0\n"));
-				fsensor_restore_print_and_continue();
-			}
 			else
-			{
 				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_m600_enqueued) )
-		{
-			fsensor_stop_and_save_print();
-			fsensor_enque_M600();
+		if (CHECK_FSENSOR && fsensor_enabled && ir_sensor_detected)
+        {
+               if(digitalRead(IR_SENSOR_PIN))
+               {                                  // IR_SENSOR_PIN ~ H
+#if IR_SENSOR_ANALOG
+                    if(!bIRsensorStateFlag)
+                    {
+                         bIRsensorStateFlag=true;
+                         nIRsensorLastTime=_millis();
+                    }
+                    else
+                    {
+                         if((_millis()-nIRsensorLastTime)>IR_SENSOR_STEADY)
+                         {
+                              uint8_t nMUX1,nMUX2;
+                              uint16_t nADC;
+                              bIRsensorStateFlag=false;
+                              // sequence for direct data reading from AD converter
+                              DISABLE_TEMPERATURE_INTERRUPT();
+                              nMUX1=ADMUX;        // ADMUX saving
+                              nMUX2=ADCSRB;
+                              adc_setmux(VOLT_IR_PIN);
+                              ADCSRA|=(1<<ADSC);  // first conversion after ADMUX change discarded (preventively)
+                              while(ADCSRA&(1<<ADSC))
+                                   ;
+                              ADCSRA|=(1<<ADSC);  // second conversion used
+                              while(ADCSRA&(1<<ADSC))
+                                   ;
+                              nADC=ADC;
+                              ADMUX=nMUX1;        // ADMUX restoring
+                              ADCSRB=nMUX2;
+                              ENABLE_TEMPERATURE_INTERRUPT();
+                              // end of sequence for ...
+                              if((oFsensorPCB==ClFsensorPCB::_Rev03b)&&((nADC*OVERSAMPLENR)>((int)IRsensor_Hopen_TRESHOLD)))
+                              {
+                                   fsensor_disable();
+                                   fsensor_not_responding = true;
+                                   printf_P(PSTR("IR sensor not responding (%d)!\n"),1);
+                                   if((ClFsensorActionNA)eeprom_read_byte((uint8_t*)EEPROM_FSENSOR_ACTION_NA)==ClFsensorActionNA::_Pause)
+                                   if(oFsensorActionNA==ClFsensorActionNA::_Pause)
+                                        lcd_pause_print();
+                              }
+                              else
+                              {
+#endif //IR_SENSOR_ANALOG
+                                  fsensor_checkpoint_print();
+                                  fsensor_enque_M600();
+#if IR_SENSOR_ANALOG
+                              }
+                         }
+                    }
+               }
+               else
+               {                                  // IR_SENSOR_PIN ~ L
+                    bIRsensorStateFlag=false;
+#endif //IR_SENSOR_ANALOG
+               }
 		}
 #endif //PAT9125
 }
+
+#if IR_SENSOR_ANALOG
+bool fsensor_IR_check()
+{
+uint16_t volt_IR_int;
+bool bCheckResult;
+
+volt_IR_int=current_voltage_raw_IR;
+bCheckResult=(volt_IR_int<((int)IRsensor_Lmax_TRESHOLD))||(volt_IR_int>((int)IRsensor_Hmin_TRESHOLD));
+bCheckResult=bCheckResult&&(!((oFsensorPCB==ClFsensorPCB::_Rev03b)&&(volt_IR_int>((int)IRsensor_Hopen_TRESHOLD))));
+return(bCheckResult);
+}
+#endif //IR_SENSOR_ANALOG

+ 36 - 6
Firmware/fsensor.h

@@ -3,6 +3,7 @@
 #define FSENSOR_H
 
 #include <inttypes.h>
+#include "config.h"
 
 
 //! minimum meassured chunk length in steps
@@ -20,6 +21,8 @@ extern bool fsensor_oq_meassure_enabled;
 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);
+//! split the current gcode stream to insert new instructions
+extern void fsensor_checkpoint_print(void);
 //! @}
 
 //! initialize
@@ -27,8 +30,8 @@ extern void fsensor_init(void);
 
 //! @name enable/disable
 //! @{
-extern bool fsensor_enable(void);
-extern void fsensor_disable(void);
+extern bool fsensor_enable(bool bUpdateEEPROM=true);
+extern void fsensor_disable(bool bUpdateEEPROM=true);
 //! @}
 
 //autoload feature enabled
@@ -57,12 +60,39 @@ extern void fsensor_oq_meassure_stop(void);
 extern bool fsensor_oq_result(void);
 //! @}
 
-
-#include "planner.h"
 //! @name callbacks from stepper
 //! @{
-extern void fsensor_st_block_begin(block_t* bl);
-extern void fsensor_st_block_chunk(block_t* bl, int cnt);
+extern void fsensor_st_block_chunk(int cnt);
+
+// There's really nothing to do in block_begin: the stepper ISR likely has
+// called us already at the end of the last block, making this integration
+// redundant. LA1.5 might not always do that during a coasting move, so attempt
+// to drain fsensor_st_cnt anyway at the beginning of the new block.
+#define fsensor_st_block_begin(rev) fsensor_st_block_chunk(0)
 //! @}
 
+
+#if IR_SENSOR_ANALOG
+#define IR_SENSOR_STEADY 10                       // [ms]
+
+enum class ClFsensorPCB:uint_least8_t
+{
+    _Old=0,
+    _Rev03b=1,
+    _Undef=EEPROM_EMPTY_VALUE
+};
+
+enum class ClFsensorActionNA:uint_least8_t
+{
+    _Continue=0,
+    _Pause=1,
+    _Undef=EEPROM_EMPTY_VALUE
+};
+
+extern ClFsensorPCB oFsensorPCB;
+extern ClFsensorActionNA oFsensorActionNA;
+
+extern bool fsensor_IR_check();
+#endif //IR_SENSOR_ANALOG
+
 #endif //FSENSOR_H

+ 48 - 0
Firmware/la10compat.cpp

@@ -0,0 +1,48 @@
+#include "la10compat.h"
+#include "Marlin.h"
+
+
+static LA10C_MODE la10c_mode = LA10C_UNKNOWN;
+
+
+void la10c_mode_change(LA10C_MODE mode)
+{
+    if(mode == la10c_mode) return;
+
+    SERIAL_ECHOPGM("LA10C: Linear Advance mode: ");
+    switch(mode)
+    {
+    case LA10C_UNKNOWN: SERIAL_ECHOLNPGM("UNKNOWN"); break;
+    case LA10C_LA15:    SERIAL_ECHOLNPGM("1.5"); break;
+    case LA10C_LA10:    SERIAL_ECHOLNPGM("1.0"); break;
+    }
+    la10c_mode = mode;
+}
+
+
+// Approximate a LA10 value to a LA15 equivalent.
+static float la10c_convert(float k)
+{
+    float new_K = k * 0.004 - 0.06;
+    return (new_K < 0? 0: new_K);
+}
+
+
+float la10c_value(float k)
+{
+    if(la10c_mode == LA10C_UNKNOWN)
+    {
+        // do not autodetect until a valid value is seen
+        if(k == 0)
+            return 0;
+        else if(k < 0)
+            return -1;
+
+        la10c_mode_change(k < 10? LA10C_LA15: LA10C_LA10);
+    }
+
+    if(la10c_mode == LA10C_LA15)
+        return (k >= 0 && k < 10? k: -1);
+    else
+        return (k >= 0? la10c_convert(k): -1);
+}

+ 39 - 0
Firmware/la10compat.h

@@ -0,0 +1,39 @@
+// la10compat: LA10->LA15 conversion
+//
+// When the current mode is UNKNOWN autodetection is active and any K<10
+// will set the mode to LA15, LA10 is set otherwise. When LA10
+// compatbility mode is active the K factor is converted to a LA15
+// equivalent (that is, the return value is always a LA15 value).
+//
+// Once the interpretation mode has been set it is kept until the mode
+// is explicitly reset. This is done to handle transparent fallback for
+// old firmware revisions in combination with the following gcode
+// sequence:
+//
+//   M900 K0.01 ; set LA15 value (interpreted by any firmware)
+//   M900 K10   ; set LA10 value (ignored by LA15 firmware)
+//
+// A LA15 firmware without this module will only parse the first
+// correctly, rejecting the second. A LA10 FW will parse both, but keep
+// the last value. Since the LA15 value, if present, corresponds to the
+// truth value, the compatibility stub needs to "lock" onto the first
+// seen value for the current print.
+//
+// The mode needs to be carefully reset for each print in order for
+// diffent versions of M900 to be interpreted independently.
+
+#pragma once
+
+enum __attribute__((packed)) LA10C_MODE
+{
+    LA10C_UNKNOWN = 0,
+    LA10C_LA15    = 1,
+    LA10C_LA10    = 2
+};
+
+// Explicitly set/reset the interpretation mode for la10c_value()
+void la10c_mode_change(LA10C_MODE mode);
+static inline void la10c_reset() { la10c_mode_change(LA10C_UNKNOWN); }
+
+// Return a LA15 K value according to the supplied value and mode
+float la10c_value(float k);

+ 3 - 3
Firmware/language.c

@@ -17,10 +17,10 @@ uint8_t lang_selected = 0;
 
 #if (LANG_MODE == 0) //primary language only
 
-uint8_t lang_select(uint8_t lang) { return 0; }
+uint8_t lang_select(__attribute__((unused)) uint8_t lang) { return 0; }
 uint8_t lang_get_count() { return 1; }
-uint16_t lang_get_code(uint8_t lang) { return LANG_CODE_EN; }
-const char* lang_get_name_by_code(uint16_t code) { return _n("English"); }
+uint16_t lang_get_code(__attribute__((unused)) uint8_t lang) { return LANG_CODE_EN; }
+const char* lang_get_name_by_code(__attribute__((unused)) uint16_t code) { return _n("English"); }
 void lang_reset(void) { }
 uint8_t lang_is_selected(void) { return 1; }
 

+ 48 - 10
Firmware/menu.cpp

@@ -102,7 +102,7 @@ void menu_back(void)
 menu_back(1);
 }
 
-static void menu_back_no_reset(void)
+void menu_back_no_reset(void)
 {
 	if (menu_depth > 0)
 	{
@@ -136,7 +136,7 @@ void menu_submenu(menu_func_t submenu)
 	}
 }
 
-static void menu_submenu_no_reset(menu_func_t submenu)
+void menu_submenu_no_reset(menu_func_t submenu)
 {
 	if (menu_depth < MENU_DEPTH_MAX)
 	{
@@ -184,6 +184,22 @@ static void menu_draw_item_puts_P(char type_char, const char* str)
     lcd_printf_P(PSTR("%c%-18.18S%c"), menu_selection_mark(), str, type_char);
 }
 
+static void menu_draw_toggle_puts_P(const char* str, const char* toggle, const uint8_t settings)
+{
+    //settings:
+    //xxxxxcba
+    //a = selection mark. If it's set(1), then '>' will be used as the first character on the line. Else leave blank
+    //b = toggle string is from progmem
+    //c = do not set cursor at all. Must be handled externally.
+    char lineStr[LCD_WIDTH + 1];
+    const char eol = (toggle == NULL)?LCD_STR_ARROW_RIGHT[0]:' ';
+    if (toggle == NULL) toggle = _T(MSG_NA);
+    sprintf_P(lineStr, PSTR("%c%-18.18S"), (settings & 0x01)?'>':' ', str);
+    sprintf_P(lineStr + LCD_WIDTH - ((settings & 0x02)?strlen_P(toggle):strlen(toggle)) - 3, (settings & 0x02)?PSTR("[%S]%c"):PSTR("[%s]%c"), toggle, eol);
+    if (!(settings & 0x04)) lcd_set_cursor(0, menu_row);
+    fputs(lineStr, lcdout);
+}
+
 //! @brief Format sheet name
 //!
 //! @param[in] sheet_E Sheet in EEPROM
@@ -375,6 +391,33 @@ uint8_t menu_item_function_P(const char* str, char number, void (*func)(uint8_t)
     return 0;
 }
 
+uint8_t menu_item_toggle_P(const char* str, const char* toggle, menu_func_t func, const uint8_t settings)
+{
+	if (menu_item == menu_line)
+	{
+		if (lcd_draw_update) menu_draw_toggle_puts_P(str, toggle, settings | (menu_selection_mark()=='>'));
+		if (menu_clicked && (lcd_encoder == menu_item))
+		{
+			if (toggle == NULL) // print N/A warning message
+			{
+				menu_submenu(func);
+				return menu_item_ret();
+			}
+			else // do the actual toggling
+			{
+				menu_clicked = false;
+				lcd_consume_click();
+				lcd_update_enabled = 0;
+				if (func) func();
+				lcd_update_enabled = 1;
+				return menu_item_ret();
+			}
+		}
+	}
+	menu_item++;
+	return 0;
+}
+
 uint8_t menu_item_gcode_P(const char* str, const char* str_gcode)
 {
 	if (menu_item == menu_line)
@@ -390,17 +433,12 @@ uint8_t menu_item_gcode_P(const char* str, const char* str_gcode)
 	return 0;
 }
 
-
-const char menu_20x_space[] PROGMEM = "                    ";
-
 const char menu_fmt_int3[] PROGMEM = "%c%.15S:%s%3d";
 
 const char menu_fmt_float31[] PROGMEM = "%-12.12S%+8.1f";
 
 const char menu_fmt_float13[] PROGMEM = "%c%-13.13S%+5.3f";
 
-const char menu_fmt_float13off[] PROGMEM = "%c%-13.13S%6.6S";
-
 template<typename T>
 static void menu_draw_P(char chr, const char* str, int16_t val);
 
@@ -409,8 +447,8 @@ void menu_draw_P<int16_t*>(char chr, const char* str, int16_t val)
 {
 	int text_len = strlen_P(str);
 	if (text_len > 15) text_len = 15;
-	char spaces[21];
-	strcpy_P(spaces, menu_20x_space);
+	char spaces[LCD_WIDTH + 1] = {0};
+    memset(spaces,' ', LCD_WIDTH);
 	if (val <= -100) spaces[15 - text_len - 1] = 0;
 	else spaces[15 - text_len] = 0;
 	lcd_printf_P(menu_fmt_int3, chr, str, spaces, val);
@@ -423,7 +461,7 @@ void menu_draw_P<uint8_t*>(char chr, const char* str, int16_t val)
     float factor = 1.0f + static_cast<float>(val) / 1000.0f;
     if (val <= _md->minEditValue)
     {
-        lcd_printf_P(menu_fmt_float13off, chr, str, _i(" [off]"));
+        menu_draw_toggle_puts_P(str, _T(MSG_OFF), 0x04 | 0x02 | (chr=='>'));
     }
     else
     {

+ 6 - 1
Firmware/menu.h

@@ -76,6 +76,7 @@ void menu_start(void);
 extern void menu_end(void);
 
 extern void menu_back(void);
+extern void menu_back_no_reset(void);
 extern void menu_back(uint8_t nLevel);
 
 extern void menu_back_if_clicked(void);
@@ -83,6 +84,7 @@ extern void menu_back_if_clicked(void);
 extern void menu_back_if_clicked_fb(void);
 
 extern void menu_submenu(menu_func_t submenu);
+extern void menu_submenu_no_reset(menu_func_t submenu);
 
 extern uint8_t menu_item_ret(void);
 
@@ -118,6 +120,10 @@ extern uint8_t menu_item_function_P(const char* str, menu_func_t func);
 #define MENU_ITEM_FUNCTION_NR_P(str, number, func, fn_par) do { if (menu_item_function_P(str, number, func, fn_par)) return; } while (0)
 extern uint8_t menu_item_function_P(const char* str, char number, void (*func)(uint8_t), uint8_t fn_par);
 
+#define MENU_ITEM_TOGGLE_P(str, toggle, func) do { if (menu_item_toggle_P(str, toggle, func, 0x02)) return; } while (0)
+#define MENU_ITEM_TOGGLE(str, toggle, func) do { if (menu_item_toggle_P(str, toggle, func, 0x00)) return; } while (0)
+extern uint8_t menu_item_toggle_P(const char* str, const char* toggle, menu_func_t func, const uint8_t settings);
+
 #define MENU_ITEM_GCODE_P(str, str_gcode) do { if (menu_item_gcode_P(str, str_gcode)) return; } while (0)
 extern uint8_t menu_item_gcode_P(const char* str, const char* str_gcode);
 
@@ -127,7 +133,6 @@ extern const char menu_fmt_int3[];
 extern const char menu_fmt_float31[];
 extern const char menu_fmt_float13[];
 
-
 extern void menu_draw_float31(const char* str, float val);
 
 extern void menu_draw_float13(const char* str, float val);

+ 51 - 14
Firmware/messages.c

@@ -9,7 +9,6 @@
 
 //internationalized messages
 const char MSG_AUTO_HOME[] PROGMEM_I1 = ISTR("Auto home"); ////
-const char MSG_AUTO_MODE_ON[] PROGMEM_I1 = ISTR("Mode [auto power]"); ////
 const char MSG_BABYSTEP_Z[] PROGMEM_I1 = ISTR("Live adjust Z"); //// c=18
 const char MSG_BABYSTEP_Z_NOT_SET[] PROGMEM_I1 = ISTR("Distance between tip of the nozzle and the bed surface has not been set yet. Please follow the manual, chapter First steps, section First layer calibration."); ////c=20 r=12
 const char MSG_BED[] PROGMEM_I1 = ISTR("Bed"); ////
@@ -22,9 +21,7 @@ const char MSG_CARD_MENU[] PROGMEM_I1 = ISTR("Print from SD"); ////
 const char MSG_CONFIRM_NOZZLE_CLEAN[] PROGMEM_I1 = ISTR("Please clean the nozzle for calibration. Click when done."); ////c=20 r=8
 const char MSG_COOLDOWN[] PROGMEM_I1 = ISTR("Cooldown"); ////
 const char MSG_CRASH_DETECTED[] PROGMEM_I1 = ISTR("Crash detected."); ////c=20 r=1
-const char MSG_CRASHDETECT_NA[] PROGMEM_I1 = ISTR("Crash det.  [N/A]"); ////
-const char MSG_CRASHDETECT_OFF[] PROGMEM_I1 = ISTR("Crash det.  [off]"); ////
-const char MSG_CRASHDETECT_ON[] PROGMEM_I1 = ISTR("Crash det.   [on]"); ////
+const char MSG_CRASHDETECT[] PROGMEM_I1 = ISTR("Crash det."); ////
 const char MSG_ERROR[] PROGMEM_I1 = ISTR("ERROR:"); ////
 const char MSG_EXTRUDER[] PROGMEM_I1 = ISTR("Extruder"); ////c=17 r=1
 const char MSG_FILAMENT[] PROGMEM_I1 = ISTR("Filament"); ////c=17 r=1
@@ -40,9 +37,8 @@ const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE2[] PROGMEM_I1 = ISTR(" of 4"); ////
 const char MSG_FINISHING_MOVEMENTS[] PROGMEM_I1 = ISTR("Finishing movements"); ////c=20 r=1
 const char MSG_FOLLOW_CALIBRATION_FLOW[] PROGMEM_I1 = ISTR("Printer has not been calibrated yet. Please follow the manual, chapter First steps, section Calibration flow."); ////c=20 r=8
 const char MSG_FOLLOW_Z_CALIBRATION_FLOW[] PROGMEM_I1 = ISTR("There is still a need to make Z calibration. Please follow the manual, chapter First steps, section Calibration flow."); ////c=20 r=8
-const char MSG_FSENS_AUTOLOAD_NA[] PROGMEM_I1 = ISTR("F. autoload [N/A]"); ////c=17 r=1
-const char MSG_FSENSOR_OFF[] PROGMEM_I1 = ISTR("Fil. sensor [off]"); ////
-const char MSG_FSENSOR_ON[] PROGMEM_I1 = ISTR("Fil. sensor  [on]"); ////
+const char MSG_FSENSOR_AUTOLOAD[] PROGMEM_I1 = ISTR("F. autoload"); ////c=17 r=1
+const char MSG_FSENSOR[] PROGMEM_I1 = ISTR("Fil. sensor"); ////
 const char MSG_HEATING[] PROGMEM_I1 = ISTR("Heating"); ////
 const char MSG_HEATING_COMPLETE[] PROGMEM_I1 = ISTR("Heating done."); ////c=20
 const char MSG_HOMEYZ[] PROGMEM_I1 = ISTR("Calibrate Z"); ////
@@ -85,14 +81,16 @@ const char MSG_SELFTEST_FILAMENT_SENSOR[] PROGMEM_I1 = ISTR("Filament sensor");
 const char MSG_SELFTEST_WIRINGERROR[] PROGMEM_I1 = ISTR("Wiring error"); ////
 const char MSG_SETTINGS[] PROGMEM_I1 = ISTR("Settings"); ////
 const char MSG_HW_SETUP[] PROGMEM_I1 = ISTR("HW Setup"); ////
-const char MSG_SILENT_MODE_OFF[] PROGMEM_I1 = ISTR("Mode [high power]"); ////
-const char MSG_SILENT_MODE_ON[] PROGMEM_I1 = ISTR("Mode     [silent]"); ////
-const char MSG_STEALTH_MODE_OFF[] PROGMEM_I1 = ISTR("Mode     [Normal]"); ////
-const char MSG_STEALTH_MODE_ON[] PROGMEM_I1 = ISTR("Mode    [Stealth]"); ////
+const char MSG_MODE[] PROGMEM_I1 = ISTR("Mode"); ////
+const char MSG_HIGH_POWER[] PROGMEM_I1 = ISTR("High power"); ////
+const char MSG_AUTO_POWER[] PROGMEM_I1 = ISTR("Auto power"); ////
+const char MSG_SILENT[] PROGMEM_I1 = ISTR("Silent"); ////
+const char MSG_NORMAL[] PROGMEM_I1 = ISTR("Normal"); ////
+const char MSG_STEALTH[] PROGMEM_I1 = ISTR("Stealth"); ////
 const char MSG_STEEL_SHEET_CHECK[] PROGMEM_I1 = ISTR("Is steel sheet on heatbed?"); ////c=20 r=2
 const char MSG_STOP_PRINT[] PROGMEM_I1 = ISTR("Stop print"); ////
 const char MSG_STOPPED[] PROGMEM_I1 = ISTR("STOPPED. "); ////
-const char MSG_TEMP_CALIBRATION[] PROGMEM_I1 = ISTR("Temp. cal.          "); ////c=20 r=1
+const char MSG_TEMP_CALIBRATION[] PROGMEM_I1 = ISTR("Temp. cal."); ////c=12 r=1
 const char MSG_TEMP_CALIBRATION_DONE[] PROGMEM_I1 = ISTR("Temperature calibration is finished and active. Temp. calibration can be disabled in menu Settings->Temp. cal."); ////c=20 r=12
 const char MSG_UNLOAD_FILAMENT[] PROGMEM_I1 = ISTR("Unload filament"); ////c=17
 const char MSG_UNLOADING_FILAMENT[] PROGMEM_I1 = ISTR("Unloading filament"); ////c=20 r=1
@@ -104,13 +102,48 @@ const char MSG_WIZARD_QUIT[] PROGMEM_I1 = ISTR("You can always resume the Wizard
 const char MSG_YES[] PROGMEM_I1 = ISTR("Yes"); ////
 const char MSG_V2_CALIBRATION[] PROGMEM_I1 = ISTR("First layer cal."); ////c=17 r=1
 const char WELCOME_MSG[] PROGMEM_I1 = ISTR(CUSTOM_MENDEL_NAME " OK."); ////c=20
+const char MSG_OFF[] PROGMEM_I1 = ISTR("Off"); ////
+const char MSG_ON[] PROGMEM_I1 = ISTR("On"); ////
+const char MSG_NA[] PROGMEM_I1 = ISTR("N/A"); ////
+const char MSG_AUTO_DEPLETE[] PROGMEM_I1 = ISTR("SpoolJoin"); ////
+const char MSG_CUTTER[] PROGMEM_I1 = ISTR("Cutter"); ////
+const char MSG_NONE[] PROGMEM_I1 = ISTR("None"); ////
+const char MSG_WARN[] PROGMEM_I1 = ISTR("Warn"); ////
+const char MSG_STRICT[] PROGMEM_I1 = ISTR("Strict"); ////
+const char MSG_MODEL[] PROGMEM_I1 = ISTR("Model"); ////
+const char MSG_FIRMWARE[] PROGMEM_I1 = ISTR("Firmware"); ////
+const char MSG_GCODE[] PROGMEM_I1 = ISTR("Gcode"); ////
+const char MSG_NOZZLE_DIAMETER[] PROGMEM_I1 = ISTR("Nozzle d."); ////
+const char MSG_MMU_MODE[] PROGMEM_I1 = ISTR("MMU Mode"); ////
+const char MSG_SD_CARD[] PROGMEM_I1 = ISTR("SD card"); ////
+const char MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY[] PROGMEM_I1 = ISTR("FlashAir"); ////
+const char MSG_SORT[] PROGMEM_I1 = ISTR("Sort"); ////
+const char MSG_SORT_TIME[] PROGMEM_I1 = ISTR("Time"); ////
+const char MSG_SORT_ALPHA[] PROGMEM_I1 = ISTR("Alphabet"); ////
+const char MSG_RPI_PORT[] PROGMEM_I1 = ISTR("RPi port"); ////
+const char MSG_SOUND[] PROGMEM_I1 = ISTR("Sound"); ////
+const char MSG_SOUND_LOUD[] PROGMEM_I1 = ISTR("Loud"); ////
+const char MSG_SOUND_ONCE[] PROGMEM_I1 = ISTR("Once"); ////
+const char MSG_SOUND_BLIND[] PROGMEM_I1 = ISTR("Assist"); ////
+const char MSG_MESH[] PROGMEM_I1 = ISTR("Mesh"); ////
+const char MSG_Z_PROBE_NR[] PROGMEM_I1 = ISTR("Z-probe nr."); ////
+const char MSG_MAGNETS_COMP[] PROGMEM_I1 = ISTR("Magnets comp."); ////
+const char MSG_FS_ACTION[] PROGMEM_I1 = ISTR("FS Action"); ////
+const char MSG_FS_CONTINUE[] PROGMEM_I1 = ISTR("Cont."); ////
+const char MSG_FS_PAUSE[] PROGMEM_I1 = ISTR("Pause"); ////
+const char MSG_BRIGHTNESS[] PROGMEM_I1 = ISTR("Brightness"); ////
+const char MSG_BL_HIGH[] PROGMEM_I1 = ISTR("Level Bright"); ////
+const char MSG_BL_LOW[] PROGMEM_I1 = ISTR("Level Dimmed"); ////
+const char MSG_TIMEOUT[] PROGMEM_I1 = ISTR("Timeout"); ////
+const char MSG_BRIGHT[] PROGMEM_I1 = ISTR("Bright"); ////
+const char MSG_DIM[] PROGMEM_I1 = ISTR("Dim"); ////
+const char MSG_AUTO[] PROGMEM_I1 = ISTR("Auto"); ////
+
 //not internationalized messages
 const char MSG_SD_WORKDIR_FAIL[] PROGMEM_N1 = "workDir open failed"; ////
 const char MSG_BROWNOUT_RESET[] PROGMEM_N1 = " Brown out Reset"; ////
 const char MSG_EXTERNAL_RESET[] PROGMEM_N1 = " External Reset"; ////
 const char MSG_FILE_SAVED[] PROGMEM_N1 = "Done saving file."; ////
-const char MSG_OFF[] PROGMEM_N1 = "Off"; ////
-const char MSG_ON[] PROGMEM_N1 = "On "; ////
 const char MSG_POSITION_UNKNOWN[] PROGMEM_N1 = "Home X/Y before Z"; ////
 const char MSG_SOFTWARE_RESET[] PROGMEM_N1 = " Software Reset"; ////
 const char MSG_UNKNOWN_COMMAND[] PROGMEM_N1 = "Unknown command: \""; ////
@@ -134,3 +167,7 @@ const char MSG_OCTOPRINT_RESUMED[] PROGMEM_N1 = "// action:resumed"; ////
 const char MSG_OCTOPRINT_CANCEL[] PROGMEM_N1 = "// action:cancel"; ////
 const char MSG_FANCHECK_EXTRUDER[] PROGMEM_N1 = "Err: EXTR. FAN ERROR"; ////c=20
 const char MSG_FANCHECK_PRINT[] PROGMEM_N1 = "Err: PRINT FAN ERROR"; ////c=20
+const char MSG_M112_KILL[] PROGMEM_N1 = "M112 called. Emergency Stop."; ////c=20
+#ifdef LA_LIVE_K
+const char MSG_ADVANCE_K[] PROGMEM_N1 = "Advance K:"; ////c=13
+#endif

+ 48 - 13
Firmware/messages.h

@@ -10,7 +10,6 @@ extern "C" {
 // LCD Menu Messages
 //internationalized messages
 extern const char MSG_AUTO_HOME[];
-extern const char MSG_AUTO_MODE_ON[];
 extern const char MSG_BABYSTEP_Z[];
 extern const char MSG_BABYSTEP_Z_NOT_SET[];
 extern const char MSG_BED[];
@@ -23,9 +22,7 @@ extern const char MSG_CARD_MENU[];
 extern const char MSG_CONFIRM_NOZZLE_CLEAN[];
 extern const char MSG_COOLDOWN[];
 extern const char MSG_CRASH_DETECTED[];
-extern const char MSG_CRASHDETECT_NA[];
-extern const char MSG_CRASHDETECT_OFF[];
-extern const char MSG_CRASHDETECT_ON[];
+extern const char MSG_CRASHDETECT[];
 extern const char MSG_ERROR[];
 extern const char MSG_EXTRUDER[];
 extern const char MSG_FILAMENT[];
@@ -41,9 +38,8 @@ extern const char MSG_FIND_BED_OFFSET_AND_SKEW_LINE2[];
 extern const char MSG_FINISHING_MOVEMENTS[];
 extern const char MSG_FOLLOW_CALIBRATION_FLOW[];
 extern const char MSG_FOLLOW_Z_CALIBRATION_FLOW[];
-extern const char MSG_FSENS_AUTOLOAD_NA[];
-extern const char MSG_FSENSOR_OFF[];
-extern const char MSG_FSENSOR_ON[];
+extern const char MSG_FSENSOR_AUTOLOAD[];
+extern const char MSG_FSENSOR[];
 extern const char MSG_HEATING[];
 extern const char MSG_HEATING_COMPLETE[];
 extern const char MSG_HOMEYZ[];
@@ -85,10 +81,12 @@ extern const char MSG_SELFTEST_FILAMENT_SENSOR[];
 extern const char MSG_SELFTEST_WIRINGERROR[];
 extern const char MSG_SETTINGS[];
 extern const char MSG_HW_SETUP[];
-extern const char MSG_SILENT_MODE_OFF[];
-extern const char MSG_SILENT_MODE_ON[];
-extern const char MSG_STEALTH_MODE_OFF[];
-extern const char MSG_STEALTH_MODE_ON[];
+extern const char MSG_MODE[];
+extern const char MSG_HIGH_POWER[];
+extern const char MSG_AUTO_POWER[];
+extern const char MSG_SILENT[];
+extern const char MSG_NORMAL[];
+extern const char MSG_STEALTH[];
 extern const char MSG_STEEL_SHEET_CHECK[];
 extern const char MSG_STOP_PRINT[];
 extern const char MSG_STOPPED[];
@@ -104,12 +102,47 @@ extern const char MSG_WIZARD_QUIT[];
 extern const char MSG_YES[];
 extern const char MSG_V2_CALIBRATION[];
 extern const char WELCOME_MSG[];
+extern const char MSG_OFF[];
+extern const char MSG_ON[];
+extern const char MSG_NA[];
+extern const char MSG_AUTO_DEPLETE[];
+extern const char MSG_CUTTER[];
+extern const char MSG_NONE[];
+extern const char MSG_WARN[];
+extern const char MSG_STRICT[];
+extern const char MSG_MODEL[];
+extern const char MSG_FIRMWARE[];
+extern const char MSG_GCODE[];
+extern const char MSG_NOZZLE_DIAMETER[];
+extern const char MSG_MMU_MODE[];
+extern const char MSG_SD_CARD[];
+extern const char MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY[];
+extern const char MSG_SORT[];
+extern const char MSG_SORT_TIME[];
+extern const char MSG_SORT_ALPHA[];
+extern const char MSG_RPI_PORT[];
+extern const char MSG_SOUND[];
+extern const char MSG_SOUND_LOUD[];
+extern const char MSG_SOUND_ONCE[];
+extern const char MSG_SOUND_BLIND[];
+extern const char MSG_MESH[];
+extern const char MSG_Z_PROBE_NR[];
+extern const char MSG_MAGNETS_COMP[];
+extern const char MSG_FS_ACTION[];
+extern const char MSG_FS_CONTINUE[];
+extern const char MSG_FS_PAUSE[];
+extern const char MSG_BRIGHTNESS[];
+extern const char MSG_BL_HIGH[];
+extern const char MSG_BL_LOW[];
+extern const char MSG_TIMEOUT[];
+extern const char MSG_BRIGHT[];
+extern const char MSG_DIM[];
+extern const char MSG_AUTO[];
+
 //not internationalized messages
 extern const char MSG_BROWNOUT_RESET[];
 extern const char MSG_EXTERNAL_RESET[];
 extern const char MSG_FILE_SAVED[];
-extern const char MSG_OFF[];
-extern const char MSG_ON[];
 extern const char MSG_POSITION_UNKNOWN[];
 extern const char MSG_SOFTWARE_RESET[];
 extern const char MSG_UNKNOWN_COMMAND[];
@@ -135,6 +168,8 @@ extern const char MSG_OCTOPRINT_RESUMED[];
 extern const char MSG_OCTOPRINT_CANCEL[];
 extern const char MSG_FANCHECK_EXTRUDER[];
 extern const char MSG_FANCHECK_PRINT[];
+extern const char MSG_M112_KILL[];
+extern const char MSG_ADVANCE_K[];
 
 #if defined(__cplusplus)
 }

+ 19 - 23
Firmware/mmu.cpp

@@ -70,6 +70,7 @@ uint8_t mmu_extruder = MMU_FILAMENT_UNKNOWN;
 uint8_t tmp_extruder = MMU_FILAMENT_UNKNOWN;
 
 int8_t mmu_finda = -1;
+uint32_t mmu_last_finda_response = 0;
 
 int16_t mmu_version = -1;
 
@@ -264,6 +265,7 @@ void mmu_loop(void)
 		if (mmu_rx_ok() > 0)
 		{
 			fscanf_P(uart2io, PSTR("%hhu"), &mmu_finda); //scan finda from buffer
+			mmu_last_finda_response = _millis();
 			FDEBUG_PRINTF_P(PSTR("MMU => '%dok'\n"), mmu_finda);
 			puts_P(PSTR("MMU - ENABLED"));
 			mmu_enabled = true;
@@ -376,11 +378,11 @@ void mmu_loop(void)
 		if (mmu_rx_ok() > 0)
 		{
 			fscanf_P(uart2io, PSTR("%hhu"), &mmu_finda); //scan finda from buffer
+			mmu_last_finda_response = _millis();
 			FDEBUG_PRINTF_P(PSTR("MMU => '%dok'\n"), mmu_finda);
 			//printf_P(PSTR("Eact: %d\n"), int(e_active()));
 			if (!mmu_finda && CHECK_FSENSOR && fsensor_enabled) {
-				fsensor_stop_and_save_print();
-				enquecommand_front_P(PSTR("PRUSA fsensor_recover")); //then recover
+				fsensor_checkpoint_print();
 				ad_markDepleted(mmu_extruder);
 				if (lcd_autoDepleteEnabled() && !ad_allDepleted())
 				{
@@ -1355,7 +1357,7 @@ void lcd_mmu_load_to_nozzle(uint8_t filament_nr)
         manage_response(true, true, MMU_TCODE_MOVE);
         mmu_continue_loading(false);
         mmu_extruder = tmp_extruder; //filament change is finished
-        marlin_rise_z();
+        raise_z_above(MIN_Z_FOR_LOAD, false);
         mmu_load_to_nozzle();
         load_filament_final_feed();
         st_synchronize();
@@ -1545,7 +1547,7 @@ void mmu_continue_loading(bool blocking)
     };
     Ls state = Ls::Enter;
 
-    const uint_least8_t max_retry = 2;
+    const uint_least8_t max_retry = 3;
     uint_least8_t retry = 0;
 
     while (!success)
@@ -1556,34 +1558,27 @@ void mmu_continue_loading(bool blocking)
             increment_load_fail();
             // no break
         case Ls::Retry:
-#ifdef MMU_HAS_CUTTER
-            if (1 == eeprom_read_byte((uint8_t*)EEPROM_MMU_CUTTER_ENABLED))
+            ++retry; // overflow not handled, as it is not dangerous.
+            if (retry >= max_retry)
             {
-                mmu_command(MmuCmd::K0 + tmp_extruder);
-                manage_response(true, true, MMU_UNLOAD_MOVE);
-            }
+                state = Ls::Unload;
+#ifdef MMU_HAS_CUTTER
+                if (1 == eeprom_read_byte((uint8_t*)EEPROM_MMU_CUTTER_ENABLED))
+                {
+                    mmu_command(MmuCmd::K0 + tmp_extruder);
+                    manage_response(true, true, MMU_UNLOAD_MOVE);
+                }
 #endif //MMU_HAS_CUTTER
+            }
             mmu_command(MmuCmd::T0 + tmp_extruder);
             manage_response(true, true, MMU_TCODE_MOVE);
             success = load_more();
             if (success) success = can_load();
-            ++retry; // overflow not handled, as it is not dangerous.
-            if (retry >= max_retry) state = Ls::Unload;
+
             break;
         case Ls::Unload:
             stop_and_save_print_to_ram(0, 0);
-
-            //lift z
-            current_position[Z_AXIS] += Z_PAUSE_LIFT;
-            if (current_position[Z_AXIS] > Z_MAX_POS) current_position[Z_AXIS] = Z_MAX_POS;
-            plan_buffer_line_curposXYZE(15, active_extruder);
-            st_synchronize();
-
-            //Move XY to side
-            current_position[X_AXIS] = X_PAUSE_POS;
-            current_position[Y_AXIS] = Y_PAUSE_POS;
-            plan_buffer_line_curposXYZE(50, active_extruder);
-            st_synchronize();
+            long_pause();
 
             mmu_command(MmuCmd::U0);
             manage_response(false, true, MMU_UNLOAD_MOVE);
@@ -1594,6 +1589,7 @@ void mmu_continue_loading(bool blocking)
             if (blocking)
             {
                 marlin_wait_for_click();
+                st_synchronize();
                 restore_print_from_ram_and_continue(0);
                 state = Ls::Retry;
             }

+ 1 - 0
Firmware/mmu.h

@@ -14,6 +14,7 @@ extern uint8_t mmu_extruder;
 extern uint8_t tmp_extruder;
 
 extern int8_t mmu_finda;
+extern uint32_t mmu_last_finda_response;
 extern bool ir_sensor_detected;
 
 extern int16_t mmu_version;

+ 2 - 2
Firmware/optiboot_w25x20cl.cpp

@@ -258,11 +258,11 @@ void optiboot_w25x20cl_enter()
         uint32_t addr = (((uint32_t)rampz) << 16) | address;
         // During a single bootloader run, only erase a 64kB block once.
         // An 8bit bitmask 'pages_erased' covers 512kB of FLASH memory.
-        if (address == 0 && (pages_erased & (1 << addr)) == 0) {
+        if ((address == 0) && (pages_erased & (1 << (addr >> 16))) == 0) {
           w25x20cl_wait_busy();
           w25x20cl_enable_wr();
           w25x20cl_block64_erase(addr);
-          pages_erased |= (1 << addr);
+          pages_erased |= (1 << (addr >> 16));
         }
         w25x20cl_wait_busy();
         w25x20cl_enable_wr();

+ 3 - 2
Firmware/pins_Einsy_1_0.h

@@ -71,12 +71,13 @@
 #define HEATER_2_PIN        -1
 #define TEMP_2_PIN          -1
 
-#define TEMP_AMBIENT_PIN     5 //A5
+#define TEMP_AMBIENT_PIN     6 //A6
 
 #define TEMP_PINDA_PIN       3 //A3
 
 #define VOLT_PWR_PIN         4 //A4
 #define VOLT_BED_PIN         9 //A9
+#define VOLT_IR_PIN          8 //A8
 
 
 #define E0_TMC2130_CS       66
@@ -99,7 +100,7 @@
 
 //#define KILL_PIN            32
 
-//#define LCD_BL_PIN          5   //backlight control pin
+#define LCD_BL_PIN          5   //backlight control pin
 #define BEEPER              84  // Beeper on AUX-4
 #define LCD_PINS_RS         82
 #define LCD_PINS_ENABLE     61 // !!! changed from 18 (EINY03)

+ 170 - 70
Firmware/planner.cpp

@@ -126,11 +126,14 @@ float extrude_min_temp=EXTRUDE_MINTEMP;
 #endif
 
 #ifdef LIN_ADVANCE
-    float extruder_advance_k = LIN_ADVANCE_K,
-    advance_ed_ratio = LIN_ADVANCE_E_D_RATIO,
-    position_float[NUM_AXIS] = { 0 };
+float extruder_advance_K = LIN_ADVANCE_K;
+float position_float[NUM_AXIS];
 #endif
 
+// Request the next block to start at zero E count
+static bool plan_reset_next_e_queue;
+static bool plan_reset_next_e_sched;
+
 // Returns the index of the next block in the ring buffer
 // NOTE: Removed modulo (%) operator, which uses an expensive divide and multiplication.
 static inline int8_t next_block_index(int8_t block_index) {
@@ -262,6 +265,13 @@ void calculate_trapezoid_for_block(block_t *block, float entry_speed, float exit
     }
   }
 
+#ifdef LIN_ADVANCE
+  uint16_t final_adv_steps = 0;
+  if (block->use_advance_lead) {
+      final_adv_steps = exit_speed * block->adv_comp;
+  }
+#endif
+
   CRITICAL_SECTION_START;  // Fill variables used by the stepper in a critical section
   // This block locks the interrupts globally for 4.38 us,
   // which corresponds to a maximum repeat frequency of 228.57 kHz.
@@ -272,6 +282,9 @@ void calculate_trapezoid_for_block(block_t *block, float entry_speed, float exit
     block->decelerate_after = accelerate_steps+plateau_steps;
     block->initial_rate = initial_rate;
     block->final_rate = final_rate;
+#ifdef LIN_ADVANCE
+    block->final_adv_steps = final_adv_steps;
+#endif
   }
   CRITICAL_SECTION_END;
 }
@@ -424,14 +437,16 @@ void plan_init() {
   block_buffer_head = 0;
   block_buffer_tail = 0;
   memset(position, 0, sizeof(position)); // clear position
-#ifdef LIN_ADVANCE
-  memset(position_float, 0, sizeof(position)); // clear position
-#endif
+  #ifdef LIN_ADVANCE
+  memset(position_float, 0, sizeof(position_float)); // clear position
+  #endif
   previous_speed[0] = 0.0;
   previous_speed[1] = 0.0;
   previous_speed[2] = 0.0;
   previous_speed[3] = 0.0;
   previous_nominal_speed = 0.0;
+  plan_reset_next_e_queue = false;
+  plan_reset_next_e_sched = false;
 }
 
 
@@ -639,7 +654,9 @@ void planner_abort_hard()
     // Apply inverse world correction matrix.
     machine2world(current_position[X_AXIS], current_position[Y_AXIS]);
     memcpy(destination, current_position, sizeof(destination));
-
+#ifdef LIN_ADVANCE
+    memcpy(position_float, current_position, sizeof(position_float));
+#endif
     // Resets planner junction speeds. Assumes start from rest.
     previous_nominal_speed = 0.0;
     previous_speed[0] = 0.0;
@@ -647,6 +664,9 @@ void planner_abort_hard()
     previous_speed[2] = 0.0;
     previous_speed[3] = 0.0;
 
+    plan_reset_next_e_queue = false;
+    plan_reset_next_e_sched = false;
+
     // Relay to planner wait routine, that the current line shall be canceled.
     waiting_inside_plan_buffer_line_print_aborted = true;
 }
@@ -659,15 +679,15 @@ float junction_deviation = 0.1;
 // Add a new linear movement to the buffer. steps_x, _y and _z is the absolute position in 
 // mm. Microseconds specify how many microseconds the move should take to perform. To aid acceleration
 // calculation the caller must also provide the physical length of the line in millimeters.
-void plan_buffer_line(float x, float y, float z, const float &e, float feed_rate, uint8_t extruder)
+void plan_buffer_line(float x, float y, float z, const float &e, float feed_rate, uint8_t extruder, const float* gcode_target)
 {
     // Calculate the buffer head after we push this byte
   int next_buffer_head = next_block_index(block_buffer_head);
 
   // If the buffer is full: good! That means we are well ahead of the robot. 
   // Rest here until there is room in the buffer.
+  waiting_inside_plan_buffer_line_print_aborted = false;
   if (block_buffer_tail == next_buffer_head) {
-      waiting_inside_plan_buffer_line_print_aborted = false;
       do {
           manage_heater(); 
           // Vojtech: Don't disable motors inside the planner!
@@ -687,6 +707,43 @@ void plan_buffer_line(float x, float y, float z, const float &e, float feed_rate
   planner_update_queue_min_counter();
 #endif /* PLANNER_DIAGNOSTICS */
 
+  // Prepare to set up new block
+  block_t *block = &block_buffer[block_buffer_head];
+
+  // Mark block as not busy (Not executed by the stepper interrupt, could be still tinkered with.)
+  block->busy = false;
+
+  // Set sdlen for calculating sd position
+  block->sdlen = 0;
+
+  // Save original destination of the move
+  if (gcode_target)
+      memcpy(block->gcode_target, gcode_target, sizeof(block_t::gcode_target));
+  else
+  {
+      block->gcode_target[X_AXIS] = x;
+      block->gcode_target[Y_AXIS] = y;
+      block->gcode_target[Z_AXIS] = z;
+      block->gcode_target[E_AXIS] = e;
+  }
+
+  // Save the global feedrate at scheduling time
+  block->gcode_feedrate = feedrate;
+
+  // Reset the starting E position when requested
+  if (plan_reset_next_e_queue)
+  {
+      position[E_AXIS] = 0;
+#ifdef LIN_ADVANCE
+      position_float[E_AXIS] = 0;
+#endif
+
+      // the block might still be discarded later, but we need to ensure the lower-level
+      // count_position is also reset correctly for consistent results!
+      plan_reset_next_e_queue = false;
+      plan_reset_next_e_sched = true;
+  }
+
 #ifdef ENABLE_AUTO_BED_LEVELING
   apply_rotation_xyz(plan_bed_level_matrix, x, y, z);
 #endif // ENABLE_AUTO_BED_LEVELING
@@ -752,21 +809,15 @@ void plan_buffer_line(float x, float y, float z, const float &e, float feed_rate
 #endif // ENABLE_MESH_BED_LEVELING
   target[E_AXIS] = lround(e*cs.axis_steps_per_unit[E_AXIS]);
   
-#ifdef LIN_ADVANCE
-    const float mm_D_float = sqrt(sq(x - position_float[X_AXIS]) + sq(y - position_float[Y_AXIS]));
-    float de_float = e - position_float[E_AXIS];
-#endif
-    
   #ifdef PREVENT_DANGEROUS_EXTRUDE
   if(target[E_AXIS]!=position[E_AXIS])
   {
     if(degHotend(active_extruder)<extrude_min_temp)
     {
       position[E_AXIS]=target[E_AXIS]; //behave as if the move really took place, but ignore E part
-#ifdef LIN_ADVANCE
+      #ifdef LIN_ADVANCE
       position_float[E_AXIS] = e;
-      de_float = 0;
-#endif
+      #endif
       SERIAL_ECHO_START;
       SERIAL_ECHOLNRPGM(_n(" cold extrusion prevented"));////MSG_ERR_COLD_EXTRUDE_STOP
     }
@@ -775,10 +826,9 @@ void plan_buffer_line(float x, float y, float z, const float &e, float feed_rate
     if(labs(target[E_AXIS]-position[E_AXIS])>cs.axis_steps_per_unit[E_AXIS]*EXTRUDE_MAXLENGTH)
     {
       position[E_AXIS]=target[E_AXIS]; //behave as if the move really took place, but ignore E part
-#ifdef LIN_ADVANCE
-        position_float[E_AXIS] = e;
-        de_float = 0;
-#endif
+      #ifdef LIN_ADVANCE
+      position_float[E_AXIS] = e;
+      #endif
       SERIAL_ECHO_START;
       SERIAL_ECHOLNRPGM(_n(" too long extrusion prevented"));////MSG_ERR_LONG_EXTRUDE_STOP
     }
@@ -786,15 +836,6 @@ void plan_buffer_line(float x, float y, float z, const float &e, float feed_rate
   }
   #endif
 
-  // Prepare to set up new block
-  block_t *block = &block_buffer[block_buffer_head];
-
-  // Set sdlen for calculating sd position
-  block->sdlen = 0;
-
-  // Mark block as not busy (Not executed by the stepper interrupt, could be still tinkered with.)
-  block->busy = false;
-
   // Number of steps for each axis
 #ifndef COREXY
 // default non-h-bot planning
@@ -998,6 +1039,9 @@ Having the real displacement of the head, we can calculate the total movement le
     block->nominal_rate *= speed_factor;
   }
 
+#ifdef LIN_ADVANCE
+  float e_D_ratio = 0;
+#endif
   // Compute and limit the acceleration rate for the trapezoid generator.  
   // block->step_event_count ... event count of the fastest axis
   // block->millimeters ... Euclidian length of the XYZ movement or the E length, if no XYZ movement.
@@ -1005,10 +1049,51 @@ Having the real displacement of the head, we can calculate the total movement le
   if(block->steps_x.wide == 0 && block->steps_y.wide == 0 && block->steps_z.wide == 0)
   {
     block->acceleration_st = ceil(cs.retract_acceleration * steps_per_mm); // convert to: acceleration steps/sec^2
+    #ifdef LIN_ADVANCE
+    block->use_advance_lead = false;
+    #endif
   }
   else
   {
     block->acceleration_st = ceil(cs.acceleration * steps_per_mm); // convert to: acceleration steps/sec^2
+
+    #ifdef LIN_ADVANCE
+    /**
+     * Use LIN_ADVANCE within this block if all these are true:
+     *
+     * block->steps_e           : This is a print move, because we checked for X, Y, Z steps before.
+     * extruder_advance_K       : There is an advance factor set.
+     * delta_mm[E_AXIS] > 0     : Extruder is running forward (e.g., for "Wipe while retracting" (Slic3r) or "Combing" (Cura) moves)
+     * |delta_mm[Z_AXIS]| < 0.5 : Z is only moved for leveling (_not_ for priming)
+     */
+    block->use_advance_lead = block->steps_e.wide
+                              && extruder_advance_K
+                              && delta_mm[E_AXIS] > 0
+                              && abs(delta_mm[Z_AXIS]) < 0.5;
+    if (block->use_advance_lead) {
+        e_D_ratio = (e - position_float[E_AXIS]) /
+                    sqrt(sq(x - position_float[X_AXIS])
+                         + sq(y - position_float[Y_AXIS])
+                         + sq(z - position_float[Z_AXIS]));
+
+        // Check for unusual high e_D ratio to detect if a retract move was combined with the last
+        // print move due to min. steps per segment. Never execute this with advance! This assumes
+        // no one will use a retract length of 0mm < retr_length < ~0.2mm and no one will print
+        // 100mm wide lines using 3mm filament or 35mm wide lines using 1.75mm filament.
+        if (e_D_ratio > 3.0)
+            block->use_advance_lead = false;
+        else {
+            const uint32_t max_accel_steps_per_s2 = cs.max_jerk[E_AXIS] / (extruder_advance_K * e_D_ratio) * steps_per_mm;
+            if (block->acceleration_st > max_accel_steps_per_s2) {
+                block->acceleration_st = max_accel_steps_per_s2;
+                #ifdef LA_DEBUG
+                SERIAL_ECHOLNPGM("LA: Block acceleration limited due to max E-jerk");
+                #endif
+            }
+        }
+    }
+    #endif
+
     // Limit acceleration per axis
     //FIXME Vojtech: One shall rather limit a projection of the acceleration vector instead of using the limit.
     if(((float)block->acceleration_st * (float)block->steps_x.wide / (float)block->step_event_count.wide) > axis_steps_per_sqr_second[X_AXIS])
@@ -1041,6 +1126,40 @@ Having the real displacement of the head, we can calculate the total movement le
 
   block->acceleration_rate = (long)((float)block->acceleration_st * (16777216.0 / (F_CPU / 8.0)));
 
+#ifdef LIN_ADVANCE
+  if (block->use_advance_lead) {
+      // the nominal speed doesn't change past this point: calculate the compression ratio for the
+      // segment and the required advance steps
+      block->adv_comp = extruder_advance_K * e_D_ratio * cs.axis_steps_per_unit[E_AXIS];
+      block->max_adv_steps = block->nominal_speed * block->adv_comp;
+
+      // to save more space we avoid another copy of calc_timer and go through slow division, but we
+      // still need to replicate the *exact* same step grouping policy (see below)
+      float advance_speed = (extruder_advance_K * e_D_ratio * block->acceleration * cs.axis_steps_per_unit[E_AXIS]);
+      if (advance_speed > MAX_STEP_FREQUENCY) advance_speed = MAX_STEP_FREQUENCY;
+      block->advance_rate = (F_CPU / 8.0) / advance_speed;
+      if (block->advance_rate > 20000) {
+          block->advance_rate = (block->advance_rate >> 2)&0x3fff;
+          block->advance_step_loops = 4;
+      }
+      else if (block->advance_rate > 10000) {
+          block->advance_rate = (block->advance_rate >> 1)&0x7fff;
+          block->advance_step_loops = 2;
+      }
+      else
+          block->advance_step_loops = 1;
+
+      #ifdef LA_DEBUG
+      if (block->advance_step_loops > 2)
+          // @wavexx: we should really check for the difference between step_loops and
+          //          advance_step_loops instead. A difference of more than 1 will lead
+          //          to uneven speed and *should* be adjusted here by furthermore
+          //          reducing the speed.
+          SERIAL_ECHOLNPGM("LA: More than 2 steps per eISR loop executed.");
+      #endif
+  }
+#endif
+
   // Start with a safe speed.
   // Safe speed is the speed, from which the machine may halt to stop immediately.
   float safe_speed = block->nominal_speed;
@@ -1069,6 +1188,13 @@ Having the real displacement of the head, we can calculate the total movement le
   // Reset the block flag.
   block->flag = 0;
 
+  if (plan_reset_next_e_sched)
+  {
+      // finally propagate a pending reset
+      block->flag |= BLOCK_FLAG_E_RESET;
+      plan_reset_next_e_sched = false;
+  }
+
   // Initial limit on the segment entry velocity.
   float vmax_junction;
 
@@ -1157,37 +1283,6 @@ Having the real displacement of the head, we can calculate the total movement le
   previous_nominal_speed = block->nominal_speed;
   previous_safe_speed = safe_speed;
 
-#ifdef LIN_ADVANCE
-
-    //
-    // Use LIN_ADVANCE for blocks if all these are true:
-    //
-    // esteps                                          : We have E steps todo (a printing move)
-    //
-    // block->steps[X_AXIS] || block->steps[Y_AXIS]    : We have a movement in XY direction (i.e., not retract / prime).
-    //
-    // extruder_advance_k                              : There is an advance factor set.
-    //
-    // block->steps[E_AXIS] != block->step_event_count : A problem occurs if the move before a retract is too small.
-    //                                                   In that case, the retract and move will be executed together.
-    //                                                   This leads to too many advance steps due to a huge e_acceleration.
-    //                                                   The math is good, but we must avoid retract moves with advance!
-    // de_float > 0.0                                  : Extruder is running forward (e.g., for "Wipe while retracting" (Slic3r) or "Combing" (Cura) moves)
-    //
-    block->use_advance_lead =  block->steps_e.wide
-                           && (block->steps_x.wide || block->steps_y.wide)
-                           && extruder_advance_k
-                           && (uint32_t)block->steps_e.wide != block->step_event_count.wide
-                           && de_float > 0.0;
-    if (block->use_advance_lead)
-        block->abs_adv_steps_multiplier8 = lround(
-                          extruder_advance_k
-                          * ((advance_ed_ratio < 0.000001) ? de_float / mm_D_float : advance_ed_ratio) // Use the fixed ratio, if set
-                          * (block->nominal_speed / (float)block->nominal_rate)
-                          * cs.axis_steps_per_unit[E_AXIS] * 256.0
-                          );
-#endif
-    
   // Precalculate the division, so when all the trapezoids in the planner queue get recalculated, the division is not repeated.
   block->speed_factor = block->nominal_rate / block->nominal_speed;
   calculate_trapezoid_for_block(block, block->entry_speed, safe_speed);
@@ -1201,12 +1296,12 @@ Having the real displacement of the head, we can calculate the total movement le
   // Update position
   memcpy(position, target, sizeof(target)); // position[] = target[]
 
-#ifdef LIN_ADVANCE
+  #ifdef LIN_ADVANCE
   position_float[X_AXIS] = x;
   position_float[Y_AXIS] = y;
   position_float[Z_AXIS] = z;
   position_float[E_AXIS] = e;
-#endif
+  #endif
     
   // Recalculate the trapezoids to maximize speed at the segment transitions while respecting
   // the machine limits (maximum acceleration and maximum jerk).
@@ -1269,12 +1364,12 @@ void plan_set_position(float x, float y, float z, const float &e)
   position[Z_AXIS] = lround(z*cs.axis_steps_per_unit[Z_AXIS]);
 #endif // ENABLE_MESH_BED_LEVELING
   position[E_AXIS] = lround(e*cs.axis_steps_per_unit[E_AXIS]);
-#ifdef LIN_ADVANCE
+  #ifdef LIN_ADVANCE
   position_float[X_AXIS] = x;
   position_float[Y_AXIS] = y;
   position_float[Z_AXIS] = z;
   position_float[E_AXIS] = e;
-#endif
+  #endif
   st_set_position(position[X_AXIS], position[Y_AXIS], position[Z_AXIS], position[E_AXIS]);
   previous_nominal_speed = 0.0; // Resets planner junction speeds. Assumes start from rest.
   previous_speed[0] = 0.0;
@@ -1286,11 +1381,11 @@ void plan_set_position(float x, float y, float z, const float &e)
 // Only useful in the bed leveling routine, when the mesh bed leveling is off.
 void plan_set_z_position(const float &z)
 {
-	#ifdef LIN_ADVANCE
-	position_float[Z_AXIS] = z;
-	#endif
-    position[Z_AXIS] = lround(z*cs.axis_steps_per_unit[Z_AXIS]);
-    st_set_position(position[X_AXIS], position[Y_AXIS], position[Z_AXIS], position[E_AXIS]);
+  #ifdef LIN_ADVANCE
+  position_float[Z_AXIS] = z;
+  #endif
+  position[Z_AXIS] = lround(z*cs.axis_steps_per_unit[Z_AXIS]);
+  st_set_position(position[X_AXIS], position[Y_AXIS], position[Z_AXIS], position[E_AXIS]);
 }
 
 void plan_set_e_position(const float &e)
@@ -1302,6 +1397,11 @@ void plan_set_e_position(const float &e)
   st_set_e_position(position[E_AXIS]);
 }
 
+void plan_reset_next_e()
+{
+    plan_reset_next_e_queue = true;
+}
+
 #ifdef PREVENT_DANGEROUS_EXTRUDE
 void set_extrude_min_temp(float temp)
 {

+ 19 - 6
Firmware/planner.h

@@ -44,6 +44,8 @@ enum BlockFlag {
     // than 32767, therefore the DDA algorithm may run with 16bit resolution only.
     // In addition, the stepper routine will not do any end stop checking for higher performance.
     BLOCK_FLAG_DDA_LOWRES = 8,
+    // Block starts with Zeroed E counter
+    BLOCK_FLAG_E_RESET = 16,
 };
 
 union dda_isteps_t
@@ -110,17 +112,24 @@ typedef struct {
 
   // Pre-calculated division for the calculate_trapezoid_for_block() routine to run faster.
   float speed_factor;
-    
+
 #ifdef LIN_ADVANCE
-  bool use_advance_lead;
-  unsigned long abs_adv_steps_multiplier8; // Factorised by 2^8 to avoid float
+  bool use_advance_lead;            // Whether the current block uses LA
+  uint16_t advance_rate,            // Step-rate for extruder speed
+           max_adv_steps,           // max. advance steps to get cruising speed pressure (not always nominal_speed!)
+           final_adv_steps;         // advance steps due to exit speed
+  uint8_t advance_step_loops;       // Number of stepper ticks for each advance isr
+  float adv_comp;                   // Precomputed E compression factor
 #endif
 
-  uint16_t sdlen;
+  // Save/recovery state data
+  float gcode_target[NUM_AXIS];     // Target (abs mm) of the original Gcode instruction
+  uint16_t gcode_feedrate;          // Default and/or move feedrate
+  uint16_t sdlen;                   // Length of the Gcode instruction
 } block_t;
 
 #ifdef LIN_ADVANCE
-  extern float extruder_advance_k, advance_ed_ratio;
+extern float extruder_advance_K;    // Linear-advance K factor
 #endif
 
 #ifdef ENABLE_AUTO_BED_LEVELING
@@ -147,7 +156,7 @@ vector_3 plan_get_position();
 /// The performance penalty is negligible, since these planned lines are usually maintenance moves with the extruder.
 void plan_buffer_line_curposXYZE(float feed_rate, uint8_t extruder);
 
-void plan_buffer_line(float x, float y, float z, const float &e, float feed_rate, uint8_t extruder);
+void plan_buffer_line(float x, float y, float z, const float &e, float feed_rate, uint8_t extruder, const float* gcode_target = NULL);
 //void plan_buffer_line(const float &x, const float &y, const float &z, const float &e, float feed_rate, const uint8_t &extruder);
 #endif // ENABLE_AUTO_BED_LEVELING
 
@@ -161,6 +170,9 @@ void plan_set_position(float x, float y, float z, const float &e);
 void plan_set_z_position(const float &z);
 void plan_set_e_position(const float &e);
 
+// Reset the E position to zero at the start of the next segment
+void plan_reset_next_e();
+
 inline void set_current_to_destination() { memcpy(current_position, destination, sizeof(current_position)); }
 inline void set_destination_to_current() { memcpy(destination, current_position, sizeof(destination)); }
 
@@ -241,6 +253,7 @@ FORCE_INLINE bool planner_queue_full() {
 // wait for the steppers to stop,
 // update planner's current position and the current_position of the front end.
 extern void planner_abort_hard();
+extern bool waiting_inside_plan_buffer_line_print_aborted;
 
 #ifdef PREVENT_DANGEROUS_EXTRUDE
 void set_extrude_min_temp(float temp);

+ 7 - 0
Firmware/sound.cpp

@@ -5,6 +5,7 @@
 //#include <inttypes.h>
 //#include <avr/eeprom.h>
 //#include "eeprom.h"
+#include "backlight.h"
 
 
 //eSOUND_MODE eSoundMode=e_SOUND_MODE_LOUD;
@@ -63,6 +64,7 @@ Sound_SaveMode();
 
 //if critical is true then silend and once mode is ignored
 void Sound_MakeCustom(uint16_t ms,uint16_t tone_,bool critical){
+    backlight_wake();
      if (!critical){
           if (eSoundMode != e_SOUND_MODE_SILENT){
                if(!tone_){
@@ -135,6 +137,7 @@ switch(eSoundMode)
 
 static void Sound_DoSound_Blind_Alert(void)
 {
+    backlight_wake(1);
      uint8_t nI;
 
      for(nI=0; nI<20; nI++)
@@ -148,6 +151,7 @@ static void Sound_DoSound_Blind_Alert(void)
 
  static void Sound_DoSound_Encoder_Move(void)
 {
+    backlight_wake();
 uint8_t nI;
 
  for(nI=0;nI<5;nI++)
@@ -161,6 +165,7 @@ uint8_t nI;
 
 static void Sound_DoSound_Echo(void)
 {
+    backlight_wake();
 uint8_t nI;
 
 for(nI=0;nI<10;nI++)
@@ -174,6 +179,7 @@ for(nI=0;nI<10;nI++)
 
 static void Sound_DoSound_Prompt(void)
 {
+    backlight_wake(2);
 WRITE(BEEPER,HIGH);
 _delay_ms(500);
 WRITE(BEEPER,LOW);
@@ -181,6 +187,7 @@ WRITE(BEEPER,LOW);
 
 static void Sound_DoSound_Alert(bool bOnce)
 {
+    backlight_wake();
 uint8_t nI,nMax;
 
 nMax=bOnce?1:3;

+ 0 - 6
Firmware/sound.h

@@ -3,12 +3,6 @@
 #define SOUND_H
 
 
-#define MSG_SOUND_MODE_LOUD   "Sound      [loud]"
-#define MSG_SOUND_MODE_ONCE   "Sound      [once]"
-#define MSG_SOUND_MODE_SILENT "Sound    [silent]"
-#define MSG_SOUND_MODE_BLIND  "Sound    [assist]" 
-
-
 #define e_SOUND_MODE_NULL 0xFF
 typedef enum
      {e_SOUND_MODE_LOUD,e_SOUND_MODE_ONCE,e_SOUND_MODE_SILENT,e_SOUND_MODE_BLIND} eSOUND_MODE;

+ 147 - 0
Firmware/speed_lookuptable.cpp

@@ -0,0 +1,147 @@
+#include "speed_lookuptable.h"
+
+#if F_CPU == 16000000
+
+const uint16_t speed_lookuptable_fast[256][2] PROGMEM = {\
+{ 62500, 55556}, { 6944, 3268}, { 3676, 1176}, { 2500, 607}, { 1893, 369}, { 1524, 249}, { 1275, 179}, { 1096, 135}, 
+{ 961, 105}, { 856, 85}, { 771, 69}, { 702, 58}, { 644, 49}, { 595, 42}, { 553, 37}, { 516, 32}, 
+{ 484, 28}, { 456, 25}, { 431, 23}, { 408, 20}, { 388, 19}, { 369, 16}, { 353, 16}, { 337, 14}, 
+{ 323, 13}, { 310, 11}, { 299, 11}, { 288, 11}, { 277, 9}, { 268, 9}, { 259, 8}, { 251, 8}, 
+{ 243, 8}, { 235, 7}, { 228, 6}, { 222, 6}, { 216, 6}, { 210, 6}, { 204, 5}, { 199, 5}, 
+{ 194, 5}, { 189, 4}, { 185, 4}, { 181, 4}, { 177, 4}, { 173, 4}, { 169, 4}, { 165, 3}, 
+{ 162, 3}, { 159, 4}, { 155, 3}, { 152, 3}, { 149, 2}, { 147, 3}, { 144, 3}, { 141, 2}, 
+{ 139, 3}, { 136, 2}, { 134, 2}, { 132, 3}, { 129, 2}, { 127, 2}, { 125, 2}, { 123, 2}, 
+{ 121, 2}, { 119, 1}, { 118, 2}, { 116, 2}, { 114, 1}, { 113, 2}, { 111, 2}, { 109, 1}, 
+{ 108, 2}, { 106, 1}, { 105, 2}, { 103, 1}, { 102, 1}, { 101, 1}, { 100, 2}, { 98, 1}, 
+{ 97, 1}, { 96, 1}, { 95, 2}, { 93, 1}, { 92, 1}, { 91, 1}, { 90, 1}, { 89, 1}, 
+{ 88, 1}, { 87, 1}, { 86, 1}, { 85, 1}, { 84, 1}, { 83, 0}, { 83, 1}, { 82, 1}, 
+{ 81, 1}, { 80, 1}, { 79, 1}, { 78, 0}, { 78, 1}, { 77, 1}, { 76, 1}, { 75, 0}, 
+{ 75, 1}, { 74, 1}, { 73, 1}, { 72, 0}, { 72, 1}, { 71, 1}, { 70, 0}, { 70, 1}, 
+{ 69, 0}, { 69, 1}, { 68, 1}, { 67, 0}, { 67, 1}, { 66, 0}, { 66, 1}, { 65, 0}, 
+{ 65, 1}, { 64, 1}, { 63, 0}, { 63, 1}, { 62, 0}, { 62, 1}, { 61, 0}, { 61, 1}, 
+{ 60, 0}, { 60, 0}, { 60, 1}, { 59, 0}, { 59, 1}, { 58, 0}, { 58, 1}, { 57, 0}, 
+{ 57, 1}, { 56, 0}, { 56, 0}, { 56, 1}, { 55, 0}, { 55, 1}, { 54, 0}, { 54, 0}, 
+{ 54, 1}, { 53, 0}, { 53, 0}, { 53, 1}, { 52, 0}, { 52, 0}, { 52, 1}, { 51, 0}, 
+{ 51, 0}, { 51, 1}, { 50, 0}, { 50, 0}, { 50, 1}, { 49, 0}, { 49, 0}, { 49, 1}, 
+{ 48, 0}, { 48, 0}, { 48, 1}, { 47, 0}, { 47, 0}, { 47, 0}, { 47, 1}, { 46, 0}, 
+{ 46, 0}, { 46, 1}, { 45, 0}, { 45, 0}, { 45, 0}, { 45, 1}, { 44, 0}, { 44, 0}, 
+{ 44, 0}, { 44, 1}, { 43, 0}, { 43, 0}, { 43, 0}, { 43, 1}, { 42, 0}, { 42, 0}, 
+{ 42, 0}, { 42, 1}, { 41, 0}, { 41, 0}, { 41, 0}, { 41, 0}, { 41, 1}, { 40, 0}, 
+{ 40, 0}, { 40, 0}, { 40, 0}, { 40, 1}, { 39, 0}, { 39, 0}, { 39, 0}, { 39, 0}, 
+{ 39, 1}, { 38, 0}, { 38, 0}, { 38, 0}, { 38, 0}, { 38, 1}, { 37, 0}, { 37, 0}, 
+{ 37, 0}, { 37, 0}, { 37, 0}, { 37, 1}, { 36, 0}, { 36, 0}, { 36, 0}, { 36, 0}, 
+{ 36, 1}, { 35, 0}, { 35, 0}, { 35, 0}, { 35, 0}, { 35, 0}, { 35, 0}, { 35, 1}, 
+{ 34, 0}, { 34, 0}, { 34, 0}, { 34, 0}, { 34, 0}, { 34, 1}, { 33, 0}, { 33, 0}, 
+{ 33, 0}, { 33, 0}, { 33, 0}, { 33, 0}, { 33, 1}, { 32, 0}, { 32, 0}, { 32, 0}, 
+{ 32, 0}, { 32, 0}, { 32, 0}, { 32, 0}, { 32, 1}, { 31, 0}, { 31, 0}, { 31, 0}, 
+{ 31, 0}, { 31, 0}, { 31, 0}, { 31, 1}, { 30, 0}, { 30, 0}, { 30, 0}, { 30, 0}
+};
+
+const uint16_t speed_lookuptable_slow[256][2] PROGMEM = {\
+{ 62500, 12500}, { 50000, 8334}, { 41666, 5952}, { 35714, 4464}, { 31250, 3473}, { 27777, 2777}, { 25000, 2273}, { 22727, 1894}, 
+{ 20833, 1603}, { 19230, 1373}, { 17857, 1191}, { 16666, 1041}, { 15625, 920}, { 14705, 817}, { 13888, 731}, { 13157, 657}, 
+{ 12500, 596}, { 11904, 541}, { 11363, 494}, { 10869, 453}, { 10416, 416}, { 10000, 385}, { 9615, 356}, { 9259, 331}, 
+{ 8928, 308}, { 8620, 287}, { 8333, 269}, { 8064, 252}, { 7812, 237}, { 7575, 223}, { 7352, 210}, { 7142, 198}, 
+{ 6944, 188}, { 6756, 178}, { 6578, 168}, { 6410, 160}, { 6250, 153}, { 6097, 145}, { 5952, 139}, { 5813, 132}, 
+{ 5681, 126}, { 5555, 121}, { 5434, 115}, { 5319, 111}, { 5208, 106}, { 5102, 102}, { 5000, 99}, { 4901, 94}, 
+{ 4807, 91}, { 4716, 87}, { 4629, 84}, { 4545, 81}, { 4464, 79}, { 4385, 75}, { 4310, 73}, { 4237, 71}, 
+{ 4166, 68}, { 4098, 66}, { 4032, 64}, { 3968, 62}, { 3906, 60}, { 3846, 59}, { 3787, 56}, { 3731, 55}, 
+{ 3676, 53}, { 3623, 52}, { 3571, 50}, { 3521, 49}, { 3472, 48}, { 3424, 46}, { 3378, 45}, { 3333, 44}, 
+{ 3289, 43}, { 3246, 41}, { 3205, 41}, { 3164, 39}, { 3125, 39}, { 3086, 38}, { 3048, 36}, { 3012, 36}, 
+{ 2976, 35}, { 2941, 35}, { 2906, 33}, { 2873, 33}, { 2840, 32}, { 2808, 31}, { 2777, 30}, { 2747, 30}, 
+{ 2717, 29}, { 2688, 29}, { 2659, 28}, { 2631, 27}, { 2604, 27}, { 2577, 26}, { 2551, 26}, { 2525, 25}, 
+{ 2500, 25}, { 2475, 25}, { 2450, 23}, { 2427, 24}, { 2403, 23}, { 2380, 22}, { 2358, 22}, { 2336, 22}, 
+{ 2314, 21}, { 2293, 21}, { 2272, 20}, { 2252, 20}, { 2232, 20}, { 2212, 20}, { 2192, 19}, { 2173, 18}, 
+{ 2155, 19}, { 2136, 18}, { 2118, 18}, { 2100, 17}, { 2083, 17}, { 2066, 17}, { 2049, 17}, { 2032, 16}, 
+{ 2016, 16}, { 2000, 16}, { 1984, 16}, { 1968, 15}, { 1953, 16}, { 1937, 14}, { 1923, 15}, { 1908, 15}, 
+{ 1893, 14}, { 1879, 14}, { 1865, 14}, { 1851, 13}, { 1838, 14}, { 1824, 13}, { 1811, 13}, { 1798, 13}, 
+{ 1785, 12}, { 1773, 13}, { 1760, 12}, { 1748, 12}, { 1736, 12}, { 1724, 12}, { 1712, 12}, { 1700, 11}, 
+{ 1689, 12}, { 1677, 11}, { 1666, 11}, { 1655, 11}, { 1644, 11}, { 1633, 10}, { 1623, 11}, { 1612, 10}, 
+{ 1602, 10}, { 1592, 10}, { 1582, 10}, { 1572, 10}, { 1562, 10}, { 1552, 9}, { 1543, 10}, { 1533, 9}, 
+{ 1524, 9}, { 1515, 9}, { 1506, 9}, { 1497, 9}, { 1488, 9}, { 1479, 9}, { 1470, 9}, { 1461, 8}, 
+{ 1453, 8}, { 1445, 9}, { 1436, 8}, { 1428, 8}, { 1420, 8}, { 1412, 8}, { 1404, 8}, { 1396, 8}, 
+{ 1388, 7}, { 1381, 8}, { 1373, 7}, { 1366, 8}, { 1358, 7}, { 1351, 7}, { 1344, 8}, { 1336, 7}, 
+{ 1329, 7}, { 1322, 7}, { 1315, 7}, { 1308, 6}, { 1302, 7}, { 1295, 7}, { 1288, 6}, { 1282, 7}, 
+{ 1275, 6}, { 1269, 7}, { 1262, 6}, { 1256, 6}, { 1250, 7}, { 1243, 6}, { 1237, 6}, { 1231, 6}, 
+{ 1225, 6}, { 1219, 6}, { 1213, 6}, { 1207, 6}, { 1201, 5}, { 1196, 6}, { 1190, 6}, { 1184, 5}, 
+{ 1179, 6}, { 1173, 5}, { 1168, 6}, { 1162, 5}, { 1157, 5}, { 1152, 6}, { 1146, 5}, { 1141, 5}, 
+{ 1136, 5}, { 1131, 5}, { 1126, 5}, { 1121, 5}, { 1116, 5}, { 1111, 5}, { 1106, 5}, { 1101, 5}, 
+{ 1096, 5}, { 1091, 5}, { 1086, 4}, { 1082, 5}, { 1077, 5}, { 1072, 4}, { 1068, 5}, { 1063, 4}, 
+{ 1059, 5}, { 1054, 4}, { 1050, 4}, { 1046, 5}, { 1041, 4}, { 1037, 4}, { 1033, 5}, { 1028, 4}, 
+{ 1024, 4}, { 1020, 4}, { 1016, 4}, { 1012, 4}, { 1008, 4}, { 1004, 4}, { 1000, 4}, { 996, 4}, 
+{ 992, 4}, { 988, 4}, { 984, 4}, { 980, 4}, { 976, 4}, { 972, 4}, { 968, 3}, { 965, 3}
+};
+
+#elif F_CPU == 20000000
+
+const uint16_t speed_lookuptable_fast[256][2] PROGMEM = {
+   {62500, 54055}, {8445, 3917}, {4528, 1434}, {3094, 745}, {2349, 456}, {1893, 307}, {1586, 222}, {1364, 167},
+   {1197, 131}, {1066, 105}, {961, 86}, {875, 72}, {803, 61}, {742, 53}, {689, 45}, {644, 40},
+   {604, 35}, {569, 32}, {537, 28}, {509, 25}, {484, 23}, {461, 21}, {440, 19}, {421, 17},
+   {404, 16}, {388, 15}, {373, 14}, {359, 13}, {346, 12}, {334, 11}, {323, 10}, {313, 10},
+   {303, 9}, {294, 9}, {285, 8}, {277, 7}, {270, 8}, {262, 7}, {255, 6}, {249, 6},
+   {243, 6}, {237, 6}, {231, 5}, {226, 5}, {221, 5}, {216, 5}, {211, 4}, {207, 5},
+   {202, 4}, {198, 4}, {194, 4}, {190, 3}, {187, 4}, {183, 3}, {180, 3}, {177, 4},
+   {173, 3}, {170, 3}, {167, 2}, {165, 3}, {162, 3}, {159, 2}, {157, 3}, {154, 2},
+   {152, 3}, {149, 2}, {147, 2}, {145, 2}, {143, 2}, {141, 2}, {139, 2}, {137, 2},
+   {135, 2}, {133, 2}, {131, 2}, {129, 1}, {128, 2}, {126, 2}, {124, 1}, {123, 2},
+   {121, 1}, {120, 2}, {118, 1}, {117, 1}, {116, 2}, {114, 1}, {113, 1}, {112, 2},
+   {110, 1}, {109, 1}, {108, 1}, {107, 2}, {105, 1}, {104, 1}, {103, 1}, {102, 1},
+   {101, 1}, {100, 1}, {99, 1}, {98, 1}, {97, 1}, {96, 1}, {95, 1}, {94, 1},
+   {93, 1}, {92, 1}, {91, 0}, {91, 1}, {90, 1}, {89, 1}, {88, 1}, {87, 0},
+   {87, 1}, {86, 1}, {85, 1}, {84, 0}, {84, 1}, {83, 1}, {82, 1}, {81, 0},
+   {81, 1}, {80, 1}, {79, 0}, {79, 1}, {78, 0}, {78, 1}, {77, 1}, {76, 0},
+   {76, 1}, {75, 0}, {75, 1}, {74, 1}, {73, 0}, {73, 1}, {72, 0}, {72, 1},
+   {71, 0}, {71, 1}, {70, 0}, {70, 1}, {69, 0}, {69, 1}, {68, 0}, {68, 1},
+   {67, 0}, {67, 1}, {66, 0}, {66, 1}, {65, 0}, {65, 0}, {65, 1}, {64, 0},
+   {64, 1}, {63, 0}, {63, 1}, {62, 0}, {62, 0}, {62, 1}, {61, 0}, {61, 1},
+   {60, 0}, {60, 0}, {60, 1}, {59, 0}, {59, 0}, {59, 1}, {58, 0}, {58, 0},
+   {58, 1}, {57, 0}, {57, 0}, {57, 1}, {56, 0}, {56, 0}, {56, 1}, {55, 0},
+   {55, 0}, {55, 1}, {54, 0}, {54, 0}, {54, 1}, {53, 0}, {53, 0}, {53, 0},
+   {53, 1}, {52, 0}, {52, 0}, {52, 1}, {51, 0}, {51, 0}, {51, 0}, {51, 1},
+   {50, 0}, {50, 0}, {50, 0}, {50, 1}, {49, 0}, {49, 0}, {49, 0}, {49, 1},
+   {48, 0}, {48, 0}, {48, 0}, {48, 1}, {47, 0}, {47, 0}, {47, 0}, {47, 1},
+   {46, 0}, {46, 0}, {46, 0}, {46, 0}, {46, 1}, {45, 0}, {45, 0}, {45, 0},
+   {45, 1}, {44, 0}, {44, 0}, {44, 0}, {44, 0}, {44, 1}, {43, 0}, {43, 0},
+   {43, 0}, {43, 0}, {43, 1}, {42, 0}, {42, 0}, {42, 0}, {42, 0}, {42, 0},
+   {42, 1}, {41, 0}, {41, 0}, {41, 0}, {41, 0}, {41, 0}, {41, 1}, {40, 0},
+   {40, 0}, {40, 0}, {40, 0}, {40, 1}, {39, 0}, {39, 0}, {39, 0}, {39, 0},
+   {39, 0}, {39, 0}, {39, 1}, {38, 0}, {38, 0}, {38, 0}, {38, 0}, {38, 0},
+};
+
+const uint16_t speed_lookuptable_slow[256][2] PROGMEM = {
+   {62500, 10417}, {52083, 7441}, {44642, 5580}, {39062, 4340}, {34722, 3472}, {31250, 2841}, {28409, 2368}, {26041, 2003},
+   {24038, 1717}, {22321, 1488}, {20833, 1302}, {19531, 1149}, {18382, 1021}, {17361, 914}, {16447, 822}, {15625, 745},
+   {14880, 676}, {14204, 618}, {13586, 566}, {13020, 520}, {12500, 481}, {12019, 445}, {11574, 414}, {11160, 385},
+   {10775, 359}, {10416, 336}, {10080, 315}, {9765, 296}, {9469, 278}, {9191, 263}, {8928, 248}, {8680, 235},
+   {8445, 222}, {8223, 211}, {8012, 200}, {7812, 191}, {7621, 181}, {7440, 173}, {7267, 165}, {7102, 158},
+   {6944, 151}, {6793, 145}, {6648, 138}, {6510, 133}, {6377, 127}, {6250, 123}, {6127, 118}, {6009, 113},
+   {5896, 109}, {5787, 106}, {5681, 101}, {5580, 98}, {5482, 95}, {5387, 91}, {5296, 88}, {5208, 86},
+   {5122, 82}, {5040, 80}, {4960, 78}, {4882, 75}, {4807, 73}, {4734, 70}, {4664, 69}, {4595, 67},
+   {4528, 64}, {4464, 63}, {4401, 61}, {4340, 60}, {4280, 58}, {4222, 56}, {4166, 55}, {4111, 53},
+   {4058, 52}, {4006, 51}, {3955, 49}, {3906, 48}, {3858, 48}, {3810, 45}, {3765, 45}, {3720, 44},
+   {3676, 43}, {3633, 42}, {3591, 40}, {3551, 40}, {3511, 39}, {3472, 38}, {3434, 38}, {3396, 36},
+   {3360, 36}, {3324, 35}, {3289, 34}, {3255, 34}, {3221, 33}, {3188, 32}, {3156, 31}, {3125, 31},
+   {3094, 31}, {3063, 30}, {3033, 29}, {3004, 28}, {2976, 28}, {2948, 28}, {2920, 27}, {2893, 27},
+   {2866, 26}, {2840, 25}, {2815, 25}, {2790, 25}, {2765, 24}, {2741, 24}, {2717, 24}, {2693, 23},
+   {2670, 22}, {2648, 22}, {2626, 22}, {2604, 22}, {2582, 21}, {2561, 21}, {2540, 20}, {2520, 20},
+   {2500, 20}, {2480, 20}, {2460, 19}, {2441, 19}, {2422, 19}, {2403, 18}, {2385, 18}, {2367, 18},
+   {2349, 17}, {2332, 18}, {2314, 17}, {2297, 16}, {2281, 17}, {2264, 16}, {2248, 16}, {2232, 16},
+   {2216, 16}, {2200, 15}, {2185, 15}, {2170, 15}, {2155, 15}, {2140, 15}, {2125, 14}, {2111, 14},
+   {2097, 14}, {2083, 14}, {2069, 14}, {2055, 13}, {2042, 13}, {2029, 13}, {2016, 13}, {2003, 13},
+   {1990, 13}, {1977, 12}, {1965, 12}, {1953, 13}, {1940, 11}, {1929, 12}, {1917, 12}, {1905, 12},
+   {1893, 11}, {1882, 11}, {1871, 11}, {1860, 11}, {1849, 11}, {1838, 11}, {1827, 11}, {1816, 10},
+   {1806, 11}, {1795, 10}, {1785, 10}, {1775, 10}, {1765, 10}, {1755, 10}, {1745, 9}, {1736, 10},
+   {1726, 9}, {1717, 10}, {1707, 9}, {1698, 9}, {1689, 9}, {1680, 9}, {1671, 9}, {1662, 9},
+   {1653, 9}, {1644, 8}, {1636, 9}, {1627, 8}, {1619, 9}, {1610, 8}, {1602, 8}, {1594, 8},
+   {1586, 8}, {1578, 8}, {1570, 8}, {1562, 8}, {1554, 7}, {1547, 8}, {1539, 8}, {1531, 7},
+   {1524, 8}, {1516, 7}, {1509, 7}, {1502, 7}, {1495, 7}, {1488, 7}, {1481, 7}, {1474, 7},
+   {1467, 7}, {1460, 7}, {1453, 7}, {1446, 6}, {1440, 7}, {1433, 7}, {1426, 6}, {1420, 6},
+   {1414, 7}, {1407, 6}, {1401, 6}, {1395, 7}, {1388, 6}, {1382, 6}, {1376, 6}, {1370, 6},
+   {1364, 6}, {1358, 6}, {1352, 6}, {1346, 5}, {1341, 6}, {1335, 6}, {1329, 5}, {1324, 6},
+   {1318, 5}, {1313, 6}, {1307, 5}, {1302, 6}, {1296, 5}, {1291, 5}, {1286, 6}, {1280, 5},
+   {1275, 5}, {1270, 5}, {1265, 5}, {1260, 5}, {1255, 5}, {1250, 5}, {1245, 5}, {1240, 5},
+   {1235, 5}, {1230, 5}, {1225, 5}, {1220, 5}, {1215, 4}, {1211, 5}, {1206, 5}, {1201, 5},
+};
+
+#endif

+ 112 - 139
Firmware/speed_lookuptable.h

@@ -3,150 +3,123 @@
 
 #include "Marlin.h"
 
-#if F_CPU == 16000000
+extern const uint16_t speed_lookuptable_fast[256][2] PROGMEM;
+extern const uint16_t speed_lookuptable_slow[256][2] PROGMEM;
 
-const uint16_t speed_lookuptable_fast[256][2] PROGMEM = {\
-{ 62500, 55556}, { 6944, 3268}, { 3676, 1176}, { 2500, 607}, { 1893, 369}, { 1524, 249}, { 1275, 179}, { 1096, 135}, 
-{ 961, 105}, { 856, 85}, { 771, 69}, { 702, 58}, { 644, 49}, { 595, 42}, { 553, 37}, { 516, 32}, 
-{ 484, 28}, { 456, 25}, { 431, 23}, { 408, 20}, { 388, 19}, { 369, 16}, { 353, 16}, { 337, 14}, 
-{ 323, 13}, { 310, 11}, { 299, 11}, { 288, 11}, { 277, 9}, { 268, 9}, { 259, 8}, { 251, 8}, 
-{ 243, 8}, { 235, 7}, { 228, 6}, { 222, 6}, { 216, 6}, { 210, 6}, { 204, 5}, { 199, 5}, 
-{ 194, 5}, { 189, 4}, { 185, 4}, { 181, 4}, { 177, 4}, { 173, 4}, { 169, 4}, { 165, 3}, 
-{ 162, 3}, { 159, 4}, { 155, 3}, { 152, 3}, { 149, 2}, { 147, 3}, { 144, 3}, { 141, 2}, 
-{ 139, 3}, { 136, 2}, { 134, 2}, { 132, 3}, { 129, 2}, { 127, 2}, { 125, 2}, { 123, 2}, 
-{ 121, 2}, { 119, 1}, { 118, 2}, { 116, 2}, { 114, 1}, { 113, 2}, { 111, 2}, { 109, 1}, 
-{ 108, 2}, { 106, 1}, { 105, 2}, { 103, 1}, { 102, 1}, { 101, 1}, { 100, 2}, { 98, 1}, 
-{ 97, 1}, { 96, 1}, { 95, 2}, { 93, 1}, { 92, 1}, { 91, 1}, { 90, 1}, { 89, 1}, 
-{ 88, 1}, { 87, 1}, { 86, 1}, { 85, 1}, { 84, 1}, { 83, 0}, { 83, 1}, { 82, 1}, 
-{ 81, 1}, { 80, 1}, { 79, 1}, { 78, 0}, { 78, 1}, { 77, 1}, { 76, 1}, { 75, 0}, 
-{ 75, 1}, { 74, 1}, { 73, 1}, { 72, 0}, { 72, 1}, { 71, 1}, { 70, 0}, { 70, 1}, 
-{ 69, 0}, { 69, 1}, { 68, 1}, { 67, 0}, { 67, 1}, { 66, 0}, { 66, 1}, { 65, 0}, 
-{ 65, 1}, { 64, 1}, { 63, 0}, { 63, 1}, { 62, 0}, { 62, 1}, { 61, 0}, { 61, 1}, 
-{ 60, 0}, { 60, 0}, { 60, 1}, { 59, 0}, { 59, 1}, { 58, 0}, { 58, 1}, { 57, 0}, 
-{ 57, 1}, { 56, 0}, { 56, 0}, { 56, 1}, { 55, 0}, { 55, 1}, { 54, 0}, { 54, 0}, 
-{ 54, 1}, { 53, 0}, { 53, 0}, { 53, 1}, { 52, 0}, { 52, 0}, { 52, 1}, { 51, 0}, 
-{ 51, 0}, { 51, 1}, { 50, 0}, { 50, 0}, { 50, 1}, { 49, 0}, { 49, 0}, { 49, 1}, 
-{ 48, 0}, { 48, 0}, { 48, 1}, { 47, 0}, { 47, 0}, { 47, 0}, { 47, 1}, { 46, 0}, 
-{ 46, 0}, { 46, 1}, { 45, 0}, { 45, 0}, { 45, 0}, { 45, 1}, { 44, 0}, { 44, 0}, 
-{ 44, 0}, { 44, 1}, { 43, 0}, { 43, 0}, { 43, 0}, { 43, 1}, { 42, 0}, { 42, 0}, 
-{ 42, 0}, { 42, 1}, { 41, 0}, { 41, 0}, { 41, 0}, { 41, 0}, { 41, 1}, { 40, 0}, 
-{ 40, 0}, { 40, 0}, { 40, 0}, { 40, 1}, { 39, 0}, { 39, 0}, { 39, 0}, { 39, 0}, 
-{ 39, 1}, { 38, 0}, { 38, 0}, { 38, 0}, { 38, 0}, { 38, 1}, { 37, 0}, { 37, 0}, 
-{ 37, 0}, { 37, 0}, { 37, 0}, { 37, 1}, { 36, 0}, { 36, 0}, { 36, 0}, { 36, 0}, 
-{ 36, 1}, { 35, 0}, { 35, 0}, { 35, 0}, { 35, 0}, { 35, 0}, { 35, 0}, { 35, 1}, 
-{ 34, 0}, { 34, 0}, { 34, 0}, { 34, 0}, { 34, 0}, { 34, 1}, { 33, 0}, { 33, 0}, 
-{ 33, 0}, { 33, 0}, { 33, 0}, { 33, 0}, { 33, 1}, { 32, 0}, { 32, 0}, { 32, 0}, 
-{ 32, 0}, { 32, 0}, { 32, 0}, { 32, 0}, { 32, 1}, { 31, 0}, { 31, 0}, { 31, 0}, 
-{ 31, 0}, { 31, 0}, { 31, 0}, { 31, 1}, { 30, 0}, { 30, 0}, { 30, 0}, { 30, 0}
-};
+#ifndef _NO_ASM
 
-const uint16_t speed_lookuptable_slow[256][2] PROGMEM = {\
-{ 62500, 12500}, { 50000, 8334}, { 41666, 5952}, { 35714, 4464}, { 31250, 3473}, { 27777, 2777}, { 25000, 2273}, { 22727, 1894}, 
-{ 20833, 1603}, { 19230, 1373}, { 17857, 1191}, { 16666, 1041}, { 15625, 920}, { 14705, 817}, { 13888, 731}, { 13157, 657}, 
-{ 12500, 596}, { 11904, 541}, { 11363, 494}, { 10869, 453}, { 10416, 416}, { 10000, 385}, { 9615, 356}, { 9259, 331}, 
-{ 8928, 308}, { 8620, 287}, { 8333, 269}, { 8064, 252}, { 7812, 237}, { 7575, 223}, { 7352, 210}, { 7142, 198}, 
-{ 6944, 188}, { 6756, 178}, { 6578, 168}, { 6410, 160}, { 6250, 153}, { 6097, 145}, { 5952, 139}, { 5813, 132}, 
-{ 5681, 126}, { 5555, 121}, { 5434, 115}, { 5319, 111}, { 5208, 106}, { 5102, 102}, { 5000, 99}, { 4901, 94}, 
-{ 4807, 91}, { 4716, 87}, { 4629, 84}, { 4545, 81}, { 4464, 79}, { 4385, 75}, { 4310, 73}, { 4237, 71}, 
-{ 4166, 68}, { 4098, 66}, { 4032, 64}, { 3968, 62}, { 3906, 60}, { 3846, 59}, { 3787, 56}, { 3731, 55}, 
-{ 3676, 53}, { 3623, 52}, { 3571, 50}, { 3521, 49}, { 3472, 48}, { 3424, 46}, { 3378, 45}, { 3333, 44}, 
-{ 3289, 43}, { 3246, 41}, { 3205, 41}, { 3164, 39}, { 3125, 39}, { 3086, 38}, { 3048, 36}, { 3012, 36}, 
-{ 2976, 35}, { 2941, 35}, { 2906, 33}, { 2873, 33}, { 2840, 32}, { 2808, 31}, { 2777, 30}, { 2747, 30}, 
-{ 2717, 29}, { 2688, 29}, { 2659, 28}, { 2631, 27}, { 2604, 27}, { 2577, 26}, { 2551, 26}, { 2525, 25}, 
-{ 2500, 25}, { 2475, 25}, { 2450, 23}, { 2427, 24}, { 2403, 23}, { 2380, 22}, { 2358, 22}, { 2336, 22}, 
-{ 2314, 21}, { 2293, 21}, { 2272, 20}, { 2252, 20}, { 2232, 20}, { 2212, 20}, { 2192, 19}, { 2173, 18}, 
-{ 2155, 19}, { 2136, 18}, { 2118, 18}, { 2100, 17}, { 2083, 17}, { 2066, 17}, { 2049, 17}, { 2032, 16}, 
-{ 2016, 16}, { 2000, 16}, { 1984, 16}, { 1968, 15}, { 1953, 16}, { 1937, 14}, { 1923, 15}, { 1908, 15}, 
-{ 1893, 14}, { 1879, 14}, { 1865, 14}, { 1851, 13}, { 1838, 14}, { 1824, 13}, { 1811, 13}, { 1798, 13}, 
-{ 1785, 12}, { 1773, 13}, { 1760, 12}, { 1748, 12}, { 1736, 12}, { 1724, 12}, { 1712, 12}, { 1700, 11}, 
-{ 1689, 12}, { 1677, 11}, { 1666, 11}, { 1655, 11}, { 1644, 11}, { 1633, 10}, { 1623, 11}, { 1612, 10}, 
-{ 1602, 10}, { 1592, 10}, { 1582, 10}, { 1572, 10}, { 1562, 10}, { 1552, 9}, { 1543, 10}, { 1533, 9}, 
-{ 1524, 9}, { 1515, 9}, { 1506, 9}, { 1497, 9}, { 1488, 9}, { 1479, 9}, { 1470, 9}, { 1461, 8}, 
-{ 1453, 8}, { 1445, 9}, { 1436, 8}, { 1428, 8}, { 1420, 8}, { 1412, 8}, { 1404, 8}, { 1396, 8}, 
-{ 1388, 7}, { 1381, 8}, { 1373, 7}, { 1366, 8}, { 1358, 7}, { 1351, 7}, { 1344, 8}, { 1336, 7}, 
-{ 1329, 7}, { 1322, 7}, { 1315, 7}, { 1308, 6}, { 1302, 7}, { 1295, 7}, { 1288, 6}, { 1282, 7}, 
-{ 1275, 6}, { 1269, 7}, { 1262, 6}, { 1256, 6}, { 1250, 7}, { 1243, 6}, { 1237, 6}, { 1231, 6}, 
-{ 1225, 6}, { 1219, 6}, { 1213, 6}, { 1207, 6}, { 1201, 5}, { 1196, 6}, { 1190, 6}, { 1184, 5}, 
-{ 1179, 6}, { 1173, 5}, { 1168, 6}, { 1162, 5}, { 1157, 5}, { 1152, 6}, { 1146, 5}, { 1141, 5}, 
-{ 1136, 5}, { 1131, 5}, { 1126, 5}, { 1121, 5}, { 1116, 5}, { 1111, 5}, { 1106, 5}, { 1101, 5}, 
-{ 1096, 5}, { 1091, 5}, { 1086, 4}, { 1082, 5}, { 1077, 5}, { 1072, 4}, { 1068, 5}, { 1063, 4}, 
-{ 1059, 5}, { 1054, 4}, { 1050, 4}, { 1046, 5}, { 1041, 4}, { 1037, 4}, { 1033, 5}, { 1028, 4}, 
-{ 1024, 4}, { 1020, 4}, { 1016, 4}, { 1012, 4}, { 1008, 4}, { 1004, 4}, { 1000, 4}, { 996, 4}, 
-{ 992, 4}, { 988, 4}, { 984, 4}, { 980, 4}, { 976, 4}, { 972, 4}, { 968, 3}, { 965, 3}
-};
+// intRes = intIn1 * intIn2 >> 16
+// uses:
+// r26 to store 0
+// r27 to store the byte 1 of the 24 bit result
+#define MultiU16X8toH16(intRes, charIn1, intIn2) \
+asm volatile ( \
+"clr r26 \n\t" \
+"mul %A1, %B2 \n\t" \
+"movw %A0, r0 \n\t" \
+"mul %A1, %A2 \n\t" \
+"add %A0, r1 \n\t" \
+"adc %B0, r26 \n\t" \
+"lsr r0 \n\t" \
+"adc %A0, r26 \n\t" \
+"adc %B0, r26 \n\t" \
+"clr r1 \n\t" \
+: \
+"=&r" (intRes) \
+: \
+"d" (charIn1), \
+"d" (intIn2) \
+: \
+"r26" \
+)
 
-#elif F_CPU == 20000000
+// intRes = longIn1 * longIn2 >> 24
+// uses:
+// r26 to store 0
+// r27 to store the byte 1 of the 48bit result
+#define MultiU24X24toH16(intRes, longIn1, longIn2) \
+asm volatile ( \
+"clr r26 \n\t" \
+"mul %A1, %B2 \n\t" \
+"mov r27, r1 \n\t" \
+"mul %B1, %C2 \n\t" \
+"movw %A0, r0 \n\t" \
+"mul %C1, %C2 \n\t" \
+"add %B0, r0 \n\t" \
+"mul %C1, %B2 \n\t" \
+"add %A0, r0 \n\t" \
+"adc %B0, r1 \n\t" \
+"mul %A1, %C2 \n\t" \
+"add r27, r0 \n\t" \
+"adc %A0, r1 \n\t" \
+"adc %B0, r26 \n\t" \
+"mul %B1, %B2 \n\t" \
+"add r27, r0 \n\t" \
+"adc %A0, r1 \n\t" \
+"adc %B0, r26 \n\t" \
+"mul %C1, %A2 \n\t" \
+"add r27, r0 \n\t" \
+"adc %A0, r1 \n\t" \
+"adc %B0, r26 \n\t" \
+"mul %B1, %A2 \n\t" \
+"add r27, r1 \n\t" \
+"adc %A0, r26 \n\t" \
+"adc %B0, r26 \n\t" \
+"lsr r27 \n\t" \
+"adc %A0, r26 \n\t" \
+"adc %B0, r26 \n\t" \
+"clr r1 \n\t" \
+: \
+"=&r" (intRes) \
+: \
+"d" (longIn1), \
+"d" (longIn2) \
+: \
+"r26" , "r27" \
+)
 
-const uint16_t speed_lookuptable_fast[256][2] PROGMEM = {
-   {62500, 54055}, {8445, 3917}, {4528, 1434}, {3094, 745}, {2349, 456}, {1893, 307}, {1586, 222}, {1364, 167},
-   {1197, 131}, {1066, 105}, {961, 86}, {875, 72}, {803, 61}, {742, 53}, {689, 45}, {644, 40},
-   {604, 35}, {569, 32}, {537, 28}, {509, 25}, {484, 23}, {461, 21}, {440, 19}, {421, 17},
-   {404, 16}, {388, 15}, {373, 14}, {359, 13}, {346, 12}, {334, 11}, {323, 10}, {313, 10},
-   {303, 9}, {294, 9}, {285, 8}, {277, 7}, {270, 8}, {262, 7}, {255, 6}, {249, 6},
-   {243, 6}, {237, 6}, {231, 5}, {226, 5}, {221, 5}, {216, 5}, {211, 4}, {207, 5},
-   {202, 4}, {198, 4}, {194, 4}, {190, 3}, {187, 4}, {183, 3}, {180, 3}, {177, 4},
-   {173, 3}, {170, 3}, {167, 2}, {165, 3}, {162, 3}, {159, 2}, {157, 3}, {154, 2},
-   {152, 3}, {149, 2}, {147, 2}, {145, 2}, {143, 2}, {141, 2}, {139, 2}, {137, 2},
-   {135, 2}, {133, 2}, {131, 2}, {129, 1}, {128, 2}, {126, 2}, {124, 1}, {123, 2},
-   {121, 1}, {120, 2}, {118, 1}, {117, 1}, {116, 2}, {114, 1}, {113, 1}, {112, 2},
-   {110, 1}, {109, 1}, {108, 1}, {107, 2}, {105, 1}, {104, 1}, {103, 1}, {102, 1},
-   {101, 1}, {100, 1}, {99, 1}, {98, 1}, {97, 1}, {96, 1}, {95, 1}, {94, 1},
-   {93, 1}, {92, 1}, {91, 0}, {91, 1}, {90, 1}, {89, 1}, {88, 1}, {87, 0},
-   {87, 1}, {86, 1}, {85, 1}, {84, 0}, {84, 1}, {83, 1}, {82, 1}, {81, 0},
-   {81, 1}, {80, 1}, {79, 0}, {79, 1}, {78, 0}, {78, 1}, {77, 1}, {76, 0},
-   {76, 1}, {75, 0}, {75, 1}, {74, 1}, {73, 0}, {73, 1}, {72, 0}, {72, 1},
-   {71, 0}, {71, 1}, {70, 0}, {70, 1}, {69, 0}, {69, 1}, {68, 0}, {68, 1},
-   {67, 0}, {67, 1}, {66, 0}, {66, 1}, {65, 0}, {65, 0}, {65, 1}, {64, 0},
-   {64, 1}, {63, 0}, {63, 1}, {62, 0}, {62, 0}, {62, 1}, {61, 0}, {61, 1},
-   {60, 0}, {60, 0}, {60, 1}, {59, 0}, {59, 0}, {59, 1}, {58, 0}, {58, 0},
-   {58, 1}, {57, 0}, {57, 0}, {57, 1}, {56, 0}, {56, 0}, {56, 1}, {55, 0},
-   {55, 0}, {55, 1}, {54, 0}, {54, 0}, {54, 1}, {53, 0}, {53, 0}, {53, 0},
-   {53, 1}, {52, 0}, {52, 0}, {52, 1}, {51, 0}, {51, 0}, {51, 0}, {51, 1},
-   {50, 0}, {50, 0}, {50, 0}, {50, 1}, {49, 0}, {49, 0}, {49, 0}, {49, 1},
-   {48, 0}, {48, 0}, {48, 0}, {48, 1}, {47, 0}, {47, 0}, {47, 0}, {47, 1},
-   {46, 0}, {46, 0}, {46, 0}, {46, 0}, {46, 1}, {45, 0}, {45, 0}, {45, 0},
-   {45, 1}, {44, 0}, {44, 0}, {44, 0}, {44, 0}, {44, 1}, {43, 0}, {43, 0},
-   {43, 0}, {43, 0}, {43, 1}, {42, 0}, {42, 0}, {42, 0}, {42, 0}, {42, 0},
-   {42, 1}, {41, 0}, {41, 0}, {41, 0}, {41, 0}, {41, 0}, {41, 1}, {40, 0},
-   {40, 0}, {40, 0}, {40, 0}, {40, 1}, {39, 0}, {39, 0}, {39, 0}, {39, 0},
-   {39, 0}, {39, 0}, {39, 1}, {38, 0}, {38, 0}, {38, 0}, {38, 0}, {38, 0},
-};
+#else //_NO_ASM
 
-const uint16_t speed_lookuptable_slow[256][2] PROGMEM = {
-   {62500, 10417}, {52083, 7441}, {44642, 5580}, {39062, 4340}, {34722, 3472}, {31250, 2841}, {28409, 2368}, {26041, 2003},
-   {24038, 1717}, {22321, 1488}, {20833, 1302}, {19531, 1149}, {18382, 1021}, {17361, 914}, {16447, 822}, {15625, 745},
-   {14880, 676}, {14204, 618}, {13586, 566}, {13020, 520}, {12500, 481}, {12019, 445}, {11574, 414}, {11160, 385},
-   {10775, 359}, {10416, 336}, {10080, 315}, {9765, 296}, {9469, 278}, {9191, 263}, {8928, 248}, {8680, 235},
-   {8445, 222}, {8223, 211}, {8012, 200}, {7812, 191}, {7621, 181}, {7440, 173}, {7267, 165}, {7102, 158},
-   {6944, 151}, {6793, 145}, {6648, 138}, {6510, 133}, {6377, 127}, {6250, 123}, {6127, 118}, {6009, 113},
-   {5896, 109}, {5787, 106}, {5681, 101}, {5580, 98}, {5482, 95}, {5387, 91}, {5296, 88}, {5208, 86},
-   {5122, 82}, {5040, 80}, {4960, 78}, {4882, 75}, {4807, 73}, {4734, 70}, {4664, 69}, {4595, 67},
-   {4528, 64}, {4464, 63}, {4401, 61}, {4340, 60}, {4280, 58}, {4222, 56}, {4166, 55}, {4111, 53},
-   {4058, 52}, {4006, 51}, {3955, 49}, {3906, 48}, {3858, 48}, {3810, 45}, {3765, 45}, {3720, 44},
-   {3676, 43}, {3633, 42}, {3591, 40}, {3551, 40}, {3511, 39}, {3472, 38}, {3434, 38}, {3396, 36},
-   {3360, 36}, {3324, 35}, {3289, 34}, {3255, 34}, {3221, 33}, {3188, 32}, {3156, 31}, {3125, 31},
-   {3094, 31}, {3063, 30}, {3033, 29}, {3004, 28}, {2976, 28}, {2948, 28}, {2920, 27}, {2893, 27},
-   {2866, 26}, {2840, 25}, {2815, 25}, {2790, 25}, {2765, 24}, {2741, 24}, {2717, 24}, {2693, 23},
-   {2670, 22}, {2648, 22}, {2626, 22}, {2604, 22}, {2582, 21}, {2561, 21}, {2540, 20}, {2520, 20},
-   {2500, 20}, {2480, 20}, {2460, 19}, {2441, 19}, {2422, 19}, {2403, 18}, {2385, 18}, {2367, 18},
-   {2349, 17}, {2332, 18}, {2314, 17}, {2297, 16}, {2281, 17}, {2264, 16}, {2248, 16}, {2232, 16},
-   {2216, 16}, {2200, 15}, {2185, 15}, {2170, 15}, {2155, 15}, {2140, 15}, {2125, 14}, {2111, 14},
-   {2097, 14}, {2083, 14}, {2069, 14}, {2055, 13}, {2042, 13}, {2029, 13}, {2016, 13}, {2003, 13},
-   {1990, 13}, {1977, 12}, {1965, 12}, {1953, 13}, {1940, 11}, {1929, 12}, {1917, 12}, {1905, 12},
-   {1893, 11}, {1882, 11}, {1871, 11}, {1860, 11}, {1849, 11}, {1838, 11}, {1827, 11}, {1816, 10},
-   {1806, 11}, {1795, 10}, {1785, 10}, {1775, 10}, {1765, 10}, {1755, 10}, {1745, 9}, {1736, 10},
-   {1726, 9}, {1717, 10}, {1707, 9}, {1698, 9}, {1689, 9}, {1680, 9}, {1671, 9}, {1662, 9},
-   {1653, 9}, {1644, 8}, {1636, 9}, {1627, 8}, {1619, 9}, {1610, 8}, {1602, 8}, {1594, 8},
-   {1586, 8}, {1578, 8}, {1570, 8}, {1562, 8}, {1554, 7}, {1547, 8}, {1539, 8}, {1531, 7},
-   {1524, 8}, {1516, 7}, {1509, 7}, {1502, 7}, {1495, 7}, {1488, 7}, {1481, 7}, {1474, 7},
-   {1467, 7}, {1460, 7}, {1453, 7}, {1446, 6}, {1440, 7}, {1433, 7}, {1426, 6}, {1420, 6},
-   {1414, 7}, {1407, 6}, {1401, 6}, {1395, 7}, {1388, 6}, {1382, 6}, {1376, 6}, {1370, 6},
-   {1364, 6}, {1358, 6}, {1352, 6}, {1346, 5}, {1341, 6}, {1335, 6}, {1329, 5}, {1324, 6},
-   {1318, 5}, {1313, 6}, {1307, 5}, {1302, 6}, {1296, 5}, {1291, 5}, {1286, 6}, {1280, 5},
-   {1275, 5}, {1270, 5}, {1265, 5}, {1260, 5}, {1255, 5}, {1250, 5}, {1245, 5}, {1240, 5},
-   {1235, 5}, {1230, 5}, {1225, 5}, {1220, 5}, {1215, 4}, {1211, 5}, {1206, 5}, {1201, 5},
-};
+// NOTE: currently not implemented
+void MultiU16X8toH16(unsigned short& intRes, unsigned char& charIn1, unsigned short& intIn2);
+void MultiU24X24toH16(uint16_t& intRes, int32_t& longIn1, long& longIn2);
 
-#endif
+#endif //_NO_ASM
+
+
+FORCE_INLINE unsigned short calc_timer(uint16_t step_rate, uint8_t& step_loops) {
+  unsigned short timer;
+  if(step_rate > MAX_STEP_FREQUENCY) step_rate = MAX_STEP_FREQUENCY;
+
+  if(step_rate > 20000) { // If steprate > 20kHz >> step 4 times
+    step_rate = (step_rate >> 2)&0x3fff;
+    step_loops = 4;
+  }
+  else if(step_rate > 10000) { // If steprate > 10kHz >> step 2 times
+    step_rate = (step_rate >> 1)&0x7fff;
+    step_loops = 2;
+  }
+  else {
+    step_loops = 1;
+  }
+
+  if(step_rate < (F_CPU/500000)) step_rate = (F_CPU/500000);
+  step_rate -= (F_CPU/500000); // Correct for minimal speed
+  if(step_rate >= (8*256)){ // higher step rate
+    unsigned short table_address = (unsigned short)&speed_lookuptable_fast[(unsigned char)(step_rate>>8)][0];
+    unsigned char tmp_step_rate = (step_rate & 0x00ff);
+    unsigned short gain = (unsigned short)pgm_read_word_near(table_address+2);
+    MultiU16X8toH16(timer, tmp_step_rate, gain);
+    timer = (unsigned short)pgm_read_word_near(table_address) - timer;
+  }
+  else { // lower step rates
+    unsigned short table_address = (unsigned short)&speed_lookuptable_slow[0][0];
+    table_address += ((step_rate)>>1) & 0xfffc;
+    timer = (unsigned short)pgm_read_word_near(table_address);
+    timer -= (((unsigned short)pgm_read_word_near(table_address+2) * (unsigned char)(step_rate & 0x0007))>>3);
+  }
+  if(timer < 100) { timer = 100; }//(20kHz this should never happen)////MSG_STEPPER_TOO_HIGH c=0 r=0
+  return timer;
+}
 
 #endif

+ 289 - 384
Firmware/stepper.cpp

@@ -113,23 +113,30 @@ volatile long count_position[NUM_AXIS] = { 0, 0, 0, 0};
 volatile signed char count_direction[NUM_AXIS] = { 1, 1, 1, 1};
 
 #ifdef LIN_ADVANCE
+  void advance_isr_scheduler();
+  void advance_isr();
 
-  static uint16_t nextMainISR = 0;
+  static const uint16_t ADV_NEVER      = 0xFFFF;
+  static const uint8_t  ADV_INIT       = 0b01;
+  static const uint8_t  ADV_DECELERATE = 0b10;
+
+  static uint16_t nextMainISR;
+  static uint16_t nextAdvanceISR;
+
+  static uint16_t main_Rate;
   static uint16_t eISR_Rate;
+  static uint16_t eISR_Err;
+
+  static uint16_t current_adv_steps;
+  static uint16_t final_adv_steps;
+  static uint16_t max_adv_steps;
+  static uint32_t LA_decelerate_after;
 
-  // Extrusion steps to be executed by the stepper.
-  // If set to non zero, the timer ISR routine will tick the Linear Advance extruder ticks first.
-  // If e_steps is zero, then the timer ISR routine will perform the usual DDA step.
-  static volatile int16_t e_steps = 0;
-  // How many extruder steps shall be ticked at a single ISR invocation?
-  static uint8_t          estep_loops;
-  // The current speed of the extruder, scaled by the linear advance constant, so it has the same measure
-  // as current_adv_steps.
-  static int              current_estep_rate;
-  // The current pretension of filament expressed in extruder micro steps.
-  static int              current_adv_steps;
-
-  #define _NEXT_ISR(T)    nextMainISR = T
+  static int8_t e_steps;
+  static uint8_t e_step_loops;
+  static int8_t LA_phase;
+
+  #define _NEXT_ISR(T)    main_Rate = nextMainISR = T
 #else
   #define _NEXT_ISR(T)    OCR1A = T
 #endif
@@ -143,92 +150,6 @@ extern uint16_t stepper_timer_overflow_last;
 //=============================functions         ============================
 //===========================================================================
 
-#ifndef _NO_ASM
-
-// intRes = intIn1 * intIn2 >> 16
-// uses:
-// r26 to store 0
-// r27 to store the byte 1 of the 24 bit result
-#define MultiU16X8toH16(intRes, charIn1, intIn2) \
-asm volatile ( \
-"clr r26 \n\t" \
-"mul %A1, %B2 \n\t" \
-"movw %A0, r0 \n\t" \
-"mul %A1, %A2 \n\t" \
-"add %A0, r1 \n\t" \
-"adc %B0, r26 \n\t" \
-"lsr r0 \n\t" \
-"adc %A0, r26 \n\t" \
-"adc %B0, r26 \n\t" \
-"clr r1 \n\t" \
-: \
-"=&r" (intRes) \
-: \
-"d" (charIn1), \
-"d" (intIn2) \
-: \
-"r26" \
-)
-
-// intRes = longIn1 * longIn2 >> 24
-// uses:
-// r26 to store 0
-// r27 to store the byte 1 of the 48bit result
-#define MultiU24X24toH16(intRes, longIn1, longIn2) \
-asm volatile ( \
-"clr r26 \n\t" \
-"mul %A1, %B2 \n\t" \
-"mov r27, r1 \n\t" \
-"mul %B1, %C2 \n\t" \
-"movw %A0, r0 \n\t" \
-"mul %C1, %C2 \n\t" \
-"add %B0, r0 \n\t" \
-"mul %C1, %B2 \n\t" \
-"add %A0, r0 \n\t" \
-"adc %B0, r1 \n\t" \
-"mul %A1, %C2 \n\t" \
-"add r27, r0 \n\t" \
-"adc %A0, r1 \n\t" \
-"adc %B0, r26 \n\t" \
-"mul %B1, %B2 \n\t" \
-"add r27, r0 \n\t" \
-"adc %A0, r1 \n\t" \
-"adc %B0, r26 \n\t" \
-"mul %C1, %A2 \n\t" \
-"add r27, r0 \n\t" \
-"adc %A0, r1 \n\t" \
-"adc %B0, r26 \n\t" \
-"mul %B1, %A2 \n\t" \
-"add r27, r1 \n\t" \
-"adc %A0, r26 \n\t" \
-"adc %B0, r26 \n\t" \
-"lsr r27 \n\t" \
-"adc %A0, r26 \n\t" \
-"adc %B0, r26 \n\t" \
-"clr r1 \n\t" \
-: \
-"=&r" (intRes) \
-: \
-"d" (longIn1), \
-"d" (longIn2) \
-: \
-"r26" , "r27" \
-)
-
-#else //_NO_ASM
-
-void MultiU16X8toH16(unsigned short& intRes, unsigned char& charIn1, unsigned short& intIn2)
-{
-}
-
-void MultiU24X24toH16(uint16_t& intRes, int32_t& longIn1, long& longIn2)
-{
-}
-
-#endif //_NO_ASM
-
-// Some useful constants
-
 void checkHitEndstops()
 {
  if( endstop_x_hit || endstop_y_hit || endstop_z_hit) {
@@ -316,42 +237,6 @@ void invert_z_endstop(bool endstop_invert)
 //  step_events_completed reaches block->decelerate_after after which it decelerates until the trapezoid generator is reset.
 //  The slope of acceleration is calculated with the leib ramp alghorithm.
 
-FORCE_INLINE unsigned short calc_timer(uint16_t step_rate) {
-  unsigned short timer;
-  if(step_rate > MAX_STEP_FREQUENCY) step_rate = MAX_STEP_FREQUENCY;
-
-  if(step_rate > 20000) { // If steprate > 20kHz >> step 4 times
-    step_rate = (step_rate >> 2)&0x3fff;
-    step_loops = 4;
-  }
-  else if(step_rate > 10000) { // If steprate > 10kHz >> step 2 times
-    step_rate = (step_rate >> 1)&0x7fff;
-    step_loops = 2;
-  }
-  else {
-    step_loops = 1;
-  }
-//    step_loops = 1;
-
-  if(step_rate < (F_CPU/500000)) step_rate = (F_CPU/500000);
-  step_rate -= (F_CPU/500000); // Correct for minimal speed
-  if(step_rate >= (8*256)){ // higher step rate
-    unsigned short table_address = (unsigned short)&speed_lookuptable_fast[(unsigned char)(step_rate>>8)][0];
-    unsigned char tmp_step_rate = (step_rate & 0x00ff);
-    unsigned short gain = (unsigned short)pgm_read_word_near(table_address+2);
-    MultiU16X8toH16(timer, tmp_step_rate, gain);
-    timer = (unsigned short)pgm_read_word_near(table_address) - timer;
-  }
-  else { // lower step rates
-    unsigned short table_address = (unsigned short)&speed_lookuptable_slow[0][0];
-    table_address += ((step_rate)>>1) & 0xfffc;
-    timer = (unsigned short)pgm_read_word_near(table_address);
-    timer -= (((unsigned short)pgm_read_word_near(table_address+2) * (unsigned char)(step_rate & 0x0007))>>3);
-  }
-  if(timer < 100) { timer = 100; MYSERIAL.print(_N("Steprate too high: ")); MYSERIAL.println(step_rate); }//(20kHz this should never happen)////MSG_STEPPER_TOO_HIGH
-  return timer;
-}
-
 // "The Stepper Driver Interrupt" - This timer interrupt is the workhorse.
 // It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately.
 ISR(TIMER1_COMPA_vect) {
@@ -361,53 +246,10 @@ ISR(TIMER1_COMPA_vect) {
 #endif //DEBUG_STACK_MONITOR
 
 #ifdef LIN_ADVANCE
-  // If there are any e_steps planned, tick them.
-  bool run_main_isr = false;
-  if (e_steps) {
-    //WRITE_NC(LOGIC_ANALYZER_CH7, true);
-	uint8_t cnt = 0;
-    for (uint8_t i = estep_loops; e_steps && i --;) {
-        WRITE_NC(E0_STEP_PIN, !INVERT_E_STEP_PIN);
-        -- e_steps;
-		cnt++;
-        WRITE_NC(E0_STEP_PIN, INVERT_E_STEP_PIN);
-    }
-#ifdef FILAMENT_SENSOR
-		if (READ(E0_DIR_PIN) == INVERT_E0_DIR)
-		{
-			if (count_direction[E_AXIS] == 1)
-				fsensor_counter -= cnt;
-			else
-				fsensor_counter += cnt;
-		}
-		else
-		{
-			if (count_direction[E_AXIS] == 1)
-				fsensor_counter += cnt;
-			else
-				fsensor_counter -= cnt;
-		}
-#endif //FILAMENT_SENSOR
-    if (e_steps) {
-      // Plan another Linear Advance tick.
-      OCR1A = eISR_Rate;
-      nextMainISR -= eISR_Rate;
-    } else if (! (nextMainISR & 0x8000) || nextMainISR < 16) {
-      // The timer did not overflow and it is big enough, so it makes sense to plan it.
-      OCR1A = nextMainISR;
-    } else {
-      // The timer has overflown, or it is too small. Run the main ISR just after the Linear Advance routine
-      // in the current interrupt tick.
-      run_main_isr = true;
-      //FIXME pick the serial line.
-    }
-    //WRITE_NC(LOGIC_ANALYZER_CH7, false);
-  } else
-    run_main_isr = true;
-
-  if (run_main_isr)
-#endif
+    advance_isr_scheduler();
+#else
     isr();
+#endif
 
   // Don't run the ISR faster than possible
   // Is there a 8us time left before the next interrupt triggers?
@@ -493,10 +335,6 @@ FORCE_INLINE void stepper_next_block()
 	}
 #endif
 
-#ifdef FILAMENT_SENSOR
-	fsensor_counter = 0;
-	fsensor_st_block_begin(current_block);
-#endif //FILAMENT_SENSOR
     // The busy flag is set by the plan_get_current_block() call.
     // current_block->busy = true;
     // Initializes the trapezoid generator from the current block. Called whenever a new
@@ -507,10 +345,26 @@ FORCE_INLINE void stepper_next_block()
     // state is reached.
     step_loops_nominal = 0;
     acc_step_rate = uint16_t(current_block->initial_rate);
-    acceleration_time = calc_timer(acc_step_rate);
+    acceleration_time = calc_timer(acc_step_rate, step_loops);
+
 #ifdef LIN_ADVANCE
-    current_estep_rate = ((unsigned long)acc_step_rate * current_block->abs_adv_steps_multiplier8) >> 17;
-#endif /* LIN_ADVANCE */
+    if (current_block->use_advance_lead) {
+        LA_decelerate_after = current_block->decelerate_after;
+        final_adv_steps = current_block->final_adv_steps;
+        max_adv_steps = current_block->max_adv_steps;
+        e_step_loops = current_block->advance_step_loops;
+    } else {
+        e_steps = 0;
+        e_step_loops = 1;
+        current_adv_steps = 0;
+    }
+    nextAdvanceISR = ADV_NEVER;
+    LA_phase = -1;
+#endif
+
+    if (current_block->flag & BLOCK_FLAG_E_RESET) {
+        count_position[E_AXIS] = 0;
+    }
 
     if (current_block->flag & BLOCK_FLAG_DDA_LOWRES) {
       counter_x.lo = -(current_block->step_event_count.lo >> 1);
@@ -567,9 +421,24 @@ FORCE_INLINE void stepper_next_block()
 #endif /* LIN_ADVANCE */
       count_direction[E_AXIS] = 1;
     }
+#ifdef FILAMENT_SENSOR
+	fsensor_counter = 0;
+	fsensor_st_block_begin(count_direction[E_AXIS] < 0);
+#endif //FILAMENT_SENSOR
   }
   else {
-    OCR1A = 2000; // 1kHz.
+      _NEXT_ISR(2000); // 1kHz.
+
+#ifdef LIN_ADVANCE
+      // reset LA state when there's no block
+      nextAdvanceISR = ADV_NEVER;
+      e_steps = 0;
+
+      // incrementally lose pressure to give a chance for
+      // a new LA block to be scheduled and recover
+      if(current_adv_steps)
+          --current_adv_steps;
+#endif
   }
   //WRITE_NC(LOGIC_ANALYZER_CH2, false);
 }
@@ -779,10 +648,10 @@ FORCE_INLINE void stepper_tick_lowres()
       counter_e.lo -= current_block->step_event_count.lo;
       count_position[E_AXIS] += count_direction[E_AXIS];
 #ifdef LIN_ADVANCE
-      ++ e_steps;
+      e_steps += count_direction[E_AXIS];
 #else
 	#ifdef FILAMENT_SENSOR
-	  ++ fsensor_counter;
+	  fsensor_counter += count_direction[E_AXIS];
 	#endif //FILAMENT_SENSOR
       WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN);
 #endif
@@ -841,11 +710,11 @@ FORCE_INLINE void stepper_tick_highres()
       counter_e.wide -= current_block->step_event_count.wide;
       count_position[E_AXIS]+=count_direction[E_AXIS];
 #ifdef LIN_ADVANCE
-      ++ e_steps;
+      e_steps += count_direction[E_AXIS];
 #else
-  #ifdef FILAMENT_SENSOR
-      ++ fsensor_counter;
-  #endif //FILAMENT_SENSOR
+    #ifdef FILAMENT_SENSOR
+      fsensor_counter += count_direction[E_AXIS];
+    #endif //FILAMENT_SENSOR
       WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN);
 #endif
     }
@@ -854,8 +723,53 @@ FORCE_INLINE void stepper_tick_highres()
   }
 }
 
-// 50us delay
-#define LIN_ADV_FIRST_TICK_DELAY 100
+
+#ifdef LIN_ADVANCE
+// @wavexx: fast uint16_t division for small dividends<5
+//          q/3 based on "Hacker's delight" formula
+FORCE_INLINE uint16_t fastdiv(uint16_t q, uint8_t d)
+{
+    if(d != 3) return q >> (d / 2);
+    else return ((uint32_t)0xAAAB * q) >> 17;
+}
+
+FORCE_INLINE void advance_spread(uint16_t timer)
+{
+    if(eISR_Err > timer)
+    {
+        // advance-step skipped
+        eISR_Err -= timer;
+        eISR_Rate = timer;
+        nextAdvanceISR = timer;
+        return;
+    }
+
+    // at least one step
+    uint8_t ticks = 1;
+    uint32_t block = current_block->advance_rate;
+    uint16_t max_t = timer - eISR_Err;
+    while (block < max_t)
+    {
+        ++ticks;
+        block += current_block->advance_rate;
+    }
+    if (block > timer)
+        eISR_Err += block - timer;
+    else
+        eISR_Err -= timer - block;
+
+    if (ticks <= 4)
+        eISR_Rate = fastdiv(timer, ticks);
+    else
+    {
+        // >4 ticks are still possible on slow moves
+        eISR_Rate = timer / ticks;
+    }
+
+    nextAdvanceISR = eISR_Rate / 2;
+}
+#endif
+
 
 FORCE_INLINE void isr() {
   //WRITE_NC(LOGIC_ANALYZER_CH0, true);
@@ -868,81 +782,18 @@ FORCE_INLINE void isr() {
   if (current_block != NULL) 
   {
     stepper_check_endstops();
-#ifdef LIN_ADVANCE
-      e_steps = 0;
-#endif /* LIN_ADVANCE */
     if (current_block->flag & BLOCK_FLAG_DDA_LOWRES)
       stepper_tick_lowres();
     else
       stepper_tick_highres();
 
+
 #ifdef LIN_ADVANCE
-      if (out_bits&(1<<E_AXIS))
-        // Move in negative direction.
-        e_steps = - e_steps;
-      if (current_block->use_advance_lead) {
-        //int esteps_inc = 0;
-        //esteps_inc = current_estep_rate - current_adv_steps;
-        //e_steps += esteps_inc;
-        e_steps += current_estep_rate - current_adv_steps;
-#if 0
-        if (abs(esteps_inc) > 4) {
-          LOGIC_ANALYZER_SERIAL_TX_WRITE(esteps_inc);
-          if (esteps_inc < -511 || esteps_inc > 511)
-            LOGIC_ANALYZER_SERIAL_TX_WRITE(esteps_inc >> 9);
-        }
-#endif
-        current_adv_steps = current_estep_rate;
-      }
-      // If we have esteps to execute, step some of them now.
-      if (e_steps) {
-        //WRITE_NC(LOGIC_ANALYZER_CH7, true);
-        // Set the step direction.
-		bool neg = e_steps < 0;
-        {
-          bool dir =
-        #ifdef SNMM
-            (neg == (mmu_extruder & 1))
-        #else
-            neg
-        #endif
-            ? INVERT_E0_DIR : !INVERT_E0_DIR; //If we have SNMM, reverse every second extruder.
-          WRITE_NC(E0_DIR_PIN, dir);
-          if (neg)
-            // Flip the e_steps counter to be always positive.
-            e_steps = - e_steps;
-        }
-        // Tick min(step_loops, abs(e_steps)).
-        estep_loops = (e_steps & 0x0ff00) ? 4 : e_steps;
-        if (step_loops < estep_loops)
-          estep_loops = step_loops;
-#ifdef FILAMENT_SENSOR
-		if (READ(E0_DIR_PIN) == INVERT_E0_DIR)
-		{
-			if (count_direction[E_AXIS] == 1)
-				fsensor_counter -= estep_loops;
-			else
-				fsensor_counter += estep_loops;
-		}
-		else
-		{
-			if (count_direction[E_AXIS] == 1)
-				fsensor_counter += estep_loops;
-			else
-				fsensor_counter -= estep_loops;
-		}
-#endif //FILAMENT_SENSOR
-        do {
-          WRITE_NC(E0_STEP_PIN, !INVERT_E_STEP_PIN);
-          -- e_steps;
-          WRITE_NC(E0_STEP_PIN, INVERT_E_STEP_PIN);
-        } while (-- estep_loops != 0);
-        //WRITE_NC(LOGIC_ANALYZER_CH7, false);
-        MSerial.checkRx(); // Check for serial chars.
-      }
+    if (e_steps) WRITE_NC(E0_DIR_PIN, e_steps < 0? INVERT_E0_DIR: !INVERT_E0_DIR);
+    uint8_t la_state = 0;
 #endif
 
-    // Calculare new timer value
+    // Calculate new timer value
     // 13.38-14.63us for steady state,
     // 25.12us for acceleration / deceleration.
     {
@@ -955,14 +806,15 @@ FORCE_INLINE void isr() {
         if(acc_step_rate > uint16_t(current_block->nominal_rate))
           acc_step_rate = current_block->nominal_rate;
         // step_rate to timer interval
-        uint16_t timer = calc_timer(acc_step_rate);
+        uint16_t timer = calc_timer(acc_step_rate, step_loops);
         _NEXT_ISR(timer);
         acceleration_time += timer;
-  #ifdef LIN_ADVANCE
-        if (current_block->use_advance_lead)
-          // int32_t = (uint16_t * uint32_t) >> 17
-          current_estep_rate = ((uint32_t)acc_step_rate * current_block->abs_adv_steps_multiplier8) >> 17;
-  #endif
+#ifdef LIN_ADVANCE
+        if (current_block->use_advance_lead) {
+            if (step_events_completed.wide <= (unsigned long int)step_loops)
+                la_state = ADV_INIT;
+        }
+#endif
       }
       else if (step_events_completed.wide > (unsigned long int)current_block->decelerate_after) {
         uint16_t step_rate;
@@ -973,24 +825,23 @@ FORCE_INLINE void isr() {
           step_rate = uint16_t(current_block->final_rate);
         }
         // Step_rate to timer interval.
-        uint16_t timer = calc_timer(step_rate);
+        uint16_t timer = calc_timer(step_rate, step_loops);
         _NEXT_ISR(timer);
         deceleration_time += timer;
-  #ifdef LIN_ADVANCE
-        if (current_block->use_advance_lead)
-          current_estep_rate = ((uint32_t)step_rate * current_block->abs_adv_steps_multiplier8) >> 17;
-  #endif
+#ifdef LIN_ADVANCE
+        if (current_block->use_advance_lead) {
+            la_state = ADV_DECELERATE;
+            if (step_events_completed.wide <= (unsigned long int)current_block->decelerate_after + step_loops)
+                la_state |= ADV_INIT;
+        }
+#endif
       }
       else {
         if (! step_loops_nominal) {
           // Calculation of the steady state timer rate has been delayed to the 1st tick of the steady state to lower
           // the initial interrupt blocking.
-          OCR1A_nominal = calc_timer(uint16_t(current_block->nominal_rate));
+          OCR1A_nominal = calc_timer(uint16_t(current_block->nominal_rate), step_loops);
           step_loops_nominal = step_loops;
-  #ifdef LIN_ADVANCE
-          if (current_block->use_advance_lead)
-            current_estep_rate = (current_block->nominal_rate * current_block->abs_adv_steps_multiplier8) >> 17;
-  #endif
         }
         _NEXT_ISR(OCR1A_nominal);
       }
@@ -998,110 +849,40 @@ FORCE_INLINE void isr() {
     }
 
 #ifdef LIN_ADVANCE
-    if (e_steps && current_block->use_advance_lead) {
-      //WRITE_NC(LOGIC_ANALYZER_CH7, true);
-      MSerial.checkRx(); // Check for serial chars.
-      // Some of the E steps were not ticked yet. Plan additional interrupts.
-      uint16_t now = TCNT1;
-      // Plan the first linear advance interrupt after 50us from now.
-      uint16_t to_go = nextMainISR - now - LIN_ADV_FIRST_TICK_DELAY;
-      eISR_Rate = 0;
-      if ((to_go & 0x8000) == 0) {
-        // The to_go number is not negative.
-        // Count the number of 7812,5 ticks, that fit into to_go 2MHz ticks.
-        uint8_t ticks = to_go >> 8;
-        if (ticks == 1) {
-          // Avoid running the following loop for a very short interval.
-          estep_loops = 255;
-          eISR_Rate = 1;
-        } else if ((e_steps & 0x0ff00) == 0) {
-          // e_steps <= 0x0ff
-          if (uint8_t(e_steps) <= ticks) {
-            // Spread the e_steps along the whole go_to interval.
-            eISR_Rate = to_go / uint8_t(e_steps);
-            estep_loops = 1;
-          } else if (ticks != 0) {
-            // At least one tick fits into the to_go interval. Calculate the e-step grouping.
-            uint8_t e = uint8_t(e_steps) >> 1;
-            estep_loops = 2;
-            while (e > ticks) {
-              e >>= 1;
-              estep_loops <<= 1;
+    // avoid multiple instances or function calls to advance_spread
+    if (la_state & ADV_INIT) eISR_Err = current_block->advance_rate / 4;
+    if (la_state & ADV_INIT || nextAdvanceISR != ADV_NEVER) {
+        advance_spread(main_Rate);
+        if (la_state & ADV_DECELERATE) {
+            if (step_loops == e_step_loops)
+                LA_phase = (eISR_Rate > main_Rate);
+            else {
+                // avoid overflow through division. warning: we need to _guarantee_ step_loops
+                // and e_step_loops are <= 4 due to fastdiv's limit
+                LA_phase = (fastdiv(eISR_Rate, step_loops) > fastdiv(main_Rate, e_step_loops));
             }
-            // Now the estep_loops contains the number of loops of power of 2, that will be sufficient
-            // to squeeze enough of Linear Advance ticks until nextMainISR.
-            // Calculate the tick rate.
-            eISR_Rate = to_go / ticks;          
-          }
-        } else {
-          // This is an exterme case with too many e_steps inserted by the linear advance.
-          // At least one tick fits into the to_go interval. Calculate the e-step grouping.
-          estep_loops = 2;
-          uint16_t e = e_steps >> 1;
-          while (e & 0x0ff00) {
-            e >>= 1;
-            estep_loops <<= 1;
-          }
-          while (uint8_t(e) > ticks) {
-            e >>= 1;
-            estep_loops <<= 1;
-          }
-          // Now the estep_loops contains the number of loops of power of 2, that will be sufficient
-          // to squeeze enough of Linear Advance ticks until nextMainISR.
-          // Calculate the tick rate.
-          eISR_Rate = to_go / ticks;
         }
-      }
-      if (eISR_Rate == 0) {
-        // There is not enough time to fit even a single additional tick.
-        // Tick all the extruder ticks now.
-        MSerial.checkRx(); // Check for serial chars.
-#ifdef FILAMENT_SENSOR
-		if (READ(E0_DIR_PIN) == INVERT_E0_DIR)
-		{
-			if (count_direction[E_AXIS] == 1)
-				fsensor_counter -= e_steps;
-			else
-				fsensor_counter += e_steps;
-		}
-		else
-		{
-			if (count_direction[E_AXIS] == 1)
-				fsensor_counter += e_steps;
-			else
-				fsensor_counter -= e_steps;
-		}
-#endif //FILAMENT_SENSOR
-        do {
-          WRITE_NC(E0_STEP_PIN, !INVERT_E_STEP_PIN);
-          -- e_steps;
-          WRITE_NC(E0_STEP_PIN, INVERT_E_STEP_PIN);
-        } while (e_steps);
-        OCR1A = nextMainISR;
-      } else {
-        // Tick the 1st Linear Advance interrupt after 50us from now.
-        nextMainISR -= LIN_ADV_FIRST_TICK_DELAY;
-        OCR1A = now + LIN_ADV_FIRST_TICK_DELAY;
-      }
-      //WRITE_NC(LOGIC_ANALYZER_CH7, false);
-    } else
-      OCR1A = nextMainISR;
+    }
+
+    // Check for serial chars. This executes roughtly inbetween 50-60% of the total runtime of the
+    // entire isr, making this spot a much better choice than checking during esteps
+    MSerial.checkRx();
 #endif
 
     // If current block is finished, reset pointer
     if (step_events_completed.wide >= current_block->step_event_count.wide) {
-#ifdef FILAMENT_SENSOR
-		fsensor_st_block_chunk(current_block, fsensor_counter);
+#if !defined(LIN_ADVANCE) && defined(FILAMENT_SENSOR)
+		fsensor_st_block_chunk(fsensor_counter);
 		fsensor_counter = 0;
 #endif //FILAMENT_SENSOR
 
       current_block = NULL;
       plan_discard_current_block();
     }
-#ifdef FILAMENT_SENSOR
-  	else if ((fsensor_counter >= fsensor_chunk_len))
+#if !defined(LIN_ADVANCE) && defined(FILAMENT_SENSOR)
+	else if ((abs(fsensor_counter) >= fsensor_chunk_len))
   	{
-      fsensor_st_block_chunk(current_block, fsensor_counter);
+      fsensor_st_block_chunk(fsensor_counter);
   	  fsensor_counter = 0;
   	}
 #endif //FILAMENT_SENSOR
@@ -1115,12 +896,105 @@ FORCE_INLINE void isr() {
 }
 
 #ifdef LIN_ADVANCE
-
-void clear_current_adv_vars() {
-  e_steps = 0; //Should be already 0 at an filament change event, but just to be sure..
-  current_adv_steps = 0;
+// Timer interrupt for E. e_steps is set in the main routine.
+
+FORCE_INLINE void advance_isr() {
+    if (step_events_completed.wide > LA_decelerate_after && current_adv_steps > final_adv_steps) {
+        // decompression
+        e_steps -= e_step_loops;
+        if (e_steps) WRITE_NC(E0_DIR_PIN, e_steps < 0? INVERT_E0_DIR: !INVERT_E0_DIR);
+        if(current_adv_steps > e_step_loops)
+            current_adv_steps -= e_step_loops;
+        else
+            current_adv_steps = 0;
+        nextAdvanceISR = eISR_Rate;
+    }
+    else if (step_events_completed.wide < LA_decelerate_after && current_adv_steps < max_adv_steps) {
+        // compression
+        e_steps += e_step_loops;
+        if (e_steps) WRITE_NC(E0_DIR_PIN, e_steps < 0? INVERT_E0_DIR: !INVERT_E0_DIR);
+        current_adv_steps += e_step_loops;
+        nextAdvanceISR = eISR_Rate;
+    }
+    else {
+        // advance steps completed
+        nextAdvanceISR = ADV_NEVER;
+        LA_phase = -1;
+        e_step_loops = 1;
+    }
 }
 
+FORCE_INLINE void advance_isr_scheduler() {
+    // Integrate the final timer value, accounting for scheduling adjustments
+    if(nextAdvanceISR && nextAdvanceISR != ADV_NEVER)
+    {
+        if(nextAdvanceISR > OCR1A)
+            nextAdvanceISR -= OCR1A;
+        else
+            nextAdvanceISR = 0;
+    }
+    if(nextMainISR > OCR1A)
+        nextMainISR -= OCR1A;
+    else
+        nextMainISR = 0;
+
+    // Run main stepping ISR if flagged
+    if (!nextMainISR)
+    {
+#ifdef LA_DEBUG_LOGIC
+        WRITE_NC(LOGIC_ANALYZER_CH0, true);
+#endif
+        isr();
+#ifdef LA_DEBUG_LOGIC
+        WRITE_NC(LOGIC_ANALYZER_CH0, false);
+#endif
+    }
+
+    // Run the next advance isr if triggered
+    bool eisr = !nextAdvanceISR;
+    if (eisr)
+    {
+#ifdef LA_DEBUG_LOGIC
+        WRITE_NC(LOGIC_ANALYZER_CH1, true);
+#endif
+        advance_isr();
+#ifdef LA_DEBUG_LOGIC
+        WRITE_NC(LOGIC_ANALYZER_CH1, false);
+#endif
+    }
+
+    // Tick E steps if any
+    if (e_steps && (LA_phase < 0 || LA_phase == eisr)) {
+        uint8_t max_ticks = (eisr? e_step_loops: step_loops);
+        max_ticks = min(abs(e_steps), max_ticks);
+        bool rev = (e_steps < 0);
+        do
+        {
+            WRITE_NC(E0_STEP_PIN, !INVERT_E_STEP_PIN);
+            e_steps += (rev? 1: -1);
+            WRITE_NC(E0_STEP_PIN, INVERT_E_STEP_PIN);
+#ifdef FILAMENT_SENSOR
+            fsensor_counter += (rev? -1: 1);
+#endif
+        }
+        while(--max_ticks);
+
+#ifdef FILAMENT_SENSOR
+        if (abs(fsensor_counter) >= fsensor_chunk_len)
+        {
+            fsensor_st_block_chunk(fsensor_counter);
+            fsensor_counter = 0;
+        }
+#endif
+    }
+
+    // Schedule the next closest tick, ignoring advance if scheduled too
+    // soon in order to avoid skewing the regular stepper acceleration
+    if (nextAdvanceISR != ADV_NEVER && (nextAdvanceISR + TCNT1 + 40) < nextMainISR)
+        OCR1A = nextAdvanceISR;
+    else
+        OCR1A = nextMainISR;
+}
 #endif // LIN_ADVANCE
 
 void st_init()
@@ -1347,18 +1221,49 @@ void st_init()
   // Plan the first interrupt after 8ms from now.
   OCR1A = 0x4000;
   TCNT1 = 0;
-  ENABLE_STEPPER_DRIVER_INTERRUPT();
 
 #ifdef LIN_ADVANCE
-    e_steps = 0;
-    current_adv_steps = 0;
+#ifdef LA_DEBUG_LOGIC
+  LOGIC_ANALYZER_CH0_ENABLE;
+  LOGIC_ANALYZER_CH1_ENABLE;
+  WRITE_NC(LOGIC_ANALYZER_CH0, false);
+  WRITE_NC(LOGIC_ANALYZER_CH1, false);
 #endif
-    
+
+  // Initialize state for the linear advance scheduler
+  nextMainISR = 0;
+  nextAdvanceISR = ADV_NEVER;
+  main_Rate = ADV_NEVER;
+  e_steps = 0;
+  e_step_loops = 1;
+  LA_phase = -1;
+  current_adv_steps = 0;
+#endif
+
   enable_endstops(true); // Start with endstops active. After homing they can be disabled
+
+  ENABLE_STEPPER_DRIVER_INTERRUPT();
   sei();
 }
 
 
+void st_reset_timer()
+{
+  // Clear a possible pending interrupt on OCR1A overflow.
+  TIFR1 |= 1 << OCF1A;
+  // Reset the counter.
+  TCNT1 = 0;
+  // Wake up after 1ms from now.
+  OCR1A = 2000;
+
+#ifdef LIN_ADVANCE
+  nextMainISR = 0;
+  if(nextAdvanceISR && nextAdvanceISR != ADV_NEVER)
+      nextAdvanceISR = 0;
+#endif
+}
+
+
 // Block until all buffered steps are executed
 void st_synchronize()
 {
@@ -1443,6 +1348,10 @@ void quickStop()
   DISABLE_STEPPER_DRIVER_INTERRUPT();
   while (blocks_queued()) plan_discard_current_block(); 
   current_block = NULL;
+#ifdef LIN_ADVANCE
+  nextAdvanceISR = ADV_NEVER;
+  current_adv_steps = 0;
+#endif
   st_reset_timer();
   ENABLE_STEPPER_DRIVER_INTERRUPT();
 }
@@ -1564,10 +1473,6 @@ void st_current_init() //Initialize Digipot Motor Current
 {
 #ifdef MOTOR_CURRENT_PWM_XY_PIN
   uint8_t SilentMode = eeprom_read_byte((uint8_t*)EEPROM_SILENT);
-  if (SilentMode == 0xff){ //set power to High Power (MK2.5) or Normal Power (MK3, unused)
-    SilentMode = SILENT_MODE_POWER;
-    eeprom_update_byte((uint8_t*)EEPROM_SILENT, SilentMode);
-  }
   SilentModeMenu = SilentMode;
     pinMode(MOTOR_CURRENT_PWM_XY_PIN, OUTPUT);
     pinMode(MOTOR_CURRENT_PWM_Z_PIN, OUTPUT);

+ 1 - 15
Firmware/stepper.h

@@ -37,12 +37,6 @@ void st_init();
 
 void isr();
 
-#ifdef LIN_ADVANCE
-  void advance_isr();
-  void advance_isr_scheduler();
-  void clear_current_adv_vars(); //Used to reset the built up pretension and remaining esteps on filament change.
-#endif
-
 // Block until all buffered steps are executed
 void st_synchronize();
 
@@ -62,15 +56,7 @@ float st_get_position_mm(uint8_t axis);
 
 // Call this function just before re-enabling the stepper driver interrupt and the global interrupts
 // to avoid a stepper timer overflow.
-FORCE_INLINE void st_reset_timer()
-{
-  // Clear a possible pending interrupt on OCR1A overflow.
-  TIFR1 |= 1 << OCF1A;
-  // Reset the counter.
-  TCNT1 = 0;
-  // Wake up after 1ms from now.
-  OCR1A = 2000;
-}
+void st_reset_timer();
 
 void checkHitEndstops(); //call from somewhere to create an serial error message with the locations the endstops where hit, in case they were triggered
 bool endstops_hit_on_purpose(); //avoid creation of the message, i.e. after homing and before a routine call of checkHitEndstops();

+ 15 - 3
Firmware/temperature.cpp

@@ -44,6 +44,8 @@
 #include "Timer.h"
 #include "Configuration_prusa.h"
 
+#include "config.h"
+
 //===========================================================================
 //=============================public variables============================
 //===========================================================================
@@ -71,6 +73,10 @@ int current_voltage_raw_pwr = 0;
 int current_voltage_raw_bed = 0;
 #endif
 
+#if IR_SENSOR_ANALOG
+int current_voltage_raw_IR = 0;
+#endif //IR_SENSOR_ANALOG
+
 int current_temperature_bed_raw = 0;
 float current_temperature_bed = 0.0;
   
@@ -505,7 +511,10 @@ void checkFanSpeed()
 		// we may even send some info to the LCD from here
 		fan_check_error = EFCE_FIXED;
 	}
-
+	if ((fan_check_error == EFCE_FIXED) && !PRINTER_ACTIVE){
+		fan_check_error = EFCE_OK; //if the issue is fixed while the printer is doing nothing, reenable processing immediately.
+		lcd_reset_alert_level(); //for another fan speed error
+	}
 	if ((fan_speed_errors[0] > max_extruder_fan_errors) && fans_check_enabled && (fan_check_error == EFCE_OK)) {
 		fan_speed_errors[0] = 0;
 		fanSpeedError(0); //extruder fan
@@ -870,7 +879,7 @@ static float analog2temp(int raw, uint8_t e) {
       SERIAL_ERROR_START;
       SERIAL_ERROR((int)e);
       SERIAL_ERRORLNPGM(" - Invalid extruder number !");
-      kill(PSTR(""), 6);
+      kill(NULL, 6);
       return 0.0;
   } 
   #ifdef HEATER_0_USES_MAX6675
@@ -1573,11 +1582,14 @@ void adc_ready(void) //callback from adc when sampling finished
 	current_voltage_raw_pwr = adc_values[ADC_PIN_IDX(VOLT_PWR_PIN)];
 #endif
 #ifdef AMBIENT_THERMISTOR
-	current_temperature_raw_ambient = adc_values[ADC_PIN_IDX(TEMP_AMBIENT_PIN)];
+	current_temperature_raw_ambient = adc_values[ADC_PIN_IDX(TEMP_AMBIENT_PIN)]; // 5->6
 #endif //AMBIENT_THERMISTOR
 #ifdef VOLT_BED_PIN
 	current_voltage_raw_bed = adc_values[ADC_PIN_IDX(VOLT_BED_PIN)]; // 6->9
 #endif
+#if IR_SENSOR_ANALOG
+     current_voltage_raw_IR = adc_values[ADC_PIN_IDX(VOLT_IR_PIN)];
+#endif //IR_SENSOR_ANALOG
 	temp_meas_ready = true;
 }
 

+ 5 - 0
Firmware/temperature.h

@@ -27,6 +27,8 @@
   #include "stepper.h"
 #endif
 
+#include "config.h"
+
 
 #ifdef SYSTEM_TIMER_2
 
@@ -74,6 +76,9 @@ extern int current_voltage_raw_pwr;
 extern int current_voltage_raw_bed;
 #endif
 
+#if IR_SENSOR_ANALOG
+extern int current_voltage_raw_IR;
+#endif //IR_SENSOR_ANALOG
 
 #if defined(CONTROLLERFAN_PIN) && CONTROLLERFAN_PIN > -1
   extern unsigned char soft_pwm_bed;

+ 8 - 8
Firmware/tmc2130.cpp

@@ -24,7 +24,7 @@ uint8_t tmc2130_current_h[4] = TMC2130_CURRENTS_H;
 uint8_t tmc2130_current_r[4] = TMC2130_CURRENTS_R;
 
 //running currents for homing
-uint8_t tmc2130_current_r_home[4] = {8, 10, 20, 18};
+uint8_t tmc2130_current_r_home[4] = TMC2130_CURRENTS_R_HOME;
 
 
 //pwm_ampl
@@ -40,7 +40,7 @@ uint8_t tmc2130_mres[4] = {0, 0, 0, 0}; //will be filed at begin of init
 
 
 uint8_t tmc2130_sg_thr[4] = {TMC2130_SG_THRS_X, TMC2130_SG_THRS_Y, TMC2130_SG_THRS_Z, TMC2130_SG_THRS_E};
-uint8_t tmc2130_sg_thr_home[4] = {3, 3, TMC2130_SG_THRS_Z, TMC2130_SG_THRS_E};
+uint8_t tmc2130_sg_thr_home[4] = TMC2130_SG_THRS_HOME;
 
 
 uint8_t tmc2130_sg_homing_axes_mask = 0x00;
@@ -427,7 +427,7 @@ void tmc2130_check_overtemp()
 
 void tmc2130_setup_chopper(uint8_t axis, uint8_t mres, uint8_t current_h, uint8_t current_r)
 {
-	uint8_t intpol = 1;
+	uint8_t intpol = (mres != 0); // intpol to 256 only if microsteps aren't 256
 	uint8_t toff = tmc2130_chopper_config[axis].toff; // toff = 3 (fchop = 27.778kHz)
 	uint8_t hstrt = tmc2130_chopper_config[axis].hstr; //initial 4, modified to 5
 	uint8_t hend = tmc2130_chopper_config[axis].hend; //original value = 1
@@ -600,7 +600,7 @@ void tmc2130_wr_THIGH(uint8_t axis, uint32_t val32)
 
 uint8_t tmc2130_usteps2mres(uint16_t usteps)
 {
-	uint8_t mres = 8; while (mres && (usteps >>= 1)) mres--;
+	uint8_t mres = 8; while (usteps >>= 1) mres--;
 	return mres;
 }
 
@@ -807,15 +807,15 @@ void tmc2130_goto_step(uint8_t axis, uint8_t step, uint8_t dir, uint16_t delay_u
 	{
 		dir = tmc2130_get_inv(axis)?0:1;
 		int steps = (int)step - (int)(mscnt >> shift);
-		if (steps < 0)
+		if (steps > static_cast<int>(cnt / 2))
 		{
 			dir ^= 1;
-			steps = -steps;
+			steps = cnt - steps; // This can create a negative step value
 		}
-		if (steps > static_cast<int>(cnt / 2))
+        if (steps < 0)
 		{
 			dir ^= 1;
-			steps = cnt - steps;
+			steps = -steps;
 		}
 		cnt = steps;
 	}

+ 594 - 353
Firmware/ultralcd.cpp

@@ -19,6 +19,8 @@
 #include "lcd.h"
 #include "menu.h"
 
+#include "backlight.h"
+
 #include "util.h"
 #include "mesh_bed_leveling.h"
 #include "mesh_bed_calibration.h"
@@ -45,6 +47,10 @@
 #include "io_atmega2560.h"
 #include "first_lay_cal.h"
 
+#include "fsensor.h"
+#include "adc.h"
+#include "config.h"
+
 
 int scrollstuff = 0;
 char longFilenameOLD[LONG_FILENAME_LENGTH];
@@ -52,6 +58,7 @@ char longFilenameOLD[LONG_FILENAME_LENGTH];
 
 static void lcd_sd_updir();
 static void lcd_mesh_bed_leveling_settings();
+static void lcd_backlight_menu();
 
 int8_t ReInitLCD = 0;
 
@@ -61,9 +68,6 @@ uint8_t SilentModeMenu_MMU = 1; //activate mmu unit stealth mode
 
 int8_t FSensorStateMenu = 1;
 
-extern bool fsensor_enable();
-extern void fsensor_disable();
-
 
 #ifdef SDCARD_SORT_ALPHA
 bool presort_flag = false;
@@ -111,7 +115,9 @@ static const char* lcd_display_message_fullscreen_nonBlocking_P(const char *msg,
 
 /* Different menus */
 static void lcd_status_screen();
+#if (LANG_MODE != 0)
 static void lcd_language_menu();
+#endif
 static void lcd_main_menu();
 static void lcd_tune_menu();
 //static void lcd_move_menu();
@@ -147,6 +153,10 @@ static void mmu_cut_filament_menu();
 static void lcd_menu_fails_stats();
 #endif //TMC2130 or FILAMENT_SENSOR
 
+#ifdef TMC2130
+static void lcd_belttest_v();
+#endif //TMC2130
+
 static void lcd_selftest_v();
 
 #ifdef TMC2130
@@ -193,6 +203,7 @@ enum class TestError : uint_least8_t
     SwappedFan,
     WiringFsensor,
     TriggeringFsensor,
+    FsensorLevel
 };
 
 static int  lcd_selftest_screen(TestScreen screen, int _progress, int _progress_scale, bool _clear, int _delay);
@@ -224,6 +235,9 @@ static FanCheck lcd_selftest_fan_auto(int _fan);
 static bool lcd_selftest_fsensor();
 #endif //PAT9125
 static bool selftest_irsensor();
+#if IR_SENSOR_ANALOG
+static bool lcd_selftest_IRsensor();
+#endif //IR_SENSOR_ANALOG
 static void lcd_selftest_error(TestError error, const char *_error_1, const char *_error_2);
 static void lcd_colorprint_change();
 #ifdef SNMM
@@ -236,7 +250,9 @@ static void fil_unload_menu();
 static void lcd_disable_farm_mode();
 static void lcd_set_fan_check();
 static void lcd_cutter_enabled();
+#ifdef SNMM
 static char snmm_stop_print_menu();
+#endif //SNMM
 #ifdef SDCARD_SORT_ALPHA
  static void lcd_sort_type_set();
 #endif
@@ -310,18 +326,24 @@ bool bSettings;                                   // flag (i.e. 'fake parameter'
 const char STR_SEPARATOR[] PROGMEM = "------------";
 
 
-static void lcd_implementation_drawmenu_sdfile_selected(uint8_t row, char* longFilename)
+static void lcd_implementation_drawmenu_sdfile_selected(uint8_t row, const char* filename, char* longFilename)
 {
     char c;
-    int enc_dif = lcd_encoder_diff;
+    int enc_dif = lcd_encoder_diff / ENCODER_PULSES_PER_STEP;
     uint8_t n = LCD_WIDTH - 1;
+
     for(uint_least8_t g = 0; g<4;g++){
       lcd_set_cursor(0, g);
     lcd_print(' ');
     }
-
     lcd_set_cursor(0, row);
     lcd_print('>');
+
+    if (longFilename[0] == '\0')
+    {
+        longFilename = filename;
+    }
+
     int i = 1;
     int j = 0;
     char* longFilenameTMP = longFilename;
@@ -339,7 +361,7 @@ static void lcd_implementation_drawmenu_sdfile_selected(uint8_t row, char* longF
           n = LCD_WIDTH - 1;
           for(int g = 0; g<300 ;g++){
 			  manage_heater();
-            if(LCD_CLICKED || ( enc_dif != lcd_encoder_diff )){
+            if(LCD_CLICKED || ( enc_dif != (lcd_encoder_diff / ENCODER_PULSES_PER_STEP))){
 				longFilenameTMP = longFilename;
 				*(longFilenameTMP + LCD_WIDTH - 2) = '\0';
 				i = 1;
@@ -537,7 +559,7 @@ static uint8_t menu_item_sdfile(const char*
 		if (lcd_draw_update)
 		{
 			if (lcd_encoder == menu_item)
-				lcd_implementation_drawmenu_sdfile_selected(menu_row, str_fnl);
+				lcd_implementation_drawmenu_sdfile_selected(menu_row, str_fn, str_fnl);
 			else
 				lcd_implementation_drawmenu_sdfile(menu_row, str_fn, str_fnl);
 		}
@@ -566,7 +588,7 @@ void lcdui_print_Z_coord(void)
     if (custom_message_type == CustomMsg::MeshBedLeveling)
         lcd_puts_P(_N("Z   --- "));
     else
-		lcd_printf_P(_N("Z%6.2f "), current_position[Z_AXIS]);
+		lcd_printf_P(_N("Z%6.2f%c"), current_position[Z_AXIS], axis_known_position[Z_AXIS]?' ':'?');
 }
 
 #ifdef PLANNER_DIAGNOSTICS
@@ -605,6 +627,19 @@ void lcdui_print_percent_done(void)
 	const char* src = is_usb_printing?_N("USB"):(IS_SD_PRINTING?_N(" SD"):_N("   "));
 	char per[4];
 	bool num = IS_SD_PRINTING || (PRINTER_ACTIVE && (print_percent_done_normal != PRINT_PERCENT_DONE_INIT));
+	if (!num || heating_status) // either not printing or heating
+	{
+		const int8_t sheetNR = eeprom_read_byte(&(EEPROM_Sheets_base->active_sheet));
+		const int8_t nextSheet = eeprom_next_initialized_sheet(sheetNR);
+		if ((nextSheet >= 0) && (sheetNR != nextSheet))
+		{
+			char sheet[8];
+			eeprom_read_block(sheet, EEPROM_Sheets_base->s[sheetNR].name, 7);
+			sheet[7] = '\0';
+			lcd_printf_P(PSTR("%-7s"),sheet);
+			return; //do not also print the percentage
+		}
+	}
 	sprintf_P(per, num?_N("%3hhd"):_N("---"), calc_percent_done());
 	lcd_printf_P(_N("%3S%3s%%"), src, per);
 }
@@ -709,10 +744,10 @@ void lcdui_print_status_line(void)
 {
 	if (IS_SD_PRINTING)
 	{
-		if (strcmp(longFilenameOLD, card.longFilename) != 0)
+		if (strcmp(longFilenameOLD, (card.longFilename[0] ? card.longFilename : card.filename)) != 0)
 		{
 			memset(longFilenameOLD, '\0', strlen(longFilenameOLD));
-			sprintf_P(longFilenameOLD, PSTR("%s"), card.longFilename);
+			sprintf_P(longFilenameOLD, PSTR("%s"), (card.longFilename[0] ? card.longFilename : card.filename));
 			scrollstuff = 0;
 		}
 	}
@@ -760,16 +795,16 @@ void lcdui_print_status_line(void)
 	}
 	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)
+		if(strlen(longFilenameOLD) > LCD_WIDTH)
 		{
 			int inters = 0;
 			int gh = scrollstuff;
 			while (((gh - scrollstuff) < LCD_WIDTH) && (inters == 0))
 			{
-				if (card.longFilename[gh] == '\0')
+				if (longFilenameOLD[gh] == '\0')
 				{
 					lcd_set_cursor(gh - scrollstuff, 3);
-					lcd_print(card.longFilename[gh - 1]);
+					lcd_print(longFilenameOLD[gh - 1]);
 					scrollstuff = 0;
 					gh = scrollstuff;
 					inters = 1;
@@ -777,7 +812,7 @@ void lcdui_print_status_line(void)
 				else
 				{
 					lcd_set_cursor(gh - scrollstuff, 3);
-					lcd_print(card.longFilename[gh - 1]);
+					lcd_print(longFilenameOLD[gh - 1]);
 					gh++;
 				}
 			}
@@ -785,7 +820,7 @@ void lcdui_print_status_line(void)
 		}
 		else
 		{
-			lcd_print(longFilenameOLD);
+			lcd_printf_P(PSTR("%-20s"), longFilenameOLD);
 		}
 	}
 	else
@@ -838,12 +873,13 @@ void lcdui_print_status_line(void)
 			break;
 		case CustomMsg::TempCal: // PINDA temp calibration in progress
 			{
+				char statusLine[LCD_WIDTH + 1];
+				sprintf_P(statusLine, PSTR("%-20S"), _T(MSG_TEMP_CALIBRATION));
 				char progress[4];
+				sprintf_P(progress, PSTR("%d/6"), custom_message_state);
+				memcpy(statusLine + 12, progress, sizeof(progress) - 1);
 				lcd_set_cursor(0, 3);
-				lcd_puts_P(_T(MSG_TEMP_CALIBRATION));
-				lcd_set_cursor(12, 3);
-				sprintf(progress, "%d/6", custom_message_state);
-				lcd_print(progress);
+				lcd_print(statusLine);
 			}
 			break;
 		case CustomMsg::TempCompPreheat: // temp compensation preheat
@@ -1025,7 +1061,6 @@ static void lcd_status_screen()
 	}
 
 	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
 	)
 	{
@@ -1072,12 +1107,9 @@ void lcd_commands()
 		if (!blocks_queued() && !homing_flag)
 		{
 			lcd_setstatuspgm(_i("Print paused"));////MSG_PRINT_PAUSED c=20 r=1
-			long_pause();
-               if (lcd_commands_type == LcdCommands::LongPause) // !!! because "lcd_commands_type" can be changed during/inside "long_pause()"
-               {
-                    lcd_commands_type = LcdCommands::Idle;
-                    lcd_commands_step = 0;
-               }
+            lcd_commands_type = LcdCommands::Idle;
+            lcd_commands_step = 0;
+            long_pause();
 		}
 	}
 
@@ -1439,98 +1471,6 @@ void lcd_commands()
 
 #endif // not SNMM
 
-	if (lcd_commands_type == LcdCommands::StopPrint)   /// stop print
-	{
-		
-
-		if (lcd_commands_step == 0) 
-		{ 
-			lcd_commands_step = 6; 
-		}
-
-		if (lcd_commands_step == 1 && !blocks_queued())
-		{
-			lcd_commands_step = 0;
-			lcd_commands_type = LcdCommands::Idle;
-			lcd_setstatuspgm(_T(WELCOME_MSG));
-			custom_message_type = CustomMsg::Status;
-			isPrintPaused = false;
-		}
-		if (lcd_commands_step == 2 && !blocks_queued())
-		{
-			setTargetBed(0);
-			enquecommand_P(PSTR("M104 S0")); //set hotend temp to 0
-
-			manage_heater();
-			lcd_setstatuspgm(_T(WELCOME_MSG));
-			cancel_heatup = false;
-			lcd_commands_step = 1;
-		}
-		if (lcd_commands_step == 3 && !blocks_queued())
-		{
-      // M84: Disable steppers.
-			enquecommand_P(PSTR("M84"));
-			autotempShutdown();
-			lcd_commands_step = 2;
-		}
-		if (lcd_commands_step == 4 && !blocks_queued())
-		{
-			lcd_setstatuspgm(_T(MSG_PLEASE_WAIT));
-      // G90: Absolute positioning.
-			enquecommand_P(PSTR("G90"));
-      // M83: Set extruder to relative mode.
-			enquecommand_P(PSTR("M83"));
-			#ifdef X_CANCEL_POS 
-			enquecommand_P(PSTR("G1 X"  STRINGIFY(X_CANCEL_POS) " Y" STRINGIFY(Y_CANCEL_POS) " E0 F7000"));
-			#else
-			enquecommand_P(PSTR("G1 X50 Y" STRINGIFY(Y_MAX_POS) " E0 F7000"));
-			#endif
-			lcd_ignore_click(false);
-			if (mmu_enabled)
-				lcd_commands_step = 8;
-			else
-				lcd_commands_step = 3;
-		}
-		if (lcd_commands_step == 5 && !blocks_queued())
-		{
-			lcd_setstatuspgm(_T(MSG_PRINT_ABORTED));
-      // G91: Set to relative positioning.
-			enquecommand_P(PSTR("G91"));
-      // Lift up.
-			enquecommand_P(PSTR("G1 Z15 F1500"));
-			if (axis_known_position[X_AXIS] && axis_known_position[Y_AXIS]) lcd_commands_step = 4;
-			else lcd_commands_step = 3;
-		}
-		if (lcd_commands_step == 6 && !blocks_queued())
-		{
-			lcd_setstatuspgm(_T(MSG_PRINT_ABORTED));
-			cancel_heatup = true;
-			setTargetBed(0);
-			if (mmu_enabled)
-				setAllTargetHotends(0);
-			manage_heater();
-			custom_message_type = CustomMsg::FilamentLoading;
-			lcd_commands_step = 5;
-		}
-		if (lcd_commands_step == 7 && !blocks_queued())
-		{
-			if (mmu_enabled)
-				enquecommand_P(PSTR("M702 C")); //current
-			else
-				switch(snmm_stop_print_menu())
-				{
-				case 0: enquecommand_P(PSTR("M702")); break;//all 
-				case 1: enquecommand_P(PSTR("M702 U")); break; //used
-				case 2: enquecommand_P(PSTR("M702 C")); break; //current
-				default: enquecommand_P(PSTR("M702")); break;
-				}
-			lcd_commands_step = 3;
-		}
-		if (lcd_commands_step == 8 && !blocks_queued()) { //step 8 is here for delay (going to next step after execution of all gcodes from step 4)
-			lcd_commands_step = 7; 
-		}
-	}
-
 	if (lcd_commands_type == LcdCommands::FarmModeConfirm)   /// farm mode confirm
 	{
 
@@ -1634,9 +1574,8 @@ void lcd_return_to_status()
 //! @brief Pause print, disable nozzle heater, move to park position
 void lcd_pause_print()
 {
+    stop_and_save_print_to_ram(0.0, -default_retraction);
     lcd_return_to_status();
-    stop_and_save_print_to_ram(0.0,0.0);
-    setAllTargetHotends(0);
     isPrintPaused = true;
     if (LcdCommands::Idle == lcd_commands_type)
     {
@@ -1843,8 +1782,8 @@ static void lcd_menu_fails_stats_total()
 //! @code{.unparsed}
 //! |01234567890123456789|
 //! |Last print failures |	c=20 r=1
-//! | Power failures: 000|	c=14 r=1
-//! | Filam. runouts: 000|	c=14 r=1
+//! | Power failures  000|	c=14 r=1
+//! | Filam. runouts  000|	c=14 r=1
 //! | Crash   X:000 Y:000|	c=7 r=1
 //! ----------------------
 //! @endcode
@@ -1890,6 +1829,7 @@ static void lcd_menu_fails_stats()
 }
 
 #elif defined(FILAMENT_SENSOR)
+static const char failStatsFmt[] PROGMEM = "%S\n" " %-16.16S%-3d\n" "%S\n" " %-16.16S%-3d\n";
 //! 
 //! @brief Print last print and total filament run outs
 //! 
@@ -1900,9 +1840,9 @@ static void lcd_menu_fails_stats()
 //! @code{.unparsed}
 //! |01234567890123456789|
 //! |Last print failures |	c=20 r=1
-//! | Filam. runouts: 000|	c=14 r=1
+//! | Filam. runouts  000|	c=14 r=1
 //! |Total failures      |	c=20 r=1
-//! | Filam. runouts: 000|	c=14 r=1
+//! | Filam. runouts  000|	c=14 r=1
 //! ----------------------
 //! @endcode
 //! @todo Positioning of the messages and values on LCD aren't fixed to their exact place. This causes issues with translations.
@@ -1912,11 +1852,13 @@ static void lcd_menu_fails_stats()
     uint8_t filamentLast = eeprom_read_byte((uint8_t*)EEPROM_FERROR_COUNT);
     uint16_t filamentTotal = eeprom_read_word((uint16_t*)EEPROM_FERROR_COUNT_TOT);
 	lcd_home();
-    lcd_printf_P(PSTR("Last print failures\n"  ////c=20 r=1 
-        " Filam. runouts  %-3d\n"   ////c=14 r=1
-        "Total failures\n"  ////c=20 r=1
-        " Filam. runouts  %-3d"), filamentLast, filamentTotal);  ////c=14 r=1
-    menu_back_if_clicked();
+	lcd_printf_P(failStatsFmt, 
+        _i("Last print failures"),   ////c=20 r=1
+        _i("Filam. runouts"), filamentLast,   ////c=14 r=1
+        _i("Total failures"),  ////c=20 r=1
+        _i("Filam. runouts"), filamentTotal);   ////c=14 r=1
+
+	menu_back_if_clicked();
 }
 #else
 static void lcd_menu_fails_stats()
@@ -1998,11 +1940,11 @@ static void lcd_menu_temperatures()
     menu_back_if_clicked();
 }
 
-#if defined (VOLT_BED_PIN) || defined (VOLT_PWR_PIN)
+#if defined (VOLT_BED_PIN) || defined (VOLT_PWR_PIN) || IR_SENSOR_ANALOG
 #define VOLT_DIV_R1 10000
 #define VOLT_DIV_R2 2370
 #define VOLT_DIV_FAC ((float)VOLT_DIV_R2 / (VOLT_DIV_R2 + VOLT_DIV_R1))
-#define VOLT_DIV_REF 5
+
 //! @brief Show Voltages
 //!
 //! @code{.unparsed}
@@ -2020,10 +1962,17 @@ static void lcd_menu_voltages()
 	float volt_pwr = VOLT_DIV_REF * ((float)current_voltage_raw_pwr / (1023 * OVERSAMPLENR)) / VOLT_DIV_FAC;
 	float volt_bed = VOLT_DIV_REF * ((float)current_voltage_raw_bed / (1023 * OVERSAMPLENR)) / VOLT_DIV_FAC;
 	lcd_home();
-	lcd_printf_P(PSTR(" PWR:      %d.%01dV\n" " BED:      %d.%01dV"), (int)volt_pwr, (int)(10*fabs(volt_pwr - (int)volt_pwr)), (int)volt_bed, (int)(10*fabs(volt_bed - (int)volt_bed)));
-    menu_back_if_clicked();
+#if !IR_SENSOR_ANALOG
+	lcd_printf_P(PSTR("\n"));
+#endif //!IR_SENSOR_ANALOG
+     lcd_printf_P(PSTR(" PWR:      %4.1fV\n" " BED:      %4.1fV"), volt_pwr, volt_bed);
+#if IR_SENSOR_ANALOG
+     float volt_IR = VOLT_DIV_REF * ((float)current_voltage_raw_IR / (1023 * OVERSAMPLENR));
+     lcd_printf_P(PSTR("\n IR :       %3.1fV"),volt_IR);
+#endif //IR_SENSOR_ANALOG
+     menu_back_if_clicked();
 }
-#endif //defined VOLT_BED_PIN || defined VOLT_PWR_PIN
+#endif //defined (VOLT_BED_PIN) || defined (VOLT_PWR_PIN) || IR_SENSOR_ANALOG
 
 #ifdef TMC2130
 //! @brief Show Belt Status
@@ -2250,6 +2199,9 @@ static void lcd_support_menu()
 void lcd_set_fan_check() {
 	fans_check_enabled = !fans_check_enabled;
 	eeprom_update_byte((unsigned char *)EEPROM_FAN_CHECK_ENABLED, fans_check_enabled);
+#ifdef FANCHECK
+	if (fans_check_enabled == false) fan_check_error = EFCE_OK; //reset error if fanCheck is disabled during error. Allows resuming print.
+#endif //FANCHECK
 }
 
 #ifdef MMU_HAS_CUTTER
@@ -2371,9 +2323,11 @@ void mFilamentItem(uint16_t nTemp, uint16_t nTempBed)
             {
                 lcd_commands_type = LcdCommands::Layer1Cal;
             }
-            else if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE))
+            else
             {
-                lcd_wizard(WizState::LoadFilHot);
+                raise_z_above(MIN_Z_FOR_PREHEAT);
+                if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE))
+                    lcd_wizard(WizState::LoadFilHot);
             }
             return;
         }
@@ -3014,7 +2968,7 @@ static void lcd_menu_xyz_y_min()
 	for (uint8_t i = 0; i < 2; i++)
 	{
 		lcd_set_cursor(11,2+i);
-		if (distanceMin[i] >= 200) lcd_puts_P(_N("N/A"));  ////c=3 r=1
+		if (distanceMin[i] >= 200) lcd_puts_P(_T(MSG_NA)); ////c=3 r=1
 		else lcd_printf_P(_N("%6.2fmm"), distanceMin[i]);
 	}
     if (lcd_clicked())
@@ -3060,7 +3014,7 @@ static void lcd_menu_xyz_skew()
 	}
 	else{
 		lcd_set_cursor(15,0);
-		lcd_puts_P(_N("N/A"));
+		lcd_puts_P(_T(MSG_NA));
 	}
     if (lcd_clicked())
         menu_goto(lcd_menu_xyz_offset, 0, true, true);
@@ -3446,6 +3400,8 @@ void lcd_wait_for_cool_down() {
 	lcd_set_custom_characters_degree();
 	setAllTargetHotends(0);
 	setTargetBed(0);
+	int fanSpeedBckp = fanSpeed;
+	fanSpeed = 255;
 	while ((degHotend(0)>MAX_HOTEND_TEMP_CALIBRATION) || (degBed() > MAX_BED_TEMP_CALIBRATION)) {
 		lcd_display_message_fullscreen_P(_i("Waiting for nozzle and bed cooling"));////MSG_WAITING_TEMP c=20 r=3
 
@@ -3464,6 +3420,7 @@ void lcd_wait_for_cool_down() {
 		delay_keep_alive(1000);
 		serialecho_temperatures();
 	}
+	fanSpeed = fanSpeedBckp;
 	lcd_set_custom_characters_arrows();
 	lcd_update_enable(true);
 }
@@ -3994,13 +3951,13 @@ static void lcd_print_state(uint8_t state)
 {
 	switch (state) {
 		case STATE_ON:
-			lcd_puts_P(_i("  1"));
+			lcd_puts_P(_N("  1"));
 		break;
 		case STATE_OFF:
-			lcd_puts_P(_i("  0"));
+			lcd_puts_P(_N("  0"));
 		break;
 		default: 
-			lcd_puts_P(_i("N/A"));
+			lcd_puts_P(_T(MSG_NA));
 		break;
 	}
 }
@@ -4013,7 +3970,8 @@ static void lcd_show_sensors_state()
 	uint8_t idler_state = STATE_NA;
 
 	pinda_state = READ(Z_MIN_PIN);
-	if (mmu_enabled) {
+	if (mmu_enabled && ((_millis() - mmu_last_finda_response) < 1000ul) )
+	{
 		finda_state = mmu_finda;
 	}
 	if (ir_sensor_detected) {
@@ -4070,7 +4028,7 @@ void prusa_statistics(int _message, uint8_t _fil_nr) {
 		{   
 			prusa_statistics_case0(15);
 		}
-		else if (isPrintPaused || card.paused) 
+		else if (isPrintPaused)
 		{
 			prusa_statistics_case0(14);
 		}
@@ -4773,10 +4731,10 @@ void lcd_toshiba_flash_air_compatibility_toggle()
 //!
 //! @code{.unparsed}
 //! |01234567890123456789|
-//! |[Smooth1]Live adj. Z|  c=11
-//! |value set, continue |  c=20
-//! |or start from zero? |  c=20
-//! |>Continue Reset     |  c=a, c=b, a+b = 18
+//! |Sheet Smooth1 actual|  c=a, c=b, a+b = 13
+//! |Z offset: -1.480 mm |  c=a, c=b, a+b = 14
+//! |>Continue           |  c=19
+//! | Start from zero    |  c=19
 //! ----------------------
 //! @endcode
 void lcd_first_layer_calibration_reset()
@@ -4814,8 +4772,9 @@ void lcd_first_layer_calibration_reset()
     char sheet_name[sizeof(Sheet::name)];
     eeprom_read_block(sheet_name, &EEPROM_Sheets_base->s[(eeprom_read_byte(&(EEPROM_Sheets_base->active_sheet)))].name, sizeof(Sheet::name));
     lcd_set_cursor(0, 0);
-    lcd_printf_P(_i("[%.7s]Live adj. Z\nvalue set, continue\nor start from zero?\n%cContinue%cReset"), //// \n denotes line break, %.7s is replaced by 7 character long sheet name, %+1.3f is replaced by 6 character long floating point number, %c is replaced by > or white space (one character) based on whether first or second option is selected. % denoted place holders can not be reordered. r=4
-            sheet_name, menuData->reset ? ' ' : '>', menuData->reset ? '>' : ' ');
+    float offset = static_cast<int16_t>(eeprom_read_word(reinterpret_cast<uint16_t*>(&EEPROM_Sheets_base->s[(eeprom_read_byte(&(EEPROM_Sheets_base->active_sheet)))].z_offset)))/cs.axis_steps_per_unit[Z_AXIS];
+    lcd_printf_P(_i("Sheet %.7s\nZ offset: %+1.3f mm\n%cContinue\n%cStart from zero"), //// \n denotes line break, %.7s is replaced by 7 character long sheet name, %+1.3f is replaced by 6 character long floating point number, %c is replaced by > or white space (one character) based on whether first or second option is selected. % denoted place holders can not be reordered. r=4
+            sheet_name, offset, menuData->reset ? ' ' : '>', menuData->reset ? '>' : ' ');
 
 }
 
@@ -4887,6 +4846,7 @@ void lcd_wizard() {
 	}
 }
 
+#if (LANG_MODE != 0)
 void lcd_language()
 {
 	lcd_update_enable(true);
@@ -4906,6 +4866,7 @@ void lcd_language()
 	else
 		lang_select(LANG_ID_PRI);
 }
+#endif
 
 static void wait_preheat()
 {
@@ -4929,12 +4890,12 @@ static void lcd_wizard_load()
 {
 	if (mmu_enabled)
 	{
-		lcd_show_fullscreen_message_and_wait_P(_i("Please insert filament to the first tube of MMU, then press the knob to load it."));////c=20 r=8
+		lcd_show_fullscreen_message_and_wait_P(_i("Please insert filament into the first tube of the MMU, then press the knob to load it."));////c=20 r=8
 		tmp_extruder = 0;
 	} 
 	else
 	{
-		lcd_show_fullscreen_message_and_wait_P(_i("Please insert filament to the extruder, then press knob to load it."));////MSG_WIZARD_LOAD_FILAMENT c=20 r=8
+		lcd_show_fullscreen_message_and_wait_P(_i("Please insert filament into the extruder, then press the knob to load it."));////MSG_WIZARD_LOAD_FILAMENT c=20 r=8
 	}	
 	lcd_update_enable(false);
 	lcd_clear();
@@ -4958,7 +4919,7 @@ static void wizard_lay1cal_message(bool cold)
     if (mmu_enabled)
     {
         lcd_show_fullscreen_message_and_wait_P(
-                _i("First you will select filament you wish to use for calibration. Then select temperature which matches your material."));
+                _i("Choose a filament for the First Layer Calibration and select it in the on-screen menu."));
     }
     else if (cold)
     {
@@ -4966,7 +4927,7 @@ static void wizard_lay1cal_message(bool cold)
                 _i("Select temperature which matches your material."));
     }
     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
+            _i("The printer will start printing a zig-zag line. Rotate the knob until you reach the optimal height. Check the pictures in the handbook (Calibration chapter).")); ////MSG_WIZARD_V2_CAL_2 c=20 r=12
 }
 
 //! @brief Printer first run wizard (Selftest and calibration)
@@ -5014,8 +4975,10 @@ void lcd_wizard(WizState state)
 	// Make sure EEPROM_WIZARD_ACTIVE is true if entering using different entry point
 	// other than WizState::Run - it is useful for debugging wizard.
 	if (state != S::Run) eeprom_update_byte((uint8_t*)EEPROM_WIZARD_ACTIVE, 1);
-
-	while (!end) {
+    
+    FORCE_BL_ON_START;
+	
+    while (!end) {
 		printf_P(PSTR("Wizard state: %d\n"), state);
 		switch (state) {
 		case S::Run: //Run wizard?
@@ -5094,7 +5057,7 @@ void lcd_wizard(WizState state)
 			setTargetBed(PLA_PREHEAT_HPB_TEMP);
 			if (mmu_enabled)
 			{
-			    wizard_event = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Is any filament loaded?"), true);////c=20 r=2
+			    wizard_event = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Is filament loaded?"), true);////c=20 r=2
 			} else
 			{
 			    wizard_event = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Is filament loaded?"), true);////MSG_WIZARD_FILAMENT_LOADED c=20 r=2
@@ -5139,7 +5102,7 @@ void lcd_wizard(WizState state)
 			}
 			else
 			{
-			    lcd_show_fullscreen_message_and_wait_P(_i("If you have more steel sheets you can calibrate additional presets in Settings / HW Setup / Steel sheets."));
+			    lcd_show_fullscreen_message_and_wait_P(_i("If you have additional steel sheets, calibrate their presets in Settings - HW Setup - Steel sheets."));
 				state = S::Finish;
 			}
 			break;
@@ -5151,7 +5114,9 @@ void lcd_wizard(WizState state)
 		default: break;
 		}
 	}
-
+    
+    FORCE_BL_ON_END;
+    
 	printf_P(_N("Wizard end state: %d\n"), state);
 	switch (state) { //final message
 	case S::Restore: //printer was already calibrated
@@ -5212,29 +5177,29 @@ do\
         if (fsensor_not_responding && (mmu_enabled == false))\
         {\
             /* Filament sensor not working*/\
-            MENU_ITEM_FUNCTION_P(_i("Fil. sensor [N/A]"), lcd_fsensor_state_set);/*////MSG_FSENSOR_NA*/\
-            MENU_ITEM_SUBMENU_P(_T(MSG_FSENS_AUTOLOAD_NA), lcd_fsensor_fail);\
+            MENU_ITEM_TOGGLE_P(_T(MSG_FSENSOR), _T(MSG_NA), lcd_fsensor_state_set);/*////MSG_FSENSOR_NA*/\
+            MENU_ITEM_TOGGLE_P(_T(MSG_FSENSOR_AUTOLOAD), NULL, lcd_fsensor_fail);\
         }\
         else\
         {\
             /* Filament sensor turned off, working, no problems*/\
-            MENU_ITEM_FUNCTION_P(_T(MSG_FSENSOR_OFF), lcd_fsensor_state_set);\
+            MENU_ITEM_TOGGLE_P(_T(MSG_FSENSOR), _T(MSG_OFF), lcd_fsensor_state_set);\
             if (mmu_enabled == false)\
             {\
-                MENU_ITEM_SUBMENU_P(_T(MSG_FSENS_AUTOLOAD_NA), lcd_filament_autoload_info);\
+                MENU_ITEM_TOGGLE_P(_T(MSG_FSENSOR_AUTOLOAD), NULL, lcd_filament_autoload_info);\
             }\
         }\
     }\
     else\
     {\
         /* Filament sensor turned on, working, no problems*/\
-        MENU_ITEM_FUNCTION_P(_T(MSG_FSENSOR_ON), lcd_fsensor_state_set);\
+        MENU_ITEM_TOGGLE_P(_T(MSG_FSENSOR), _T(MSG_ON), lcd_fsensor_state_set);\
         if (mmu_enabled == false)\
         {\
             if (fsensor_autoload_enabled)\
-                MENU_ITEM_FUNCTION_P(_i("F. autoload  [on]"), lcd_set_filament_autoload);/*////MSG_FSENS_AUTOLOAD_ON c=17 r=1*/\
+                MENU_ITEM_TOGGLE_P(_T(MSG_FSENSOR_AUTOLOAD), _T(MSG_ON), lcd_set_filament_autoload);/*////MSG_FSENS_AUTOLOAD_ON c=17 r=1*/\
             else\
-                MENU_ITEM_FUNCTION_P(_i("F. autoload [off]"), lcd_set_filament_autoload);/*////MSG_FSENS_AUTOLOAD_OFF c=17 r=1*/\
+                MENU_ITEM_TOGGLE_P(_T(MSG_FSENSOR_AUTOLOAD), _T(MSG_OFF), lcd_set_filament_autoload);/*////MSG_FSENS_AUTOLOAD_OFF c=17 r=1*/\
             /*if (fsensor_oq_meassure_enabled)*/\
                 /*MENU_ITEM_FUNCTION_P(_i("F. OQ meass. [on]"), lcd_set_filament_oq_meass);*//*////MSG_FSENS_OQMEASS_ON c=17 r=1*/\
             /*else*/\
@@ -5254,60 +5219,58 @@ static void auto_deplete_switch()
     eeprom_update_byte((unsigned char *)EEPROM_AUTO_DEPLETE, lcd_autoDeplete);
 }
 
-static bool settingsAutoDeplete()
+static void settingsAutoDeplete()
 {
     if (mmu_enabled)
     {
         if (!fsensor_enabled)
         {
-            if (menu_item_text_P(_i("SpoolJoin   [N/A]"))) return true;
+            MENU_ITEM_TOGGLE_P(_T(MSG_AUTO_DEPLETE), _T(MSG_NA), NULL);
         }
         else if (lcd_autoDeplete)
         {
-            if (menu_item_function_P(_i("SpoolJoin    [on]"), auto_deplete_switch)) return true;
+            MENU_ITEM_TOGGLE_P(_T(MSG_AUTO_DEPLETE), _T(MSG_ON), auto_deplete_switch);
         }
         else
         {
-            if (menu_item_function_P(_i("SpoolJoin   [off]"), auto_deplete_switch)) return true;
+            MENU_ITEM_TOGGLE_P(_T(MSG_AUTO_DEPLETE), _T(MSG_OFF), auto_deplete_switch);
         }
     }
-    return false;
 }
 
 #define SETTINGS_AUTO_DEPLETE \
 do\
 {\
-    if(settingsAutoDeplete()) return;\
+    settingsAutoDeplete();\
 }\
 while(0)\
 
 #ifdef MMU_HAS_CUTTER
-static bool settingsCutter()
+static void settingsCutter()
 {
     if (mmu_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
+            MENU_ITEM_TOGGLE_P(_T(MSG_CUTTER), _T(MSG_ON), lcd_cutter_enabled);
         }
 #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
+            MENU_ITEM_TOGGLE_P(_T(MSG_CUTTER), _i("Always"), lcd_cutter_enabled);
         }
 #endif
         else
         {
-            if (menu_item_function_P(_i("Cutter      [off]"), lcd_cutter_enabled)) return true;//// c=17 r=1
+            MENU_ITEM_TOGGLE_P(_T(MSG_CUTTER), _T(MSG_OFF), lcd_cutter_enabled);
         }
     }
-    return false;
 }
 
 #define SETTINGS_CUTTER \
 do\
 {\
-    if(settingsCutter()) return;\
+    settingsCutter();\
 }\
 while(0)
 #else
@@ -5322,18 +5285,15 @@ do\
     {\
         if (SilentModeMenu == SILENT_MODE_NORMAL)\
         {\
-            MENU_ITEM_FUNCTION_P(_T(MSG_STEALTH_MODE_OFF), lcd_silent_mode_set);\
+            MENU_ITEM_TOGGLE_P(_T(MSG_MODE), _T(MSG_NORMAL), lcd_silent_mode_set);\
         }\
-        else MENU_ITEM_FUNCTION_P(_T(MSG_STEALTH_MODE_ON), lcd_silent_mode_set);\
+        else MENU_ITEM_TOGGLE_P(_T(MSG_MODE), _T(MSG_STEALTH), lcd_silent_mode_set);\
         if (SilentModeMenu == SILENT_MODE_NORMAL)\
         {\
-            if (lcd_crash_detect_enabled())\
-            {\
-                MENU_ITEM_FUNCTION_P(_T(MSG_CRASHDETECT_ON), crash_mode_switch);\
-            }\
-            else MENU_ITEM_FUNCTION_P(_T(MSG_CRASHDETECT_OFF), crash_mode_switch);\
+            if (lcd_crash_detect_enabled()) MENU_ITEM_TOGGLE_P(_T(MSG_CRASHDETECT), _T(MSG_ON), crash_mode_switch);\
+            else MENU_ITEM_TOGGLE_P(_T(MSG_CRASHDETECT), _T(MSG_OFF), crash_mode_switch);\
         }\
-        else MENU_ITEM_SUBMENU_P(_T(MSG_CRASHDETECT_NA), lcd_crash_mode_info);\
+        else MENU_ITEM_TOGGLE_P(_T(MSG_CRASHDETECT), NULL, lcd_crash_mode_info);\
     }\
 }\
 while (0)
@@ -5347,16 +5307,16 @@ do\
         switch (SilentModeMenu)\
         {\
         case SILENT_MODE_POWER:\
-            MENU_ITEM_FUNCTION_P(_T(MSG_SILENT_MODE_OFF), lcd_silent_mode_set);\
+            MENU_ITEM_TOGGLE_P(_T(MSG_MODE), _T(MSG_HIGH_POWER), lcd_silent_mode_set);\
             break;\
         case SILENT_MODE_SILENT:\
-            MENU_ITEM_FUNCTION_P(_T(MSG_SILENT_MODE_ON), lcd_silent_mode_set);\
+            MENU_ITEM_TOGGLE_P(_T(MSG_MODE), _T(MSG_SILENT), lcd_silent_mode_set);\
             break;\
         case SILENT_MODE_AUTO:\
-            MENU_ITEM_FUNCTION_P(_T(MSG_AUTO_MODE_ON), lcd_silent_mode_set);\
+            MENU_ITEM_TOGGLE_P(_T(MSG_MODE), _T(MSG_AUTO_POWER), lcd_silent_mode_set);\
             break;\
         default:\
-            MENU_ITEM_FUNCTION_P(_T(MSG_SILENT_MODE_OFF), lcd_silent_mode_set);\
+            MENU_ITEM_TOGGLE_P(_T(MSG_MODE), _T(MSG_HIGH_POWER), lcd_silent_mode_set);\
             break; /* (probably) not needed*/\
         }\
     }\
@@ -5370,8 +5330,8 @@ do\
 {\
 	if (mmu_enabled)\
 	{\
-		if (SilentModeMenu_MMU == 0) MENU_ITEM_FUNCTION_P(_i("MMU Mode [Normal]"), lcd_silent_mode_mmu_set); \
-		else MENU_ITEM_FUNCTION_P(_i("MMU Mode[Stealth]"), lcd_silent_mode_mmu_set); \
+		if (SilentModeMenu_MMU == 0) MENU_ITEM_TOGGLE_P(_T(MSG_MMU_MODE), _T(MSG_NORMAL), lcd_silent_mode_mmu_set);\
+		else MENU_ITEM_TOGGLE_P(_T(MSG_MMU_MODE), _T(MSG_STEALTH), lcd_silent_mode_mmu_set);\
 	}\
 }\
 while (0) 
@@ -5384,9 +5344,9 @@ while (0)
 do\
 {\
     if (card.ToshibaFlashAir_isEnabled())\
-        MENU_ITEM_FUNCTION_P(_i("SD card [flshAir]"), lcd_toshiba_flash_air_compatibility_toggle);/*////MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON c=19 r=1*/\
+        MENU_ITEM_TOGGLE_P(_T(MSG_SD_CARD), _T(MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY), lcd_toshiba_flash_air_compatibility_toggle);\
     else\
-        MENU_ITEM_FUNCTION_P(_i("SD card  [normal]"), lcd_toshiba_flash_air_compatibility_toggle);/*////MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF c=19 r=1*/\
+        MENU_ITEM_TOGGLE_P(_T(MSG_SD_CARD), _T(MSG_NORMAL), lcd_toshiba_flash_air_compatibility_toggle);\
 \
     if (!farm_mode)\
     {\
@@ -5394,9 +5354,9 @@ do\
         EEPROM_read(EEPROM_SD_SORT, (uint8_t*)&sdSort, sizeof(sdSort));\
         switch (sdSort)\
         {\
-          case SD_SORT_TIME: MENU_ITEM_FUNCTION_P(_i("Sort       [time]"), lcd_sort_type_set); break;/*////MSG_SORT_TIME c=17 r=1*/\
-          case SD_SORT_ALPHA: MENU_ITEM_FUNCTION_P(_i("Sort   [alphabet]"), lcd_sort_type_set); break;/*////MSG_SORT_ALPHA c=17 r=1*/\
-          default: MENU_ITEM_FUNCTION_P(_i("Sort       [none]"), lcd_sort_type_set);/*////MSG_SORT_NONE c=17 r=1*/\
+          case SD_SORT_TIME: MENU_ITEM_TOGGLE_P(_T(MSG_SORT), _T(MSG_SORT_TIME), lcd_sort_type_set); break;\
+          case SD_SORT_ALPHA: MENU_ITEM_TOGGLE_P(_T(MSG_SORT), _T(MSG_SORT_ALPHA), lcd_sort_type_set); break;\
+          default: MENU_ITEM_TOGGLE_P(_T(MSG_SORT), _T(MSG_NONE), lcd_sort_type_set);\
         }\
     }\
 }\
@@ -5406,9 +5366,9 @@ while (0)
 do\
 {\
     if (card.ToshibaFlashAir_isEnabled())\
-        MENU_ITEM_FUNCTION_P(_i("SD card [flshAir]"), lcd_toshiba_flash_air_compatibility_toggle);/*////MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON c=19 r=1*/\
+        MENU_ITEM_TOGGLE_P(_T(MSG_SD_CARD), _T(MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY), lcd_toshiba_flash_air_compatibility_toggle);\
     else\
-        MENU_ITEM_FUNCTION_P(_i("SD card  [normal]"), lcd_toshiba_flash_air_compatibility_toggle);/*////MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF c=19 r=1*/\
+        MENU_ITEM_TOGGLE_P(_T(MSG_SD_CARD), _T(MSG_NORMAL), lcd_toshiba_flash_air_compatibility_toggle);\
 }\
 while (0)
 #endif // SDCARD_SORT_ALPHA
@@ -5440,22 +5400,22 @@ while (0)
 do\
 {\
     switch(eSoundMode)\
-         {\
-         case e_SOUND_MODE_LOUD:\
-              MENU_ITEM_FUNCTION_P(_i(MSG_SOUND_MODE_LOUD),lcd_sound_state_set);\
-              break;\
-         case e_SOUND_MODE_ONCE:\
-              MENU_ITEM_FUNCTION_P(_i(MSG_SOUND_MODE_ONCE),lcd_sound_state_set);\
-              break;\
-         case e_SOUND_MODE_SILENT:\
-              MENU_ITEM_FUNCTION_P(_i(MSG_SOUND_MODE_SILENT),lcd_sound_state_set);\
-              break;\
-         case e_SOUND_MODE_BLIND:\
-              MENU_ITEM_FUNCTION_P(_i(MSG_SOUND_MODE_BLIND),lcd_sound_state_set);\
-              break;\
-         default:\
-              MENU_ITEM_FUNCTION_P(_i(MSG_SOUND_MODE_LOUD),lcd_sound_state_set);\
-         }\
+    {\
+        case e_SOUND_MODE_LOUD:\
+            MENU_ITEM_TOGGLE_P(_T(MSG_SOUND), _T(MSG_SOUND_LOUD), lcd_sound_state_set);\
+            break;\
+        case e_SOUND_MODE_ONCE:\
+            MENU_ITEM_TOGGLE_P(_T(MSG_SOUND), _T(MSG_SOUND_ONCE), lcd_sound_state_set);\
+            break;\
+        case e_SOUND_MODE_SILENT:\
+            MENU_ITEM_TOGGLE_P(_T(MSG_SOUND), _T(MSG_SILENT), lcd_sound_state_set);\
+            break;\
+        case e_SOUND_MODE_BLIND:\
+            MENU_ITEM_TOGGLE_P(_T(MSG_SOUND), _T(MSG_SOUND_BLIND), lcd_sound_state_set);\
+            break;\
+        default:\
+            MENU_ITEM_TOGGLE_P(_T(MSG_SOUND), _T(MSG_SOUND_LOUD), lcd_sound_state_set);\
+    }\
 }\
 while (0)
 
@@ -5485,16 +5445,16 @@ do\
     switch(oCheckMode)\
          {\
          case ClCheckMode::_None:\
-              MENU_ITEM_FUNCTION_P(_i("Nozzle     [none]"),lcd_check_mode_set);\
+              MENU_ITEM_TOGGLE_P(_T(MSG_NOZZLE), _T(MSG_NONE), lcd_check_mode_set);\
               break;\
          case ClCheckMode::_Warn:\
-              MENU_ITEM_FUNCTION_P(_i("Nozzle     [warn]"),lcd_check_mode_set);\
+              MENU_ITEM_TOGGLE_P(_T(MSG_NOZZLE), _T(MSG_WARN), lcd_check_mode_set);\
               break;\
          case ClCheckMode::_Strict:\
-              MENU_ITEM_FUNCTION_P(_i("Nozzle   [strict]"),lcd_check_mode_set);\
+              MENU_ITEM_TOGGLE_P(_T(MSG_NOZZLE), _T(MSG_STRICT), lcd_check_mode_set);\
               break;\
          default:\
-              MENU_ITEM_FUNCTION_P(_i("Nozzle     [none]"),lcd_check_mode_set);\
+              MENU_ITEM_TOGGLE_P(_T(MSG_NOZZLE), _T(MSG_NONE), lcd_check_mode_set);\
          }\
 }\
 while (0)
@@ -5528,20 +5488,15 @@ eeprom_update_word((uint16_t*)EEPROM_NOZZLE_DIAMETER_uM,nDiameter);
 #define SETTINGS_NOZZLE \
 do\
 {\
+    float fNozzleDiam;\
     switch(oNozzleDiameter)\
-         {\
-         case ClNozzleDiameter::_Diameter_250:\
-              MENU_ITEM_FUNCTION_P(_i("Nozzle d.  [0.25]"),lcd_nozzle_diameter_set);\
-              break;\
-         case ClNozzleDiameter::_Diameter_400:\
-              MENU_ITEM_FUNCTION_P(_i("Nozzle d.  [0.40]"),lcd_nozzle_diameter_set);\
-              break;\
-         case ClNozzleDiameter::_Diameter_600:\
-              MENU_ITEM_FUNCTION_P(_i("Nozzle d.  [0.60]"),lcd_nozzle_diameter_set);\
-              break;\
-         default:\
-              MENU_ITEM_FUNCTION_P(_i("Nozzle d.  [0.40]"),lcd_nozzle_diameter_set);\
-         }\
+    {\
+        case ClNozzleDiameter::_Diameter_250: fNozzleDiam = 0.25f; break;\
+        case ClNozzleDiameter::_Diameter_400: fNozzleDiam = 0.4f; break;\
+        case ClNozzleDiameter::_Diameter_600: fNozzleDiam = 0.6f; break;\
+        default: fNozzleDiam = 0.4f; break;\
+    }\
+    MENU_ITEM_TOGGLE(_T(MSG_NOZZLE_DIAMETER), ftostr12ns(fNozzleDiam), lcd_nozzle_diameter_set);\
 }\
 while (0)
 
@@ -5570,16 +5525,16 @@ do\
     switch(oCheckModel)\
          {\
          case ClCheckModel::_None:\
-              MENU_ITEM_FUNCTION_P(_i("Model      [none]"),lcd_check_model_set);\
+              MENU_ITEM_TOGGLE_P(_T(MSG_MODEL), _T(MSG_NONE), lcd_check_model_set);\
               break;\
          case ClCheckModel::_Warn:\
-              MENU_ITEM_FUNCTION_P(_i("Model      [warn]"),lcd_check_model_set);\
+              MENU_ITEM_TOGGLE_P(_T(MSG_MODEL), _T(MSG_WARN), lcd_check_model_set);\
               break;\
          case ClCheckModel::_Strict:\
-              MENU_ITEM_FUNCTION_P(_i("Model    [strict]"),lcd_check_model_set);\
+              MENU_ITEM_TOGGLE_P(_T(MSG_MODEL), _T(MSG_STRICT), lcd_check_model_set);\
               break;\
          default:\
-              MENU_ITEM_FUNCTION_P(_i("Model      [none]"),lcd_check_model_set);\
+              MENU_ITEM_TOGGLE_P(_T(MSG_MODEL), _T(MSG_NONE), lcd_check_model_set);\
          }\
 }\
 while (0)
@@ -5609,16 +5564,16 @@ do\
     switch(oCheckVersion)\
          {\
          case ClCheckVersion::_None:\
-              MENU_ITEM_FUNCTION_P(_i("Firmware   [none]"),lcd_check_version_set);\
+              MENU_ITEM_TOGGLE_P(_T(MSG_FIRMWARE), _T(MSG_NONE), lcd_check_version_set);\
               break;\
          case ClCheckVersion::_Warn:\
-              MENU_ITEM_FUNCTION_P(_i("Firmware   [warn]"),lcd_check_version_set);\
+              MENU_ITEM_TOGGLE_P(_T(MSG_FIRMWARE), _T(MSG_WARN), lcd_check_version_set);\
               break;\
          case ClCheckVersion::_Strict:\
-              MENU_ITEM_FUNCTION_P(_i("Firmware [strict]"),lcd_check_version_set);\
+              MENU_ITEM_TOGGLE_P(_T(MSG_FIRMWARE), _T(MSG_STRICT), lcd_check_version_set);\
               break;\
          default:\
-              MENU_ITEM_FUNCTION_P(_i("Firmware   [none]"),lcd_check_version_set);\
+              MENU_ITEM_TOGGLE_P(_T(MSG_FIRMWARE), _T(MSG_NONE), lcd_check_version_set);\
          }\
 }\
 while (0)
@@ -5648,16 +5603,16 @@ do\
     switch(oCheckGcode)\
          {\
          case ClCheckGcode::_None:\
-              MENU_ITEM_FUNCTION_P(_i("Gcode      [none]"),lcd_check_gcode_set);\
+              MENU_ITEM_TOGGLE_P(_T(MSG_GCODE), _T(MSG_NONE), lcd_check_gcode_set);\
               break;\
          case ClCheckGcode::_Warn:\
-              MENU_ITEM_FUNCTION_P(_i("Gcode      [warn]"),lcd_check_gcode_set);\
+              MENU_ITEM_TOGGLE_P(_T(MSG_GCODE), _T(MSG_WARN), lcd_check_gcode_set);\
               break;\
          case ClCheckGcode::_Strict:\
-              MENU_ITEM_FUNCTION_P(_i("Gcode    [strict]"),lcd_check_gcode_set);\
+              MENU_ITEM_TOGGLE_P(_T(MSG_GCODE), _T(MSG_STRICT), lcd_check_gcode_set);\
               break;\
          default:\
-              MENU_ITEM_FUNCTION_P(_i("Gcode      [none]"),lcd_check_gcode_set);\
+              MENU_ITEM_TOGGLE_P(_T(MSG_GCODE), _T(MSG_NONE), lcd_check_gcode_set);\
          }\
 }\
 while (0)
@@ -5674,6 +5629,41 @@ SETTINGS_VERSION;
 MENU_END();
 }
 
+#if IR_SENSOR_ANALOG
+static void lcd_fsensor_actionNA_set(void)
+{
+switch(oFsensorActionNA)
+     {
+     case ClFsensorActionNA::_Continue:
+          oFsensorActionNA=ClFsensorActionNA::_Pause;
+          break;
+     case ClFsensorActionNA::_Pause:
+          oFsensorActionNA=ClFsensorActionNA::_Continue;
+          break;
+     default:
+          oFsensorActionNA=ClFsensorActionNA::_Continue;
+     }
+eeprom_update_byte((uint8_t*)EEPROM_FSENSOR_ACTION_NA,(uint8_t)oFsensorActionNA);
+}
+
+#define FSENSOR_ACTION_NA \
+do\
+{\
+    switch(oFsensorActionNA)\
+         {\
+         case ClFsensorActionNA::_Continue:\
+              MENU_ITEM_TOGGLE_P(_T(MSG_FS_ACTION), _T(MSG_FS_CONTINUE), lcd_fsensor_actionNA_set);\
+              break;\
+         case ClFsensorActionNA::_Pause:\
+              MENU_ITEM_TOGGLE_P(_T(MSG_FS_ACTION), _T(MSG_FS_PAUSE), lcd_fsensor_actionNA_set);\
+              break;\
+         default:\
+              oFsensorActionNA=ClFsensorActionNA::_Continue;\
+         }\
+}\
+while (0)
+#endif //IR_SENSOR_ANALOG
+
 template <uint8_t number>
 static void select_sheet_menu()
 {
@@ -5705,6 +5695,9 @@ void lcd_hw_setup_menu(void)                      // can not be "static"
     SETTINGS_NOZZLE;
     MENU_ITEM_SUBMENU_P(_i("Checks"), lcd_checking_menu);
 
+#if IR_SENSOR_ANALOG
+    FSENSOR_ACTION_NA;
+#endif //IR_SENSOR_ANALOG
     MENU_END();
 }
 
@@ -5726,10 +5719,7 @@ static void lcd_settings_menu()
 
 	SETTINGS_CUTTER;
 
-	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
+	MENU_ITEM_TOGGLE_P(_i("Fans check"), fans_check_enabled ? _T(MSG_ON) : _T(MSG_OFF), lcd_set_fan_check);
 
 	SETTINGS_SILENT_MODE;
 
@@ -5747,16 +5737,10 @@ static void lcd_settings_menu()
     MENU_ITEM_SUBMENU_P(_i("Lin. correction"), lcd_settings_linearity_correction_menu);
 #endif //LINEARITY_CORRECTION && TMC2130
 
-  if (temp_cal_active == false)
-	  MENU_ITEM_FUNCTION_P(_i("Temp. cal.  [off]"), lcd_temp_calibration_set);////MSG_TEMP_CALIBRATION_OFF c=20 r=1
-  else
-	  MENU_ITEM_FUNCTION_P(_i("Temp. cal.   [on]"), lcd_temp_calibration_set);////MSG_TEMP_CALIBRATION_ON c=20 r=1
+	MENU_ITEM_TOGGLE_P(_T(MSG_TEMP_CALIBRATION), temp_cal_active ? _T(MSG_ON) : _T(MSG_OFF), lcd_temp_calibration_set);
 
 #ifdef HAS_SECOND_SERIAL_PORT
-	if (selectedSerialPort == 0)
-		MENU_ITEM_FUNCTION_P(_i("RPi port    [off]"), lcd_second_serial_set);////MSG_SECOND_SERIAL_OFF c=17 r=1
-	else
-		MENU_ITEM_FUNCTION_P(_i("RPi port     [on]"), lcd_second_serial_set);////MSG_SECOND_SERIAL_ON c=17 r=1
+    MENU_ITEM_TOGGLE_P(_T(MSG_RPI_PORT), (selectedSerialPort == 0) ? _T(MSG_OFF) : _T(MSG_ON), lcd_second_serial_set);
 #endif //HAS_SECOND_SERIAL
 
 	if (!isPrintPaused && !homing_flag)
@@ -5769,6 +5753,13 @@ static void lcd_settings_menu()
 	SETTINGS_SD;
 	SETTINGS_SOUND;
 
+#ifdef LCD_BL_PIN
+    if (backlightSupport)
+    {
+        MENU_ITEM_SUBMENU_P(_T(MSG_BRIGHTNESS), lcd_backlight_menu);
+    }
+#endif //LCD_BL_PIN
+
 	if (farm_mode)
 	{
 		MENU_ITEM_SUBMENU_P(PSTR("Farm number"), lcd_farm_no);
@@ -5817,6 +5808,9 @@ static void lcd_calibration_menu()
          MENU_ITEM_SUBMENU_P(_T(MSG_V2_CALIBRATION), lcd_first_layer_calibration_reset);
     }
 	MENU_ITEM_GCODE_P(_T(MSG_AUTO_HOME), PSTR("G28 W"));
+#ifdef TMC2130
+	MENU_ITEM_FUNCTION_P(_i("Belt test        "), lcd_belttest_v);////MSG_BELTTEST
+#endif //TMC2130
 	MENU_ITEM_FUNCTION_P(_i("Selftest         "), lcd_selftest_v);////MSG_SELFTEST
 #ifdef MK1BP
     // MK1
@@ -5969,7 +5963,7 @@ void bowden_menu() {
 	}
 }
 
-//#ifdef SNMM
+#ifdef SNMM
 
 static char snmm_stop_print_menu() { //menu for choosing which filaments will be unloaded in stop print
 	lcd_clear();
@@ -6020,6 +6014,8 @@ static char snmm_stop_print_menu() { //menu for choosing which filaments will be
 	
 }
 
+#endif //SNMM
+
 //! @brief Select one of numbered items
 //!
 //! Create list of items with header. Header can not be selected.
@@ -6357,6 +6353,8 @@ void unload_filament()
 	custom_message_type = CustomMsg::FilamentLoading;
 	lcd_setstatuspgm(_T(MSG_UNLOADING_FILAMENT));
 
+    raise_z_above(MIN_Z_FOR_UNLOAD);
+
 	//		extr_unload2();
 
 	current_position[E_AXIS] -= 45;
@@ -6639,6 +6637,7 @@ static void lcd_test_menu()
 static bool fan_error_selftest()
 {
 #ifdef FANCHECK
+    if (!fans_check_enabled) return 0;
 
     fanSpeed = 255;
 #ifdef FAN_SOFT_PWM
@@ -6669,9 +6668,8 @@ static bool fan_error_selftest()
         return 1;
     }
 #endif
+#endif //FANCHECK
     return 0;
-
-#endif //FANCHECK   
 }
 
 //! @brief Resume paused print
@@ -6680,16 +6678,17 @@ static bool fan_error_selftest()
 void lcd_resume_print()
 {
     lcd_return_to_status();
-    lcd_reset_alert_level();
-    lcd_setstatuspgm(_T(MSG_RESUMING_PRINT));
     lcd_reset_alert_level(); //for fan speed error
-
     if (fan_error_selftest()) return; //abort if error persists
 
-    restore_print_from_ram_and_continue(0.0);
+    lcd_setstatuspgm(_T(MSG_FINISHING_MOVEMENTS));
+    st_synchronize();
+
+    lcd_setstatuspgm(_T(MSG_RESUMING_PRINT));
+    isPrintPaused = false;
+    restore_print_from_ram_and_continue(default_retraction);
     pause_time += (_millis() - start_pause_print); //accumulate time when print is paused for correct statistics calculation
     refresh_cmd_timeout();
-    isPrintPaused = false;
     SERIAL_PROTOCOLLNRPGM(MSG_OCTOPRINT_RESUMED); //resume octoprint
 }
 
@@ -6826,10 +6825,15 @@ static void lcd_main_menu()
   }
 
 
+  if(isPrintPaused && saved_printing_type == PRINTING_TYPE_USB)
+  {
 #ifdef FANCHECK
-  if((fan_check_error == EFCE_FIXED) && (saved_printing_type == PRINTING_TYPE_USB))
-    MENU_ITEM_SUBMENU_P(_i("Resume print"), lcd_resume_print);////MSG_RESUME_PRINT
+      if((fan_check_error == EFCE_FIXED) || (fan_check_error == EFCE_OK))
+          MENU_ITEM_SUBMENU_P(_i("Resume print"), lcd_resume_print);////MSG_RESUME_PRINT
+#else
+      MENU_ITEM_SUBMENU_P(_i("Resume print"), lcd_resume_print);////MSG_RESUME_PRINT
 #endif
+  }
 
 #ifdef SDSUPPORT
   if (card.cardOK || lcd_commands_type == LcdCommands::Layer1Cal)
@@ -6841,7 +6845,7 @@ static void lcd_main_menu()
 			{
 				MENU_ITEM_FUNCTION_P(_i("Pause print"), lcd_pause_print);////MSG_PAUSE_PRINT
 			}
-			else
+			else if(isPrintPaused)
 			{
 				#ifdef FANCHECK
 					if((fan_check_error == EFCE_FIXED) || (fan_check_error == EFCE_OK))
@@ -6998,6 +7002,60 @@ static void lcd_colorprint_change() {
 	lcd_draw_update = 3;
 }
 
+
+#ifdef LA_LIVE_K
+// @wavexx: looks like there's no generic float editing function in menu.cpp so we
+//          redefine our custom handling functions to mimick other tunables
+const char menu_fmt_float13off[] PROGMEM = "%c%-13.13S%6.6S";
+
+static void lcd_advance_draw_K(char chr, float val)
+{
+    if (val <= 0)
+        lcd_printf_P(menu_fmt_float13off, chr, MSG_ADVANCE_K, _T(MSG_OFF));
+    else
+        lcd_printf_P(menu_fmt_float13, chr, MSG_ADVANCE_K, val);
+}
+
+static void lcd_advance_edit_K(void)
+{
+    if (lcd_draw_update)
+    {
+        if (lcd_encoder < 0) lcd_encoder = 0;
+        if (lcd_encoder > 999) lcd_encoder = 999;
+        lcd_set_cursor(0, 1);
+        lcd_advance_draw_K(' ', 0.01 * lcd_encoder);
+    }
+    if (LCD_CLICKED)
+    {
+        extruder_advance_K = 0.01 * lcd_encoder;
+        menu_back_no_reset();
+    }
+}
+
+static uint8_t lcd_advance_K()
+{
+    if (menu_item == menu_line)
+    {
+        if (lcd_draw_update)
+        {
+            lcd_set_cursor(0, menu_row);
+            lcd_advance_draw_K((lcd_encoder == menu_item)?'>':' ', extruder_advance_K);
+        }
+        if (menu_clicked && (lcd_encoder == menu_item))
+        {
+            menu_submenu_no_reset(lcd_advance_edit_K);
+            lcd_encoder = 100. * extruder_advance_K;
+            return menu_item_ret();
+        }
+    }
+    menu_item++;
+    return 0;
+}
+
+#define MENU_ITEM_EDIT_advance_K() do { if (lcd_advance_K()) return; } while (0)
+#endif
+
+
 static void lcd_tune_menu()
 {
 	typedef struct
@@ -7036,17 +7094,30 @@ static void lcd_tune_menu()
 
 	MENU_ITEM_EDIT_int3_P(_T(MSG_FAN_SPEED), &fanSpeed, 0, 255);//5
 	MENU_ITEM_EDIT_int3_P(_i("Flow"), &extrudemultiply, 10, 999);//6////MSG_FLOW
+#ifdef LA_LIVE_K
+	MENU_ITEM_EDIT_advance_K();//7
+#endif
 #ifdef FILAMENTCHANGEENABLE
-	MENU_ITEM_FUNCTION_P(_T(MSG_FILAMENTCHANGE), lcd_colorprint_change);//7
+	MENU_ITEM_FUNCTION_P(_T(MSG_FILAMENTCHANGE), lcd_colorprint_change);//8
 #endif
 
 #ifdef FILAMENT_SENSOR
 	if (FSensorStateMenu == 0) {
-		MENU_ITEM_FUNCTION_P(_T(MSG_FSENSOR_OFF), lcd_fsensor_state_set);
+          if (fsensor_not_responding && (mmu_enabled == false)) {
+               /* Filament sensor not working*/
+               MENU_ITEM_TOGGLE_P(_T(MSG_FSENSOR), _T(MSG_NA), lcd_fsensor_state_set);
+          }
+          else {
+               /* Filament sensor turned off, working, no problems*/
+               MENU_ITEM_TOGGLE_P(_T(MSG_FSENSOR), _T(MSG_OFF), lcd_fsensor_state_set);
+          }
 	}
 	else {
-		MENU_ITEM_FUNCTION_P(_T(MSG_FSENSOR_ON), lcd_fsensor_state_set);
+		MENU_ITEM_TOGGLE_P(_T(MSG_FSENSOR), _T(MSG_ON), lcd_fsensor_state_set);
 	}
+#if IR_SENSOR_ANALOG
+     FSENSOR_ACTION_NA;
+#endif //IR_SENSOR_ANALOG
 #endif //FILAMENT_SENSOR
 
 	SETTINGS_AUTO_DEPLETE;
@@ -7055,54 +7126,40 @@ static void lcd_tune_menu()
 
      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
+       MENU_ITEM_TOGGLE_P(_i("Fans check"), fans_check_enabled ? _T(MSG_ON) : _T(MSG_OFF), lcd_set_fan_check);
      }
 
 #ifdef TMC2130
      if(!farm_mode)
      {
-          if (SilentModeMenu == SILENT_MODE_NORMAL) MENU_ITEM_FUNCTION_P(_T(MSG_STEALTH_MODE_OFF), lcd_silent_mode_set);
-          else MENU_ITEM_FUNCTION_P(_T(MSG_STEALTH_MODE_ON), lcd_silent_mode_set);
+          if (SilentModeMenu == SILENT_MODE_NORMAL) MENU_ITEM_TOGGLE_P(_T(MSG_MODE), _T(MSG_NORMAL), lcd_silent_mode_set);
+          else MENU_ITEM_TOGGLE_P(_T(MSG_MODE), _T(MSG_STEALTH), lcd_silent_mode_set);
 
           if (SilentModeMenu == SILENT_MODE_NORMAL)
           {
-               if (lcd_crash_detect_enabled()) MENU_ITEM_FUNCTION_P(_T(MSG_CRASHDETECT_ON), crash_mode_switch);
-               else MENU_ITEM_FUNCTION_P(_T(MSG_CRASHDETECT_OFF), crash_mode_switch);
+               if (lcd_crash_detect_enabled()) MENU_ITEM_TOGGLE_P(_T(MSG_CRASHDETECT), _T(MSG_ON), crash_mode_switch);
+               else MENU_ITEM_TOGGLE_P(_T(MSG_CRASHDETECT), _T(MSG_OFF), crash_mode_switch);
           }
-          else MENU_ITEM_SUBMENU_P(_T(MSG_CRASHDETECT_NA), lcd_crash_mode_info);
+          else MENU_ITEM_TOGGLE_P(_T(MSG_CRASHDETECT), NULL, lcd_crash_mode_info);
      }
 #else //TMC2130
 	if (!farm_mode) { //dont show in menu if we are in farm mode
 		switch (SilentModeMenu) {
-		case SILENT_MODE_POWER: MENU_ITEM_FUNCTION_P(_T(MSG_SILENT_MODE_OFF), lcd_silent_mode_set); break;
-		case SILENT_MODE_SILENT: MENU_ITEM_FUNCTION_P(_T(MSG_SILENT_MODE_ON), lcd_silent_mode_set); break;
-		case SILENT_MODE_AUTO: MENU_ITEM_FUNCTION_P(_T(MSG_AUTO_MODE_ON), lcd_silent_mode_set); break;
-		default: MENU_ITEM_FUNCTION_P(_T(MSG_SILENT_MODE_OFF), lcd_silent_mode_set); break; // (probably) not needed
+		case SILENT_MODE_POWER: MENU_ITEM_TOGGLE_P(_T(MSG_MODE), _T(MSG_HIGH_POWER), lcd_silent_mode_set); break;
+		case SILENT_MODE_SILENT: MENU_ITEM_TOGGLE_P(_T(MSG_MODE), _T(MSG_SILENT), lcd_silent_mode_set); break;
+		case SILENT_MODE_AUTO: MENU_ITEM_TOGGLE_P(_T(MSG_MODE), _T(MSG_AUTO_POWER), lcd_silent_mode_set); break;
+		default: MENU_ITEM_TOGGLE_P(_T(MSG_MODE), _T(MSG_HIGH_POWER), lcd_silent_mode_set); break; // (probably) not needed
 		}
 	}
 #endif //TMC2130
-	 SETTINGS_MMU_MODE;
-     switch(eSoundMode)
-          {
-          case e_SOUND_MODE_LOUD:
-               MENU_ITEM_FUNCTION_P(_i(MSG_SOUND_MODE_LOUD),lcd_sound_state_set);
-               break;
-          case e_SOUND_MODE_ONCE:
-               MENU_ITEM_FUNCTION_P(_i(MSG_SOUND_MODE_ONCE),lcd_sound_state_set);
-               break;
-          case e_SOUND_MODE_SILENT:
-               MENU_ITEM_FUNCTION_P(_i(MSG_SOUND_MODE_SILENT),lcd_sound_state_set);
-               break;
-          case e_SOUND_MODE_BLIND:
-               MENU_ITEM_FUNCTION_P(_i(MSG_SOUND_MODE_BLIND),lcd_sound_state_set);
-               break;
-          default:
-               MENU_ITEM_FUNCTION_P(_i(MSG_SOUND_MODE_LOUD),lcd_sound_state_set);
-          }
-
+	SETTINGS_MMU_MODE;
+    SETTINGS_SOUND;
+#ifdef LCD_BL_PIN
+    if (backlightSupport)
+    {
+        MENU_ITEM_SUBMENU_P(_T(MSG_BRIGHTNESS), lcd_backlight_menu);
+    }
+#endif //LCD_BL_PIN
 	MENU_END();
 }
 
@@ -7135,25 +7192,53 @@ static void lcd_mesh_bed_leveling_settings()
 	
 	bool magnet_elimination = (eeprom_read_byte((uint8_t*)EEPROM_MBL_MAGNET_ELIMINATION) > 0);
 	uint8_t points_nr = eeprom_read_byte((uint8_t*)EEPROM_MBL_POINTS_NR);
+	char sToggle[4]; //enough for nxn format
 
 	MENU_BEGIN();
-	MENU_ITEM_BACK_P(_T(MSG_SETTINGS)); 
-	if(points_nr == 3) MENU_ITEM_FUNCTION_P(_i("Mesh         [3x3]"), mbl_mesh_toggle); ////MSG_MESH_3x3 c=18
-	else			   MENU_ITEM_FUNCTION_P(_i("Mesh         [7x7]"), mbl_mesh_toggle); ////MSG_MESH_7x7 c=18
-	switch (mbl_z_probe_nr) {
-		case 1: MENU_ITEM_FUNCTION_P(_i("Z-probe nr.    [1]"), mbl_probe_nr_toggle); break; ////MSG_Z_PROBE_NR_1 c=18
-		case 5: MENU_ITEM_FUNCTION_P(_i("Z-probe nr.    [5]"), mbl_probe_nr_toggle); break; ////MSG_Z_PROBE_NR_1 c=18
-		default: MENU_ITEM_FUNCTION_P(_i("Z-probe nr.    [3]"), mbl_probe_nr_toggle); break; ////MSG_Z_PROBE_NR_1 c=18
-	}
-	if (points_nr == 7) {
-		if (magnet_elimination) MENU_ITEM_FUNCTION_P(_i("Magnets comp. [On]"), mbl_magnets_elimination_toggle); ////MSG_MAGNETS_COMP_ON c=18
-		else				    MENU_ITEM_FUNCTION_P(_i("Magnets comp.[Off]"), mbl_magnets_elimination_toggle); ////MSG_MAGNETS_COMP_OFF c=18
-	}
-	else					        menu_item_text_P(_i("Magnets comp.[N/A]")); ////MSG_MAGNETS_COMP_NA c=18
+	MENU_ITEM_BACK_P(_T(MSG_SETTINGS));
+	sToggle[0] = points_nr + '0';
+	sToggle[1] = 'x';
+	sToggle[2] = points_nr + '0';
+	sToggle[3] = 0;
+	MENU_ITEM_TOGGLE(_T(MSG_MESH), sToggle, mbl_mesh_toggle);
+	sToggle[0] = mbl_z_probe_nr + '0';
+	sToggle[1] = 0;
+	MENU_ITEM_TOGGLE(_T(MSG_Z_PROBE_NR), sToggle, mbl_probe_nr_toggle);
+	MENU_ITEM_TOGGLE_P(_T(MSG_MAGNETS_COMP), (points_nr == 7) ? (magnet_elimination ? _T(MSG_ON): _T(MSG_OFF)) : _T(MSG_NA), mbl_magnets_elimination_toggle);
 	MENU_END();
 	//SETTINGS_MBL_MODE;
 }
 
+#ifdef LCD_BL_PIN
+static void backlight_mode_toggle()
+{
+    switch (backlightMode)
+    {
+        case BACKLIGHT_MODE_BRIGHT: backlightMode = BACKLIGHT_MODE_DIM; break;
+        case BACKLIGHT_MODE_DIM: backlightMode = BACKLIGHT_MODE_AUTO; break;
+        case BACKLIGHT_MODE_AUTO: backlightMode = BACKLIGHT_MODE_BRIGHT; break;
+        default: backlightMode = BACKLIGHT_MODE_BRIGHT; break;
+    }
+    backlight_save();
+}
+
+static void lcd_backlight_menu()
+{
+    MENU_BEGIN();
+    ON_MENU_LEAVE(
+        backlight_save();
+    );
+    
+    MENU_ITEM_BACK_P(_T(MSG_BACK));
+    MENU_ITEM_EDIT_int3_P(_T(MSG_BL_HIGH), &backlightLevel_HIGH, backlightLevel_LOW, 255);
+    MENU_ITEM_EDIT_int3_P(_T(MSG_BL_LOW), &backlightLevel_LOW, 0, backlightLevel_HIGH);
+	MENU_ITEM_TOGGLE_P(_T(MSG_MODE), ((backlightMode==BACKLIGHT_MODE_BRIGHT) ? _T(MSG_BRIGHT) : ((backlightMode==BACKLIGHT_MODE_DIM) ? _T(MSG_DIM) : _T(MSG_AUTO))), backlight_mode_toggle);
+    MENU_ITEM_EDIT_int3_P(_T(MSG_TIMEOUT), &backlightTimer_period, 1, 999);
+    
+    MENU_END();
+}
+#endif //LCD_BL_PIN
+
 static void lcd_control_temperature_menu()
 {
 #ifdef PIDTEMP
@@ -7204,42 +7289,66 @@ static void lcd_sd_updir()
 
 void lcd_print_stop()
 {
-//-//
-     if(!card.sdprinting)
-          {
-          SERIAL_ECHOLNRPGM(MSG_OCTOPRINT_CANCEL);   // for Octoprint
-          }
-	saved_printing = false;
-    saved_printing_type = PRINTING_TYPE_NONE;
-	cancel_heatup = true;
-#ifdef MESH_BED_LEVELING
-	mbl.active = false;
-#endif
-	// Stop the stoppers, update the position from the stoppers.
-	if (mesh_bed_leveling_flag == false && homing_flag == false)
-	{
-		planner_abort_hard();
-		// Because the planner_abort_hard() initialized current_position[Z] from the stepper,
-		// Z baystep is no more applied. Reset it.
-		babystep_reset();
-	}
-	// Clean the input command queue.
+    if (!card.sdprinting) {
+        SERIAL_ECHOLNRPGM(MSG_OCTOPRINT_CANCEL);   // for Octoprint
+    }
+
+    CRITICAL_SECTION_START;
+
+    // Clear any saved printing state
+    cancel_saved_printing();
+
+    // Abort the planner/queue/sd
+    planner_abort_hard();
 	cmdqueue_reset();
-	lcd_setstatuspgm(_T(MSG_PRINT_ABORTED));
 	card.sdprinting = false;
 	card.closefile();
+    st_reset_timer();
+
+    CRITICAL_SECTION_END;
+
+#ifdef MESH_BED_LEVELING
+    mbl.active = false; //also prevents undoing the mbl compensation a second time in the second planner_abort_hard()
+#endif
+
+	lcd_setstatuspgm(_T(MSG_PRINT_ABORTED));
 	stoptime = _millis();
 	unsigned long t = (stoptime - starttime - pause_time) / 1000; //time in s
 	pause_time = 0;
 	save_statistics(total_filament_used, t);
-	lcd_return_to_status();
-	lcd_ignore_click(true);
-	lcd_commands_step = 0;
-	lcd_commands_type = LcdCommands::StopPrint;
-	// Turn off the print fan
-	SET_OUTPUT(FAN_PIN);
-	WRITE(FAN_PIN, 0);
-	fanSpeed = 0;
+
+    lcd_commands_step = 0;
+    lcd_commands_type = LcdCommands::Idle;
+
+    lcd_cooldown(); //turns off heaters and fan; goes to status screen.
+    cancel_heatup = true; //unroll temperature wait loop stack.
+
+    current_position[Z_AXIS] += 10; //lift Z.
+    plan_buffer_line_curposXYZE(manual_feedrate[Z_AXIS] / 60, active_extruder);
+
+    if (axis_known_position[X_AXIS] && axis_known_position[Y_AXIS]) //if axis are homed, move to parked position.
+    {
+        current_position[X_AXIS] = X_CANCEL_POS;
+        current_position[Y_AXIS] = Y_CANCEL_POS;
+        plan_buffer_line_curposXYZE(manual_feedrate[0] / 60, active_extruder);
+    }
+    st_synchronize();
+
+    if (mmu_enabled) extr_unload(); //M702 C
+
+    finishAndDisableSteppers(); //M84
+
+    lcd_setstatuspgm(_T(WELCOME_MSG));
+    custom_message_type = CustomMsg::Status;
+
+    planner_abort_hard(); //needs to be done since plan_buffer_line resets waiting_inside_plan_buffer_line_print_aborted to false. Also copies current to destination.
+    
+    axis_relative_modes[X_AXIS] = false;
+    axis_relative_modes[Y_AXIS] = false;
+    axis_relative_modes[Z_AXIS] = false;
+    axis_relative_modes[E_AXIS] = true;
+    
+    isPrintPaused = false; //clear isPrintPaused flag to allow starting next print after pause->stop scenario.
 }
 
 void lcd_sdcard_stop()
@@ -7329,6 +7438,98 @@ void lcd_sdcard_menu()
   }
   MENU_END();
 }
+#ifdef TMC2130
+static void lcd_belttest_v()
+{
+    lcd_belttest();
+    menu_back_if_clicked();
+}
+void lcd_belttest_print(const char* msg, uint16_t X, uint16_t Y)
+{
+    lcd_clear();
+    lcd_printf_P(
+              _N(
+                 "%S:\n"
+                 "%S\n"
+                 "X:%d\n"
+                 "Y:%d"
+                 ),
+              _i("Belt status"),
+              msg,
+              X,Y
+            );
+}
+void lcd_belttest()
+{
+    int _progress = 0;
+    bool _result = true;
+    uint16_t   X = eeprom_read_word((uint16_t*)(EEPROM_BELTSTATUS_X));
+    uint16_t   Y = eeprom_read_word((uint16_t*)(EEPROM_BELTSTATUS_Y));
+    lcd_belttest_print(_i("Checking X..."), X, Y);
+
+    _delay(2000);
+    KEEPALIVE_STATE(IN_HANDLER);
+
+    _result = lcd_selfcheck_axis_sg(X_AXIS);
+    X = eeprom_read_word((uint16_t*)(EEPROM_BELTSTATUS_X));
+    if (!_result){
+        lcd_belttest_print(_i("Error"), X, Y);
+        return;
+    }
+
+    lcd_belttest_print(_i("Checking Y..."), X, Y);
+    _result = lcd_selfcheck_axis_sg(Y_AXIS);
+    Y = eeprom_read_word((uint16_t*)(EEPROM_BELTSTATUS_Y));
+
+    if (!_result){
+        lcd_belttest_print(_i("Error"), X, Y);
+        lcd_clear();
+        return;
+    }
+
+
+    lcd_belttest_print(_i("Done"), X, Y);
+
+    KEEPALIVE_STATE(NOT_BUSY);
+    _delay(3000);
+}
+#endif //TMC2130
+
+#if IR_SENSOR_ANALOG
+static bool lcd_selftest_IRsensor()
+{
+bool bAction;
+bool bPCBrev03b;
+uint16_t volt_IR_int;
+float volt_IR;
+
+volt_IR_int=current_voltage_raw_IR;
+bPCBrev03b=(volt_IR_int<((int)IRsensor_Hopen_TRESHOLD));
+volt_IR=VOLT_DIV_REF*((float)volt_IR_int/(1023*OVERSAMPLENR));
+printf_P(PSTR("Measured filament sensor high level: %4.2fV\n"),volt_IR);
+if(volt_IR_int<((int)IRsensor_Hmin_TRESHOLD))
+     {
+     lcd_selftest_error(TestError::FsensorLevel,"HIGH","");
+     return(false);
+     }
+lcd_show_fullscreen_message_and_wait_P(_i("Please insert filament (but not load them!) into extruder and then press the knob."));
+volt_IR_int=current_voltage_raw_IR;
+volt_IR=VOLT_DIV_REF*((float)volt_IR_int/(1023*OVERSAMPLENR));
+printf_P(PSTR("Measured filament sensor low level: %4.2fV\n"),volt_IR);
+if(volt_IR_int>((int)IRsensor_Lmax_TRESHOLD))
+     {
+     lcd_selftest_error(TestError::FsensorLevel,"LOW","");
+     return(false);
+     }
+if((bPCBrev03b?1:0)!=(uint8_t)oFsensorPCB)        // safer then "(uint8_t)bPCBrev03b"
+     {
+     printf_P(PSTR("Filament sensor board change detected: revision %S\n"),bPCBrev03b?PSTR("03b or newer"):PSTR("03 or older"));
+     oFsensorPCB=bPCBrev03b?ClFsensorPCB::_Rev03b:ClFsensorPCB::_Old;
+     eeprom_update_byte((uint8_t*)EEPROM_FSENSOR_PCB,(uint8_t)oFsensorPCB);
+     }
+return(true);
+}
+#endif //IR_SENSOR_ANALOG
 
 static void lcd_selftest_v()
 {
@@ -7346,8 +7547,20 @@ bool lcd_selftest()
 	#ifdef TMC2130
 	  FORCE_HIGH_POWER_START;
 	#endif // TMC2130
+#if !IR_SENSOR_ANALOG
+     _delay(2000);
+#endif //!IR_SENSOR_ANALOG
+    
+    FORCE_BL_ON_START;
+    
 	_delay(2000);
 	KEEPALIVE_STATE(IN_HANDLER);
+#if IR_SENSOR_ANALOG
+     bool bAction;
+     bAction=lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Is filament unloaded?"),false,true);
+     if(!bAction)
+          return(false);
+#endif //IR_SENSOR_ANALOG
 
 	_progress = lcd_selftest_screen(TestScreen::ExtruderFan, _progress, 3, true, 2000);
 #if (defined(FANCHECK) && defined(TACH_0))
@@ -7543,12 +7756,20 @@ bool lcd_selftest()
         {
 #ifdef PAT9125
 			_progress = lcd_selftest_screen(TestScreen::Fsensor, _progress, 3, true, 2000); //check filaments sensor
-            _result = lcd_selftest_fsensor();
+               _result = lcd_selftest_fsensor();
 			if (_result)
 			{
 				_progress = lcd_selftest_screen(TestScreen::FsensorOk, _progress, 3, true, 2000); //fil sensor OK
 			}
 #endif //PAT9125
+#if IR_SENSOR_ANALOG
+			_progress = lcd_selftest_screen(TestScreen::Fsensor, _progress, 3, true, 2000); //check filament sensor
+               _result = lcd_selftest_IRsensor();
+			if (_result)
+			{
+				_progress = lcd_selftest_screen(TestScreen::FsensorOk, _progress, 3, true, 2000); //filament sensor OK
+			}
+#endif //IR_SENSOR_ANALOG
         }
     }
 #endif //FILAMENT_SENSOR
@@ -7575,7 +7796,10 @@ bool lcd_selftest()
 	#ifdef TMC2130
 	  FORCE_HIGH_POWER_END;
 	#endif // TMC2130
-	KEEPALIVE_STATE(NOT_BUSY);
+    
+    FORCE_BL_ON_END;
+	
+    KEEPALIVE_STATE(NOT_BUSY);
 	return(_result);
 }
 
@@ -7982,7 +8206,9 @@ static bool lcd_selfcheck_check_heater(bool _isbed)
 static void lcd_selftest_error(TestError testError, const char *_error_1, const char *_error_2)
 {
 	lcd_beeper_quick_feedback();
-
+    
+    FORCE_BL_ON_END;
+    
 	target_temperature[0] = 0;
 	target_temperature_bed = 0;
 	manage_heater();
@@ -8082,11 +8308,17 @@ static void lcd_selftest_error(TestError testError, const char *_error_1, const
 		lcd_puts_P(_T(MSG_SELFTEST_WIRINGERROR));
 		break;
 	case TestError::TriggeringFsensor:
-	    lcd_set_cursor(0, 2);
-        lcd_puts_P(_T(MSG_SELFTEST_FILAMENT_SENSOR));
-        lcd_set_cursor(0, 3);
-        lcd_puts_P(_i("False triggering"));////c=20
-        break;
+          lcd_set_cursor(0, 2);
+          lcd_puts_P(_T(MSG_SELFTEST_FILAMENT_SENSOR));
+          lcd_set_cursor(0, 3);
+          lcd_puts_P(_i("False triggering"));////c=20
+          break;
+	case TestError::FsensorLevel:
+          lcd_set_cursor(0, 2);
+          lcd_puts_P(_T(MSG_SELFTEST_FILAMENT_SENSOR));
+          lcd_set_cursor(0, 3);
+          lcd_printf_P(_i("%s level expected"),_error_1);////c=20
+          break;
 	}
 
 	_delay(1000);
@@ -8575,6 +8807,7 @@ void ultralcd_init()
         else lcd_autoDeplete = autoDepleteRaw;
 
     }
+    backlight_init();
 	lcd_init();
 	lcd_refresh();
 	lcd_longpress_func = menu_lcd_longpress_func;
@@ -8723,6 +8956,7 @@ uint8_t get_message_level()
 
 void menu_lcd_longpress_func(void)
 {
+	backlight_wake();
     if (homing_flag || mesh_bed_leveling_flag || menu_menu == lcd_babystep_z || menu_menu == lcd_move_z)
     {
         // disable longpress during re-entry, while homing or calibration
@@ -8804,6 +9038,7 @@ void menu_lcd_lcdupdate_func(void)
 		lcd_draw_update = 2;
 		lcd_oldcardstatus = IS_SD_INSERTED;
 		lcd_refresh(); // to maybe revive the LCD if static electricity killed it.
+        backlight_wake();
 		if (lcd_oldcardstatus)
 		{
 			card.initsd();
@@ -8821,6 +9056,7 @@ void menu_lcd_lcdupdate_func(void)
 		}
 	}
 #endif//CARDINSERTED
+    backlight_update();
 	if (lcd_next_update_millis < _millis())
 	{
 		if (abs(lcd_encoder_diff) >= ENCODER_PULSES_PER_STEP)
@@ -8831,9 +9067,14 @@ void menu_lcd_lcdupdate_func(void)
 			Sound_MakeSound(e_SOUND_TYPE_EncoderMove);
 			lcd_encoder_diff = 0;
 			lcd_timeoutToStatus.start();
+			backlight_wake();
 		}
 
-		if (LCD_CLICKED) lcd_timeoutToStatus.start();
+		if (LCD_CLICKED)
+		{
+			lcd_timeoutToStatus.start();
+			backlight_wake();
+		}
 
 		(*menu_menu)();
 

+ 14 - 0
Firmware/ultralcd.h

@@ -6,6 +6,9 @@
 #include "conv2str.h"
 #include "menu.h"
 #include "mesh_bed_calibration.h"
+#include "config.h"
+
+#include "config.h"
 
 extern void menu_lcd_longpress_func(void);
 extern void menu_lcd_charsetup_func(void);
@@ -47,6 +50,7 @@ unsigned char lcd_choose_color();
 void lcd_load_filament_color_check();
 //void lcd_mylang();
 
+extern void lcd_belttest();
 extern bool lcd_selftest();
 
 void lcd_menu_statistics(); 
@@ -217,7 +221,9 @@ void lcd_set_degree();
 void lcd_set_progress();
 #endif
 
+#if (LANG_MODE != 0)
 void lcd_language();
+#endif
 
 void lcd_wizard();
 bool lcd_autoDepleteEnabled();
@@ -244,4 +250,12 @@ enum class WizState : uint8_t
 
 void lcd_wizard(WizState state);
 
+#define VOLT_DIV_REF 5
+#if IR_SENSOR_ANALOG
+#define IRsensor_Hmin_TRESHOLD (3.0*1023*OVERSAMPLENR/VOLT_DIV_REF) // ~3.0V (0.6*Vcc)
+#define IRsensor_Lmax_TRESHOLD (1.5*1023*OVERSAMPLENR/VOLT_DIV_REF) // ~1.5V (0.3*Vcc)
+#define IRsensor_Hopen_TRESHOLD (4.6*1023*OVERSAMPLENR/VOLT_DIV_REF) // ~4.6V (N.C. @ Ru~20-50k, Rd'=56k, Ru'=10k)
+#define IRsensor_Ldiode_TRESHOLD (0.3*1023*OVERSAMPLENR/VOLT_DIV_REF) // ~0.3V
+#endif //IR_SENSOR_ANALOG
+
 #endif //ULTRALCD_H

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

@@ -504,7 +504,7 @@
 #define MMU_REQUIRED_FW_BUILDNR 132
 #define MMU_FORCE_STEALTH_MODE
 #define MMU_DEBUG //print communication between MMU2 and printer on serial
-//#define MMU_HAS_CUTTER
+#define MMU_HAS_CUTTER
 
 #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
 

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

@@ -505,7 +505,7 @@
 #define MMU_REQUIRED_FW_BUILDNR 132
 #define MMU_FORCE_STEALTH_MODE
 #define MMU_DEBUG //print communication between MMU2 and printer on serial
-//#define MMU_HAS_CUTTER
+#define MMU_HAS_CUTTER
 
 #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
 

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

@@ -504,7 +504,7 @@
 #define MMU_REQUIRED_FW_BUILDNR 132
 #define MMU_FORCE_STEALTH_MODE
 #define MMU_DEBUG //print communication between MMU2 and printer on serial
-//#define MMU_HAS_CUTTER
+#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

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

@@ -505,7 +505,7 @@
 #define MMU_REQUIRED_FW_BUILDNR 132
 #define MMU_FORCE_STEALTH_MODE
 #define MMU_DEBUG //print communication between MMU2 and printer on serial
-//#define MMU_HAS_CUTTER
+#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

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

@@ -260,11 +260,13 @@
 #define TMC2130_SG_THRS_Y       3     // stallguard sensitivity for Y axis
 #define TMC2130_SG_THRS_Z       4     // stallguard sensitivity for Z axis
 #define TMC2130_SG_THRS_E       3     // stallguard sensitivity for E axis
+#define TMC2130_SG_THRS_HOME {3, 3, TMC2130_SG_THRS_Z, TMC2130_SG_THRS_E}
 
 //new settings is possible for vsense = 1, running current value > 31 set vsense to zero and shift both currents by 1 bit right (Z axis only)
 #define TMC2130_CURRENTS_H {16, 20, 35, 30}  // default holding currents for all axes
 #define TMC2130_CURRENTS_R {16, 20, 35, 30}  // default running currents for all axes
-#define TMC2130_UNLOAD_CURRENT_R 12			 // lowe current for M600 to protect filament sensor 
+#define TMC2130_CURRENTS_R_HOME {8, 10, 20, 18}  // homing running currents for all axes
+// #define TMC2130_UNLOAD_CURRENT_R 12			 // lower current for M600 to protect filament sensor - Unused
 
 #define TMC2130_STEALTH_Z
 
@@ -628,7 +630,7 @@
 #define MMU_REQUIRED_FW_BUILDNR 83
 #define MMU_HWRESET
 #define MMU_DEBUG //print communication between MMU2 and printer on serial
-//#define MMU_HAS_CUTTER
+#define MMU_HAS_CUTTER
 #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

+ 4 - 2
Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h

@@ -262,11 +262,13 @@
 #define TMC2130_SG_THRS_Y       3     // stallguard sensitivity for Y axis
 #define TMC2130_SG_THRS_Z       4     // stallguard sensitivity for Z axis
 #define TMC2130_SG_THRS_E       3     // stallguard sensitivity for E axis
+#define TMC2130_SG_THRS_HOME {3, 3, TMC2130_SG_THRS_Z, TMC2130_SG_THRS_E}
 
 //new settings is possible for vsense = 1, running current value > 31 set vsense to zero and shift both currents by 1 bit right (Z axis only)
 #define TMC2130_CURRENTS_H {16, 20, 35, 30}  // default holding currents for all axes
 #define TMC2130_CURRENTS_R {16, 20, 35, 30}  // default running currents for all axes
-#define TMC2130_UNLOAD_CURRENT_R 12			 // lowe current for M600 to protect filament sensor 
+#define TMC2130_CURRENTS_R_HOME {8, 10, 20, 18}  // homing running currents for all axes
+// #define TMC2130_UNLOAD_CURRENT_R 12			 // lower current for M600 to protect filament sensor - Unused
 
 #define TMC2130_STEALTH_Z
 
@@ -630,7 +632,7 @@
 #define MMU_REQUIRED_FW_BUILDNR 83
 #define MMU_HWRESET
 #define MMU_DEBUG //print communication between MMU2 and printer on serial
-//#define MMU_HAS_CUTTER
+#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

+ 61 - 56
PF-build.sh

@@ -56,7 +56,7 @@
 #   Some may argue that this is only used by a script, BUT as soon someone accidentally or on purpose starts Arduino IDE
 #   it will use the default Arduino IDE folders and so can corrupt the build environment.
 #
-# Version: 1.0.6-Build_9
+# Version: 1.0.6-Build_10
 # Change log:
 # 12 Jan 2019, 3d-gussner, Fixed "compiler.c.elf.flags=-w -Os -Wl,-u,vfprintf -lprintf_flt -lm -Wl,--gc-sections" in 'platform.txt'
 # 16 Jan 2019, 3d-gussner, Build_2, Added development check to modify 'Configuration.h' to prevent unwanted LCD messages that Firmware is unknown
@@ -112,7 +112,9 @@
 #                          Changed Hex-files folder to PF-build-hex as requested in PR
 # 23 Jul 2019, 3d-gussner, Added Finding OS version routine so supporting new OS should get easier
 # 26 Jul 2019, 3d-gussner, Change JSON repository to prusa3d after PR https://github.com/prusa3d/Arduino_Boards/pull/1 was merged
-
+# 23 Sep 2019, 3d-gussner, Prepare PF-build.sh for comming Prusa3d/Arduino_Boards version 1.0.2 Pull Request
+# 17 Oct 2019, 3d-gussner, Changed folder and check file names to have seperated build enviroments depening on Arduino IDE version and
+#                          board-versions. 
 #### Start check if OSTYPE is supported
 OS_FOUND=$( command -v uname)
 
@@ -211,7 +213,8 @@ fi
 #### Set build environment 
 ARDUINO_ENV="1.8.5"
 BUILD_ENV="1.0.6"
-BOARD="PrusaResearchRambo"
+BOARD="rambo"
+BOARD_PACKAGE_NAME="PrusaResearchRambo"
 BOARD_VERSION="1.0.1"
 BOARD_URL="https://raw.githubusercontent.com/prusa3d/Arduino_Boards/master/IDE_Board_Manager/package_prusa3d_index.json"
 BOARD_FILENAME="prusa3drambo"
@@ -229,6 +232,7 @@ echo ""
 echo "Ardunio IDE :" $ARDUINO_ENV
 echo "Build env   :" $BUILD_ENV
 echo "Board       :" $BOARD
+echo "Package name:" $BOARD_PACKAGE_NAME
 echo "Specific Lib:" $LIB
 echo ""
 
@@ -259,12 +263,12 @@ if [ $TARGET_OS == "windows" ]; then
 		wget https://downloads.arduino.cc/arduino-$ARDUINO_ENV-windows.zip || exit 7
 		echo "$(tput sgr 0)"
 	fi
-	if [ ! -d "../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor" ]; then
+	if [[ ! -d "../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor" && ! -e "../PF-build-env-$BUILD_ENV/arduino-$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor.txt" ]]; then
 		echo "$(tput setaf 6)Unzipping Windows 32/64-bit Arduino IDE portable...$(tput setaf 2)"
 		sleep 2
 		unzip arduino-$ARDUINO_ENV-windows.zip -d ../PF-build-env-$BUILD_ENV || exit 7
-		mv ../PF-build-env-$BUILD_ENV/arduino-$ARDUINO_ENV ../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor
-		echo "# arduino-$ARDUINO_ENV-$TARGET_OS-$Processor" >> ../PF-build-env-$BUILD_ENV/arduino-$ARDUINO_ENV-$TARGET_OS-$Processor
+		mv ../PF-build-env-$BUILD_ENV/arduino-$ARDUINO_ENV ../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor
+		echo "# arduino-$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor" >> ../PF-build-env-$BUILD_ENV/arduino-$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor.txt
 		echo "$(tput sgr0)"
 	fi
 fi
@@ -277,55 +281,55 @@ if [ $TARGET_OS == "linux" ]; then
 		wget --no-check-certificate https://downloads.arduino.cc/arduino-$ARDUINO_ENV-linux$Processor.tar.xz || exit 8
 		echo "$(tput sgr 0)"
 	fi
-	if [[ ! -d "../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor" && ! -e "../PF-build-env-$BUILD_ENV/arduino-$ARDUINO_ENV-$TARGET_OS-$Processor.txt" ]]; then
+	if [[ ! -d "../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor" && ! -e "../PF-build-env-$BUILD_ENV/arduino-$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor.txt" ]]; then
 		echo "$(tput setaf 6)Unzipping Linux $Processor Arduino IDE portable...$(tput setaf 2)"
 		sleep 2
 		tar -xvf arduino-$ARDUINO_ENV-linux$Processor.tar.xz -C ../PF-build-env-$BUILD_ENV/ || exit 8
-		mv ../PF-build-env-$BUILD_ENV/arduino-$ARDUINO_ENV ../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor
-		echo "# arduino-$ARDUINO_ENV-$TARGET_OS-$Processor" >> ../PF-build-env-$BUILD_ENV/arduino-$ARDUINO_ENV-$TARGET_OS-$Processor.txt
+		mv ../PF-build-env-$BUILD_ENV/arduino-$ARDUINO_ENV ../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor
+		echo "# arduino-$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor" >> ../PF-build-env-$BUILD_ENV/arduino-$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor.txt
 		echo "$(tput sgr0)"
 	fi
 fi
 # Make Arduino IDE portable
-if [ ! -d ../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/ ]; then
-	mkdir ../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/
+if [ ! -d ../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/ ]; then
+	mkdir ../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/
 fi
 
-if [ ! -d ../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/portable/ ]; then
-	mkdir ../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/portable
+if [ ! -d ../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/portable/ ]; then
+	mkdir ../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/portable
 fi
-if [ ! -d ../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/portable/output/ ]; then
-	mkdir ../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/portable/output
+if [ ! -d ../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/portable/output/ ]; then
+	mkdir ../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/portable/output
 fi
-if [ ! -d ../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/portable/packages/ ]; then
-	mkdir ../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/portable/packages
+if [ ! -d ../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/portable/packages/ ]; then
+	mkdir ../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/portable/packages
 fi
-if [ ! -d ../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/portable/sketchbook/ ]; then
-	mkdir ../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/portable/sketchbook
+if [ ! -d ../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/portable/sketchbook/ ]; then
+	mkdir ../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/portable/sketchbook
 fi
-if [ ! -d ../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/portable/sketchbook/libraries/ ]; then
-	mkdir ../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/portable/sketchbook/libraries
+if [ ! -d ../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/portable/sketchbook/libraries/ ]; then
+	mkdir ../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/portable/sketchbook/libraries
 fi
-if [ ! -d ../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/portable/staging/ ]; then
-	mkdir ../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/portable/staging
+if [ ! -d ../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/portable/staging/ ]; then
+	mkdir ../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/portable/staging
 fi
 
 # Change Arduino IDE preferences
-if [ ! -e ../PF-build-env-$BUILD_ENV/Preferences-$TARGET_OS-$Processor.txt ]; then
-	echo "$(tput setaf 6)Setting $TARGET_OS-$Processor Arduino IDE preferences for portable GUI usage...$(tput setaf 2)"
+if [ ! -e ../PF-build-env-$BUILD_ENV/Preferences-$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor.txt ]; then
+	echo "$(tput setaf 6)Setting $ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor Arduino IDE preferences for portable GUI usage...$(tput setaf 2)"
 	sleep 2
 	echo "update.check"
-	sed -i 's/update.check = true/update.check = false/g' ../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/lib/preferences.txt
+	sed -i 's/update.check = true/update.check = false/g' ../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/lib/preferences.txt
 	echo "board"
-	sed -i 's/board = uno/board = rambo/g' ../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/lib/preferences.txt
+	sed -i 's/board = uno/board = $BOARD/g' ../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/lib/preferences.txt
 	echo "editor.linenumbers"
-	sed -i 's/editor.linenumbers = false/editor.linenumbers = true/g' ../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/lib/preferences.txt
+	sed -i 's/editor.linenumbers = false/editor.linenumbers = true/g' ../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/lib/preferences.txt
 	echo "boardsmanager.additional.urls"
-	echo "boardsmanager.additional.urls=$BOARD_URL" >>../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/lib/preferences.txt
-	echo "build.verbose=true" >>../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/lib/preferences.txt
-	echo "compiler.cache_core=false" >>../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/lib/preferences.txt
-	echo "compiler.warning_level=all" >>../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/lib/preferences.txt
-	echo "# Preferences-$TARGET_OS-$Processor" >> ../PF-build-env-$BUILD_ENV/Preferences-$TARGET_OS-$Processor.txt
+	echo "boardsmanager.additional.urls=$BOARD_URL" >>../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/lib/preferences.txt
+	echo "build.verbose=true" >>../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/lib/preferences.txt
+	echo "compiler.cache_core=false" >>../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/lib/preferences.txt
+	echo "compiler.warning_level=all" >>../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/lib/preferences.txt
+	echo "# Preferences-$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor" >> ../PF-build-env-$BUILD_ENV/Preferences-$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor.txt
 	echo "$(tput sgr0)"
 fi
 
@@ -336,25 +340,26 @@ if [ ! -f "$BOARD_FILENAME-$BOARD_VERSION.tar.bz2" ]; then
 	sleep 2
 	wget $BOARD_FILE_URL || exit 9
 fi
-if [[ ! -d "../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/portable/packages/$BOARD/hardware/avr/$BOARD_VERSION" || ! -e "../PF-build-env-$BUILD_ENV/$BOARD_FILENAME-$BOARD_VERSION-$TARGET_OS-$Processor.txt" ]]; then
-	echo "$(tput setaf 6)Unzipping $BOARD Arduino IDE portable...$(tput setaf 2)"
+if [[ ! -d "../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/portable/packages/$BOARD_PACKAGE_NAME/hardware/avr/$BOARD_VERSION" || ! -e "../PF-build-env-$BUILD_ENV/$BOARD_FILENAME-$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor.txt" ]]; then
+	echo "$(tput setaf 6)Unzipping $BOARD_PACKAGE_NAME Arduino IDE portable...$(tput setaf 2)"
 	sleep 2
 	tar -xvf $BOARD_FILENAME-$BOARD_VERSION.tar.bz2 -C ../PF-build-env-$BUILD_ENV/ || exit 10
-	if [ ! -d ../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/portable/packages/$BOARD ]; then
-		mkdir ../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/portable/packages/$BOARD
+	if [ ! -d ../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/portable/packages/$BOARD_PACKAGE_NAME ]; then
+		mkdir ../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/portable/packages/$BOARD_PACKAGE_NAME
 	fi
-	if [ ! -d ../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/portable/packages/$BOARD ]; then
-		mkdir ../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/portable/packages/$BOARD
+	if [ ! -d ../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/portable/packages/$BOARD_PACKAGE_NAME ]; then
+		mkdir ../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/portable/packages/$BOARD_PACKAGE_NAME
 	fi
-	if [ ! -d ../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/portable/packages/$BOARD/hardware ]; then
-		mkdir ../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/portable/packages/$BOARD/hardware
+	if [ ! -d ../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/portable/packages/$BOARD_PACKAGE_NAME/hardware ]; then
+		mkdir ../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/portable/packages/$BOARD_PACKAGE_NAME/hardware
 	fi
-	if [ ! -d ../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/portable/packages/$BOARD/hardware/avr ]; then
-		mkdir ../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/portable/packages/$BOARD/hardware/avr
+	if [ ! -d ../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/portable/packages/$BOARD_PACKAGE_NAME/hardware/avr ]; then
+		mkdir ../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/portable/packages/$BOARD_PACKAGE_NAME/hardware/avr
 	fi
 	
-	mv ../PF-build-env-$BUILD_ENV/$BOARD_FILENAME-$BOARD_VERSION ../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/portable/packages/$BOARD/hardware/avr/$BOARD_VERSION
-	echo "# $BOARD_FILENAME-$BOARD_VERSION" >> ../PF-build-env-$BUILD_ENV/$BOARD_FILENAME-$BOARD_VERSION-$TARGET_OS-$Processor.txt
+	mv ../PF-build-env-$BUILD_ENV/$BOARD_FILENAME-$BOARD_VERSION ../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/portable/packages/$BOARD_PACKAGE_NAME/hardware/avr/$BOARD_VERSION
+	echo "# $BOARD_FILENAME-$BOARD_VERSION" >> ../PF-build-env-$BUILD_ENV/$BOARD_FILENAME-$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor.txt
+
 	echo "$(tput sgr 0)"
 fi	
 
@@ -365,30 +370,30 @@ if [ ! -f "PF-build-env-$BUILD_ENV.zip" ]; then
 	wget $PF_BUILD_FILE_URL || exit 11
 	echo "$(tput sgr 0)"
 fi
-if [ ! -e "../PF-build-env-$BUILD_ENV/PF-build-env-$BUILD_ENV-$TARGET_OS-$Processor.txt" ]; then
+if [ ! -e "../PF-build-env-$BUILD_ENV/PF-build-env-$BUILD_ENV-$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor.txt" ]; then
 	echo "$(tput setaf 6)Unzipping Prusa Firmware build environment...$(tput setaf 2)"
 	sleep 2
-	unzip -o PF-build-env-$BUILD_ENV.zip -d ../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor || exit 12
-	echo "# PF-build-env-$TARGET_OS-$Processor-$BUILD_ENV" >> ../PF-build-env-$BUILD_ENV/PF-build-env-$BUILD_ENV-$TARGET_OS-$Processor.txt
+	unzip -o PF-build-env-$BUILD_ENV.zip -d ../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor || exit 12
+	echo "# PF-build-env-$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor-$BUILD_ENV" >> ../PF-build-env-$BUILD_ENV/PF-build-env-$BUILD_ENV-$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor.txt
 	echo "$(tput sgr0)"
 fi
 
 # Check if User updated Arduino IDE 1.8.5 boardsmanager and tools
-if [ -d "../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/portable/packages/arduino/tools" ]; then
+if [ -d "../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/portable/packages/arduino/tools" ]; then
 	echo "$(tput setaf 6)Arduino IDE boards / tools have been manually updated...$"
 	echo "Please don't update the 'Arduino AVR boards' as this will prevent running this script (tput setaf 2)"
 	sleep 2
 fi	
-if [ -d "../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/portable/packages/arduino/tools/avr-gcc/4.9.2-atmel3.5.4-arduino2" ]; then
+if [ -d "../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/portable/packages/arduino/tools/avr-gcc/4.9.2-atmel3.5.4-arduino2" ]; then
 	echo "$(tput setaf 6)PrusaReasearch compatible tools have been manually updated...$(tput setaf 2)"
 	sleep 2
 	echo "$(tput setaf 6)Copying Prusa Firmware build environment to manually updated boards / tools...$(tput setaf 2)"
 	sleep 2
-	cp -f ../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/hardware/tools/avr/avr/lib/ldscripts/avr6.xn ../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/portable/packages/arduino/tools/avr-gcc/4.9.2-atmel3.5.4-arduino2/avr/lib/ldscripts/avr6.xn
-	echo "# PF-build-env-portable-$TARGET_OS-$Processor-$BUILD_ENV" >> ../PF-build-env-$BUILD_ENV/PF-build-env-portable-$BUILD_ENV-$TARGET_OS-$Processor.txt
+	cp -f ../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/hardware/tools/avr/avr/lib/ldscripts/avr6.xn ../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/portable/packages/arduino/tools/avr-gcc/4.9.2-atmel3.5.4-arduino2/avr/lib/ldscripts/avr6.xn
+	echo "# PF-build-env-portable-$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor-$BUILD_ENV" >> ../PF-build-env-$BUILD_ENV/PF-build-env-portable-$BUILD_ENV-$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor.txt
 	echo "$(tput sgr0)"
 fi	
-if [ -d "../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor/portable/packages/arduino/tools/avr-gcc/5.4.0-atmel3.6.1-arduino2" ]; then
+if [ -d "../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor/portable/packages/arduino/tools/avr-gcc/5.4.0-atmel3.6.1-arduino2" ]; then
 	echo "$(tput setaf 1)Arduino IDE tools have been updated manually to a non supported version!!!"
 	echo "Delete ../PF-build-env-$BUILD_ENV and start the script again"
 	echo "Script will not continue until this have been fixed $(tput setaf 2)"
@@ -489,7 +494,7 @@ if [ ! -z "$3" ] ; then
 fi
 
 #Set BUILD_ENV_PATH
-cd ../PF-build-env-$BUILD_ENV/$TARGET_OS-$Processor || exit 24
+cd ../PF-build-env-$BUILD_ENV/$ARDUINO_ENV-$BOARD_VERSION-$TARGET_OS-$Processor || exit 24
 BUILD_ENV_PATH="$( pwd -P )"
 
 cd ../..
@@ -634,8 +639,8 @@ do
 	echo "Start to build Prusa Firmware ..."
 	echo "Using variant $VARIANT$(tput setaf 3)"
 	sleep 2
-	#$BUILD_ENV_PATH/arduino-builder -dump-prefs -debug-level 10 -compile -hardware $ARDUINO/hardware -hardware $ARDUINO/portable/packages -tools $ARDUINO/tools-builder -tools $ARDUINO/hardware/tools/avr -tools $ARDUINO/portable/packages -built-in-libraries $ARDUINO/libraries -libraries $ARDUINO/portable/sketchbook/libraries -fqbn=$BOARD:avr:rambo -ide-version=10805 -build-path=$BUILD_PATH -warnings=all $SCRIPT_PATH/Firmware/Firmware.ino || exit 14
-	$BUILD_ENV_PATH/arduino-builder -compile -hardware $ARDUINO/hardware -hardware $ARDUINO/portable/packages -tools $ARDUINO/tools-builder -tools $ARDUINO/hardware/tools/avr -tools $ARDUINO/portable/packages -built-in-libraries $ARDUINO/libraries -libraries $ARDUINO/portable/sketchbook/libraries -fqbn=$BOARD:avr:rambo -ide-version=10805 -build-path=$BUILD_PATH -warnings=all $SCRIPT_PATH/Firmware/Firmware.ino || exit 14
+	#$BUILD_ENV_PATH/arduino-builder -dump-prefs -debug-level 10 -compile -hardware $ARDUINO/hardware -hardware $ARDUINO/portable/packages -tools $ARDUINO/tools-builder -tools $ARDUINO/hardware/tools/avr -tools $ARDUINO/portable/packages -built-in-libraries $ARDUINO/libraries -libraries $ARDUINO/portable/sketchbook/libraries -fqbn=$BOARD_PACKAGE_NAME:avr:$BOARD -build-path=$BUILD_PATH -warnings=all $SCRIPT_PATH/Firmware/Firmware.ino || exit 14
+	$BUILD_ENV_PATH/arduino-builder -compile -hardware $ARDUINO/hardware -hardware $ARDUINO/portable/packages -tools $ARDUINO/tools-builder -tools $ARDUINO/hardware/tools/avr -tools $ARDUINO/portable/packages -built-in-libraries $ARDUINO/libraries -libraries $ARDUINO/portable/sketchbook/libraries -fqbn=$BOARD_PACKAGE_NAME:avr:$BOARD -build-path=$BUILD_PATH -warnings=all $SCRIPT_PATH/Firmware/Firmware.ino || exit 14
 	echo "$(tput sgr 0)"
 
 	if [ $LANGUAGES ==  "ALL" ]; then

+ 1 - 0
README.md

@@ -178,6 +178,7 @@ Example:
 
 # 4. Documentation
 run [doxygen](http://www.doxygen.nl/) in Firmware folder
+or visit https://prusa3d.github.io/Prusa-Firmware-Doc for doxygen generated output
 
 # 5. FAQ
 Q:I built firmware using Arduino and I see "?" instead of numbers in printer user interface.

+ 2 - 3
Tests/PrusaStatistics_test.cpp

@@ -198,7 +198,7 @@ void prusa_statistics(int _message, uint8_t _fil_nr) {
 			SERIAL_ECHOLN("}");
 			status_number = 15;
 		}
-		else if (isPrintPaused || card.paused) 
+		else if (isPrintPaused)
 		{
 			SERIAL_ECHO("{");
 			prusa_stat_printerstatus(14);
@@ -490,7 +490,7 @@ void prusa_statistics(int _message, uint8_t _fil_nr) {
 		{   
 			prusa_statistics_case0(15);
 		}
-		else if (isPrintPaused || card.paused) 
+		else if (isPrintPaused)
 		{
 			prusa_statistics_case0(14);
 		}
@@ -753,7 +753,6 @@ TEST_CASE("Prusa_statistics test", "[prusa_stats]")
 				SERIALS_RESET();
 
 				isPrintPaused = 0;
-				card.paused = 0;
 				IS_SD_PRINTING = 1;
 				old_code::prusa_statistics(test_codes[i],0);
 				new_code::prusa_statistics(test_codes[i],0);

+ 1 - 1
lang/lang-add.sh

@@ -51,7 +51,7 @@ if ! [ -e lang_add.txt ]; then
 fi
 
 cat lang_add.txt | sed 's/^/"/;s/$/"/' | while read new_s; do
-	if grep "$new_s" lang_en.txt >/dev/nul; then
+	if grep "$new_s" lang_en.txt >/dev/null; then
 		echo "text already exist:"
 		echo "$new_s"
 		echo

+ 92 - 141
lang/lang_en.txt

@@ -37,14 +37,8 @@
 #MSG_CONFIRM_CARRIAGE_AT_THE_TOP c=20 r=2
 "Are left and right Z~carriages all up?"
 
-#MSG_AUTO_DEPLETE_ON c=17 r=1
-"SpoolJoin    [on]"
-
-#
-"SpoolJoin   [N/A]"
-
-#MSG_AUTO_DEPLETE_OFF c=17 r=1
-"SpoolJoin   [off]"
+#MSG_AUTO_DEPLETE c=17 r=1
+"SpoolJoin"
 
 #MSG_AUTO_HOME
 "Auto home"
@@ -130,14 +124,10 @@
 #
 "Copy selected language?"
 
-#MSG_CRASHDETECT_ON
-"Crash det.   [on]"
-
-#MSG_CRASHDETECT_NA
-"Crash det.  [N/A]"
-
-#MSG_CRASHDETECT_OFF
-"Crash det.  [off]"
+#MSG_CRASHDETECT
+"Crash det."
+#
+"Choose a filament for the First Layer Calibration and select it in the on-screen menu."
 
 #MSG_CRASH_DETECTED c=20 r=1
 "Crash detected."
@@ -202,14 +192,8 @@
 #
 "Fail stats MMU"
 
-#MSG_FSENS_AUTOLOAD_ON c=17 r=1
-"F. autoload  [on]"
-
-#MSG_FSENS_AUTOLOAD_NA c=17 r=1
-"F. autoload [N/A]"
-
-#MSG_FSENS_AUTOLOAD_OFF c=17 r=1
-"F. autoload [off]"
+#MSG_FSENSOR_AUTOLOAD
+"F. autoload"
 
 #
 "Fail stats"
@@ -220,20 +204,11 @@
 #MSG_SELFTEST_FAN c=20
 "Fan test"
 
-#MSG_FANS_CHECK_ON c=17 r=1
-"Fans check   [on]"
-
-#MSG_FANS_CHECK_OFF c=17 r=1
-"Fans check  [off]"
+#MSG_FANS_CHECK
+"Fans check"
 
-#MSG_FSENSOR_ON
-"Fil. sensor  [on]"
-
-#MSG_FSENSOR_NA
-"Fil. sensor [N/A]"
-
-#MSG_FSENSOR_OFF
-"Fil. sensor [off]"
+#MSG_FSENSOR
+"Fil. sensor"
 
 #
 "Filam. runouts"
@@ -361,6 +336,9 @@
 #
 "Last print failures"
 
+#
+"If you have additional steel sheets, calibrate their presets in Settings - HW Setup - Steel sheets."
+
 #
 "Last print"
 
@@ -427,11 +405,14 @@
 #MSG_MMU_OK_RESUMING c=20 r=4
 "MMU OK. Resuming..."
 
-#MSG_STEALTH_MODE_OFF
-"Mode     [Normal]"
+#MSG_MODE
+"Mode"
 
-#MSG_SILENT_MODE_ON
-"Mode     [silent]"
+#MSG_NORMAL
+"Normal"
+
+#MSG_SILENT
+"Silent"
 
 #
 "MMU needs user attention."
@@ -439,14 +420,14 @@
 #
 "MMU power fails"
 
-#MSG_STEALTH_MODE_ON
-"Mode    [Stealth]"
+#MSG_STEALTH
+"Stealth"
 
-#MSG_AUTO_MODE_ON
-"Mode [auto power]"
+#MSG_AUTO_POWER
+"Auto power"
 
-#MSG_SILENT_MODE_OFF
-"Mode [high power]"
+#MSG_HIGH_POWER
+"High power"
 
 #
 "MMU2 connected"
@@ -472,7 +453,7 @@
 #MSG_NO_CARD
 "No SD card"
 
-#
+#MSG_NA
 "N/A"
 
 #MSG_NO
@@ -613,6 +594,15 @@
 #
 "Print FAN"
 
+#
+"Please insert filament into the extruder, then press the knob to load it."
+
+#
+"Please insert filament into the first tube of the MMU, then press the knob to load it."
+
+#
+"Please load filament first."
+
 #MSG_PRUSA3D
 "prusa3d.com"
 
@@ -643,20 +633,17 @@
 #MSG_BED_CORRECTION_RIGHT c=14 r=1
 "Right side[um]"
 
-#MSG_SECOND_SERIAL_ON c=17 r=1
-"RPi port     [on]"
-
-#MSG_SECOND_SERIAL_OFF c=17 r=1
-"RPi port    [off]"
+#MSG_RPI_PORT
+"RPi port"
 
 #MSG_WIZARD_RERUN c=20 r=7
 "Running Wizard will delete current calibration results and start from the beginning. Continue?"
 
-#MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF c=19 r=1
-"SD card  [normal]"
+#MSG_SD_CARD
+"SD card"
 
-#MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON c=19 r=1
-"SD card [flshAir]"
+#MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY
+"FlashAir"
 
 #
 "Right"
@@ -688,9 +675,6 @@
 #
 "Select nozzle preheat temperature which matches your material."
 
-#
-"Select PLA filament:"
-
 #MSG_SET_TEMPERATURE c=19 r=1
 "Set temperature:"
 
@@ -706,38 +690,38 @@
 #MSG_FILE_CNT c=20 r=4
 "Some files will not be sorted. Max. No. of files in 1 folder for sorting is 100."
 
-#MSG_SORT_NONE c=17 r=1
-"Sort       [none]"
+#MSG_SORT
+"Sort"
 
-#MSG_SORT_TIME c=17 r=1
-"Sort       [time]"
+#MSG_NONE
+"None"
+
+#MSG_SORT_TIME
+"Time"
 
 #
 "Severe skew:"
 
-#MSG_SORT_ALPHA c=17 r=1
-"Sort   [alphabet]"
+#MSG_SORT_ALPHA
+"Alphabet"
 
 #MSG_SORTING c=20 r=1
 "Sorting files"
 
-#MSG_SOUND_LOUD c=17 r=1
-"Sound      [loud]"
+#MSG_SOUND_LOUD
+"Loud"
 
 #
 "Slight skew:"
 
-#MSG_SOUND_MUTE c=17 r=1
-"Sound      [mute]"
+#MSG_SOUND
+"Sound"
 
 #
 "Some problem encountered, Z-leveling enforced ..."
 
-#MSG_SOUND_ONCE c=17 r=1
-"Sound      [once]"
-
-#MSG_SOUND_SILENT c=17 r=1
-"Sound    [silent]"
+#MSG_SOUND_ONCE
+"Once"
 
 #MSG_SPEED
 "Speed"
@@ -763,14 +747,14 @@
 #MSG_SELFTEST_SWAPPED
 "Swapped"
 
-#MSG_TEMP_CALIBRATION c=20 r=1
-"Temp. cal.          "
+#
+"Select filament:"
 
-#MSG_TEMP_CALIBRATION_ON c=20 r=1
-"Temp. cal.   [on]"
+#MSG_TEMP_CALIBRATION c=12 r=1
+"Temp. cal."
 
-#MSG_TEMP_CALIBRATION_OFF c=20 r=1
-"Temp. cal.  [off]"
+#
+"Select temperature which matches your material."
 
 #MSG_CALIBRATION_PINDA_MENU c=17 r=1
 "Temp. calibration"
@@ -904,11 +888,17 @@
 #
 "Y distance from min"
 
+#
+"The printer will start printing a zig-zag line. Rotate the knob until you reach the optimal height. Check the pictures in the handbook (Calibration chapter)."
+
 #
 "Y-correct:"
 
 #MSG_OFF
-" [off]"
+"Off"
+
+#MSG_ON
+"On"
 
 #
 "Back"
@@ -922,14 +912,14 @@
 #
 "FINDA:"
 
-#
-"Firmware   [none]"
+#MSG_FIRMWARE
+"Firmware"
 
-#
-"Firmware [strict]"
+#MSG_STRICT
+"Strict"
 
-#
-"Firmware   [warn]"
+#MSG_WARN
+"Warn"
 
 #
 "HW Setup"
@@ -937,20 +927,11 @@
 #
 "IR:"
 
-#
-"Magnets comp.[N/A]"
+#MSG_MAGNETS_COMP
+"Magnets comp."
 
-#
-"Magnets comp.[Off]"
-
-#
-"Magnets comp. [On]"
-
-#
-"Mesh         [3x3]"
-
-#
-"Mesh         [7x7]"
+#MSG_MESH
+"Mesh"
 
 #
 "Mesh bed leveling"
@@ -958,41 +939,17 @@
 #
 "MK3S firmware detected on MK3 printer"
 
-#
-"MMU Mode [Normal]"
-
-#
-"MMU Mode[Stealth]"
+#MSG_MMU_MODE
+"MMU Mode"
 
 #
 "Mode change in progress ..."
 
-#
-"Model      [none]"
-
-#
-"Model    [strict]"
-
-#
-"Model      [warn]"
+#MSG_MODEL
+"Model"
 
-#
-"Nozzle d.  [0.25]"
-
-#
-"Nozzle d.  [0.40]"
-
-#
-"Nozzle d.  [0.60]"
-
-#
-"Nozzle     [none]"
-
-#
-"Nozzle   [strict]"
-
-#
-"Nozzle     [warn]"
+#MSG_NOZZLE_DIAMETER
+"Nozzle d."
 
 #
 "G-code sliced for a different level. Continue?"
@@ -1039,8 +996,8 @@
 #
 "Sheet"
 
-#
-"Sound    [assist]"
+#MSG_SOUND_BLIND
+"Assist"
 
 #
 "Steel sheets"
@@ -1048,11 +1005,5 @@
 #
 "Z-correct:"
 
-#
-"Z-probe nr.    [1]"
-
-#
-"Z-probe nr.    [3]"
-
-#
-"Z-probe nr.    [5]"
+#MSG_Z_PROBE_NR
+"Z-probe nr."

+ 132 - 196
lang/lang_en_cz.txt

@@ -50,18 +50,10 @@
 "Are left and right Z~carriages all up?"
 "Dojely oba Z voziky k~hornimu dorazu?"
 
-#MSG_AUTO_DEPLETE_ON c=17 r=1
-"SpoolJoin    [on]"
-"SpoolJoin   [zap]"
-
-#
-"SpoolJoin   [N/A]"
+#MSG_AUTO_DEPLETE c=17 r=1
+"SpoolJoin"
 "\x00"
 
-#MSG_AUTO_DEPLETE_OFF c=17 r=1
-"SpoolJoin   [off]"
-"SpoolJoin   [vyp]"
-
 #MSG_AUTO_HOME
 "Auto home"
 "\x00"
@@ -72,7 +64,7 @@
 
 #MSG_AUTOLOADING_ONLY_IF_FSENS_ON c=20 r=4
 "Autoloading filament available only when filament sensor is turned on..."
-"Automaticke zavadeni filamentu je dostupne pouze pri zapnutem filament senzoru..."
+"Automaticke zavadeni filamentu je mozne pouze pri zapnutem filament senzoru..."
 
 #MSG_AUTOLOADING_ENABLED c=20 r=4
 "Autoloading filament is active, just press the knob and insert filament..."
@@ -174,17 +166,13 @@
 "Copy selected language?"
 "Kopirovat vybrany jazyk?"
 
-#MSG_CRASHDETECT_ON
-"Crash det.   [on]"
-"Crash det.  [zap]"
-
-#MSG_CRASHDETECT_NA
-"Crash det.  [N/A]"
+#MSG_CRASHDETECT
+"Crash det."
 "\x00"
 
-#MSG_CRASHDETECT_OFF
-"Crash det.  [off]"
-"Crash det.  [vyp]"
+#
+"Zvolte filament pro kalibraci prvni vrstvy z nasledujiciho menu"
+"Choose a filament for the First Layer Calibration and select it in the on-screen menu."
 
 #MSG_CRASH_DETECTED c=20 r=1
 "Crash detected."
@@ -270,17 +258,9 @@
 "Fail stats MMU"
 "Selhani MMU"
 
-#MSG_FSENS_AUTOLOAD_ON c=17 r=1
-"F. autoload  [on]"
-"F. autozav. [zap]"
-
-#MSG_FSENS_AUTOLOAD_NA c=17 r=1
-"F. autoload [N/A]"
-"F. autozav. [N/A]"
-
-#MSG_FSENS_AUTOLOAD_OFF c=17 r=1
-"F. autoload [off]"
-"F. autozav. [vyp]"
+#MSG_FSENSOR_AUTOLOAD
+"F. autoload"
+"F. autozav."
 
 #
 "Fail stats"
@@ -294,25 +274,13 @@
 "Fan test"
 "Test ventilatoru"
 
-#MSG_FANS_CHECK_ON c=17 r=1
-"Fans check   [on]"
-"Kontr. vent.[zap]"
-
-#MSG_FANS_CHECK_OFF c=17 r=1
-"Fans check  [off]"
-"Kontr. vent.[vyp]"
-
-#MSG_FSENSOR_ON
-"Fil. sensor  [on]"
-"Fil. senzor [zap]"
-
-#MSG_FSENSOR_NA
-"Fil. sensor [N/A]"
-"Fil. senzor [N/A]"
+#MSG_FANS_CHECK
+"Fans check"
+"Kontr. vent."
 
-#MSG_FSENSOR_OFF
-"Fil. sensor [off]"
-"Fil. senzor [vyp]"
+#MSG_FSENSOR
+"Fil. sensor"
+"Fil. senzor"
 
 #
 "Filam. runouts"
@@ -482,6 +450,10 @@
 "Last print failures"
 "Selhani posl. tisku"
 
+#
+"If you have additional steel sheets, calibrate their presets in Settings - HW Setup - Steel sheets."
+"Mate-li vice tiskovych platu, kalibrujte je v menu Nastaveni - HW nastaveni - Tiskove platy"
+
 #
 "Last print"
 "Posledni tisk"
@@ -570,13 +542,17 @@
 "MMU OK. Resuming..."
 "MMU OK. Pokracuji..."
 
-#MSG_STEALTH_MODE_OFF
-"Mode     [Normal]"
-"Mod      [Normal]"
+#MSG_MODE
+"Mode"
+"Mod"
 
-#MSG_SILENT_MODE_ON
-"Mode     [silent]"
-"Mod       [tichy]"
+#MSG_NORMAL
+"Normal"
+"\x00"
+
+#MSG_SILENT
+"Silent"
+"Tichy"
 
 #
 "MMU needs user attention."
@@ -586,17 +562,17 @@
 "MMU power fails"
 "MMU vypadky proudu"
 
-#MSG_STEALTH_MODE_ON
-"Mode    [Stealth]"
-"Mod       [tichy]"
+#MSG_STEALTH
+"Stealth"
+"Tichy"
 
-#MSG_AUTO_MODE_ON
-"Mode [auto power]"
-"Mod [automaticky]"
+#MSG_AUTO_POWER
+"Auto power"
+"Automaticky"
 
-#MSG_SILENT_MODE_OFF
-"Mode [high power]"
-"Mod  [vys. vykon]"
+#MSG_HIGH_POWER
+"High power"
+"Vys. vykon"
 
 #
 "MMU2 connected"
@@ -630,7 +606,7 @@
 "No SD card"
 "Zadna SD karta"
 
-#
+#MSG_NA
 "N/A"
 "\x00"
 
@@ -818,6 +794,18 @@
 "Print FAN"
 "Tiskovy vent."
 
+#
+"Please insert filament into the extruder, then press the knob to load it."
+"Prosim vlozte filament do extruderu a stisknete tlacitko k jeho zavedeni"
+
+#
+"Please insert filament into the first tube of the MMU, then press the knob to load it."
+"Prosim vlozte filament do prvni trubicky MMU a stisknete tlacitko k jeho zavedeni"
+
+#
+"Please load filament first."
+"Prosim nejdriv zavedte filament"
+
 #MSG_PRUSA3D
 "prusa3d.com"
 "\x00"
@@ -858,25 +846,21 @@
 "Right side[um]"
 "Vpravo [um]"
 
-#MSG_SECOND_SERIAL_ON c=17 r=1
-"RPi port     [on]"
-"RPi port    [zap]"
-
-#MSG_SECOND_SERIAL_OFF c=17 r=1
-"RPi port    [off]"
-"RPi port    [vyp]"
+#MSG_RPI_PORT
+"RPi port"
+"\x00"
 
 #MSG_WIZARD_RERUN c=20 r=7
 "Running Wizard will delete current calibration results and start from the beginning. Continue?"
 "Spusteni Pruvodce vymaze ulozene vysledky vsech kalibraci a spusti kalibracni proces od zacatku. Pokracovat?"
 
-#MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF c=19 r=1
-"SD card  [normal]"
+#MSG_SD_CARD
+"SD card"
 "\x00"
 
-#MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON c=19 r=1
-"SD card [flshAir]"
-"SD card [FlshAir]"
+#MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY
+"FlashAir"
+"\x00"
 
 #
 "Right"
@@ -918,10 +902,6 @@
 "Select nozzle preheat temperature which matches your material."
 "Vyberte teplotu predehrati trysky ktera odpovida vasemu materialu."
 
-#
-"Select PLA filament:"
-"Vyberte PLA filament:"
-
 #MSG_SET_TEMPERATURE c=19 r=1
 "Set temperature:"
 "Nastavte teplotu:"
@@ -942,49 +922,49 @@
 "Some files will not be sorted. Max. No. of files in 1 folder for sorting is 100."
 "Nektere soubory nebudou setrideny. Maximalni pocet souboru ve slozce pro setrideni je 100."
 
-#MSG_SORT_NONE c=17 r=1
-"Sort       [none]"
-"Trideni   [Zadne]"
+#MSG_SORT
+"Sort"
+"Trideni"
 
-#MSG_SORT_TIME c=17 r=1
-"Sort       [time]"
-"Trideni     [cas]"
+#MSG_NONE
+"None"
+"Zadne"
+
+#MSG_SORT_TIME
+"Time"
+"Cas"
 
 #
 "Severe skew:"
 "Tezke zkoseni:"
 
-#MSG_SORT_ALPHA c=17 r=1
-"Sort   [alphabet]"
-"Trideni [Abeceda]"
+#MSG_SORT_ALPHA
+"Alphabet"
+"Abeceda"
 
 #MSG_SORTING c=20 r=1
 "Sorting files"
 "Trideni souboru"
 
-#MSG_SOUND_LOUD c=17 r=1
-"Sound      [loud]"
-"Zvuk    [hlasity]"
+#MSG_SOUND_LOUD
+"Loud"
+"Hlasity"
 
 #
 "Slight skew:"
 "Lehke zkoseni:"
 
-#MSG_SOUND_MUTE c=17 r=1
-"Sound      [mute]"
-"Zvuk    [vypnuto]"
+#MSG_SOUND
+"Sound"
+"Zvuk"
 
 #
 "Some problem encountered, Z-leveling enforced ..."
 "Vyskytl se problem, srovnavam osu Z ..."
 
-#MSG_SOUND_ONCE c=17 r=1
-"Sound      [once]"
-"Zvuk     [jednou]"
-
-#MSG_SOUND_SILENT c=17 r=1
-"Sound    [silent]"
-"Zvuk      [tichy]"
+#MSG_SOUND_ONCE
+"Once"
+"Jednou"
 
 #MSG_SPEED
 "Speed"
@@ -1018,17 +998,17 @@
 "Swapped"
 "Prohozene"
 
-#MSG_TEMP_CALIBRATION c=20 r=1
-"Temp. cal.          "
-"Tepl. kal. "
+#
+"Select filament:"
+"Zvolte filament:"
 
-#MSG_TEMP_CALIBRATION_ON c=20 r=1
-"Temp. cal.   [on]"
-"Tepl. kal.  [zap]"
+#MSG_TEMP_CALIBRATION c=12 r=1
+"Temp. cal."
+"Tepl. kal."
 
-#MSG_TEMP_CALIBRATION_OFF c=20 r=1
-"Temp. cal.  [off]"
-"Tepl. kal.  [vyp]"
+#
+"Select temperature which matches your material."
+"Zvolte teplotu, ktera odpovida vasemu materialu."
 
 #MSG_CALIBRATION_PINDA_MENU c=17 r=1
 "Temp. calibration"
@@ -1206,13 +1186,21 @@
 "Y distance from min"
 "Y vzdalenost od min"
 
+#
+"The printer will start printing a zig-zag line. Rotate the knob until you reach the optimal height. Check the pictures in the handbook (Calibration chapter)."
+"Tiskarna zacne tisknout lomenou caru. Otacenim tlacitka nastavte optimalni vysku. Postupujte podle obrazku v handbooku (kapitola Kalibrace)."
+
 #
 "Y-correct:"
 "Korekce Y:"
 
 #MSG_OFF
-" [off]"
-" [vyp]"
+"Off"
+"Vyp"
+
+#MSG_ON
+"On"
+"Zap"
 
 #
 "Back"
@@ -1230,17 +1218,17 @@
 "FINDA:"
 "\x00"
 
-#
-"Firmware   [none]"
-"Firmware  [Zadne]"
+#MSG_FIRMWARE
+"Firmware"
+"\x00"
 
-#
-"Firmware [strict]"
-"Firmware [Prisne]"
+#MSG_STRICT
+"Strict"
+"Prisne"
 
-#
-"Firmware   [warn]"
-"Firmware[Varovat]"
+#MSG_WARN
+"Warn"
+"Varovat"
 
 #
 "HW Setup"
@@ -1250,25 +1238,13 @@
 "IR:"
 "\x00"
 
-#
-"Magnets comp.[N/A]"
-"Komp. magnetu[N/A]"
-
-#
-"Magnets comp.[Off]"
-"Komp. magnetu[Vyp]"
-
-#
-"Magnets comp. [On]"
-"Komp. magnetu[Zap]"
+#MSG_MAGNETS_COMP
+"Magnets comp."
+"Komp. magnetu"
 
-#
-"Mesh         [3x3]"
-"Mesh         [3x3]"
-
-#
-"Mesh         [7x7]"
-"Mesh         [7x7]"
+#MSG_MESH
+"Mesh"
+"\x00"
 
 #
 "Mesh bed leveling"
@@ -1278,53 +1254,21 @@
 "MK3S firmware detected on MK3 printer"
 "MK3S firmware detekovan na tiskarne MK3"
 
-#
-"MMU Mode [Normal]"
-"MMU mod  [Normal]"
-
-#
-"MMU Mode[Stealth]"
-"MMU Mod   [Tichy]"
+#MSG_MMU_MODE
+"MMU Mode"
+"MMU mod"
 
 #
 "Mode change in progress ..."
 "Probiha zmena modu..."
 
-#
-"Model      [none]"
-"Model     [Zadne]"
-
-#
-"Model    [strict]"
-"Model    [Prisne]"
-
-#
-"Model      [warn]"
-"Model   [Varovat]"
-
-#
-"Nozzle d.  [0.25]"
-"Tryska     [0.25]"
-
-#
-"Nozzle d.  [0.40]"
-"Tryska     [0.40]"
-
-#
-"Nozzle d.  [0.60]"
-"Tryska     [0.60]"
-
-#
-"Nozzle     [none]"
-"Tryska    [Zadne]"
-
-#
-"Nozzle   [strict]"
-"Tryska   [Prisne]"
+#MSG_MODEL
+"Model"
+"\x00"
 
-#
-"Nozzle     [warn]"
-"Tryska  [Varovat]"
+#MSG_NOZZLE_DIAMETER
+"Nozzle d."
+"Tryska"
 
 #
 "G-code sliced for a different level. Continue?"
@@ -1386,9 +1330,9 @@
 "Sheet"
 "Plat"
 
-#
-"Sound    [assist]"
-"Zvuk     [Asist.]"
+#MSG_SOUND_BLIND
+"Assist"
+"Asist."
 
 #
 "Steel sheets"
@@ -1398,14 +1342,6 @@
 "Z-correct:"
 "Korekce Z:"
 
-#
-"Z-probe nr.    [1]"
-"Pocet mereni Z [1]"
-
-#
-"Z-probe nr.    [3]"
-"Pocet mereni Z [3]"
-
-#
-"Z-probe nr.    [5]"
-"Pocet mereni Z [5]"
+#MSG_Z_PROBE_NR
+"Z-probe nr."
+"Pocet mereni Z"

+ 136 - 201
lang/lang_en_de.txt

@@ -50,17 +50,9 @@
 "Are left and right Z~carriages all up?"
 "Sind linke+rechte Z- Schlitten ganz oben?"
 
-#MSG_AUTO_DEPLETE_ON c=17 r=1
-"SpoolJoin    [on]"
-"SpoolJoin    [an]"
-
-#
-"SpoolJoin   [N/A]"
-"SpoolJoin   [N/V]"
-
-#MSG_AUTO_DEPLETE_OFF c=17 r=1
-"SpoolJoin   [off]"
-"SpoolJoin   [aus]"
+#MSG_AUTO_DEPLETE c=17 r=1
+"SpoolJoin"
+"\x00"
 
 #MSG_AUTO_HOME
 "Auto home"
@@ -72,7 +64,7 @@
 
 #MSG_AUTOLOADING_ONLY_IF_FSENS_ON c=20 r=4
 "Autoloading filament available only when filament sensor is turned on..."
-"Automatisches Laden Filament nur bei einge schaltetem Filament- sensor verfuegbar..."
+"Automatisches Laden Filament nur bei eingeschaltetem Fil. sensor verfuegbar..."
 
 #MSG_AUTOLOADING_ENABLED c=20 r=4
 "Autoloading filament is active, just press the knob and insert filament..."
@@ -174,17 +166,13 @@
 "Copy selected language?"
 "Gewaehlte Sprache kopieren?"
 
-#MSG_CRASHDETECT_ON
-"Crash det.   [on]"
-"Crash Erk.   [an]"
-
-#MSG_CRASHDETECT_NA
-"Crash det.  [N/A]"
-"Crash Erk.   [nv]"
+#MSG_CRASHDETECT
+"Crash det."
+"Crash Erk."
 
-#MSG_CRASHDETECT_OFF
-"Crash det.  [off]"
-"Crash Erk.  [aus]"
+#
+"Choose a filament for the First Layer Calibration and select it in the on-screen menu."
+"Waehlen Sie ein Filament fuer Erste Schichtkalibrierung aus und waehlen Sie es im On-Screen-Menu aus."
 
 #MSG_CRASH_DETECTED c=20 r=1
 "Crash detected."
@@ -270,17 +258,9 @@
 "Fail stats MMU"
 "MMU-Fehler"
 
-#MSG_FSENS_AUTOLOAD_ON c=17 r=1
-"F. autoload  [on]"
-"F.Autoladen  [an]"
-
-#MSG_FSENS_AUTOLOAD_NA c=17 r=1
-"F. autoload [N/A]"
-"F. Autoload  [nv]"
-
-#MSG_FSENS_AUTOLOAD_OFF c=17 r=1
-"F. autoload [off]"
-"F. Autoload [aus]"
+#MSG_FSENSOR_AUTOLOAD
+"F. autoload"
+"F. autoladen"
 
 #
 "Fail stats"
@@ -294,25 +274,13 @@
 "Fan test"
 "Lueftertest"
 
-#MSG_FANS_CHECK_ON c=17 r=1
-"Fans check   [on]"
-"Luefter Chk. [an]"
-
-#MSG_FANS_CHECK_OFF c=17 r=1
-"Fans check  [off]"
-"Luefter Chk.[aus]"
-
-#MSG_FSENSOR_ON
-"Fil. sensor  [on]"
-"Fil. Sensor  [an]"
+#MSG_FANS_CHECK
+"Fans check"
+"Luefter Chk."
 
-#MSG_FSENSOR_NA
-"Fil. sensor [N/A]"
-"Fil. Sensor  [nv]"
-
-#MSG_FSENSOR_OFF
-"Fil. sensor [off]"
-"Fil. Sensor [aus]"
+#MSG_FSENSOR
+"Fil. sensor"
+"\x00"
 
 #
 "Filam. runouts"
@@ -482,6 +450,10 @@
 "Last print failures"
 "Letzte Druckfehler"
 
+#
+"If you have additional steel sheets, calibrate their presets in Settings - HW Setup - Steel sheets."
+"Wenn Sie zusaetzliche Stahlbleche haben, kalibrieren Sie deren Voreinstellungen unter Einstellungen - HW Setup - Stahlbleche."
+
 #
 "Last print"
 "Letzter Druck"
@@ -570,13 +542,17 @@
 "MMU OK. Resuming..."
 "MMU OK.  Weiterdrucken..."
 
-#MSG_STEALTH_MODE_OFF
-"Mode     [Normal]"
-"Modus    [Normal]"
+#MSG_MODE
+"Mode"
+"Modus"
+
+#MSG_NORMAL
+"Normal"
+"\x00"
 
-#MSG_SILENT_MODE_ON
-"Mode     [silent]"
-"Modus     [leise]"
+#MSG_SILENT
+"Silent"
+"Leise"
 
 #
 "MMU needs user attention."
@@ -586,17 +562,17 @@
 "MMU power fails"
 "MMU Netzfehler"
 
-#MSG_STEALTH_MODE_ON
-"Mode    [Stealth]"
-"Modus   [Stealth]"
+#MSG_STEALTH
+"Stealth"
+"\x00"
 
-#MSG_AUTO_MODE_ON
-"Mode [auto power]"
-"Modus[Auto Power]"
+#MSG_AUTO_POWER
+"Auto power"
+"\x00"
 
-#MSG_SILENT_MODE_OFF
-"Mode [high power]"
-"Modus[Hohe Leist]"
+#MSG_HIGH_POWER
+"High power"
+"Hohe leist"
 
 #
 "MMU2 connected"
@@ -630,9 +606,9 @@
 "No SD card"
 "Keine SD Karte"
 
-#
+#MSG_NA
 "N/A"
-"N.V."
+"N/V"
 
 #MSG_NO
 "No"
@@ -818,6 +794,18 @@
 "Print FAN"
 "Druckvent."
 
+#
+"Please insert filament into the extruder, then press the knob to load it."
+"Bitte legen Sie das Filament in den Extruder ein und druecken Sie dann den Knopf, um es zu laden."
+
+#
+"Please insert filament into the first tube of the MMU, then press the knob to load it."
+"Bitte stecken Sie das Filament in den ersten Schlauch der MMU und druecken Sie dann den Knopf, um es zu laden."
+
+#
+"Please load filament first."
+"Bitte laden Sie zuerst das Filament."
+
 #MSG_PRUSA3D
 "prusa3d.com"
 "\x00"
@@ -858,25 +846,21 @@
 "Right side[um]"
 "Rechts [um]"
 
-#MSG_SECOND_SERIAL_ON c=17 r=1
-"RPi port     [on]"
-"RPi Port     [an]"
-
-#MSG_SECOND_SERIAL_OFF c=17 r=1
-"RPi port    [off]"
-"RPi Port    [aus]"
+#MSG_RPI_PORT
+"RPi port"
+"\x00"
 
 #MSG_WIZARD_RERUN c=20 r=7
 "Running Wizard will delete current calibration results and start from the beginning. Continue?"
 "Der Assistent wird die aktuellen Kalibrierungsdaten loeschen und von vorne beginnen. Weiterfahren?"
 
-#MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF c=19 r=1
-"SD card  [normal]"
-"SD Karte [normal]"
+#MSG_SD_CARD
+"SD card"
+"SD Karte"
 
-#MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON c=19 r=1
-"SD card [flshAir]"
-"SD Karte[flshAir]"
+#MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY
+"FlashAir"
+"\x00"
 
 #
 "Right"
@@ -918,10 +902,6 @@
 "Select nozzle preheat temperature which matches your material."
 "Bitte Vorheiztemperatur auswaehlen, die Ihrem Material entspricht."
 
-#
-"Select PLA filament:"
-"PLA Filament auswaehlen:"
-
 #MSG_SET_TEMPERATURE c=19 r=1
 "Set temperature:"
 "Temp. einstellen:"
@@ -942,49 +922,49 @@
 "Some files will not be sorted. Max. No. of files in 1 folder for sorting is 100."
 "Einige Dateien wur- den nicht sortiert. Max. Dateien pro Verzeichnis = 100."
 
-#MSG_SORT_NONE c=17 r=1
-"Sort       [none]"
-"Sort.      [ohne]"
+#MSG_SORT
+"Sort"
+"Sort."
 
-#MSG_SORT_TIME c=17 r=1
-"Sort       [time]"
-"Sort.      [Zeit]"
+#MSG_NONE
+"None"
+"Ohne"
+
+#MSG_SORT_TIME
+"Time"
+"Zeit"
 
 #
 "Severe skew:"
 "Schwer.Schr:"
 
-#MSG_SORT_ALPHA c=17 r=1
-"Sort   [alphabet]"
-"Sort.  [Alphabet]"
+#MSG_SORT_ALPHA
+"Alphabet"
+"\x00"
 
 #MSG_SORTING c=20 r=1
 "Sorting files"
 "Sortiere Dateien"
 
-#MSG_SOUND_LOUD c=17 r=1
-"Sound      [loud]"
-"Sound      [laut]"
+#MSG_SOUND_LOUD
+"Loud"
+"Laut"
 
 #
 "Slight skew:"
 "Leicht.Schr:"
 
-#MSG_SOUND_MUTE c=17 r=1
-"Sound      [mute]"
-"Sound     [stumm]"
+#MSG_SOUND
+"Sound"
+"\x00"
 
 #
 "Some problem encountered, Z-leveling enforced ..."
 "Fehler aufgetreten, Z-Kalibrierung erforderlich..."
 
-#MSG_SOUND_ONCE c=17 r=1
-"Sound      [once]"
-"Sound    [einmal]"
-
-#MSG_SOUND_SILENT c=17 r=1
-"Sound    [silent]"
-"Sound     [leise]"
+#MSG_SOUND_ONCE
+"Once"
+"Einmal"
 
 #MSG_SPEED
 "Speed"
@@ -1018,17 +998,17 @@
 "Swapped"
 "Ausgetauscht"
 
-#MSG_TEMP_CALIBRATION c=20 r=1
-"Temp. cal.          "
-"Temp Kalib.         "
+#
+"Select filament:"
+"Filament auswaehlen:"
 
-#MSG_TEMP_CALIBRATION_ON c=20 r=1
-"Temp. cal.   [on]"
-"Temp. Kal.   [an]"
+#MSG_TEMP_CALIBRATION c=12 r=1
+"Temp. cal."
+"Temp Kalib."
 
-#MSG_TEMP_CALIBRATION_OFF c=20 r=1
-"Temp. cal.  [off]"
-"Temp. Kal.  [aus]"
+#
+"Select temperature which matches your material."
+"Waehlen Sie die Temperatur, die zu Ihrem Material passt."
 
 #MSG_CALIBRATION_PINDA_MENU c=17 r=1
 "Temp. calibration"
@@ -1202,18 +1182,25 @@
 "XYZ calibration failed. Right front calibration point not reachable."
 "XYZ-Kalibrierung fehlgeschlagen. Rechter vorderer Kalibrierpunkt ist nicht erreichbar."
 
-
 #
 "Y distance from min"
 "Y Entfernung vom Min"
 
+#
+"The printer will start printing a zig-zag line. Rotate the knob until you reach the optimal height. Check the pictures in the handbook (Calibration chapter)."
+"Der Drucker beginnt mit dem Drucken einer Zickzacklinie. Drehen Sie den Knopf, bis Sie die optimale Hoehe erreicht haben. Ueberpruefen Sie die Bilder im Handbuch (Kapitel Kalibrierung)."
+
 #
 "Y-correct:"
 "Y-Korrektur:"
 
 #MSG_OFF
-" [off]"
-" [aus]"
+"Off"
+"Aus"
+
+#MSG_ON
+"On"
+"An"
 
 #
 "Back"
@@ -1231,17 +1218,17 @@
 "FINDA:"
 "\x00"
 
-#
-"Firmware   [none]"
-"Firmware   [ohne]"
+#MSG_FIRMWARE
+"Firmware"
+"\x00"
 
-#
-"Firmware [strict]"
-"Firmware [strikt]"
+#MSG_STRICT
+"Strict"
+"Strikt"
 
-#
-"Firmware   [warn]"
-"Firmware [warnen]"
+#MSG_WARN
+"Warn"
+"Warnen"
 
 #
 "HW Setup"
@@ -1251,25 +1238,13 @@
 "IR:"
 "\x00"
 
-#
-"Magnets comp.[N/A]"
-"Magnet Komp.  [nv]"
-
-#
-"Magnets comp.[Off]"
-"Magnet Komp. [Aus]"
-
-#
-"Magnets comp. [On]"
-"Magnet Komp.  [An]"
-
-#
-"Mesh         [3x3]"
-"Gitter       [3x3]"
+#MSG_MAGNETS_COMP
+"Magnets comp."
+"Magnet Komp."
 
-#
-"Mesh         [7x7]"
-"Gitter       [7x7]"
+#MSG_MESH
+"Mesh"
+"Gitter"
 
 #
 "Mesh bed leveling"
@@ -1279,53 +1254,21 @@
 "MK3S firmware detected on MK3 printer"
 "MK3S-Firmware auf MK3-Drucker erkannt"
 
-#
-"MMU Mode [Normal]"
-"MMU Modus[Normal]"
-
-#
-"MMU Mode[Stealth]"
-"MMU Mod.[Stealth]"
+#MSG_MMU_MODE
+"MMU Mode"
+"MMU Modus"
 
 #
 "Mode change in progress ..."
 "Moduswechsel erfolgt..."
 
-#
-"Model      [none]"
-"Modell     [ohne]"
+#MSG_MODEL
+"Model"
+"Modell"
 
-#
-"Model    [strict]"
-"Modell   [strikt]"
-
-#
-"Model      [warn]"
-"Modell   [warnen]"
-
-#
-"Nozzle d.  [0.25]"
-"Duese D.   [0.25]"
-
-#
-"Nozzle d.  [0.40]"
-"Duese D.   [0.40]"
-
-#
-"Nozzle d.  [0.60]"
-"Duese D.   [0.60]"
-
-#
-"Nozzle     [none]"
-"Duese      [ohne]"
-
-#
-"Nozzle   [strict]"
-"Duese    [strikt]"
-
-#
-"Nozzle     [warn]"
-"Duese    [warnen]"
+#MSG_NOZZLE_DIAMETER
+"Nozzle d."
+"Duese D."
 
 #
 "G-code sliced for a different level. Continue?"
@@ -1387,9 +1330,9 @@
 "Sheet"
 "Blech"
 
-#
-"Sound    [assist]"
-"Sound    [Assist]"
+#MSG_SOUND_BLIND
+"Assist"
+"\x00"
 
 #
 "Steel sheets"
@@ -1399,14 +1342,6 @@
 "Z-correct:"
 "Z-Korrektur:"
 
-#
-"Z-probe nr.    [1]"
-"Z-Probe Nr.    [1]"
-
-#
-"Z-probe nr.    [3]"
-"Z-Probe Nr.    [3]"
-
-#
-"Z-probe nr.    [5]"
-"Z-Probe Nr.    [5]"
+#MSG_Z_PROBE_NR
+"Z-probe nr."
+"\x00"

+ 135 - 199
lang/lang_en_es.txt

@@ -50,16 +50,8 @@
 "Are left and right Z~carriages all up?"
 "Carros Z izq./der. estan arriba maximo?"
 
-#MSG_AUTO_DEPLETE_ON c=17 r=1
-"SpoolJoin    [on]"
-"\x00"
-
-#
-"SpoolJoin   [N/A]"
-"\x00"
-
-#MSG_AUTO_DEPLETE_OFF c=17 r=1
-"SpoolJoin   [off]"
+#MSG_AUTO_DEPLETE c=17 r=1
+"SpoolJoin"
 "\x00"
 
 #MSG_AUTO_HOME
@@ -72,11 +64,11 @@
 
 #MSG_AUTOLOADING_ONLY_IF_FSENS_ON c=20 r=4
 "Autoloading filament available only when filament sensor is turned on..."
-"La carga automatica de filamento solo funciona si el sensor de filamento esta activado..."
+"La carga automatica solo funciona si el sensor de filamento esta activado..."
 
 #MSG_AUTOLOADING_ENABLED c=20 r=4
 "Autoloading filament is active, just press the knob and insert filament..."
-"La carga automatica de filamento esta activada, pulse el dial e inserte el filamento..."
+"La carga automatica esta activada, pulse el dial e inserte el filamento..."
 
 #MSG_SELFTEST_AXIS_LENGTH
 "Axis length"
@@ -174,17 +166,13 @@
 "Copy selected language?"
 "Copiar idioma seleccionado?"
 
-#MSG_CRASHDETECT_ON
-"Crash det.   [on]"
-"Det. choque [act]"
+#MSG_CRASHDETECT
+"Crash det."
+"Det. choque"
 
-#MSG_CRASHDETECT_NA
-"Crash det.  [N/A]"
-"Dec. choque [N/D]"
-
-#MSG_CRASHDETECT_OFF
-"Crash det.  [off]"
-"Det. choque [ina]"
+#
+"Choose a filament for the First Layer Calibration and select it in the on-screen menu."
+"Escoge un filamento para la Calibracion de la Primera Capa y seleccionalo en el menu en pantalla."
 
 #MSG_CRASH_DETECTED c=20 r=1
 "Crash detected."
@@ -270,17 +258,9 @@
 "Fail stats MMU"
 "Estadistica de fallos MMU"
 
-#MSG_FSENS_AUTOLOAD_ON c=17 r=1
-"F. autoload  [on]"
-"Autocarg.Fil[act]"
-
-#MSG_FSENS_AUTOLOAD_NA c=17 r=1
-"F. autoload [N/A]"
-"Autocarg.Fil[N/D]"
-
-#MSG_FSENS_AUTOLOAD_OFF c=17 r=1
-"F. autoload [off]"
-"Autocarg.Fil[ina]"
+#MSG_FSENSOR_AUTOLOAD
+"F. autoload"
+"Autocarg.fil."
 
 #
 "Fail stats"
@@ -294,25 +274,13 @@
 "Fan test"
 "Test ventiladores"
 
-#MSG_FANS_CHECK_ON c=17 r=1
-"Fans check   [on]"
-"Comprob.vent[act]"
+#MSG_FANS_CHECK
+"Fans check"
+"Comprob.vent"
 
-#MSG_FANS_CHECK_OFF c=17 r=1
-"Fans check  [off]"
-"Comprob.vent[ina]"
-
-#MSG_FSENSOR_ON
-"Fil. sensor  [on]"
-"Sensor Fil. [act]"
-
-#MSG_FSENSOR_NA
-"Fil. sensor [N/A]"
-"Sensor Fil. [N/D]"
-
-#MSG_FSENSOR_OFF
-"Fil. sensor [off]"
-"Sensor Fil. [ina]"
+#MSG_FSENSOR
+"Fil. sensor"
+"Sensor Fil."
 
 #
 "Filam. runouts"
@@ -482,6 +450,10 @@
 "Last print failures"
 "Ultimas impresiones fallidas"
 
+#
+"If you have additional steel sheets, calibrate their presets in Settings - HW Setup - Steel sheets."
+"Si tienes planchas de acero adicionales, calibra sus ajustes en Ajustes - Ajustes HW - Planchas acero."
+
 #
 "Last print"
 "Ultima impresion"
@@ -570,13 +542,17 @@
 "MMU OK. Resuming..."
 "MMU OK. Resumiendo..."
 
-#MSG_STEALTH_MODE_OFF
-"Mode     [Normal]"
-"Modo     [Normal]"
+#MSG_MODE
+"Mode"
+"Modo"
 
-#MSG_SILENT_MODE_ON
-"Mode     [silent]"
-"Modo   [silencio]"
+#MSG_NORMAL
+"Normal"
+"\x00"
+
+#MSG_SILENT
+"Silent"
+"Silencio"
 
 #
 "MMU needs user attention."
@@ -586,17 +562,17 @@
 "MMU power fails"
 "Fallo de energia en MMU"
 
-#MSG_STEALTH_MODE_ON
-"Mode    [Stealth]"
-"Modo   [Silencio]"
+#MSG_STEALTH
+"Stealth"
+"Silencio"
 
-#MSG_AUTO_MODE_ON
-"Mode [auto power]"
-"Modo[fuerza auto]"
+#MSG_AUTO_POWER
+"Auto power"
+"Fuerza auto"
 
-#MSG_SILENT_MODE_OFF
-"Mode [high power]"
-"Modo [rend.pleno]"
+#MSG_HIGH_POWER
+"High power"
+"Rend.pleno"
 
 #
 "MMU2 connected"
@@ -630,7 +606,7 @@
 "No SD card"
 "No hay tarjeta SD"
 
-#
+#MSG_NA
 "N/A"
 "N/A"
 
@@ -818,6 +794,18 @@
 "Print FAN"
 "Vent. extr"
 
+#
+"Please insert filament into the extruder, then press the knob to load it."
+"Por favor, coloca el filamento en el extrusor, luego presiona el dial para cargarlo."
+
+#
+"Please insert filament into the first tube of the MMU, then press the knob to load it."
+"Por favor, coloca el filamento en el primer tubo de la MMU, luego pulsa el dial para cargarlo."
+
+#
+"Please load filament first."
+"Por favor, cargar primero el filamento. "
+
 #MSG_PRUSA3D
 "prusa3d.com"
 "prusa3d.es"
@@ -858,25 +846,21 @@
 "Right side[um]"
 "Derecha [um]"
 
-#MSG_SECOND_SERIAL_ON c=17 r=1
-"RPi port     [on]"
-"Puerto RPi  [act]"
-
-#MSG_SECOND_SERIAL_OFF c=17 r=1
-"RPi port    [off]"
-"Puerto RPi  [ina]"
+#MSG_RPI_PORT
+"RPi port"
+"Puerto RPi"
 
 #MSG_WIZARD_RERUN c=20 r=7
 "Running Wizard will delete current calibration results and start from the beginning. Continue?"
 "Ejecutar el Wizard borrara los valores de calibracion actuales y comenzara de nuevo. Continuar?"
 
-#MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF c=19 r=1
-"SD card  [normal]"
-"Tarj. SD [normal]"
+#MSG_SD_CARD
+"SD card"
+"Tarj. SD"
 
-#MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON c=19 r=1
-"SD card [flshAir]"
-"Tarj. SD[FlshAir]"
+#MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY
+"FlashAir"
+"\x00"
 
 #
 "Right"
@@ -918,10 +902,6 @@
 "Select nozzle preheat temperature which matches your material."
 "Selecciona la temperatura para precalentar la boquilla que se ajuste a tu material. "
 
-#
-"Select PLA filament:"
-"Seleccionar filamento PLA:"
-
 #MSG_SET_TEMPERATURE c=19 r=1
 "Set temperature:"
 "Establecer temp.:"
@@ -942,49 +922,49 @@
 "Some files will not be sorted. Max. No. of files in 1 folder for sorting is 100."
 "Algunos archivos no se ordenaran. Maximo 100 archivos por carpeta para ordenar. "
 
-#MSG_SORT_NONE c=17 r=1
-"Sort       [none]"
-"Ordenar [ninguno]"
+#MSG_SORT
+"Sort"
+"Ordenar"
 
-#MSG_SORT_TIME c=17 r=1
-"Sort       [time]"
-"Ordenar   [fecha]"
+#MSG_NONE
+"None"
+"Ninguno"
+
+#MSG_SORT_TIME
+"Time"
+"Fecha"
 
 #
 "Severe skew:"
 "Incl.severa:"
 
-#MSG_SORT_ALPHA c=17 r=1
-"Sort   [alphabet]"
-"Ordenar [alfabet]"
+#MSG_SORT_ALPHA
+"Alphabet"
+"Alfabet"
 
 #MSG_SORTING c=20 r=1
 "Sorting files"
 "Ordenando archivos"
 
-#MSG_SOUND_LOUD c=17 r=1
-"Sound      [loud]"
-"Sonido     [alto]"
+#MSG_SOUND_LOUD
+"Loud"
+"Alto"
 
 #
 "Slight skew:"
 "Liger.incl.:"
 
-#MSG_SOUND_MUTE c=17 r=1
-"Sound      [mute]"
-"Sonido[silenciad]"
+#MSG_SOUND
+"Sound"
+"Sonido"
 
 #
 "Some problem encountered, Z-leveling enforced ..."
 "Problema encontrado, nivelacion Z forzosa ..."
 
-#MSG_SOUND_ONCE c=17 r=1
-"Sound      [once]"
-"Sonido  [una vez]"
-
-#MSG_SOUND_SILENT c=17 r=1
-"Sound    [silent]"
-"Sonido[silencios]"
+#MSG_SOUND_ONCE
+"Once"
+"Una vez"
 
 #MSG_SPEED
 "Speed"
@@ -1018,17 +998,17 @@
 "Swapped"
 "Intercambiado"
 
-#MSG_TEMP_CALIBRATION c=20 r=1
-"Temp. cal.          "
-"Cal. temp. "
+#
+"Select filament:"
+"Selecciona filamento:"
 
-#MSG_TEMP_CALIBRATION_ON c=20 r=1
-"Temp. cal.   [on]"
-"Cal. temp.   [on]"
+#MSG_TEMP_CALIBRATION c=12 r=1
+"Temp. cal."
+"Cal. temp."
 
-#MSG_TEMP_CALIBRATION_OFF c=20 r=1
-"Temp. cal.  [off]"
-"Cal. temp.  [off]"
+#
+"Select temperature which matches your material."
+"Selecciona la temperatura adecuada a tu material."
 
 #MSG_CALIBRATION_PINDA_MENU c=17 r=1
 "Temp. calibration"
@@ -1206,13 +1186,21 @@
 "Y distance from min"
 "Distancia en Y desde el min"
 
+#
+"The printer will start printing a zig-zag line. Rotate the knob until you reach the optimal height. Check the pictures in the handbook (Calibration chapter)."
+"La impresora comenzara a imprimir una linea en zig-zag. Gira el dial hasta que la linea alcance la altura optima. Mira las fotos del manual (Capitulo de calibracion)."
+
 #
 "Y-correct:"
 "Corregir-Y:"
 
 #MSG_OFF
-" [off]"
-"[apag]"
+"Off"
+"Ina"
+
+#MSG_ON
+"On"
+"Act"
 
 #
 "Back"
@@ -1230,17 +1218,17 @@
 "FINDA:"
 "FINDA:"
 
-#
-"Firmware   [none]"
-"Firmware[ninguno]"
+#MSG_FIRMWARE
+"Firmware"
+"\x00"
 
-#
-"Firmware [strict]"
-"Firmware[estrict]"
+#MSG_STRICT
+"Strict"
+"Estrict"
 
-#
-"Firmware   [warn]"
-"Firmware  [aviso]"
+#MSG_WARN
+"Warn"
+"Aviso"
 
 #
 "HW Setup"
@@ -1250,25 +1238,13 @@
 "IR:"
 "\x00"
 
-#
-"Magnets comp.[N/A]"
-"Comp. imanes [N/A]"
-
-#
-"Magnets comp.[Off]"
-"Comp. imanes [Off]"
-
-#
-"Magnets comp. [On]"
-"Comp. imanes  [On]"
-
-#
-"Mesh         [3x3]"
-"Malla        [3x3]"
+#MSG_MAGNETS_COMP
+"Magnets comp."
+"Comp. imanes"
 
-#
-"Mesh         [7x7]"
-"Malla        [7x7]"
+#MSG_MESH
+"Mesh"
+"Malla"
 
 #
 "Mesh bed leveling"
@@ -1278,53 +1254,21 @@
 "MK3S firmware detected on MK3 printer"
 "Firmware MK3S detectado en impresora MK3"
 
-#
-"MMU Mode [Normal]"
-"Modo MMU [Normal]"
-
-#
-"MMU Mode[Stealth]"
-"Modo MMU[Silenci]"
+#MSG_MMU_MODE
+"MMU Mode"
+"Modo MMU"
 
 #
 "Mode change in progress ..."
 "Cambio de modo progresando ..."
 
-#
-"Model      [none]"
-"Modelo  [ninguno]"
+#MSG_MODEL
+"Model"
+"Modelo"
 
-#
-"Model    [strict]"
-"Modelo [estricto]"
-
-#
-"Model      [warn]"
-"Modelo    [aviso]"
-
-#
-"Nozzle d.  [0.25]"
-"Diam. nozzl[0.25]"
-
-#
-"Nozzle d.  [0.40]"
-"Diam. nozzl[0.40]"
-
-#
-"Nozzle d.  [0.60]"
-"Diam. nozzl[0.60]"
-
-#
-"Nozzle     [none]"
-"Nozzle  [ninguno]"
-
-#
-"Nozzle   [strict]"
-"Nozzle [estricto]"
-
-#
-"Nozzle     [warn]"
-"Nozzle    [aviso]"
+#MSG_NOZZLE_DIAMETER
+"Nozzle d."
+"Diam. nozzl"
 
 #
 "G-code sliced for a different level. Continue?"
@@ -1386,9 +1330,9 @@
 "Sheet"
 "Lamina"
 
-#
-"Sound    [assist]"
-"Sonido [asistido]"
+#MSG_SOUND_BLIND
+"Assist"
+"Asistido"
 
 #
 "Steel sheets"
@@ -1398,14 +1342,6 @@
 "Z-correct:"
 "Corregir-Z:"
 
-#
-"Z-probe nr.    [1]"
-"Z-sensor nr.   [1]"
-
-#
-"Z-probe nr.    [3]"
-"Z-sensor nr.   [3]"
-
-#
-"Z-probe nr.    [5]"
-"Z-sensor nr.   [5]"
+#MSG_Z_PROBE_NR
+"Z-probe nr."
+"Z-sensor nr."

+ 131 - 199
lang/lang_en_fr.txt

@@ -50,16 +50,8 @@
 "Are left and right Z~carriages all up?"
 "Z~carriages gauche + droite tout en haut?"
 
-#MSG_AUTO_DEPLETE_ON c=17 r=1
-"SpoolJoin    [on]"
-"\x00"
-
-#
-"SpoolJoin   [N/A]"
-"\x00"
-
-#MSG_AUTO_DEPLETE_OFF c=17 r=1
-"SpoolJoin   [off]"
+#MSG_AUTO_DEPLETE c=17 r=1
+"SpoolJoin"
 "\x00"
 
 #MSG_AUTO_HOME
@@ -174,17 +166,13 @@
 "Copy selected language?"
 "Copier la langue selectionne?"
 
-#MSG_CRASHDETECT_ON
-"Crash det.   [on]"
-"Detect.crash [on]"
+#MSG_CRASHDETECT
+"Crash det."
+"Detect.crash"
 
-#MSG_CRASHDETECT_NA
-"Crash det.  [N/A]"
-"Detect.crash[N/A]"
-
-#MSG_CRASHDETECT_OFF
-"Crash det.  [off]"
-"Detect.crash[off]"
+#
+"Choose a filament for the First Layer Calibration and select it in the on-screen menu."
+"Choisissez un filament pour la Calibration de la Premiere Couche et selectionnez-le depuis le menu a l'ecran."
 
 #MSG_CRASH_DETECTED c=20 r=1
 "Crash detected."
@@ -270,18 +258,9 @@
 "Fail stats MMU"
 "Stat. d'echec MMU"
 
-#MSG_FSENS_AUTOLOAD_ON c=17 r=1
-"F. autoload  [on]"
-"Autochargeur [on]"
-
-#MSG_FSENS_AUTOLOAD_NA c=17 r=1
-"F. autoload [N/A]"
-"Autochargeur[N/A]"
-
-#MSG_FSENS_AUTOLOAD_OFF c=17 r=1
-"F. autoload [off]"
-"Autochargeur[off]"
-
+#MSG_FSENSOR_AUTOLOAD
+"F. autoload"
+"Autochargeur"
 #
 "Fail stats"
 "Stat. d'echec"
@@ -294,26 +273,13 @@
 "Fan test"
 "Test du ventilateur"
 
-#MSG_FANS_CHECK_ON c=17 r=1
-"Fans check   [on]"
-"Verif vent.  [on]"
-
-#MSG_FANS_CHECK_OFF c=17 r=1
-"Fans check  [off]"
-"Verif vent. [off]"
-
-#MSG_FSENSOR_ON
-"Fil. sensor  [on]"
-"Capteur Fil. [on]"
-
-#MSG_FSENSOR_NA
-"Fil. sensor [N/A]"
-"Capteur Fil.[N/A]"
-
-#MSG_FSENSOR_OFF
-"Fil. sensor [off]"
-"Capteur Fil.[off]"
+#MSG_FANS_CHECK
+"Fans check"
+"Verif vent."
 
+#MSG_FSENSOR
+"Fil. sensor"
+"Capteur Fil."
 #
 "Filam. runouts"
 "Fins de filament"
@@ -482,6 +448,10 @@
 "Last print failures"
 "Echecs derniere imp."
 
+#
+"If you have additional steel sheets, calibrate their presets in Settings - HW Setup - Steel sheets."
+"Si vous avez d'autres feuilles d'acier,  calibrez leurs pre-reglages dans Reglages - Config HW - Feuilles d'acier."
+
 #
 "Last print"
 "Derniere impres."
@@ -570,13 +540,17 @@
 "MMU OK. Resuming..."
 "MMU OK. Reprise ..."
 
-#MSG_STEALTH_MODE_OFF
-"Mode     [Normal]"
+#MSG_MODE
+"Mode"
+"\x00"
+
+#MSG_NORMAL
+"Normal"
 "\x00"
 
-#MSG_SILENT_MODE_ON
-"Mode     [silent]"
-"Mode     [feutre]"
+#MSG_SILENT
+"Silent"
+"Feutre"
 
 #
 "MMU needs user attention."
@@ -586,17 +560,17 @@
 "MMU power fails"
 "Echecs alim. MMU"
 
-#MSG_STEALTH_MODE_ON
-"Mode    [Stealth]"
-"Mode     [furtif]"
+#MSG_STEALTH
+"Stealth"
+"Furtif"
 
-#MSG_AUTO_MODE_ON
-"Mode [auto power]"
-"Mode [puiss.auto]"
+#MSG_AUTO_POWER
+"Auto power"
+"Puiss.auto"
 
-#MSG_SILENT_MODE_OFF
-"Mode [high power]"
-"Mode[haute puiss]"
+#MSG_HIGH_POWER
+"High power"
+"Haute puiss"
 
 #
 "MMU2 connected"
@@ -630,7 +604,7 @@
 "No SD card"
 "Pas de carte SD"
 
-#
+#MSG_NA
 "N/A"
 "\x00"
 
@@ -818,6 +792,18 @@
 "Print FAN"
 "Vent. impr"
 
+#
+"Please insert filament into the extruder, then press the knob to load it."
+"Veuillez inserer le filament dans l'extrudeur, puis appuyez sur le bouton pour le charger."
+
+#
+"Please insert filament into the first tube of the MMU, then press the knob to load it."
+"Veuillez inserer le filament dans le premier tube du MMU, puis appuyez sur le bouton pour le charger."
+
+#
+"Please load filament first."
+"Veuillez d'abord charger un filament."
+
 #MSG_PRUSA3D
 "prusa3d.com"
 "\x00"
@@ -858,25 +844,21 @@
 "Right side[um]"
 "Droite [um]"
 
-#MSG_SECOND_SERIAL_ON c=17 r=1
-"RPi port     [on]"
-"Port RPi     [on]"
-
-#MSG_SECOND_SERIAL_OFF c=17 r=1
-"RPi port    [off]"
-"Port RPi    [off]"
+#MSG_RPI_PORT
+"RPi port"
+"Port RPi"
 
 #MSG_WIZARD_RERUN c=20 r=7
 "Running Wizard will delete current calibration results and start from the beginning. Continue?"
 "Lancement de l'Assistant supprimera les resultats actuels de calibration et commencera du debut. Continuer?"
 
-#MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF c=19 r=1
-"SD card  [normal]"
-"Carte SD [normal]"
+#MSG_SD_CARD
+"SD card"
+"Carte SD"
 
-#MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON c=19 r=1
-"SD card [flshAir]"
-"Carte SD[flshAir]"
+#MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY
+"FlashAir"
+"FlshAir"
 
 #
 "Right"
@@ -918,10 +900,6 @@
 "Select nozzle preheat temperature which matches your material."
 "Selectionnez la temperature de prechauffage de la buse qui correspond a votre materiau."
 
-#
-"Select PLA filament:"
-"Selectionnez le fil. PLA:"
-
 #MSG_SET_TEMPERATURE c=19 r=1
 "Set temperature:"
 "Regler temp.:"
@@ -942,50 +920,49 @@
 "Some files will not be sorted. Max. No. of files in 1 folder for sorting is 100."
 "Certains fichiers ne seront pas tries. Max 100 fichiers tries par dossier."
 
-#MSG_SORT_NONE c=17 r=1
-"Sort       [none]"
-"Tri       [aucun]"
+#MSG_SORT
+"Sort"
+"Tri"
 
-#MSG_SORT_TIME c=17 r=1
-"Sort       [time]"
-"Tri       [heure]"
+#MSG_NONE
+"None"
+"Aucun"
+
+#MSG_SORT_TIME
+"Time"
+"Heure"
 
 #
 "Severe skew:"
 "Deviat.sev.:"
 
-#MSG_SORT_ALPHA c=17 r=1
-"Sort   [alphabet]"
-"Tri    [alphabet]"
+#MSG_SORT_ALPHA
+"Alphabet"
+"\x00"
 
 #MSG_SORTING c=20 r=1
 "Sorting files"
 "Tri des fichiers"
 
-#MSG_SOUND_LOUD c=17 r=1
-"Sound      [loud]"
-"Son        [fort]"
+#MSG_SOUND_LOUD
+"Loud"
+"Fort"
 
 #
 "Slight skew:"
 "Deviat.leg.:"
 
-#MSG_SOUND_MUTE c=17 r=1
-"Sound      [mute]"
-"Son        [muet]"
+#MSG_SOUND
+"Sound"
+"Son"
 
 #
 "Some problem encountered, Z-leveling enforced ..."
 "Probleme rencontre, cliquez sur le bouton pour niveller l'axe Z..."
 
-#MSG_SOUND_ONCE c=17 r=1
-"Sound      [once]"
-"Son    [une fois]"
-
-#MSG_SOUND_SILENT c=17 r=1
-"Sound    [silent]"
-"Son      [feutre]"
-
+#MSG_SOUND_ONCE
+"Once"
+"Une fois"
 #MSG_SPEED
 "Speed"
 "Vitesse"
@@ -1018,17 +995,17 @@
 "Swapped"
 "Echange"
 
-#MSG_TEMP_CALIBRATION c=20 r=1
-"Temp. cal.          "
-"Calib. Temp."
+#
+"Select filament:"
+"Selectionnez le filament:"
 
-#MSG_TEMP_CALIBRATION_ON c=20 r=1
-"Temp. cal.   [on]"
-"Calib. Temp. [on]"
+#MSG_TEMP_CALIBRATION c=12 r=1
+"Temp. cal."
+"Calib. Temp."
 
-#MSG_TEMP_CALIBRATION_OFF c=20 r=1
-"Temp. cal.  [off]"
-"Calib. Temp.[off]"
+#
+"Select temperature which matches your material."
+"Selectionnez la temperature qui correspond a votre materiau."
 
 #MSG_CALIBRATION_PINDA_MENU c=17 r=1
 "Temp. calibration"
@@ -1206,13 +1183,21 @@
 "Y distance from min"
 "Distance Y du min"
 
+#
+"The printer will start printing a zig-zag line. Rotate the knob until you reach the optimal height. Check the pictures in the handbook (Calibration chapter)."
+"L'imprimante commencera a  imprimer une ligne en zig-zag. Tournez le bouton jusqu'a atteindre la hauteur optimale. Consultez les photos dans le manuel (chapitre Calibration)."
+
 #
 "Y-correct:"
 "Correct-Y:"
 
 #MSG_OFF
-" [off]"
-" [off]"
+"Off"
+"\x00"
+
+#MSG_ON
+"On"
+"\x00"
 
 #
 "Back"
@@ -1230,17 +1215,17 @@
 "FINDA:"
 "FINDA:"
 
-#
-"Firmware   [none]"
-"Firmware [aucune]"
+#MSG_FIRMWARE
+"Firmware"
+"\x00"
 
-#
-"Firmware [strict]"
-"Firmware[stricte]"
+#MSG_STRICT
+"Strict"
+"Stricte"
 
-#
-"Firmware   [warn]"
-"Firmware  [avert]"
+#MSG_WARN
+"Warn"
+"Avert"
 
 #
 "HW Setup"
@@ -1250,24 +1235,12 @@
 "IR:"
 "IR:"
 
-#
-"Magnets comp.[N/A]"
-"Compens. aim.[N/A]"
-
-#
-"Magnets comp.[Off]"
-"Compens. aim.[off]"
-
-#
-"Magnets comp. [On]"
-"Compens. aim. [on]"
-
-#
-"Mesh         [3x3]"
-"\x00"
+#MSG_MAGNETS_COMP
+"Magnets comp."
+"Compens. aim."
 
-#
-"Mesh         [7x7]"
+#MSG_MESH
+"Mesh"
 "\x00"
 
 #
@@ -1278,53 +1251,21 @@
 "MK3S firmware detected on MK3 printer"
 "Firmware MK3S detecte sur imprimante MK3"
 
-#
-"MMU Mode [Normal]"
-"Mode MMU [normal]"
-
-#
-"MMU Mode[Stealth]"
-"Mode MMU [feutre]"
+#MSG_MMU_MODE
+"MMU Mode"
+"Mode MMU"
 
 #
 "Mode change in progress ..."
 "Changement de mode en cours..."
 
-#
-"Model      [none]"
-"Modele   [aucune]"
-
-#
-"Model    [strict]"
-"Modele  [stricte]"
-
-#
-"Model      [warn]"
-"Modele    [avert]"
-
-#
-"Nozzle d.  [0.25]"
-"Diam. buse [0.25]"
-
-#
-"Nozzle d.  [0.40]"
-"Diam. buse [0.40]"
-
-#
-"Nozzle d.  [0.60]"
-"Diam. buse [0.60]"
-
-#
-"Nozzle     [none]"
-"Buse     [aucune]"
-
-#
-"Nozzle   [strict]"
-"Buse    [stricte]"
+#MSG_MODEL
+"Model"
+"Modele"
 
-#
-"Nozzle     [warn]"
-"Buse      [avert]"
+#MSG_NOZZLE_DIAMETER
+"Nozzle d."
+"Diam. buse"
 
 #
 "G-code sliced for a different level. Continue?"
@@ -1386,9 +1327,9 @@
 "Sheet"
 "Plaque"
 
-#
-"Sound    [assist]"
-"Son      [assist]"
+#MSG_SOUND_BLIND
+"Assist"
+"\x00"
 
 #
 "Steel sheets"
@@ -1398,15 +1339,6 @@
 "Z-correct:"
 "Correct-Z:"
 
-#
-"Z-probe nr.    [1]"
-"Mesurer x-fois [1]"
-
-#
-"Z-probe nr.    [3]"
-"Mesurer x-fois [3]"
-
-#
-"Z-probe nr.    [5]"
-"Mesurer x-fois [5]"
- 
+#MSG_Z_PROBE_NR
+"Z-probe nr."
+"Mesurer x-fois"

+ 132 - 197
lang/lang_en_it.txt

@@ -50,16 +50,8 @@
 "Are left and right Z~carriages all up?"
 "I carrelli Z sin/des sono altezza max?"
 
-#MSG_AUTO_DEPLETE_ON c=17 r=1
-"SpoolJoin    [on]"
-"\x00"
-
-#
-"SpoolJoin   [N/A]"
-"\x00"
-
-#MSG_AUTO_DEPLETE_OFF c=17 r=1
-"SpoolJoin   [off]"
+#MSG_AUTO_DEPLETE c=17 r=1
+"SpoolJoin"
 "\x00"
 
 #MSG_AUTO_HOME
@@ -174,17 +166,13 @@
 "Copy selected language?"
 "Copiare la lingua selezionata?"
 
-#MSG_CRASHDETECT_ON
-"Crash det.   [on]"
-"Rileva.crash [on]"
+#MSG_CRASHDETECT
+"Crash det."
+"Rileva.crash"
 
-#MSG_CRASHDETECT_NA
-"Crash det.  [N/A]"
-"Rileva.crash[N/A]"
-
-#MSG_CRASHDETECT_OFF
-"Crash det.  [off]"
-"Rileva.crash[off]"
+#
+"Choose a filament for the First Layer Calibration and select it in the on-screen menu."
+"Scegli un filamento per la calibrazione del primo strato e selezionalo nel menu sullo schermo."
 
 #MSG_CRASH_DETECTED c=20 r=1
 "Crash detected."
@@ -270,17 +258,9 @@
 "Fail stats MMU"
 "Stat.fall. MMU"
 
-#MSG_FSENS_AUTOLOAD_ON c=17 r=1
-"F. autoload  [on]"
-"Autocar.fil. [on]"
-
-#MSG_FSENS_AUTOLOAD_NA c=17 r=1
-"F. autoload [N/A]"
-"Autocar.fil.[N/A]"
-
-#MSG_FSENS_AUTOLOAD_OFF c=17 r=1
-"F. autoload [off]"
-"Autocar.fil.[off]"
+#MSG_FSENSOR_AUTOLOAD
+"F. autoload"
+"Autocar.fil."
 
 #
 "Fail stats"
@@ -294,26 +274,13 @@
 "Fan test"
 "Test ventola"
 
-#MSG_FANS_CHECK_ON c=17 r=1
-"Fans check   [on]"
-"Control.vent [on]"
-
-#MSG_FANS_CHECK_OFF c=17 r=1
-"Fans check  [off]"
-"Control.vent[off]"
-
-#MSG_FSENSOR_ON
-"Fil. sensor  [on]"
-"Sensore fil. [on]"
-
-#MSG_FSENSOR_NA
-"Fil. sensor [N/A]"
-"Sensore fil.[N/A]"
-
-#MSG_FSENSOR_OFF
-"Fil. sensor [off]"
-"Sensore fil.[off]"
+#MSG_FANS_CHECK
+"Fans check"
+"Control.vent"
 
+#MSG_FSENSOR
+"Fil. sensor"
+"Sensore fil."
 #
 "Filam. runouts"
 "Filam. esauriti"
@@ -482,6 +449,10 @@
 "Last print failures"
 "Fallimenti ultima stampa"
 
+#
+"If you have additional steel sheets, calibrate their presets in Settings - HW Setup - Steel sheets."
+"Se hai piastre d'acciaio aggiuntive, calibra i preset in Impostazioni - Setup HW - Piastre in Acciaio."
+
 #
 "Last print"
 "Ultima stampa"
@@ -570,13 +541,17 @@
 "MMU OK. Resuming..."
 "MMU OK. Riprendendo... "
 
-#MSG_STEALTH_MODE_OFF
-"Mode     [Normal]"
-"Mod.    [normale]"
+#MSG_MODE
+"Mode"
+"Mod."
 
-#MSG_SILENT_MODE_ON
-"Mode     [silent]"
-"Mod. [silenziosa]"
+#MSG_NORMAL
+"Normal"
+"Normale"
+
+#MSG_SILENT
+"Silent"
+"Silenzioso"
 
 #
 "MMU needs user attention."
@@ -586,17 +561,17 @@
 "MMU power fails"
 "Manc. corr. MMU"
 
-#MSG_STEALTH_MODE_ON
-"Mode    [Stealth]"
-"Mod. [silenziosa]"
+#MSG_STEALTH
+"Stealth"
+"Silenziosa"
 
-#MSG_AUTO_MODE_ON
-"Mode [auto power]"
-"Mod.       [auto]"
+#MSG_AUTO_POWER
+"Auto power"
+"Auto"
 
-#MSG_SILENT_MODE_OFF
-"Mode [high power]"
-"Mod.      [forte]"
+#MSG_HIGH_POWER
+"High power"
+"Forte"
 
 #
 "MMU2 connected"
@@ -630,7 +605,7 @@
 "No SD card"
 "Nessuna SD"
 
-#
+#MSG_NA
 "N/A"
 "\x00"
 
@@ -818,6 +793,18 @@
 "Print FAN"
 "Ventola di stampa"
 
+#
+"Please insert filament into the extruder, then press the knob to load it."
+"Inserisci il filamento nell'estrusore, poi premi la manopola per caricarlo."
+
+#
+"Please insert filament into the first tube of the MMU, then press the knob to load it."
+"Per favore inserisci il filamento nel primo tubo del MMU, poi premi la manopola per caricarlo."
+
+#
+"Please load filament first."
+"Per favore prima carica il filamento."
+
 #MSG_PRUSA3D
 "prusa3d.com"
 "\x00"
@@ -858,25 +845,21 @@
 "Right side[um]"
 "Destra [um]"
 
-#MSG_SECOND_SERIAL_ON c=17 r=1
-"RPi port     [on]"
-"Porta RPi    [on]"
-
-#MSG_SECOND_SERIAL_OFF c=17 r=1
-"RPi port    [off]"
-"Porta RPi   [off]"
+#MSG_RPI_PORT
+"RPi port"
+"Porta RPi"
 
 #MSG_WIZARD_RERUN c=20 r=7
 "Running Wizard will delete current calibration results and start from the beginning. Continue?"
 "Se avvi il Wizard perderai la calibrazione preesistente e dovrai ricominciare dall'inizio. Continuare?"
 
-#MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF c=19 r=1
-"SD card  [normal]"
-"Mem. SD [normale]"
+#MSG_SD_CARD
+"SD card"
+"Mem. SD"
 
-#MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON c=19 r=1
-"SD card [flshAir]"
-"Mem. SD [flshAir]"
+#MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY
+"FlashAir"
+"\x00"
 
 #
 "Right"
@@ -918,10 +901,6 @@
 "Select nozzle preheat temperature which matches your material."
 "Selezionate la temperatura per il preriscaldamento dell'ugello adatta al vostro materiale."
 
-#
-"Select PLA filament:"
-"Selezionate filamento PLA:"
-
 #MSG_SET_TEMPERATURE c=19 r=1
 "Set temperature:"
 "Imposta temperatura:"
@@ -942,49 +921,49 @@
 "Some files will not be sorted. Max. No. of files in 1 folder for sorting is 100."
 "Alcuni file non saranno ordinati. Il numero massimo di file in una cartella e 100 perche siano ordinati."
 
-#MSG_SORT_NONE c=17 r=1
-"Sort       [none]"
-"Ordina  [nessuno]"
+#MSG_SORT
+"Sort"
+"Ordina"
+
+#MSG_NONE
+"None"
+"Nessuno"
 
-#MSG_SORT_TIME c=17 r=1
-"Sort       [time]"
-"Ordina    [cron.]"
+#MSG_SORT_TIME
+"Time"
+"Cron."
 
 #
 "Severe skew:"
 "Devia.grave:"
 
-#MSG_SORT_ALPHA c=17 r=1
-"Sort   [alphabet]"
-"Ordine [alfabeti]"
+#MSG_SORT_ALPHA
+"Alphabet"
+"Alfabeti"
 
 #MSG_SORTING c=20 r=1
 "Sorting files"
 "Ordinando i file"
 
-#MSG_SOUND_LOUD c=17 r=1
-"Sound      [loud]"
-"Suono     [forte]"
+#MSG_SOUND_LOUD
+"Loud"
+"Forte"
 
 #
 "Slight skew:"
 "Devia.lieve:"
 
-#MSG_SOUND_MUTE c=17 r=1
-"Sound      [mute]"
-"Suono      [mute]"
+#MSG_SOUND
+"Sound"
+"Suono"
 
 #
 "Some problem encountered, Z-leveling enforced ..."
 "Sono stati rilevati problemi, avviato livellamento Z ..."
 
-#MSG_SOUND_ONCE c=17 r=1
-"Sound      [once]"
-"Suono   [singolo]"
-
-#MSG_SOUND_SILENT c=17 r=1
-"Sound    [silent]"
-"Suono[silenzioso]"
+#MSG_SOUND_ONCE
+"Once"
+"Singolo"
 
 #MSG_SPEED
 "Speed"
@@ -1018,17 +997,17 @@
 "Swapped"
 "Scambiato"
 
-#MSG_TEMP_CALIBRATION c=20 r=1
-"Temp. cal.          "
-"Calib. temp. "
+#
+"Select filament:"
+"Seleziona il filamento:"
 
-#MSG_TEMP_CALIBRATION_ON c=20 r=1
-"Temp. cal.   [on]"
-"Calib. temp. [on]"
+#MSG_TEMP_CALIBRATION c=12 r=1
+"Temp. cal."
+"Calib. temp."
 
-#MSG_TEMP_CALIBRATION_OFF c=20 r=1
-"Temp. cal.  [off]"
-"Calib. temp.[off]"
+#
+"Select temperature which matches your material."
+"Seleziona la temperatura appropriata per il tuo materiale."
 
 #MSG_CALIBRATION_PINDA_MENU c=17 r=1
 "Temp. calibration"
@@ -1206,12 +1185,20 @@
 "Y distance from min"
 "Distanza Y dal min"
 
+#
+"The printer will start printing a zig-zag line. Rotate the knob until you reach the optimal height. Check the pictures in the handbook (Calibration chapter)."
+"La stampante iniziera a stampare una linea a zig-zag. Gira la manopola fino a che non hai raggiungo l'altezza ottimale. Verifica con le immagini nel manuale (capitolo sulla calibrazione):"
+
 #
 "Y-correct:"
 "Correzione-Y:"
 
 #MSG_OFF
-" [off]"
+"Off"
+"\x00"
+
+#MSG_ON
+"On"
 "\x00"
 
 #
@@ -1230,17 +1217,17 @@
 "FINDA:"
 "\x00"
 
-#
-"Firmware   [none]"
-"Firmware[nessuno]"
+#MSG_FIRMWARE
+"Firmware"
+"\x00"
 
-#
-"Firmware [strict]"
-"Firmware [esatto]"
+#MSG_STRICT
+"Strict"
+"Esatto"
 
-#
-"Firmware   [warn]"
-"Firmware [avviso]"
+#MSG_WARN
+"Warn"
+"Avviso"
 
 #
 "HW Setup"
@@ -1250,25 +1237,13 @@
 "IR:"
 "\x00"
 
-#
-"Magnets comp.[N/A]"
-"Comp. Magneti[N/A]"
-
-#
-"Magnets comp.[Off]"
-"Comp. Magneti[off]"
-
-#
-"Magnets comp. [On]"
-"Comp. Magneti [on]"
-
-#
-"Mesh         [3x3]"
-"Griglia      [3x3]"
+#MSG_MAGNETS_COMP
+"Magnets comp."
+"Comp. Magneti"
 
-#
-"Mesh         [7x7]"
-"Griglia      [7x7]"
+#MSG_MESH
+"Mesh"
+"Griglia"
 
 #
 "Mesh bed leveling"
@@ -1278,53 +1253,21 @@
 "MK3S firmware detected on MK3 printer"
 "Firmware MK3S rilevato su stampante MK3"
 
-#
-"MMU Mode [Normal]"
-"Modalita MMU [Normale]"
-
-#
-"MMU Mode[Stealth]"
-"Modalita MMU [Silenziosa]"
+#MSG_MMU_MODE
+"MMU Mode"
+"Mod. MMU"
 
 #
 "Mode change in progress ..."
 "Cambio modalita in corso ..."
 
-#
-"Model      [none]"
-"Modello [nessuno]"
-
-#
-"Model    [strict]"
-"Modello  [esatto]"
-
-#
-"Model      [warn]"
-"Modello  [avviso]"
-
-#
-"Nozzle d.  [0.25]"
-"Diam.Ugello[0.25]"
-
-#
-"Nozzle d.  [0.40]"
-"Diam.Ugello[0.40]"
-
-#
-"Nozzle d.  [0.60]"
-"Diam.Ugello[0.60]"
-
-#
-"Nozzle     [none]"
-"Ugello  [nessuno]"
-
-#
-"Nozzle   [strict]"
-"Ugello   [esatto]"
+#MSG_MODEL
+"Model"
+"Modello"
 
-#
-"Nozzle     [warn]"
-"Ugello   [avviso]"
+#MSG_NOZZLE_DIAMETER
+"Nozzle d."
+"Diam.Ugello"
 
 #
 "G-code sliced for a different level. Continue?"
@@ -1386,9 +1329,9 @@
 "Sheet"
 "Piano"
 
-#
-"Sound    [assist]"
-"Suono   [assist.]"
+#MSG_SOUND_BLIND
+"Assist"
+"Assist."
 
 #
 "Steel sheets"
@@ -1398,14 +1341,6 @@
 "Z-correct:"
 "Correzione-Z:"
 
-#
-"Z-probe nr.    [1]"
-"Z-probe nr.    [1]"
-
-#
-"Z-probe nr.    [3]"
-"Z-probe nr.    [3]"
-
-#
-"Z-probe nr.    [5]"
-"Z-probe nr.    [5]"
+#MSG_Z_PROBE_NR
+"Z-probe nr."
+"\x00"

+ 134 - 199
lang/lang_en_pl.txt

@@ -50,17 +50,9 @@
 "Are left and right Z~carriages all up?"
 "Obydwa konce osi sa na szczycie?"
 
-#MSG_AUTO_DEPLETE_ON c=17 r=1
-"SpoolJoin    [on]"
-"SpoolJoin    [wl]"
-
-#
-"SpoolJoin   [N/A]"
-"SpoolJoin   [N/D]"
-
-#MSG_AUTO_DEPLETE_OFF c=17 r=1
-"SpoolJoin   [off]"
-"SpoolJoin   [wyl]"
+#MSG_AUTO_DEPLETE c=17 r=1
+"SpoolJoin"
+"\x00"
 
 #MSG_AUTO_HOME
 "Auto home"
@@ -72,7 +64,7 @@
 
 #MSG_AUTOLOADING_ONLY_IF_FSENS_ON c=20 r=4
 "Autoloading filament available only when filament sensor is turned on..."
-"Autoladowanie filamentu dostepne tylko gdy czujnik filamentu jest wlaczony..."
+"Autoladowanie fil. dostepne tylko gdy czujnik filamentu jest wlaczony..."
 
 #MSG_AUTOLOADING_ENABLED c=20 r=4
 "Autoloading filament is active, just press the knob and insert filament..."
@@ -175,16 +167,12 @@
 "Skopiowac wybrany jezyk?"
 
 #MSG_CRASHDETECT_ON
-"Crash det.   [on]"
-"Wykr.zderzen [wl]"
-
-#MSG_CRASHDETECT_NA
-"Crash det.  [N/A]"
-"Wykr.zderzen[N/D]"
+"Crash det."
+"Wykr.zderzen"
 
-#MSG_CRASHDETECT_OFF
-"Crash det.  [off]"
-"Wykr.zderzen[wyl]"
+#
+"Choose a filament for the First Layer Calibration and select it in the on-screen menu."
+"Wybierz filament do Kalibracji Pierwszej Warstwy i potwierdz w menu ekranowym."
 
 #MSG_CRASH_DETECTED c=20 r=1
 "Crash detected."
@@ -270,17 +258,9 @@
 "Fail stats MMU"
 "Bledy MMU"
 
-#MSG_FSENS_AUTOLOAD_ON c=17 r=1
-"F. autoload  [on]"
-"Autolad.fil. [wl]"
-
-#MSG_FSENS_AUTOLOAD_NA c=17 r=1
-"F. autoload [N/A]"
-"Autolad.fil.[N/D]"
-
-#MSG_FSENS_AUTOLOAD_OFF c=17 r=1
-"F. autoload [off]"
-"Autolad.fil.[wyl]"
+#MSG_FSENSOR_AUTOLOAD
+"F. autoload"
+"Autolad. fil."
 
 #
 "Fail stats"
@@ -294,25 +274,13 @@
 "Fan test"
 "Test wentylatora"
 
-#MSG_FANS_CHECK_ON c=17 r=1
-"Fans check   [on]"
-"Sprawd.went. [wl]"
-
-#MSG_FANS_CHECK_OFF c=17 r=1
-"Fans check  [off]"
-"Sprawd.went.[wyl]"
-
-#MSG_FSENSOR_ON
-"Fil. sensor  [on]"
-"Czuj. filam. [wl]"
+#MSG_FANS_CHECK
+"Fans check"
+"Sprawd.went."
 
-#MSG_FSENSOR_NA
-"Fil. sensor [N/A]"
-"Czuj. filam.[N/D]"
-
-#MSG_FSENSOR_OFF
-"Fil. sensor [off]"
-"Czuj. filam.[wyl]"
+#MSG_FSENSOR
+"Fil. sensor"
+"Czuj. filam."
 
 #
 "Filam. runouts"
@@ -482,6 +450,10 @@
 "Last print failures"
 "Ostatnie bledy druku"
 
+#
+"If you have additional steel sheets, calibrate their presets in Settings - HW Setup - Steel sheets."
+"Jesli masz dodatkowe plyty stalowe, to skalibruj ich ustawienia w menu Ustawienia - Ustawienia HW - Plyty stalowe."
+
 #
 "Last print"
 "Ost. wydruk"
@@ -570,13 +542,17 @@
 "MMU OK. Resuming..."
 "MMU OK. Wznawianie..."
 
-#MSG_STEALTH_MODE_OFF
-"Mode     [Normal]"
-"Tryb   [normalny]"
+#MSG_MODE
+"Mode"
+"Tryb"
 
-#MSG_SILENT_MODE_ON
-"Mode     [silent]"
-"Tryb      [cichy]"
+#MSG_NORMAL
+"Normal"
+"Normalny"
+
+#MSG_SILENT
+"Silent"
+"Cichy"
 
 #
 "MMU needs user attention."
@@ -586,17 +562,17 @@
 "MMU power fails"
 "Zaniki zasil. MMU"
 
-#MSG_STEALTH_MODE_ON
-"Mode    [Stealth]"
-"Tryb      [cichy]"
+#MSG_STEALTH
+"Stealth"
+"Cichy"
 
-#MSG_AUTO_MODE_ON
-"Mode [auto power]"
-"Tryb [automatycz]"
+#MSG_AUTO_POWER
+"Auto power"
+"Automatycz"
 
-#MSG_SILENT_MODE_OFF
-"Mode [high power]"
-"Tryb[wysoka wyd.]"
+#MSG_HIGH_POWER
+"High power"
+"Wysoka wyd."
 
 #
 "MMU2 connected"
@@ -630,7 +606,7 @@
 "No SD card"
 "Brak karty SD"
 
-#
+#MSG_NA
 "N/A"
 "N/D"
 
@@ -818,6 +794,18 @@
 "Print FAN"
 "WentWydruk"
 
+#
+"Please insert filament into the extruder, then press the knob to load it."
+"Wsun filament do ekstrudera i nacisnij pokretlo, aby go zaladowac."
+
+#
+"Please insert filament into the first tube of the MMU, then press the knob to load it."
+"Wsun filament do pierwszego kanalu w MMU2 i nacisnij pokretlo, aby go zaladowac."
+
+#
+"Please load filament first."
+"Najpierw zaladuj filament."
+
 #MSG_PRUSA3D
 "prusa3d.com"
 "\x00"
@@ -858,25 +846,21 @@
 "Right side[um]"
 "Prawo [um]"
 
-#MSG_SECOND_SERIAL_ON c=17 r=1
-"RPi port     [on]"
-"Port RPi     [wl]"
-
-#MSG_SECOND_SERIAL_OFF c=17 r=1
-"RPi port    [off]"
-"Port RPi    [wyl]"
+#MSG_RPI_PORT
+"RPi port"
+"Port RPi"
 
 #MSG_WIZARD_RERUN c=20 r=7
 "Running Wizard will delete current calibration results and start from the beginning. Continue?"
 "Wlaczenie Asystenta usunie obecne dane kalibracyjne i zacznie od poczatku. Kontynuowac?"
 
-#MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_OFF c=19 r=1
-"SD card  [normal]"
-"Karta SD [normal]"
+#MSG_SD_CARD
+"SD card"
+"Karta SD"
 
-#MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY_ON c=19 r=1
-"SD card [flshAir]"
-"Karta SD[FlshAir]"
+#MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY
+"FlashAir"
+"\x00"
 
 #
 "Right"
@@ -918,10 +902,6 @@
 "Select nozzle preheat temperature which matches your material."
 "Wybierz temperature grzania dyszy odpowiednia dla materialu."
 
-#
-"Select PLA filament:"
-"Wybierz filament PLA:"
-
 #MSG_SET_TEMPERATURE c=19 r=1
 "Set temperature:"
 "Ustaw temperature:"
@@ -942,50 +922,49 @@
 "Some files will not be sorted. Max. No. of files in 1 folder for sorting is 100."
 "Niektore pliki nie zostana posortowane. Max. liczba plikow w 1 folderze = 100."
 
-#MSG_SORT_NONE c=17 r=1
-"Sort       [none]"
-"Sortowanie [brak]"
+#MSG_SORT
+"Sort"
+"Sortowanie"
+
+#MSG_NONE
+"None"
+"Brak"
 
-#MSG_SORT_TIME c=17 r=1
-"Sort       [time]"
-"Sortowanie [czas]"
+#MSG_SORT_TIME
+"Time"
+"Czas"
 
 #
 "Severe skew:"
 "Znaczny skos:"
 
-#MSG_SORT_ALPHA c=17 r=1
-"Sort   [alphabet]"
-"Sortowanie[alfab]"
+#MSG_SORT_ALPHA
+"Alphabet"
+"Alfab"
 
 #MSG_SORTING c=20 r=1
 "Sorting files"
 "Sortowanie plikow"
 
-#MSG_SOUND_LOUD c=17 r=1
-"Sound      [loud]"
-"Dzwiek   [glosny]"
+#MSG_SOUND_LOUD
+"Loud"
+"Glosny"
 
 #
 "Slight skew:"
 "Lekki skos:"
 
-#MSG_SOUND_MUTE c=17 r=1
-"Sound      [mute]"
-"Dzwiek[wylaczony]"
+#MSG_SOUND
+"Sound"
+"Dzwiek"
 
 #
 "Some problem encountered, Z-leveling enforced ..."
 "Wykryto problem, wymuszono poziomowanie osi Z."
 
-#MSG_SOUND_ONCE c=17 r=1
-"Sound      [once]"
-"Dzwiek    [1-raz]"
-
-#MSG_SOUND_SILENT c=17 r=1
-"Sound    [silent]"
-"Dzwiek    [cichy]"
-
+#MSG_SOUND_ONCE
+"Once"
+"1-raz"
 #MSG_SPEED
 "Speed"
 "Predkosc"
@@ -1018,17 +997,17 @@
 "Swapped"
 "Zamieniono"
 
-#MSG_TEMP_CALIBRATION c=20 r=1
-"Temp. cal.          "
-"Kalibracja temp."
+#
+"Select filament:"
+"Wybierz filament:"
 
-#MSG_TEMP_CALIBRATION_ON c=20 r=1
-"Temp. cal.   [on]"
-"Kalibr.temp. [wl]"
+#MSG_TEMP_CALIBRATION c=12 r=1
+"Temp. cal."
+"Kalibracja temp."
 
-#MSG_TEMP_CALIBRATION_OFF c=20 r=1
-"Temp. cal.  [off]"
-"Kalibr.temp.[wyl]"
+#
+"Select temperature which matches your material."
+"Wybierz temperature, ktora odpowiada Twojemu filamentowi."
 
 #MSG_CALIBRATION_PINDA_MENU c=17 r=1
 "Temp. calibration"
@@ -1206,13 +1185,21 @@
 "Y distance from min"
 "Dystans od 0 w osi Y"
 
+#
+"The printer will start printing a zig-zag line. Rotate the knob until you reach the optimal height. Check the pictures in the handbook (Calibration chapter)."
+"Drukarka zacznie drukowanie linii w ksztalcie zygzaka. Ustaw optymalna wysokosc obracajac pokretlo. Porownaj z ilustracjami w Podreczniku (rozdzial Kalibracja)."
+
 #
 "Y-correct:"
 "Korekcja-Y:"
 
 #MSG_OFF
-" [off]"
-" [wyl]"
+"Off"
+"Wyl"
+
+#MSG_ON
+"On"
+"Wl"
 
 #
 "Back"
@@ -1230,17 +1217,17 @@
 "FINDA:"
 "\x00"
 
-#
-"Firmware   [none]"
-"Firmware   [brak]"
+#MSG_FIRMWARE
+"Firmware"
+"\x00"
 
-#
-"Firmware [strict]"
-"Firmware [restr.]"
+#MSG_STRICT
+"Strict"
+"Restr."
 
-#
-"Firmware   [warn]"
-"Firmware[ostrzez]"
+#MSG_WARN
+"Warn"
+"Ostrzez"
 
 #
 "HW Setup"
@@ -1250,25 +1237,13 @@
 "IR:"
 "\x00"
 
-#
-"Magnets comp.[N/A]"
-"Kor. magnesow[N/D]"
-
-#
-"Magnets comp.[Off]"
-"Kor. magnesow[wyl]"
+#MSG_MAGNETS_COMP
+"Magnets comp."
+"Kor. magnesow"
 
-#
-"Magnets comp. [On]"
-"Kor. magnesow [wl]"
-
-#
-"Mesh         [3x3]"
-"Siatka       [3x3]"
-
-#
-"Mesh         [7x7]"
-"Siatka       [7x7]"
+#MSG_MESH
+"Mesh"
+"Siatka"
 
 #
 "Mesh bed leveling"
@@ -1278,53 +1253,21 @@
 "MK3S firmware detected on MK3 printer"
 "Wykryto firmware MK3S w drukarce MK3"
 
-#
-"MMU Mode [Normal]"
-"Tryb MMU[Normaln]"
-
-#
-"MMU Mode[Stealth]"
-"Tryb MMU[Stealth]"
+#MSG_MMU_MODE
+"MMU Mode"
+"Tryb MMU"
 
 #
 "Mode change in progress ..."
 "Trwa zmiana trybu..."
 
-#
-"Model      [none]"
-"Model      [brak]"
-
-#
-"Model    [strict]"
-"Model [restrykc.]"
-
-#
-"Model      [warn]"
-"Model  [ostrzez.]"
-
-#
-"Nozzle d.  [0.25]"
-"Sr. dyszy  [0,25]"
-
-#
-"Nozzle d.  [0.40]"
-"Sr. dyszy  [0,40]"
-
-#
-"Nozzle d.  [0.60]"
-"Sr. dyszy  [0,60]"
-
-#
-"Nozzle     [none]"
-"Dysza      [brak]"
-
-#
-"Nozzle   [strict]"
-"Dysza [restrykc.]"
+#MSG_MODEL
+"Model"
+"\x00"
 
-#
-"Nozzle     [warn]"
-"Dysza  [ostrzez.]"
+#MSG_NOZZLE_DIAMETER
+"Nozzle d."
+"Sr. dyszy"
 
 #
 "G-code sliced for a different level. Continue?"
@@ -1386,9 +1329,9 @@
 "Sheet"
 "Plyta"
 
-#
-"Sound    [assist]"
-"Dzwiek   [asyst.]"
+#MSG_SOUND_BLIND
+"Assist"
+"Asyst."
 
 #
 "Steel sheets"
@@ -1398,14 +1341,6 @@
 "Z-correct:"
 "Korekcja-Z:"
 
-#
-"Z-probe nr.    [1]"
-"Ilosc Pomiarow [1]"
-
-#
-"Z-probe nr.    [3]"
-"Ilosc Pomiarow [3]"
-
-#
-"Z-probe nr.    [5]"
-"Ilosc Pomiarow [5]"
+#MSG_Z_PROBE_NR
+"Z-probe nr."
+"Ilosc Pomiarow"