From 21dcfb23f45b11bdb41c316d75d9bed1fd406cfa Mon Sep 17 00:00:00 2001
From: 3d-gussner <3d.gussner@gmail.com>
Date: Thu, 31 Oct 2019 15:31:08 +0100
Subject: [PATCH 01/58] Follow RepRap Wiki G-codes documentation M120 is Enable
 endstops M121 is disable endstops I guess this was just a typo issue.

---
 Firmware/Marlin_main.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp
index a2cbece5..593194c6 100755
--- a/Firmware/Marlin_main.cpp
+++ b/Firmware/Marlin_main.cpp
@@ -6366,16 +6366,16 @@ Sigma_Exit:
       lcd_setstatus(strchr_pointer + 5);
       break;*/
 
-    //! ### M120 - Disable endstops
+    //! ### M120 - Ensable endstops
     // ----------------------------------------
     case 120:
-      enable_endstops(false) ;
+      enable_endstops(true) ;
       break;
 
-    //! ### M121 - Enable endstops
+    //! ### M121 - Disable endstops
     // ----------------------------------------
     case 121:
-      enable_endstops(true) ;
+      enable_endstops(false) ;
       break;
 
     //! ### M119 - Get endstop states

From 6017600714a751a46b879964d186ea97115c5277 Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Sun, 16 Jun 2019 21:05:13 +0200
Subject: [PATCH 02/58] Reintroduce the ability to disable TMC interpolation
 per-axis

---
 Firmware/tmc2130.cpp | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/Firmware/tmc2130.cpp b/Firmware/tmc2130.cpp
index 108d00b1..b87272e2 100755
--- a/Firmware/tmc2130.cpp
+++ b/Firmware/tmc2130.cpp
@@ -437,6 +437,9 @@ void tmc2130_setup_chopper(uint8_t axis, uint8_t mres, uint8_t current_h, uint8_
 	uint8_t tbl = tmc2130_chopper_config[axis].tbl; //blanking time, original value = 2
 	if (axis == E_AXIS)
 	{
+#if defined(TMC2130_INTPOL_E) && (TMC2130_INTPOL_E == 0)
+        intpol = 0;
+#endif
 #ifdef TMC2130_CNSTOFF_E
 		// fd = 0 (slow decay only)
 		hstrt = 0; //fd0..2
@@ -447,6 +450,16 @@ void tmc2130_setup_chopper(uint8_t axis, uint8_t mres, uint8_t current_h, uint8_
 //		toff = TMC2130_TOFF_E; // toff = 3-5
 //		rndtf = 1;
 	}
+#if defined(TMC2130_INTPOL_XY) && (TMC2130_INTPOL_XY == 0)
+    else if (axis == X_AXIS || axis == Y_AXIS) {
+        intpol = 0;
+    }
+#endif
+#if defined(TMC2130_INTPOL_Z) && (TMC2130_INTPOL_Z == 0)
+    else if (axis == Z_AXIS) {
+        intpol = 0;
+    }
+#endif
 //	DBG(_n("tmc2130_setup_chopper(axis=%hhd, mres=%hhd, curh=%hhd, curr=%hhd\n"), axis, mres, current_h, current_r);
 //	DBG(_n(" toff=%hhd, hstr=%hhd, hend=%hhd, tbl=%hhd\n"), toff, hstrt, hend, tbl);
 	if (current_r <= 31)

From 6ceca9bf85f93479e677194635e873bbfa831bbb Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Tue, 18 Feb 2020 11:52:36 +0100
Subject: [PATCH 03/58] Implement double-edge stepping

Introduce new wrapper macros to tick the stepper pins.
Default to the original raising-edge stepping mode.

When using the TMC double-edge stepping mode (aka half-wave or
square-wave mode) the _LO macros become no-ops.
---
 Firmware/stepper.cpp | 128 +++++++++++++++++++++++++++++--------------
 Firmware/tmc2130.cpp |  16 +++++-
 2 files changed, 100 insertions(+), 44 deletions(-)

diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp
index de250ec9..8f2a4f12 100644
--- a/Firmware/stepper.cpp
+++ b/Firmware/stepper.cpp
@@ -48,6 +48,50 @@ int fsensor_counter; //counter for e-steps
 uint16_t SP_min = 0x21FF;
 #endif //DEBUG_STACK_MONITOR
 
+
+/*
+ * Stepping macros
+ */
+#define _STEP_PIN_X_AXIS X_STEP_PIN
+#define _STEP_PIN_Y_AXIS Y_STEP_PIN
+#define _STEP_PIN_Z_AXIS Z_STEP_PIN
+#define _STEP_PIN_E_AXIS E0_STEP_PIN
+
+#ifdef DEBUG_XSTEP_DUP_PIN
+#define _STEP_PIN_X_DUP_AXIS DEBUG_XSTEP_DUP_PIN
+#endif
+#ifdef DEBUG_YSTEP_DUP_PIN
+#define _STEP_PIN_Y_DUP_AXIS DEBUG_YSTEP_DUP_PIN
+#endif
+#ifdef Y_DUAL_STEPPER_DRIVERS
+#error Y_DUAL_STEPPER_DRIVERS not fully implemented
+#define _STEP_PIN_Y2_AXIS Y2_STEP_PIN
+#endif
+#ifdef Z_DUAL_STEPPER_DRIVERS
+#error Z_DUAL_STEPPER_DRIVERS not fully implemented
+#define _STEP_PIN_Z2_AXIS Z2_STEP_PIN
+#endif
+
+#ifdef TMC2130_DEDGE_STEPPING
+#define STEP_NC_HI(axis) TOGGLE(_STEP_PIN_##axis)
+#define STEP_NC_LO(axis) //NOP
+#else
+
+#define _STEP_HI_X_AXIS  !INVERT_X_STEP_PIN
+#define _STEP_LO_X_AXIS  INVERT_X_STEP_PIN
+#define _STEP_HI_Y_AXIS  !INVERT_Y_STEP_PIN
+#define _STEP_LO_Y_AXIS  INVERT_Y_STEP_PIN
+#define _STEP_HI_Z_AXIS  !INVERT_Z_STEP_PIN
+#define _STEP_LO_Z_AXIS  INVERT_Z_STEP_PIN
+#define _STEP_HI_E_AXIS  !INVERT_E_STEP_PIN
+#define _STEP_LO_E_AXIS  INVERT_E_STEP_PIN
+
+#define STEP_NC_HI(axis) WRITE_NC(_STEP_PIN_##axis, _STEP_HI_##axis)
+#define STEP_NC_LO(axis) WRITE_NC(_STEP_PIN_##axis, _STEP_LO_##axis)
+
+#endif //TMC2130_DEDGE_STEPPING
+
+
 //===========================================================================
 //=============================public variables  ============================
 //===========================================================================
@@ -300,9 +344,9 @@ FORCE_INLINE void stepper_next_block()
 			_delay_us(100);
 			for (uint8_t i = 0; i < st_backlash_x; i++)
 			{
-				WRITE_NC(X_STEP_PIN, !INVERT_X_STEP_PIN);
+				STEP_NC_HI(X_AXIS);
 				_delay_us(100);
-				WRITE_NC(X_STEP_PIN, INVERT_X_STEP_PIN);
+				STEP_NC_LO(X_AXIS);
 				_delay_us(900);
 			}
 		}
@@ -323,9 +367,9 @@ FORCE_INLINE void stepper_next_block()
 			_delay_us(100);
 			for (uint8_t i = 0; i < st_backlash_y; i++)
 			{
-				WRITE_NC(Y_STEP_PIN, !INVERT_Y_STEP_PIN);
+				STEP_NC_HI(Y_AXIS);
 				_delay_us(100);
-				WRITE_NC(Y_STEP_PIN, INVERT_Y_STEP_PIN);
+				STEP_NC_LO(Y_AXIS);
 				_delay_us(900);
 			}
 		}
@@ -607,44 +651,44 @@ FORCE_INLINE void stepper_tick_lowres()
     // Step in X axis
     counter_x.lo += current_block->steps_x.lo;
     if (counter_x.lo > 0) {
-      WRITE_NC(X_STEP_PIN, !INVERT_X_STEP_PIN);
+      STEP_NC_HI(X_AXIS);
 #ifdef DEBUG_XSTEP_DUP_PIN
-      WRITE_NC(DEBUG_XSTEP_DUP_PIN,!INVERT_X_STEP_PIN);
+      STEP_NC_HI(X_DUP_AXIS);
 #endif //DEBUG_XSTEP_DUP_PIN
       counter_x.lo -= current_block->step_event_count.lo;
       count_position[X_AXIS]+=count_direction[X_AXIS];
-      WRITE_NC(X_STEP_PIN, INVERT_X_STEP_PIN);
+      STEP_NC_LO(X_AXIS);
 #ifdef DEBUG_XSTEP_DUP_PIN
-      WRITE_NC(DEBUG_XSTEP_DUP_PIN,INVERT_X_STEP_PIN);
+      STEP_NC_LO(X_DUP_AXIS);
 #endif //DEBUG_XSTEP_DUP_PIN
     }
     // Step in Y axis
     counter_y.lo += current_block->steps_y.lo;
     if (counter_y.lo > 0) {
-      WRITE_NC(Y_STEP_PIN, !INVERT_Y_STEP_PIN);
+      STEP_NC_HI(Y_AXIS);
 #ifdef DEBUG_YSTEP_DUP_PIN
-      WRITE_NC(DEBUG_YSTEP_DUP_PIN,!INVERT_Y_STEP_PIN);
+      STEP_NC_HI(Y_DUP_AXIS);
 #endif //DEBUG_YSTEP_DUP_PIN
       counter_y.lo -= current_block->step_event_count.lo;
       count_position[Y_AXIS]+=count_direction[Y_AXIS];
-      WRITE_NC(Y_STEP_PIN, INVERT_Y_STEP_PIN);
+      STEP_NC_LO(Y_AXIS);
 #ifdef DEBUG_YSTEP_DUP_PIN
-      WRITE_NC(DEBUG_YSTEP_DUP_PIN,INVERT_Y_STEP_PIN);
+      STEP_NC_LO(Y_DUP_AXIS);
 #endif //DEBUG_YSTEP_DUP_PIN    
     }
     // Step in Z axis
     counter_z.lo += current_block->steps_z.lo;
     if (counter_z.lo > 0) {
-      WRITE_NC(Z_STEP_PIN, !INVERT_Z_STEP_PIN);
+      STEP_NC_HI(Z_AXIS);
       counter_z.lo -= current_block->step_event_count.lo;
       count_position[Z_AXIS]+=count_direction[Z_AXIS];
-      WRITE_NC(Z_STEP_PIN, INVERT_Z_STEP_PIN);
+      STEP_NC_LO(Z_AXIS);
     }
     // Step in E axis
     counter_e.lo += current_block->steps_e.lo;
     if (counter_e.lo > 0) {
 #ifndef LIN_ADVANCE
-      WRITE(E0_STEP_PIN, !INVERT_E_STEP_PIN);
+      STEP_NC_HI(E_AXIS);
 #endif /* LIN_ADVANCE */
       counter_e.lo -= current_block->step_event_count.lo;
       count_position[E_AXIS] += count_direction[E_AXIS];
@@ -654,7 +698,7 @@ FORCE_INLINE void stepper_tick_lowres()
 	#ifdef FILAMENT_SENSOR
 	  fsensor_counter += count_direction[E_AXIS];
 	#endif //FILAMENT_SENSOR
-      WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN);
+      STEP_NC_LO(E_AXIS);
 #endif
     }
     if(++ step_events_completed.lo >= current_block->step_event_count.lo)
@@ -669,44 +713,44 @@ FORCE_INLINE void stepper_tick_highres()
     // Step in X axis
     counter_x.wide += current_block->steps_x.wide;
     if (counter_x.wide > 0) {
-      WRITE_NC(X_STEP_PIN, !INVERT_X_STEP_PIN);
+      STEP_NC_HI(X_AXIS);
 #ifdef DEBUG_XSTEP_DUP_PIN
-      WRITE_NC(DEBUG_XSTEP_DUP_PIN,!INVERT_X_STEP_PIN);
+      STEP_NC_HI(X_DUP_AXIS);
 #endif //DEBUG_XSTEP_DUP_PIN
       counter_x.wide -= current_block->step_event_count.wide;
       count_position[X_AXIS]+=count_direction[X_AXIS];   
-      WRITE_NC(X_STEP_PIN, INVERT_X_STEP_PIN);
+      STEP_NC_LO(X_AXIS);
 #ifdef DEBUG_XSTEP_DUP_PIN
-      WRITE_NC(DEBUG_XSTEP_DUP_PIN,INVERT_X_STEP_PIN);
+      STEP_NC_LO(X_DUP_AXIS);
 #endif //DEBUG_XSTEP_DUP_PIN
     }
     // Step in Y axis
     counter_y.wide += current_block->steps_y.wide;
     if (counter_y.wide > 0) {
-      WRITE_NC(Y_STEP_PIN, !INVERT_Y_STEP_PIN);
+      STEP_NC_HI(Y_AXIS);
 #ifdef DEBUG_YSTEP_DUP_PIN
-      WRITE_NC(DEBUG_YSTEP_DUP_PIN,!INVERT_Y_STEP_PIN);
+      STEP_NC_HI(Y_DUP_AXIS);
 #endif //DEBUG_YSTEP_DUP_PIN
       counter_y.wide -= current_block->step_event_count.wide;
       count_position[Y_AXIS]+=count_direction[Y_AXIS];
-      WRITE_NC(Y_STEP_PIN, INVERT_Y_STEP_PIN);
+      STEP_NC_LO(Y_AXIS);
 #ifdef DEBUG_YSTEP_DUP_PIN
-      WRITE_NC(DEBUG_YSTEP_DUP_PIN,INVERT_Y_STEP_PIN);
+      STEP_NC_LO(Y_DUP_AXIS);
 #endif //DEBUG_YSTEP_DUP_PIN    
     }
     // Step in Z axis
     counter_z.wide += current_block->steps_z.wide;
     if (counter_z.wide > 0) {
-      WRITE_NC(Z_STEP_PIN, !INVERT_Z_STEP_PIN);
+      STEP_NC_HI(Z_AXIS);
       counter_z.wide -= current_block->step_event_count.wide;
       count_position[Z_AXIS]+=count_direction[Z_AXIS];
-      WRITE_NC(Z_STEP_PIN, INVERT_Z_STEP_PIN);
+      STEP_NC_LO(Z_AXIS);
     }
     // Step in E axis
     counter_e.wide += current_block->steps_e.wide;
     if (counter_e.wide > 0) {
 #ifndef LIN_ADVANCE
-      WRITE(E0_STEP_PIN, !INVERT_E_STEP_PIN);
+      STEP_NC_HI(E_AXIS);
 #endif /* LIN_ADVANCE */
       counter_e.wide -= current_block->step_event_count.wide;
       count_position[E_AXIS]+=count_direction[E_AXIS];
@@ -716,7 +760,7 @@ FORCE_INLINE void stepper_tick_highres()
     #ifdef FILAMENT_SENSOR
       fsensor_counter += count_direction[E_AXIS];
     #endif //FILAMENT_SENSOR
-      WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN);
+      STEP_NC_LO(E_AXIS);
 #endif
     }
     if(++ step_events_completed.wide >= current_block->step_event_count.wide)
@@ -997,9 +1041,9 @@ FORCE_INLINE void advance_isr_scheduler() {
         bool rev = (e_steps < 0);
         do
         {
-            WRITE_NC(E0_STEP_PIN, !INVERT_E_STEP_PIN);
+            STEP_NC_HI(E_AXIS);
             e_steps += (rev? 1: -1);
-            WRITE_NC(E0_STEP_PIN, INVERT_E_STEP_PIN);
+            STEP_NC_LO(E_AXIS);
 #if defined(FILAMENT_SENSOR) && defined(PAT9125)
             fsensor_counter += (rev? -1: 1);
 #endif
@@ -1385,14 +1429,14 @@ void babystep(const uint8_t axis,const bool direction)
     WRITE(X_DIR_PIN,(INVERT_X_DIR)^direction);
     
     //perform step 
-    WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN); 
+    STEP_NC_HI(X_AXIS);
 #ifdef DEBUG_XSTEP_DUP_PIN
-    WRITE(DEBUG_XSTEP_DUP_PIN,!INVERT_X_STEP_PIN);
+    STEP_NC_HI(X_DUP_AXIS);
 #endif //DEBUG_XSTEP_DUP_PIN
     delayMicroseconds(1);
-    WRITE(X_STEP_PIN, INVERT_X_STEP_PIN);
+    STEP_NC_LO(X_AXIS);
 #ifdef DEBUG_XSTEP_DUP_PIN
-    WRITE(DEBUG_XSTEP_DUP_PIN,INVERT_X_STEP_PIN);
+    STEP_NC_LO(X_DUP_AXIS);
 #endif //DEBUG_XSTEP_DUP_PIN
 
     //get old pin state back.
@@ -1408,14 +1452,14 @@ void babystep(const uint8_t axis,const bool direction)
     WRITE(Y_DIR_PIN,(INVERT_Y_DIR)^direction);
     
     //perform step 
-    WRITE(Y_STEP_PIN, !INVERT_Y_STEP_PIN); 
+    STEP_NC_HI(Y_AXIS);
 #ifdef DEBUG_YSTEP_DUP_PIN
-    WRITE(DEBUG_YSTEP_DUP_PIN,!INVERT_Y_STEP_PIN);
+    STEP_NC_HI(Y_DUP_AXIS);
 #endif //DEBUG_YSTEP_DUP_PIN
     delayMicroseconds(1);
-    WRITE(Y_STEP_PIN, INVERT_Y_STEP_PIN);
+    STEP_NC_LO(Y_AXIS);
 #ifdef DEBUG_YSTEP_DUP_PIN
-    WRITE(DEBUG_YSTEP_DUP_PIN,INVERT_Y_STEP_PIN);
+    STEP_NC_LO(Y_DUP_AXIS);
 #endif //DEBUG_YSTEP_DUP_PIN
 
     //get old pin state back.
@@ -1434,14 +1478,14 @@ void babystep(const uint8_t axis,const bool direction)
       WRITE(Z2_DIR_PIN,(INVERT_Z_DIR)^direction^BABYSTEP_INVERT_Z);
     #endif
     //perform step 
-    WRITE(Z_STEP_PIN, !INVERT_Z_STEP_PIN); 
+    STEP_NC_HI(Z_AXIS);
     #ifdef Z_DUAL_STEPPER_DRIVERS
-      WRITE(Z2_STEP_PIN, !INVERT_Z_STEP_PIN);
+      STEP_NC_HI(Z2_AXIS);
     #endif
     delayMicroseconds(1);
-    WRITE(Z_STEP_PIN, INVERT_Z_STEP_PIN);
+    STEP_NC_LO(Z_AXIS);
     #ifdef Z_DUAL_STEPPER_DRIVERS
-      WRITE(Z2_STEP_PIN, INVERT_Z_STEP_PIN);
+      STEP_NC_LO(Z2_AXIS);
     #endif
 
     //get old pin state back.
diff --git a/Firmware/tmc2130.cpp b/Firmware/tmc2130.cpp
index b87272e2..20c23704 100755
--- a/Firmware/tmc2130.cpp
+++ b/Firmware/tmc2130.cpp
@@ -428,6 +428,11 @@ 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 = (mres != 0); // intpol to 256 only if microsteps aren't 256
+#ifdef TMC2130_DEDGE_STEPPING
+	uint8_t dedge = 1;
+#else
+	uint8_t dedge = 0;
+#endif
 	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
@@ -464,12 +469,12 @@ void tmc2130_setup_chopper(uint8_t axis, uint8_t mres, uint8_t current_h, uint8_
 //	DBG(_n(" toff=%hhd, hstr=%hhd, hend=%hhd, tbl=%hhd\n"), toff, hstrt, hend, tbl);
 	if (current_r <= 31)
 	{
-		tmc2130_wr_CHOPCONF(axis, toff, hstrt, hend, fd3, 0, rndtf, chm, tbl, 1, 0, 0, 0, mres, intpol, 0, 0);
+		tmc2130_wr_CHOPCONF(axis, toff, hstrt, hend, fd3, 0, rndtf, chm, tbl, 1, 0, 0, 0, mres, intpol, dedge, 0);
 		tmc2130_wr(axis, TMC2130_REG_IHOLD_IRUN, 0x000f0000 | ((current_r & 0x1f) << 8) | (current_h & 0x1f));
 	}
 	else
 	{
-		tmc2130_wr_CHOPCONF(axis, toff, hstrt, hend, fd3, 0, rndtf, chm, tbl, 0, 0, 0, 0, mres, intpol, 0, 0);
+		tmc2130_wr_CHOPCONF(axis, toff, hstrt, hend, fd3, 0, rndtf, chm, tbl, 0, 0, 0, 0, mres, intpol, dedge, 0);
 		tmc2130_wr(axis, TMC2130_REG_IHOLD_IRUN, 0x000f0000 | (((current_r >> 1) & 0x1f) << 8) | ((current_h >> 1) & 0x1f));
 	}
 }
@@ -706,10 +711,17 @@ static uint8_t tmc2130_rx(uint8_t axis, uint8_t addr, uint32_t* rval)
 #define _SET_DIR_Z(dir) { WRITE(Z_DIR_PIN, dir?INVERT_Z_DIR:!INVERT_Z_DIR); asm("nop"); }
 #define _SET_DIR_E(dir) { WRITE(E0_DIR_PIN, dir?INVERT_E0_DIR:!INVERT_E0_DIR); asm("nop"); }
 
+#ifdef TMC2130_DEDGE_STEPPING
+#define _DO_STEP_X      { TOGGLE(X_STEP_PIN); asm("nop"); }
+#define _DO_STEP_Y      { TOGGLE(Y_STEP_PIN); asm("nop"); }
+#define _DO_STEP_Z      { TOGGLE(Z_STEP_PIN); asm("nop"); }
+#define _DO_STEP_E      { TOGGLE(E0_STEP_PIN); asm("nop"); }
+#else
 #define _DO_STEP_X      { WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN); asm("nop"); WRITE(X_STEP_PIN, INVERT_X_STEP_PIN); asm("nop"); }
 #define _DO_STEP_Y      { WRITE(Y_STEP_PIN, !INVERT_Y_STEP_PIN); asm("nop"); WRITE(Y_STEP_PIN, INVERT_Y_STEP_PIN); asm("nop"); }
 #define _DO_STEP_Z      { WRITE(Z_STEP_PIN, !INVERT_Z_STEP_PIN); asm("nop"); WRITE(Z_STEP_PIN, INVERT_Z_STEP_PIN); asm("nop"); }
 #define _DO_STEP_E      { WRITE(E0_STEP_PIN, !INVERT_E_STEP_PIN); asm("nop"); WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN); asm("nop"); }
+#endif
 
 
 uint16_t tmc2130_get_res(uint8_t axis)

From 1181beffb1c47828a1d40303348b53f2c06345e7 Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Mon, 17 Jun 2019 21:10:18 +0200
Subject: [PATCH 04/58] Enable DEDGE stepping on supported variants

---
 Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h  | 1 +
 Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h b/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h
index b135d8d1..e1eb2ef1 100644
--- a/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h
+++ b/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h
@@ -269,6 +269,7 @@
 // #define TMC2130_UNLOAD_CURRENT_R 12			 // lower current for M600 to protect filament sensor - Unused
 
 #define TMC2130_STEALTH_Z
+#define TMC2130_DEDGE_STEPPING
 
 //#define TMC2130_SERVICE_CODES_M910_M918
 
diff --git a/Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h b/Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h
index e618c54e..d4c52281 100644
--- a/Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h
+++ b/Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h
@@ -271,6 +271,7 @@
 // #define TMC2130_UNLOAD_CURRENT_R 12			 // lower current for M600 to protect filament sensor - Unused
 
 #define TMC2130_STEALTH_Z
+#define TMC2130_DEDGE_STEPPING
 
 //#define TMC2130_SERVICE_CODES_M910_M918
 

From e6b182aa9fc3a8f812a8580a0c25152418f3c2bc Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Tue, 18 Jun 2019 17:11:01 +0200
Subject: [PATCH 05/58] Implement proper step/delay pauses in tmc2130 functions

Add constants for the various required delays in tmc2130.h,
which will come in handy for stepper.cpp as well.

Move the delays in the _set functions and remove the pauses
from the various calling points and macros.

Note that the hard-coded pause wouldn't cut it for the stepper ISR,
but it's fine for other use cases.
---
 Firmware/tmc2130.cpp | 39 ++++++++++++++++++++-------------------
 Firmware/tmc2130.h   |  4 ++++
 2 files changed, 24 insertions(+), 19 deletions(-)

diff --git a/Firmware/tmc2130.cpp b/Firmware/tmc2130.cpp
index 20c23704..15646b92 100755
--- a/Firmware/tmc2130.cpp
+++ b/Firmware/tmc2130.cpp
@@ -696,31 +696,31 @@ static uint8_t tmc2130_rx(uint8_t axis, uint8_t addr, uint32_t* rval)
 #define _GET_PWR_Z      (READ(Z_ENABLE_PIN) == Z_ENABLE_ON)
 #define _GET_PWR_E      (READ(E0_ENABLE_PIN) == E_ENABLE_ON)
 
-#define _SET_PWR_X(ena) { WRITE(X_ENABLE_PIN, ena?X_ENABLE_ON:!X_ENABLE_ON); asm("nop"); }
-#define _SET_PWR_Y(ena) { WRITE(Y_ENABLE_PIN, ena?Y_ENABLE_ON:!Y_ENABLE_ON); asm("nop"); }
-#define _SET_PWR_Z(ena) { WRITE(Z_ENABLE_PIN, ena?Z_ENABLE_ON:!Z_ENABLE_ON); asm("nop"); }
-#define _SET_PWR_E(ena) { WRITE(E0_ENABLE_PIN, ena?E_ENABLE_ON:!E_ENABLE_ON); asm("nop"); }
+#define _SET_PWR_X(ena) WRITE(X_ENABLE_PIN, ena?X_ENABLE_ON:!X_ENABLE_ON)
+#define _SET_PWR_Y(ena) WRITE(Y_ENABLE_PIN, ena?Y_ENABLE_ON:!Y_ENABLE_ON)
+#define _SET_PWR_Z(ena) WRITE(Z_ENABLE_PIN, ena?Z_ENABLE_ON:!Z_ENABLE_ON)
+#define _SET_PWR_E(ena) WRITE(E0_ENABLE_PIN, ena?E_ENABLE_ON:!E_ENABLE_ON)
 
 #define _GET_DIR_X      (READ(X_DIR_PIN) == INVERT_X_DIR)
 #define _GET_DIR_Y      (READ(Y_DIR_PIN) == INVERT_Y_DIR)
 #define _GET_DIR_Z      (READ(Z_DIR_PIN) == INVERT_Z_DIR)
 #define _GET_DIR_E      (READ(E0_DIR_PIN) == INVERT_E0_DIR)
 
-#define _SET_DIR_X(dir) { WRITE(X_DIR_PIN, dir?INVERT_X_DIR:!INVERT_X_DIR); asm("nop"); }
-#define _SET_DIR_Y(dir) { WRITE(Y_DIR_PIN, dir?INVERT_Y_DIR:!INVERT_Y_DIR); asm("nop"); }
-#define _SET_DIR_Z(dir) { WRITE(Z_DIR_PIN, dir?INVERT_Z_DIR:!INVERT_Z_DIR); asm("nop"); }
-#define _SET_DIR_E(dir) { WRITE(E0_DIR_PIN, dir?INVERT_E0_DIR:!INVERT_E0_DIR); asm("nop"); }
+#define _SET_DIR_X(dir) WRITE(X_DIR_PIN, dir?INVERT_X_DIR:!INVERT_X_DIR)
+#define _SET_DIR_Y(dir) WRITE(Y_DIR_PIN, dir?INVERT_Y_DIR:!INVERT_Y_DIR)
+#define _SET_DIR_Z(dir) WRITE(Z_DIR_PIN, dir?INVERT_Z_DIR:!INVERT_Z_DIR)
+#define _SET_DIR_E(dir) WRITE(E0_DIR_PIN, dir?INVERT_E0_DIR:!INVERT_E0_DIR)
 
 #ifdef TMC2130_DEDGE_STEPPING
-#define _DO_STEP_X      { TOGGLE(X_STEP_PIN); asm("nop"); }
-#define _DO_STEP_Y      { TOGGLE(Y_STEP_PIN); asm("nop"); }
-#define _DO_STEP_Z      { TOGGLE(Z_STEP_PIN); asm("nop"); }
-#define _DO_STEP_E      { TOGGLE(E0_STEP_PIN); asm("nop"); }
+#define _DO_STEP_X      TOGGLE(X_STEP_PIN)
+#define _DO_STEP_Y      TOGGLE(Y_STEP_PIN)
+#define _DO_STEP_Z      TOGGLE(Z_STEP_PIN)
+#define _DO_STEP_E      TOGGLE(E0_STEP_PIN)
 #else
-#define _DO_STEP_X      { WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN); asm("nop"); WRITE(X_STEP_PIN, INVERT_X_STEP_PIN); asm("nop"); }
-#define _DO_STEP_Y      { WRITE(Y_STEP_PIN, !INVERT_Y_STEP_PIN); asm("nop"); WRITE(Y_STEP_PIN, INVERT_Y_STEP_PIN); asm("nop"); }
-#define _DO_STEP_Z      { WRITE(Z_STEP_PIN, !INVERT_Z_STEP_PIN); asm("nop"); WRITE(Z_STEP_PIN, INVERT_Z_STEP_PIN); asm("nop"); }
-#define _DO_STEP_E      { WRITE(E0_STEP_PIN, !INVERT_E_STEP_PIN); asm("nop"); WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN); asm("nop"); }
+#define _DO_STEP_X      { WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN); delayMicroseconds(TMC2130_MINIMUM_PULSE); WRITE(X_STEP_PIN, INVERT_X_STEP_PIN); }
+#define _DO_STEP_Y      { WRITE(Y_STEP_PIN, !INVERT_Y_STEP_PIN); delayMicroseconds(TMC2130_MINIMUM_PULSE); WRITE(Y_STEP_PIN, INVERT_Y_STEP_PIN); }
+#define _DO_STEP_Z      { WRITE(Z_STEP_PIN, !INVERT_Z_STEP_PIN); delayMicroseconds(TMC2130_MINIMUM_PULSE); WRITE(Z_STEP_PIN, INVERT_Z_STEP_PIN); }
+#define _DO_STEP_E      { WRITE(E0_STEP_PIN, !INVERT_E_STEP_PIN); delayMicroseconds(TMC2130_MINIMUM_PULSE); WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN); }
 #endif
 
 
@@ -762,6 +762,7 @@ void tmc2130_set_pwr(uint8_t axis, uint8_t pwr)
 	case Z_AXIS: _SET_PWR_Z(pwr); break;
 	case E_AXIS: _SET_PWR_E(pwr); break;
 	}
+    delayMicroseconds(TMC2130_SET_PWR_DELAY);
 }
 
 uint8_t tmc2130_get_inv(uint8_t axis)
@@ -798,6 +799,7 @@ void tmc2130_set_dir(uint8_t axis, uint8_t dir)
 	case Z_AXIS: _SET_DIR_Z(dir); break;
 	case E_AXIS: _SET_DIR_E(dir); break;
 	}
+    delayMicroseconds(TMC2130_SET_DIR_DELAY);
 }
 
 void tmc2130_do_step(uint8_t axis)
@@ -813,8 +815,8 @@ void tmc2130_do_step(uint8_t axis)
 
 void tmc2130_do_steps(uint8_t axis, uint16_t steps, uint8_t dir, uint16_t delay_us)
 {
-	tmc2130_set_dir(axis, dir);
-	delayMicroseconds(100);
+    if (tmc2130_get_dir(axis) != dir)
+        tmc2130_set_dir(axis, dir);
 	while (steps--)
 	{
 		tmc2130_do_step(axis);
@@ -845,7 +847,6 @@ void tmc2130_goto_step(uint8_t axis, uint8_t step, uint8_t dir, uint16_t delay_u
 		cnt = steps;
 	}
 	tmc2130_set_dir(axis, dir);
-	delayMicroseconds(100);
 	mscnt = tmc2130_rd_MSCNT(axis);
 	while ((cnt--) && ((mscnt >> shift) != step))
 	{
diff --git a/Firmware/tmc2130.h b/Firmware/tmc2130.h
index ed4c0d7c..4b5b764c 100644
--- a/Firmware/tmc2130.h
+++ b/Firmware/tmc2130.h
@@ -29,6 +29,10 @@ extern uint8_t tmc2130_sg_homing_axes_mask;
 #define TMC2130_WAVE_FAC1000_MAX 200
 #define TMC2130_WAVE_FAC1000_STP   1
 
+#define TMC2130_MINIMUM_PULSE 0   // minimum pulse width in uS
+#define TMC2130_SET_DIR_DELAY 20  // minimum delay after setting direction in uS
+#define TMC2130_SET_PWR_DELAY 0   // minimum delay after changing pwr mode in uS
+
 extern uint8_t tmc2130_home_enabled;
 extern uint8_t tmc2130_home_origin[2];
 extern uint8_t tmc2130_home_bsteps[2];

From 6ea198a866efcc6ecc55d2c7c29a4535ee9bee14 Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Sun, 14 Jul 2019 17:39:06 +0200
Subject: [PATCH 06/58] Fix DEDGE in sm4.c (fixes xyz calibration)

---
 Firmware/sm4.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Firmware/sm4.c b/Firmware/sm4.c
index 34cf8a3c..b68e0276 100644
--- a/Firmware/sm4.c
+++ b/Firmware/sm4.c
@@ -129,11 +129,15 @@ void sm4_set_dir_bits(uint8_t dir_bits)
 void sm4_do_step(uint8_t axes_mask)
 {
 #if ((MOTHERBOARD == BOARD_RAMBO_MINI_1_0) || (MOTHERBOARD == BOARD_RAMBO_MINI_1_3) || (MOTHERBOARD == BOARD_EINSY_1_0a))
+#ifdef TMC2130_DEDGE_STEPPING
+	PORTC ^= (axes_mask & 0x0f); //set step signals by mask
+#else
     register uint8_t portC = PORTC & 0xf0;
 	PORTC = portC | (axes_mask & 0x0f); //set step signals by mask
 	asm("nop");
 	PORTC = portC; //set step signals to zero
 	asm("nop");
+#endif
 #endif //((MOTHERBOARD == BOARD_RAMBO_MINI_1_0) || (MOTHERBOARD == BOARD_RAMBO_MINI_1_3) || (MOTHERBOARD == BOARD_EINSY_1_0a))
 }
 

From 78bbfc62379719a127cd5edcc48b3eb21aa2594f Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Sun, 14 Jul 2019 18:53:37 +0200
Subject: [PATCH 07/58] Fix delay calculations inside babystep()

- Avoid all delays when using DEDGE stepping
- Correctly account for direction change delays
---
 Firmware/stepper.cpp | 179 +++++++++++++++++++++++++------------------
 1 file changed, 105 insertions(+), 74 deletions(-)

diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp
index 8f2a4f12..b3cc5a57 100644
--- a/Firmware/stepper.cpp
+++ b/Firmware/stepper.cpp
@@ -72,6 +72,14 @@ uint16_t SP_min = 0x21FF;
 #define _STEP_PIN_Z2_AXIS Z2_STEP_PIN
 #endif
 
+#ifdef TMC2130
+#define STEPPER_MINIMUM_PULSE TMC2130_MINIMUM_PULSE
+#define STEPPER_SET_DIR_DELAY TMC2130_SET_DIR_DELAY
+#else
+#define STEPPER_MINIMUM_PULSE 2
+#define STEPPER_SET_DIR_DELAY 100
+#endif
+
 #ifdef TMC2130_DEDGE_STEPPING
 #define STEP_NC_HI(axis) TOGGLE(_STEP_PIN_##axis)
 #define STEP_NC_LO(axis) //NOP
@@ -1416,89 +1424,112 @@ void quickStop()
 #ifdef BABYSTEPPING
 void babystep(const uint8_t axis,const bool direction)
 {
-  //MUST ONLY BE CALLED BY A ISR, it depends on that no other ISR interrupts this
-    //store initial pin states
-  switch(axis)
-  {
-  case X_AXIS:
-  {
-    enable_x();   
-    uint8_t old_x_dir_pin= READ(X_DIR_PIN);  //if dualzstepper, both point to same direction.
-   
-    //setup new step
-    WRITE(X_DIR_PIN,(INVERT_X_DIR)^direction);
-    
-    //perform step 
-    STEP_NC_HI(X_AXIS);
+    // MUST ONLY BE CALLED BY A ISR as stepper pins are manipulated directly.
+    // note: when switching direction no delay is inserted at the end when the
+    //       original is restored. We assume enough time passes as the function
+    //       returns and the stepper is manipulated again (to avoid dead times)
+    switch(axis)
+    {
+    case X_AXIS:
+    {
+        enable_x();
+        uint8_t old_x_dir_pin = READ(X_DIR_PIN);  //if dualzstepper, both point to same direction.
+        uint8_t new_x_dir_pin = (INVERT_X_DIR)^direction;
+
+        //setup new step
+        if (new_x_dir_pin != old_x_dir_pin) {
+            WRITE_NC(X_DIR_PIN, new_x_dir_pin);
+            delayMicroseconds(STEPPER_SET_DIR_DELAY);
+        }
+
+        //perform step
+        STEP_NC_HI(X_AXIS);
 #ifdef DEBUG_XSTEP_DUP_PIN
-    STEP_NC_HI(X_DUP_AXIS);
-#endif //DEBUG_XSTEP_DUP_PIN
-    delayMicroseconds(1);
-    STEP_NC_LO(X_AXIS);
+        STEP_NC_HI(X_DUP_AXIS);
+#endif
+#ifndef TMC2130_DEDGE_STEPPING
+        delayMicroseconds(STEPPER_MINIMUM_PULSE);
+        STEP_NC_LO(X_AXIS);
 #ifdef DEBUG_XSTEP_DUP_PIN
-    STEP_NC_LO(X_DUP_AXIS);
-#endif //DEBUG_XSTEP_DUP_PIN
+        STEP_NC_LO(X_DUP_AXIS);
+#endif
+#endif
 
-    //get old pin state back.
-    WRITE(X_DIR_PIN,old_x_dir_pin);
-  }
-  break;
-  case Y_AXIS:
-  {
-    enable_y();   
-    uint8_t old_y_dir_pin= READ(Y_DIR_PIN);  //if dualzstepper, both point to same direction.
-   
-    //setup new step
-    WRITE(Y_DIR_PIN,(INVERT_Y_DIR)^direction);
-    
-    //perform step 
-    STEP_NC_HI(Y_AXIS);
+        //get old pin state back.
+        WRITE_NC(X_DIR_PIN, old_x_dir_pin);
+    }
+    break;
+
+    case Y_AXIS:
+    {
+        enable_y();
+        uint8_t old_y_dir_pin = READ(Y_DIR_PIN);  //if dualzstepper, both point to same direction.
+        uint8_t new_y_dir_pin = (INVERT_Y_DIR)^direction;
+
+        //setup new step
+        if (new_y_dir_pin != old_y_dir_pin) {
+            WRITE_NC(Y_DIR_PIN, new_y_dir_pin);
+            delayMicroseconds(STEPPER_SET_DIR_DELAY);
+        }
+
+        //perform step
+        STEP_NC_HI(Y_AXIS);
 #ifdef DEBUG_YSTEP_DUP_PIN
-    STEP_NC_HI(Y_DUP_AXIS);
-#endif //DEBUG_YSTEP_DUP_PIN
-    delayMicroseconds(1);
-    STEP_NC_LO(Y_AXIS);
+        STEP_NC_HI(Y_DUP_AXIS);
+#endif
+#ifndef TMC2130_DEDGE_STEPPING
+        delayMicroseconds(STEPPER_MINIMUM_PULSE);
+        STEP_NC_LO(Y_AXIS);
 #ifdef DEBUG_YSTEP_DUP_PIN
-    STEP_NC_LO(Y_DUP_AXIS);
-#endif //DEBUG_YSTEP_DUP_PIN
+        STEP_NC_LO(Y_DUP_AXIS);
+#endif
+#endif
 
-    //get old pin state back.
-    WRITE(Y_DIR_PIN,old_y_dir_pin);
+        //get old pin state back.
+        WRITE_NC(Y_DIR_PIN, old_y_dir_pin);
+    }
+    break;
 
-  }
-  break;
- 
-  case Z_AXIS:
-  {
-    enable_z();
-    uint8_t old_z_dir_pin= READ(Z_DIR_PIN);  //if dualzstepper, both point to same direction.
-    //setup new step
-    WRITE(Z_DIR_PIN,(INVERT_Z_DIR)^direction^BABYSTEP_INVERT_Z);
-    #ifdef Z_DUAL_STEPPER_DRIVERS
-      WRITE(Z2_DIR_PIN,(INVERT_Z_DIR)^direction^BABYSTEP_INVERT_Z);
-    #endif
-    //perform step 
-    STEP_NC_HI(Z_AXIS);
-    #ifdef Z_DUAL_STEPPER_DRIVERS
-      STEP_NC_HI(Z2_AXIS);
-    #endif
-    delayMicroseconds(1);
-    STEP_NC_LO(Z_AXIS);
-    #ifdef Z_DUAL_STEPPER_DRIVERS
-      STEP_NC_LO(Z2_AXIS);
-    #endif
+    case Z_AXIS:
+    {
+        enable_z();
+        uint8_t old_z_dir_pin = READ(Z_DIR_PIN);  //if dualzstepper, both point to same direction.
+        uint8_t new_z_dir_pin = (INVERT_Z_DIR)^direction^BABYSTEP_INVERT_Z;
 
-    //get old pin state back.
-    WRITE(Z_DIR_PIN,old_z_dir_pin);
-    #ifdef Z_DUAL_STEPPER_DRIVERS
-      WRITE(Z2_DIR_PIN,old_z_dir_pin);
-    #endif
+        //setup new step
+        if (new_z_dir_pin != old_z_dir_pin) {
+            WRITE_NC(Z_DIR_PIN, new_z_dir_pin);
+#ifdef Z_DUAL_STEPPER_DRIVERS
+            WRITE_NC(Z2_DIR_PIN, new_z_dir_pin);
+#endif
+            delayMicroseconds(STEPPER_SET_DIR_DELAY);
+        }
 
-  }
-  break;
- 
-  default:    break;
-  }
+        //perform step
+        STEP_NC_HI(Z_AXIS);
+#ifdef Z_DUAL_STEPPER_DRIVERS
+        STEP_NC_HI(Z2_AXIS);
+#endif
+#ifndef TMC2130_DEDGE_STEPPING
+        delayMicroseconds(STEPPER_MINIMUM_PULSE);
+        STEP_NC_LO(Z_AXIS);
+#ifdef Z_DUAL_STEPPER_DRIVERS
+        STEP_NC_LO(Z2_AXIS);
+#endif
+#endif
+
+        //get old pin state back.
+        if (new_z_dir_pin != old_z_dir_pin) {
+            WRITE_NC(Z_DIR_PIN, old_z_dir_pin);
+#ifdef Z_DUAL_STEPPER_DRIVERS
+            WRITE_NC(Z2_DIR_PIN, old_z_dir_pin);
+#endif
+        }
+    }
+    break;
+
+    default: break;
+    }
 }
 #endif //BABYSTEPPING
 

From 502bc8c72ddcb92828a4016546439674b2a74d5d Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Thu, 20 Aug 2020 12:33:52 +0200
Subject: [PATCH 08/58] Isolate more pat9125 code

Remove probing from Marlin_main and move it into pat9125_probe so that
it can support the various variants.
---
 Firmware/Marlin_main.cpp | 15 ++++-----------
 Firmware/config.h        |  4 +++-
 Firmware/pat9125.c       | 39 +++++++++++++++++++++++++++++----------
 Firmware/pat9125.h       |  1 +
 4 files changed, 37 insertions(+), 22 deletions(-)

diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp
index 2a261db2..e3be3dfb 100755
--- a/Firmware/Marlin_main.cpp
+++ b/Firmware/Marlin_main.cpp
@@ -88,18 +88,13 @@
 #include "la10compat.h"
 #endif
 
-#ifdef SWSPI
-#include "swspi.h"
-#endif //SWSPI
-
 #include "spi.h"
 
-#ifdef SWI2C
-#include "swi2c.h"
-#endif //SWI2C
-
 #ifdef FILAMENT_SENSOR
 #include "fsensor.h"
+#ifdef IR_SENSOR
+#include "pat9125.h" // for pat9125_probe
+#endif
 #endif //FILAMENT_SENSOR
 
 #ifdef TMC2130
@@ -864,9 +859,7 @@ static void check_if_fw_is_on_right_printer(){
 #ifdef FILAMENT_SENSOR
   if((PRINTER_TYPE == PRINTER_MK3) || (PRINTER_TYPE == PRINTER_MK3S)){
     #ifdef IR_SENSOR
-    swi2c_init();
-    const uint8_t pat9125_detected = swi2c_readByte_A8(PAT9125_I2C_ADDR,0x00,NULL);
-      if (pat9125_detected){
+      if (pat9125_probe()){
         lcd_show_fullscreen_message_and_wait_P(_i("MK3S firmware detected on MK3 printer"));}////c=20 r=3
     #endif //IR_SENSOR
 
diff --git a/Firmware/config.h b/Firmware/config.h
index 1a0a9700..b7705584 100644
--- a/Firmware/config.h
+++ b/Firmware/config.h
@@ -23,7 +23,6 @@
 #define ADC_CALLBACK      adc_ready //callback function ()
 
 //SWI2C configuration
-#define SWI2C
 //#define SWI2C_SDA         20 //SDA on P3
 //#define SWI2C_SCL         21 //SCL on P3
 #define SWI2C_A8
@@ -31,7 +30,10 @@
 #define SWI2C_TMO         2048 //2048 cycles timeout
 
 //PAT9125 configuration
+//#define PAT9125_SWSPI
 #define PAT9125_SWI2C
+//#define PAT9125_I2C
+
 #define PAT9125_I2C_ADDR  0x75  //ID=LO
 //#define PAT9125_I2C_ADDR  0x79  //ID=HI
 //#define PAT9125_I2C_ADDR  0x73  //ID=NC
diff --git a/Firmware/pat9125.c b/Firmware/pat9125.c
index de4693d2..10b06b3e 100644
--- a/Firmware/pat9125.c
+++ b/Firmware/pat9125.c
@@ -26,12 +26,15 @@
 #define PAT9125_BANK_SELECTION	0x7f
 
 
-#ifdef PAT9125_SWSPI
+#if defined(PAT9125_SWSPI)
 #include "swspi.h"
-#endif //PAT9125_SWSPI
-#ifdef PAT9125_SWI2C
+#elif defined(PAT9125_SWI2C)
 #include "swi2c.h"
-#endif //PAT9125_SWI2C
+#elif defined(PAT9125_I2C)
+#error not implemented
+#else
+#error unknown PAT9125 communication method
+#endif
 
 
 uint8_t pat9125_PID1 = 0;
@@ -103,14 +106,30 @@ extern FILE _uartout;
 #define uartout (&_uartout)
 
 
+uint8_t pat9125_probe()
+{
+#if defined(PAT9125_SWSPI)
+    swspi_init();
+    //#error not implemented
+#elif defined(PAT9125_SWI2C)
+    swi2c_init();
+    return swi2c_readByte_A8(PAT9125_I2C_ADDR,0x00,NULL);
+#elif defined(PAT9125_I2C)
+    twi_init();
+  #ifdef IR_SENSOR
+    // NOTE: this is called from the MK3S variant, so it should be kept minimal
+    #error not implemented
+  #else
+	return pat9125_rd_reg(PAT9125_PID1) != 0;
+  #endif
+#endif
+}
+
 uint8_t pat9125_init(void)
 {
-#ifdef PAT9125_SWSPI
-	swspi_init();
-#endif //PAT9125_SWSPI
-#ifdef PAT9125_SWI2C
-	swi2c_init();
-#endif //PAT9125_SWI2C
+    if (!pat9125_probe())
+        return 0;
+
 	// Verify that the sensor responds with its correct product ID.
 	pat9125_PID1 = pat9125_rd_reg(PAT9125_PID1);
 	pat9125_PID2 = pat9125_rd_reg(PAT9125_PID2);
diff --git a/Firmware/pat9125.h b/Firmware/pat9125.h
index 12f7fe94..1fb2539f 100755
--- a/Firmware/pat9125.h
+++ b/Firmware/pat9125.h
@@ -18,6 +18,7 @@ extern int16_t pat9125_y;
 extern uint8_t pat9125_b;
 extern uint8_t pat9125_s;
 
+extern uint8_t pat9125_probe(void);     // Return non-zero if PAT9125 can be trivially detected
 extern uint8_t pat9125_init(void);
 extern uint8_t pat9125_update(void);    // update all sensor data
 extern uint8_t pat9125_update_y(void);  // update _y only

From 240dc1132ee90fe3680e787dcde665306cc3bcf2 Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Thu, 20 Aug 2020 12:36:01 +0200
Subject: [PATCH 09/58] Include initial implementation based on Arduino's twi

---
 Firmware/config.h  |   4 +-
 Firmware/pat9125.c |  47 ++--
 Firmware/twi.c     | 561 +++++++++++++++++++++++++++++++++++++++++++++
 Firmware/twi.h     |  55 +++++
 4 files changed, 646 insertions(+), 21 deletions(-)
 create mode 100644 Firmware/twi.c
 create mode 100644 Firmware/twi.h

diff --git a/Firmware/config.h b/Firmware/config.h
index b7705584..b107d0ec 100644
--- a/Firmware/config.h
+++ b/Firmware/config.h
@@ -31,8 +31,8 @@
 
 //PAT9125 configuration
 //#define PAT9125_SWSPI
-#define PAT9125_SWI2C
-//#define PAT9125_I2C
+//#define PAT9125_SWI2C
+#define PAT9125_I2C
 
 #define PAT9125_I2C_ADDR  0x75  //ID=LO
 //#define PAT9125_I2C_ADDR  0x79  //ID=HI
diff --git a/Firmware/pat9125.c b/Firmware/pat9125.c
index 10b06b3e..bf2c0d95 100644
--- a/Firmware/pat9125.c
+++ b/Firmware/pat9125.c
@@ -31,7 +31,7 @@
 #elif defined(PAT9125_SWI2C)
 #include "swi2c.h"
 #elif defined(PAT9125_I2C)
-#error not implemented
+#include "twi.h"
 #else
 #error unknown PAT9125 communication method
 #endif
@@ -253,39 +253,48 @@ uint8_t pat9125_update_bs(void)
 uint8_t pat9125_rd_reg(uint8_t addr)
 {
 	uint8_t data = 0;
-#ifdef PAT9125_SWSPI
+#if defined(PAT9125_SWSPI)
 	swspi_start();
 	swspi_tx(addr & 0x7f);
 	data = swspi_rx();
 	swspi_stop();
-#endif //PAT9125_SWSPI
-#ifdef PAT9125_SWI2C
+#elif defined(PAT9125_SWI2C)
 	if (!swi2c_readByte_A8(PAT9125_I2C_ADDR, addr, &data)) //NO ACK error
-	{
-		pat9125_PID1 = 0xff;
-		pat9125_PID2 = 0xff;
-		return 0;
-	}
-#endif //PAT9125_SWI2C
+        goto error;
+#elif defined(PAT9125_I2C)
+	if (twi_writeTo(PAT9125_I2C_ADDR,&addr,1,1,0) != 0 ||
+        twi_readFrom(PAT9125_I2C_ADDR,&data,1,1) != 1)
+        goto error;
+#endif
 	return data;
+
+ error:
+    pat9125_PID1 = 0xff;
+    pat9125_PID2 = 0xff;
+    return 0;
 }
 
 void pat9125_wr_reg(uint8_t addr, uint8_t data)
 {
-#ifdef PAT9125_SWSPI
+#if defined(PAT9125_SWSPI)
 	swspi_start();
 	swspi_tx(addr | 0x80);
 	swspi_tx(data);
 	swspi_stop();
-#endif //PAT9125_SWSPI
-#ifdef PAT9125_SWI2C
+#elif defined(PAT9125_SWI2C)
 	if (!swi2c_writeByte_A8(PAT9125_I2C_ADDR, addr, &data)) //NO ACK error
-	{
-		pat9125_PID1 = 0xff;
-		pat9125_PID2 = 0xff;
-		return;
-	}
-#endif //PAT9125_SWI2C
+        goto error;
+#elif defined(PAT9125_I2C)
+	if (twi_writeTo(PAT9125_I2C_ADDR,&addr,1,1,0) != 0 ||
+        twi_writeTo(PAT9125_I2C_ADDR,&data,1,1,1) != 0)
+        goto error;
+#endif
+    return;
+
+ error:
+    pat9125_PID1 = 0xff;
+    pat9125_PID2 = 0xff;
+    return;
 }
 
 uint8_t pat9125_wr_reg_verify(uint8_t addr, uint8_t data)
diff --git a/Firmware/twi.c b/Firmware/twi.c
new file mode 100644
index 00000000..171af730
--- /dev/null
+++ b/Firmware/twi.c
@@ -0,0 +1,561 @@
+/*
+  twi.c - TWI/I2C library for Wiring & Arduino
+  Copyright (c) 2006 Nicholas Zambetti.  All right reserved.
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+  Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts
+*/
+
+#include <math.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <compat/twi.h>
+#include "Arduino.h" // for digitalWrite
+
+#ifndef cbi
+#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
+#endif
+
+#ifndef sbi
+#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
+#endif
+
+#include "pins_arduino.h"
+#include "twi.h"
+
+static volatile uint8_t twi_state;
+static volatile uint8_t twi_slarw;
+static volatile uint8_t twi_sendStop;			// should the transaction end with a stop
+static volatile uint8_t twi_inRepStart;			// in the middle of a repeated start
+
+static void (*twi_onSlaveTransmit)(void);
+static void (*twi_onSlaveReceive)(uint8_t*, int);
+
+static uint8_t twi_masterBuffer[TWI_BUFFER_LENGTH];
+static volatile uint8_t twi_masterBufferIndex;
+static volatile uint8_t twi_masterBufferLength;
+
+static uint8_t twi_txBuffer[TWI_BUFFER_LENGTH];
+static volatile uint8_t twi_txBufferIndex;
+static volatile uint8_t twi_txBufferLength;
+
+static uint8_t twi_rxBuffer[TWI_BUFFER_LENGTH];
+static volatile uint8_t twi_rxBufferIndex;
+
+static volatile uint8_t twi_error;
+
+/* 
+ * Function twi_init
+ * Desc     readys twi pins and sets twi bitrate
+ * Input    none
+ * Output   none
+ */
+void twi_init(void)
+{
+  // initialize state
+  twi_state = TWI_READY;
+  twi_sendStop = true;		// default value
+  twi_inRepStart = false;
+  
+  // activate internal pullups for twi.
+  digitalWrite(SDA, 1);
+  digitalWrite(SCL, 1);
+
+  // initialize twi prescaler and bit rate
+  cbi(TWSR, TWPS0);
+  cbi(TWSR, TWPS1);
+  TWBR = ((F_CPU / TWI_FREQ) - 16) / 2;
+
+  /* twi bit rate formula from atmega128 manual pg 204
+  SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR))
+  note: TWBR should be 10 or higher for master mode
+  It is 72 for a 16mhz Wiring board with 100kHz TWI */
+
+  // enable twi module, acks, and twi interrupt
+  TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
+}
+
+/* 
+ * Function twi_disable
+ * Desc     disables twi pins
+ * Input    none
+ * Output   none
+ */
+void twi_disable(void)
+{
+  // disable twi module, acks, and twi interrupt
+  TWCR &= ~(_BV(TWEN) | _BV(TWIE) | _BV(TWEA));
+
+  // deactivate internal pullups for twi.
+  digitalWrite(SDA, 0);
+  digitalWrite(SCL, 0);
+}
+
+/* 
+ * Function twi_slaveInit
+ * Desc     sets slave address and enables interrupt
+ * Input    none
+ * Output   none
+ */
+void twi_setAddress(uint8_t address)
+{
+  // set twi slave address (skip over TWGCE bit)
+  TWAR = address << 1;
+}
+
+/* 
+ * Function twi_setClock
+ * Desc     sets twi bit rate
+ * Input    Clock Frequency
+ * Output   none
+ */
+void twi_setFrequency(uint32_t frequency)
+{
+  TWBR = ((F_CPU / frequency) - 16) / 2;
+  
+  /* twi bit rate formula from atmega128 manual pg 204
+  SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR))
+  note: TWBR should be 10 or higher for master mode
+  It is 72 for a 16mhz Wiring board with 100kHz TWI */
+}
+
+/* 
+ * Function twi_readFrom
+ * Desc     attempts to become twi bus master and read a
+ *          series of bytes from a device on the bus
+ * Input    address: 7bit i2c device address
+ *          data: pointer to byte array
+ *          length: number of bytes to read into array
+ *          sendStop: Boolean indicating whether to send a stop at the end
+ * Output   number of bytes read
+ */
+uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop)
+{
+  uint8_t i;
+
+  // ensure data will fit into buffer
+  if(TWI_BUFFER_LENGTH < length){
+    return 0;
+  }
+
+  // wait until twi is ready, become master receiver
+  while(TWI_READY != twi_state){
+    continue;
+  }
+  twi_state = TWI_MRX;
+  twi_sendStop = sendStop;
+  // reset error state (0xFF.. no error occured)
+  twi_error = 0xFF;
+
+  // initialize buffer iteration vars
+  twi_masterBufferIndex = 0;
+  twi_masterBufferLength = length-1;  // This is not intuitive, read on...
+  // On receive, the previously configured ACK/NACK setting is transmitted in
+  // response to the received byte before the interrupt is signalled. 
+  // Therefor we must actually set NACK when the _next_ to last byte is
+  // received, causing that NACK to be sent in response to receiving the last
+  // expected byte of data.
+
+  // build sla+w, slave device address + w bit
+  twi_slarw = TW_READ;
+  twi_slarw |= address << 1;
+
+  if (true == twi_inRepStart) {
+    // if we're in the repeated start state, then we've already sent the start,
+    // (@@@ we hope), and the TWI statemachine is just waiting for the address byte.
+    // We need to remove ourselves from the repeated start state before we enable interrupts,
+    // since the ISR is ASYNC, and we could get confused if we hit the ISR before cleaning
+    // up. Also, don't enable the START interrupt. There may be one pending from the 
+    // repeated start that we sent ourselves, and that would really confuse things.
+    twi_inRepStart = false;			// remember, we're dealing with an ASYNC ISR
+    do {
+      TWDR = twi_slarw;
+    } while(TWCR & _BV(TWWC));
+    TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE);	// enable INTs, but not START
+  }
+  else
+    // send start condition
+    TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA);
+
+  // wait for read operation to complete
+  while(TWI_MRX == twi_state){
+    continue;
+  }
+
+  if (twi_masterBufferIndex < length)
+    length = twi_masterBufferIndex;
+
+  // copy twi buffer to data
+  for(i = 0; i < length; ++i){
+    data[i] = twi_masterBuffer[i];
+  }
+	
+  return length;
+}
+
+/* 
+ * Function twi_writeTo
+ * Desc     attempts to become twi bus master and write a
+ *          series of bytes to a device on the bus
+ * Input    address: 7bit i2c device address
+ *          data: pointer to byte array
+ *          length: number of bytes in array
+ *          wait: boolean indicating to wait for write or not
+ *          sendStop: boolean indicating whether or not to send a stop at the end
+ * Output   0 .. success
+ *          1 .. length to long for buffer
+ *          2 .. address send, NACK received
+ *          3 .. data send, NACK received
+ *          4 .. other twi error (lost bus arbitration, bus error, ..)
+ */
+uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait, uint8_t sendStop)
+{
+  uint8_t i;
+
+  // ensure data will fit into buffer
+  if(TWI_BUFFER_LENGTH < length){
+    return 1;
+  }
+
+  // wait until twi is ready, become master transmitter
+  while(TWI_READY != twi_state){
+    continue;
+  }
+  twi_state = TWI_MTX;
+  twi_sendStop = sendStop;
+  // reset error state (0xFF.. no error occured)
+  twi_error = 0xFF;
+
+  // initialize buffer iteration vars
+  twi_masterBufferIndex = 0;
+  twi_masterBufferLength = length;
+  
+  // copy data to twi buffer
+  for(i = 0; i < length; ++i){
+    twi_masterBuffer[i] = data[i];
+  }
+  
+  // build sla+w, slave device address + w bit
+  twi_slarw = TW_WRITE;
+  twi_slarw |= address << 1;
+  
+  // if we're in a repeated start, then we've already sent the START
+  // in the ISR. Don't do it again.
+  //
+  if (true == twi_inRepStart) {
+    // if we're in the repeated start state, then we've already sent the start,
+    // (@@@ we hope), and the TWI statemachine is just waiting for the address byte.
+    // We need to remove ourselves from the repeated start state before we enable interrupts,
+    // since the ISR is ASYNC, and we could get confused if we hit the ISR before cleaning
+    // up. Also, don't enable the START interrupt. There may be one pending from the 
+    // repeated start that we sent outselves, and that would really confuse things.
+    twi_inRepStart = false;			// remember, we're dealing with an ASYNC ISR
+    do {
+      TWDR = twi_slarw;				
+    } while(TWCR & _BV(TWWC));
+    TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE);	// enable INTs, but not START
+  }
+  else
+    // send start condition
+    TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE) | _BV(TWSTA);	// enable INTs
+
+  // wait for write operation to complete
+  while(wait && (TWI_MTX == twi_state)){
+    continue;
+  }
+  
+  if (twi_error == 0xFF)
+    return 0;	// success
+  else if (twi_error == TW_MT_SLA_NACK)
+    return 2;	// error: address send, nack received
+  else if (twi_error == TW_MT_DATA_NACK)
+    return 3;	// error: data send, nack received
+  else
+    return 4;	// other twi error
+}
+
+/* 
+ * Function twi_transmit
+ * Desc     fills slave tx buffer with data
+ *          must be called in slave tx event callback
+ * Input    data: pointer to byte array
+ *          length: number of bytes in array
+ * Output   1 length too long for buffer
+ *          2 not slave transmitter
+ *          0 ok
+ */
+uint8_t twi_transmit(const uint8_t* data, uint8_t length)
+{
+  uint8_t i;
+
+  // ensure data will fit into buffer
+  if(TWI_BUFFER_LENGTH < (twi_txBufferLength+length)){
+    return 1;
+  }
+  
+  // ensure we are currently a slave transmitter
+  if(TWI_STX != twi_state){
+    return 2;
+  }
+  
+  // set length and copy data into tx buffer
+  for(i = 0; i < length; ++i){
+    twi_txBuffer[twi_txBufferLength+i] = data[i];
+  }
+  twi_txBufferLength += length;
+  
+  return 0;
+}
+
+/* 
+ * Function twi_attachSlaveRxEvent
+ * Desc     sets function called before a slave read operation
+ * Input    function: callback function to use
+ * Output   none
+ */
+void twi_attachSlaveRxEvent( void (*function)(uint8_t*, int) )
+{
+  twi_onSlaveReceive = function;
+}
+
+/* 
+ * Function twi_attachSlaveTxEvent
+ * Desc     sets function called before a slave write operation
+ * Input    function: callback function to use
+ * Output   none
+ */
+void twi_attachSlaveTxEvent( void (*function)(void) )
+{
+  twi_onSlaveTransmit = function;
+}
+
+/* 
+ * Function twi_reply
+ * Desc     sends byte or readys receive line
+ * Input    ack: byte indicating to ack or to nack
+ * Output   none
+ */
+void twi_reply(uint8_t ack)
+{
+  // transmit master read ready signal, with or without ack
+  if(ack){
+    TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA);
+  }else{
+	  TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT);
+  }
+}
+
+/* 
+ * Function twi_stop
+ * Desc     relinquishes bus master status
+ * Input    none
+ * Output   none
+ */
+void twi_stop(void)
+{
+  // send stop condition
+  TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTO);
+
+  // wait for stop condition to be exectued on bus
+  // TWINT is not set after a stop condition!
+  while(TWCR & _BV(TWSTO)){
+    continue;
+  }
+
+  // update twi state
+  twi_state = TWI_READY;
+}
+
+/* 
+ * Function twi_releaseBus
+ * Desc     releases bus control
+ * Input    none
+ * Output   none
+ */
+void twi_releaseBus(void)
+{
+  // release bus
+  TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT);
+
+  // update twi state
+  twi_state = TWI_READY;
+}
+
+ISR(TWI_vect)
+{
+  switch(TW_STATUS){
+    // All Master
+    case TW_START:     // sent start condition
+    case TW_REP_START: // sent repeated start condition
+      // copy device address and r/w bit to output register and ack
+      TWDR = twi_slarw;
+      twi_reply(1);
+      break;
+
+    // Master Transmitter
+    case TW_MT_SLA_ACK:  // slave receiver acked address
+    case TW_MT_DATA_ACK: // slave receiver acked data
+      // if there is data to send, send it, otherwise stop 
+      if(twi_masterBufferIndex < twi_masterBufferLength){
+        // copy data to output register and ack
+        TWDR = twi_masterBuffer[twi_masterBufferIndex++];
+        twi_reply(1);
+      }else{
+	if (twi_sendStop)
+          twi_stop();
+	else {
+	  twi_inRepStart = true;	// we're gonna send the START
+	  // don't enable the interrupt. We'll generate the start, but we 
+	  // avoid handling the interrupt until we're in the next transaction,
+	  // at the point where we would normally issue the start.
+	  TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ;
+	  twi_state = TWI_READY;
+	}
+      }
+      break;
+    case TW_MT_SLA_NACK:  // address sent, nack received
+      twi_error = TW_MT_SLA_NACK;
+      twi_stop();
+      break;
+    case TW_MT_DATA_NACK: // data sent, nack received
+      twi_error = TW_MT_DATA_NACK;
+      twi_stop();
+      break;
+    case TW_MT_ARB_LOST: // lost bus arbitration
+      twi_error = TW_MT_ARB_LOST;
+      twi_releaseBus();
+      break;
+
+    // Master Receiver
+    case TW_MR_DATA_ACK: // data received, ack sent
+      // put byte into buffer
+      twi_masterBuffer[twi_masterBufferIndex++] = TWDR;
+    case TW_MR_SLA_ACK:  // address sent, ack received
+      // ack if more bytes are expected, otherwise nack
+      if(twi_masterBufferIndex < twi_masterBufferLength){
+        twi_reply(1);
+      }else{
+        twi_reply(0);
+      }
+      break;
+    case TW_MR_DATA_NACK: // data received, nack sent
+      // put final byte into buffer
+      twi_masterBuffer[twi_masterBufferIndex++] = TWDR;
+	if (twi_sendStop)
+          twi_stop();
+	else {
+	  twi_inRepStart = true;	// we're gonna send the START
+	  // don't enable the interrupt. We'll generate the start, but we 
+	  // avoid handling the interrupt until we're in the next transaction,
+	  // at the point where we would normally issue the start.
+	  TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ;
+	  twi_state = TWI_READY;
+	}    
+	break;
+    case TW_MR_SLA_NACK: // address sent, nack received
+      twi_stop();
+      break;
+    // TW_MR_ARB_LOST handled by TW_MT_ARB_LOST case
+
+    // Slave Receiver
+    case TW_SR_SLA_ACK:   // addressed, returned ack
+    case TW_SR_GCALL_ACK: // addressed generally, returned ack
+    case TW_SR_ARB_LOST_SLA_ACK:   // lost arbitration, returned ack
+    case TW_SR_ARB_LOST_GCALL_ACK: // lost arbitration, returned ack
+      // enter slave receiver mode
+      twi_state = TWI_SRX;
+      // indicate that rx buffer can be overwritten and ack
+      twi_rxBufferIndex = 0;
+      twi_reply(1);
+      break;
+    case TW_SR_DATA_ACK:       // data received, returned ack
+    case TW_SR_GCALL_DATA_ACK: // data received generally, returned ack
+      // if there is still room in the rx buffer
+      if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){
+        // put byte in buffer and ack
+        twi_rxBuffer[twi_rxBufferIndex++] = TWDR;
+        twi_reply(1);
+      }else{
+        // otherwise nack
+        twi_reply(0);
+      }
+      break;
+    case TW_SR_STOP: // stop or repeated start condition received
+      // ack future responses and leave slave receiver state
+      twi_releaseBus();
+      // put a null char after data if there's room
+      if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){
+        twi_rxBuffer[twi_rxBufferIndex] = '\0';
+      }
+      // callback to user defined callback
+      twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex);
+      // since we submit rx buffer to "wire" library, we can reset it
+      twi_rxBufferIndex = 0;
+      break;
+    case TW_SR_DATA_NACK:       // data received, returned nack
+    case TW_SR_GCALL_DATA_NACK: // data received generally, returned nack
+      // nack back at master
+      twi_reply(0);
+      break;
+    
+    // Slave Transmitter
+    case TW_ST_SLA_ACK:          // addressed, returned ack
+    case TW_ST_ARB_LOST_SLA_ACK: // arbitration lost, returned ack
+      // enter slave transmitter mode
+      twi_state = TWI_STX;
+      // ready the tx buffer index for iteration
+      twi_txBufferIndex = 0;
+      // set tx buffer length to be zero, to verify if user changes it
+      twi_txBufferLength = 0;
+      // request for txBuffer to be filled and length to be set
+      // note: user must call twi_transmit(bytes, length) to do this
+      twi_onSlaveTransmit();
+      // if they didn't change buffer & length, initialize it
+      if(0 == twi_txBufferLength){
+        twi_txBufferLength = 1;
+        twi_txBuffer[0] = 0x00;
+      }
+      // transmit first byte from buffer, fall
+    case TW_ST_DATA_ACK: // byte sent, ack returned
+      // copy data to output register
+      TWDR = twi_txBuffer[twi_txBufferIndex++];
+      // if there is more to send, ack, otherwise nack
+      if(twi_txBufferIndex < twi_txBufferLength){
+        twi_reply(1);
+      }else{
+        twi_reply(0);
+      }
+      break;
+    case TW_ST_DATA_NACK: // received nack, we are done 
+    case TW_ST_LAST_DATA: // received ack, but we are done already!
+      // ack future responses
+      twi_reply(1);
+      // leave slave receiver state
+      twi_state = TWI_READY;
+      break;
+
+    // All
+    case TW_NO_INFO:   // no state information
+      break;
+    case TW_BUS_ERROR: // bus error, illegal stop/start
+      twi_error = TW_BUS_ERROR;
+      twi_stop();
+      break;
+  }
+}
+
diff --git a/Firmware/twi.h b/Firmware/twi.h
new file mode 100644
index 00000000..cb48708c
--- /dev/null
+++ b/Firmware/twi.h
@@ -0,0 +1,55 @@
+/*
+  twi.h - TWI/I2C library for Wiring & Arduino
+  Copyright (c) 2006 Nicholas Zambetti.  All right reserved.
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#ifndef twi_h
+#define twi_h
+
+  #include <inttypes.h>
+
+  //#define ATMEGA8
+
+  #ifndef TWI_FREQ
+  #define TWI_FREQ 400000L
+  #endif
+
+  #ifndef TWI_BUFFER_LENGTH
+  #define TWI_BUFFER_LENGTH 32
+  #endif
+
+  #define TWI_READY 0
+  #define TWI_MRX   1
+  #define TWI_MTX   2
+  #define TWI_SRX   3
+  #define TWI_STX   4
+  
+  void twi_init(void);
+  void twi_disable(void);
+  void twi_setAddress(uint8_t);
+  void twi_setFrequency(uint32_t);
+  uint8_t twi_readFrom(uint8_t, uint8_t*, uint8_t, uint8_t);
+  uint8_t twi_writeTo(uint8_t, uint8_t*, uint8_t, uint8_t, uint8_t);
+  uint8_t twi_transmit(const uint8_t*, uint8_t);
+  void twi_attachSlaveRxEvent( void (*)(uint8_t*, int) );
+  void twi_attachSlaveTxEvent( void (*)(void) );
+  void twi_reply(uint8_t);
+  void twi_stop(void);
+  void twi_releaseBus(void);
+
+#endif
+

From 7f425120f09dc33b7bd1b75af4d42cdad5ad1441 Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Thu, 20 Aug 2020 15:29:57 +0200
Subject: [PATCH 10/58] Strip down the TWI code

- Only implement a single syncronous read/write function to read a byte,
  since that's all we need currently
- Implement a compact IR_SENSOR probe for PAT9125
- Saves 242 bytes compared to PAT9125_SWI2C
---
 Firmware/pat9125.c |  13 +-
 Firmware/twi.c     | 518 +++------------------------------------------
 Firmware/twi.h     |  64 +++---
 3 files changed, 63 insertions(+), 532 deletions(-)

diff --git a/Firmware/pat9125.c b/Firmware/pat9125.c
index bf2c0d95..ab6342aa 100644
--- a/Firmware/pat9125.c
+++ b/Firmware/pat9125.c
@@ -118,9 +118,10 @@ uint8_t pat9125_probe()
     twi_init();
   #ifdef IR_SENSOR
     // NOTE: this is called from the MK3S variant, so it should be kept minimal
-    #error not implemented
+    uint8_t addr = PAT9125_PID1;
+    return (twi_rw8(PAT9125_I2C_ADDR,TW_READ,&addr) == 0);
   #else
-	return pat9125_rd_reg(PAT9125_PID1) != 0;
+    return (pat9125_rd_reg(PAT9125_PID1) != 0);
   #endif
 #endif
 }
@@ -262,8 +263,8 @@ uint8_t pat9125_rd_reg(uint8_t addr)
 	if (!swi2c_readByte_A8(PAT9125_I2C_ADDR, addr, &data)) //NO ACK error
         goto error;
 #elif defined(PAT9125_I2C)
-	if (twi_writeTo(PAT9125_I2C_ADDR,&addr,1,1,0) != 0 ||
-        twi_readFrom(PAT9125_I2C_ADDR,&data,1,1) != 1)
+	if (twi_rw8(PAT9125_I2C_ADDR,TW_WRITE,&addr) ||
+        twi_rw8(PAT9125_I2C_ADDR,TW_READ,&data))
         goto error;
 #endif
 	return data;
@@ -285,8 +286,8 @@ void pat9125_wr_reg(uint8_t addr, uint8_t data)
 	if (!swi2c_writeByte_A8(PAT9125_I2C_ADDR, addr, &data)) //NO ACK error
         goto error;
 #elif defined(PAT9125_I2C)
-	if (twi_writeTo(PAT9125_I2C_ADDR,&addr,1,1,0) != 0 ||
-        twi_writeTo(PAT9125_I2C_ADDR,&data,1,1,1) != 0)
+	if (twi_rw8(PAT9125_I2C_ADDR,TW_WRITE,&addr) ||
+        twi_rw8(PAT9125_I2C_ADDR,TW_READ,&data))
         goto error;
 #endif
     return;
diff --git a/Firmware/twi.c b/Firmware/twi.c
index 171af730..161db52a 100644
--- a/Firmware/twi.c
+++ b/Firmware/twi.c
@@ -1,5 +1,5 @@
 /*
-  twi.c - TWI/I2C library for Wiring & Arduino
+  twi.c - Stripped-down TWI/I2C library
   Copyright (c) 2006 Nicholas Zambetti.  All right reserved.
 
   This library is free software; you can redistribute it and/or
@@ -20,11 +20,6 @@
 */
 
 #include <math.h>
-#include <stdlib.h>
-#include <inttypes.h>
-#include <avr/io.h>
-#include <avr/interrupt.h>
-#include <compat/twi.h>
 #include "Arduino.h" // for digitalWrite
 
 #ifndef cbi
@@ -35,43 +30,11 @@
 #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
 #endif
 
-#include "pins_arduino.h"
 #include "twi.h"
 
-static volatile uint8_t twi_state;
-static volatile uint8_t twi_slarw;
-static volatile uint8_t twi_sendStop;			// should the transaction end with a stop
-static volatile uint8_t twi_inRepStart;			// in the middle of a repeated start
 
-static void (*twi_onSlaveTransmit)(void);
-static void (*twi_onSlaveReceive)(uint8_t*, int);
-
-static uint8_t twi_masterBuffer[TWI_BUFFER_LENGTH];
-static volatile uint8_t twi_masterBufferIndex;
-static volatile uint8_t twi_masterBufferLength;
-
-static uint8_t twi_txBuffer[TWI_BUFFER_LENGTH];
-static volatile uint8_t twi_txBufferIndex;
-static volatile uint8_t twi_txBufferLength;
-
-static uint8_t twi_rxBuffer[TWI_BUFFER_LENGTH];
-static volatile uint8_t twi_rxBufferIndex;
-
-static volatile uint8_t twi_error;
-
-/* 
- * Function twi_init
- * Desc     readys twi pins and sets twi bitrate
- * Input    none
- * Output   none
- */
 void twi_init(void)
 {
-  // initialize state
-  twi_state = TWI_READY;
-  twi_sendStop = true;		// default value
-  twi_inRepStart = false;
-  
   // activate internal pullups for twi.
   digitalWrite(SDA, 1);
   digitalWrite(SCL, 1);
@@ -85,477 +48,46 @@ void twi_init(void)
   SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR))
   note: TWBR should be 10 or higher for master mode
   It is 72 for a 16mhz Wiring board with 100kHz TWI */
-
-  // enable twi module, acks, and twi interrupt
-  TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
 }
 
-/* 
- * Function twi_disable
- * Desc     disables twi pins
- * Input    none
- * Output   none
- */
 void twi_disable(void)
 {
-  // disable twi module, acks, and twi interrupt
-  TWCR &= ~(_BV(TWEN) | _BV(TWIE) | _BV(TWEA));
-
   // deactivate internal pullups for twi.
   digitalWrite(SDA, 0);
   digitalWrite(SCL, 0);
 }
 
-/* 
- * Function twi_slaveInit
- * Desc     sets slave address and enables interrupt
- * Input    none
- * Output   none
- */
-void twi_setAddress(uint8_t address)
+uint8_t twi_waitfor(uint8_t status)
 {
-  // set twi slave address (skip over TWGCE bit)
-  TWAR = address << 1;
+    while(!(TWCR & _BV(TWINT)));
+    return (TW_STATUS != status);
 }
 
-/* 
- * Function twi_setClock
- * Desc     sets twi bit rate
- * Input    Clock Frequency
- * Output   none
- */
-void twi_setFrequency(uint32_t frequency)
+uint8_t twi_rw8(uint8_t address, uint8_t mode, uint8_t* data)
 {
-  TWBR = ((F_CPU / frequency) - 16) / 2;
-  
-  /* twi bit rate formula from atmega128 manual pg 204
-  SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR))
-  note: TWBR should be 10 or higher for master mode
-  It is 72 for a 16mhz Wiring board with 100kHz TWI */
-}
+  // send start condition
+  TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWSTA);
+  if(twi_waitfor(TW_START))
+      return 1;
 
-/* 
- * Function twi_readFrom
- * Desc     attempts to become twi bus master and read a
- *          series of bytes from a device on the bus
- * Input    address: 7bit i2c device address
- *          data: pointer to byte array
- *          length: number of bytes to read into array
- *          sendStop: Boolean indicating whether to send a stop at the end
- * Output   number of bytes read
- */
-uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop)
-{
-  uint8_t i;
+  // send address
+  TWDR = mode;
+  TWDR |= (address << 1);
+  TWCR = _BV(TWEN) | _BV(TWINT);
+  if(twi_waitfor(mode == TW_READ? TW_MR_SLA_ACK: TW_MT_SLA_ACK))
+      return 2;
 
-  // ensure data will fit into buffer
-  if(TWI_BUFFER_LENGTH < length){
-    return 0;
-  }
+  // send or receive data
+  if(mode == TW_WRITE)
+      TWDR = *data;
+  TWCR = _BV(TWEN) | _BV(TWINT);
+  if(twi_waitfor(mode == TW_READ? TW_MR_DATA_NACK: TW_MT_DATA_ACK))
+      return 3;
+  if(mode == TW_READ)
+      *data = TWDR;
 
-  // wait until twi is ready, become master receiver
-  while(TWI_READY != twi_state){
-    continue;
-  }
-  twi_state = TWI_MRX;
-  twi_sendStop = sendStop;
-  // reset error state (0xFF.. no error occured)
-  twi_error = 0xFF;
+  // send stop
+  TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWSTO);
 
-  // initialize buffer iteration vars
-  twi_masterBufferIndex = 0;
-  twi_masterBufferLength = length-1;  // This is not intuitive, read on...
-  // On receive, the previously configured ACK/NACK setting is transmitted in
-  // response to the received byte before the interrupt is signalled. 
-  // Therefor we must actually set NACK when the _next_ to last byte is
-  // received, causing that NACK to be sent in response to receiving the last
-  // expected byte of data.
-
-  // build sla+w, slave device address + w bit
-  twi_slarw = TW_READ;
-  twi_slarw |= address << 1;
-
-  if (true == twi_inRepStart) {
-    // if we're in the repeated start state, then we've already sent the start,
-    // (@@@ we hope), and the TWI statemachine is just waiting for the address byte.
-    // We need to remove ourselves from the repeated start state before we enable interrupts,
-    // since the ISR is ASYNC, and we could get confused if we hit the ISR before cleaning
-    // up. Also, don't enable the START interrupt. There may be one pending from the 
-    // repeated start that we sent ourselves, and that would really confuse things.
-    twi_inRepStart = false;			// remember, we're dealing with an ASYNC ISR
-    do {
-      TWDR = twi_slarw;
-    } while(TWCR & _BV(TWWC));
-    TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE);	// enable INTs, but not START
-  }
-  else
-    // send start condition
-    TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA);
-
-  // wait for read operation to complete
-  while(TWI_MRX == twi_state){
-    continue;
-  }
-
-  if (twi_masterBufferIndex < length)
-    length = twi_masterBufferIndex;
-
-  // copy twi buffer to data
-  for(i = 0; i < length; ++i){
-    data[i] = twi_masterBuffer[i];
-  }
-	
-  return length;
-}
-
-/* 
- * Function twi_writeTo
- * Desc     attempts to become twi bus master and write a
- *          series of bytes to a device on the bus
- * Input    address: 7bit i2c device address
- *          data: pointer to byte array
- *          length: number of bytes in array
- *          wait: boolean indicating to wait for write or not
- *          sendStop: boolean indicating whether or not to send a stop at the end
- * Output   0 .. success
- *          1 .. length to long for buffer
- *          2 .. address send, NACK received
- *          3 .. data send, NACK received
- *          4 .. other twi error (lost bus arbitration, bus error, ..)
- */
-uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait, uint8_t sendStop)
-{
-  uint8_t i;
-
-  // ensure data will fit into buffer
-  if(TWI_BUFFER_LENGTH < length){
-    return 1;
-  }
-
-  // wait until twi is ready, become master transmitter
-  while(TWI_READY != twi_state){
-    continue;
-  }
-  twi_state = TWI_MTX;
-  twi_sendStop = sendStop;
-  // reset error state (0xFF.. no error occured)
-  twi_error = 0xFF;
-
-  // initialize buffer iteration vars
-  twi_masterBufferIndex = 0;
-  twi_masterBufferLength = length;
-  
-  // copy data to twi buffer
-  for(i = 0; i < length; ++i){
-    twi_masterBuffer[i] = data[i];
-  }
-  
-  // build sla+w, slave device address + w bit
-  twi_slarw = TW_WRITE;
-  twi_slarw |= address << 1;
-  
-  // if we're in a repeated start, then we've already sent the START
-  // in the ISR. Don't do it again.
-  //
-  if (true == twi_inRepStart) {
-    // if we're in the repeated start state, then we've already sent the start,
-    // (@@@ we hope), and the TWI statemachine is just waiting for the address byte.
-    // We need to remove ourselves from the repeated start state before we enable interrupts,
-    // since the ISR is ASYNC, and we could get confused if we hit the ISR before cleaning
-    // up. Also, don't enable the START interrupt. There may be one pending from the 
-    // repeated start that we sent outselves, and that would really confuse things.
-    twi_inRepStart = false;			// remember, we're dealing with an ASYNC ISR
-    do {
-      TWDR = twi_slarw;				
-    } while(TWCR & _BV(TWWC));
-    TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE);	// enable INTs, but not START
-  }
-  else
-    // send start condition
-    TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE) | _BV(TWSTA);	// enable INTs
-
-  // wait for write operation to complete
-  while(wait && (TWI_MTX == twi_state)){
-    continue;
-  }
-  
-  if (twi_error == 0xFF)
-    return 0;	// success
-  else if (twi_error == TW_MT_SLA_NACK)
-    return 2;	// error: address send, nack received
-  else if (twi_error == TW_MT_DATA_NACK)
-    return 3;	// error: data send, nack received
-  else
-    return 4;	// other twi error
-}
-
-/* 
- * Function twi_transmit
- * Desc     fills slave tx buffer with data
- *          must be called in slave tx event callback
- * Input    data: pointer to byte array
- *          length: number of bytes in array
- * Output   1 length too long for buffer
- *          2 not slave transmitter
- *          0 ok
- */
-uint8_t twi_transmit(const uint8_t* data, uint8_t length)
-{
-  uint8_t i;
-
-  // ensure data will fit into buffer
-  if(TWI_BUFFER_LENGTH < (twi_txBufferLength+length)){
-    return 1;
-  }
-  
-  // ensure we are currently a slave transmitter
-  if(TWI_STX != twi_state){
-    return 2;
-  }
-  
-  // set length and copy data into tx buffer
-  for(i = 0; i < length; ++i){
-    twi_txBuffer[twi_txBufferLength+i] = data[i];
-  }
-  twi_txBufferLength += length;
-  
   return 0;
 }
-
-/* 
- * Function twi_attachSlaveRxEvent
- * Desc     sets function called before a slave read operation
- * Input    function: callback function to use
- * Output   none
- */
-void twi_attachSlaveRxEvent( void (*function)(uint8_t*, int) )
-{
-  twi_onSlaveReceive = function;
-}
-
-/* 
- * Function twi_attachSlaveTxEvent
- * Desc     sets function called before a slave write operation
- * Input    function: callback function to use
- * Output   none
- */
-void twi_attachSlaveTxEvent( void (*function)(void) )
-{
-  twi_onSlaveTransmit = function;
-}
-
-/* 
- * Function twi_reply
- * Desc     sends byte or readys receive line
- * Input    ack: byte indicating to ack or to nack
- * Output   none
- */
-void twi_reply(uint8_t ack)
-{
-  // transmit master read ready signal, with or without ack
-  if(ack){
-    TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA);
-  }else{
-	  TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT);
-  }
-}
-
-/* 
- * Function twi_stop
- * Desc     relinquishes bus master status
- * Input    none
- * Output   none
- */
-void twi_stop(void)
-{
-  // send stop condition
-  TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTO);
-
-  // wait for stop condition to be exectued on bus
-  // TWINT is not set after a stop condition!
-  while(TWCR & _BV(TWSTO)){
-    continue;
-  }
-
-  // update twi state
-  twi_state = TWI_READY;
-}
-
-/* 
- * Function twi_releaseBus
- * Desc     releases bus control
- * Input    none
- * Output   none
- */
-void twi_releaseBus(void)
-{
-  // release bus
-  TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT);
-
-  // update twi state
-  twi_state = TWI_READY;
-}
-
-ISR(TWI_vect)
-{
-  switch(TW_STATUS){
-    // All Master
-    case TW_START:     // sent start condition
-    case TW_REP_START: // sent repeated start condition
-      // copy device address and r/w bit to output register and ack
-      TWDR = twi_slarw;
-      twi_reply(1);
-      break;
-
-    // Master Transmitter
-    case TW_MT_SLA_ACK:  // slave receiver acked address
-    case TW_MT_DATA_ACK: // slave receiver acked data
-      // if there is data to send, send it, otherwise stop 
-      if(twi_masterBufferIndex < twi_masterBufferLength){
-        // copy data to output register and ack
-        TWDR = twi_masterBuffer[twi_masterBufferIndex++];
-        twi_reply(1);
-      }else{
-	if (twi_sendStop)
-          twi_stop();
-	else {
-	  twi_inRepStart = true;	// we're gonna send the START
-	  // don't enable the interrupt. We'll generate the start, but we 
-	  // avoid handling the interrupt until we're in the next transaction,
-	  // at the point where we would normally issue the start.
-	  TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ;
-	  twi_state = TWI_READY;
-	}
-      }
-      break;
-    case TW_MT_SLA_NACK:  // address sent, nack received
-      twi_error = TW_MT_SLA_NACK;
-      twi_stop();
-      break;
-    case TW_MT_DATA_NACK: // data sent, nack received
-      twi_error = TW_MT_DATA_NACK;
-      twi_stop();
-      break;
-    case TW_MT_ARB_LOST: // lost bus arbitration
-      twi_error = TW_MT_ARB_LOST;
-      twi_releaseBus();
-      break;
-
-    // Master Receiver
-    case TW_MR_DATA_ACK: // data received, ack sent
-      // put byte into buffer
-      twi_masterBuffer[twi_masterBufferIndex++] = TWDR;
-    case TW_MR_SLA_ACK:  // address sent, ack received
-      // ack if more bytes are expected, otherwise nack
-      if(twi_masterBufferIndex < twi_masterBufferLength){
-        twi_reply(1);
-      }else{
-        twi_reply(0);
-      }
-      break;
-    case TW_MR_DATA_NACK: // data received, nack sent
-      // put final byte into buffer
-      twi_masterBuffer[twi_masterBufferIndex++] = TWDR;
-	if (twi_sendStop)
-          twi_stop();
-	else {
-	  twi_inRepStart = true;	// we're gonna send the START
-	  // don't enable the interrupt. We'll generate the start, but we 
-	  // avoid handling the interrupt until we're in the next transaction,
-	  // at the point where we would normally issue the start.
-	  TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ;
-	  twi_state = TWI_READY;
-	}    
-	break;
-    case TW_MR_SLA_NACK: // address sent, nack received
-      twi_stop();
-      break;
-    // TW_MR_ARB_LOST handled by TW_MT_ARB_LOST case
-
-    // Slave Receiver
-    case TW_SR_SLA_ACK:   // addressed, returned ack
-    case TW_SR_GCALL_ACK: // addressed generally, returned ack
-    case TW_SR_ARB_LOST_SLA_ACK:   // lost arbitration, returned ack
-    case TW_SR_ARB_LOST_GCALL_ACK: // lost arbitration, returned ack
-      // enter slave receiver mode
-      twi_state = TWI_SRX;
-      // indicate that rx buffer can be overwritten and ack
-      twi_rxBufferIndex = 0;
-      twi_reply(1);
-      break;
-    case TW_SR_DATA_ACK:       // data received, returned ack
-    case TW_SR_GCALL_DATA_ACK: // data received generally, returned ack
-      // if there is still room in the rx buffer
-      if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){
-        // put byte in buffer and ack
-        twi_rxBuffer[twi_rxBufferIndex++] = TWDR;
-        twi_reply(1);
-      }else{
-        // otherwise nack
-        twi_reply(0);
-      }
-      break;
-    case TW_SR_STOP: // stop or repeated start condition received
-      // ack future responses and leave slave receiver state
-      twi_releaseBus();
-      // put a null char after data if there's room
-      if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){
-        twi_rxBuffer[twi_rxBufferIndex] = '\0';
-      }
-      // callback to user defined callback
-      twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex);
-      // since we submit rx buffer to "wire" library, we can reset it
-      twi_rxBufferIndex = 0;
-      break;
-    case TW_SR_DATA_NACK:       // data received, returned nack
-    case TW_SR_GCALL_DATA_NACK: // data received generally, returned nack
-      // nack back at master
-      twi_reply(0);
-      break;
-    
-    // Slave Transmitter
-    case TW_ST_SLA_ACK:          // addressed, returned ack
-    case TW_ST_ARB_LOST_SLA_ACK: // arbitration lost, returned ack
-      // enter slave transmitter mode
-      twi_state = TWI_STX;
-      // ready the tx buffer index for iteration
-      twi_txBufferIndex = 0;
-      // set tx buffer length to be zero, to verify if user changes it
-      twi_txBufferLength = 0;
-      // request for txBuffer to be filled and length to be set
-      // note: user must call twi_transmit(bytes, length) to do this
-      twi_onSlaveTransmit();
-      // if they didn't change buffer & length, initialize it
-      if(0 == twi_txBufferLength){
-        twi_txBufferLength = 1;
-        twi_txBuffer[0] = 0x00;
-      }
-      // transmit first byte from buffer, fall
-    case TW_ST_DATA_ACK: // byte sent, ack returned
-      // copy data to output register
-      TWDR = twi_txBuffer[twi_txBufferIndex++];
-      // if there is more to send, ack, otherwise nack
-      if(twi_txBufferIndex < twi_txBufferLength){
-        twi_reply(1);
-      }else{
-        twi_reply(0);
-      }
-      break;
-    case TW_ST_DATA_NACK: // received nack, we are done 
-    case TW_ST_LAST_DATA: // received ack, but we are done already!
-      // ack future responses
-      twi_reply(1);
-      // leave slave receiver state
-      twi_state = TWI_READY;
-      break;
-
-    // All
-    case TW_NO_INFO:   // no state information
-      break;
-    case TW_BUS_ERROR: // bus error, illegal stop/start
-      twi_error = TW_BUS_ERROR;
-      twi_stop();
-      break;
-  }
-}
-
diff --git a/Firmware/twi.h b/Firmware/twi.h
index cb48708c..abcb8e97 100644
--- a/Firmware/twi.h
+++ b/Firmware/twi.h
@@ -1,5 +1,5 @@
 /*
-  twi.h - TWI/I2C library for Wiring & Arduino
+  twi.h - Stripped-down TWI/I2C library
   Copyright (c) 2006 Nicholas Zambetti.  All right reserved.
 
   This library is free software; you can redistribute it and/or
@@ -17,39 +17,37 @@
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
 
-#ifndef twi_h
-#define twi_h
+#pragma once
 
-  #include <inttypes.h>
-
-  //#define ATMEGA8
-
-  #ifndef TWI_FREQ
-  #define TWI_FREQ 400000L
-  #endif
-
-  #ifndef TWI_BUFFER_LENGTH
-  #define TWI_BUFFER_LENGTH 32
-  #endif
-
-  #define TWI_READY 0
-  #define TWI_MRX   1
-  #define TWI_MTX   2
-  #define TWI_SRX   3
-  #define TWI_STX   4
-  
-  void twi_init(void);
-  void twi_disable(void);
-  void twi_setAddress(uint8_t);
-  void twi_setFrequency(uint32_t);
-  uint8_t twi_readFrom(uint8_t, uint8_t*, uint8_t, uint8_t);
-  uint8_t twi_writeTo(uint8_t, uint8_t*, uint8_t, uint8_t, uint8_t);
-  uint8_t twi_transmit(const uint8_t*, uint8_t);
-  void twi_attachSlaveRxEvent( void (*)(uint8_t*, int) );
-  void twi_attachSlaveTxEvent( void (*)(void) );
-  void twi_reply(uint8_t);
-  void twi_stop(void);
-  void twi_releaseBus(void);
+#include <inttypes.h>
+#include <compat/twi.h>
 
+#ifndef TWI_FREQ
+#define TWI_FREQ 400000L
 #endif
 
+/*
+ * Function twi_init
+ * Desc     readys twi pins and sets twi bitrate
+ * Input    none
+ * Output   none
+ */
+void twi_init(void);
+
+/*
+ * Function twi_disable
+ * Desc     disables twi pins
+ * Input    none
+ * Output   none
+ */
+void twi_disable(void);
+
+/*
+ * Function twi_rw8
+ * Desc     read/write a single byte from a device
+ * Input    address: 7bit i2c device address
+ *          mode: TW_READ or TW_WRITE
+ *          data: pointer to byte
+ * Output   0 on success
+ */
+uint8_t twi_rw8(uint8_t address, uint8_t mode, uint8_t* data);

From 30e7b777e03054417f23d161b9a30df3b96e89ee Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Thu, 20 Aug 2020 22:13:13 +0200
Subject: [PATCH 11/58] Error-out with PAT9125_SWSPI (not fully implemented)

.. and likely will never was/be.
---
 Firmware/pat9125.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Firmware/pat9125.c b/Firmware/pat9125.c
index ab6342aa..f47d676b 100644
--- a/Firmware/pat9125.c
+++ b/Firmware/pat9125.c
@@ -110,7 +110,7 @@ uint8_t pat9125_probe()
 {
 #if defined(PAT9125_SWSPI)
     swspi_init();
-    //#error not implemented
+  #error not implemented
 #elif defined(PAT9125_SWI2C)
     swi2c_init();
     return swi2c_readByte_A8(PAT9125_I2C_ADDR,0x00,NULL);

From d8a88379385504241747aca0877076049992e3dc Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Tue, 25 Aug 2020 11:31:35 +0200
Subject: [PATCH 12/58] Document the 3 possible modes

---
 Firmware/config.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Firmware/config.h b/Firmware/config.h
index b107d0ec..c64bd441 100644
--- a/Firmware/config.h
+++ b/Firmware/config.h
@@ -30,9 +30,9 @@
 #define SWI2C_TMO         2048 //2048 cycles timeout
 
 //PAT9125 configuration
-//#define PAT9125_SWSPI
-//#define PAT9125_SWI2C
-#define PAT9125_I2C
+//#define PAT9125_SWSPI // software SPI mode (incomplete)
+//#define PAT9125_SWI2C // software I2C mode
+#define PAT9125_I2C     // hardware I2C mode
 
 #define PAT9125_I2C_ADDR  0x75  //ID=LO
 //#define PAT9125_I2C_ADDR  0x79  //ID=HI

From e37cdab38fd0a8df2bcad4eca3e410e7b9de148f Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Tue, 25 Aug 2020 11:58:48 +0200
Subject: [PATCH 13/58] PAT9125_I2C: accept either NACK or ACK in receive

Both would be technically correct.
---
 Firmware/twi.c | 38 ++++++++++++++++++++++++++++----------
 1 file changed, 28 insertions(+), 10 deletions(-)

diff --git a/Firmware/twi.c b/Firmware/twi.c
index 161db52a..11c708aa 100644
--- a/Firmware/twi.c
+++ b/Firmware/twi.c
@@ -57,34 +57,52 @@ void twi_disable(void)
   digitalWrite(SCL, 0);
 }
 
-uint8_t twi_waitfor(uint8_t status)
+static void twi_wait()
 {
     while(!(TWCR & _BV(TWINT)));
-    return (TW_STATUS != status);
 }
 
 uint8_t twi_rw8(uint8_t address, uint8_t mode, uint8_t* data)
 {
   // send start condition
   TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWSTA);
-  if(twi_waitfor(TW_START))
+  twi_wait();
+  if(TW_STATUS != TW_START)
       return 1;
 
   // send address
   TWDR = mode;
   TWDR |= (address << 1);
   TWCR = _BV(TWEN) | _BV(TWINT);
-  if(twi_waitfor(mode == TW_READ? TW_MR_SLA_ACK: TW_MT_SLA_ACK))
-      return 2;
+  twi_wait();
 
-  // send or receive data
   if(mode == TW_WRITE)
+  {
+      if(TW_STATUS != TW_MT_SLA_ACK)
+          return 2;
+
+      // send data
       TWDR = *data;
-  TWCR = _BV(TWEN) | _BV(TWINT);
-  if(twi_waitfor(mode == TW_READ? TW_MR_DATA_NACK: TW_MT_DATA_ACK))
-      return 3;
-  if(mode == TW_READ)
+      TWCR = _BV(TWEN) | _BV(TWINT);
+      twi_wait();
+      if(TW_STATUS != TW_MT_DATA_ACK)
+          return 3;
+  }
+  else
+  {
+      if(TW_STATUS != TW_MR_SLA_ACK)
+          return 2;
+
+      // receive data
+      TWCR = _BV(TWEN) | _BV(TWINT);
+      twi_wait();
+
+      // accept ACK or NACK (since only 1 byte is read)
+      if(!(TW_STATUS & TW_MR_DATA_ACK))
+          return 3;
+
       *data = TWDR;
+  }
 
   // send stop
   TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWSTO);

From 6d476d71447e707df2ee5b3c367a650235357f9b Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Sun, 27 Sep 2020 14:29:07 +0200
Subject: [PATCH 14/58] Still use SWI2C on RAMBo10a boards

The wiring for the PAT9125 on RAMBo10a boards is not directly connected
to the SCL pin and requires the sw mode.

Detect this requirement by checking the definition for the SWI2C_SCL pin
in the board definition.

Remove SWI2C_SCL/SDA from the other boards to use the HW mode.
---
 Firmware/config.h         | 5 ++++-
 Firmware/pins_Einsy_1_0.h | 6 ------
 Firmware/pins_Rambo_1_3.h | 3 ---
 Firmware/swi2c.c          | 3 +++
 4 files changed, 7 insertions(+), 10 deletions(-)

diff --git a/Firmware/config.h b/Firmware/config.h
index c64bd441..922a5398 100644
--- a/Firmware/config.h
+++ b/Firmware/config.h
@@ -31,8 +31,11 @@
 
 //PAT9125 configuration
 //#define PAT9125_SWSPI // software SPI mode (incomplete)
-//#define PAT9125_SWI2C // software I2C mode
+#ifdef SWI2C_SCL
+#define PAT9125_SWI2C   // software I2C mode
+#else
 #define PAT9125_I2C     // hardware I2C mode
+#endif
 
 #define PAT9125_I2C_ADDR  0x75  //ID=LO
 //#define PAT9125_I2C_ADDR  0x79  //ID=HI
diff --git a/Firmware/pins_Einsy_1_0.h b/Firmware/pins_Einsy_1_0.h
index 14b56233..21578ebd 100755
--- a/Firmware/pins_Einsy_1_0.h
+++ b/Firmware/pins_Einsy_1_0.h
@@ -18,12 +18,6 @@
 #define W25X20CL                 // external 256kB flash
 #define BOOTAPP                  // bootloader support
 
-
-#define SWI2C_SDA      20 //SDA on P3
-#define SWI2C_SCL      21 //SCL on P3
-
-
-
 #define X_TMC2130_CS           41
 #define X_TMC2130_DIAG         64 // !!! changed from 40 (EINY03)
 #define X_STEP_PIN             37
diff --git a/Firmware/pins_Rambo_1_3.h b/Firmware/pins_Rambo_1_3.h
index 538fb4f3..522ad28f 100644
--- a/Firmware/pins_Rambo_1_3.h
+++ b/Firmware/pins_Rambo_1_3.h
@@ -11,9 +11,6 @@
 
 #define PINDA_THERMISTOR
 
-#define SWI2C_SDA      20 //SDA on P3
-#define SWI2C_SCL      21 //SCL on P3
-
 #ifdef MICROMETER_LOGGING
 #define D_DATACLOCK		24	//Y_MAX (green)
 #define D_DATA			30	//X_MAX (blue)
diff --git a/Firmware/swi2c.c b/Firmware/swi2c.c
index 49fbc5ef..62a28e1a 100644
--- a/Firmware/swi2c.c
+++ b/Firmware/swi2c.c
@@ -7,6 +7,7 @@
 #include "pins.h"
 #include "io_atmega2560.h"
 
+#ifdef SWI2C_SCL
 
 #define SWI2C_RMSK   0x01 //read mask (bit0 = 1)
 #define SWI2C_WMSK   0x00 //write mask (bit0 = 0)
@@ -187,3 +188,5 @@ uint8_t swi2c_writeByte_A16(uint8_t dev_addr, unsigned short addr, uint8_t* pbyt
 }
 
 #endif //SWI2C_A16
+
+#endif //SWI2C_SCL

From 384f40956c4292c33ec087e90f9dfa6da5383800 Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Sun, 27 Sep 2020 16:42:20 +0200
Subject: [PATCH 15/58] Remove obsolete cbi/sbi

---
 Firmware/twi.c | 11 +----------
 1 file changed, 1 insertion(+), 10 deletions(-)

diff --git a/Firmware/twi.c b/Firmware/twi.c
index 11c708aa..f8c077ab 100644
--- a/Firmware/twi.c
+++ b/Firmware/twi.c
@@ -22,14 +22,6 @@
 #include <math.h>
 #include "Arduino.h" // for digitalWrite
 
-#ifndef cbi
-#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
-#endif
-
-#ifndef sbi
-#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
-#endif
-
 #include "twi.h"
 
 
@@ -40,8 +32,7 @@ void twi_init(void)
   digitalWrite(SCL, 1);
 
   // initialize twi prescaler and bit rate
-  cbi(TWSR, TWPS0);
-  cbi(TWSR, TWPS1);
+  TWSR &= ~(_BV(TWPS0) | _BV(TWPS1));
   TWBR = ((F_CPU / TWI_FREQ) - 16) / 2;
 
   /* twi bit rate formula from atmega128 manual pg 204

From c2e8d229a751df2451fd49915c55b4d3ba3f52c7 Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Mon, 28 Sep 2020 20:21:07 +0200
Subject: [PATCH 16/58] Be more compliant in the I2C protocol

- Enter a repeated-start for reading data
- Write in the same session
---
 Firmware/pat9125.c |   6 +--
 Firmware/twi.c     | 110 +++++++++++++++++++++++++++++----------------
 Firmware/twi.h     |  20 ++++++---
 3 files changed, 89 insertions(+), 47 deletions(-)

diff --git a/Firmware/pat9125.c b/Firmware/pat9125.c
index f47d676b..c6ffecf3 100644
--- a/Firmware/pat9125.c
+++ b/Firmware/pat9125.c
@@ -263,8 +263,7 @@ uint8_t pat9125_rd_reg(uint8_t addr)
 	if (!swi2c_readByte_A8(PAT9125_I2C_ADDR, addr, &data)) //NO ACK error
         goto error;
 #elif defined(PAT9125_I2C)
-	if (twi_rw8(PAT9125_I2C_ADDR,TW_WRITE,&addr) ||
-        twi_rw8(PAT9125_I2C_ADDR,TW_READ,&data))
+	if (twi_r8(PAT9125_I2C_ADDR,addr,&data))
         goto error;
 #endif
 	return data;
@@ -286,8 +285,7 @@ void pat9125_wr_reg(uint8_t addr, uint8_t data)
 	if (!swi2c_writeByte_A8(PAT9125_I2C_ADDR, addr, &data)) //NO ACK error
         goto error;
 #elif defined(PAT9125_I2C)
-	if (twi_rw8(PAT9125_I2C_ADDR,TW_WRITE,&addr) ||
-        twi_rw8(PAT9125_I2C_ADDR,TW_READ,&data))
+	if (twi_w8(PAT9125_I2C_ADDR,addr,data))
         goto error;
 #endif
     return;
diff --git a/Firmware/twi.c b/Firmware/twi.c
index f8c077ab..6dd1645c 100644
--- a/Firmware/twi.c
+++ b/Firmware/twi.c
@@ -48,55 +48,89 @@ void twi_disable(void)
   digitalWrite(SCL, 0);
 }
 
-static void twi_wait()
+
+static void twi_stop()
 {
-    while(!(TWCR & _BV(TWINT)));
+  TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWSTO);
 }
 
-uint8_t twi_rw8(uint8_t address, uint8_t mode, uint8_t* data)
+
+static uint8_t twi_wait(uint8_t status)
+{
+  while(!(TWCR & _BV(TWINT)));
+  if(TW_STATUS != status)
+  {
+      twi_stop();
+      return 1;
+  }
+  return 0;
+}
+
+
+static uint8_t twi_start(uint8_t address, uint8_t reg)
 {
   // send start condition
   TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWSTA);
-  twi_wait();
-  if(TW_STATUS != TW_START)
+  if(twi_wait(TW_START))
       return 1;
 
   // send address
-  TWDR = mode;
-  TWDR |= (address << 1);
+  TWDR = TW_WRITE | (address << 1);
   TWCR = _BV(TWEN) | _BV(TWINT);
-  twi_wait();
+  if(twi_wait(TW_MT_SLA_ACK))
+      return 2;
 
-  if(mode == TW_WRITE)
-  {
-      if(TW_STATUS != TW_MT_SLA_ACK)
-          return 2;
-
-      // send data
-      TWDR = *data;
-      TWCR = _BV(TWEN) | _BV(TWINT);
-      twi_wait();
-      if(TW_STATUS != TW_MT_DATA_ACK)
-          return 3;
-  }
-  else
-  {
-      if(TW_STATUS != TW_MR_SLA_ACK)
-          return 2;
-
-      // receive data
-      TWCR = _BV(TWEN) | _BV(TWINT);
-      twi_wait();
-
-      // accept ACK or NACK (since only 1 byte is read)
-      if(!(TW_STATUS & TW_MR_DATA_ACK))
-          return 3;
-
-      *data = TWDR;
-  }
-
-  // send stop
-  TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWSTO);
+  // send register
+  TWDR = reg;
+  TWCR = _BV(TWEN) | _BV(TWINT);
+  if(twi_wait(TW_MT_DATA_ACK))
+      return 3;
 
   return 0;
 }
+
+
+uint8_t twi_r8(uint8_t address, uint8_t reg, uint8_t* data)
+{
+  if(twi_start(address, reg))
+      return 1;
+
+  // repeat start
+  TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWSTA);
+  if(twi_wait(TW_REP_START))
+      return 2;
+
+  // start receiving
+  TWDR = TW_READ | (address << 1);
+  TWCR = _BV(TWEN) | _BV(TWINT);
+  if(twi_wait(TW_MR_SLA_ACK))
+      return 3;
+
+  // receive data
+  TWCR = _BV(TWEN) | _BV(TWINT);
+  if(twi_wait(TW_MR_DATA_NACK))
+      return 4;
+
+  *data = TWDR;
+
+  // send stop
+  twi_stop();
+  return 0;
+}
+
+
+uint8_t twi_w8(uint8_t address, uint8_t reg, uint8_t data)
+{
+  if(twi_start(address, reg))
+      return 1;
+
+  // send data
+  TWDR = data;
+  TWCR = _BV(TWEN) | _BV(TWINT);
+  if(twi_wait(TW_MT_DATA_ACK))
+      return 2;
+
+  // send stop
+  twi_stop();
+  return 0;
+}
diff --git a/Firmware/twi.h b/Firmware/twi.h
index abcb8e97..bdb617fc 100644
--- a/Firmware/twi.h
+++ b/Firmware/twi.h
@@ -43,11 +43,21 @@ void twi_init(void);
 void twi_disable(void);
 
 /*
- * Function twi_rw8
- * Desc     read/write a single byte from a device
+ * Function twi_r8
+ * Desc     read a single byte from a device
  * Input    address: 7bit i2c device address
- *          mode: TW_READ or TW_WRITE
- *          data: pointer to byte
+ *          reg: register address
+ *          data: pointer to byte for result
  * Output   0 on success
  */
-uint8_t twi_rw8(uint8_t address, uint8_t mode, uint8_t* data);
+uint8_t twi_r8(uint8_t address, uint8_t reg, uint8_t* data);
+
+/*
+ * Function twi_w8
+ * Desc     write a single byte from a device
+ * Input    address: 7bit i2c device address
+ *          reg: register address
+ *          data: byte to write
+ * Output   0 on success
+ */
+uint8_t twi_w8(uint8_t address, uint8_t reg, uint8_t data);

From df824414eface1c89175eb23e41ca06210bda334 Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Mon, 28 Sep 2020 21:02:06 +0200
Subject: [PATCH 17/58] Fix probing in IR_SENSOR

---
 Firmware/pat9125.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Firmware/pat9125.c b/Firmware/pat9125.c
index c6ffecf3..58308a9a 100644
--- a/Firmware/pat9125.c
+++ b/Firmware/pat9125.c
@@ -118,8 +118,8 @@ uint8_t pat9125_probe()
     twi_init();
   #ifdef IR_SENSOR
     // NOTE: this is called from the MK3S variant, so it should be kept minimal
-    uint8_t addr = PAT9125_PID1;
-    return (twi_rw8(PAT9125_I2C_ADDR,TW_READ,&addr) == 0);
+    uint8_t data;
+    return (twi_r8(PAT9125_I2C_ADDR,PAT9125_PID1,&data) == 0);
   #else
     return (pat9125_rd_reg(PAT9125_PID1) != 0);
   #endif

From 8a27b6abdb556307070c6f5bf2f76711d0436286 Mon Sep 17 00:00:00 2001
From: 3d-gussner <3d.gussner@gmail.com>
Date: Thu, 7 Jan 2021 11:45:40 +0100
Subject: [PATCH 18/58] Move Z up before xy home running xyz calibration to
 prevent scratches on bed and sheet

---
 Firmware/Marlin_main.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp
index c6f9e4b7..a4123ded 100755
--- a/Firmware/Marlin_main.cpp
+++ b/Firmware/Marlin_main.cpp
@@ -2974,6 +2974,8 @@ bool gcode_M45(bool onlyZ, int8_t verbosity_level)
 	//set_destination_to_current();
 	int l_feedmultiply = setup_for_endstop_move();
 	lcd_display_message_fullscreen_P(_T(MSG_AUTO_HOME));
+  raise_z_above(MESH_HOME_Z_SEARCH);
+  st_synchronize();
 	home_xy();
 
 	enable_endstops(false);

From dea3f23a69f700032b97f765a77d03b71a2d1e27 Mon Sep 17 00:00:00 2001
From: Voinea Dragos <voinea.dragos.alexandru@gmail.com>
Date: Thu, 14 Jan 2021 11:52:22 +0200
Subject: [PATCH 19/58] PRUSA SN in eeprom

---
 Firmware/Marlin_main.cpp | 38 ++++++++++++++++++++++++++++++--------
 Firmware/eeprom.h        |  4 +++-
 2 files changed, 33 insertions(+), 9 deletions(-)

diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp
index 3be46591..86b14402 100755
--- a/Firmware/Marlin_main.cpp
+++ b/Firmware/Marlin_main.cpp
@@ -407,6 +407,7 @@ static void gcode_M105(uint8_t extruder);
 static void temp_compensation_start();
 static void temp_compensation_apply();
 
+static bool get_PRUSA_SN(char* SN);
 
 uint16_t gcode_in_progress = 0;
 uint16_t mcode_in_progress = 0;
@@ -1075,6 +1076,21 @@ void setup()
           if(!(eeprom_read_byte((uint8_t*)EEPROM_FAN_CHECK_ENABLED)))
                eeprom_update_byte((unsigned char *)EEPROM_FAN_CHECK_ENABLED,true);
 	}
+
+
+    if (eeprom_read_byte((uint8_t*)EEPROM_PRUSA_SN + 19)) //saved EEPROM SN is not valid. Try to retrieve it.
+    {
+        char SN[20];
+        if (get_PRUSA_SN(SN))
+        {
+            eeprom_update_block(SN, (uint8_t*)EEPROM_PRUSA_SN, 20);
+            puts_P(PSTR("SN updated"));
+        }
+        else
+            puts_P(PSTR("SN update failed"));
+    }
+
+
 #ifndef W25X20CL
 	SERIAL_PROTOCOLLNPGM("start");
 #else
@@ -3386,25 +3402,26 @@ void gcode_M701()
  *
  * Typical format of S/N is:CZPX0917X003XC13518
  *
- * Command operates only in farm mode, if not in farm mode, "Not in farm mode." is written to MYSERIAL.
- *
  * Send command ;S to serial port 0 to retrieve serial number stored in 32U2 processor,
- * reply is transmitted to serial port 1 character by character.
+ * reply is transmitted to the selected serial port.
  * Operation takes typically 23 ms. If the retransmit is not finished until 100 ms,
  * it is interrupted, so less, or no characters are retransmitted, only newline character is send
  * in any case.
+ * The command will fail if the 32U2 processor is unpowered via USB since it is isolated from the rest of the electronics.
+ * In that case the value that is stored in the EEPROM should be used instead.
+ *
+ * @return 1 on success
  */
-static void gcode_PRUSA_SN()
+static bool get_PRUSA_SN(char* SN)
 {
     uint8_t selectedSerialPort_bak = selectedSerialPort;
-    char SN[20];
     selectedSerialPort = 0;
     SERIAL_ECHOLNRPGM(PSTR(";S"));
     uint8_t numbersRead = 0;
     ShortTimer timeout;
     timeout.start();
 
-    while (numbersRead < (sizeof(SN) - 1)) {
+    while (numbersRead < 19) {
         if (MSerial.available() > 0) {
             SN[numbersRead] = MSerial.read();
             numbersRead++;
@@ -3413,7 +3430,7 @@ static void gcode_PRUSA_SN()
     }
     SN[numbersRead] = 0;
     selectedSerialPort = selectedSerialPort_bak;
-    SERIAL_ECHOLN(SN);
+    return (numbersRead == 19);
 }
 //! Detection of faulty RAMBo 1.1b boards equipped with bigger capacitors
 //! at the TACH_1 pin, which causes bad detection of print fan speed.
@@ -3950,7 +3967,12 @@ void process_commands()
         card.openFile(strchr_pointer+4,false);
 
 	} else if (code_seen("SN")) { // PRUSA SN
-        gcode_PRUSA_SN();
+        char SN[20];
+        eeprom_read_block(SN, (uint8_t*)EEPROM_PRUSA_SN, 20);
+        if (SN[19])
+            puts_P(PSTR("SN invalid"));
+        else
+            puts(SN);
 
 	} else if(code_seen("Fir")){ // PRUSA Fir
 
diff --git a/Firmware/eeprom.h b/Firmware/eeprom.h
index 731db1da..f54bb8ed 100644
--- a/Firmware/eeprom.h
+++ b/Firmware/eeprom.h
@@ -316,6 +316,7 @@ static_assert(sizeof(Sheets) == EEPROM_SHEETS_SIZEOF, "Sizeof(Sheets) is not EEP
 | 0x0D29 3369		| uint8		| EEPROM_PINDA_TEMP_COMPENSATION   		| ffh 255		| ffh 255				| PINDA temp compensation unknown state	            | LCD menu		| D3 Ax0d29 C1
 | ^					| ^			| ^										| 00h 0			| ^						| PINDA has no temp compensation PINDA v1/2    		| ^				| ^
 | ^					| ^			| ^										| 01h 1			| ^						| PINDA has temp compensation aka SuperPINDA       	| ^				| ^
+| 0x0D15 3349		| char[20]	| EEPROM_PRUSA_SN						| SN[19] == 0	| ffffffffffffffff...	| PRUSA Serial number string						| PRUSA SN		| D3 Ax0d15 C20
 
   
 | Address begin		| Bit/Type 	| Name 									| Valid values	| Default/FactoryReset	| Description 										| Gcode/Function| Debug code
@@ -521,8 +522,9 @@ static Sheets * const EEPROM_Sheets_base = (Sheets*)(EEPROM_SHEETS_BASE);
 #define EEPROM_ALTFAN_OVERRIDE (EEPROM_UVLO_LA_K-1) //uint8
 #define EEPROM_EXPERIMENTAL_VISIBILITY (EEPROM_ALTFAN_OVERRIDE-1) //uint8
 #define EEPROM_PINDA_TEMP_COMPENSATION (EEPROM_EXPERIMENTAL_VISIBILITY-1) //uint8
+#define EEPROM_PRUSA_SN (EEPROM_PINDA_TEMP_COMPENSATION-20) //char[20]
 //This is supposed to point to last item to allow EEPROM overrun check. Please update when adding new items.
-#define EEPROM_LAST_ITEM EEPROM_PINDA_TEMP_COMPENSATION
+#define EEPROM_LAST_ITEM EEPROM_PRUSA_SN
 // !!!!!
 // !!!!! this is end of EEPROM section ... all updates MUST BE inserted before this mark !!!!!
 // !!!!!

From 20c3f4cb7709692824d7751e150d9df0606b75b3 Mon Sep 17 00:00:00 2001
From: Alex Voinea <voinea.dragos.alexandru@gmail.com>
Date: Thu, 14 Jan 2021 12:53:12 +0200
Subject: [PATCH 20/58] Update comments

---
 Firmware/Marlin_main.cpp | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp
index 86b14402..d43e05e5 100755
--- a/Firmware/Marlin_main.cpp
+++ b/Firmware/Marlin_main.cpp
@@ -1077,8 +1077,9 @@ void setup()
                eeprom_update_byte((unsigned char *)EEPROM_FAN_CHECK_ENABLED,true);
 	}
 
-
-    if (eeprom_read_byte((uint8_t*)EEPROM_PRUSA_SN + 19)) //saved EEPROM SN is not valid. Try to retrieve it.
+    //saved EEPROM SN is not valid. Try to retrieve it.
+    //SN is valid only if it is NULL terminated. Any other character means either uninitialized or corrupted
+    if (eeprom_read_byte((uint8_t*)EEPROM_PRUSA_SN + 19))
     {
         char SN[20];
         if (get_PRUSA_SN(SN))
@@ -3403,14 +3404,14 @@ void gcode_M701()
  * Typical format of S/N is:CZPX0917X003XC13518
  *
  * Send command ;S to serial port 0 to retrieve serial number stored in 32U2 processor,
- * reply is transmitted to the selected serial port.
+ * reply is stored in *SN.
  * Operation takes typically 23 ms. If the retransmit is not finished until 100 ms,
- * it is interrupted, so less, or no characters are retransmitted, only newline character is send
- * in any case.
+ * it is interrupted, so less, or no characters are retransmitted, the function returns false
  * The command will fail if the 32U2 processor is unpowered via USB since it is isolated from the rest of the electronics.
  * In that case the value that is stored in the EEPROM should be used instead.
  *
  * @return 1 on success
+ * @return 0 on general failure
  */
 static bool get_PRUSA_SN(char* SN)
 {

From 4fed728e083306aa4cddc950a9a1624bf7c61faf Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Tue, 26 Jan 2021 15:59:21 +0100
Subject: [PATCH 21/58] Elide delayMicroseconds for TMC2130 in non-DEDGE mode

Introduce new macros TMC2130_MINIMUM_DELAY/STEPPER_MINIMUM_DELAY for
blocking pauses.

If MINIMUM_PULSE has defined to be zero, avoid the delay call entirely.
---
 Firmware/stepper.cpp | 8 +++++---
 Firmware/tmc2130.cpp | 8 ++++----
 Firmware/tmc2130.h   | 6 ++++++
 3 files changed, 15 insertions(+), 7 deletions(-)

diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp
index b3cc5a57..e06e0602 100644
--- a/Firmware/stepper.cpp
+++ b/Firmware/stepper.cpp
@@ -75,9 +75,11 @@ uint16_t SP_min = 0x21FF;
 #ifdef TMC2130
 #define STEPPER_MINIMUM_PULSE TMC2130_MINIMUM_PULSE
 #define STEPPER_SET_DIR_DELAY TMC2130_SET_DIR_DELAY
+#define STEPPER_MINIMUM_DELAY TMC2130_MINIMUM_DELAY
 #else
 #define STEPPER_MINIMUM_PULSE 2
 #define STEPPER_SET_DIR_DELAY 100
+#define STEPPER_MINIMUM_DELAY delayMicroseconds(STEPPER_MINIMUM_PULSE)
 #endif
 
 #ifdef TMC2130_DEDGE_STEPPING
@@ -1448,7 +1450,7 @@ void babystep(const uint8_t axis,const bool direction)
         STEP_NC_HI(X_DUP_AXIS);
 #endif
 #ifndef TMC2130_DEDGE_STEPPING
-        delayMicroseconds(STEPPER_MINIMUM_PULSE);
+        STEPPER_MINIMUM_DELAY;
         STEP_NC_LO(X_AXIS);
 #ifdef DEBUG_XSTEP_DUP_PIN
         STEP_NC_LO(X_DUP_AXIS);
@@ -1478,7 +1480,7 @@ void babystep(const uint8_t axis,const bool direction)
         STEP_NC_HI(Y_DUP_AXIS);
 #endif
 #ifndef TMC2130_DEDGE_STEPPING
-        delayMicroseconds(STEPPER_MINIMUM_PULSE);
+        STEPPER_MINIMUM_DELAY;
         STEP_NC_LO(Y_AXIS);
 #ifdef DEBUG_YSTEP_DUP_PIN
         STEP_NC_LO(Y_DUP_AXIS);
@@ -1511,7 +1513,7 @@ void babystep(const uint8_t axis,const bool direction)
         STEP_NC_HI(Z2_AXIS);
 #endif
 #ifndef TMC2130_DEDGE_STEPPING
-        delayMicroseconds(STEPPER_MINIMUM_PULSE);
+        STEPPER_MINIMUM_DELAY;
         STEP_NC_LO(Z_AXIS);
 #ifdef Z_DUAL_STEPPER_DRIVERS
         STEP_NC_LO(Z2_AXIS);
diff --git a/Firmware/tmc2130.cpp b/Firmware/tmc2130.cpp
index 15646b92..41f7b7c1 100755
--- a/Firmware/tmc2130.cpp
+++ b/Firmware/tmc2130.cpp
@@ -717,10 +717,10 @@ static uint8_t tmc2130_rx(uint8_t axis, uint8_t addr, uint32_t* rval)
 #define _DO_STEP_Z      TOGGLE(Z_STEP_PIN)
 #define _DO_STEP_E      TOGGLE(E0_STEP_PIN)
 #else
-#define _DO_STEP_X      { WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN); delayMicroseconds(TMC2130_MINIMUM_PULSE); WRITE(X_STEP_PIN, INVERT_X_STEP_PIN); }
-#define _DO_STEP_Y      { WRITE(Y_STEP_PIN, !INVERT_Y_STEP_PIN); delayMicroseconds(TMC2130_MINIMUM_PULSE); WRITE(Y_STEP_PIN, INVERT_Y_STEP_PIN); }
-#define _DO_STEP_Z      { WRITE(Z_STEP_PIN, !INVERT_Z_STEP_PIN); delayMicroseconds(TMC2130_MINIMUM_PULSE); WRITE(Z_STEP_PIN, INVERT_Z_STEP_PIN); }
-#define _DO_STEP_E      { WRITE(E0_STEP_PIN, !INVERT_E_STEP_PIN); delayMicroseconds(TMC2130_MINIMUM_PULSE); WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN); }
+#define _DO_STEP_X      { WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN); TMC2130_MINIMUM_DELAY; WRITE(X_STEP_PIN, INVERT_X_STEP_PIN); }
+#define _DO_STEP_Y      { WRITE(Y_STEP_PIN, !INVERT_Y_STEP_PIN); TMC2130_MINIMUM_DELAY; WRITE(Y_STEP_PIN, INVERT_Y_STEP_PIN); }
+#define _DO_STEP_Z      { WRITE(Z_STEP_PIN, !INVERT_Z_STEP_PIN); TMC2130_MINIMUM_DELAY; WRITE(Z_STEP_PIN, INVERT_Z_STEP_PIN); }
+#define _DO_STEP_E      { WRITE(E0_STEP_PIN, !INVERT_E_STEP_PIN); TMC2130_MINIMUM_DELAY; WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN); }
 #endif
 
 
diff --git a/Firmware/tmc2130.h b/Firmware/tmc2130.h
index 4b5b764c..36ba5552 100644
--- a/Firmware/tmc2130.h
+++ b/Firmware/tmc2130.h
@@ -33,6 +33,12 @@ extern uint8_t tmc2130_sg_homing_axes_mask;
 #define TMC2130_SET_DIR_DELAY 20  // minimum delay after setting direction in uS
 #define TMC2130_SET_PWR_DELAY 0   // minimum delay after changing pwr mode in uS
 
+#if TMC2130_MINIMUM_PULSE == 0
+#define TMC2130_MINIMUM_DELAY //NOP
+#else
+#define TMC2130_MINIMUM_DELAY delayMicroseconds(TMC2130_MINIMUM_PULSE)
+#endif
+
 extern uint8_t tmc2130_home_enabled;
 extern uint8_t tmc2130_home_origin[2];
 extern uint8_t tmc2130_home_bsteps[2];

From 2a6989ecd559f70ceb08aa471e0399c52747ddc8 Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Tue, 26 Jan 2021 16:09:23 +0100
Subject: [PATCH 22/58] Remove TMC2130 special-cases

With the new STEPPER_MINIMUM_DELAY being automatically removed for
TMC2130 we no longer need to add specialized #ifdefs for DEDGE in
babystep.
---
 Firmware/stepper.cpp | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp
index e06e0602..e74d7154 100644
--- a/Firmware/stepper.cpp
+++ b/Firmware/stepper.cpp
@@ -1449,12 +1449,10 @@ void babystep(const uint8_t axis,const bool direction)
 #ifdef DEBUG_XSTEP_DUP_PIN
         STEP_NC_HI(X_DUP_AXIS);
 #endif
-#ifndef TMC2130_DEDGE_STEPPING
         STEPPER_MINIMUM_DELAY;
         STEP_NC_LO(X_AXIS);
 #ifdef DEBUG_XSTEP_DUP_PIN
         STEP_NC_LO(X_DUP_AXIS);
-#endif
 #endif
 
         //get old pin state back.
@@ -1479,12 +1477,10 @@ void babystep(const uint8_t axis,const bool direction)
 #ifdef DEBUG_YSTEP_DUP_PIN
         STEP_NC_HI(Y_DUP_AXIS);
 #endif
-#ifndef TMC2130_DEDGE_STEPPING
         STEPPER_MINIMUM_DELAY;
         STEP_NC_LO(Y_AXIS);
 #ifdef DEBUG_YSTEP_DUP_PIN
         STEP_NC_LO(Y_DUP_AXIS);
-#endif
 #endif
 
         //get old pin state back.
@@ -1512,12 +1508,10 @@ void babystep(const uint8_t axis,const bool direction)
 #ifdef Z_DUAL_STEPPER_DRIVERS
         STEP_NC_HI(Z2_AXIS);
 #endif
-#ifndef TMC2130_DEDGE_STEPPING
         STEPPER_MINIMUM_DELAY;
         STEP_NC_LO(Z_AXIS);
 #ifdef Z_DUAL_STEPPER_DRIVERS
         STEP_NC_LO(Z2_AXIS);
-#endif
 #endif
 
         //get old pin state back.

From b17cdcd4d7ebd9e53a4180cf9e6768845d1b1eef Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Tue, 26 Jan 2021 16:12:59 +0100
Subject: [PATCH 23/58] Ensure MINIMUM_PULSE is always 0 in DEDGE mode

This ensures delays are always properly elided without having to check
for DEDGE all over the place.
---
 Firmware/stepper.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp
index e74d7154..8684713b 100644
--- a/Firmware/stepper.cpp
+++ b/Firmware/stepper.cpp
@@ -83,6 +83,7 @@ uint16_t SP_min = 0x21FF;
 #endif
 
 #ifdef TMC2130_DEDGE_STEPPING
+static_assert(TMC2130_MINIMUM_PULSE == 0, "DEDGE requires/implies TMC2130_MINIMUM_PULSE == 0");
 #define STEP_NC_HI(axis) TOGGLE(_STEP_PIN_##axis)
 #define STEP_NC_LO(axis) //NOP
 #else

From d3734b02cc1fbb8ba9a446d9ac5ef83b91756178 Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Tue, 26 Jan 2021 16:18:23 +0100
Subject: [PATCH 24/58] Also fix delay instances inside unused BACKLASH_[XY]

---
 Firmware/stepper.cpp | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp
index 8684713b..d47dd2dc 100644
--- a/Firmware/stepper.cpp
+++ b/Firmware/stepper.cpp
@@ -352,13 +352,13 @@ FORCE_INLINE void stepper_next_block()
 				WRITE_NC(X_DIR_PIN, INVERT_X_DIR);
 			else
 				WRITE_NC(X_DIR_PIN, !INVERT_X_DIR);
-			_delay_us(100);
+			delayMicroseconds(STEPPER_SET_DIR_DELAY);
 			for (uint8_t i = 0; i < st_backlash_x; i++)
 			{
 				STEP_NC_HI(X_AXIS);
-				_delay_us(100);
+				STEPPER_MINIMUM_DELAY;
 				STEP_NC_LO(X_AXIS);
-				_delay_us(900);
+				_delay_us(900); // hard-coded jerk! *bad*
 			}
 		}
 		last_dir_bits &= ~1;
@@ -375,13 +375,13 @@ FORCE_INLINE void stepper_next_block()
 				WRITE_NC(Y_DIR_PIN, INVERT_Y_DIR);
 			else
 				WRITE_NC(Y_DIR_PIN, !INVERT_Y_DIR);
-			_delay_us(100);
+			delayMicroseconds(STEPPER_SET_DIR_DELAY);
 			for (uint8_t i = 0; i < st_backlash_y; i++)
 			{
 				STEP_NC_HI(Y_AXIS);
-				_delay_us(100);
+				STEPPER_MINIMUM_DELAY;
 				STEP_NC_LO(Y_AXIS);
-				_delay_us(900);
+				_delay_us(900); // hard-coded jerk! *bad*
 			}
 		}
 		last_dir_bits &= ~2;

From a9625747db85f22cb583d4fdc4c4f0dc2706e687 Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Tue, 26 Jan 2021 19:37:14 +0100
Subject: [PATCH 25/58] Reinstate the nop instruction as delay in non-DEDGE

When TMC2130_MINIMUM_PULSE is 0 a minimum delay is implied.
In this case, use a single "nop" instruction.
---
 Firmware/stepper.cpp | 3 ++-
 Firmware/tmc2130.h   | 4 +++-
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp
index d47dd2dc..fc8d9f44 100644
--- a/Firmware/stepper.cpp
+++ b/Firmware/stepper.cpp
@@ -83,7 +83,8 @@ uint16_t SP_min = 0x21FF;
 #endif
 
 #ifdef TMC2130_DEDGE_STEPPING
-static_assert(TMC2130_MINIMUM_PULSE == 0, "DEDGE requires/implies TMC2130_MINIMUM_PULSE == 0");
+static_assert(TMC2130_MINIMUM_DELAY 1, // this will fail to compile when non-empty
+              "DEDGE implies/requires an empty TMC2130_MINIMUM_DELAY");
 #define STEP_NC_HI(axis) TOGGLE(_STEP_PIN_##axis)
 #define STEP_NC_LO(axis) //NOP
 #else
diff --git a/Firmware/tmc2130.h b/Firmware/tmc2130.h
index 36ba5552..485bf41c 100644
--- a/Firmware/tmc2130.h
+++ b/Firmware/tmc2130.h
@@ -33,8 +33,10 @@ extern uint8_t tmc2130_sg_homing_axes_mask;
 #define TMC2130_SET_DIR_DELAY 20  // minimum delay after setting direction in uS
 #define TMC2130_SET_PWR_DELAY 0   // minimum delay after changing pwr mode in uS
 
-#if TMC2130_MINIMUM_PULSE == 0
+#ifdef TMC2130_DEDGE_STEPPING
 #define TMC2130_MINIMUM_DELAY //NOP
+#elif TMC2130_MINIMUM_PULSE == 0
+#define TMC2130_MINIMUM_DELAY asm("nop")
 #else
 #define TMC2130_MINIMUM_DELAY delayMicroseconds(TMC2130_MINIMUM_PULSE)
 #endif

From fba83bd3091414bda8d0e1b220ab4f229610e436 Mon Sep 17 00:00:00 2001
From: 3d-gussner <3d.gussner@gmail.com>
Date: Wed, 27 Jan 2021 12:43:41 +0100
Subject: [PATCH 26/58] Add new flags -c -p -n

---
 PF-build.sh | 47 +++++++++++++++++++++++++++++++++++++----------
 1 file changed, 37 insertions(+), 10 deletions(-)

diff --git a/PF-build.sh b/PF-build.sh
index b7539578..5b0979e2 100755
--- a/PF-build.sh
+++ b/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_33
+# Version: 1.0.6-Build_36
 # 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
@@ -135,6 +135,7 @@
 #                          Update exit numbers 1-13 for prepare build env 21-29 for prepare compiling 30-36 compiling
 # 08 Jan 2021, 3d-gussner, Comment out 'sudo' auto installation
 #                          Add '-?' '-h' help option
+# 27 Jan 2021, 3d-gussner, Add `-c`, `-p` and `-n` options
 
 #### Start check if OSTYPE is supported
 OS_FOUND=$( command -v uname)
@@ -451,7 +452,7 @@ if type git > /dev/null; then
 	git_available="1"
 fi
 
-while getopts v:l:d:b:o:?h flag
+while getopts v:l:d:b:o:c:p:n:?h flag
 	do
 	    case "${flag}" in
 	        v) variant_flag=${OPTARG};;
@@ -459,6 +460,9 @@ while getopts v:l:d:b:o:?h flag
 	        d) devel_flag=${OPTARG};;
 			b) build_flag=${OPTARG};;
 			o) output_flag=${OPTARG};;
+			c) clean_flag=${OPTARG};;
+			p) prusa_flag=${OPTARG};;
+			n) new_build_flag=${OPTARG};;
 			?) help_flag=1;;
 			h) help_flag=1;;
 	    esac
@@ -469,6 +473,9 @@ while getopts v:l:d:b:o:?h flag
 #echo "build_flag: $build_flag";
 #echo "output_flag: $output_flag";
 #echo "help_flag: $help_flag"
+#echo "clean_flag: $clean_flag"
+#echo "prusa_flag: $prusa_flag"
+#echo "new_build_flag: $new_build_flag"
 
 #
 # '?' 'h' argument usage and help
@@ -482,19 +489,23 @@ echo "$(tput setaf 2)-l$(tput sgr0) Languages '$(tput setaf 2)ALL$(tput sgr0)' f
 echo "$(tput setaf 2)-d$(tput sgr0) Devel build '$(tput setaf 2)GOLD$(tput sgr0)', '$(tput setaf 2)RC$(tput sgr0)', '$(tput setaf 2)BETA$(tput sgr0)', '$(tput setaf 2)ALPHA$(tput sgr0)', '$(tput setaf 2)DEBUG$(tput sgr0)', '$(tput setaf 2)DEVEL$(tput sgr0)' and '$(tput setaf 2)UNKNOWN$(tput sgr0)'"
 echo "$(tput setaf 2)-b$(tput sgr0) Build/commit number '$(tput setaf 2)Auto$(tput sgr0)' needs git or a number"
 echo "$(tput setaf 2)-o$(tput sgr0) Output '$(tput setaf 2)1$(tput sgr0)' force or '$(tput setaf 2)0$(tput sgr0)' block output and delays"
+echo "$(tput setaf 2)-c$(tput sgr0) Do not clean up lang build'$(tput setaf 2)0$(tput sgr0)' no '$(tput setaf 2)1$(tput sgr0)' yes"
+echo "$(tput setaf 2)-p$(tput sgr0) Keep Configuration_prusa.h '$(tput setaf 2)0$(tput sgr0)' no '$(tput setaf 2)1$(tput sgr0)' yes"
+echo "$(tput setaf 2)-n$(tput sgr0) New fresh build '$(tput setaf 2)0$(tput sgr0)' no '$(tput setaf 2)1$(tput sgr0)' yes"
 echo "$(tput setaf 2)-?$(tput sgr0) Help"
 echo "$(tput setaf 2)-h$(tput sgr0) Help"
 echo 
 echo "Brief USAGE:"
-echo "  $(tput setaf 2)./PF-build.sh$(tput sgr0)  [-v] [-l] [-d] [-b] [-o]"
+echo "  $(tput setaf 2)./PF-build.sh$(tput sgr0)  [-v] [-l] [-d] [-b] [-o] [-c] [-p] [-n]"
 echo
 echo "Example:"
 echo "  $(tput setaf 2)./PF-build.sh -v All -l ALL -d GOLD$(tput sgr0)"
 echo "  Will build all variants as multi language and final GOLD version"
 echo
-echo "  $(tput setaf 2) ./PF-build.sh -v 1_75mm_MK3S-EINSy10a-E3Dv6full.h -b Auto -l ALL -d GOLD -o 1$(tput sgr0)"
+echo "  $(tput setaf 2) ./PF-build.sh -v 1_75mm_MK3S-EINSy10a-E3Dv6full.h -b Auto -l ALL -d GOLD -o 1 -c 1 -p 1 -n 1$(tput sgr0)"
 echo "  Will build MK3S multi language final GOLD firmware "
-echo "  with current commit count number and output extra information"
+echo "  with current commit count number and output extra information,"
+echo "  not delete lang build temporary files, keep Configuration_prusa.h and build with new fresh build folder."
 echo
 exit 
 
@@ -807,6 +818,12 @@ do
 	if [ $OUTPUT == "1" ] ; then
 		sleep 2
 	fi
+
+	#New fresh PF-Firmware-build
+	if [ "$new_build_flag" == "1" ]; then
+		rm -r -f $BUILD_PATH/* || exit 36
+	fi
+
 	#$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 30
 	echo "$(tput sgr 0)"
@@ -874,17 +891,21 @@ do
 			fi
 		fi
 		# Cleanup after build
-		echo "$(tput setaf 3)"
-		./fw-clean.sh || exit 34
-		./lang-clean.sh || exit 35
-		echo "$(tput sgr 0)"
+		if [[ -z "$clean_flag" || "$clean_flag" == "0" ]]; then
+			echo "$(tput setaf 3)"
+			./fw-clean.sh || exit 34
+			./lang-clean.sh || exit 35
+			echo "$(tput sgr 0)"
+		fi
 	else
 		echo "$(tput setaf 2)Copying English only firmware to PF-build-hex folder$(tput sgr 0)"
 		cp -f $BUILD_PATH/Firmware.ino.hex $SCRIPT_PATH/../$OUTPUT_FOLDER/FW$FW-Build$BUILD-$VARIANT-EN_ONLY.hex || exit 34
 	fi
 
 	# Cleanup Firmware
-	rm $SCRIPT_PATH/Firmware/Configuration_prusa.h || exit 36
+	if [[ -z "$prusa_flag" || "$prusa_flag" == "0" ]]; then
+		rm $SCRIPT_PATH/Firmware/Configuration_prusa.h || exit 36
+	fi
 	if find $SCRIPT_PATH/lang/ -name '*RAMBo10a*.txt' -printf 1 -quit | grep -q 1
 	then
 		rm $SCRIPT_PATH/lang/*RAMBo10a*.txt
@@ -901,6 +922,12 @@ do
 	then
 		rm $SCRIPT_PATH/lang/not_used.txt
 	fi
+
+	#New fresh PF-Firmware-build
+	if [ "$new_build_flag" == "1" ]; then
+		rm -r -f $BUILD_PATH/* || exit 36
+	fi
+
 	# Restore files to previous state
 	sed -i -- "s/^#define FW_DEV_VERSION FW_VERSION_$DEV_STATUS/#define FW_DEV_VERSION FW_VERSION_UNKNOWN/g" $SCRIPT_PATH/Firmware/Configuration.h
 	sed -i -- 's/^#define FW_REPOSITORY "Prusa3d"/#define FW_REPOSITORY "Unknown"/g' $SCRIPT_PATH/Firmware/Configuration.h

From e9d5c447322e899b0e7cfdc71146e4911e7a0b5a Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Fri, 29 Jan 2021 00:13:49 +0100
Subject: [PATCH 27/58] Also toggle pins efficiently in sm4.c

Use the same technique used in fastio to toggle pins efficiently in sm4
when DEDGE is used.
---
 Firmware/sm4.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Firmware/sm4.c b/Firmware/sm4.c
index b68e0276..c2f12824 100644
--- a/Firmware/sm4.c
+++ b/Firmware/sm4.c
@@ -130,7 +130,7 @@ void sm4_do_step(uint8_t axes_mask)
 {
 #if ((MOTHERBOARD == BOARD_RAMBO_MINI_1_0) || (MOTHERBOARD == BOARD_RAMBO_MINI_1_3) || (MOTHERBOARD == BOARD_EINSY_1_0a))
 #ifdef TMC2130_DEDGE_STEPPING
-	PORTC ^= (axes_mask & 0x0f); //set step signals by mask
+	PINC = (axes_mask & 0x0f); // toggle step signals by mask
 #else
     register uint8_t portC = PORTC & 0xf0;
 	PORTC = portC | (axes_mask & 0x0f); //set step signals by mask

From 30262b0a6eeecade45186a5d708f0c94d4cff20f Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Fri, 29 Jan 2021 17:30:04 +0100
Subject: [PATCH 28/58] Remove redundant definitions of CRITICAL_SECTION_*

Move CRITICAL_SECTION_START/END into fastio.h, where it's needed.
---
 Firmware/Marlin.h | 5 -----
 Firmware/fastio.h | 7 +++++++
 Firmware/tone04.c | 9 ---------
 3 files changed, 7 insertions(+), 14 deletions(-)

diff --git a/Firmware/Marlin.h b/Firmware/Marlin.h
index 697f2f72..f81abd8f 100755
--- a/Firmware/Marlin.h
+++ b/Firmware/Marlin.h
@@ -287,11 +287,6 @@ FORCE_INLINE unsigned long millis_nc() {
 void setPwmFrequency(uint8_t pin, int val);
 #endif
 
-#ifndef CRITICAL_SECTION_START
-  #define CRITICAL_SECTION_START  unsigned char _sreg = SREG; cli();
-  #define CRITICAL_SECTION_END    SREG = _sreg;
-#endif //CRITICAL_SECTION_START
-
 extern bool fans_check_enabled;
 extern float homing_feedrate[];
 extern uint8_t axis_relative_modes;
diff --git a/Firmware/fastio.h b/Firmware/fastio.h
index e4f25ed8..c4fee101 100644
--- a/Firmware/fastio.h
+++ b/Firmware/fastio.h
@@ -17,6 +17,13 @@
 #define MASK(PIN)  (1 << PIN)
 #endif
 
+#ifndef CRITICAL_SECTION_START
+  #define CRITICAL_SECTION_START  unsigned char _sreg = SREG; cli();
+  #define CRITICAL_SECTION_END    SREG = _sreg;
+  #include <avr/interrupt.h>
+#endif //CRITICAL_SECTION_START
+
+
 /*
   magic I/O routines
   now you can simply SET_OUTPUT(STEP); WRITE(STEP, 1); WRITE(STEP, 0);
diff --git a/Firmware/tone04.c b/Firmware/tone04.c
index 41f904a9..5c36a537 100644
--- a/Firmware/tone04.c
+++ b/Firmware/tone04.c
@@ -7,16 +7,7 @@
 
 #ifdef SYSTEM_TIMER_2
 
-#include <avr/io.h>
-#include <avr/interrupt.h>
 #include "pins.h"
-
-#ifndef CRITICAL_SECTION_START
-	#define CRITICAL_SECTION_START  unsigned char _sreg = SREG; cli();
-	#define CRITICAL_SECTION_END    SREG = _sreg;
-#endif //CRITICAL_SECTION_START
-
-
 #include "fastio.h"
 
 void timer4_init(void)

From 1fa7b8cd8d0f04b0332dd242283c57caf600d103 Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Fri, 29 Jan 2021 17:48:59 +0100
Subject: [PATCH 29/58] Move SDA/SCL pins into pins.h for fastio compatibility

fastio relies on macros for pin definitions, so we cannot use the const
declaration in Sd2PinMap or the arduino's definition.

Declare SDA/SCL_PIN into pins.h based on the current MCU, which is
identical in all our variants.

Remove the conflicting/unused declaration in Sd2PinMap.
---
 Firmware/Sd2PinMap.h | 6 +-----
 Firmware/pins.h      | 5 +++++
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/Firmware/Sd2PinMap.h b/Firmware/Sd2PinMap.h
index 8a608731..da50958f 100644
--- a/Firmware/Sd2PinMap.h
+++ b/Firmware/Sd2PinMap.h
@@ -37,10 +37,6 @@ struct pin_map_t {
 || defined(__AVR_ATmega2560__)
 // Mega
 
-// Two Wire (aka I2C) ports
-uint8_t const SDA_PIN = 20;  // D1
-uint8_t const SCL_PIN = 21;  // D0
-
 #undef MOSI_PIN
 #undef MISO_PIN
 // SPI port
@@ -365,4 +361,4 @@ static inline __attribute__((always_inline))
 #endif  // Sd2PinMap_h
 
 
-#endif
\ No newline at end of file
+#endif
diff --git a/Firmware/pins.h b/Firmware/pins.h
index 5d3b4f83..1c20a001 100644
--- a/Firmware/pins.h
+++ b/Firmware/pins.h
@@ -25,6 +25,11 @@
 #error Unknown MOTHERBOARD value in configuration.h
 #endif
 
+#if !defined(SDA_PIN) && (defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__))
+#define SDA_PIN 20
+#define SCL_PIN 21
+#endif
+
 //List of pins which to ignore when asked to change by gcode, 0 and 1 are RX and TX, do not mess with those!
 #define _E0_PINS E0_STEP_PIN, E0_DIR_PIN, E0_ENABLE_PIN, HEATER_0_PIN,
 #if EXTRUDERS > 1

From 2d71a071f0d4f63c4dbc2bfa56294c497c5988da Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Fri, 29 Jan 2021 17:51:38 +0100
Subject: [PATCH 30/58] Switch twi.c to fastio

---
 Firmware/twi.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/Firmware/twi.c b/Firmware/twi.c
index 6dd1645c..e8c9a378 100644
--- a/Firmware/twi.c
+++ b/Firmware/twi.c
@@ -19,17 +19,18 @@
   Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts
 */
 
-#include <math.h>
-#include "Arduino.h" // for digitalWrite
 
+#include <math.h>
+#include "config.h"
+#include "fastio.h"
 #include "twi.h"
 
 
 void twi_init(void)
 {
   // activate internal pullups for twi.
-  digitalWrite(SDA, 1);
-  digitalWrite(SCL, 1);
+  WRITE(SDA_PIN, 1);
+  WRITE(SCL_PIN, 1);
 
   // initialize twi prescaler and bit rate
   TWSR &= ~(_BV(TWPS0) | _BV(TWPS1));
@@ -44,8 +45,8 @@ void twi_init(void)
 void twi_disable(void)
 {
   // deactivate internal pullups for twi.
-  digitalWrite(SDA, 0);
-  digitalWrite(SCL, 0);
+  WRITE(SDA_PIN, 0);
+  WRITE(SCL_PIN, 0);
 }
 
 

From b8b75186fe96a695521402edc1dd015dfc684ffa Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Fri, 29 Jan 2021 18:30:16 +0100
Subject: [PATCH 31/58] Remove the extra copy of CRITICAL_SECTION from fastio

---
 Firmware/fastio.h | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/Firmware/fastio.h b/Firmware/fastio.h
index 94a029a6..855c000e 100644
--- a/Firmware/fastio.h
+++ b/Firmware/fastio.h
@@ -9,12 +9,6 @@
 #include <avr/io.h>
 #include "macros.h"
 
-#ifndef CRITICAL_SECTION_START
-  #define CRITICAL_SECTION_START  unsigned char _sreg = SREG; cli();
-  #define CRITICAL_SECTION_END    SREG = _sreg;
-  #include <avr/interrupt.h>
-#endif //CRITICAL_SECTION_START
-
 
 /*
   magic I/O routines

From 6b6205d2f6a0ddf5045886ba89aa53ce55ab635f Mon Sep 17 00:00:00 2001
From: Voinea Dragos <voinea.dragos.alexandru@gmail.com>
Date: Sun, 31 Jan 2021 15:06:20 +0200
Subject: [PATCH 32/58] M27 refactoring and M27 L initial implementation

---
 Firmware/Marlin_main.cpp |  2 +-
 Firmware/cardreader.cpp  | 55 ++++++++++++++++++++++------------------
 Firmware/cardreader.h    |  2 +-
 3 files changed, 33 insertions(+), 26 deletions(-)

diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp
index 4739dc4a..a1671848 100755
--- a/Firmware/Marlin_main.cpp
+++ b/Firmware/Marlin_main.cpp
@@ -5818,7 +5818,7 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
 	### 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();
+      card.getStatus(code_seen('L'));
       break;
 
     /*!
diff --git a/Firmware/cardreader.cpp b/Firmware/cardreader.cpp
index e228c523..2140a09a 100644
--- a/Firmware/cardreader.cpp
+++ b/Firmware/cardreader.cpp
@@ -502,31 +502,38 @@ uint32_t CardReader::getFileSize()
 	return filesize;
 }
 
-void CardReader::getStatus()
+void CardReader::getStatus(bool arg_L)
 {
-  if(sdprinting)
-  {
-      if (isPrintPaused) {
-          SERIAL_PROTOCOLLNPGM("SD print paused");
-      }
-      else if (saved_printing) {
-          SERIAL_PROTOCOLLNPGM("Print saved");
-      }
-      else {
-          SERIAL_PROTOCOLLN(LONGEST_FILENAME);
-          SERIAL_PROTOCOLRPGM(_N("SD printing byte "));////MSG_SD_PRINTING_BYTE
-          SERIAL_PROTOCOL(sdpos);
-          SERIAL_PROTOCOL('/');
-          SERIAL_PROTOCOLLN(filesize);
-          uint16_t time = ( _millis() - starttime ) / 60000U;
-          SERIAL_PROTOCOL(itostr2(time/60));
-          SERIAL_PROTOCOL(':');
-          SERIAL_PROTOCOLLN(itostr2(time%60));
-      }
-  }
-  else {
-    SERIAL_PROTOCOLLNPGM("Not SD printing");
-  }
+    if (isPrintPaused)
+    {
+        if (saved_printing && (saved_printing_type == PRINTING_TYPE_SD))
+            SERIAL_PROTOCOLLNPGM("SD print paused");
+        else
+            SERIAL_PROTOCOLLNPGM("Print saved");
+    }
+    else if (sdprinting)
+    {
+        if (arg_L)
+        {
+            SERIAL_PROTOCOL('/');
+            for (uint8_t i = 0; i < getWorkDirDepth(); i++)
+                printf_P(PSTR("%s/"), dir_names[i]);
+            puts(filename);
+        }
+        else
+            SERIAL_PROTOCOLLN(LONGEST_FILENAME);
+        
+        SERIAL_PROTOCOLRPGM(_N("SD printing byte "));////MSG_SD_PRINTING_BYTE
+        SERIAL_PROTOCOL(sdpos);
+        SERIAL_PROTOCOL('/');
+        SERIAL_PROTOCOLLN(filesize);
+        uint16_t time = ( _millis() - starttime ) / 60000U;
+        SERIAL_PROTOCOL(itostr2(time/60));
+        SERIAL_PROTOCOL(':');
+        SERIAL_PROTOCOLLN(itostr2(time%60));
+    }
+    else
+        SERIAL_PROTOCOLLNPGM("Not SD printing");
 }
 void CardReader::write_command(char *buf)
 {
diff --git a/Firmware/cardreader.h b/Firmware/cardreader.h
index 25e97882..40098d3c 100644
--- a/Firmware/cardreader.h
+++ b/Firmware/cardreader.h
@@ -26,7 +26,7 @@ public:
   void release();
   void startFileprint();
   uint32_t getFileSize();
-  void getStatus();
+  void getStatus(bool arg_L);
   void printingHasFinished();
 
   void getfilename(uint16_t nr, const char* const match=NULL);

From 698499f00df6bc7797cdf8bca212661cfd79f8da Mon Sep 17 00:00:00 2001
From: Voinea Dragos <voinea.dragos.alexandru@gmail.com>
Date: Sun, 31 Jan 2021 17:18:32 +0200
Subject: [PATCH 33/58] split timer0 and timer2 initialization. Move timer2
 init early

---
 Firmware/Marlin_main.cpp |  2 ++
 Firmware/temperature.cpp |  5 ++++-
 Firmware/timer02.c       | 20 ++++++++++++--------
 Firmware/timer02.h       |  3 +++
 4 files changed, 21 insertions(+), 9 deletions(-)

diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp
index d43e05e5..68ecb1c1 100755
--- a/Firmware/Marlin_main.cpp
+++ b/Firmware/Marlin_main.cpp
@@ -1013,6 +1013,8 @@ static void w25x20cl_err_msg()
 // are initialized by the main() routine provided by the Arduino framework.
 void setup()
 {
+	timer2_init(); // enables functional millis
+
 	mmu_init();
 
 	ultralcd_init();
diff --git a/Firmware/temperature.cpp b/Firmware/temperature.cpp
index 3b38c25c..a1281b64 100755
--- a/Firmware/temperature.cpp
+++ b/Firmware/temperature.cpp
@@ -1124,7 +1124,10 @@ void tp_init()
 
   adc_init();
 
-  timer0_init();
+  timer0_init(); //enables the heatbed timer.
+
+  // timer2 already enabled earlier in the code
+  // now enable the COMPB temperature interrupt
   OCR2B = 128;
   TIMSK2 |= (1<<OCIE2B);
   
diff --git a/Firmware/timer02.c b/Firmware/timer02.c
index a866fa25..47f7d2a2 100644
--- a/Firmware/timer02.c
+++ b/Firmware/timer02.c
@@ -9,13 +9,11 @@
 
 #include <avr/io.h>
 #include <avr/interrupt.h>
+#include "macros.h"
 
 void timer0_init(void)
 {
-	//save sreg
-	uint8_t _sreg = SREG;
-	//disable interrupts for sure
-	cli();
+	CRITICAL_SECTION_START;
 
 	TCNT0  = 0;
 	// Fast PWM duty (0-255). 
@@ -25,7 +23,14 @@ void timer0_init(void)
 	TCCR0A = (1 << WGM01) | (1 << WGM00) | (1 << COM0B1) | (1 << COM0B0);  
 	TCCR0B = (1 << CS01);    // CLK/8 prescaling
 	TIMSK0 |= (1 << TOIE0);  // enable timer overflow interrupt
-	
+
+	CRITICAL_SECTION_END;
+}
+
+void timer2_init(void)
+{
+	CRITICAL_SECTION_START;
+
 	// Everything, that used to be on timer0 was moved to timer2 (delay, beeping, millis etc.)
 	//setup timer2
 	TCCR2A = 0x00; //COM_A-B=00, WGM_0-1=00
@@ -36,9 +41,8 @@ void timer0_init(void)
 	TIMSK2 &= ~(1<<OCIE2B);
 	//set timer2 OCR registers (OCRB interrupt generated 0.5ms after OVF interrupt)
 	OCR2A = 0;
-	OCR2B = 128;
-	//restore sreg (enable interrupts)
-	SREG = _sreg;
+
+	CRITICAL_SECTION_END;
 }
 
 
diff --git a/Firmware/timer02.h b/Firmware/timer02.h
index 2eef98f6..3aaa5236 100644
--- a/Firmware/timer02.h
+++ b/Firmware/timer02.h
@@ -14,6 +14,9 @@ extern "C" {
 ///! Initializes TIMER0 for fast PWM mode-driven bed heating
 extern void timer0_init(void);
 
+///! Initializes TIMER2 for time keeping and temperature interrupt
+extern void timer2_init(void);
+
 ///! Reimplemented original millis() using timer2
 extern unsigned long millis2(void);
 

From 30131c9ab5b8594219f665470664c1fdc42d8bad Mon Sep 17 00:00:00 2001
From: Voinea Dragos <voinea.dragos.alexandru@gmail.com>
Date: Sun, 31 Jan 2021 16:56:58 +0200
Subject: [PATCH 34/58] Patch broken string PROGMEM transition with
 setTargetedHotend() error

---
 Firmware/Marlin_main.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp
index 4739dc4a..1feb6944 100755
--- a/Firmware/Marlin_main.cpp
+++ b/Firmware/Marlin_main.cpp
@@ -10026,16 +10026,16 @@ bool setTargetedHotend(int code, uint8_t &extruder)
           SERIAL_ECHORPGM(_n("M104 Invalid extruder "));////MSG_M104_INVALID_EXTRUDER
           break;
         case 105:
-          SERIAL_ECHO(_n("M105 Invalid extruder "));////MSG_M105_INVALID_EXTRUDER
+          SERIAL_ECHORPGM(_n("M105 Invalid extruder "));////MSG_M105_INVALID_EXTRUDER
           break;
         case 109:
-          SERIAL_ECHO(_n("M109 Invalid extruder "));////MSG_M109_INVALID_EXTRUDER
+          SERIAL_ECHORPGM(_n("M109 Invalid extruder "));////MSG_M109_INVALID_EXTRUDER
           break;
         case 218:
-          SERIAL_ECHO(_n("M218 Invalid extruder "));////MSG_M218_INVALID_EXTRUDER
+          SERIAL_ECHORPGM(_n("M218 Invalid extruder "));////MSG_M218_INVALID_EXTRUDER
           break;
         case 221:
-          SERIAL_ECHO(_n("M221 Invalid extruder "));////MSG_M221_INVALID_EXTRUDER
+          SERIAL_ECHORPGM(_n("M221 Invalid extruder "));////MSG_M221_INVALID_EXTRUDER
           break;
       }
       SERIAL_PROTOCOLLN((int)extruder);

From ec4c1be0582a3ba3a5109a3328c953d8a1847d67 Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Fri, 29 Jan 2021 16:34:09 +0100
Subject: [PATCH 35/58] Silence bUpdateEEPROM unused warning in MK3 variant

---
 Firmware/fsensor.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Firmware/fsensor.cpp b/Firmware/fsensor.cpp
index 7c225bf2..4eac7bd0 100755
--- a/Firmware/fsensor.cpp
+++ b/Firmware/fsensor.cpp
@@ -233,6 +233,8 @@ void fsensor_init(void)
 bool fsensor_enable(bool bUpdateEEPROM)
 {
 #ifdef PAT9125
+    (void)bUpdateEEPROM; // silence unused warning in this variant
+
 	if (mmu_enabled == false) { //filament sensor is pat9125, enable only if it is working
 		uint8_t pat9125 = pat9125_init();
 		printf_P(PSTR("PAT9125_init:%hhu\n"), pat9125);

From b6d56bc0f401928e80811c866ec303e198d7eb65 Mon Sep 17 00:00:00 2001
From: Alex Voinea <voinea.dragos.alexandru@gmail.com>
Date: Mon, 1 Feb 2021 14:54:37 +0200
Subject: [PATCH 36/58] Change M27 argument from L to P as that makes more
 sense (path vs LFN))

---
 Firmware/Marlin_main.cpp | 2 +-
 Firmware/cardreader.cpp  | 4 ++--
 Firmware/cardreader.h    | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp
index a1671848..62ec6f67 100755
--- a/Firmware/Marlin_main.cpp
+++ b/Firmware/Marlin_main.cpp
@@ -5818,7 +5818,7 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
 	### 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(code_seen('L'));
+      card.getStatus(code_seen('P'));
       break;
 
     /*!
diff --git a/Firmware/cardreader.cpp b/Firmware/cardreader.cpp
index 2140a09a..a9626897 100644
--- a/Firmware/cardreader.cpp
+++ b/Firmware/cardreader.cpp
@@ -502,7 +502,7 @@ uint32_t CardReader::getFileSize()
 	return filesize;
 }
 
-void CardReader::getStatus(bool arg_L)
+void CardReader::getStatus(bool arg_P)
 {
     if (isPrintPaused)
     {
@@ -513,7 +513,7 @@ void CardReader::getStatus(bool arg_L)
     }
     else if (sdprinting)
     {
-        if (arg_L)
+        if (arg_P)
         {
             SERIAL_PROTOCOL('/');
             for (uint8_t i = 0; i < getWorkDirDepth(); i++)
diff --git a/Firmware/cardreader.h b/Firmware/cardreader.h
index 40098d3c..52445400 100644
--- a/Firmware/cardreader.h
+++ b/Firmware/cardreader.h
@@ -26,7 +26,7 @@ public:
   void release();
   void startFileprint();
   uint32_t getFileSize();
-  void getStatus(bool arg_L);
+  void getStatus(bool arg_P);
   void printingHasFinished();
 
   void getfilename(uint16_t nr, const char* const match=NULL);

From 7e09df6a340972cc9738699ee2a88977d3439534 Mon Sep 17 00:00:00 2001
From: Alex Voinea <voinea.dragos.alexandru@gmail.com>
Date: Mon, 1 Feb 2021 14:54:44 +0200
Subject: [PATCH 37/58] Add documentation

---
 Firmware/Marlin_main.cpp | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp
index 62ec6f67..652466d7 100755
--- a/Firmware/Marlin_main.cpp
+++ b/Firmware/Marlin_main.cpp
@@ -5816,6 +5816,12 @@ if(eSoundMode!=e_SOUND_MODE_SILENT)
 
     /*!
 	### M27 - Get SD status <a href="https://reprap.org/wiki/G-code#M27:_Report_SD_print_status">M27: Report SD print status</a>
+    #### Usage
+	
+	      M27 [ P ]
+	
+	#### Parameters
+	  - `P` - Show full SFN path instead of LFN only.
     */
     case 27:
       card.getStatus(code_seen('P'));

From 2f4119a6d723fc1e0e7b148aed73101cb89c5369 Mon Sep 17 00:00:00 2001
From: Alex Voinea <voinea.dragos.alexandru@gmail.com>
Date: Tue, 2 Feb 2021 13:21:16 +0200
Subject: [PATCH 38/58] M552 - Printer IP address

---
 Firmware/Marlin.h        |  2 ++
 Firmware/Marlin_main.cpp | 19 +++++++++++++++++++
 Firmware/ultralcd.cpp    | 31 +++++++++++++++++++------------
 Firmware/util.cpp        |  7 +++++++
 Firmware/util.h          |  3 +++
 5 files changed, 50 insertions(+), 12 deletions(-)

diff --git a/Firmware/Marlin.h b/Firmware/Marlin.h
index 307b8c91..17fce271 100755
--- a/Firmware/Marlin.h
+++ b/Firmware/Marlin.h
@@ -501,4 +501,6 @@ void raise_z_above(float target, bool plan=true);
 
 extern "C" void softReset();
 
+extern uint32_t IP_address;
+
 #endif
diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp
index 9deb5105..61e5a33c 100755
--- a/Firmware/Marlin_main.cpp
+++ b/Firmware/Marlin_main.cpp
@@ -321,6 +321,8 @@ uint16_t print_time_remaining_normal = PRINT_TIME_REMAINING_INIT; //estimated re
 uint8_t print_percent_done_silent = PRINT_PERCENT_DONE_INIT;
 uint16_t print_time_remaining_silent = PRINT_TIME_REMAINING_INIT; //estimated remaining print time in minutes
 
+uint32_t IP_address = 0;
+
 //===========================================================================
 //=============================Private Variables=============================
 //===========================================================================
@@ -8003,6 +8005,23 @@ Sigma_Exit:
       break;
     }
     #endif // CUSTOM_M_CODE_SET_Z_PROBE_OFFSET
+    case 552:
+    {
+        if (code_seen('P'))
+        {
+            uint8_t valCnt = 0;
+            IP_address = 0;
+            do
+            {
+                *strchr_pointer = '*';
+                ((uint8_t*)&IP_address)[valCnt] = code_value_short();
+                valCnt++;
+            } while ((valCnt < 4) && code_seen('.'));
+            
+            if (valCnt != 4)
+                IP_address = 0;
+        }
+    } break;
 
     #ifdef FILAMENTCHANGEENABLE
 
diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp
index d7976d27..0f6bc1fa 100755
--- a/Firmware/ultralcd.cpp
+++ b/Firmware/ultralcd.cpp
@@ -2057,8 +2057,8 @@ static void lcd_support_menu()
 	{	// 22bytes total
 		int8_t status;                 // 1byte
 		bool is_flash_air;             // 1byte
-		uint8_t ip[4];                 // 4bytes
-		char ip_str[3*4+3+1];          // 16bytes
+		uint32_t ip;                   // 4bytes
+		char ip_str[IP4_STR_SIZE];     // 16bytes
 	} _menu_data_t;
     static_assert(sizeof(menu_data)>= sizeof(_menu_data_t),"_menu_data_t doesn't fit into menu_data");
 	_menu_data_t* _md = (_menu_data_t*)&(menu_data[0]);
@@ -2069,17 +2069,10 @@ static void lcd_support_menu()
         _md->status = 1;
         _md->is_flash_air = card.ToshibaFlashAir_isEnabled();
         if (_md->is_flash_air) {
-            card.ToshibaFlashAir_GetIP(_md->ip); // ip[4] filled with 0 if it failed
-            // Prepare IP string from ip[4]
-            sprintf_P(_md->ip_str, PSTR("%d.%d.%d.%d"), 
-                _md->ip[0], _md->ip[1], 
-                _md->ip[2], _md->ip[3]);
+            card.ToshibaFlashAir_GetIP((uint8_t*)(&_md->ip)); // ip == 0 if it failed
         }
-    } else if (_md->is_flash_air && 
-        _md->ip[0] == 0 && _md->ip[1] == 0 && 
-        _md->ip[2] == 0 && _md->ip[3] == 0 &&
-        ++ _md->status == 16)
-	{
+    } else if (_md->is_flash_air && _md->ip == 0 && ++ _md->status == 16)
+    {
         // Waiting for the FlashAir card to get an IP address from a router. Force an update.
         _md->status = 0;
     }
@@ -2143,6 +2136,20 @@ static void lcd_support_menu()
       MENU_ITEM_BACK_P(PSTR(" "));
       if (((menu_item - 1) == menu_line) && lcd_draw_update) {
           lcd_set_cursor(2, menu_row);
+          ip4_to_str(_md->ip_str, (uint8_t*)(&_md->ip));
+          lcd_printf_P(PSTR("%s"), _md->ip_str);
+      }
+  }
+  
+  // Show the printer IP address, if it is available.
+  if (IP_address) {
+      
+      MENU_ITEM_BACK_P(STR_SEPARATOR);
+      MENU_ITEM_BACK_P(PSTR("Printer IP Addr:"));  //c=18 r=1
+      MENU_ITEM_BACK_P(PSTR(" "));
+      if (((menu_item - 1) == menu_line) && lcd_draw_update) {
+          lcd_set_cursor(2, menu_row);
+          ip4_to_str(_md->ip_str, (uint8_t*)(&IP_address));
           lcd_printf_P(PSTR("%s"), _md->ip_str);
       }
   }
diff --git a/Firmware/util.cpp b/Firmware/util.cpp
index e335793a..a25efd35 100644
--- a/Firmware/util.cpp
+++ b/Firmware/util.cpp
@@ -4,6 +4,7 @@
 #include "sound.h"
 #include "language.h"
 #include "util.h"
+#include <avr/pgmspace.h>
 
 // Allocate the version string in the program memory. Otherwise the string lands either on the stack or in the global RAM.
 const char FW_VERSION_STR[] PROGMEM = FW_VERSION;
@@ -604,3 +605,9 @@ else {
      sPrinterName=_sPrinterName;
      }
 }
+
+
+void ip4_to_str(char* dest, uint8_t* IP)
+{
+    sprintf_P(dest, PSTR("%u.%u.%u.%u"), IP[0], IP[1], IP[2], IP[3]);
+}
diff --git a/Firmware/util.h b/Firmware/util.h
index f25749de..6d34aa08 100644
--- a/Firmware/util.h
+++ b/Firmware/util.h
@@ -110,4 +110,7 @@ void gcode_level_check(uint16_t nGcodeLevel);
 
 void fSetMmuMode(bool bMMu);
 
+#define IP4_STR_SIZE 16
+extern void ip4_to_str(char* dest, uint8_t* IP);
+
 #endif /* UTIL_H */

From 647cde0caeb3365e66d65cf1d558168c2ae2dc29 Mon Sep 17 00:00:00 2001
From: Alex Voinea <voinea.dragos.alexandru@gmail.com>
Date: Tue, 2 Feb 2021 13:38:20 +0200
Subject: [PATCH 39/58] Add documentation

---
 Firmware/Marlin_main.cpp | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp
index 61e5a33c..777a05ff 100755
--- a/Firmware/Marlin_main.cpp
+++ b/Firmware/Marlin_main.cpp
@@ -3734,6 +3734,7 @@ extern uint8_t st_backlash_y;
 //!@n M503 - print the current settings (from memory not from EEPROM)
 //!@n M509 - force language selection on next restart
 //!@n M540 - Use S[0|1] to enable or disable the stop SD card print on endstop hit (requires ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED)
+//!@n M552 - Set IP address
 //!@n M600 - Pause for filament change X[pos] Y[pos] Z[relative lift] E[initial retract] L[later retract distance for removal]
 //!@n M605 - Set dual x-carriage movement mode: S<mode> [ X<duplication x-offset> R<duplication temp offset> ]
 //!@n M860 - Wait for PINDA thermistor to reach target temperature.
@@ -8005,6 +8006,19 @@ Sigma_Exit:
       break;
     }
     #endif // CUSTOM_M_CODE_SET_Z_PROBE_OFFSET
+
+	/*!
+	### M552 - Set IP address <a href="https://reprap.org/wiki/G-code#M552:_Set_IP_address.2C_enable.2Fdisable_network_interface">M552: Set IP address, enable/disable network interface"</a>
+    Sets the printer IP address that is shown in the support menu. Designed to be used with the help of host software.
+    If P is not specified nothing happens.
+    If the structure of the IP address is invalid, 0.0.0.0 is assumed and nothing is shown on the screen in the Support menu.
+    #### Usage
+    
+        M552 [ P<IP_address> ]
+    
+    #### Parameters
+    - `P` - The IP address in xxx.xxx.xxx.xxx format. Eg: P192.168.1.14
+	*/
     case 552:
     {
         if (code_seen('P'))

From 5c9d202871c0bdb63323b77d5ed88827588d9533 Mon Sep 17 00:00:00 2001
From: Alex Voinea <voinea.dragos.alexandru@gmail.com>
Date: Tue, 2 Feb 2021 19:08:19 +0200
Subject: [PATCH 40/58] Change MAX_DIR_DEPTH from 10 to 6

You can't run M23 with so many directories as the length of the command will exceed the maximum allowed by cmdqueue
---
 Firmware/cardreader.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Firmware/cardreader.h b/Firmware/cardreader.h
index 52445400..9bf9bd0a 100644
--- a/Firmware/cardreader.h
+++ b/Firmware/cardreader.h
@@ -3,7 +3,7 @@
 
 #ifdef SDSUPPORT
 
-#define MAX_DIR_DEPTH 10
+#define MAX_DIR_DEPTH 6
 
 #include "SdFile.h"
 enum LsAction {LS_SerialPrint,LS_SerialPrint_LFN,LS_Count,LS_GetFilename};

From f6ae3790770d39d3df71911c5112485edc04582b Mon Sep 17 00:00:00 2001
From: Alex Voinea <voinea.dragos.alexandru@gmail.com>
Date: Tue, 2 Feb 2021 19:08:44 +0200
Subject: [PATCH 41/58] Fix dir_names array definition. Prevents overrun

---
 Firmware/Marlin.h        | 2 +-
 Firmware/Marlin_main.cpp | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/Firmware/Marlin.h b/Firmware/Marlin.h
index 17fce271..aa057bc5 100755
--- a/Firmware/Marlin.h
+++ b/Firmware/Marlin.h
@@ -352,7 +352,7 @@ extern bool mesh_bed_run_from_menu;
 
 extern bool sortAlpha;
 
-extern char dir_names[3][9];
+extern char dir_names[MAX_DIR_DEPTH][9];
 
 extern int8_t lcd_change_fil_state;
 // save/restore printing
diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp
index 777a05ff..4e0511c1 100755
--- a/Firmware/Marlin_main.cpp
+++ b/Firmware/Marlin_main.cpp
@@ -228,7 +228,7 @@ bool fan_state[2];
 int fan_edge_counter[2];
 int fan_speed[2];
 
-char dir_names[3][9];
+char dir_names[MAX_DIR_DEPTH][9];
 
 bool sortAlpha = false;
 

From 896f4e1dd1b55bc14e77cd63996aab87267a4464 Mon Sep 17 00:00:00 2001
From: Alex Voinea <voinea.dragos.alexandru@gmail.com>
Date: Tue, 2 Feb 2021 19:14:05 +0200
Subject: [PATCH 42/58] Fix compile error

---
 Firmware/Marlin.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Firmware/Marlin.h b/Firmware/Marlin.h
index aa057bc5..1ed5e0bd 100755
--- a/Firmware/Marlin.h
+++ b/Firmware/Marlin.h
@@ -352,7 +352,7 @@ extern bool mesh_bed_run_from_menu;
 
 extern bool sortAlpha;
 
-extern char dir_names[MAX_DIR_DEPTH][9];
+extern char dir_names[][9];
 
 extern int8_t lcd_change_fil_state;
 // save/restore printing

From 1c76152e62e9aa6fd3dafbc8eecb800cab6003f6 Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Sun, 20 Sep 2020 18:15:27 +0200
Subject: [PATCH 43/58] Implement separate travel acceleration (M204 T)

Allow to separate extrusion and travel acceleration settings using M204,
as Marlin 1.1.x and 2.x does using M204 T.

This allows to reduce the number of instructions required during
printing, since resetting the acceleration for travel moves is no longer
required and can be done a single time during the print.

Provision for this parameter was pre-existing, but not implemented.
M204 has two forms: the lagacy format (Marlin <1.1):

  M204 S[print-acc] T[retract-acc]

and the newer format:

  M204 P[print-acc] R[retract-acc] T[travel-acc]

The distinction in the MK3 FW is done based on the presence of the P
parameter. If P is seen, the new format is adoped. In the new format
however, M204 T was ignored until this change.

To keep backward compatibility, M204 S[acc] will set both print and
travel acceleration, which is identical in behavior to recent versions
of Marlin.
---
 Firmware/ConfigurationStore.cpp |  3 ++-
 Firmware/ConfigurationStore.h   |  1 +
 Firmware/Marlin_main.cpp        | 11 +++--------
 Firmware/planner.cpp            |  3 ++-
 4 files changed, 8 insertions(+), 10 deletions(-)

diff --git a/Firmware/ConfigurationStore.cpp b/Firmware/ConfigurationStore.cpp
index 0bd13a3a..009a9024 100644
--- a/Firmware/ConfigurationStore.cpp
+++ b/Firmware/ConfigurationStore.cpp
@@ -184,7 +184,7 @@ static_assert (false, "zprobe_zoffset was not initialized in printers in field t
         "0.0, if this is not acceptable, increment EEPROM_VERSION to force use default_conf");
 #endif
 
-static_assert (sizeof(M500_conf) == 192, "sizeof(M500_conf) has changed, ensure that EEPROM_VERSION has been incremented, "
+static_assert (sizeof(M500_conf) == 196, "sizeof(M500_conf) has changed, ensure that EEPROM_VERSION has been incremented, "
         "or if you added members in the end of struct, ensure that historically uninitialized values will be initialized."
         "If this is caused by change to more then 8bit processor, decide whether make this struct packed to save EEPROM,"
         "leave as it is to keep fast code, or reorder struct members to pack more tightly.");
@@ -232,6 +232,7 @@ static const M500_conf default_conf PROGMEM =
 #else // TMC2130
     {16,16,16,16},
 #endif
+    DEFAULT_TRAVEL_ACCELERATION,
 };
 
 //! @brief Read M500 configuration
diff --git a/Firmware/ConfigurationStore.h b/Firmware/ConfigurationStore.h
index b9dca368..3e3caf72 100644
--- a/Firmware/ConfigurationStore.h
+++ b/Firmware/ConfigurationStore.h
@@ -38,6 +38,7 @@ typedef struct
     float max_feedrate_silent[4]; //!< max speeds for silent mode
     unsigned long max_acceleration_units_per_sq_second_silent[4];
     unsigned char axis_ustep_resolution[4];
+    float travel_acceleration; //!< travel acceleration mm/s^2
 } M500_conf;
 
 extern M500_conf cs;
diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp
index 4e0511c1..f25b5aeb 100755
--- a/Firmware/Marlin_main.cpp
+++ b/Firmware/Marlin_main.cpp
@@ -7258,7 +7258,7 @@ Sigma_Exit:
           // Legacy acceleration format. This format is used by the legacy Marlin, MK2 or MK3 firmware,
           // and it is also generated by Slic3r to control acceleration per extrusion type
           // (there is a separate acceleration settings in Slicer for perimeter, first layer etc).
-          cs.acceleration = code_value();
+          cs.acceleration = cs.travel_acceleration = code_value();
           // Interpret the T value as retract acceleration in the old Marlin format.
           if(code_seen('T'))
             cs.retract_acceleration = code_value();
@@ -7268,13 +7268,8 @@ Sigma_Exit:
             cs.acceleration = code_value();
           if(code_seen('R'))
             cs.retract_acceleration = code_value();
-          if(code_seen('T')) {
-            // Interpret the T value as the travel acceleration in the new Marlin format.
-            /*!
-            @todo Prusa3D firmware currently does not support travel acceleration value independent from the extruding acceleration value.
-            */
-            // travel_acceleration = code_value();
-          }
+          if(code_seen('T'))
+            cs.travel_acceleration = code_value();
         }
       }
       break;
diff --git a/Firmware/planner.cpp b/Firmware/planner.cpp
index 2615ef66..ba3791ae 100644
--- a/Firmware/planner.cpp
+++ b/Firmware/planner.cpp
@@ -1082,7 +1082,8 @@ Having the real displacement of the head, we can calculate the total movement le
   }
   else
   {
-    block->acceleration_st = ceil(cs.acceleration * steps_per_mm); // convert to: acceleration steps/sec^2
+    float acceleration = (block->steps_e.wide == 0? cs.travel_acceleration: cs.acceleration);
+    block->acceleration_st = ceil(acceleration * steps_per_mm); // convert to: acceleration steps/sec^2
 
     #ifdef LIN_ADVANCE
     /**

From 5589954b77dd35042ed743f8aa8d94c2d717d44f Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Sun, 20 Sep 2020 19:03:05 +0200
Subject: [PATCH 44/58] Add DEFAULT_TRAVEL_ACCELERATION in all variants

Use the same value as DEFAULT_ACCELERATION for compatibility.
---
 Firmware/variants/1_75mm_MK2-RAMBo10a-E3Dv6full.h   | 3 ++-
 Firmware/variants/1_75mm_MK2-RAMBo13a-E3Dv6full.h   | 3 ++-
 Firmware/variants/1_75mm_MK25-RAMBo10a-E3Dv6full.h  | 5 +++--
 Firmware/variants/1_75mm_MK25-RAMBo13a-E3Dv6full.h  | 5 +++--
 Firmware/variants/1_75mm_MK25S-RAMBo10a-E3Dv6full.h | 5 +++--
 Firmware/variants/1_75mm_MK25S-RAMBo13a-E3Dv6full.h | 5 +++--
 Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h   | 5 +++--
 Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h  | 5 +++--
 8 files changed, 22 insertions(+), 14 deletions(-)

diff --git a/Firmware/variants/1_75mm_MK2-RAMBo10a-E3Dv6full.h b/Firmware/variants/1_75mm_MK2-RAMBo10a-E3Dv6full.h
index a74b6948..4c20082e 100644
--- a/Firmware/variants/1_75mm_MK2-RAMBo10a-E3Dv6full.h
+++ b/Firmware/variants/1_75mm_MK2-RAMBo10a-E3Dv6full.h
@@ -90,8 +90,9 @@ AXIS SETTINGS
 #define DEFAULT_MAX_ACCELERATION      {9000,9000,500,10000}    // X, Y, Z, E maximum start speed for accelerated moves. E default values are good for Skeinforge 40+, for older versions raise them a lot.
 #define DEFAULT_MAX_ACCELERATION_SILENT     {960, 960, 200, 5000}    // (mm/sec^2) max acceleration (M201), silent mode
 
-#define DEFAULT_ACCELERATION          1500    // X, Y, Z and E max acceleration in mm/s^2 for printing moves
+#define DEFAULT_ACCELERATION          1500   // X, Y, Z and E max acceleration in mm/s^2 for printing moves
 #define DEFAULT_RETRACT_ACCELERATION  1500   // X, Y, Z and E max acceleration in mm/s^2 for retracts
+#define DEFAULT_TRAVEL_ACCELERATION   1500   // X, Y, Z and E max acceleration in mm/s^2 for travels
 
 
 #define MANUAL_FEEDRATE {3000, 3000, 1000, 100}   // set the speeds for manual moves (mm/min)
diff --git a/Firmware/variants/1_75mm_MK2-RAMBo13a-E3Dv6full.h b/Firmware/variants/1_75mm_MK2-RAMBo13a-E3Dv6full.h
index 72ac605f..35313a41 100644
--- a/Firmware/variants/1_75mm_MK2-RAMBo13a-E3Dv6full.h
+++ b/Firmware/variants/1_75mm_MK2-RAMBo13a-E3Dv6full.h
@@ -90,8 +90,9 @@ AXIS SETTINGS
 #define DEFAULT_MAX_ACCELERATION      {9000,9000,500,10000}    // X, Y, Z, E maximum start speed for accelerated moves. E default values are good for Skeinforge 40+, for older versions raise them a lot.
 #define DEFAULT_MAX_ACCELERATION_SILENT     {960, 960, 200, 5000}    // (mm/sec^2) max acceleration (M201), silent mode
 
-#define DEFAULT_ACCELERATION          1500    // X, Y, Z and E max acceleration in mm/s^2 for printing moves
+#define DEFAULT_ACCELERATION          1500   // X, Y, Z and E max acceleration in mm/s^2 for printing moves
 #define DEFAULT_RETRACT_ACCELERATION  1500   // X, Y, Z and E max acceleration in mm/s^2 for retracts
+#define DEFAULT_TRAVEL_ACCELERATION   1500   // X, Y, Z and E max acceleration in mm/s^2 for travels
 
 
 #define MANUAL_FEEDRATE {3000, 3000, 1000, 100}   // set the speeds for manual moves (mm/min)
diff --git a/Firmware/variants/1_75mm_MK25-RAMBo10a-E3Dv6full.h b/Firmware/variants/1_75mm_MK25-RAMBo10a-E3Dv6full.h
index ba40e046..acd7883d 100644
--- a/Firmware/variants/1_75mm_MK25-RAMBo10a-E3Dv6full.h
+++ b/Firmware/variants/1_75mm_MK25-RAMBo10a-E3Dv6full.h
@@ -94,8 +94,9 @@
 #define DEFAULT_MAX_ACCELERATION      {1000, 1000, 200, 5000}  // (mm/sec^2) max acceleration (M201)
 #define DEFAULT_MAX_ACCELERATION_SILENT     {960, 960, 200, 5000}    // (mm/sec^2) max acceleration (M201), silent mode
 
-#define DEFAULT_ACCELERATION          1250   // X, Y, Z and E max acceleration in mm/s^2 for printing moves (M204S)
-#define DEFAULT_RETRACT_ACCELERATION  1250   // X, Y, Z and E max acceleration in mm/s^2 for retracts (M204T)
+#define DEFAULT_ACCELERATION          1250   // X, Y, Z and E max acceleration in mm/s^2 for printing moves (M204P)
+#define DEFAULT_RETRACT_ACCELERATION  1250   // X, Y, Z and E max acceleration in mm/s^2 for retracts (M204R)
+#define DEFAULT_TRAVEL_ACCELERATION   1250   // X, Y, Z and E max acceleration in mm/s^2 for travels (M204T)
 
 #define MANUAL_FEEDRATE {2700, 2700, 1000, 100}   // set the speeds for manual moves (mm/min)
 
diff --git a/Firmware/variants/1_75mm_MK25-RAMBo13a-E3Dv6full.h b/Firmware/variants/1_75mm_MK25-RAMBo13a-E3Dv6full.h
index 33bb4717..ddf7e77a 100644
--- a/Firmware/variants/1_75mm_MK25-RAMBo13a-E3Dv6full.h
+++ b/Firmware/variants/1_75mm_MK25-RAMBo13a-E3Dv6full.h
@@ -95,8 +95,9 @@
 #define DEFAULT_MAX_ACCELERATION_SILENT     {960, 960, 200, 5000}    // (mm/sec^2) max acceleration (M201), silent mode
 
 
-#define DEFAULT_ACCELERATION          1250   // X, Y, Z and E max acceleration in mm/s^2 for printing moves (M204S)
-#define DEFAULT_RETRACT_ACCELERATION  1250   // X, Y, Z and E max acceleration in mm/s^2 for retracts (M204T)
+#define DEFAULT_ACCELERATION          1250   // X, Y, Z and E max acceleration in mm/s^2 for printing moves (M204P)
+#define DEFAULT_RETRACT_ACCELERATION  1250   // X, Y, Z and E max acceleration in mm/s^2 for retracts (M204R)
+#define DEFAULT_TRAVEL_ACCELERATION   1250   // X, Y, Z and E max acceleration in mm/s^2 for travels (M204T)
 
 #define MANUAL_FEEDRATE {2700, 2700, 1000, 100}   // set the speeds for manual moves (mm/min)
 
diff --git a/Firmware/variants/1_75mm_MK25S-RAMBo10a-E3Dv6full.h b/Firmware/variants/1_75mm_MK25S-RAMBo10a-E3Dv6full.h
index 19b2c76f..e7b114d9 100644
--- a/Firmware/variants/1_75mm_MK25S-RAMBo10a-E3Dv6full.h
+++ b/Firmware/variants/1_75mm_MK25S-RAMBo10a-E3Dv6full.h
@@ -94,8 +94,9 @@
 #define DEFAULT_MAX_ACCELERATION      {1000, 1000, 200, 5000}  // (mm/sec^2) max acceleration (M201)
 #define DEFAULT_MAX_ACCELERATION_SILENT     {960, 960, 200, 5000}    // (mm/sec^2) max acceleration (M201), silent mode
 
-#define DEFAULT_ACCELERATION          1250   // X, Y, Z and E max acceleration in mm/s^2 for printing moves (M204S)
-#define DEFAULT_RETRACT_ACCELERATION  1250   // X, Y, Z and E max acceleration in mm/s^2 for retracts (M204T)
+#define DEFAULT_ACCELERATION          1250   // X, Y, Z and E max acceleration in mm/s^2 for printing moves (M204P)
+#define DEFAULT_RETRACT_ACCELERATION  1250   // X, Y, Z and E max acceleration in mm/s^2 for retracts (M204R)
+#define DEFAULT_TRAVEL_ACCELERATION   1250   // X, Y, Z and E max acceleration in mm/s^2 for travels (M204T)
 
 #define MANUAL_FEEDRATE {2700, 2700, 1000, 100}   // set the speeds for manual moves (mm/min)
 
diff --git a/Firmware/variants/1_75mm_MK25S-RAMBo13a-E3Dv6full.h b/Firmware/variants/1_75mm_MK25S-RAMBo13a-E3Dv6full.h
index cc02867d..cde81249 100644
--- a/Firmware/variants/1_75mm_MK25S-RAMBo13a-E3Dv6full.h
+++ b/Firmware/variants/1_75mm_MK25S-RAMBo13a-E3Dv6full.h
@@ -95,8 +95,9 @@
 #define DEFAULT_MAX_ACCELERATION_SILENT     {960, 960, 200, 5000}    // (mm/sec^2) max acceleration (M201), silent mode
 
 
-#define DEFAULT_ACCELERATION          1250   // X, Y, Z and E max acceleration in mm/s^2 for printing moves (M204S)
-#define DEFAULT_RETRACT_ACCELERATION  1250   // X, Y, Z and E max acceleration in mm/s^2 for retracts (M204T)
+#define DEFAULT_ACCELERATION          1250   // X, Y, Z and E max acceleration in mm/s^2 for printing moves (M204P)
+#define DEFAULT_RETRACT_ACCELERATION  1250   // X, Y, Z and E max acceleration in mm/s^2 for retracts (M204R)
+#define DEFAULT_TRAVEL_ACCELERATION   1250   // X, Y, Z and E max acceleration in mm/s^2 for travels (M204T)
 
 #define MANUAL_FEEDRATE {2700, 2700, 1000, 100}   // set the speeds for manual moves (mm/min)
 
diff --git a/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h b/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h
index 65f7ae99..2c62f2fd 100644
--- a/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h
+++ b/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h
@@ -99,8 +99,9 @@
 #define DEFAULT_MAX_ACCELERATION_SILENT     {960, 960, 200, 5000}    // (mm/sec^2) max acceleration (M201), silent mode
 
 
-#define DEFAULT_ACCELERATION          1250   // X, Y, Z and E max acceleration in mm/s^2 for printing moves (M204S)
-#define DEFAULT_RETRACT_ACCELERATION  1250   // X, Y, Z and E max acceleration in mm/s^2 for retracts (M204T)
+#define DEFAULT_ACCELERATION          1250   // X, Y, Z and E max acceleration in mm/s^2 for printing moves (M204P)
+#define DEFAULT_RETRACT_ACCELERATION  1250   // X, Y, Z and E max acceleration in mm/s^2 for retracts (M204R)
+#define DEFAULT_TRAVEL_ACCELERATION   1250   // X, Y, Z and E max acceleration in mm/s^2 for travels (M204T)
 
 #define MANUAL_FEEDRATE {2700, 2700, 1000, 100}   // set the speeds for manual moves (mm/min)
 
diff --git a/Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h b/Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h
index c7ab7508..d74d75d5 100644
--- a/Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h
+++ b/Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h
@@ -101,8 +101,9 @@
 #define DEFAULT_MAX_ACCELERATION_SILENT     {960, 960, 200, 5000}    // (mm/sec^2) max acceleration (M201), silent mode
 
 
-#define DEFAULT_ACCELERATION          1250   // X, Y, Z and E max acceleration in mm/s^2 for printing moves (M204S)
-#define DEFAULT_RETRACT_ACCELERATION  1250   // X, Y, Z and E max acceleration in mm/s^2 for retracts (M204T)
+#define DEFAULT_ACCELERATION          1250   // X, Y, Z and E max acceleration in mm/s^2 for printing moves (M204P)
+#define DEFAULT_RETRACT_ACCELERATION  1250   // X, Y, Z and E max acceleration in mm/s^2 for retracts (M204R)
+#define DEFAULT_TRAVEL_ACCELERATION   1250   // X, Y, Z and E max acceleration in mm/s^2 for travels (M204T)
 
 #define MANUAL_FEEDRATE {2700, 2700, 1000, 100}   // set the speeds for manual moves (mm/min)
 

From 45811f82aa04b58dadd93990298fef36747ea82d Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Sun, 20 Sep 2020 19:04:08 +0200
Subject: [PATCH 45/58] Initialize default travel_acceleration from EEPROM

When reading uninitialized memory, preset the travel acceleration to be
the same as the default acceleration.
---
 Firmware/ConfigurationStore.cpp | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/Firmware/ConfigurationStore.cpp b/Firmware/ConfigurationStore.cpp
index 009a9024..c8548564 100644
--- a/Firmware/ConfigurationStore.cpp
+++ b/Firmware/ConfigurationStore.cpp
@@ -235,6 +235,18 @@ static const M500_conf default_conf PROGMEM =
     DEFAULT_TRAVEL_ACCELERATION,
 };
 
+
+static bool is_uninitialized(void* addr, uint8_t len)
+{
+    while(len--)
+    {
+        if(reinterpret_cast<uint8_t*>(addr)[len] != 0xff)
+            return false;
+    }
+    return true;
+}
+
+
 //! @brief Read M500 configuration
 //! @retval true Succeeded. Stored settings retrieved or default settings retrieved in case EEPROM has been erased.
 //! @retval false Failed. Default settings has been retrieved, because of older version or corrupted data.
@@ -294,6 +306,9 @@ bool Config_RetrieveSettings()
 		tmc2130_set_res(E_AXIS, cs.axis_ustep_resolution[E_AXIS]);
 #endif //TMC2130
 
+        if(is_uninitialized(&cs.travel_acceleration, sizeof(cs.travel_acceleration)))
+            cs.travel_acceleration = cs.acceleration;
+
 		reset_acceleration_rates();
 
 		// Call updatePID (similar to when we have processed M301)

From 76911f67dbd69c22558beb84f45b85f643515372 Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Sun, 20 Sep 2020 19:05:19 +0200
Subject: [PATCH 46/58] Take advantage of the new is_uninitialized function

Save some space and perform some cleanup
---
 Firmware/ConfigurationStore.cpp | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/Firmware/ConfigurationStore.cpp b/Firmware/ConfigurationStore.cpp
index c8548564..dc8126ac 100644
--- a/Firmware/ConfigurationStore.cpp
+++ b/Firmware/ConfigurationStore.cpp
@@ -270,13 +270,9 @@ bool Config_RetrieveSettings()
         for (uint8_t i = 0; i < (sizeof(cs.max_feedrate_silent)/sizeof(cs.max_feedrate_silent[0])); ++i)
         {
             const uint32_t erased = 0xffffffff;
-            bool initialized = false;
-
-            for(uint8_t j = 0; j < sizeof(float); ++j)
-            {
-                if(0xff != reinterpret_cast<uint8_t*>(&(cs.max_feedrate_silent[i]))[j]) initialized = true;
+            if (is_uninitialized(&(cs.max_feedrate_silent[i]), sizeof(float))) {
+                memcpy_P(&cs.max_feedrate_silent[i],&default_conf.max_feedrate_silent[i], sizeof(cs.max_feedrate_silent[i]));
             }
-            if (!initialized) memcpy_P(&cs.max_feedrate_silent[i],&default_conf.max_feedrate_silent[i], sizeof(cs.max_feedrate_silent[i]));
             if (erased == cs.max_acceleration_units_per_sq_second_silent[i]) {
                 memcpy_P(&cs.max_acceleration_units_per_sq_second_silent[i],&default_conf.max_acceleration_units_per_sq_second_silent[i],sizeof(cs.max_acceleration_units_per_sq_second_silent[i]));
             }

From f7542aa0644b8ea6d9928e8dbe64e527e686599f Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Sun, 20 Sep 2020 19:06:15 +0200
Subject: [PATCH 47/58] Report travel acceleration in M503

Use the new M204 format consistently also in M503's output
---
 Firmware/ConfigurationStore.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/Firmware/ConfigurationStore.cpp b/Firmware/ConfigurationStore.cpp
index dc8126ac..adccb399 100644
--- a/Firmware/ConfigurationStore.cpp
+++ b/Firmware/ConfigurationStore.cpp
@@ -96,7 +96,7 @@ void Config_PrintSettings(uint8_t level)
 		"%SMaximum feedrates - stealth (mm/s):\n%S  M203 X%.2f Y%.2f Z%.2f E%.2f\n"
 		"%SMaximum acceleration - normal (mm/s2):\n%S  M201 X%lu Y%lu Z%lu E%lu\n"
 		"%SMaximum acceleration - stealth (mm/s2):\n%S  M201 X%lu Y%lu Z%lu E%lu\n"
-		"%SAcceleration: S=acceleration, T=retract acceleration\n%S  M204 S%.2f T%.2f\n"
+		"%SAcceleration: P=print, R=retract, T=travel\n%S  M204 P%.2f R%.2f T%.2f\n"
 		"%SAdvanced variables: S=Min feedrate (mm/s), T=Min travel feedrate (mm/s), B=minimum segment time (ms), X=maximum XY jerk (mm/s),  Z=maximum Z jerk (mm/s),  E=maximum E jerk (mm/s)\n%S  M205 S%.2f T%.2f B%.2f X%.2f Y%.2f Z%.2f E%.2f\n"
 		"%SHome offset (mm):\n%S  M206 X%.2f Y%.2f Z%.2f\n"
 		),
@@ -106,7 +106,7 @@ void Config_PrintSettings(uint8_t level)
 		echomagic, echomagic, cs.max_feedrate_silent[X_AXIS], cs.max_feedrate_silent[Y_AXIS], cs.max_feedrate_silent[Z_AXIS], cs.max_feedrate_silent[E_AXIS],
 		echomagic, echomagic, cs.max_acceleration_units_per_sq_second_normal[X_AXIS], cs.max_acceleration_units_per_sq_second_normal[Y_AXIS], cs.max_acceleration_units_per_sq_second_normal[Z_AXIS], cs.max_acceleration_units_per_sq_second_normal[E_AXIS],
 		echomagic, echomagic, cs.max_acceleration_units_per_sq_second_silent[X_AXIS], cs.max_acceleration_units_per_sq_second_silent[Y_AXIS], cs.max_acceleration_units_per_sq_second_silent[Z_AXIS], cs.max_acceleration_units_per_sq_second_silent[E_AXIS],
-		echomagic, echomagic, cs.acceleration, cs.retract_acceleration,
+		echomagic, echomagic, cs.acceleration, cs.retract_acceleration, cs.travel_acceleration,
 		echomagic, echomagic, cs.minimumfeedrate, cs.mintravelfeedrate, cs.minsegmenttime, cs.max_jerk[X_AXIS], cs.max_jerk[Y_AXIS], cs.max_jerk[Z_AXIS], cs.max_jerk[E_AXIS],
 		echomagic, echomagic, cs.add_homing[X_AXIS], cs.add_homing[Y_AXIS], cs.add_homing[Z_AXIS]
 #else //TMC2130
@@ -114,14 +114,14 @@ void Config_PrintSettings(uint8_t level)
 		"%SSteps per unit:\n%S  M92 X%.2f Y%.2f Z%.2f E%.2f\n"
 		"%SMaximum feedrates (mm/s):\n%S  M203 X%.2f Y%.2f Z%.2f E%.2f\n"
 		"%SMaximum acceleration (mm/s2):\n%S  M201 X%lu Y%lu Z%lu E%lu\n"
-		"%SAcceleration: S=acceleration, T=retract acceleration\n%S  M204 S%.2f T%.2f\n"
+		"%SAcceleration: P=print, R=retract, T=travel\n%S  M204 P%.2f R%.2f T%.2f\n"
 		"%SAdvanced variables: S=Min feedrate (mm/s), T=Min travel feedrate (mm/s), B=minimum segment time (ms), X=maximum XY jerk (mm/s),  Z=maximum Z jerk (mm/s),  E=maximum E jerk (mm/s)\n%S  M205 S%.2f T%.2f B%.2f X%.2f Y%.2f Z%.2f E%.2f\n"
 		"%SHome offset (mm):\n%S  M206 X%.2f Y%.2f Z%.2f\n"
 		),
 		echomagic, echomagic, cs.axis_steps_per_unit[X_AXIS], cs.axis_steps_per_unit[Y_AXIS], cs.axis_steps_per_unit[Z_AXIS], cs.axis_steps_per_unit[E_AXIS],
 		echomagic, echomagic, max_feedrate[X_AXIS], max_feedrate[Y_AXIS], max_feedrate[Z_AXIS], max_feedrate[E_AXIS],
 		echomagic, echomagic, max_acceleration_units_per_sq_second[X_AXIS], max_acceleration_units_per_sq_second[Y_AXIS], max_acceleration_units_per_sq_second[Z_AXIS], max_acceleration_units_per_sq_second[E_AXIS],
-		echomagic, echomagic, cs.acceleration, cs.retract_acceleration,
+		echomagic, echomagic, cs.acceleration, cs.retract_acceleration, cs.travel_acceleration,
 		echomagic, echomagic, cs.minimumfeedrate, cs.mintravelfeedrate, cs.minsegmenttime, cs.max_jerk[X_AXIS], cs.max_jerk[Y_AXIS], cs.max_jerk[Z_AXIS], cs.max_jerk[E_AXIS],
 		echomagic, echomagic, cs.add_homing[X_AXIS], cs.add_homing[Y_AXIS], cs.add_homing[Z_AXIS]
 #endif //TMC2130

From 186ce0f4b32dda9d5a2fa8e0e2649cc130d2cfca Mon Sep 17 00:00:00 2001
From: Yuri D'Elia <wavexx@thregr.org>
Date: Mon, 1 Feb 2021 00:02:49 +0100
Subject: [PATCH 48/58] Handle acceleration settings in UVLO/power panic

Acceleration settings need to be saved in UVLO, since these are often
changed/set during a print. This is especially important for travel and
retract acceleration, which is usually set once per-print.

Saving and restoring is not 100% correct.

We save the current front-end value, which might ahead of the backend
when UVLO is triggered. Print acceleration, likely the most significant,
should be saved in the block buffer to be accurate.

Acceleration needs to be restored after the UVLO Z repositioning is
performed, using an M204 command. This is correct, however we don't save
the _temporary_ max acceleration limits set via M201, which could be
higher than the saved limits (via M500). This could result in lower
clamped values compared to the original print.

Maximum acceleration/jerk/feedrate limits should _all_ be saved in UVLO
in the future.
---
 Firmware/Marlin_main.cpp | 11 +++++++++++
 Firmware/eeprom.h        | 11 +++++++++--
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp
index f25b5aeb..780a0bca 100755
--- a/Firmware/Marlin_main.cpp
+++ b/Firmware/Marlin_main.cpp
@@ -10963,6 +10963,10 @@ void uvlo_()
 #endif
 	eeprom_update_word((uint16_t*)(EEPROM_EXTRUDEMULTIPLY), (uint16_t)extrudemultiply);
 
+	eeprom_update_float((float*)(EEPROM_UVLO_ACCELL), cs.acceleration);
+	eeprom_update_float((float*)(EEPROM_UVLO_RETRACT_ACCELL), cs.retract_acceleration);
+	eeprom_update_float((float*)(EEPROM_UVLO_TRAVEL_ACCELL), cs.travel_acceleration);
+
     // 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]);
@@ -11307,6 +11311,13 @@ void restore_print_from_eeprom(bool mbl_was_active) {
     sprintf_P(cmd, PSTR("G1 Z%f"), eeprom_read_float((float*)(EEPROM_UVLO_CURRENT_POSITION_Z)));
 	enquecommand(cmd);
 
+    // Restore acceleration settings
+    float acceleration = eeprom_read_float((float*)(EEPROM_UVLO_ACCELL));
+    float retract_acceleration = eeprom_read_float((float*)(EEPROM_UVLO_RETRACT_ACCELL));
+    float travel_acceleration = eeprom_read_float((float*)(EEPROM_UVLO_TRAVEL_ACCELL));
+    sprintf_P(cmd, PSTR("M204 P%f R%f T%f"), acceleration, retract_acceleration, travel_acceleration);
+    enquecommand(cmd);
+
   // Unretract.
     sprintf_P(cmd, PSTR("G1 E%0.3f F2700"), default_retraction);
     enquecommand(cmd);
diff --git a/Firmware/eeprom.h b/Firmware/eeprom.h
index 03af214f..f9f93b7d 100644
--- a/Firmware/eeprom.h
+++ b/Firmware/eeprom.h
@@ -319,8 +319,10 @@ static_assert(sizeof(Sheets) == EEPROM_SHEETS_SIZEOF, "Sizeof(Sheets) is not EEP
 | ^					| ^			| ^										| 00h 0			| ^						| PINDA has no temp compensation PINDA v1/2    		| ^				| ^
 | ^					| ^			| ^										| 01h 1			| ^						| PINDA has temp compensation aka SuperPINDA       	| ^				| ^
 | 0x0D15 3349		| char[20]	| EEPROM_PRUSA_SN						| SN[19] == 0	| ffffffffffffffff...	| PRUSA Serial number string						| PRUSA SN		| D3 Ax0d15 C20
+| 0x0D11 3345		| float		| EEPROM_UVLO_ACCELL                	| ???			| ff ff ff ffh			| Power panic saved normal acceleration     		| ???			| D3 Ax0d11 C4
+| 0x0D0D 3341		| float		| EEPROM_UVLO_RETRACT_ACCELL			| ???			| ff ff ff ffh			| Power panic saved retract acceleration     		| ???			| D3 Ax0d0d C4
+| 0x0D09 3337		| float		| EEPROM_UVLO_TRAVEL_ACCELL				| ???			| ff ff ff ffh			| Power panic saved travel acceleration     		| ???			| D3 Ax0d09 C4
 
-  
 | Address begin		| Bit/Type 	| Name 									| Valid values	| Default/FactoryReset	| Description 										| Gcode/Function| Debug code
 | :--:				| :--: 		| :--: 									| :--:			| :--:					| :--:												| :--:			| :--:
 | 0x0012 18			| uint16	| EEPROM_FIRMWARE_VERSION_END			| ???			| ff ffh 65535			| ???												| ???			| D3 Ax0012 C2
@@ -525,8 +527,13 @@ static Sheets * const EEPROM_Sheets_base = (Sheets*)(EEPROM_SHEETS_BASE);
 #define EEPROM_EXPERIMENTAL_VISIBILITY (EEPROM_ALTFAN_OVERRIDE-1) //uint8
 #define EEPROM_PINDA_TEMP_COMPENSATION (EEPROM_EXPERIMENTAL_VISIBILITY-1) //uint8
 #define EEPROM_PRUSA_SN (EEPROM_PINDA_TEMP_COMPENSATION-20) //char[20]
+
+#define EEPROM_UVLO_ACCELL (EEPROM_PRUSA_SN-4) // float
+#define EEPROM_UVLO_RETRACT_ACCELL (EEPROM_UVLO_ACCELL-4) // float
+#define EEPROM_UVLO_TRAVEL_ACCELL (EEPROM_UVLO_RETRACT_ACCELL-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_PRUSA_SN
+#define EEPROM_LAST_ITEM EEPROM_UVLO_TRAVEL_ACCELL
 // !!!!!
 // !!!!! this is end of EEPROM section ... all updates MUST BE inserted before this mark !!!!!
 // !!!!!

From f343e6432ac33c7417d35d3f2faadcb9f94ae515 Mon Sep 17 00:00:00 2001
From: Voinea Dragos <voinea.dragos.alexandru@gmail.com>
Date: Sun, 31 Jan 2021 16:42:01 +0200
Subject: [PATCH 49/58] Fix diveSubfolder string termination

---
 Firmware/cardreader.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Firmware/cardreader.cpp b/Firmware/cardreader.cpp
index a9626897..4b55e816 100644
--- a/Firmware/cardreader.cpp
+++ b/Firmware/cardreader.cpp
@@ -340,9 +340,9 @@ void CardReader::diveSubfolder (const char *fileName, SdFile& dir)
             {
                 const size_t maxLen = 12;
                 char subdirname[maxLen+1];
-                subdirname[maxLen] = 0;
                 const size_t len = ((static_cast<size_t>(dirname_end-dirname_start))>maxLen) ? maxLen : (dirname_end-dirname_start);
                 strncpy(subdirname, dirname_start, len);
+                subdirname[len] = 0;
                 SERIAL_ECHOLN(subdirname);
                 if (!dir.open(curDir, subdirname, O_READ))
                 {

From 52f7a71dce177cf7dc484988a6701f08e689d9e2 Mon Sep 17 00:00:00 2001
From: Voinea Dragos <voinea.dragos.alexandru@gmail.com>
Date: Sat, 6 Feb 2021 14:59:11 +0200
Subject: [PATCH 50/58] More fixes that were extracted from #2405

---
 Firmware/Marlin.h        |  4 --
 Firmware/Marlin_main.cpp |  8 +---
 Firmware/cardreader.cpp  | 81 +++++++++++++++++++++-------------------
 Firmware/cardreader.h    | 10 +++--
 Firmware/messages.c      |  1 +
 Firmware/messages.h      |  1 +
 Firmware/ultralcd.cpp    | 12 ++----
 7 files changed, 57 insertions(+), 60 deletions(-)

diff --git a/Firmware/Marlin.h b/Firmware/Marlin.h
index 1ed5e0bd..cbe03c0f 100755
--- a/Firmware/Marlin.h
+++ b/Firmware/Marlin.h
@@ -350,10 +350,6 @@ extern unsigned long t_fan_rising_edge;
 extern bool mesh_bed_leveling_flag;
 extern bool mesh_bed_run_from_menu;
 
-extern bool sortAlpha;
-
-extern char dir_names[][9];
-
 extern int8_t lcd_change_fil_state;
 // save/restore printing
 extern bool saved_printing;
diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp
index 6db1d277..e5daeee0 100755
--- a/Firmware/Marlin_main.cpp
+++ b/Firmware/Marlin_main.cpp
@@ -228,10 +228,6 @@ bool fan_state[2];
 int fan_edge_counter[2];
 int fan_speed[2];
 
-char dir_names[MAX_DIR_DEPTH][9];
-
-bool sortAlpha = false;
-
 
 float extruder_multiplier[EXTRUDERS] = {1.0
   #if EXTRUDERS > 1
@@ -11281,8 +11277,8 @@ void restore_print_from_eeprom(bool mbl_was_active) {
 		}
 		dir_name[8] = '\0';
 		MYSERIAL.println(dir_name);
-		strcpy(dir_names[i], dir_name);
-		card.chdir(dir_name);
+		// strcpy(dir_names[i], dir_name);
+		card.chdir(dir_name, false);
 	}
 
 	for (int i = 0; i < 8; i++) {
diff --git a/Firmware/cardreader.cpp b/Firmware/cardreader.cpp
index 4b55e816..418dbb94 100644
--- a/Firmware/cardreader.cpp
+++ b/Firmware/cardreader.cpp
@@ -32,6 +32,7 @@ CardReader::CardReader()
    workDirDepth = 0;
    file_subcall_ctr=0;
    memset(workDirParents, 0, sizeof(workDirParents));
+   presort_flag = false;
 
    autostart_stilltocheck=true; //the SD start is delayed, because otherwise the serial cannot answer fast enough to make contact with the host software.
    lastnr=0;
@@ -69,12 +70,15 @@ char *createFilename(char *buffer,const dir_t &p) //buffer>12characters
 +*/
 
 void CardReader::lsDive(const char *prepend, SdFile parent, const char * const match/*=NULL*/) {
+	static uint8_t recursionCnt = 0;
 	dir_t p;
 	uint8_t cnt = 0;
 		// Read the next entry from a directory
 		while (parent.readDir(p, longFilename) > 0) {
-			// If the entry is a directory and the action is LS_SerialPrint
-			if (DIR_IS_SUBDIR(&p) && lsAction != LS_Count && lsAction != LS_GetFilename) {
+			if (recursionCnt >= MAX_DIR_DEPTH)
+				return;
+			else if (DIR_IS_SUBDIR(&p) && lsAction != LS_Count && lsAction != LS_GetFilename) { // If the entry is a directory and the action is LS_SerialPrint
+				recursionCnt++;
 				// Get the short name for the item, which we know is a folder
 				char lfilename[FILENAME_LENGTH];
 				createFilename(lfilename, p);
@@ -108,6 +112,7 @@ void CardReader::lsDive(const char *prepend, SdFile parent, const char * const m
 				
 				if (lsAction == LS_SerialPrint_LFN)
 					puts_P(PSTR("DIR_EXIT"));
+				recursionCnt--;
 			}
 			else {
 				uint8_t pn0 = p.name[0];
@@ -241,18 +246,18 @@ void CardReader::initsd()
   
 }
 
-void CardReader::setroot()
+void CardReader::setroot(bool doPresort)
 {
-  /*if(!workDir.openRoot(&volume))
-  {
-    SERIAL_ECHOLNPGM(MSG_SD_WORKDIR_FAIL);
-  }*/
   workDir=root;
+  workDirDepth = 0;
   
   curDir=&workDir;
-  #ifdef SDCARD_SORT_ALPHA
-	  presort();
-  #endif
+#ifdef SDCARD_SORT_ALPHA
+	if (doPresort)
+		presort();
+	else
+		presort_flag = true;
+#endif
 }
 void CardReader::release()
 {
@@ -317,19 +322,17 @@ void CardReader::getAbsFilename(char *t)
  * @param[in,out] fileName
  *  expects file name including path
  *  in case of absolute path, file name without path is returned
- * @param[in,out] dir SdFile object to operate with,
- *  in case of absolute path, curDir is modified to point to dir,
- *  so it is not possible to create on stack inside this function,
- *  as curDir would point to destroyed object.
  */
-void CardReader::diveSubfolder (const char *fileName, SdFile& dir)
+bool CardReader::diveSubfolder (const char *&fileName)
 {
     curDir=&root;
-    if (!fileName) return;
+    if (!fileName)
+        return 1;
 
     const char *dirname_start, *dirname_end;
     if (fileName[0] == '/') // absolute path
     {
+        setroot(false);
         dirname_start = fileName + 1;
         while (*dirname_start)
         {
@@ -344,19 +347,10 @@ void CardReader::diveSubfolder (const char *fileName, SdFile& dir)
                 strncpy(subdirname, dirname_start, len);
                 subdirname[len] = 0;
                 SERIAL_ECHOLN(subdirname);
-                if (!dir.open(curDir, subdirname, O_READ))
-                {
-                    SERIAL_PROTOCOLRPGM(MSG_SD_OPEN_FILE_FAIL);
-                    SERIAL_PROTOCOL(subdirname);
-                    SERIAL_PROTOCOLLN('.');
-                    return;
-                }
-                else
-                {
-                    //SERIAL_ECHOLN("dive ok");
-                }
+                if (!chdir(subdirname, false))
+                    return 0;
 
-                curDir = &dir;
+                curDir = &workDir;
                 dirname_start = dirname_end + 1;
             }
             else // the reminder after all /fsa/fdsa/ is the filename
@@ -373,6 +367,7 @@ void CardReader::diveSubfolder (const char *fileName, SdFile& dir)
     {
         curDir = &workDir;
     }
+    return 1;
 }
 
 void CardReader::openFile(const char* name,bool read, bool replace_current/*=true*/)
@@ -423,9 +418,9 @@ void CardReader::openFile(const char* name,bool read, bool replace_current/*=tru
   }
   sdprinting = false;
 
-  SdFile myDir;
   const char *fname=name;
-  diveSubfolder(fname,myDir);
+  if (!diveSubfolder(fname))
+    return;
 
   if(read)
   {
@@ -438,10 +433,9 @@ void CardReader::openFile(const char* name,bool read, bool replace_current/*=tru
       SERIAL_PROTOCOLLN(filesize);
       sdpos = 0;
       
-      SERIAL_PROTOCOLLNRPGM(_N("File selected"));////MSG_SD_FILE_SELECTED
+      SERIAL_PROTOCOLLNRPGM(MSG_FILE_SELECTED);
+      lcd_setstatuspgm(MSG_FILE_SELECTED);
       getfilename(0, fname);
-      lcd_setstatus(longFilename[0] ? longFilename : fname);
-      lcd_setstatuspgm(PSTR("SD-PRINTING"));
     }
     else
     {
@@ -475,9 +469,9 @@ void CardReader::removeFile(const char* name)
     file.close();
     sdprinting = false;
 
-    SdFile myDir;
     const char *fname=name;
-    diveSubfolder(fname,myDir);
+    if (!diveSubfolder(fname))
+      return;
 
     if (file.remove(curDir, fname)) 
     {
@@ -670,7 +664,7 @@ uint16_t CardReader::getnrfilenames()
   return nrFiles;
 }
 
-void CardReader::chdir(const char * relpath)
+bool CardReader::chdir(const char * relpath, bool doPresort)
 {
   SdFile newfile;
   SdFile *parent=&root;
@@ -678,23 +672,32 @@ void CardReader::chdir(const char * relpath)
   if(workDir.isOpen())
     parent=&workDir;
   
-  if(!newfile.open(*parent,relpath, O_READ))
+  if(!newfile.open(*parent,relpath, O_READ) || ((workDirDepth + 1) >= MAX_DIR_DEPTH))
   {
    SERIAL_ECHO_START;
    SERIAL_ECHORPGM(_n("Cannot enter subdir: "));////MSG_SD_CANT_ENTER_SUBDIR
    SERIAL_ECHOLN(relpath);
+   return 0;
   }
   else
   {
+    strcpy(dir_names[workDirDepth], relpath);
+    puts(relpath);
+
     if (workDirDepth < MAX_DIR_DEPTH) {
       for (int d = ++workDirDepth; d--;)
         workDirParents[d+1] = workDirParents[d];
       workDirParents[0]=*parent;
     }
     workDir=newfile;
-	#ifdef SDCARD_SORT_ALPHA
+
+#ifdef SDCARD_SORT_ALPHA
+	if (doPresort)
 		presort();
-	#endif
+	else
+		presort_flag = true;
+#endif
+	return 1;
   }
 }
 
diff --git a/Firmware/cardreader.h b/Firmware/cardreader.h
index 9bf9bd0a..819e8bf2 100644
--- a/Firmware/cardreader.h
+++ b/Firmware/cardreader.h
@@ -39,9 +39,9 @@ public:
   
 
   void ls(bool printLFN);
-  void chdir(const char * relpath);
+  bool chdir(const char * relpath, bool doPresort);
   void updir();
-  void setroot();
+  void setroot(bool doPresort);
 
   #ifdef SDCARD_SORT_ALPHA
      void presort();
@@ -82,6 +82,10 @@ public:
   char longFilename[LONG_FILENAME_LENGTH];
   bool filenameIsDir;
   int lastnr; //last number of the autostart;
+#ifdef SDCARD_SORT_ALPHA
+  bool presort_flag;
+  char dir_names[MAX_DIR_DEPTH][9];
+#endif // SDCARD_SORT_ALPHA
 private:
   SdFile root,*curDir,workDir,workDirParents[MAX_DIR_DEPTH];
   uint16_t workDirDepth;
@@ -155,7 +159,7 @@ private:
   int16_t nrFiles; //counter for the files in the current directory and recycled as position counter for getting the nrFiles'th name in the directory.
   char* diveDirName;
 
-  void diveSubfolder (const char *fileName, SdFile& dir);
+  bool diveSubfolder (const char *&fileName);
   void lsDive(const char *prepend, SdFile parent, const char * const match=NULL);
 #ifdef SDCARD_SORT_ALPHA
   void flush_presort();
diff --git a/Firmware/messages.c b/Firmware/messages.c
index 0b1d58e0..39f0cf33 100644
--- a/Firmware/messages.c
+++ b/Firmware/messages.c
@@ -197,3 +197,4 @@ const char MSG_M112_KILL[] PROGMEM_N1 = "M112 called. Emergency Stop."; ////c=20
 const char MSG_ADVANCE_K[] PROGMEM_N1 = "Advance K:"; ////c=13
 const char MSG_POWERPANIC_DETECTED[] PROGMEM_N1 = "POWER PANIC DETECTED"; ////c=20
 const char MSG_LCD_STATUS_CHANGED[] PROGMEM_N1 = "LCD status changed";
+const char MSG_FILE_SELECTED[] PROGMEM_N1 = "File selected"; ////c=20
diff --git a/Firmware/messages.h b/Firmware/messages.h
index 0a05c58f..a5b672fa 100644
--- a/Firmware/messages.h
+++ b/Firmware/messages.h
@@ -197,6 +197,7 @@ extern const char MSG_M112_KILL[];
 extern const char MSG_ADVANCE_K[];
 extern const char MSG_POWERPANIC_DETECTED[];
 extern const char MSG_LCD_STATUS_CHANGED[];
+extern const char MSG_FILE_SELECTED[];
 
 #if defined(__cplusplus)
 }
diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp
index 0f6bc1fa..2d92596f 100755
--- a/Firmware/ultralcd.cpp
+++ b/Firmware/ultralcd.cpp
@@ -4317,7 +4317,7 @@ static void lcd_sort_type_set() {
 		default: sdSort = SD_SORT_TIME;
 	}
 	eeprom_update_byte((unsigned char *)EEPROM_SD_SORT, sdSort);
-	presort_flag = true;
+	card.presort_flag = true;
 }
 #endif //SDCARD_SORT_ALPHA
 
@@ -8548,7 +8548,7 @@ static void menu_action_sdfile(const char* filename)
 
   for (uint_least8_t i = 0; i < depth; i++) {
 	  for (uint_least8_t j = 0; j < 8; j++) {
-		  eeprom_write_byte((uint8_t*)EEPROM_DIRS + j + 8 * i, dir_names[i][j]);
+		  eeprom_write_byte((uint8_t*)EEPROM_DIRS + j + 8 * i, card.dir_names[i][j]);
 	  }
   }
   
@@ -8566,12 +8566,8 @@ static void menu_action_sdfile(const char* filename)
 
 void menu_action_sddirectory(const char* filename)
 {
-	uint8_t depth = (uint8_t)card.getWorkDirDepth();
-
-	strcpy(dir_names[depth], filename);
-	MYSERIAL.println(dir_names[depth]);
-  card.chdir(filename);
-  lcd_encoder = 0;
+	card.chdir(filename, true);
+	lcd_encoder = 0;
 }
 
 /** LCD API **/

From 77a5082b5664c7ccfe05ed08af16c89ad7c7b448 Mon Sep 17 00:00:00 2001
From: Voinea Dragos <voinea.dragos.alexandru@gmail.com>
Date: Sat, 6 Feb 2021 17:25:17 +0200
Subject: [PATCH 51/58] Fix presort_flag duplicate declaration

---
 Firmware/ultralcd.cpp | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp
index 2d92596f..a736f8c2 100755
--- a/Firmware/ultralcd.cpp
+++ b/Firmware/ultralcd.cpp
@@ -75,11 +75,6 @@ int8_t FSensorStateMenu = 1;
 bool bMenuFSDetect=false;
 #endif //IR_SENSOR_ANALOG
 
-
-#ifdef SDCARD_SORT_ALPHA
-bool presort_flag = false;
-#endif
-
 LcdCommands lcd_commands_type = LcdCommands::Idle;
 static uint8_t lcd_commands_step = 0;
 
@@ -7183,8 +7178,8 @@ void lcd_sdcard_menu()
 {
   uint8_t sdSort = eeprom_read_byte((uint8_t*)EEPROM_SD_SORT);
 
-  if (presort_flag == true) {
-	  presort_flag = false;
+  if (card.presort_flag == true) {
+	  card.presort_flag = false;
 	  card.presort();
   }
   if (lcd_draw_update == 0 && LCD_CLICKED == 0)

From f5cde38a7c000eeacfc7dc08f46e820359ee8777 Mon Sep 17 00:00:00 2001
From: Alex Voinea <voinea.dragos.alexandru@gmail.com>
Date: Sat, 6 Feb 2021 21:06:37 +0200
Subject: [PATCH 52/58] Remove duplicit debug line

---
 Firmware/cardreader.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/Firmware/cardreader.cpp b/Firmware/cardreader.cpp
index 418dbb94..8273e3d0 100644
--- a/Firmware/cardreader.cpp
+++ b/Firmware/cardreader.cpp
@@ -346,7 +346,6 @@ bool CardReader::diveSubfolder (const char *&fileName)
                 const size_t len = ((static_cast<size_t>(dirname_end-dirname_start))>maxLen) ? maxLen : (dirname_end-dirname_start);
                 strncpy(subdirname, dirname_start, len);
                 subdirname[len] = 0;
-                SERIAL_ECHOLN(subdirname);
                 if (!chdir(subdirname, false))
                     return 0;
 

From c739aa900303fddd86c62bc951f26ef18178a0a8 Mon Sep 17 00:00:00 2001
From: Alex Voinea <voinea.dragos.alexandru@gmail.com>
Date: Sun, 7 Feb 2021 21:51:44 +0200
Subject: [PATCH 53/58] M23 full path support.

---
 Firmware/cardreader.cpp | 22 ++++++++++++++++------
 Firmware/cardreader.h   |  1 +
 2 files changed, 17 insertions(+), 6 deletions(-)

diff --git a/Firmware/cardreader.cpp b/Firmware/cardreader.cpp
index 8273e3d0..c414e282 100644
--- a/Firmware/cardreader.cpp
+++ b/Firmware/cardreader.cpp
@@ -309,6 +309,18 @@ void CardReader::getAbsFilename(char *t)
   else
     t[0]=0;
 }
+
+void CardReader::printAbsFilenameFast()
+{
+    SERIAL_PROTOCOL('/');
+    for (uint8_t i = 0; i < getWorkDirDepth(); i++)
+    {
+        SERIAL_PROTOCOL(dir_names[i]);
+        SERIAL_PROTOCOL('/');
+    }
+    SERIAL_PROTOCOL(LONGEST_FILENAME);
+}
+
 /**
  * @brief Dive into subfolder
  *
@@ -425,16 +437,16 @@ void CardReader::openFile(const char* name,bool read, bool replace_current/*=tru
   {
     if (file.open(curDir, fname, O_READ)) 
     {
+      getfilename(0, fname);
       filesize = file.fileSize();
       SERIAL_PROTOCOLRPGM(_N("File opened: "));////MSG_SD_FILE_OPENED
-      SERIAL_PROTOCOL(fname);
+      printAbsFilenameFast();
       SERIAL_PROTOCOLRPGM(_n(" Size: "));////MSG_SD_SIZE
       SERIAL_PROTOCOLLN(filesize);
       sdpos = 0;
       
       SERIAL_PROTOCOLLNRPGM(MSG_FILE_SELECTED);
       lcd_setstatuspgm(MSG_FILE_SELECTED);
-      getfilename(0, fname);
     }
     else
     {
@@ -508,10 +520,8 @@ void CardReader::getStatus(bool arg_P)
     {
         if (arg_P)
         {
-            SERIAL_PROTOCOL('/');
-            for (uint8_t i = 0; i < getWorkDirDepth(); i++)
-                printf_P(PSTR("%s/"), dir_names[i]);
-            puts(filename);
+            printAbsFilenameFast();
+            SERIAL_PROTOCOLLN();
         }
         else
             SERIAL_PROTOCOLLN(LONGEST_FILENAME);
diff --git a/Firmware/cardreader.h b/Firmware/cardreader.h
index 819e8bf2..0e94bd3c 100644
--- a/Firmware/cardreader.h
+++ b/Firmware/cardreader.h
@@ -34,6 +34,7 @@ public:
   uint16_t getnrfilenames();
   
   void getAbsFilename(char *t);
+  void printAbsFilenameFast();
   void getDirName(char* name, uint8_t level);
   uint16_t getWorkDirDepth();
   

From fb39e7296b126c67a34937576389429d0ffc9de2 Mon Sep 17 00:00:00 2001
From: 3d-gussner <3d.gussner@gmail.com>
Date: Mon, 8 Feb 2021 10:58:41 +0100
Subject: [PATCH 54/58] Uniform message `Press the knob`

---
 Firmware/Marlin_main.cpp | 2 +-
 lang/lang_en.txt         | 2 +-
 lang/lang_en_cz.txt      | 2 +-
 lang/lang_en_de.txt      | 2 +-
 lang/lang_en_es.txt      | 2 +-
 lang/lang_en_fr.txt      | 2 +-
 lang/lang_en_it.txt      | 2 +-
 lang/lang_en_pl.txt      | 2 +-
 8 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp
index 6db1d277..bc90849e 100755
--- a/Firmware/Marlin_main.cpp
+++ b/Firmware/Marlin_main.cpp
@@ -11786,7 +11786,7 @@ void M600_wait_for_user(float HotendTempBckp) {
 				delay_keep_alive(4);
 
 				if (_millis() > waiting_start_time + (unsigned long)M600_TIMEOUT * 1000) {
-					lcd_display_message_fullscreen_P(_i("Press knob to preheat nozzle and continue."));////MSG_PRESS_TO_PREHEAT c=20 r=4
+					lcd_display_message_fullscreen_P(_i("Press the knob to preheat nozzle and continue."));////MSG_PRESS_TO_PREHEAT c=20 r=4
 					wait_for_user_state = 1;
 					setAllTargetHotends(0);
 					st_synchronize();
diff --git a/lang/lang_en.txt b/lang/lang_en.txt
index bcb0a444..41879c5a 100644
--- a/lang/lang_en.txt
+++ b/lang/lang_en.txt
@@ -620,7 +620,7 @@
 "Please upgrade."
 
 #MSG_PRESS_TO_PREHEAT c=20 r=4
-"Press knob to preheat nozzle and continue."
+"Press the knob to preheat nozzle and continue."
 
 #MSG_FS_PAUSE c=5
 "Pause"
diff --git a/lang/lang_en_cz.txt b/lang/lang_en_cz.txt
index 0b3d7b14..4c7efc5e 100644
--- a/lang/lang_en_cz.txt
+++ b/lang/lang_en_cz.txt
@@ -827,7 +827,7 @@
 "Prosim aktualizujte."
 
 #MSG_PRESS_TO_PREHEAT c=20 r=4
-"Press knob to preheat nozzle and continue."
+"Press the knob to preheat nozzle and continue."
 "Pro nahrati trysky a pokracovani stisknete tlacitko."
 
 #MSG_FS_PAUSE c=5
diff --git a/lang/lang_en_de.txt b/lang/lang_en_de.txt
index 0a436a9e..f3869931 100644
--- a/lang/lang_en_de.txt
+++ b/lang/lang_en_de.txt
@@ -827,7 +827,7 @@
 "Bitte aktualisieren."
 
 #MSG_PRESS_TO_PREHEAT c=20 r=4
-"Press knob to preheat nozzle and continue."
+"Press the knob to preheat nozzle and continue."
 "Bitte druecken Sie den Knopf um die Duese vorzuheizen und fortzufahren."
 
 #MSG_FS_PAUSE c=5
diff --git a/lang/lang_en_es.txt b/lang/lang_en_es.txt
index 2e29fa20..f8b39e17 100644
--- a/lang/lang_en_es.txt
+++ b/lang/lang_en_es.txt
@@ -827,7 +827,7 @@
 "Actualize por favor"
 
 #MSG_PRESS_TO_PREHEAT c=20 r=4
-"Press knob to preheat nozzle and continue."
+"Press the knob to preheat nozzle and continue."
 "Pulsa el dial para precalentar la boquilla y continue."
 
 #MSG_FS_PAUSE c=5
diff --git a/lang/lang_en_fr.txt b/lang/lang_en_fr.txt
index cc0cbb95..f64f800d 100644
--- a/lang/lang_en_fr.txt
+++ b/lang/lang_en_fr.txt
@@ -827,7 +827,7 @@
 "Mettez a jour le FW."
 
 #MSG_PRESS_TO_PREHEAT c=20 r=4
-"Press knob to preheat nozzle and continue."
+"Press the knob to preheat nozzle and continue."
 "Appuyez sur le bouton pour prechauffer la buse et continuer."
 
 #MSG_FS_PAUSE c=5
diff --git a/lang/lang_en_it.txt b/lang/lang_en_it.txt
index 8cd93908..e3383336 100644
--- a/lang/lang_en_it.txt
+++ b/lang/lang_en_it.txt
@@ -827,7 +827,7 @@
 "Prego aggiornare."
 
 #MSG_PRESS_TO_PREHEAT c=20 r=4
-"Press knob to preheat nozzle and continue."
+"Press the knob to preheat nozzle and continue."
 "Premete la manopola per preriscaldare l'ugello e continuare."
 
 #MSG_FS_PAUSE c=5
diff --git a/lang/lang_en_pl.txt b/lang/lang_en_pl.txt
index 38d1421f..b796c11a 100644
--- a/lang/lang_en_pl.txt
+++ b/lang/lang_en_pl.txt
@@ -827,7 +827,7 @@
 "Prosze zaktualizowac."
 
 #MSG_PRESS_TO_PREHEAT c=20 r=4
-"Press knob to preheat nozzle and continue."
+"Press the knob to preheat nozzle and continue."
 "Wcisnij pokretlo aby rozgrzac dysze i kontynuowac."
 
 #MSG_FS_PAUSE c=5

From 214695105c181796bc5c958aee9fafb65c53ff3f Mon Sep 17 00:00:00 2001
From: 3d-gussner <3d.gussner@gmail.com>
Date: Mon, 8 Feb 2021 11:33:46 +0100
Subject: [PATCH 55/58] Fix issue #2958

---
 Firmware/ultralcd.cpp | 8 ++++----
 lang/lang_en.txt      | 6 +++---
 lang/lang_en_cz.txt   | 6 +++---
 lang/lang_en_de.txt   | 6 +++---
 lang/lang_en_es.txt   | 6 +++---
 lang/lang_en_fr.txt   | 6 +++---
 lang/lang_en_it.txt   | 6 +++---
 lang/lang_en_pl.txt   | 6 +++---
 8 files changed, 25 insertions(+), 25 deletions(-)

diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp
index 0f6bc1fa..0e654384 100755
--- a/Firmware/ultralcd.cpp
+++ b/Firmware/ultralcd.cpp
@@ -2235,18 +2235,18 @@ uint8_t nLevel;
 
 lcd_set_cursor(0,0);
 lcdui_print_temp(LCD_STR_THERMOMETER[0],(int)degHotend(0),(int)degTargetHotend(0));
-lcd_puts_at_P(0,2, _i("Press the knob"));                 ////MSG_ c=20 r=1
-lcd_set_cursor(0,3);
+lcd_puts_at_P(0,1, _i("Press the knob"));                 ////MSG_ c=20
+lcd_set_cursor(0,2);
 switch(eFilamentAction)
      {
      case FilamentAction::Load:
      case FilamentAction::AutoLoad:
      case FilamentAction::MmuLoad:
-          lcd_puts_P(_i("to load filament"));     ////MSG_ c=20 r=1
+          lcd_puts_P(_i("to load filament"));     ////MSG_ c=20 r=2
           break;
      case FilamentAction::UnLoad:
      case FilamentAction::MmuUnLoad:
-          lcd_puts_P(_i("to unload filament"));   ////MSG_ c=20 r=1
+          lcd_puts_P(_i("to unload filament"));   ////MSG_ c=20 r=2
           break;
      case FilamentAction::MmuEject:
      case FilamentAction::MmuCut:
diff --git a/lang/lang_en.txt b/lang/lang_en.txt
index 41879c5a..875aa370 100644
--- a/lang/lang_en.txt
+++ b/lang/lang_en.txt
@@ -644,7 +644,7 @@
 "Print from SD"
 
 #
-"Press the knob"
+"Press the knob" c=20 r=2
 
 #MSG_PRINT_PAUSED c=20 r=1
 "Print paused"
@@ -875,10 +875,10 @@
 "Total failures"
 
 #
-"to load filament"
+"to load filament" c=20 r=2
 
 #
-"to unload filament"
+"to unload filament" c=20 r=2
 
 #MSG_UNLOAD_FILAMENT c=17
 "Unload filament"
diff --git a/lang/lang_en_cz.txt b/lang/lang_en_cz.txt
index 4c7efc5e..3c8f0f06 100644
--- a/lang/lang_en_cz.txt
+++ b/lang/lang_en_cz.txt
@@ -859,7 +859,7 @@
 "Tisk z SD"
 
 #
-"Press the knob"
+"Press the knob" c=20 r=2
 "Stisknete hl. tlacitko"
 
 #MSG_PRINT_PAUSED c=20 r=1
@@ -1167,11 +1167,11 @@
 "Celkem selhani"
 
 #
-"to load filament"
+"to load filament" c=20 r=2
 "k zavedeni filamentu"
 
 #
-"to unload filament"
+"to unload filament" c=20 r=2
 "k vyjmuti filamentu"
 
 #MSG_UNLOAD_FILAMENT c=17
diff --git a/lang/lang_en_de.txt b/lang/lang_en_de.txt
index f3869931..649994d9 100644
--- a/lang/lang_en_de.txt
+++ b/lang/lang_en_de.txt
@@ -859,7 +859,7 @@
 "Drucken von SD"
 
 #
-"Press the knob"
+"Press the knob" c=20 r=2
 "Knopf druecken zum"
 
 #MSG_PRINT_PAUSED c=20 r=1
@@ -1167,11 +1167,11 @@
 "Gesamte Fehler"
 
 #
-"to load filament"
+"to load filament" c=20 r=2
 "Filament laden"
 
 #
-"to unload filament"
+"to unload filament" c=20 r=2
 "Filament entladen"
 
 #MSG_UNLOAD_FILAMENT c=17
diff --git a/lang/lang_en_es.txt b/lang/lang_en_es.txt
index f8b39e17..35913020 100644
--- a/lang/lang_en_es.txt
+++ b/lang/lang_en_es.txt
@@ -859,7 +859,7 @@
 "Menu tarjeta SD"
 
 #
-"Press the knob"
+"Press the knob" c=20 r=2
 "Pulsa el dial"
 
 #MSG_PRINT_PAUSED c=20 r=1
@@ -1167,11 +1167,11 @@
 "Fallos totales"
 
 #
-"to load filament"
+"to load filament" c=20 r=2
 "para cargar el filamento"
 
 #
-"to unload filament"
+"to unload filament" c=20 r=2
 "para descargar el filamento"
 
 #MSG_UNLOAD_FILAMENT c=17
diff --git a/lang/lang_en_fr.txt b/lang/lang_en_fr.txt
index f64f800d..54dc7a7c 100644
--- a/lang/lang_en_fr.txt
+++ b/lang/lang_en_fr.txt
@@ -859,7 +859,7 @@
 "Impr. depuis la SD"
 
 #
-"Press the knob"
+"Press the knob" c=20 r=2
 "App. sur sur bouton"
 
 #MSG_PRINT_PAUSED c=20 r=1
@@ -1167,11 +1167,11 @@
 "Total des echecs"
 
 #
-"to load filament"
+"to load filament" c=20 r=2
 "pour charger le fil."
 
 #
-"to unload filament"
+"to unload filament" c=20 r=2
 "pour decharger fil."
 
 #MSG_UNLOAD_FILAMENT c=17
diff --git a/lang/lang_en_it.txt b/lang/lang_en_it.txt
index e3383336..d5846cba 100644
--- a/lang/lang_en_it.txt
+++ b/lang/lang_en_it.txt
@@ -859,7 +859,7 @@
 "Stampa da SD"
 
 #
-"Press the knob"
+"Press the knob" c=20 r=2
 "Premere la manopola"
 
 #MSG_PRINT_PAUSED c=20 r=1
@@ -1167,11 +1167,11 @@
 "Totale fallimenti"
 
 #
-"to load filament"
+"to load filament" c=20 r=2
 "per caricare il filamento"
 
 #
-"to unload filament"
+"to unload filament" c=20 r=2
 "per scaricare il filamento"
 
 #MSG_UNLOAD_FILAMENT c=17
diff --git a/lang/lang_en_pl.txt b/lang/lang_en_pl.txt
index b796c11a..eb4103ee 100644
--- a/lang/lang_en_pl.txt
+++ b/lang/lang_en_pl.txt
@@ -859,7 +859,7 @@
 "Druk z karty SD"
 
 #
-"Press the knob"
+"Press the knob" c=20 r=2
 "Wcisnij pokretlo"
 
 #MSG_PRINT_PAUSED c=20 r=1
@@ -1167,11 +1167,11 @@
 "Suma bledow"
 
 #
-"to load filament"
+"to load filament" c=20 r=2
 "aby zaladow. fil."
 
 #
-"to unload filament"
+"to unload filament" c=20 r=2
 "aby rozlad. filament"
 
 #MSG_UNLOAD_FILAMENT c=17

From aecbd7ab49ec5fb0f7ca84b6bd40fd3f6823145f Mon Sep 17 00:00:00 2001
From: 3d-gussner <3d.gussner@gmail.com>
Date: Mon, 8 Feb 2021 12:17:41 +0100
Subject: [PATCH 56/58] Fix `c=aa` location in lang files Fix too long
 translations in Spanish and Italian

---
 Firmware/ultralcd.cpp |  4 ++--
 lang/lang_en.txt      | 12 ++++++------
 lang/lang_en_cz.txt   | 12 ++++++------
 lang/lang_en_de.txt   | 12 ++++++------
 lang/lang_en_es.txt   | 16 ++++++++--------
 lang/lang_en_fr.txt   | 12 ++++++------
 lang/lang_en_it.txt   | 16 ++++++++--------
 lang/lang_en_pl.txt   | 12 ++++++------
 8 files changed, 48 insertions(+), 48 deletions(-)

diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp
index 0e654384..10fa2da3 100755
--- a/Firmware/ultralcd.cpp
+++ b/Firmware/ultralcd.cpp
@@ -2242,11 +2242,11 @@ switch(eFilamentAction)
      case FilamentAction::Load:
      case FilamentAction::AutoLoad:
      case FilamentAction::MmuLoad:
-          lcd_puts_P(_i("to load filament"));     ////MSG_ c=20 r=2
+          lcd_puts_P(_i("to load filament"));     ////MSG_ c=20
           break;
      case FilamentAction::UnLoad:
      case FilamentAction::MmuUnLoad:
-          lcd_puts_P(_i("to unload filament"));   ////MSG_ c=20 r=2
+          lcd_puts_P(_i("to unload filament"));   ////MSG_ c=20
           break;
      case FilamentAction::MmuEject:
      case FilamentAction::MmuCut:
diff --git a/lang/lang_en.txt b/lang/lang_en.txt
index 875aa370..8c0e6eb9 100644
--- a/lang/lang_en.txt
+++ b/lang/lang_en.txt
@@ -643,8 +643,8 @@
 #MSG_CARD_MENU
 "Print from SD"
 
-#
-"Press the knob" c=20 r=2
+# c=20
+"Press the knob"
 
 #MSG_PRINT_PAUSED c=20 r=1
 "Print paused"
@@ -874,11 +874,11 @@
 #MSG_TOTAL_FAILURES c=20
 "Total failures"
 
-#
-"to load filament" c=20 r=2
+# c=20
+"to load filament"
 
-#
-"to unload filament" c=20 r=2
+# c=20
+"to unload filament"
 
 #MSG_UNLOAD_FILAMENT c=17
 "Unload filament"
diff --git a/lang/lang_en_cz.txt b/lang/lang_en_cz.txt
index 3c8f0f06..2c0bc664 100644
--- a/lang/lang_en_cz.txt
+++ b/lang/lang_en_cz.txt
@@ -858,8 +858,8 @@
 "Print from SD"
 "Tisk z SD"
 
-#
-"Press the knob" c=20 r=2
+# c=20
+"Press the knob"
 "Stisknete hl. tlacitko"
 
 #MSG_PRINT_PAUSED c=20 r=1
@@ -1166,12 +1166,12 @@
 "Total failures"
 "Celkem selhani"
 
-#
-"to load filament" c=20 r=2
+# c=20
+"to load filament"
 "k zavedeni filamentu"
 
-#
-"to unload filament" c=20 r=2
+# c=20
+"to unload filament"
 "k vyjmuti filamentu"
 
 #MSG_UNLOAD_FILAMENT c=17
diff --git a/lang/lang_en_de.txt b/lang/lang_en_de.txt
index 649994d9..e6fd5bcc 100644
--- a/lang/lang_en_de.txt
+++ b/lang/lang_en_de.txt
@@ -858,8 +858,8 @@
 "Print from SD"
 "Drucken von SD"
 
-#
-"Press the knob" c=20 r=2
+# c=20
+"Press the knob"
 "Knopf druecken zum"
 
 #MSG_PRINT_PAUSED c=20 r=1
@@ -1166,12 +1166,12 @@
 "Total failures"
 "Gesamte Fehler"
 
-#
-"to load filament" c=20 r=2
+# c=20
+"to load filament"
 "Filament laden"
 
-#
-"to unload filament" c=20 r=2
+# c=20
+"to unload filament"
 "Filament entladen"
 
 #MSG_UNLOAD_FILAMENT c=17
diff --git a/lang/lang_en_es.txt b/lang/lang_en_es.txt
index 35913020..4e622ebb 100644
--- a/lang/lang_en_es.txt
+++ b/lang/lang_en_es.txt
@@ -858,8 +858,8 @@
 "Print from SD"
 "Menu tarjeta SD"
 
-#
-"Press the knob" c=20 r=2
+# c=20
+"Press the knob"
 "Pulsa el dial"
 
 #MSG_PRINT_PAUSED c=20 r=1
@@ -1166,13 +1166,13 @@
 "Total failures"
 "Fallos totales"
 
-#
-"to load filament" c=20 r=2
-"para cargar el filamento"
+# c=20
+"to load filament"
+"para cargar el fil."
 
-#
-"to unload filament" c=20 r=2
-"para descargar el filamento"
+# c=20
+"to unload filament"
+"para descargar fil."
 
 #MSG_UNLOAD_FILAMENT c=17
 "Unload filament"
diff --git a/lang/lang_en_fr.txt b/lang/lang_en_fr.txt
index 54dc7a7c..edf2bb8b 100644
--- a/lang/lang_en_fr.txt
+++ b/lang/lang_en_fr.txt
@@ -858,8 +858,8 @@
 "Print from SD"
 "Impr. depuis la SD"
 
-#
-"Press the knob" c=20 r=2
+# c=20
+"Press the knob"
 "App. sur sur bouton"
 
 #MSG_PRINT_PAUSED c=20 r=1
@@ -1166,12 +1166,12 @@
 "Total failures"
 "Total des echecs"
 
-#
-"to load filament" c=20 r=2
+# c=20
+"to load filament"
 "pour charger le fil."
 
-#
-"to unload filament" c=20 r=2
+# c=20
+"to unload filament"
 "pour decharger fil."
 
 #MSG_UNLOAD_FILAMENT c=17
diff --git a/lang/lang_en_it.txt b/lang/lang_en_it.txt
index d5846cba..043d1141 100644
--- a/lang/lang_en_it.txt
+++ b/lang/lang_en_it.txt
@@ -858,8 +858,8 @@
 "Print from SD"
 "Stampa da SD"
 
-#
-"Press the knob" c=20 r=2
+# c=20
+"Press the knob"
 "Premere la manopola"
 
 #MSG_PRINT_PAUSED c=20 r=1
@@ -1166,13 +1166,13 @@
 "Total failures"
 "Totale fallimenti"
 
-#
-"to load filament" c=20 r=2
-"per caricare il filamento"
+# c=20
+"to load filament"
+"per caricare il fil."
 
-#
-"to unload filament" c=20 r=2
-"per scaricare il filamento"
+# c=20
+"to unload filament"
+"per scaricare fil."
 
 #MSG_UNLOAD_FILAMENT c=17
 "Unload filament"
diff --git a/lang/lang_en_pl.txt b/lang/lang_en_pl.txt
index eb4103ee..4e6be18e 100644
--- a/lang/lang_en_pl.txt
+++ b/lang/lang_en_pl.txt
@@ -858,8 +858,8 @@
 "Print from SD"
 "Druk z karty SD"
 
-#
-"Press the knob" c=20 r=2
+# c=20
+"Press the knob"
 "Wcisnij pokretlo"
 
 #MSG_PRINT_PAUSED c=20 r=1
@@ -1166,12 +1166,12 @@
 "Total failures"
 "Suma bledow"
 
-#
-"to load filament" c=20 r=2
+# c=20
+"to load filament"
 "aby zaladow. fil."
 
-#
-"to unload filament" c=20 r=2
+# c=20
+"to unload filament"
 "aby rozlad. filament"
 
 #MSG_UNLOAD_FILAMENT c=17

From 5f49d65546a08d633ea452816718983f0a5a6acc Mon Sep 17 00:00:00 2001
From: "D.R.racer" <drracer@drracer.eu>
Date: Mon, 8 Feb 2021 09:49:11 +0100
Subject: [PATCH 57/58] Farmers' request - allow file sorting menu item

---
 Firmware/ultralcd.cpp | 15 ++++++---------
 1 file changed, 6 insertions(+), 9 deletions(-)

diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp
index 0f6bc1fa..d3686509 100755
--- a/Firmware/ultralcd.cpp
+++ b/Firmware/ultralcd.cpp
@@ -5291,16 +5291,13 @@ do\
     else\
         MENU_ITEM_TOGGLE_P(_T(MSG_SD_CARD), _T(MSG_NORMAL), lcd_toshiba_flash_air_compatibility_toggle);\
 \
-    if (!farm_mode)\
+    uint8_t sdSort;\
+    EEPROM_read(EEPROM_SD_SORT, (uint8_t*)&sdSort, sizeof(sdSort));\
+    switch (sdSort)\
     {\
-        uint8_t sdSort;\
-        EEPROM_read(EEPROM_SD_SORT, (uint8_t*)&sdSort, sizeof(sdSort));\
-        switch (sdSort)\
-        {\
-          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);\
-        }\
+      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);\
     }\
 }\
 while (0)

From 4fcbf95db65e33d4fa7ee561a510c8f79f2bdfd1 Mon Sep 17 00:00:00 2001
From: Alex Voinea <voinea.dragos.alexandru@gmail.com>
Date: Tue, 9 Feb 2021 15:00:46 +0200
Subject: [PATCH 58/58] apply RAII principle on the lsDive recursion limiter

---
 Firmware/cardreader.cpp | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/Firmware/cardreader.cpp b/Firmware/cardreader.cpp
index c414e282..3ca88f63 100644
--- a/Firmware/cardreader.cpp
+++ b/Firmware/cardreader.cpp
@@ -71,14 +71,22 @@ char *createFilename(char *buffer,const dir_t &p) //buffer>12characters
 
 void CardReader::lsDive(const char *prepend, SdFile parent, const char * const match/*=NULL*/) {
 	static uint8_t recursionCnt = 0;
+	// RAII incrementer for the recursionCnt
+	class _incrementer
+	{
+		public:
+		_incrementer() {recursionCnt++;}
+		~_incrementer() {recursionCnt--;}
+	} recursionCntIncrementer;
+	
 	dir_t p;
 	uint8_t cnt = 0;
 		// Read the next entry from a directory
 		while (parent.readDir(p, longFilename) > 0) {
-			if (recursionCnt >= MAX_DIR_DEPTH)
+			if (recursionCnt > MAX_DIR_DEPTH)
 				return;
 			else if (DIR_IS_SUBDIR(&p) && lsAction != LS_Count && lsAction != LS_GetFilename) { // If the entry is a directory and the action is LS_SerialPrint
-				recursionCnt++;
+				
 				// Get the short name for the item, which we know is a folder
 				char lfilename[FILENAME_LENGTH];
 				createFilename(lfilename, p);
@@ -112,7 +120,6 @@ void CardReader::lsDive(const char *prepend, SdFile parent, const char * const m
 				
 				if (lsAction == LS_SerialPrint_LFN)
 					puts_P(PSTR("DIR_EXIT"));
-				recursionCnt--;
 			}
 			else {
 				uint8_t pn0 = p.name[0];