| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -209,113 +209,145 @@ enum StealthIndex : uint8_t { STEALTH_AXIS_XY, STEALTH_AXIS_Z, STEALTH_AXIS_E };
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #if AXIS_HAS_UART(X)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #ifdef X_HARDWARE_SERIAL
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      TMC_UART_DEFINE(HW, X, X);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      #define X_HAS_HW_SERIAL 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #else
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      TMC_UART_DEFINE(SW, X, X);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      #define X_HAS_SW_SERIAL 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #if AXIS_HAS_UART(X2)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #ifdef X2_HARDWARE_SERIAL
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      TMC_UART_DEFINE(HW, X2, X);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      #define X2_HAS_HW_SERIAL 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #else
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      TMC_UART_DEFINE(SW, X2, X);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      #define X2_HAS_SW_SERIAL 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #if AXIS_HAS_UART(Y)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #ifdef Y_HARDWARE_SERIAL
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      TMC_UART_DEFINE(HW, Y, Y);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      #define Y_HAS_HW_SERIAL 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #else
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      TMC_UART_DEFINE(SW, Y, Y);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      #define Y_HAS_SW_SERIAL 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #if AXIS_HAS_UART(Y2)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #ifdef Y2_HARDWARE_SERIAL
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      TMC_UART_DEFINE(HW, Y2, Y);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      #define Y2_HAS_HW_SERIAL 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #else
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      TMC_UART_DEFINE(SW, Y2, Y);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      #define Y2_HAS_SW_SERIAL 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #if AXIS_HAS_UART(Z)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #ifdef Z_HARDWARE_SERIAL
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      TMC_UART_DEFINE(HW, Z, Z);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      #define Z_HAS_HW_SERIAL 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #else
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      TMC_UART_DEFINE(SW, Z, Z);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      #define Z_HAS_SW_SERIAL 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #if AXIS_HAS_UART(Z2)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #ifdef Z2_HARDWARE_SERIAL
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      TMC_UART_DEFINE(HW, Z2, Z);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      #define Z2_HAS_HW_SERIAL 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #else
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      TMC_UART_DEFINE(SW, Z2, Z);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      #define Z2_HAS_SW_SERIAL 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #if AXIS_HAS_UART(Z3)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #ifdef Z3_HARDWARE_SERIAL
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      TMC_UART_DEFINE(HW, Z3, Z);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      #define Z3_HAS_HW_SERIAL 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #else
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      TMC_UART_DEFINE(SW, Z3, Z);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      #define Z3_HAS_SW_SERIAL 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #if AXIS_HAS_UART(Z4)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #ifdef Z4_HARDWARE_SERIAL
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      TMC_UART_DEFINE(HW, Z4, Z);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      #define Z4_HAS_HW_SERIAL 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #else
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      TMC_UART_DEFINE(SW, Z4, Z);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      #define Z4_HAS_SW_SERIAL 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #if AXIS_HAS_UART(E0)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #ifdef E0_HARDWARE_SERIAL
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      TMC_UART_DEFINE_E(HW, 0);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      #define E0_HAS_HW_SERIAL 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #else
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      TMC_UART_DEFINE_E(SW, 0);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      #define E0_HAS_SW_SERIAL 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #if AXIS_HAS_UART(E1)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #ifdef E1_HARDWARE_SERIAL
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      TMC_UART_DEFINE_E(HW, 1);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      #define E1_HAS_HW_SERIAL 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #else
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      TMC_UART_DEFINE_E(SW, 1);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      #define E1_HAS_SW_SERIAL 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #if AXIS_HAS_UART(E2)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #ifdef E2_HARDWARE_SERIAL
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      TMC_UART_DEFINE_E(HW, 2);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      #define E2_HAS_HW_SERIAL 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #else
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      TMC_UART_DEFINE_E(SW, 2);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      #define E2_HAS_SW_SERIAL 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #if AXIS_HAS_UART(E3)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #ifdef E3_HARDWARE_SERIAL
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      TMC_UART_DEFINE_E(HW, 3);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      #define E3_HAS_HW_SERIAL 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #else
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      TMC_UART_DEFINE_E(SW, 3);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      #define E3_HAS_SW_SERIAL 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #if AXIS_HAS_UART(E4)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #ifdef E4_HARDWARE_SERIAL
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      TMC_UART_DEFINE_E(HW, 4);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      #define E4_HAS_HW_SERIAL 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #else
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      TMC_UART_DEFINE_E(SW, 4);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      #define E4_HAS_SW_SERIAL 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #if AXIS_HAS_UART(E5)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #ifdef E5_HARDWARE_SERIAL
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      TMC_UART_DEFINE_E(HW, 5);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      #define E5_HAS_HW_SERIAL 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #else
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      TMC_UART_DEFINE_E(SW, 5);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      #define E5_HAS_SW_SERIAL 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #if AXIS_HAS_UART(E6)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #ifdef E6_HARDWARE_SERIAL
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      TMC_UART_DEFINE_E(HW, 6);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      #define E6_HAS_HW_SERIAL 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #else
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      TMC_UART_DEFINE_E(SW, 6);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      #define E6_HAS_SW_SERIAL 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #if AXIS_HAS_UART(E7)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #ifdef E7_HARDWARE_SERIAL
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      TMC_UART_DEFINE_E(HW, 7);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      #define E7_HAS_HW_SERIAL 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #else
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      TMC_UART_DEFINE_E(SW, 7);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      #define E7_HAS_SW_SERIAL 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -769,4 +801,77 @@ void reset_trinamic_drivers() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  stepper.set_directions();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// TMC Slave Address Conflict Detection
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// Conflict detection is performed in the following way. Similar methods are used for
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// hardware and software serial, but the implementations are indepenent.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// 1. Populate a data structure with UART parameters and addresses for all possible axis.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				//      If an axis is not in use, populate it with recognizable placeholder data.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// 2. For each axis in use, static_assert using a constexpr function, which counts the
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				//      number of matching/conflicting axis. If the value is not exactly 1, fail.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#if ANY_AXIS_HAS(HW_SERIAL)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  // Hardware serial names are compared as strings, since actually resolving them cannot occur in a constexpr.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  // Using a fixed-length character array for the port name allows this to be constexpr compatible.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  struct SanityHwSerialDetails { const char port[20]; uint32_t address; };
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #define TMC_HW_DETAIL_ARGS(A) TERN(A##_HAS_HW_SERIAL, STRINGIFY(A##_HARDWARE_SERIAL), ""), TERN0(A##_HAS_HW_SERIAL, A##_SLAVE_ADDRESS)  
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #define TMC_HW_DETAIL(A) {TMC_HW_DETAIL_ARGS(A)}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  constexpr SanityHwSerialDetails sanity_tmc_hw_details[] = {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    TMC_HW_DETAIL(X), TMC_HW_DETAIL(X2),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    TMC_HW_DETAIL(Y), TMC_HW_DETAIL(Y2),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    TMC_HW_DETAIL(Z), TMC_HW_DETAIL(Z2), TMC_HW_DETAIL(Z3), TMC_HW_DETAIL(Z4),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    TMC_HW_DETAIL(E0), TMC_HW_DETAIL(E1), TMC_HW_DETAIL(E2), TMC_HW_DETAIL(E3), TMC_HW_DETAIL(E4), TMC_HW_DETAIL(E5), TMC_HW_DETAIL(E6), TMC_HW_DETAIL(E7)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  };
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  // constexpr compatible string comparison
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  constexpr bool str_eq_ce(const char * a, const char * b) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    return *a == *b && (*a == '\0' || str_eq_ce(a+1,b+1));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  constexpr bool sc_hw_done(size_t start, size_t end) { return start == end; }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  constexpr bool sc_hw_skip(const char* port_name) { return !(*port_name); }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  constexpr bool sc_hw_match(const char* port_name, uint32_t address, size_t start, size_t end) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    return !sc_hw_done(start, end) && !sc_hw_skip(port_name) && (address == sanity_tmc_hw_details[start].address && str_eq_ce(port_name, sanity_tmc_hw_details[start].port));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  constexpr int count_tmc_hw_serial_matches(const char* port_name, uint32_t address, size_t start, size_t end) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    return sc_hw_done(start, end) ? 0 : ((sc_hw_skip(port_name) ? 0 : (sc_hw_match(port_name, address, start, end) ? 1 : 0)) + count_tmc_hw_serial_matches(port_name, address, start + 1, end));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #define TMC_HWSERIAL_CONFLICT_MSG(A) STRINGIFY(A) "_SLAVE_ADDRESS conflicts with another driver using the same " STRINGIFY(A) "_HARDWARE_SERIAL"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #define SA_NO_TMC_HW_C(A) static_assert(1 >= count_tmc_hw_serial_matches(TMC_HW_DETAIL_ARGS(A), 0, COUNT(sanity_tmc_hw_details)), TMC_HWSERIAL_CONFLICT_MSG(A));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  SA_NO_TMC_HW_C(X);SA_NO_TMC_HW_C(X2);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  SA_NO_TMC_HW_C(Y);SA_NO_TMC_HW_C(Y2);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  SA_NO_TMC_HW_C(Z);SA_NO_TMC_HW_C(Z2);SA_NO_TMC_HW_C(Z3);SA_NO_TMC_HW_C(Z4);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  SA_NO_TMC_HW_C(E0);SA_NO_TMC_HW_C(E1);SA_NO_TMC_HW_C(E2);SA_NO_TMC_HW_C(E3);SA_NO_TMC_HW_C(E4);SA_NO_TMC_HW_C(E5);SA_NO_TMC_HW_C(E6);SA_NO_TMC_HW_C(E7);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#if ANY_AXIS_HAS(SW_SERIAL)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  struct SanitySwSerialDetails { int32_t txpin; int32_t rxpin; uint32_t address; };
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #define TMC_SW_DETAIL_ARGS(A) TERN(A##_HAS_SW_SERIAL, A##_SERIAL_TX_PIN, -1), TERN(A##_HAS_SW_SERIAL, A##_SERIAL_RX_PIN, -1), TERN0(A##_HAS_SW_SERIAL, A##_SLAVE_ADDRESS)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #define TMC_SW_DETAIL(A) TMC_SW_DETAIL_ARGS(A)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  constexpr SanitySwSerialDetails sanity_tmc_sw_details[] = {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    TMC_SW_DETAIL(X), TMC_SW_DETAIL(X2),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    TMC_SW_DETAIL(Y), TMC_SW_DETAIL(Y2),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    TMC_SW_DETAIL(Z), TMC_SW_DETAIL(Z2), TMC_SW_DETAIL(Z3), TMC_SW_DETAIL(Z4),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    TMC_SW_DETAIL(E0), TMC_SW_DETAIL(E1), TMC_SW_DETAIL(E2), TMC_SW_DETAIL(E3), TMC_SW_DETAIL(E4), TMC_SW_DETAIL(E5), TMC_SW_DETAIL(E6), TMC_SW_DETAIL(E7)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  };
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  constexpr bool sc_sw_done(size_t start, size_t end) { return start == end; }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  constexpr bool sc_sw_skip(int32_t txpin) { return txpin < 0; }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  constexpr bool sc_sw_match(int32_t txpin, int32_t rxpin, uint32_t address, size_t start, size_t end) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    return !sc_sw_done(start, end) && !sc_sw_skip(txpin) && (txpin == sanity_tmc_sw_details[start].txpin || rxpin == sanity_tmc_sw_details[start].rxpin) && (address == sanity_tmc_sw_details[start].address);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  constexpr int count_tmc_sw_serial_matches(int32_t txpin, int32_t rxpin, uint32_t address, size_t start, size_t end) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    return sc_sw_done(start, end) ? 0 : ((sc_sw_skip(txpin) ? 0 : (sc_sw_match(txpin, rxpin, address, start, end) ? 1 : 0)) + count_tmc_sw_serial_matches(txpin, rxpin, address, start + 1, end));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #define TMC_SWSERIAL_CONFLICT_MSG(A) STRINGIFY(A) "_SLAVE_ADDRESS conflicts with another driver using the same " STRINGIFY(A) "_SERIAL_RX_PIN or " STRINGIFY(A) "_SERIAL_TX_PIN"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  #define SA_NO_TMC_SW_C(A) static_assert(1 >= count_tmc_sw_serial_matches(TMC_SW_DETAIL_ARGS(A), 0, COUNT(sanity_tmc_sw_details)), TMC_SWSERIAL_CONFLICT_MSG(A));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  SA_NO_TMC_SW_C(X);SA_NO_TMC_SW_C(X2);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  SA_NO_TMC_SW_C(Y);SA_NO_TMC_SW_C(Y2);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  SA_NO_TMC_SW_C(Z);SA_NO_TMC_SW_C(Z2);SA_NO_TMC_SW_C(Z3);SA_NO_TMC_SW_C(Z4);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  SA_NO_TMC_SW_C(E0);SA_NO_TMC_SW_C(E1);SA_NO_TMC_SW_C(E2);SA_NO_TMC_SW_C(E3);SA_NO_TMC_SW_C(E4);SA_NO_TMC_SW_C(E5);SA_NO_TMC_SW_C(E6);SA_NO_TMC_SW_C(E7);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#endif // HAS_TRINAMIC_CONFIG
 | 
			
		
		
	
	
		
			
				
					
					| 
						 
							
							
							
						 
					 | 
				
			
			 | 
			 | 
			
				 
 |