From 02f904dbf9df999264099a26c563b07b1d163df4 Mon Sep 17 00:00:00 2001
From: Scott Lahteine <github@thinkyhead.com>
Date: Tue, 18 May 2021 22:53:52 -0500
Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Minimize=20endstop=20bits?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 Marlin/src/module/endstops.cpp | 17 ++++---
 Marlin/src/module/endstops.h   | 87 ++++++++++++++++++++++------------
 Marlin/src/module/stepper.cpp  |  8 ++--
 3 files changed, 68 insertions(+), 44 deletions(-)

diff --git a/Marlin/src/module/endstops.cpp b/Marlin/src/module/endstops.cpp
index 2ac20c92ef6..d0befe71fb5 100644
--- a/Marlin/src/module/endstops.cpp
+++ b/Marlin/src/module/endstops.cpp
@@ -56,12 +56,12 @@ Endstops endstops;
 // private:
 
 bool Endstops::enabled, Endstops::enabled_globally; // Initialized by settings.load()
-volatile uint8_t Endstops::hit_state;
 
-Endstops::esbits_t Endstops::live_state = 0;
+volatile Endstops::endstop_mask_t Endstops::hit_state;
+Endstops::endstop_mask_t Endstops::live_state = 0;
 
 #if ENDSTOP_NOISE_THRESHOLD
-  Endstops::esbits_t Endstops::validated_live_state;
+  Endstops::endstop_mask_t Endstops::validated_live_state;
   uint8_t Endstops::endstop_poll_count;
 #endif
 
@@ -356,7 +356,7 @@ void Endstops::resync() {
 #endif
 
 void Endstops::event_handler() {
-  static uint8_t prev_hit_state; // = 0
+  static endstop_mask_t prev_hit_state; // = 0
   if (hit_state == prev_hit_state) return;
   prev_hit_state = hit_state;
   if (hit_state) {
@@ -364,15 +364,14 @@ void Endstops::event_handler() {
       char chrX = ' ', chrY = ' ', chrZ = ' ', chrP = ' ';
       #define _SET_STOP_CHAR(A,C) (chr## A = C)
     #else
-      #define _SET_STOP_CHAR(A,C) ;
+      #define _SET_STOP_CHAR(A,C) NOOP
     #endif
 
     #define _ENDSTOP_HIT_ECHO(A,C) do{ \
-      SERIAL_ECHOPAIR(" " STRINGIFY(A) ":", planner.triggered_position_mm(_AXIS(A))); \
-      _SET_STOP_CHAR(A,C); }while(0)
+      SERIAL_ECHOPAIR(" " STRINGIFY(A) ":", planner.triggered_position_mm(_AXIS(A))); _SET_STOP_CHAR(A,C); }while(0)
 
     #define _ENDSTOP_HIT_TEST(A,C) \
-      if (TEST(hit_state, A ##_MIN) || TEST(hit_state, A ##_MAX)) \
+      if (TERN0(HAS_##A##_MIN, TEST(hit_state, A##_MIN)) || TERN0(HAS_##A##_MAX, TEST(hit_state, A##_MAX))) \
         _ENDSTOP_HIT_ECHO(A,C)
 
     #define ENDSTOP_HIT_TEST_X() _ENDSTOP_HIT_TEST(X,'X')
@@ -659,7 +658,7 @@ void Endstops::update() {
      * still exist. The only way to reduce them further is to increase the number of samples.
      * To reduce the chance to 1% (1/128th) requires 7 samples (adding 7ms of delay).
      */
-    static esbits_t old_live_state;
+    static endstop_mask_t old_live_state;
     if (old_live_state != live_state) {
       endstop_poll_count = ENDSTOP_NOISE_THRESHOLD;
       old_live_state = live_state;
diff --git a/Marlin/src/module/endstops.h b/Marlin/src/module/endstops.h
index 13e814aa1f9..7d18aaf850f 100644
--- a/Marlin/src/module/endstops.h
+++ b/Marlin/src/module/endstops.h
@@ -28,50 +28,75 @@
 #include "../inc/MarlinConfig.h"
 #include <stdint.h>
 
+#define __ES_ITEM(N) N,
+#define _ES_ITEM(K,N) TERN_(K,DEFER4(__ES_ITEM)(N))
+
 enum EndstopEnum : char {
-  X_MIN,  Y_MIN,  Z_MIN,  Z_MIN_PROBE,
-  X_MAX,  Y_MAX,  Z_MAX,
-  X2_MIN, X2_MAX,
-  Y2_MIN, Y2_MAX,
-  Z2_MIN, Z2_MAX,
-  Z3_MIN, Z3_MAX,
-  Z4_MIN, Z4_MAX
+  _ES_ITEM(HAS_X_MIN, X_MIN)
+  _ES_ITEM(HAS_X_MAX, X_MAX)
+  _ES_ITEM(HAS_Y_MIN, Y_MIN)
+  _ES_ITEM(HAS_Y_MAX, Y_MAX)
+  _ES_ITEM(HAS_Z_MIN, Z_MIN)
+  _ES_ITEM(HAS_Z_MAX, Z_MAX)
+  #if ENABLED(X_DUAL_ENDSTOPS)
+    _ES_ITEM(HAS_X_MIN, X2_MIN)
+    _ES_ITEM(HAS_X_MAX, X2_MAX)
+  #endif
+  #if ENABLED(Y_DUAL_ENDSTOPS)
+    _ES_ITEM(HAS_Y_MIN, Y2_MIN)
+    _ES_ITEM(HAS_Y_MAX, Y2_MAX)
+  #endif
+  #if ENABLED(Z_MULTI_ENDSTOPS)
+    _ES_ITEM(HAS_Z_MIN, Z2_MIN)
+    _ES_ITEM(HAS_Z_MAX, Z2_MAX)
+    #if NUM_Z_STEPPER_DRIVERS >= 3
+      _ES_ITEM(HAS_Z_MIN, Z3_MIN)
+      _ES_ITEM(HAS_Z_MAX, Z3_MAX)
+    #endif
+    #if NUM_Z_STEPPER_DRIVERS >= 4
+      _ES_ITEM(HAS_Z_MIN, Z4_MIN)
+      _ES_ITEM(HAS_Z_MAX, Z4_MAX)
+    #endif
+  #endif
+  _ES_ITEM(HAS_Z_MIN_PROBE_PIN, Z_MIN_PROBE)
+  NUM_ENDSTOP_STATES
 };
 
 #define X_ENDSTOP (x_home_dir(active_extruder) < 0 ? X_MIN : X_MAX)
 #define Y_ENDSTOP (Y_HOME_DIR < 0 ? Y_MIN : Y_MAX)
 #define Z_ENDSTOP (Z_HOME_DIR < 0 ? TERN(HOMING_Z_WITH_PROBE, Z_MIN, Z_MIN_PROBE) : Z_MAX)
 
+#undef __ES_ITEM
+#undef _ES_ITEM
+
 class Endstops {
   public:
-    #if HAS_EXTRA_ENDSTOPS
-      typedef uint16_t esbits_t;
-      #if ENABLED(X_DUAL_ENDSTOPS)
-        static float x2_endstop_adj;
-      #endif
-      #if ENABLED(Y_DUAL_ENDSTOPS)
-        static float y2_endstop_adj;
-      #endif
-      #if ENABLED(Z_MULTI_ENDSTOPS)
-        static float z2_endstop_adj;
-      #endif
-      #if ENABLED(Z_MULTI_ENDSTOPS) && NUM_Z_STEPPER_DRIVERS >= 3
-        static float z3_endstop_adj;
-      #endif
-      #if ENABLED(Z_MULTI_ENDSTOPS) && NUM_Z_STEPPER_DRIVERS >= 4
-        static float z4_endstop_adj;
-      #endif
-    #else
-      typedef uint8_t esbits_t;
+
+    typedef IF<(NUM_ENDSTOP_STATES > 8), uint16_t, uint8_t>::type endstop_mask_t;
+
+    #if ENABLED(X_DUAL_ENDSTOPS)
+      static float x2_endstop_adj;
+    #endif
+    #if ENABLED(Y_DUAL_ENDSTOPS)
+      static float y2_endstop_adj;
+    #endif
+    #if ENABLED(Z_MULTI_ENDSTOPS)
+      static float z2_endstop_adj;
+    #endif
+    #if ENABLED(Z_MULTI_ENDSTOPS) && NUM_Z_STEPPER_DRIVERS >= 3
+      static float z3_endstop_adj;
+    #endif
+    #if ENABLED(Z_MULTI_ENDSTOPS) && NUM_Z_STEPPER_DRIVERS >= 4
+      static float z4_endstop_adj;
     #endif
 
   private:
     static bool enabled, enabled_globally;
-    static esbits_t live_state;
-    static volatile uint8_t hit_state;      // Use X_MIN, Y_MIN, Z_MIN and Z_MIN_PROBE as BIT index
+    static endstop_mask_t live_state;
+    static volatile endstop_mask_t hit_state; // Use X_MIN, Y_MIN, Z_MIN and Z_MIN_PROBE as BIT index
 
     #if ENDSTOP_NOISE_THRESHOLD
-      static esbits_t validated_live_state;
+      static endstop_mask_t validated_live_state;
       static uint8_t endstop_poll_count;    // Countdown from threshold for polling
     #endif
 
@@ -107,12 +132,12 @@ class Endstops {
     /**
      * Get Endstop hit state.
      */
-    FORCE_INLINE static uint8_t trigger_state() { return hit_state; }
+    FORCE_INLINE static endstop_mask_t trigger_state() { return hit_state; }
 
     /**
      * Get current endstops state
      */
-    FORCE_INLINE static esbits_t state() {
+    FORCE_INLINE static endstop_mask_t state() {
       return
         #if ENDSTOP_NOISE_THRESHOLD
           validated_live_state
diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp
index ff2be0c3565..e8f578ae91f 100644
--- a/Marlin/src/module/stepper.cpp
+++ b/Marlin/src/module/stepper.cpp
@@ -260,12 +260,12 @@ xyze_int8_t Stepper::count_direction{0};
 #define DUAL_ENDSTOP_APPLY_STEP(A,V)                                                                                        \
   if (separate_multi_axis) {                                                                                                \
     if (A##_HOME_DIR < 0) {                                                                                                 \
-      if (!(TEST(endstops.state(), A##_MIN) && count_direction[_AXIS(A)] < 0) && !locked_##A##_motor) A##_STEP_WRITE(V);    \
-      if (!(TEST(endstops.state(), A##2_MIN) && count_direction[_AXIS(A)] < 0) && !locked_##A##2_motor) A##2_STEP_WRITE(V); \
+      if (TERN0(HAS_##A##_MIN, !(TEST(endstops.state(), A##_MIN) && count_direction[_AXIS(A)] < 0) && !locked_##A##_motor)) A##_STEP_WRITE(V);     \
+      if (TERN0(HAS_##A##2_MIN, !(TEST(endstops.state(), A##2_MIN) && count_direction[_AXIS(A)] < 0) && !locked_##A##2_motor)) A##2_STEP_WRITE(V); \
     }                                                                                                                       \
     else {                                                                                                                  \
-      if (!(TEST(endstops.state(), A##_MAX) && count_direction[_AXIS(A)] > 0) && !locked_##A##_motor) A##_STEP_WRITE(V);    \
-      if (!(TEST(endstops.state(), A##2_MAX) && count_direction[_AXIS(A)] > 0) && !locked_##A##2_motor) A##2_STEP_WRITE(V); \
+      if (TERN0(HAS_##A##_MAX, !(TEST(endstops.state(), A##_MAX) && count_direction[_AXIS(A)] > 0) && !locked_##A##_motor)) A##_STEP_WRITE(V);     \
+      if (TERN0(HAS_##A##2_MAX, !(TEST(endstops.state(), A##2_MAX) && count_direction[_AXIS(A)] > 0) && !locked_##A##2_motor)) A##2_STEP_WRITE(V); \
     }                                                                                                                       \
   }                                                                                                                         \
   else {                                                                                                                    \