diff --git a/Marlin/src/core/serial.cpp b/Marlin/src/core/serial.cpp index b4184fcd623b..60729440e6e7 100644 --- a/Marlin/src/core/serial.cpp +++ b/Marlin/src/core/serial.cpp @@ -101,8 +101,11 @@ void print_bin(uint16_t val) { } } -void print_pos(const_float_t x, const_float_t y, const_float_t z, PGM_P const prefix/*=nullptr*/, PGM_P const suffix/*=nullptr*/) { +void print_pos( + LINEAR_AXIS_LIST(const_float_t x, const_float_t y, const_float_t z) + , PGM_P const prefix/*=nullptr*/, PGM_P const suffix/*=nullptr*/ +) { if (prefix) serialprintPGM(prefix); - SERIAL_ECHOPAIR_P(SP_X_STR, x, SP_Y_STR, y, SP_Z_STR, z); + SERIAL_ECHOPAIR_P(LIST_N(DOUBLE(LINEAR_AXES), SP_X_STR, x, SP_Y_STR, y, SP_Z_STR, z)); if (suffix) serialprintPGM(suffix); else SERIAL_EOL(); } diff --git a/Marlin/src/core/serial.h b/Marlin/src/core/serial.h index 74b96dbb6476..6f893795df7b 100644 --- a/Marlin/src/core/serial.h +++ b/Marlin/src/core/serial.h @@ -310,10 +310,13 @@ void serialprint_truefalse(const bool tf); void serial_spaces(uint8_t count); void print_bin(const uint16_t val); -void print_pos(const_float_t x, const_float_t y, const_float_t z, PGM_P const prefix=nullptr, PGM_P const suffix=nullptr); +void print_pos( + LINEAR_AXIS_LIST(const_float_t x, const_float_t y, const_float_t z), + PGM_P const prefix=nullptr, PGM_P const suffix=nullptr +); inline void print_pos(const xyz_pos_t &xyz, PGM_P const prefix=nullptr, PGM_P const suffix=nullptr) { - print_pos(xyz.x, xyz.y, xyz.z, prefix, suffix); + print_pos(LINEAR_AXIS_LIST(xyz.x, xyz.y, xyz.z), prefix, suffix); } #define SERIAL_POS(SUFFIX,VAR) do { print_pos(VAR, PSTR(" " STRINGIFY(VAR) "="), PSTR(" : " SUFFIX "\n")); }while(0) diff --git a/Marlin/src/core/types.h b/Marlin/src/core/types.h index b7ae85eb2ee1..41cb39f16303 100644 --- a/Marlin/src/core/types.h +++ b/Marlin/src/core/types.h @@ -39,6 +39,26 @@ struct IF { typedef R type; }; template struct IF { typedef L type; }; +#define LINEAR_AXIS_GANG(V...) GANG_N(LINEAR_AXES, V) +#define LINEAR_AXIS_CODE(V...) CODE_N(LINEAR_AXES, V) +#define LINEAR_AXIS_LIST(V...) LIST_N(LINEAR_AXES, V) +#define LINEAR_AXIS_ARRAY(V...) { LINEAR_AXIS_LIST(V) } + +#define LOGICAL_AXIS_GANG(E,V...) LINEAR_AXIS_GANG(V) GANG_ITEM_E(E) +#define LOGICAL_AXIS_CODE(E,V...) LINEAR_AXIS_CODE(V) CODE_ITEM_E(E) +#define LOGICAL_AXIS_LIST(E,V...) LINEAR_AXIS_LIST(V) LIST_ITEM_E(E) +#define LOGICAL_AXIS_ARRAY(E,V...) { LOGICAL_AXIS_LIST(E,V) } + +#if HAS_EXTRUDERS + #define LIST_ITEM_E(N) , N + #define CODE_ITEM_E(N) ; N + #define GANG_ITEM_E(N) N +#else + #define LIST_ITEM_E(N) + #define CODE_ITEM_E(N) + #define GANG_ITEM_E(N) +#endif + // // Enumerated axis indices // @@ -47,16 +67,43 @@ struct IF { typedef L type; }; // - X_HEAD, Y_HEAD, and Z_HEAD should be used for Steppers on Core kinematics // enum AxisEnum : uint8_t { - X_AXIS = 0, A_AXIS = X_AXIS, - Y_AXIS = 1, B_AXIS = Y_AXIS, - Z_AXIS = 2, C_AXIS = Z_AXIS, - E_AXIS, - X_HEAD, Y_HEAD, Z_HEAD, - E0_AXIS = E_AXIS, - E1_AXIS, E2_AXIS, E3_AXIS, E4_AXIS, E5_AXIS, E6_AXIS, E7_AXIS, + + // Linear axes may be controlled directly or indirectly + LINEAR_AXIS_LIST(X_AXIS, Y_AXIS, Z_AXIS), + + // Extruder axes may be considered distinctly + #define _EN_ITEM(N) E##N##_AXIS, + REPEAT(EXTRUDERS, _EN_ITEM) + #undef _EN_ITEM + + // Core also keeps toolhead directions + #if IS_CORE + X_HEAD, Y_HEAD, Z_HEAD, + #endif + + // Distinct axes, including all E and Core + NUM_AXIS_ENUMS, + + // Most of the time we refer only to the single E_AXIS + #if HAS_EXTRUDERS + E_AXIS = E0_AXIS, + #endif + + // A, B, and C are for DELTA, SCARA, etc. + A_AXIS = X_AXIS, + #if LINEAR_AXES >= 2 + B_AXIS = Y_AXIS, + #endif + #if LINEAR_AXES >= 3 + C_AXIS = Z_AXIS, + #endif + + // To refer to all or none ALL_AXES_ENUM = 0xFE, NO_AXIS_ENUM = 0xFF }; +typedef IF<(NUM_AXIS_ENUMS > 8), uint16_t, uint8_t>::type axis_bits_t; + // // Loop over axes // @@ -185,7 +232,7 @@ void toNative(xyz_pos_t &raw); void toNative(xyze_pos_t &raw); // -// XY coordinates, counters, etc. +// Paired XY coordinates, counters, flags, etc. // template struct XYval { @@ -197,10 +244,14 @@ struct XYval { FI void set(const T px) { x = px; } FI void set(const T px, const T py) { x = px; y = py; } FI void set(const T (&arr)[XY]) { x = arr[0]; y = arr[1]; } - FI void set(const T (&arr)[XYZ]) { x = arr[0]; y = arr[1]; } - FI void set(const T (&arr)[XYZE]) { x = arr[0]; y = arr[1]; } - #if DISTINCT_AXES > LOGICAL_AXES - FI void set(const T (&arr)[DISTINCT_AXES]) { x = arr[0]; y = arr[1]; } + #if LINEAR_AXES > XY + FI void set(const T (&arr)[LINEAR_AXES]) { x = arr[0]; y = arr[1]; } + #endif + #if LOGICAL_AXES > LINEAR_AXES + FI void set(const T (&arr)[LOGICAL_AXES]) { x = arr[0]; y = arr[1]; } + #if DISTINCT_AXES > LOGICAL_AXES + FI void set(const T (&arr)[DISTINCT_AXES]) { x = arr[0]; y = arr[1]; } + #endif #endif FI void reset() { x = y = 0; } FI T magnitude() const { return (T)sqrtf(x*x + y*y); } @@ -223,8 +274,8 @@ struct XYval { FI operator XYZval() const { return { x, y }; } FI operator XYZEval() { return { x, y }; } FI operator XYZEval() const { return { x, y }; } - FI T& operator[](const int i) { return pos[i]; } - FI const T& operator[](const int i) const { return pos[i]; } + FI T& operator[](const int n) { return pos[n]; } + FI const T& operator[](const int n) const { return pos[n]; } FI XYval& operator= (const T v) { set(v, v ); return *this; } FI XYval& operator= (const XYZval &rs) { set(rs.x, rs.y); return *this; } FI XYval& operator= (const XYZEval &rs) { set(rs.x, rs.y); return *this; } @@ -294,219 +345,227 @@ struct XYval { }; // -// XYZ coordinates, counters, etc. +// Linear Axes coordinates, counters, flags, etc. // template struct XYZval { union { - struct { T x, y, z; }; - struct { T a, b, c; }; - T pos[3]; + struct { T LINEAR_AXIS_LIST(x, y, z); }; + struct { T LINEAR_AXIS_LIST(a, b, c); }; + T pos[LINEAR_AXES]; }; FI void set(const T px) { x = px; } FI void set(const T px, const T py) { x = px; y = py; } - FI void set(const T px, const T py, const T pz) { x = px; y = py; z = pz; } + FI void set(const XYval pxy) { x = pxy.x; y = pxy.y; } FI void set(const XYval pxy, const T pz) { x = pxy.x; y = pxy.y; z = pz; } FI void set(const T (&arr)[XY]) { x = arr[0]; y = arr[1]; } - FI void set(const T (&arr)[XYZ]) { x = arr[0]; y = arr[1]; z = arr[2]; } - FI void set(const T (&arr)[XYZE]) { x = arr[0]; y = arr[1]; z = arr[2]; } - #if DISTINCT_AXES > XYZE - FI void set(const T (&arr)[DISTINCT_AXES]) { x = arr[0]; y = arr[1]; z = arr[2]; } + FI void set(const T (&arr)[LINEAR_AXES]) { LINEAR_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2]); } + #if LINEAR_AXES >= XYZ + FI void set(LINEAR_AXIS_LIST(const T px, const T py, const T pz)) + { LINEAR_AXIS_CODE(x = px, y = py, z = pz); } + #endif + #if LOGICAL_AXES > LINEAR_AXES + FI void set(const T (&arr)[LOGICAL_AXES]) { LINEAR_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2]); } + FI void set(LOGICAL_AXIS_LIST(const T, const T px, const T py, const T pz)) + { LINEAR_AXIS_CODE(x = px, y = py, z = pz); } + #if DISTINCT_AXES > LOGICAL_AXES + FI void set(const T (&arr)[DISTINCT_AXES]) { LINEAR_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2]); } + #endif #endif - FI void reset() { x = y = z = 0; } - FI T magnitude() const { return (T)sqrtf(x*x + y*y + z*z); } + FI void reset() { LINEAR_AXIS_GANG(x =, y =, z =) 0; } + FI T magnitude() const { return (T)sqrtf(LINEAR_AXIS_GANG(x*x, + y*y, + z*z)); } FI operator T* () { return pos; } - FI operator bool() { return z || x || y; } + FI operator bool() { return LINEAR_AXIS_GANG(z, || x, || y); } FI XYZval copy() const { XYZval o = *this; return o; } - FI XYZval ABS() const { return { T(_ABS(x)), T(_ABS(y)), T(_ABS(z)) }; } - FI XYZval asInt() { return { int16_t(x), int16_t(y), int16_t(z) }; } - FI XYZval asInt() const { return { int16_t(x), int16_t(y), int16_t(z) }; } - FI XYZval asLong() { return { int32_t(x), int32_t(y), int32_t(z) }; } - FI XYZval asLong() const { return { int32_t(x), int32_t(y), int32_t(z) }; } - FI XYZval ROUNDL() { return { int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)) }; } - FI XYZval ROUNDL() const { return { int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)) }; } - FI XYZval asFloat() { return { static_cast(x), static_cast(y), static_cast(z) }; } - FI XYZval asFloat() const { return { static_cast(x), static_cast(y), static_cast(z) }; } - FI XYZval reciprocal() const { return { _RECIP(x), _RECIP(y), _RECIP(z) }; } + FI XYZval ABS() const { return LINEAR_AXIS_ARRAY(T(_ABS(x)), T(_ABS(y)), T(_ABS(z))); } + FI XYZval asInt() { return LINEAR_AXIS_ARRAY(int16_t(x), int16_t(y), int16_t(z)); } + FI XYZval asInt() const { return LINEAR_AXIS_ARRAY(int16_t(x), int16_t(y), int16_t(z)); } + FI XYZval asLong() { return LINEAR_AXIS_ARRAY(int32_t(x), int32_t(y), int32_t(z)); } + FI XYZval asLong() const { return LINEAR_AXIS_ARRAY(int32_t(x), int32_t(y), int32_t(z)); } + FI XYZval ROUNDL() { return LINEAR_AXIS_ARRAY(int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z))); } + FI XYZval ROUNDL() const { return LINEAR_AXIS_ARRAY(int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z))); } + FI XYZval asFloat() { return LINEAR_AXIS_ARRAY(static_cast(x), static_cast(y), static_cast(z)); } + FI XYZval asFloat() const { return LINEAR_AXIS_ARRAY(static_cast(x), static_cast(y), static_cast(z)); } + FI XYZval reciprocal() const { return LINEAR_AXIS_ARRAY(_RECIP(x), _RECIP(y), _RECIP(z)); } FI XYZval asLogical() const { XYZval o = asFloat(); toLogical(o); return o; } FI XYZval asNative() const { XYZval o = asFloat(); toNative(o); return o; } FI operator XYval&() { return *(XYval*)this; } FI operator const XYval&() const { return *(const XYval*)this; } - FI operator XYZEval() const { return { x, y, z }; } - FI T& operator[](const int i) { return pos[i]; } - FI const T& operator[](const int i) const { return pos[i]; } - FI XYZval& operator= (const T v) { set(v, v, v ); return *this; } + FI operator XYZEval() const { return LINEAR_AXIS_ARRAY(x, y, z); } + FI T& operator[](const int n) { return pos[n]; } + FI const T& operator[](const int n) const { return pos[n]; } + FI XYZval& operator= (const T v) { set(ARRAY_N_1(LINEAR_AXES, v)); return *this; } FI XYZval& operator= (const XYval &rs) { set(rs.x, rs.y ); return *this; } - FI XYZval& operator= (const XYZEval &rs) { set(rs.x, rs.y, rs.z); return *this; } - FI XYZval operator+ (const XYval &rs) const { XYZval ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; } - FI XYZval operator+ (const XYval &rs) { XYZval ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; } - FI XYZval operator- (const XYval &rs) const { XYZval ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; } - FI XYZval operator- (const XYval &rs) { XYZval ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; } - FI XYZval operator* (const XYval &rs) const { XYZval ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; } - FI XYZval operator* (const XYval &rs) { XYZval ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; } - FI XYZval operator/ (const XYval &rs) const { XYZval ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; } - FI XYZval operator/ (const XYval &rs) { XYZval ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; } - FI XYZval operator+ (const XYZval &rs) const { XYZval ls = *this; ls.x += rs.x; ls.y += rs.y; ls.z += rs.z; return ls; } - FI XYZval operator+ (const XYZval &rs) { XYZval ls = *this; ls.x += rs.x; ls.y += rs.y; ls.z += rs.z; return ls; } - FI XYZval operator- (const XYZval &rs) const { XYZval ls = *this; ls.x -= rs.x; ls.y -= rs.y; ls.z -= rs.z; return ls; } - FI XYZval operator- (const XYZval &rs) { XYZval ls = *this; ls.x -= rs.x; ls.y -= rs.y; ls.z -= rs.z; return ls; } - FI XYZval operator* (const XYZval &rs) const { XYZval ls = *this; ls.x *= rs.x; ls.y *= rs.y; ls.z *= rs.z; return ls; } - FI XYZval operator* (const XYZval &rs) { XYZval ls = *this; ls.x *= rs.x; ls.y *= rs.y; ls.z *= rs.z; return ls; } - FI XYZval operator/ (const XYZval &rs) const { XYZval ls = *this; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; return ls; } - FI XYZval operator/ (const XYZval &rs) { XYZval ls = *this; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; return ls; } - FI XYZval operator+ (const XYZEval &rs) const { XYZval ls = *this; ls.x += rs.x; ls.y += rs.y; ls.z += rs.z; return ls; } - FI XYZval operator+ (const XYZEval &rs) { XYZval ls = *this; ls.x += rs.x; ls.y += rs.y; ls.z += rs.z; return ls; } - FI XYZval operator- (const XYZEval &rs) const { XYZval ls = *this; ls.x -= rs.x; ls.y -= rs.y; ls.z -= rs.z; return ls; } - FI XYZval operator- (const XYZEval &rs) { XYZval ls = *this; ls.x -= rs.x; ls.y -= rs.y; ls.z -= rs.z; return ls; } - FI XYZval operator* (const XYZEval &rs) const { XYZval ls = *this; ls.x *= rs.x; ls.y *= rs.y; ls.z *= rs.z; return ls; } - FI XYZval operator* (const XYZEval &rs) { XYZval ls = *this; ls.x *= rs.x; ls.y *= rs.y; ls.z *= rs.z; return ls; } - FI XYZval operator/ (const XYZEval &rs) const { XYZval ls = *this; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; return ls; } - FI XYZval operator/ (const XYZEval &rs) { XYZval ls = *this; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; return ls; } - FI XYZval operator* (const float &v) const { XYZval ls = *this; ls.x *= v; ls.y *= v; ls.z *= v; return ls; } - FI XYZval operator* (const float &v) { XYZval ls = *this; ls.x *= v; ls.y *= v; ls.z *= v; return ls; } - FI XYZval operator* (const int &v) const { XYZval ls = *this; ls.x *= v; ls.y *= v; ls.z *= v; return ls; } - FI XYZval operator* (const int &v) { XYZval ls = *this; ls.x *= v; ls.y *= v; ls.z *= v; return ls; } - FI XYZval operator/ (const float &v) const { XYZval ls = *this; ls.x /= v; ls.y /= v; ls.z /= v; return ls; } - FI XYZval operator/ (const float &v) { XYZval ls = *this; ls.x /= v; ls.y /= v; ls.z /= v; return ls; } - FI XYZval operator/ (const int &v) const { XYZval ls = *this; ls.x /= v; ls.y /= v; ls.z /= v; return ls; } - FI XYZval operator/ (const int &v) { XYZval ls = *this; ls.x /= v; ls.y /= v; ls.z /= v; return ls; } - FI XYZval operator>>(const int &v) const { XYZval ls = *this; _RS(ls.x); _RS(ls.y); _RS(ls.z); return ls; } - FI XYZval operator>>(const int &v) { XYZval ls = *this; _RS(ls.x); _RS(ls.y); _RS(ls.z); return ls; } - FI XYZval operator<<(const int &v) const { XYZval ls = *this; _LS(ls.x); _LS(ls.y); _LS(ls.z); return ls; } - FI XYZval operator<<(const int &v) { XYZval ls = *this; _LS(ls.x); _LS(ls.y); _LS(ls.z); return ls; } - FI XYZval& operator+=(const XYval &rs) { x += rs.x; y += rs.y; return *this; } - FI XYZval& operator-=(const XYval &rs) { x -= rs.x; y -= rs.y; return *this; } - FI XYZval& operator*=(const XYval &rs) { x *= rs.x; y *= rs.y; return *this; } - FI XYZval& operator/=(const XYval &rs) { x /= rs.x; y /= rs.y; return *this; } - FI XYZval& operator+=(const XYZval &rs) { x += rs.x; y += rs.y; z += rs.z; return *this; } - FI XYZval& operator-=(const XYZval &rs) { x -= rs.x; y -= rs.y; z -= rs.z; return *this; } - FI XYZval& operator*=(const XYZval &rs) { x *= rs.x; y *= rs.y; z *= rs.z; return *this; } - FI XYZval& operator/=(const XYZval &rs) { x /= rs.x; y /= rs.y; z /= rs.z; return *this; } - FI XYZval& operator+=(const XYZEval &rs) { x += rs.x; y += rs.y; z += rs.z; return *this; } - FI XYZval& operator-=(const XYZEval &rs) { x -= rs.x; y -= rs.y; z -= rs.z; return *this; } - FI XYZval& operator*=(const XYZEval &rs) { x *= rs.x; y *= rs.y; z *= rs.z; return *this; } - FI XYZval& operator/=(const XYZEval &rs) { x /= rs.x; y /= rs.y; z /= rs.z; return *this; } - FI XYZval& operator*=(const float &v) { x *= v; y *= v; z *= v; return *this; } - FI XYZval& operator*=(const int &v) { x *= v; y *= v; z *= v; return *this; } - FI XYZval& operator>>=(const int &v) { _RS(x); _RS(y); _RS(z); return *this; } - FI XYZval& operator<<=(const int &v) { _LS(x); _LS(y); _LS(z); return *this; } - FI bool operator==(const XYZEval &rs) { return x == rs.x && y == rs.y && z == rs.z; } + FI XYZval& operator= (const XYZEval &rs) { set(LINEAR_AXIS_LIST(rs.x, rs.y, rs.z)); return *this; } + FI XYZval operator+ (const XYval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, NOOP ); return ls; } + FI XYZval operator+ (const XYval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, NOOP ); return ls; } + FI XYZval operator- (const XYval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, NOOP ); return ls; } + FI XYZval operator- (const XYval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, NOOP ); return ls; } + FI XYZval operator* (const XYval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, NOOP ); return ls; } + FI XYZval operator* (const XYval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, NOOP ); return ls; } + FI XYZval operator/ (const XYval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, NOOP ); return ls; } + FI XYZval operator/ (const XYval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, NOOP ); return ls; } + FI XYZval operator+ (const XYZval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z); return ls; } + FI XYZval operator+ (const XYZval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z); return ls; } + FI XYZval operator- (const XYZval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z); return ls; } + FI XYZval operator- (const XYZval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z); return ls; } + FI XYZval operator* (const XYZval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z); return ls; } + FI XYZval operator* (const XYZval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z); return ls; } + FI XYZval operator/ (const XYZval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z); return ls; } + FI XYZval operator/ (const XYZval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z); return ls; } + FI XYZval operator+ (const XYZEval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z); return ls; } + FI XYZval operator+ (const XYZEval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z); return ls; } + FI XYZval operator- (const XYZEval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z); return ls; } + FI XYZval operator- (const XYZEval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z); return ls; } + FI XYZval operator* (const XYZEval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z); return ls; } + FI XYZval operator* (const XYZEval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z); return ls; } + FI XYZval operator/ (const XYZEval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z); return ls; } + FI XYZval operator/ (const XYZEval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z); return ls; } + FI XYZval operator* (const float &v) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v ); return ls; } + FI XYZval operator* (const float &v) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v ); return ls; } + FI XYZval operator* (const int &v) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v ); return ls; } + FI XYZval operator* (const int &v) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v ); return ls; } + FI XYZval operator/ (const float &v) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v ); return ls; } + FI XYZval operator/ (const float &v) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v ); return ls; } + FI XYZval operator/ (const int &v) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v ); return ls; } + FI XYZval operator/ (const int &v) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v ); return ls; } + FI XYZval operator>>(const int &v) const { XYZval ls = *this; LINEAR_AXIS_CODE(_RS(ls.x), _RS(ls.y), _RS(ls.z) ); return ls; } + FI XYZval operator>>(const int &v) { XYZval ls = *this; LINEAR_AXIS_CODE(_RS(ls.x), _RS(ls.y), _RS(ls.z) ); return ls; } + FI XYZval operator<<(const int &v) const { XYZval ls = *this; LINEAR_AXIS_CODE(_LS(ls.x), _LS(ls.y), _LS(ls.z) ); return ls; } + FI XYZval operator<<(const int &v) { XYZval ls = *this; LINEAR_AXIS_CODE(_LS(ls.x), _LS(ls.y), _LS(ls.z) ); return ls; } + FI XYZval& operator+=(const XYval &rs) { LINEAR_AXIS_CODE(x += rs.x, y += rs.y, NOOP ); return *this; } + FI XYZval& operator-=(const XYval &rs) { LINEAR_AXIS_CODE(x -= rs.x, y -= rs.y, NOOP ); return *this; } + FI XYZval& operator*=(const XYval &rs) { LINEAR_AXIS_CODE(x *= rs.x, y *= rs.y, NOOP ); return *this; } + FI XYZval& operator/=(const XYval &rs) { LINEAR_AXIS_CODE(x /= rs.x, y /= rs.y, NOOP ); return *this; } + FI XYZval& operator+=(const XYZval &rs) { LINEAR_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z ); return *this; } + FI XYZval& operator-=(const XYZval &rs) { LINEAR_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z ); return *this; } + FI XYZval& operator*=(const XYZval &rs) { LINEAR_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z ); return *this; } + FI XYZval& operator/=(const XYZval &rs) { LINEAR_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z ); return *this; } + FI XYZval& operator+=(const XYZEval &rs) { LINEAR_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z ); return *this; } + FI XYZval& operator-=(const XYZEval &rs) { LINEAR_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z ); return *this; } + FI XYZval& operator*=(const XYZEval &rs) { LINEAR_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z ); return *this; } + FI XYZval& operator/=(const XYZEval &rs) { LINEAR_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z ); return *this; } + FI XYZval& operator*=(const float &v) { LINEAR_AXIS_CODE(x *= v, y *= v, z *= v ); return *this; } + FI XYZval& operator*=(const int &v) { LINEAR_AXIS_CODE(x *= v, y *= v, z *= v ); return *this; } + FI XYZval& operator>>=(const int &v) { LINEAR_AXIS_CODE(_RS(x), _RS(y), _RS(z) ); return *this; } + FI XYZval& operator<<=(const int &v) { LINEAR_AXIS_CODE(_LS(x), _LS(y), _LS(z) ); return *this; } + FI bool operator==(const XYZEval &rs) { return true LINEAR_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z); } + FI bool operator==(const XYZEval &rs) const { return true LINEAR_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z); } FI bool operator!=(const XYZEval &rs) { return !operator==(rs); } - FI bool operator==(const XYZEval &rs) const { return x == rs.x && y == rs.y && z == rs.z; } FI bool operator!=(const XYZEval &rs) const { return !operator==(rs); } - FI XYZval operator-() { XYZval o = *this; o.x = -x; o.y = -y; o.z = -z; return o; } - FI const XYZval operator-() const { XYZval o = *this; o.x = -x; o.y = -y; o.z = -z; return o; } + FI XYZval operator-() { XYZval o = *this; LINEAR_AXIS_CODE(o.x = -x, o.y = -y, o.z = -z); return o; } + FI const XYZval operator-() const { XYZval o = *this; LINEAR_AXIS_CODE(o.x = -x, o.y = -y, o.z = -z); return o; } }; // -// XYZE coordinates, counters, etc. +// Logical Axes coordinates, counters, etc. // template struct XYZEval { union { - struct{ T x, y, z, e; }; - struct{ T a, b, c; }; - T pos[4]; + struct{ T LOGICAL_AXIS_LIST(e, x, y, z); }; + struct{ T LINEAR_AXIS_LIST(a, b, c); }; + T pos[LOGICAL_AXES]; }; - FI void reset() { x = y = z = e = 0; } - FI T magnitude() const { return (T)sqrtf(x*x + y*y + z*z + e*e); } + FI void reset() { LOGICAL_AXIS_GANG(e =, x =, y =, z =) 0; } + FI T magnitude() const { return (T)sqrtf(LOGICAL_AXIS_GANG(+ e*e, + x*x, + y*y, + z*z)); } FI operator T* () { return pos; } - FI operator bool() { return e || z || x || y; } - FI void set(const T px) { x = px; } - FI void set(const T px, const T py) { x = px; y = py; } - FI void set(const T px, const T py, const T pz) { x = px; y = py; z = pz; } - FI void set(const T px, const T py, const T pz, const T pe) { x = px; y = py; z = pz; e = pe; } - FI void set(const XYval pxy) { x = pxy.x; y = pxy.y; } - FI void set(const XYval pxy, const T pz) { x = pxy.x; y = pxy.y; z = pz; } - FI void set(const XYZval pxyz) { x = pxyz.x; y = pxyz.y; z = pxyz.z; } - FI void set(const XYval pxy, const T pz, const T pe) { x = pxy.x; y = pxy.y; z = pz; e = pe; } - FI void set(const XYval pxy, const XYval pze) { x = pxy.x; y = pxy.y; z = pze.z; e = pze.e; } - FI void set(const XYZval pxyz, const T pe) { x = pxyz.x; y = pxyz.y; z = pxyz.z; e = pe; } - FI void set(const T (&arr)[XY]) { x = arr[0]; y = arr[1]; } - FI void set(const T (&arr)[XYZ]) { x = arr[0]; y = arr[1]; z = arr[2]; } - FI void set(const T (&arr)[XYZE]) { x = arr[0]; y = arr[1]; z = arr[2]; e = arr[3]; } - #if DISTINCT_AXES > XYZE - FI void set(const T (&arr)[DISTINCT_AXES]) { x = arr[0]; y = arr[1]; z = arr[2]; e = arr[3]; } + FI operator bool() { return false LOGICAL_AXIS_GANG(|| e, || x, || y, || z); } + FI void set(const T px) { x = px; } + FI void set(const T px, const T py) { x = px; y = py; } + FI void set(const XYval pxy) { x = pxy.x; y = pxy.y; } + FI void set(const XYZval pxyz) { set(LINEAR_AXIS_LIST(pxyz.x, pxyz.y, pxyz.z)); } + #if LINEAR_AXES >= XYZ + FI void set(LINEAR_AXIS_LIST(const T px, const T py, const T pz)) { + LINEAR_AXIS_CODE(x = px, y = py, z = pz); + } #endif - FI XYZEval copy() const { return *this; } - FI XYZEval ABS() const { return { T(_ABS(x)), T(_ABS(y)), T(_ABS(z)), T(_ABS(e)) }; } - FI XYZEval asInt() { return { int16_t(x), int16_t(y), int16_t(z), int16_t(e) }; } - FI XYZEval asInt() const { return { int16_t(x), int16_t(y), int16_t(z), int16_t(e) }; } - FI XYZEval asLong() { return { int32_t(x), int32_t(y), int32_t(z), int32_t(e) }; } - FI XYZEval asLong() const { return { int32_t(x), int32_t(y), int32_t(z), int32_t(e) }; } - FI XYZEval ROUNDL() { return { int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(e)) }; } - FI XYZEval ROUNDL() const { return { int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(e)) }; } - FI XYZEval asFloat() { return { static_cast(x), static_cast(y), static_cast(z), static_cast(e) }; } - FI XYZEval asFloat() const { return { static_cast(x), static_cast(y), static_cast(z), static_cast(e) }; } - FI XYZEval reciprocal() const { return { _RECIP(x), _RECIP(y), _RECIP(z), _RECIP(e) }; } + #if LOGICAL_AXES > LINEAR_AXES + FI void set(LOGICAL_AXIS_LIST(const T pe, const T px, const T py, const T pz)) { + LOGICAL_AXIS_CODE(e = pe, x = px, y = py, z = pz); + } + FI void set(const XYval pxy, const T pe) { set(pxy); e = pe; } + FI void set(const XYZval pxyz, const T pe) { set(pxyz); e = pe; } + #endif + FI XYZEval copy() const { XYZEval o = *this; return o; } + FI XYZEval ABS() const { return LOGICAL_AXIS_ARRAY(T(_ABS(e)), T(_ABS(x)), T(_ABS(y)), T(_ABS(z))); } + FI XYZEval asInt() { return LOGICAL_AXIS_ARRAY(int16_t(e), int16_t(x), int16_t(y), int16_t(z)); } + FI XYZEval asInt() const { return LOGICAL_AXIS_ARRAY(int16_t(e), int16_t(x), int16_t(y), int16_t(z)); } + FI XYZEval asLong() { return LOGICAL_AXIS_ARRAY(int32_t(e), int32_t(x), int32_t(y), int32_t(z)); } + FI XYZEval asLong() const { return LOGICAL_AXIS_ARRAY(int32_t(e), int32_t(x), int32_t(y), int32_t(z)); } + FI XYZEval ROUNDL() { return LOGICAL_AXIS_ARRAY(int32_t(LROUND(e)), int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z))); } + FI XYZEval ROUNDL() const { return LOGICAL_AXIS_ARRAY(int32_t(LROUND(e)), int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z))); } + FI XYZEval asFloat() { return LOGICAL_AXIS_ARRAY(static_cast(e), static_cast(x), static_cast(y), static_cast(z)); } + FI XYZEval asFloat() const { return LOGICAL_AXIS_ARRAY(static_cast(e), static_cast(x), static_cast(y), static_cast(z)); } + FI XYZEval reciprocal() const { return LOGICAL_AXIS_ARRAY(_RECIP(e), _RECIP(x), _RECIP(y), _RECIP(z)); } FI XYZEval asLogical() const { XYZEval o = asFloat(); toLogical(o); return o; } FI XYZEval asNative() const { XYZEval o = asFloat(); toNative(o); return o; } FI operator XYval&() { return *(XYval*)this; } FI operator const XYval&() const { return *(const XYval*)this; } FI operator XYZval&() { return *(XYZval*)this; } FI operator const XYZval&() const { return *(const XYZval*)this; } - FI T& operator[](const int i) { return pos[i]; } - FI const T& operator[](const int i) const { return pos[i]; } - FI XYZEval& operator= (const T v) { set(v, v, v, v); return *this; } + FI T& operator[](const int n) { return pos[n]; } + FI const T& operator[](const int n) const { return pos[n]; } + FI XYZEval& operator= (const T v) { set(LIST_N_1(LINEAR_AXES, v)); return *this; } FI XYZEval& operator= (const XYval &rs) { set(rs.x, rs.y); return *this; } - FI XYZEval& operator= (const XYZval &rs) { set(rs.x, rs.y, rs.z); return *this; } - FI XYZEval operator+ (const XYval &rs) const { XYZEval ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; } - FI XYZEval operator+ (const XYval &rs) { XYZEval ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; } - FI XYZEval operator- (const XYval &rs) const { XYZEval ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; } - FI XYZEval operator- (const XYval &rs) { XYZEval ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; } - FI XYZEval operator* (const XYval &rs) const { XYZEval ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; } - FI XYZEval operator* (const XYval &rs) { XYZEval ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; } - FI XYZEval operator/ (const XYval &rs) const { XYZEval ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; } - FI XYZEval operator/ (const XYval &rs) { XYZEval ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; } - FI XYZEval operator+ (const XYZval &rs) const { XYZEval ls = *this; ls.x += rs.x; ls.y += rs.y; ls.z += rs.z; return ls; } - FI XYZEval operator+ (const XYZval &rs) { XYZEval ls = *this; ls.x += rs.x; ls.y += rs.y; ls.z += rs.z; return ls; } - FI XYZEval operator- (const XYZval &rs) const { XYZEval ls = *this; ls.x -= rs.x; ls.y -= rs.y; ls.z -= rs.z; return ls; } - FI XYZEval operator- (const XYZval &rs) { XYZEval ls = *this; ls.x -= rs.x; ls.y -= rs.y; ls.z -= rs.z; return ls; } - FI XYZEval operator* (const XYZval &rs) const { XYZEval ls = *this; ls.x *= rs.x; ls.y *= rs.y; ls.z *= rs.z; return ls; } - FI XYZEval operator* (const XYZval &rs) { XYZEval ls = *this; ls.x *= rs.x; ls.y *= rs.y; ls.z *= rs.z; return ls; } - FI XYZEval operator/ (const XYZval &rs) const { XYZEval ls = *this; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; return ls; } - FI XYZEval operator/ (const XYZval &rs) { XYZEval ls = *this; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; return ls; } - FI XYZEval operator+ (const XYZEval &rs) const { XYZEval ls = *this; ls.x += rs.x; ls.y += rs.y; ls.z += rs.z; ls.e += rs.e; return ls; } - FI XYZEval operator+ (const XYZEval &rs) { XYZEval ls = *this; ls.x += rs.x; ls.y += rs.y; ls.z += rs.z; ls.e += rs.e; return ls; } - FI XYZEval operator- (const XYZEval &rs) const { XYZEval ls = *this; ls.x -= rs.x; ls.y -= rs.y; ls.z -= rs.z; ls.e -= rs.e; return ls; } - FI XYZEval operator- (const XYZEval &rs) { XYZEval ls = *this; ls.x -= rs.x; ls.y -= rs.y; ls.z -= rs.z; ls.e -= rs.e; return ls; } - FI XYZEval operator* (const XYZEval &rs) const { XYZEval ls = *this; ls.x *= rs.x; ls.y *= rs.y; ls.z *= rs.z; ls.e *= rs.e; return ls; } - FI XYZEval operator* (const XYZEval &rs) { XYZEval ls = *this; ls.x *= rs.x; ls.y *= rs.y; ls.z *= rs.z; ls.e *= rs.e; return ls; } - FI XYZEval operator/ (const XYZEval &rs) const { XYZEval ls = *this; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; ls.e /= rs.e; return ls; } - FI XYZEval operator/ (const XYZEval &rs) { XYZEval ls = *this; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; ls.e /= rs.e; return ls; } - FI XYZEval operator* (const float &v) const { XYZEval ls = *this; ls.x *= v; ls.y *= v; ls.z *= v; ls.e *= v; return ls; } - FI XYZEval operator* (const float &v) { XYZEval ls = *this; ls.x *= v; ls.y *= v; ls.z *= v; ls.e *= v; return ls; } - FI XYZEval operator* (const int &v) const { XYZEval ls = *this; ls.x *= v; ls.y *= v; ls.z *= v; ls.e *= v; return ls; } - FI XYZEval operator* (const int &v) { XYZEval ls = *this; ls.x *= v; ls.y *= v; ls.z *= v; ls.e *= v; return ls; } - FI XYZEval operator/ (const float &v) const { XYZEval ls = *this; ls.x /= v; ls.y /= v; ls.z /= v; ls.e /= v; return ls; } - FI XYZEval operator/ (const float &v) { XYZEval ls = *this; ls.x /= v; ls.y /= v; ls.z /= v; ls.e /= v; return ls; } - FI XYZEval operator/ (const int &v) const { XYZEval ls = *this; ls.x /= v; ls.y /= v; ls.z /= v; ls.e /= v; return ls; } - FI XYZEval operator/ (const int &v) { XYZEval ls = *this; ls.x /= v; ls.y /= v; ls.z /= v; ls.e /= v; return ls; } - FI XYZEval operator>>(const int &v) const { XYZEval ls = *this; _RS(ls.x); _RS(ls.y); _RS(ls.z); _RS(ls.e); return ls; } - FI XYZEval operator>>(const int &v) { XYZEval ls = *this; _RS(ls.x); _RS(ls.y); _RS(ls.z); _RS(ls.e); return ls; } - FI XYZEval operator<<(const int &v) const { XYZEval ls = *this; _LS(ls.x); _LS(ls.y); _LS(ls.z); _LS(ls.e); return ls; } - FI XYZEval operator<<(const int &v) { XYZEval ls = *this; _LS(ls.x); _LS(ls.y); _LS(ls.z); _LS(ls.e); return ls; } - FI XYZEval& operator+=(const XYval &rs) { x += rs.x; y += rs.y; return *this; } - FI XYZEval& operator-=(const XYval &rs) { x -= rs.x; y -= rs.y; return *this; } - FI XYZEval& operator*=(const XYval &rs) { x *= rs.x; y *= rs.y; return *this; } - FI XYZEval& operator/=(const XYval &rs) { x /= rs.x; y /= rs.y; return *this; } - FI XYZEval& operator+=(const XYZval &rs) { x += rs.x; y += rs.y; z += rs.z; return *this; } - FI XYZEval& operator-=(const XYZval &rs) { x -= rs.x; y -= rs.y; z -= rs.z; return *this; } - FI XYZEval& operator*=(const XYZval &rs) { x *= rs.x; y *= rs.y; z *= rs.z; return *this; } - FI XYZEval& operator/=(const XYZval &rs) { x /= rs.x; y /= rs.y; z /= rs.z; return *this; } - FI XYZEval& operator+=(const XYZEval &rs) { x += rs.x; y += rs.y; z += rs.z; e += rs.e; return *this; } - FI XYZEval& operator-=(const XYZEval &rs) { x -= rs.x; y -= rs.y; z -= rs.z; e -= rs.e; return *this; } - FI XYZEval& operator*=(const XYZEval &rs) { x *= rs.x; y *= rs.y; z *= rs.z; e *= rs.e; return *this; } - FI XYZEval& operator/=(const XYZEval &rs) { x /= rs.x; y /= rs.y; z /= rs.z; e /= rs.e; return *this; } - FI XYZEval& operator*=(const T &v) { x *= v; y *= v; z *= v; e *= v; return *this; } - FI XYZEval& operator>>=(const int &v) { _RS(x); _RS(y); _RS(z); _RS(e); return *this; } - FI XYZEval& operator<<=(const int &v) { _LS(x); _LS(y); _LS(z); _LS(e); return *this; } - FI bool operator==(const XYZval &rs) { return x == rs.x && y == rs.y && z == rs.z; } + FI XYZEval& operator= (const XYZval &rs) { set(LINEAR_AXIS_LIST(rs.x, rs.y, rs.z)); return *this; } + FI XYZEval operator+ (const XYval &rs) const { XYZEval ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; } + FI XYZEval operator+ (const XYval &rs) { XYZEval ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; } + FI XYZEval operator- (const XYval &rs) const { XYZEval ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; } + FI XYZEval operator- (const XYval &rs) { XYZEval ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; } + FI XYZEval operator* (const XYval &rs) const { XYZEval ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; } + FI XYZEval operator* (const XYval &rs) { XYZEval ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; } + FI XYZEval operator/ (const XYval &rs) const { XYZEval ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; } + FI XYZEval operator/ (const XYval &rs) { XYZEval ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; } + FI XYZEval operator+ (const XYZval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z); return ls; } + FI XYZEval operator+ (const XYZval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z); return ls; } + FI XYZEval operator- (const XYZval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z); return ls; } + FI XYZEval operator- (const XYZval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z); return ls; } + FI XYZEval operator* (const XYZval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z); return ls; } + FI XYZEval operator* (const XYZval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z); return ls; } + FI XYZEval operator/ (const XYZval &rs) const { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z); return ls; } + FI XYZEval operator/ (const XYZval &rs) { XYZval ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z); return ls; } + FI XYZEval operator+ (const XYZEval &rs) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e += rs.e, ls.x += rs.x, ls.y += rs.y, ls.z += rs.z ); return ls; } + FI XYZEval operator+ (const XYZEval &rs) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e += rs.e, ls.x += rs.x, ls.y += rs.y, ls.z += rs.z ); return ls; } + FI XYZEval operator- (const XYZEval &rs) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e -= rs.e, ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z ); return ls; } + FI XYZEval operator- (const XYZEval &rs) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e -= rs.e, ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z ); return ls; } + FI XYZEval operator* (const XYZEval &rs) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e *= rs.e, ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z ); return ls; } + FI XYZEval operator* (const XYZEval &rs) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e *= rs.e, ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z ); return ls; } + FI XYZEval operator/ (const XYZEval &rs) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e /= rs.e, ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z ); return ls; } + FI XYZEval operator/ (const XYZEval &rs) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e /= rs.e, ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z ); return ls; } + FI XYZEval operator* (const float &v) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e *= v, ls.x *= v, ls.y *= v, ls.z *= v ); return ls; } + FI XYZEval operator* (const float &v) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e *= v, ls.x *= v, ls.y *= v, ls.z *= v ); return ls; } + FI XYZEval operator* (const int &v) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e *= v, ls.x *= v, ls.y *= v, ls.z *= v ); return ls; } + FI XYZEval operator* (const int &v) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e *= v, ls.x *= v, ls.y *= v, ls.z *= v ); return ls; } + FI XYZEval operator/ (const float &v) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e /= v, ls.x /= v, ls.y /= v, ls.z /= v ); return ls; } + FI XYZEval operator/ (const float &v) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e /= v, ls.x /= v, ls.y /= v, ls.z /= v ); return ls; } + FI XYZEval operator/ (const int &v) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e /= v, ls.x /= v, ls.y /= v, ls.z /= v ); return ls; } + FI XYZEval operator/ (const int &v) { XYZEval ls = *this; LOGICAL_AXIS_CODE(ls.e /= v, ls.x /= v, ls.y /= v, ls.z /= v ); return ls; } + FI XYZEval operator>>(const int &v) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(_RS(ls.e), _RS(ls.x), _RS(ls.y), _RS(ls.z) ); return ls; } + FI XYZEval operator>>(const int &v) { XYZEval ls = *this; LOGICAL_AXIS_CODE(_RS(ls.e), _RS(ls.x), _RS(ls.y), _RS(ls.z) ); return ls; } + FI XYZEval operator<<(const int &v) const { XYZEval ls = *this; LOGICAL_AXIS_CODE(_LS(ls.e), _LS(ls.x), _LS(ls.y), _LS(ls.z) ); return ls; } + FI XYZEval operator<<(const int &v) { XYZEval ls = *this; LOGICAL_AXIS_CODE(_LS(ls.e), _LS(ls.x), _LS(ls.y), _LS(ls.z) ); return ls; } + FI XYZEval& operator+=(const XYval &rs) { x += rs.x; y += rs.y; return *this; } + FI XYZEval& operator-=(const XYval &rs) { x -= rs.x; y -= rs.y; return *this; } + FI XYZEval& operator*=(const XYval &rs) { x *= rs.x; y *= rs.y; return *this; } + FI XYZEval& operator/=(const XYval &rs) { x /= rs.x; y /= rs.y; return *this; } + FI XYZEval& operator+=(const XYZval &rs) { LINEAR_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z); return *this; } + FI XYZEval& operator-=(const XYZval &rs) { LINEAR_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z); return *this; } + FI XYZEval& operator*=(const XYZval &rs) { LINEAR_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z); return *this; } + FI XYZEval& operator/=(const XYZval &rs) { LINEAR_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z); return *this; } + FI XYZEval& operator+=(const XYZEval &rs) { LOGICAL_AXIS_CODE(e += rs.e, x += rs.x, y += rs.y, z += rs.z); return *this; } + FI XYZEval& operator-=(const XYZEval &rs) { LOGICAL_AXIS_CODE(e -= rs.e, x -= rs.x, y -= rs.y, z -= rs.z); return *this; } + FI XYZEval& operator*=(const XYZEval &rs) { LOGICAL_AXIS_CODE(e *= rs.e, x *= rs.x, y *= rs.y, z *= rs.z); return *this; } + FI XYZEval& operator/=(const XYZEval &rs) { LOGICAL_AXIS_CODE(e /= rs.e, x /= rs.x, y /= rs.y, z /= rs.z); return *this; } + FI XYZEval& operator*=(const T &v) { LOGICAL_AXIS_CODE(e *= v, x *= v, y *= v, z *= v); return *this; } + FI XYZEval& operator>>=(const int &v) { LOGICAL_AXIS_CODE(_RS(e), _RS(x), _RS(y), _RS(z)); return *this; } + FI XYZEval& operator<<=(const int &v) { LOGICAL_AXIS_CODE(_LS(e), _LS(x), _LS(y), _LS(z)); return *this; } + FI bool operator==(const XYZval &rs) { return true LINEAR_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z); } + FI bool operator==(const XYZval &rs) const { return true LINEAR_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z); } FI bool operator!=(const XYZval &rs) { return !operator==(rs); } - FI bool operator==(const XYZval &rs) const { return x == rs.x && y == rs.y && z == rs.z; } FI bool operator!=(const XYZval &rs) const { return !operator==(rs); } - FI XYZEval operator-() { return { -x, -y, -z, -e }; } - FI const XYZEval operator-() const { return { -x, -y, -z, -e }; } + FI XYZEval operator-() { return LOGICAL_AXIS_ARRAY(-e, -x, -y, -z); } + FI const XYZEval operator-() const { return LOGICAL_AXIS_ARRAY(-e, -x, -y, -z); } }; #undef _RECIP @@ -514,6 +573,3 @@ struct XYZEval { #undef _LS #undef _RS #undef FI - -const xyze_char_t axis_codes { 'X', 'Y', 'Z', 'E' }; -#define AXIS_CHAR(A) ((char)('X' + A)) diff --git a/Marlin/src/core/utility.h b/Marlin/src/core/utility.h index d774b007b6d5..31d0ac6ef40a 100644 --- a/Marlin/src/core/utility.h +++ b/Marlin/src/core/utility.h @@ -76,3 +76,11 @@ class restorer { // Converts from an uint8_t in the range of 0-255 to an uint8_t // in the range 0-100 while avoiding rounding artifacts constexpr uint8_t ui8_to_percent(const uint8_t i) { return (int(i) * 100 + 127) / 255; } + +const xyze_char_t axis_codes LOGICAL_AXIS_ARRAY('E', 'X', 'Y', 'Z'); + +#if LINEAR_AXES <= XYZ + #define AXIS_CHAR(A) ((char)('X' + A)) +#else + #define AXIS_CHAR(A) axis_codes[A] +#endif diff --git a/Marlin/src/feature/encoder_i2c.cpp b/Marlin/src/feature/encoder_i2c.cpp index d6c88613fd81..c6881591b6b9 100644 --- a/Marlin/src/feature/encoder_i2c.cpp +++ b/Marlin/src/feature/encoder_i2c.cpp @@ -327,7 +327,7 @@ int32_t I2CPositionEncoder::get_raw_count() { } bool I2CPositionEncoder::test_axis() { - //only works on XYZ cartesian machines for the time being + // Only works on XYZ Cartesian machines for the time being if (!(encoderAxis == X_AXIS || encoderAxis == Y_AXIS || encoderAxis == Z_AXIS)) return false; const float startPosition = soft_endstop.min[encoderAxis] + 10, @@ -344,11 +344,14 @@ bool I2CPositionEncoder::test_axis() { startCoord[encoderAxis] = startPosition; endCoord[encoderAxis] = endPosition; - planner.synchronize(); - startCoord.e = planner.get_axis_position_mm(E_AXIS); - planner.buffer_line(startCoord, fr_mm_s, 0); planner.synchronize(); + #if HAS_EXTRUDERS + startCoord.e = planner.get_axis_position_mm(E_AXIS); + planner.buffer_line(startCoord, fr_mm_s, 0); + planner.synchronize(); + #endif + // if the module isn't currently trusted, wait until it is (or until it should be if things are working) if (!trusted) { int32_t startWaitingTime = millis(); @@ -357,7 +360,7 @@ bool I2CPositionEncoder::test_axis() { } if (trusted) { // if trusted, commence test - endCoord.e = planner.get_axis_position_mm(E_AXIS); + TERN_(HAS_EXTRUDERS, endCoord.e = planner.get_axis_position_mm(E_AXIS)); planner.buffer_line(endCoord, fr_mm_s, 0); planner.synchronize(); } @@ -402,7 +405,7 @@ void I2CPositionEncoder::calibrate_steps_mm(const uint8_t iter) { planner.synchronize(); LOOP_L_N(i, iter) { - startCoord.e = planner.get_axis_position_mm(E_AXIS); + TERN_(HAS_EXTRUDERS, startCoord.e = planner.get_axis_position_mm(E_AXIS)); planner.buffer_line(startCoord, fr_mm_s, 0); planner.synchronize(); @@ -411,7 +414,7 @@ void I2CPositionEncoder::calibrate_steps_mm(const uint8_t iter) { //do_blocking_move_to(endCoord); - endCoord.e = planner.get_axis_position_mm(E_AXIS); + TERN_(HAS_EXTRUDERS, endCoord.e = planner.get_axis_position_mm(E_AXIS)); planner.buffer_line(endCoord, fr_mm_s, 0); planner.synchronize(); @@ -497,9 +500,7 @@ void I2CPositionEncodersMgr::init() { encoders[i].set_active(encoders[i].passes_test(true)); - #if I2CPE_ENC_1_AXIS == E_AXIS - encoders[i].set_homed(); - #endif + TERN_(HAS_EXTRUDERS, if (I2CPE_ENC_1_AXIS == E_AXIS) encoders[i].set_homed()); #endif #if I2CPE_ENCODER_CNT > 1 @@ -528,9 +529,7 @@ void I2CPositionEncodersMgr::init() { encoders[i].set_active(encoders[i].passes_test(true)); - #if I2CPE_ENC_2_AXIS == E_AXIS - encoders[i].set_homed(); - #endif + TERN_(HAS_EXTRUDERS, if (I2CPE_ENC_2_AXIS == E_AXIS) encoders[i].set_homed()); #endif #if I2CPE_ENCODER_CNT > 2 @@ -557,11 +556,9 @@ void I2CPositionEncodersMgr::init() { encoders[i].set_ec_threshold(I2CPE_ENC_3_EC_THRESH); #endif - encoders[i].set_active(encoders[i].passes_test(true)); + encoders[i].set_active(encoders[i].passes_test(true)); - #if I2CPE_ENC_3_AXIS == E_AXIS - encoders[i].set_homed(); - #endif + TERN_(HAS_EXTRUDERS, if (I2CPE_ENC_3_AXIS == E_AXIS) encoders[i].set_homed()); #endif #if I2CPE_ENCODER_CNT > 3 @@ -590,9 +587,7 @@ void I2CPositionEncodersMgr::init() { encoders[i].set_active(encoders[i].passes_test(true)); - #if I2CPE_ENC_4_AXIS == E_AXIS - encoders[i].set_homed(); - #endif + TERN_(HAS_EXTRUDERS, if (I2CPE_ENC_4_AXIS == E_AXIS) encoders[i].set_homed()); #endif #if I2CPE_ENCODER_CNT > 4 @@ -621,9 +616,7 @@ void I2CPositionEncodersMgr::init() { encoders[i].set_active(encoders[i].passes_test(true)); - #if I2CPE_ENC_5_AXIS == E_AXIS - encoders[i].set_homed(); - #endif + TERN_(HAS_EXTRUDERS, if (I2CPE_ENC_5_AXIS == E_AXIS) encoders[i].set_homed()); #endif #if I2CPE_ENCODER_CNT > 5 @@ -652,9 +645,7 @@ void I2CPositionEncodersMgr::init() { encoders[i].set_active(encoders[i].passes_test(true)); - #if I2CPE_ENC_6_AXIS == E_AXIS - encoders[i].set_homed(); - #endif + TERN_(HAS_EXTRUDERS, if (I2CPE_ENC_6_AXIS == E_AXIS) encoders[i].set_homed()); #endif } diff --git a/Marlin/src/feature/tmc_util.cpp b/Marlin/src/feature/tmc_util.cpp index 9c4fbf08dfc8..e244a33eee46 100644 --- a/Marlin/src/feature/tmc_util.cpp +++ b/Marlin/src/feature/tmc_util.cpp @@ -757,7 +757,10 @@ } } - static void tmc_debug_loop(const TMC_debug_enum i, const bool print_x, const bool print_y, const bool print_z, const bool print_e) { + static void tmc_debug_loop( + const TMC_debug_enum i, + LOGICAL_AXIS_LIST(const bool print_e, const bool print_x, const bool print_y, const bool print_z) + ) { if (print_x) { #if AXIS_IS_TMC(X) tmc_status(stepperX, i); @@ -821,7 +824,10 @@ SERIAL_EOL(); } - static void drv_status_loop(const TMC_drv_status_enum i, const bool print_x, const bool print_y, const bool print_z, const bool print_e) { + static void drv_status_loop( + const TMC_drv_status_enum i, + LOGICAL_AXIS_LIST(const bool print_e, const bool print_x, const bool print_y, const bool print_z) + ) { if (print_x) { #if AXIS_IS_TMC(X) tmc_parse_drv_status(stepperX, i); @@ -889,9 +895,12 @@ * M122 report functions */ - void tmc_report_all(const bool print_x/*=true*/, const bool print_y/*=true*/, const bool print_z/*=true*/, const bool print_e/*=true*/) { - #define TMC_REPORT(LABEL, ITEM) do{ SERIAL_ECHOPGM(LABEL); tmc_debug_loop(ITEM, print_x, print_y, print_z, print_e); }while(0) - #define DRV_REPORT(LABEL, ITEM) do{ SERIAL_ECHOPGM(LABEL); drv_status_loop(ITEM, print_x, print_y, print_z, print_e); }while(0) + void tmc_report_all( + LOGICAL_AXIS_LIST(const bool print_e/*=true*/, const bool print_x/*=true*/, const bool print_y/*=true*/, const bool print_z/*=true*/) + ) { + #define TMC_REPORT(LABEL, ITEM) do{ SERIAL_ECHOPGM(LABEL); tmc_debug_loop(ITEM, LOGICAL_AXIS_LIST(print_e, print_x, print_y, print_z)); }while(0) + #define DRV_REPORT(LABEL, ITEM) do{ SERIAL_ECHOPGM(LABEL); drv_status_loop(ITEM, LOGICAL_AXIS_LIST(print_e, print_x, print_y, print_z)); }while(0) + TMC_REPORT("\t", TMC_CODES); #if HAS_DRIVER(TMC2209) TMC_REPORT("Address\t", TMC_UART_ADDR); @@ -1015,7 +1024,10 @@ } #endif - static void tmc_get_registers(TMC_get_registers_enum i, const bool print_x, const bool print_y, const bool print_z, const bool print_e) { + static void tmc_get_registers( + TMC_get_registers_enum i, + LOGICAL_AXIS_LIST(const bool print_e, const bool print_x, const bool print_y, const bool print_z) + ) { if (print_x) { #if AXIS_IS_TMC(X) tmc_get_registers(stepperX, i); @@ -1079,8 +1091,10 @@ SERIAL_EOL(); } - void tmc_get_registers(bool print_x, bool print_y, bool print_z, bool print_e) { - #define _TMC_GET_REG(LABEL, ITEM) do{ SERIAL_ECHOPGM(LABEL); tmc_get_registers(ITEM, print_x, print_y, print_z, print_e); }while(0) + void tmc_get_registers( + LOGICAL_AXIS_LIST(bool print_e, bool print_x, bool print_y, bool print_z) + ) { + #define _TMC_GET_REG(LABEL, ITEM) do{ SERIAL_ECHOPGM(LABEL); tmc_get_registers(ITEM, LOGICAL_AXIS_LIST(print_e, print_x, print_y, print_z)); }while(0) #define TMC_GET_REG(NAME, TABS) _TMC_GET_REG(STRINGIFY(NAME) TABS, TMC_GET_##NAME) _TMC_GET_REG("\t", TMC_AXIS_CODES); TMC_GET_REG(GCONF, "\t\t"); @@ -1214,7 +1228,9 @@ static bool test_connection(TMC &st) { return test_result; } -void test_tmc_connection(const bool test_x/*=true*/, const bool test_y/*=true*/, const bool test_z/*=true*/, const bool test_e/*=true*/) { +void test_tmc_connection( + LOGICAL_AXIS_LIST(const bool test_e/*=true*/, const bool test_x/*=true*/, const bool test_y/*=true*/, const bool test_z/*=true*/) +) { uint8_t axis_connection = 0; if (test_x) { diff --git a/Marlin/src/feature/tmc_util.h b/Marlin/src/feature/tmc_util.h index 179f38f72998..a07d6ce0ee17 100644 --- a/Marlin/src/feature/tmc_util.h +++ b/Marlin/src/feature/tmc_util.h @@ -335,14 +335,20 @@ void tmc_print_current(TMC &st) { #endif void monitor_tmc_drivers(); -void test_tmc_connection(const bool test_x=true, const bool test_y=true, const bool test_z=true, const bool test_e=true); +void test_tmc_connection( + LOGICAL_AXIS_LIST(const bool test_e=true, const bool test_x=true, const bool test_y=true, const bool test_z=true) +); #if ENABLED(TMC_DEBUG) #if ENABLED(MONITOR_DRIVER_STATUS) void tmc_set_report_interval(const uint16_t update_interval); #endif - void tmc_report_all(const bool print_x=true, const bool print_y=true, const bool print_z=true, const bool print_e=true); - void tmc_get_registers(const bool print_x, const bool print_y, const bool print_z, const bool print_e); + void tmc_report_all( + LOGICAL_AXIS_LIST(const bool print_e=true, const bool print_x=true, const bool print_y=true, const bool print_z=true) + ); + void tmc_get_registers( + LOGICAL_AXIS_LIST(const bool print_e, const bool print_x, const bool print_y, const bool print_z) + ); #endif /** @@ -355,7 +361,7 @@ void test_tmc_connection(const bool test_x=true, const bool test_y=true, const b #if USE_SENSORLESS // Track enabled status of stealthChop and only re-enable where applicable - struct sensorless_t { bool x, y, z, x2, y2, z2, z3, z4; }; + struct sensorless_t { bool LINEAR_AXIS_LIST(x, y, z), x2, y2, z2, z3, z4; }; #if ENABLED(IMPROVE_HOMING_RELIABILITY) extern millis_t sg_guard_period; diff --git a/Marlin/src/gcode/calibrate/G28.cpp b/Marlin/src/gcode/calibrate/G28.cpp index aacfcfa42f5a..a71f5415935d 100644 --- a/Marlin/src/gcode/calibrate/G28.cpp +++ b/Marlin/src/gcode/calibrate/G28.cpp @@ -321,12 +321,23 @@ void GcodeSuite::G28() { #else + #define _UNSAFE(A) (homeZ && TERN0(Z_SAFE_HOMING, axes_should_home(_BV(A##_AXIS)))) + const bool homeZ = parser.seen_test('Z'), - needX = homeZ && TERN0(Z_SAFE_HOMING, axes_should_home(_BV(X_AXIS))), - needY = homeZ && TERN0(Z_SAFE_HOMING, axes_should_home(_BV(Y_AXIS))), - homeX = needX || parser.seen_test('X'), homeY = needY || parser.seen_test('Y'), - home_all = homeX == homeY && homeX == homeZ, // All or None - doX = home_all || homeX, doY = home_all || homeY, doZ = home_all || homeZ; + LINEAR_AXIS_LIST( // Other axes should be homed before Z safe-homing + needX = _UNSAFE(X), needY = _UNSAFE(Y), needZ = false // UNUSED + ), + LINEAR_AXIS_LIST( // Home each axis if needed or flagged + homeX = needX || parser.seen_test('X'), + homeY = needY || parser.seen_test('Y'), + homeZZ = homeZ // UNUSED + ), + // Home-all if all or none are flagged + home_all = true LINEAR_AXIS_GANG(&& homeX == homeX, && homeX == homeY, && homeX == homeZ), + LINEAR_AXIS_LIST(doX = home_all || homeX, doY = home_all || homeY, doZ = home_all || homeZ); + + UNUSED(needZ); + UNUSED(homeZZ); #if ENABLED(HOME_Z_FIRST) @@ -336,7 +347,7 @@ void GcodeSuite::G28() { const float z_homing_height = parser.seenval('R') ? parser.value_linear_units() : Z_HOMING_HEIGHT; - if (z_homing_height && (doX || doY || TERN0(Z_SAFE_HOMING, doZ))) { + if (z_homing_height && (0 LINEAR_AXIS_GANG(|| doX, || doY, || TERN0(Z_SAFE_HOMING, doZ)))) { // Raise Z before homing any other axes and z is not already high enough (never lower z) if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("Raise Z (before homing) by ", z_homing_height); do_z_clearance(z_homing_height); @@ -469,7 +480,7 @@ void GcodeSuite::G28() { #if HAS_CURRENT_HOME(Y2) stepperY2.rms_current(tmc_save_current_Y2); #endif - #endif + #endif // HAS_HOMING_CURRENT ui.refresh(); @@ -490,7 +501,7 @@ void GcodeSuite::G28() { static constexpr AxisEnum L64XX_axis_xref[MAX_L64XX] = { X_AXIS, Y_AXIS, Z_AXIS, X_AXIS, Y_AXIS, Z_AXIS, Z_AXIS, - E_AXIS, E_AXIS, E_AXIS, E_AXIS, E_AXIS, E_AXIS + E_AXIS, E_AXIS, E_AXIS, E_AXIS, E_AXIS, E_AXIS, E_AXIS, E_AXIS }; for (uint8_t j = 1; j <= L64XX::chain[0]; j++) { const uint8_t cv = L64XX::chain[j]; diff --git a/Marlin/src/gcode/calibrate/G425.cpp b/Marlin/src/gcode/calibrate/G425.cpp index 2fb450226797..723f1ebd7b96 100644 --- a/Marlin/src/gcode/calibrate/G425.cpp +++ b/Marlin/src/gcode/calibrate/G425.cpp @@ -307,9 +307,11 @@ inline void probe_sides(measurements_t &m, const float uncertainty) { // The difference between the known and the measured location // of the calibration object is the positional error - m.pos_error.x = TERN0(HAS_X_CENTER, true_center.x - m.obj_center.x); - m.pos_error.y = TERN0(HAS_Y_CENTER, true_center.y - m.obj_center.y); - m.pos_error.z = true_center.z - m.obj_center.z; + LINEAR_AXIS_CODE( + m.pos_error.x = TERN0(HAS_X_CENTER, true_center.x - m.obj_center.x), + m.pos_error.y = TERN0(HAS_Y_CENTER, true_center.y - m.obj_center.y), + m.pos_error.z = true_center.z - m.obj_center.z + ); } #if ENABLED(CALIBRATION_REPORTING) @@ -455,7 +457,9 @@ inline void calibrate_backlash(measurements_t &m, const float uncertainty) { // New scope for TEMPORARY_BACKLASH_CORRECTION TEMPORARY_BACKLASH_CORRECTION(all_on); TEMPORARY_BACKLASH_SMOOTHING(0.0f); - const xyz_float_t move = { AXIS_CAN_CALIBRATE(X) * 3, AXIS_CAN_CALIBRATE(Y) * 3, AXIS_CAN_CALIBRATE(Z) * 3 }; + const xyz_float_t move = LINEAR_AXIS_ARRAY( + AXIS_CAN_CALIBRATE(X) * 3, AXIS_CAN_CALIBRATE(Y) * 3, AXIS_CAN_CALIBRATE(Z) * 3 + ); current_position += move; calibration_move(); current_position -= move; calibration_move(); } diff --git a/Marlin/src/gcode/calibrate/M425.cpp b/Marlin/src/gcode/calibrate/M425.cpp index 432144f491c0..7de33c1f2a9d 100644 --- a/Marlin/src/gcode/calibrate/M425.cpp +++ b/Marlin/src/gcode/calibrate/M425.cpp @@ -48,10 +48,12 @@ void GcodeSuite::M425() { auto axis_can_calibrate = [](const uint8_t a) { switch (a) { - default: - case X_AXIS: return AXIS_CAN_CALIBRATE(X); - case Y_AXIS: return AXIS_CAN_CALIBRATE(Y); - case Z_AXIS: return AXIS_CAN_CALIBRATE(Z); + default: return false; + LINEAR_AXIS_CODE( + case X_AXIS: return AXIS_CAN_CALIBRATE(X), + case Y_AXIS: return AXIS_CAN_CALIBRATE(Y), + case Z_AXIS: return AXIS_CAN_CALIBRATE(Z) + ); } }; diff --git a/Marlin/src/gcode/config/M200-M205.cpp b/Marlin/src/gcode/config/M200-M205.cpp index 06751f41c499..e765fd55b22d 100644 --- a/Marlin/src/gcode/config/M200-M205.cpp +++ b/Marlin/src/gcode/config/M200-M205.cpp @@ -88,7 +88,7 @@ void GcodeSuite::M201() { LOOP_LOGICAL_AXES(i) { if (parser.seenval(axis_codes[i])) { - const uint8_t a = (i == E_AXIS ? uint8_t(E_AXIS_N(target_extruder)) : i); + const uint8_t a = TERN(HAS_EXTRUDERS, (i == E_AXIS ? uint8_t(E_AXIS_N(target_extruder)) : i), i); planner.set_max_acceleration(a, parser.value_axis_units((AxisEnum)a)); } } @@ -106,7 +106,7 @@ void GcodeSuite::M203() { LOOP_LOGICAL_AXES(i) if (parser.seenval(axis_codes[i])) { - const uint8_t a = (i == E_AXIS ? uint8_t(E_AXIS_N(target_extruder)) : i); + const uint8_t a = TERN(HAS_EXTRUDERS, (i == E_AXIS ? uint8_t(E_AXIS_N(target_extruder)) : i), i); planner.set_max_feedrate(a, parser.value_axis_units((AxisEnum)a)); } } @@ -165,17 +165,16 @@ void GcodeSuite::M205() { } #endif #if HAS_CLASSIC_JERK - if (parser.seenval('X')) planner.set_max_jerk(X_AXIS, parser.value_linear_units()); - if (parser.seenval('Y')) planner.set_max_jerk(Y_AXIS, parser.value_linear_units()); - if (parser.seenval('Z')) { - planner.set_max_jerk(Z_AXIS, parser.value_linear_units()); - #if HAS_MESH && DISABLED(LIMITED_JERK_EDITING) - if (planner.max_jerk.z <= 0.1f) - SERIAL_ECHOLNPGM("WARNING! Low Z Jerk may lead to unwanted pauses."); - #endif - } - #if HAS_CLASSIC_E_JERK - if (parser.seenval('E')) planner.set_max_jerk(E_AXIS, parser.value_linear_units()); + bool seenZ = false; + LOGICAL_AXIS_CODE( + if (parser.seenval('E')) planner.set_max_jerk(E_AXIS, parser.value_linear_units()), + if (parser.seenval('X')) planner.set_max_jerk(X_AXIS, parser.value_linear_units()), + if (parser.seenval('Y')) planner.set_max_jerk(Y_AXIS, parser.value_linear_units()), + if ((seenZ = parser.seenval('Z'))) planner.set_max_jerk(Z_AXIS, parser.value_linear_units()) + ); + #if HAS_MESH && DISABLED(LIMITED_JERK_EDITING) + if (seenZ && planner.max_jerk.z <= 0.1f) + SERIAL_ECHOLNPGM("WARNING! Low Z Jerk may lead to unwanted pauses."); #endif - #endif + #endif // HAS_CLASSIC_JERK } diff --git a/Marlin/src/gcode/config/M92.cpp b/Marlin/src/gcode/config/M92.cpp index 06c47b825334..100cf96f151b 100644 --- a/Marlin/src/gcode/config/M92.cpp +++ b/Marlin/src/gcode/config/M92.cpp @@ -25,10 +25,12 @@ void report_M92(const bool echo=true, const int8_t e=-1) { if (echo) SERIAL_ECHO_START(); else SERIAL_CHAR(' '); - SERIAL_ECHOPAIR_P(PSTR(" M92 X"), LINEAR_UNIT(planner.settings.axis_steps_per_mm[X_AXIS]), - SP_Y_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[Y_AXIS]), - SP_Z_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[Z_AXIS])); - #if DISABLED(DISTINCT_E_FACTORS) + SERIAL_ECHOPAIR_P(LIST_N(DOUBLE(LINEAR_AXES), + PSTR(" M92 X"), LINEAR_UNIT(planner.settings.axis_steps_per_mm[X_AXIS]), + SP_Y_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[Y_AXIS]), + SP_Z_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[Z_AXIS]) + )); + #if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS) SERIAL_ECHOPAIR_P(SP_E_STR, VOLUMETRIC_UNIT(planner.settings.axis_steps_per_mm[E_AXIS])); #endif SERIAL_EOL(); @@ -64,25 +66,28 @@ void GcodeSuite::M92() { if (target_extruder < 0) return; // No arguments? Show M92 report. - if (!parser.seen("XYZE" TERN_(MAGIC_NUMBERS_GCODE, "HL"))) - return report_M92(true, target_extruder); + if (!parser.seen( + LOGICAL_AXIS_GANG("E", "X", "Y", "Z") + TERN_(MAGIC_NUMBERS_GCODE, "HL") + )) return report_M92(true, target_extruder); LOOP_LOGICAL_AXES(i) { if (parser.seenval(axis_codes[i])) { - if (i == E_AXIS) { - const float value = parser.value_per_axis_units((AxisEnum)(E_AXIS_N(target_extruder))); - if (value < 20) { - float factor = planner.settings.axis_steps_per_mm[E_AXIS_N(target_extruder)] / value; // increase e constants if M92 E14 is given for netfab. - #if HAS_CLASSIC_JERK && HAS_CLASSIC_E_JERK - planner.max_jerk.e *= factor; - #endif - planner.settings.max_feedrate_mm_s[E_AXIS_N(target_extruder)] *= factor; - planner.max_acceleration_steps_per_s2[E_AXIS_N(target_extruder)] *= factor; - } - planner.settings.axis_steps_per_mm[E_AXIS_N(target_extruder)] = value; - } - else { + if (TERN1(HAS_EXTRUDERS, i != E_AXIS)) planner.settings.axis_steps_per_mm[i] = parser.value_per_axis_units((AxisEnum)i); + else { + #if HAS_EXTRUDERS + const float value = parser.value_per_axis_units((AxisEnum)(E_AXIS_N(target_extruder))); + if (value < 20) { + float factor = planner.settings.axis_steps_per_mm[E_AXIS_N(target_extruder)] / value; // increase e constants if M92 E14 is given for netfab. + #if HAS_CLASSIC_JERK && HAS_CLASSIC_E_JERK + planner.max_jerk.e *= factor; + #endif + planner.settings.max_feedrate_mm_s[E_AXIS_N(target_extruder)] *= factor; + planner.max_acceleration_steps_per_s2[E_AXIS_N(target_extruder)] *= factor; + } + planner.settings.axis_steps_per_mm[E_AXIS_N(target_extruder)] = value; + #endif } } } diff --git a/Marlin/src/gcode/control/M17_M18_M84.cpp b/Marlin/src/gcode/control/M17_M18_M84.cpp index f02508a90171..b7cec2d48df5 100644 --- a/Marlin/src/gcode/control/M17_M18_M84.cpp +++ b/Marlin/src/gcode/control/M17_M18_M84.cpp @@ -33,11 +33,13 @@ * M17: Enable stepper motors */ void GcodeSuite::M17() { - if (parser.seen("XYZE")) { - if (parser.seen_test('X')) ENABLE_AXIS_X(); - if (parser.seen_test('Y')) ENABLE_AXIS_Y(); - if (parser.seen_test('Z')) ENABLE_AXIS_Z(); - if (TERN0(HAS_E_STEPPER_ENABLE, parser.seen_test('E'))) enable_e_steppers(); + if (parser.seen(LOGICAL_AXIS_GANG("E", "X", "Y", "Z"))) { + LOGICAL_AXIS_CODE( + if (TERN0(HAS_E_STEPPER_ENABLE, parser.seen_test('E'))) enable_e_steppers(), + if (parser.seen_test('X')) ENABLE_AXIS_X(), + if (parser.seen_test('Y')) ENABLE_AXIS_Y(), + if (parser.seen_test('Z')) ENABLE_AXIS_Z() + ); } else { LCD_MESSAGEPGM(MSG_NO_MOVE); @@ -54,12 +56,14 @@ void GcodeSuite::M18_M84() { stepper_inactive_time = parser.value_millis_from_seconds(); } else { - if (parser.seen("XYZE")) { + if (parser.seen(LOGICAL_AXIS_GANG("E", "X", "Y", "Z"))) { planner.synchronize(); - if (parser.seen_test('X')) DISABLE_AXIS_X(); - if (parser.seen_test('Y')) DISABLE_AXIS_Y(); - if (parser.seen_test('Z')) DISABLE_AXIS_Z(); - if (TERN0(HAS_E_STEPPER_ENABLE, parser.seen_test('E'))) disable_e_steppers(); + LOGICAL_AXIS_CODE( + if (TERN0(HAS_E_STEPPER_ENABLE, parser.seen_test('E'))) disable_e_steppers(), + if (parser.seen_test('X')) DISABLE_AXIS_X(), + if (parser.seen_test('Y')) DISABLE_AXIS_Y(), + if (parser.seen_test('Z')) DISABLE_AXIS_Z() + ); } else planner.finish_and_disable(); diff --git a/Marlin/src/gcode/feature/pause/G61.cpp b/Marlin/src/gcode/feature/pause/G61.cpp index a6d7cb3094c4..14a2e649695b 100644 --- a/Marlin/src/gcode/feature/pause/G61.cpp +++ b/Marlin/src/gcode/feature/pause/G61.cpp @@ -69,7 +69,7 @@ void GcodeSuite::G61(void) { SYNC_E(stored_position[slot].e); } else { - if (parser.seen("XYZ")) { + if (parser.seen(LINEAR_AXIS_GANG("X", "Y", "Z"))) { DEBUG_ECHOPAIR(STR_RESTORING_POS " S", slot); LOOP_LINEAR_AXES(i) { destination[i] = parser.seen(AXIS_CHAR(i)) @@ -82,10 +82,12 @@ void GcodeSuite::G61(void) { // Move to the saved position prepare_line_to_destination(); } - if (parser.seen_test('E')) { - DEBUG_ECHOLNPAIR(STR_RESTORING_POS " S", slot, " E", current_position.e, "=>", stored_position[slot].e); - SYNC_E(stored_position[slot].e); - } + #if HAS_EXTRUDERS + if (parser.seen_test('E')) { + DEBUG_ECHOLNPAIR(STR_RESTORING_POS " S", slot, " E", current_position.e, "=>", stored_position[slot].e); + SYNC_E(stored_position[slot].e); + } + #endif } feedrate_mm_s = saved_feedrate; diff --git a/Marlin/src/gcode/feature/trinamic/M122.cpp b/Marlin/src/gcode/feature/trinamic/M122.cpp index 054d145c8c23..3b4406705c17 100644 --- a/Marlin/src/gcode/feature/trinamic/M122.cpp +++ b/Marlin/src/gcode/feature/trinamic/M122.cpp @@ -49,13 +49,21 @@ void GcodeSuite::M122() { tmc_set_report_interval(interval); #endif - if (parser.seen_test('V')) - tmc_get_registers(print_axis.x, print_axis.y, print_axis.z, print_axis.e); - else - tmc_report_all(print_axis.x, print_axis.y, print_axis.z, print_axis.e); + if (parser.seen_test('V')) { + tmc_get_registers( + LOGICAL_AXIS_LIST(print_axis.e, print_axis.x, print_axis.y, print_axis.z) + ); + } + else { + tmc_report_all( + LOGICAL_AXIS_LIST(print_axis.e, print_axis.x, print_axis.y, print_axis.z) + ); + } #endif - test_tmc_connection(print_axis.x, print_axis.y, print_axis.z, print_axis.e); + test_tmc_connection( + LOGICAL_AXIS_LIST(print_axis.e, print_axis.x, print_axis.y, print_axis.z) + ); } #endif // HAS_TRINAMIC_CONFIG diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index 29dbf8d1c2dd..b7a842ece745 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -74,11 +74,11 @@ millis_t GcodeSuite::previous_move_ms = 0, // Relative motion mode for each logical axis static constexpr xyze_bool_t ar_init = AXIS_RELATIVE_MODES; -uint8_t GcodeSuite::axis_relative = ( - (ar_init.x ? _BV(REL_X) : 0) - | (ar_init.y ? _BV(REL_Y) : 0) - | (ar_init.z ? _BV(REL_Z) : 0) - | (ar_init.e ? _BV(REL_E) : 0) +uint8_t GcodeSuite::axis_relative = 0 LOGICAL_AXIS_GANG( + | (ar_init.e << REL_E), + | (ar_init.x << REL_X), + | (ar_init.y << REL_Y), + | (ar_init.z << REL_Z) ); #if EITHER(HAS_AUTO_REPORTING, HOST_KEEPALIVE_FEATURE) @@ -161,13 +161,15 @@ void GcodeSuite::get_destination_from_command() { destination[i] = current_position[i]; } - // Get new E position, whether absolute or relative - if ( (seen.e = parser.seenval('E')) ) { - const float v = parser.value_axis_units(E_AXIS); - destination.e = axis_is_relative(E_AXIS) ? current_position.e + v : v; - } - else - destination.e = current_position.e; + #if HAS_EXTRUDERS + // Get new E position, whether absolute or relative + if ( (seen.e = parser.seenval('E')) ) { + const float v = parser.value_axis_units(E_AXIS); + destination.e = axis_is_relative(E_AXIS) ? current_position.e + v : v; + } + else + destination.e = current_position.e; + #endif #if ENABLED(POWER_LOSS_RECOVERY) && !PIN_EXISTS(POWER_LOSS) // Only update power loss recovery on moves with E diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index befc328bb974..05b6c0cdd52c 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -314,7 +314,12 @@ #define HAS_FAST_MOVES 1 #endif -enum AxisRelative : uint8_t { REL_X, REL_Y, REL_Z, REL_E, E_MODE_ABS, E_MODE_REL }; +enum AxisRelative : uint8_t { + LOGICAL_AXIS_LIST(REL_E, REL_X, REL_Y, REL_Z) + #if HAS_EXTRUDERS + , E_MODE_ABS, E_MODE_REL + #endif +}; extern const char G28_STR[]; @@ -324,23 +329,27 @@ class GcodeSuite { static uint8_t axis_relative; static inline bool axis_is_relative(const AxisEnum a) { - if (a == E_AXIS) { - if (TEST(axis_relative, E_MODE_REL)) return true; - if (TEST(axis_relative, E_MODE_ABS)) return false; - } + #if HAS_EXTRUDERS + if (a == E_AXIS) { + if (TEST(axis_relative, E_MODE_REL)) return true; + if (TEST(axis_relative, E_MODE_ABS)) return false; + } + #endif return TEST(axis_relative, a); } static inline void set_relative_mode(const bool rel) { - axis_relative = rel ? _BV(REL_X) | _BV(REL_Y) | _BV(REL_Z) | _BV(REL_E) : 0; - } - static inline void set_e_relative() { - CBI(axis_relative, E_MODE_ABS); - SBI(axis_relative, E_MODE_REL); - } - static inline void set_e_absolute() { - CBI(axis_relative, E_MODE_REL); - SBI(axis_relative, E_MODE_ABS); + axis_relative = rel ? (0 LOGICAL_AXIS_GANG(| _BV(REL_E), | _BV(REL_X), | _BV(REL_Y), | _BV(REL_Z))) : 0; } + #if HAS_EXTRUDERS + static inline void set_e_relative() { + CBI(axis_relative, E_MODE_ABS); + SBI(axis_relative, E_MODE_REL); + } + static inline void set_e_absolute() { + CBI(axis_relative, E_MODE_REL); + SBI(axis_relative, E_MODE_ABS); + } + #endif #if ENABLED(CNC_WORKSPACE_PLANES) /** diff --git a/Marlin/src/gcode/geometry/G92.cpp b/Marlin/src/gcode/geometry/G92.cpp index a9970b1e9c09..990236c0e878 100644 --- a/Marlin/src/gcode/geometry/G92.cpp +++ b/Marlin/src/gcode/geometry/G92.cpp @@ -48,7 +48,10 @@ */ void GcodeSuite::G92() { - bool sync_E = false, sync_XYZE = false; + #if HAS_EXTRUDERS + bool sync_E = false; + #endif + bool sync_XYZE = false; #if USE_GCODE_SUBCODES const uint8_t subcode_G92 = parser.subcode; @@ -72,7 +75,11 @@ void GcodeSuite::G92() { case 9: // G92.9 - Set Current Position directly (like Marlin 1.0) LOOP_LOGICAL_AXES(i) { if (parser.seenval(axis_codes[i])) { - if (i == E_AXIS) sync_E = true; else sync_XYZE = true; + if (TERN1(HAS_EXTRUDERS, i != E_AXIS)) + sync_XYZE = true; + else { + TERN_(HAS_EXTRUDERS, sync_E = true); + } current_position[i] = parser.value_axis_units((AxisEnum)i); } } @@ -83,20 +90,26 @@ void GcodeSuite::G92() { LOOP_LOGICAL_AXES(i) { if (parser.seenval(axis_codes[i])) { const float l = parser.value_axis_units((AxisEnum)i), // Given axis coordinate value, converted to millimeters - v = i == E_AXIS ? l : LOGICAL_TO_NATIVE(l, i), // Axis position in NATIVE space (applying the existing offset) + v = TERN0(HAS_EXTRUDERS, i == E_AXIS) ? l : LOGICAL_TO_NATIVE(l, i), // Axis position in NATIVE space (applying the existing offset) d = v - current_position[i]; // How much is the current axis position altered by? if (!NEAR_ZERO(d)) { #if HAS_POSITION_SHIFT && !IS_SCARA // When using workspaces... - if (i == E_AXIS) { - sync_E = true; - current_position.e = v; // ...E is still set directly + if (TERN1(HAS_EXTRUDERS, i != E_AXIS)) { + position_shift[i] += d; // ...most axes offset the workspace... + update_workspace_offset((AxisEnum)i); } else { - position_shift[i] += d; // ...but other axes offset the workspace. - update_workspace_offset((AxisEnum)i); + #if HAS_EXTRUDERS + sync_E = true; + current_position.e = v; // ...but E is set directly + #endif } #else // Without workspaces... - if (i == E_AXIS) sync_E = true; else sync_XYZE = true; + if (TERN1(HAS_EXTRUDERS, i != E_AXIS)) + sync_XYZE = true; + else { + TERN_(HAS_EXTRUDERS, sync_E = true); + } current_position[i] = v; // ...set Current Position directly (like Marlin 1.0) #endif } @@ -111,8 +124,10 @@ void GcodeSuite::G92() { coordinate_system[active_coordinate_system] = position_shift; #endif - if (sync_XYZE) sync_plan_position(); - else if (sync_E) sync_plan_position_e(); + if (sync_XYZE) sync_plan_position(); + #if HAS_EXTRUDERS + else if (sync_E) sync_plan_position_e(); + #endif IF_DISABLED(DIRECT_STEPPING, report_current_position()); } diff --git a/Marlin/src/gcode/host/M114.cpp b/Marlin/src/gcode/host/M114.cpp index 2d43d33aa122..d28373696ad2 100644 --- a/Marlin/src/gcode/host/M114.cpp +++ b/Marlin/src/gcode/host/M114.cpp @@ -170,7 +170,7 @@ SERIAL_ECHOPGM("FromStp:"); get_cartesian_from_steppers(); // writes 'cartes' (with forward kinematics) - xyze_pos_t from_steppers = { cartes.x, cartes.y, cartes.z, planner.get_axis_position_mm(E_AXIS) }; + xyze_pos_t from_steppers = LOGICAL_AXIS_ARRAY(planner.get_axis_position_mm(E_AXIS), cartes.x, cartes.y, cartes.z); report_all_axis_pos(from_steppers); const xyze_float_t diff = from_steppers - leveled; diff --git a/Marlin/src/gcode/motion/G0_G1.cpp b/Marlin/src/gcode/motion/G0_G1.cpp index 73c5b1171422..30f824803772 100644 --- a/Marlin/src/gcode/motion/G0_G1.cpp +++ b/Marlin/src/gcode/motion/G0_G1.cpp @@ -49,9 +49,11 @@ void GcodeSuite::G0_G1(TERN_(HAS_FAST_MOVES, const bool fast_move/*=false*/)) { if (IsRunning() #if ENABLED(NO_MOTION_BEFORE_HOMING) && !homing_needed_error( - (parser.seen_test('X') ? _BV(X_AXIS) : 0) - | (parser.seen_test('Y') ? _BV(Y_AXIS) : 0) - | (parser.seen_test('Z') ? _BV(Z_AXIS) : 0) ) + LINEAR_AXIS_GANG( + (parser.seen_test('X') ? _BV(X_AXIS) : 0), + | (parser.seen_test('Y') ? _BV(Y_AXIS) : 0), + | (parser.seen_test('Z') ? _BV(Z_AXIS) : 0)) + ) #endif ) { TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_RUNNING)); @@ -83,7 +85,7 @@ void GcodeSuite::G0_G1(TERN_(HAS_FAST_MOVES, const bool fast_move/*=false*/)) { if (MIN_AUTORETRACT <= MAX_AUTORETRACT) { // When M209 Autoretract is enabled, convert E-only moves to firmware retract/recover moves - if (fwretract.autoretract_enabled && parser.seen('E') && !parser.seen("XYZ")) { + if (fwretract.autoretract_enabled && parser.seen_test('E') && !parser.seen(LINEAR_AXIS_GANG("X", "Y", "Z"))) { const float echange = destination.e - current_position.e; // Is this a retract or recover move? if (WITHIN(ABS(echange), MIN_AUTORETRACT, MAX_AUTORETRACT) && fwretract.retracted[active_extruder] == (echange > 0.0)) { diff --git a/Marlin/src/gcode/motion/G2_G3.cpp b/Marlin/src/gcode/motion/G2_G3.cpp index bafc79bcac9a..4d9f5559fe19 100644 --- a/Marlin/src/gcode/motion/G2_G3.cpp +++ b/Marlin/src/gcode/motion/G2_G3.cpp @@ -109,23 +109,32 @@ void plan_arc( #endif } - float linear_travel = cart[l_axis] - start_L, - extruder_travel = cart.e - current_position.e; + float linear_travel = cart[l_axis] - start_L; + + #if HAS_EXTRUDERS + float extruder_travel = cart.e - current_position.e; + #endif // If circling around... if (ENABLED(ARC_P_CIRCLES) && circles) { const float total_angular = angular_travel + circles * RADIANS(360), // Total rotation with all circles and remainder part_per_circle = RADIANS(360) / total_angular, // Each circle's part of the total - l_per_circle = linear_travel * part_per_circle, // L movement per circle - e_per_circle = extruder_travel * part_per_circle; // E movement per circle + l_per_circle = linear_travel * part_per_circle; // L movement per circle + + #if HAS_EXTRUDERS + const float e_per_circle = extruder_travel * part_per_circle; // E movement per circle + #endif + xyze_pos_t temp_position = current_position; // for plan_arc to compare to current_position for (uint16_t n = circles; n--;) { - temp_position.e += e_per_circle; // Destination E axis + TERN_(HAS_EXTRUDERS, temp_position.e += e_per_circle); // Destination E axis temp_position[l_axis] += l_per_circle; // Destination L axis plan_arc(temp_position, offset, clockwise, 0); // Plan a single whole circle } linear_travel = cart[l_axis] - current_position[l_axis]; - extruder_travel = cart.e - current_position.e; + #if HAS_EXTRUDERS + extruder_travel = cart.e - current_position.e; + #endif } const float flat_mm = radius * angular_travel, @@ -179,16 +188,19 @@ void plan_arc( xyze_pos_t raw; const float theta_per_segment = angular_travel / segments, linear_per_segment = linear_travel / segments, - extruder_per_segment = extruder_travel / segments, sq_theta_per_segment = sq(theta_per_segment), sin_T = theta_per_segment - sq_theta_per_segment * theta_per_segment / 6, cos_T = 1 - 0.5f * sq_theta_per_segment; // Small angle approximation + #if HAS_EXTRUDERS + const float extruder_per_segment = extruder_travel / segments; + #endif + // Initialize the linear axis raw[l_axis] = current_position[l_axis]; // Initialize the extruder axis - raw.e = current_position.e; + TERN_(HAS_EXTRUDERS, raw.e = current_position.e); #if ENABLED(SCARA_FEEDRATE_SCALING) const float inv_duration = scaled_fr_mm_s / seg_length; @@ -240,7 +252,8 @@ void plan_arc( #else raw[l_axis] += linear_per_segment; #endif - raw.e += extruder_per_segment; + + TERN_(HAS_EXTRUDERS, raw.e += extruder_per_segment); apply_motion_limits(raw); diff --git a/Marlin/src/gcode/motion/M290.cpp b/Marlin/src/gcode/motion/M290.cpp index 0a858090f955..1f0d494baf3a 100644 --- a/Marlin/src/gcode/motion/M290.cpp +++ b/Marlin/src/gcode/motion/M290.cpp @@ -87,7 +87,7 @@ void GcodeSuite::M290() { } #endif - if (!parser.seen("XYZ") || parser.seen('R')) { + if (!parser.seen(LINEAR_AXIS_GANG("X", "Y", "Z")) || parser.seen('R')) { SERIAL_ECHO_START(); #if ENABLED(BABYSTEP_ZPROBE_OFFSET) diff --git a/Marlin/src/gcode/parser.cpp b/Marlin/src/gcode/parser.cpp index 514d6b7a5daf..b07e92555cae 100644 --- a/Marlin/src/gcode/parser.cpp +++ b/Marlin/src/gcode/parser.cpp @@ -248,7 +248,8 @@ void GCodeParser::parse(char *p) { case 'R': if (!WITHIN(motion_mode_codenum, 2, 3)) return; #endif - case 'X' ... 'Z': case 'E' ... 'F': + LOGICAL_AXIS_GANG(case 'E':, case 'X':, case 'Y':, case 'Z':) + case 'F': if (motion_mode_codenum < 0) return; command_letter = 'G'; codenum = motion_mode_codenum; diff --git a/Marlin/src/gcode/parser.h b/Marlin/src/gcode/parser.h index 4270e04c9f09..dc3f3c35fb64 100644 --- a/Marlin/src/gcode/parser.h +++ b/Marlin/src/gcode/parser.h @@ -226,7 +226,7 @@ class GCodeParser { // Seen any axis parameter static inline bool seen_axis() { - return seen("XYZE"); + return seen(LOGICAL_AXIS_GANG("E", "X", "Y", "Z")); } #if ENABLED(GCODE_QUOTED_STRINGS) diff --git a/Marlin/src/inc/Conditionals_LCD.h b/Marlin/src/inc/Conditionals_LCD.h index 8001674dc4d5..a8bd7a70ac97 100644 --- a/Marlin/src/inc/Conditionals_LCD.h +++ b/Marlin/src/inc/Conditionals_LCD.h @@ -537,12 +537,12 @@ * E_STEPPERS - Number of actual E stepper motors * E_MANUAL - Number of E steppers for LCD move options */ - #if EXTRUDERS #define HAS_EXTRUDERS 1 #if EXTRUDERS > 1 #define HAS_MULTI_EXTRUDER 1 #endif + #define E_AXIS_N(E) AxisEnum(E_AXIS + E_INDEX_N(E)) #else #undef EXTRUDERS #define EXTRUDERS 0 @@ -551,6 +551,7 @@ #undef SWITCHING_NOZZLE #undef MIXING_EXTRUDER #undef HOTEND_IDLE_TIMEOUT + #undef DISABLE_E #endif #if ENABLED(SWITCHING_EXTRUDER) // One stepper for every two EXTRUDERS @@ -604,6 +605,50 @@ #define E_MANUAL EXTRUDERS #endif +/** + * Number of Linear Axes (e.g., XYZ) + * All the logical axes except for the tool (E) axis + */ +#ifndef LINEAR_AXES + #define LINEAR_AXES XYZ +#endif + +/** + * Number of Logical Axes (e.g., XYZE) + * All the logical axes that can be commanded directly by G-code. + * Delta maps stepper-specific values to ABC steppers. + */ +#if HAS_EXTRUDERS + #define LOGICAL_AXES INCREMENT(LINEAR_AXES) +#else + #define LOGICAL_AXES LINEAR_AXES +#endif + +/** + * DISTINCT_E_FACTORS is set to give extruders (some) individual settings. + * + * DISTINCT_AXES is the number of distinct addressable axes (not steppers). + * Includes all linear axes plus all distinguished extruders. + * The default behavior is to treat all extruders as a single E axis + * with shared motion and temperature settings. + * + * DISTINCT_E is the number of distinguished extruders. By default this + * well be 1 which indicates all extruders share the same settings. + * + * E_INDEX_N(E) should be used to get the E index of any item that might be + * distinguished. + */ +#if ENABLED(DISTINCT_E_FACTORS) && E_STEPPERS > 1 + #define DISTINCT_AXES (LINEAR_AXES + E_STEPPERS) + #define DISTINCT_E E_STEPPERS + #define E_INDEX_N(E) (E) +#else + #undef DISTINCT_E_FACTORS + #define DISTINCT_AXES LOGICAL_AXES + #define DISTINCT_E 1 + #define E_INDEX_N(E) 0 +#endif + #if HOTENDS #define HAS_HOTEND 1 #ifndef HOTEND_OVERSHOOT @@ -624,10 +669,6 @@ #define ARRAY_BY_HOTENDS(V...) ARRAY_N(HOTENDS, V) #define ARRAY_BY_HOTENDS1(v1) ARRAY_N_1(HOTENDS, v1) -#if ENABLED(SWITCHING_EXTRUDER) && (DISABLED(SWITCHING_NOZZLE) || SWITCHING_EXTRUDER_SERVO_NR != SWITCHING_NOZZLE_SERVO_NR) - #define DO_SWITCH_EXTRUDER 1 -#endif - /** * Default hotend offsets, if not defined */ @@ -653,39 +694,10 @@ #undef SINGLENOZZLE_STANDBY_FAN #endif -/** - * Number of Linear Axes (e.g., XYZ) - * All the logical axes except for the tool (E) axis - */ -#ifndef LINEAR_AXES - #define LINEAR_AXES XYZ -#endif - -/** - * Number of Logical Axes (e.g., XYZE) - * All the logical axes that can be commanded directly by G-code. - * Delta maps stepper-specific values to ABC steppers. - */ -#if HAS_EXTRUDERS - #define LOGICAL_AXES INCREMENT(LINEAR_AXES) -#else - #define LOGICAL_AXES LINEAR_AXES -#endif - -/** - * DISTINCT_E_FACTORS affects whether Extruders use different settings - */ -#if ENABLED(DISTINCT_E_FACTORS) && E_STEPPERS > 1 - #define DISTINCT_E E_STEPPERS - #define DISTINCT_AXES (LINEAR_AXES + E_STEPPERS) - #define E_INDEX_N(E) (E) -#else - #undef DISTINCT_E_FACTORS - #define DISTINCT_E 1 - #define DISTINCT_AXES LOGICAL_AXES - #define E_INDEX_N(E) 0 +// Switching extruder has its own servo? +#if ENABLED(SWITCHING_EXTRUDER) && (DISABLED(SWITCHING_NOZZLE) || SWITCHING_EXTRUDER_SERVO_NR != SWITCHING_NOZZLE_SERVO_NR) + #define DO_SWITCH_EXTRUDER 1 #endif -#define E_AXIS_N(E) AxisEnum(E_AXIS + E_INDEX_N(E)) /** * The BLTouch Probe emulates a servo probe @@ -726,6 +738,9 @@ #define HAS_BED_PROBE 1 #endif +/** + * Fill in undefined Filament Sensor options + */ #if ENABLED(FILAMENT_RUNOUT_SENSOR) #if NUM_RUNOUT_SENSORS >= 1 #ifndef FIL_RUNOUT1_STATE @@ -834,6 +849,9 @@ #define Z_HOME_TO_MIN 1 #endif +/** + * Conditionals based on the type of Bed Probe + */ #if HAS_BED_PROBE #if DISABLED(NOZZLE_AS_PROBE) #define HAS_PROBE_XY_OFFSET 1 @@ -868,7 +886,7 @@ #endif /** - * Set granular options based on the specific type of leveling + * Conditionals based on the type of Bed Leveling */ #if ENABLED(AUTO_BED_LEVELING_UBL) #undef LCD_BED_LEVELING diff --git a/Marlin/src/inc/Conditionals_adv.h b/Marlin/src/inc/Conditionals_adv.h index 1d3253b1ccb2..18082044e066 100644 --- a/Marlin/src/inc/Conditionals_adv.h +++ b/Marlin/src/inc/Conditionals_adv.h @@ -103,6 +103,9 @@ #undef THERMAL_PROTECTION_PERIOD #undef WATCH_TEMP_PERIOD #undef SHOW_TEMP_ADC_VALUES + #undef LCD_SHOW_E_TOTAL + #undef MANUAL_E_MOVES_RELATIVE + #undef STEALTHCHOP_E #endif #if TEMP_SENSOR_BED == 0 @@ -482,6 +485,23 @@ #endif #endif +// Remove unused STEALTHCHOP flags +#if LINEAR_AXES < 6 + #undef STEALTHCHOP_K + #if LINEAR_AXES < 5 + #undef STEALTHCHOP_J + #if LINEAR_AXES < 4 + #undef STEALTHCHOP_I + #if LINEAR_AXES < 3 + #undef STEALTHCHOP_Z + #if LINEAR_AXES < 2 + #undef STEALTHCHOP_Y + #endif + #endif + #endif + #endif +#endif + // // SD Card connection methods // Defined here so pins and sanity checks can use them diff --git a/Marlin/src/inc/Conditionals_post.h b/Marlin/src/inc/Conditionals_post.h index d86b02bdc233..a0e5db301ea1 100644 --- a/Marlin/src/inc/Conditionals_post.h +++ b/Marlin/src/inc/Conditionals_post.h @@ -1563,133 +1563,137 @@ #endif // Extruder steppers and solenoids -#if PIN_EXISTS(E0_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E0)) - #define HAS_E0_ENABLE 1 -#endif -#if PIN_EXISTS(E0_DIR) - #define HAS_E0_DIR 1 -#endif -#if PIN_EXISTS(E0_STEP) - #define HAS_E0_STEP 1 -#endif -#if PIN_EXISTS(E0_MS1) - #define HAS_E0_MS_PINS 1 -#endif -#if PIN_EXISTS(SOL0) - #define HAS_SOLENOID_0 1 -#endif +#if HAS_EXTRUDERS -#if PIN_EXISTS(E1_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E1)) - #define HAS_E1_ENABLE 1 -#endif -#if PIN_EXISTS(E1_DIR) - #define HAS_E1_DIR 1 -#endif -#if PIN_EXISTS(E1_STEP) - #define HAS_E1_STEP 1 -#endif -#if PIN_EXISTS(E1_MS1) - #define HAS_E1_MS_PINS 1 -#endif -#if PIN_EXISTS(SOL1) - #define HAS_SOLENOID_1 1 -#endif + #if PIN_EXISTS(E0_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E0)) + #define HAS_E0_ENABLE 1 + #endif + #if PIN_EXISTS(E0_DIR) + #define HAS_E0_DIR 1 + #endif + #if PIN_EXISTS(E0_STEP) + #define HAS_E0_STEP 1 + #endif + #if PIN_EXISTS(E0_MS1) + #define HAS_E0_MS_PINS 1 + #endif + #if PIN_EXISTS(SOL0) + #define HAS_SOLENOID_0 1 + #endif -#if PIN_EXISTS(E2_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E2)) - #define HAS_E2_ENABLE 1 -#endif -#if PIN_EXISTS(E2_DIR) - #define HAS_E2_DIR 1 -#endif -#if PIN_EXISTS(E2_STEP) - #define HAS_E2_STEP 1 -#endif -#if PIN_EXISTS(E2_MS1) - #define HAS_E2_MS_PINS 1 -#endif -#if PIN_EXISTS(SOL2) - #define HAS_SOLENOID_2 1 -#endif + #if PIN_EXISTS(E1_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E1)) + #define HAS_E1_ENABLE 1 + #endif + #if PIN_EXISTS(E1_DIR) + #define HAS_E1_DIR 1 + #endif + #if PIN_EXISTS(E1_STEP) + #define HAS_E1_STEP 1 + #endif + #if PIN_EXISTS(E1_MS1) + #define HAS_E1_MS_PINS 1 + #endif + #if PIN_EXISTS(SOL1) + #define HAS_SOLENOID_1 1 + #endif -#if PIN_EXISTS(E3_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E3)) - #define HAS_E3_ENABLE 1 -#endif -#if PIN_EXISTS(E3_DIR) - #define HAS_E3_DIR 1 -#endif -#if PIN_EXISTS(E3_STEP) - #define HAS_E3_STEP 1 -#endif -#if PIN_EXISTS(E3_MS1) - #define HAS_E3_MS_PINS 1 -#endif -#if PIN_EXISTS(SOL3) - #define HAS_SOLENOID_3 1 -#endif + #if PIN_EXISTS(E2_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E2)) + #define HAS_E2_ENABLE 1 + #endif + #if PIN_EXISTS(E2_DIR) + #define HAS_E2_DIR 1 + #endif + #if PIN_EXISTS(E2_STEP) + #define HAS_E2_STEP 1 + #endif + #if PIN_EXISTS(E2_MS1) + #define HAS_E2_MS_PINS 1 + #endif + #if PIN_EXISTS(SOL2) + #define HAS_SOLENOID_2 1 + #endif -#if PIN_EXISTS(E4_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E4)) - #define HAS_E4_ENABLE 1 -#endif -#if PIN_EXISTS(E4_DIR) - #define HAS_E4_DIR 1 -#endif -#if PIN_EXISTS(E4_STEP) - #define HAS_E4_STEP 1 -#endif -#if PIN_EXISTS(E4_MS1) - #define HAS_E4_MS_PINS 1 -#endif -#if PIN_EXISTS(SOL4) - #define HAS_SOLENOID_4 1 -#endif + #if PIN_EXISTS(E3_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E3)) + #define HAS_E3_ENABLE 1 + #endif + #if PIN_EXISTS(E3_DIR) + #define HAS_E3_DIR 1 + #endif + #if PIN_EXISTS(E3_STEP) + #define HAS_E3_STEP 1 + #endif + #if PIN_EXISTS(E3_MS1) + #define HAS_E3_MS_PINS 1 + #endif + #if PIN_EXISTS(SOL3) + #define HAS_SOLENOID_3 1 + #endif -#if PIN_EXISTS(E5_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E5)) - #define HAS_E5_ENABLE 1 -#endif -#if PIN_EXISTS(E5_DIR) - #define HAS_E5_DIR 1 -#endif -#if PIN_EXISTS(E5_STEP) - #define HAS_E5_STEP 1 -#endif -#if PIN_EXISTS(E5_MS1) - #define HAS_E5_MS_PINS 1 -#endif -#if PIN_EXISTS(SOL5) - #define HAS_SOLENOID_5 1 -#endif + #if PIN_EXISTS(E4_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E4)) + #define HAS_E4_ENABLE 1 + #endif + #if PIN_EXISTS(E4_DIR) + #define HAS_E4_DIR 1 + #endif + #if PIN_EXISTS(E4_STEP) + #define HAS_E4_STEP 1 + #endif + #if PIN_EXISTS(E4_MS1) + #define HAS_E4_MS_PINS 1 + #endif + #if PIN_EXISTS(SOL4) + #define HAS_SOLENOID_4 1 + #endif -#if PIN_EXISTS(E6_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E6)) - #define HAS_E6_ENABLE 1 -#endif -#if PIN_EXISTS(E6_DIR) - #define HAS_E6_DIR 1 -#endif -#if PIN_EXISTS(E6_STEP) - #define HAS_E6_STEP 1 -#endif -#if PIN_EXISTS(E6_MS1) - #define HAS_E6_MS_PINS 1 -#endif -#if PIN_EXISTS(SOL6) - #define HAS_SOLENOID_6 1 -#endif + #if PIN_EXISTS(E5_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E5)) + #define HAS_E5_ENABLE 1 + #endif + #if PIN_EXISTS(E5_DIR) + #define HAS_E5_DIR 1 + #endif + #if PIN_EXISTS(E5_STEP) + #define HAS_E5_STEP 1 + #endif + #if PIN_EXISTS(E5_MS1) + #define HAS_E5_MS_PINS 1 + #endif + #if PIN_EXISTS(SOL5) + #define HAS_SOLENOID_5 1 + #endif -#if PIN_EXISTS(E7_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E7)) - #define HAS_E7_ENABLE 1 -#endif -#if PIN_EXISTS(E7_DIR) - #define HAS_E7_DIR 1 -#endif -#if PIN_EXISTS(E7_STEP) - #define HAS_E7_STEP 1 -#endif -#if PIN_EXISTS(E7_MS1) - #define HAS_E7_MS_PINS 1 -#endif -#if PIN_EXISTS(SOL7) - #define HAS_SOLENOID_7 1 -#endif + #if PIN_EXISTS(E6_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E6)) + #define HAS_E6_ENABLE 1 + #endif + #if PIN_EXISTS(E6_DIR) + #define HAS_E6_DIR 1 + #endif + #if PIN_EXISTS(E6_STEP) + #define HAS_E6_STEP 1 + #endif + #if PIN_EXISTS(E6_MS1) + #define HAS_E6_MS_PINS 1 + #endif + #if PIN_EXISTS(SOL6) + #define HAS_SOLENOID_6 1 + #endif + + #if PIN_EXISTS(E7_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E7)) + #define HAS_E7_ENABLE 1 + #endif + #if PIN_EXISTS(E7_DIR) + #define HAS_E7_DIR 1 + #endif + #if PIN_EXISTS(E7_STEP) + #define HAS_E7_STEP 1 + #endif + #if PIN_EXISTS(E7_MS1) + #define HAS_E7_MS_PINS 1 + #endif + #if PIN_EXISTS(SOL7) + #define HAS_SOLENOID_7 1 + #endif + +#endif // HAS_EXTRUDERS // // Trinamic Stepper Drivers @@ -2348,7 +2352,10 @@ #if PIN_EXISTS(DIGIPOTSS) #define HAS_MOTOR_CURRENT_SPI 1 #endif -#if ANY_PIN(MOTOR_CURRENT_PWM_X, MOTOR_CURRENT_PWM_Y, MOTOR_CURRENT_PWM_XY, MOTOR_CURRENT_PWM_Z, MOTOR_CURRENT_PWM_E) +#if HAS_EXTRUDERS && PIN_EXISTS(MOTOR_CURRENT_PWM_E) + #define HAS_MOTOR_CURRENT_PWM_E 1 +#endif +#if HAS_MOTOR_CURRENT_PWM_E || ANY_PIN(MOTOR_CURRENT_PWM_X, MOTOR_CURRENT_PWM_Y, MOTOR_CURRENT_PWM_XY, MOTOR_CURRENT_PWM_Z) #define HAS_MOTOR_CURRENT_PWM 1 #endif diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 897cb2824fc9..eea67661481e 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -1593,11 +1593,12 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS * Homing */ constexpr float hbm[] = HOMING_BUMP_MM; -static_assert(COUNT(hbm) == XYZ, "HOMING_BUMP_MM requires X, Y, and Z elements."); -static_assert(hbm[X_AXIS] >= 0, "HOMING_BUMP_MM.X must be greater than or equal to 0."); -static_assert(hbm[Y_AXIS] >= 0, "HOMING_BUMP_MM.Y must be greater than or equal to 0."); -static_assert(hbm[Z_AXIS] >= 0, "HOMING_BUMP_MM.Z must be greater than or equal to 0."); - +static_assert(COUNT(hbm) == LINEAR_AXES, "HOMING_BUMP_MM requires one element per linear axis."); +LINEAR_AXIS_CODE( + static_assert(hbm[X_AXIS] >= 0, "HOMING_BUMP_MM.X must be greater than or equal to 0."), + static_assert(hbm[Y_AXIS] >= 0, "HOMING_BUMP_MM.Y must be greater than or equal to 0."), + static_assert(hbm[Z_AXIS] >= 0, "HOMING_BUMP_MM.Z must be greater than or equal to 0.") +); #if ENABLED(CODEPENDENT_XY_HOMING) #if ENABLED(QUICK_HOME) #error "QUICK_HOME is incompatible with CODEPENDENT_XY_HOMING." @@ -1976,12 +1977,16 @@ static_assert(hbm[Z_AXIS] >= 0, "HOMING_BUMP_MM.Z must be greater than or equal #error "HEATER_0_PIN not defined for this board." #elif !ANY_PIN(TEMP_0, MAX6675_SS) #error "TEMP_0_PIN or MAX6675_SS not defined for this board." -#elif ((defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__)) && !PINS_EXIST(E0_STEP, E0_DIR)) - #error "E0_STEP_PIN or E0_DIR_PIN not defined for this board." -#elif ( !(defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__)) && (!PINS_EXIST(E0_STEP, E0_DIR) || !HAS_E0_ENABLE)) - #error "E0_STEP_PIN, E0_DIR_PIN, or E0_ENABLE_PIN not defined for this board." -#elif EXTRUDERS && TEMP_SENSOR_0 == 0 - #error "TEMP_SENSOR_0 is required if there are any extruders." +#endif + +#if HAS_EXTRUDERS + #if ((defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__)) && !PINS_EXIST(E0_STEP, E0_DIR)) + #error "E0_STEP_PIN or E0_DIR_PIN not defined for this board." + #elif ( !(defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__)) && (!PINS_EXIST(E0_STEP, E0_DIR) || !HAS_E0_ENABLE)) + #error "E0_STEP_PIN, E0_DIR_PIN, or E0_ENABLE_PIN not defined for this board." + #elif EXTRUDERS && TEMP_SENSOR_0 == 0 + #error "TEMP_SENSOR_0 is required if there are any extruders." + #endif #endif /** diff --git a/Marlin/src/lcd/dogm/status_screen_DOGM.cpp b/Marlin/src/lcd/dogm/status_screen_DOGM.cpp index 010d9a668034..f05958e67536 100644 --- a/Marlin/src/lcd/dogm/status_screen_DOGM.cpp +++ b/Marlin/src/lcd/dogm/status_screen_DOGM.cpp @@ -856,8 +856,10 @@ void MarlinUI::draw_status_screen() { #else if (show_e_total) { - _draw_axis_value(E_AXIS, xstring, true); - lcd_put_u8str_P(PSTR(" ")); + #if ENABLED(LCD_SHOW_E_TOTAL) + _draw_axis_value(E_AXIS, xstring, true); + lcd_put_u8str_P(PSTR(" ")); + #endif } else { _draw_axis_value(X_AXIS, xstring, blink); diff --git a/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp b/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp index 3d68df7b7f02..4f9021064dc8 100644 --- a/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp +++ b/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp @@ -666,10 +666,10 @@ const struct DGUS_VP_Variable ListOfVP[] PROGMEM = { VPHELPER(VP_Z_MAX_SPEED, &planner.settings.max_feedrate_mm_s[Z_AXIS], ScreenHandler.HandleMaxSpeedChange_MKS, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<0>), #if HOTENDS >= 1 - VPHELPER(VP_E0_MAX_SPEED, &planner.settings.max_feedrate_mm_s[E0_AXIS], ScreenHandler.HandleExtruderMaxSpeedChange_MKS, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<0>), + VPHELPER(VP_E0_MAX_SPEED, &planner.settings.max_feedrate_mm_s[E_AXIS_N(0)], ScreenHandler.HandleExtruderMaxSpeedChange_MKS, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<0>), #endif #if HOTENDS >= 2 - VPHELPER(VP_E1_MAX_SPEED, &planner.settings.max_feedrate_mm_s[E1_AXIS], ScreenHandler.HandleExtruderMaxSpeedChange_MKS, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<0>), + VPHELPER(VP_E1_MAX_SPEED, &planner.settings.max_feedrate_mm_s[E_AXIS_N(1)], ScreenHandler.HandleExtruderMaxSpeedChange_MKS, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<0>), #endif VPHELPER(VP_X_ACC_MAX_SPEED, (uint16_t *)&planner.settings.max_acceleration_mm_per_s2[X_AXIS], ScreenHandler.HandleMaxAccChange_MKS, ScreenHandler.DGUSLCD_SendWordValueToDisplay), @@ -677,10 +677,10 @@ const struct DGUS_VP_Variable ListOfVP[] PROGMEM = { VPHELPER(VP_Z_ACC_MAX_SPEED, (uint16_t *)&planner.settings.max_acceleration_mm_per_s2[Z_AXIS], ScreenHandler.HandleMaxAccChange_MKS, ScreenHandler.DGUSLCD_SendWordValueToDisplay), #if HOTENDS >= 1 - VPHELPER(VP_E0_ACC_MAX_SPEED, (uint16_t *)&planner.settings.max_acceleration_mm_per_s2[E0_AXIS], ScreenHandler.HandleExtruderAccChange_MKS, ScreenHandler.DGUSLCD_SendWordValueToDisplay), + VPHELPER(VP_E0_ACC_MAX_SPEED, (uint16_t *)&planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(0)], ScreenHandler.HandleExtruderAccChange_MKS, ScreenHandler.DGUSLCD_SendWordValueToDisplay), #endif #if HOTENDS >= 2 - VPHELPER(VP_E1_ACC_MAX_SPEED, (uint16_t *)&planner.settings.max_acceleration_mm_per_s2[E1_AXIS], ScreenHandler.HandleExtruderAccChange_MKS, ScreenHandler.DGUSLCD_SendWordValueToDisplay), + VPHELPER(VP_E1_ACC_MAX_SPEED, (uint16_t *)&planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(1)], ScreenHandler.HandleExtruderAccChange_MKS, ScreenHandler.DGUSLCD_SendWordValueToDisplay), #endif VPHELPER(VP_TRAVEL_SPEED, (uint16_t *)&planner.settings.travel_acceleration, ScreenHandler.HandleTravelAccChange_MKS, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<0>), diff --git a/Marlin/src/lcd/marlinui.cpp b/Marlin/src/lcd/marlinui.cpp index ba3abc0e2dd2..044a6642fc1f 100644 --- a/Marlin/src/lcd/marlinui.cpp +++ b/Marlin/src/lcd/marlinui.cpp @@ -712,13 +712,15 @@ void MarlinUI::quick_feedback(const bool clear_buttons/*=true*/) { // Add a manual move to the queue? if (axis != NO_AXIS_ENUM && ELAPSED(millis(), start_time) && !planner.is_full()) { - const feedRate_t fr_mm_s = (axis <= E_AXIS) ? manual_feedrate_mm_s[axis] : XY_PROBE_FEEDRATE_MM_S; + const feedRate_t fr_mm_s = (axis <= LOGICAL_AXES) ? manual_feedrate_mm_s[axis] : XY_PROBE_FEEDRATE_MM_S; #if IS_KINEMATIC #if HAS_MULTI_EXTRUDER REMEMBER(ae, active_extruder); - if (axis == E_AXIS) active_extruder = e_index; + #if MULTI_E_MANUAL + if (axis == E_AXIS) active_extruder = e_index; + #endif #endif // Apply a linear offset to a single axis @@ -744,7 +746,9 @@ void MarlinUI::quick_feedback(const bool clear_buttons/*=true*/) { #else // For Cartesian / Core motion simply move to the current_position - planner.buffer_line(current_position, fr_mm_s, axis == E_AXIS ? e_index : active_extruder); + planner.buffer_line(current_position, fr_mm_s, + TERN_(MULTI_E_MANUAL, axis == E_AXIS ? e_index :) active_extruder + ); //SERIAL_ECHOLNPAIR("Add planner.move with Axis ", AS_CHAR(axis_codes[axis]), " at FR ", fr_mm_s); diff --git a/Marlin/src/lcd/menu/menu_advanced.cpp b/Marlin/src/lcd/menu/menu_advanced.cpp index e751b534466f..5c5ec9d3e140 100644 --- a/Marlin/src/lcd/menu/menu_advanced.cpp +++ b/Marlin/src/lcd/menu/menu_advanced.cpp @@ -68,10 +68,7 @@ void menu_backlash(); START_MENU(); BACK_ITEM(MSG_ADVANCED_SETTINGS); #define EDIT_DAC_PERCENT(A) EDIT_ITEM(uint8, MSG_DAC_PERCENT_##A, &driverPercent[_AXIS(A)], 0, 100, []{ stepper_dac.set_current_percents(driverPercent); }) - EDIT_DAC_PERCENT(X); - EDIT_DAC_PERCENT(Y); - EDIT_DAC_PERCENT(Z); - EDIT_DAC_PERCENT(E); + LOGICAL_AXIS_CODE(EDIT_DAC_PERCENT(E), EDIT_DAC_PERCENT(X), EDIT_DAC_PERCENT(Y), EDIT_DAC_PERCENT(Z), EDIT_DAC_PERCENT(I), EDIT_DAC_PERCENT(J), EDIT_DAC_PERCENT(K)); ACTION_ITEM(MSG_DAC_EEPROM_WRITE, stepper_dac.commit_eeprom); END_MENU(); } @@ -359,7 +356,7 @@ void menu_backlash(); #elif ENABLED(LIMITED_MAX_FR_EDITING) DEFAULT_MAX_FEEDRATE #else - { 9999, 9999, 9999, 9999 } + LOGICAL_AXIS_ARRAY(9999, 9999, 9999, 9999) #endif ; #if ENABLED(LIMITED_MAX_FR_EDITING) && !defined(MAX_FEEDRATE_EDIT_VALUES) @@ -372,9 +369,7 @@ void menu_backlash(); BACK_ITEM(MSG_ADVANCED_SETTINGS); #define EDIT_VMAX(N) EDIT_ITEM_FAST(float5, MSG_VMAX_##N, &planner.settings.max_feedrate_mm_s[_AXIS(N)], 1, max_fr_edit_scaled[_AXIS(N)]) - EDIT_VMAX(A); - EDIT_VMAX(B); - EDIT_VMAX(C); + LINEAR_AXIS_CODE(EDIT_VMAX(A), EDIT_VMAX(B), EDIT_VMAX(C), EDIT_VMAX(I), EDIT_VMAX(J), EDIT_VMAX(K)); #if E_STEPPERS EDIT_ITEM_FAST(float5, MSG_VMAX_E, &planner.settings.max_feedrate_mm_s[E_AXIS_N(active_extruder)], 1, max_fr_edit_scaled.e); @@ -404,7 +399,7 @@ void menu_backlash(); #elif ENABLED(LIMITED_MAX_ACCEL_EDITING) DEFAULT_MAX_ACCELERATION #else - { 99000, 99000, 99000, 99000 } + LOGICAL_AXIS_ARRAY(99000, 99000, 99000, 99000) #endif ; #if ENABLED(LIMITED_MAX_ACCEL_EDITING) && !defined(MAX_ACCEL_EDIT_VALUES) @@ -419,16 +414,19 @@ void menu_backlash(); // M204 P Acceleration EDIT_ITEM_FAST(float5_25, MSG_ACC, &planner.settings.acceleration, 25, max_accel); - // M204 R Retract Acceleration - EDIT_ITEM_FAST(float5, MSG_A_RETRACT, &planner.settings.retract_acceleration, 100, planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(active_extruder)]); + #if HAS_EXTRUDERS + // M204 R Retract Acceleration + EDIT_ITEM_FAST(float5, MSG_A_RETRACT, &planner.settings.retract_acceleration, 100, planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(active_extruder)]); + #endif // M204 T Travel Acceleration EDIT_ITEM_FAST(float5_25, MSG_A_TRAVEL, &planner.settings.travel_acceleration, 25, max_accel); #define EDIT_AMAX(Q,L) EDIT_ITEM_FAST(long5_25, MSG_AMAX_##Q, &planner.settings.max_acceleration_mm_per_s2[_AXIS(Q)], L, max_accel_edit_scaled[_AXIS(Q)], []{ planner.reset_acceleration_rates(); }) - EDIT_AMAX(A, 100); - EDIT_AMAX(B, 100); - EDIT_AMAX(C, 10); + LINEAR_AXIS_CODE( + EDIT_AMAX(A, 100), EDIT_AMAX(B, 100), EDIT_AMAX(C, 10), + EDIT_AMAX(I, 10), EDIT_AMAX(J, 10), EDIT_AMAX(K, 10) + ); #if ENABLED(DISTINCT_E_FACTORS) EDIT_ITEM_FAST(long5_25, MSG_AMAX_E, &planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(active_extruder)], 100, max_accel_edit_scaled.e, []{ planner.reset_acceleration_rates(); }); @@ -474,14 +472,14 @@ void menu_backlash(); #endif ; #define EDIT_JERK(N) EDIT_ITEM_FAST(float3, MSG_V##N##_JERK, &planner.max_jerk[_AXIS(N)], 1, max_jerk_edit[_AXIS(N)]) - EDIT_JERK(A); - EDIT_JERK(B); #if ENABLED(DELTA) - EDIT_JERK(C); + #define EDIT_JERK_C() EDIT_JERK(C) #else - EDIT_ITEM_FAST(float52sign, MSG_VC_JERK, &planner.max_jerk.c, 0.1f, max_jerk_edit.c); + #define EDIT_JERK_C() EDIT_ITEM_FAST(float52sign, MSG_VC_JERK, &planner.max_jerk.c, 0.1f, max_jerk_edit.c) #endif - #if HAS_CLASSIC_E_JERK + LINEAR_AXIS_CODE(EDIT_JERK(A), EDIT_JERK(B), EDIT_JERK_C()); + + #if HAS_EXTRUDERS EDIT_ITEM_FAST(float52sign, MSG_VE_JERK, &planner.max_jerk.e, 0.1f, max_jerk_edit.e); #endif @@ -517,9 +515,7 @@ void menu_advanced_steps_per_mm() { BACK_ITEM(MSG_ADVANCED_SETTINGS); #define EDIT_QSTEPS(Q) EDIT_ITEM_FAST(float51, MSG_##Q##_STEPS, &planner.settings.axis_steps_per_mm[_AXIS(Q)], 5, 9999, []{ planner.refresh_positioning(); }) - EDIT_QSTEPS(A); - EDIT_QSTEPS(B); - EDIT_QSTEPS(C); + LINEAR_AXIS_CODE(EDIT_QSTEPS(A), EDIT_QSTEPS(B), EDIT_QSTEPS(C)); #if ENABLED(DISTINCT_E_FACTORS) LOOP_L_N(n, E_STEPPERS) diff --git a/Marlin/src/module/endstops.cpp b/Marlin/src/module/endstops.cpp index dff0b6832a3f..cf152ff0281a 100644 --- a/Marlin/src/module/endstops.cpp +++ b/Marlin/src/module/endstops.cpp @@ -361,7 +361,8 @@ void Endstops::event_handler() { prev_hit_state = hit_state; if (hit_state) { #if HAS_STATUS_MESSAGE - char chrX = ' ', chrY = ' ', chrZ = ' ', chrP = ' '; + char LINEAR_AXIS_LIST(chrX = ' ', chrY = ' ', chrZ = ' '), + chrP = ' '; #define _SET_STOP_CHAR(A,C) (chr## A = C) #else #define _SET_STOP_CHAR(A,C) NOOP @@ -390,7 +391,13 @@ void Endstops::event_handler() { #endif SERIAL_EOL(); - TERN_(HAS_STATUS_MESSAGE, ui.status_printf_P(0, PSTR(S_FMT " %c %c %c %c"), GET_TEXT(MSG_LCD_ENDSTOPS), chrX, chrY, chrZ, chrP)); + TERN_(HAS_STATUS_MESSAGE, + ui.status_printf_P(0, + PSTR(S_FMT GANG_N_1(LINEAR_AXES, " %c") " %c"), + GET_TEXT(MSG_LCD_ENDSTOPS), + LINEAR_AXIS_LIST(chrX, chrY, chrZ), chrP + ) + ); #if BOTH(SD_ABORT_ON_ENDSTOP_HIT, SDSUPPORT) if (planner.abort_on_endstop_hit) { diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index 6801b210af69..ad0537b5cfb1 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -89,7 +89,7 @@ bool relative_mode; // = false; #define Z_INIT_POS Z_HOME_POS #endif -xyze_pos_t current_position = { X_HOME_POS, Y_HOME_POS, Z_INIT_POS }; +xyze_pos_t current_position = LOGICAL_AXIS_ARRAY(0, X_HOME_POS, Y_HOME_POS, Z_INIT_POS); /** * Cartesian Destination @@ -195,16 +195,25 @@ inline void report_more_positions() { // Report the logical position for a given machine position inline void report_logical_position(const xyze_pos_t &rpos) { const xyze_pos_t lpos = rpos.asLogical(); - SERIAL_ECHOPAIR_P(X_LBL, lpos.x, SP_Y_LBL, lpos.y, SP_Z_LBL, lpos.z, SP_E_LBL, lpos.e); + SERIAL_ECHOPAIR_P( + LIST_N(DOUBLE(LINEAR_AXES), X_LBL, lpos.x, SP_Y_LBL, lpos.y, SP_Z_LBL, lpos.z) + #if HAS_EXTRUDERS + , SP_E_LBL, lpos.e + #endif + ); } // Report the real current position according to the steppers. // Forward kinematics and un-leveling are applied. void report_real_position() { get_cartesian_from_steppers(); - xyze_pos_t npos = cartes; - npos.e = planner.get_axis_position_mm(E_AXIS); + xyze_pos_t npos = LOGICAL_AXIS_ARRAY( + planner.get_axis_position_mm(E_AXIS), + cartes.x, cartes.y, cartes.z + ); + TERN_(HAS_POSITION_MODIFIERS, planner.unapply_modifiers(npos, true)); + report_logical_position(npos); report_more_positions(); } @@ -309,7 +318,9 @@ void sync_plan_position() { planner.set_position_mm(current_position); } -void sync_plan_position_e() { planner.set_e_position_mm(current_position.e); } +#if HAS_EXTRUDERS + void sync_plan_position_e() { planner.set_e_position_mm(current_position.e); } +#endif /** * Get the stepper positions in the cartes[] array. @@ -354,7 +365,10 @@ void get_cartesian_from_steppers() { void set_current_from_steppers_for_axis(const AxisEnum axis) { get_cartesian_from_steppers(); xyze_pos_t pos = cartes; - pos.e = planner.get_axis_position_mm(E_AXIS); + + #if HAS_EXTRUDERS + pos.e = planner.get_axis_position_mm(E_AXIS); + #endif #if HAS_POSITION_MODIFIERS planner.unapply_modifiers(pos, true); @@ -442,9 +456,12 @@ void _internal_move_to_destination(const_feedRate_t fr_mm_s/*=0.0f*/ * - Delta may lower Z first to get into the free motion zone. * - Before returning, wait for the planner buffer to empty. */ -void do_blocking_move_to(const float rx, const float ry, const float rz, const_feedRate_t fr_mm_s/*=0.0*/) { +void do_blocking_move_to( + LINEAR_AXIS_LIST(const float rx, const float ry, const float rz), + const_feedRate_t fr_mm_s/*=0.0f*/ +) { DEBUG_SECTION(log_move, "do_blocking_move_to", DEBUGGING(LEVELING)); - if (DEBUGGING(LEVELING)) DEBUG_XYZ("> ", rx, ry, rz); + if (DEBUGGING(LEVELING)) DEBUG_XYZ("> ", LINEAR_AXIS_LIST(rx, ry, rz)); const feedRate_t z_feedrate = fr_mm_s ?: homing_feedrate(Z_AXIS), xy_feedrate = fr_mm_s ?: feedRate_t(XY_PROBE_FEEDRATE_MM_S); @@ -529,34 +546,46 @@ void do_blocking_move_to(const float rx, const float ry, const float rz, const_f } void do_blocking_move_to(const xy_pos_t &raw, const_feedRate_t fr_mm_s/*=0.0f*/) { - do_blocking_move_to(raw.x, raw.y, current_position.z, fr_mm_s); + do_blocking_move_to(LINEAR_AXIS_LIST(raw.x, raw.y, current_position.z, current_position.i), fr_mm_s); } void do_blocking_move_to(const xyz_pos_t &raw, const_feedRate_t fr_mm_s/*=0.0f*/) { - do_blocking_move_to(raw.x, raw.y, raw.z, fr_mm_s); + do_blocking_move_to(LINEAR_AXIS_LIST(raw.x, raw.y, raw.z), fr_mm_s); } void do_blocking_move_to(const xyze_pos_t &raw, const_feedRate_t fr_mm_s/*=0.0f*/) { - do_blocking_move_to(raw.x, raw.y, raw.z, fr_mm_s); + do_blocking_move_to(LINEAR_AXIS_LIST(raw.x, raw.y, raw.z), fr_mm_s); } void do_blocking_move_to_x(const_float_t rx, const_feedRate_t fr_mm_s/*=0.0*/) { - do_blocking_move_to(rx, current_position.y, current_position.z, fr_mm_s); + do_blocking_move_to( + LINEAR_AXIS_LIST(rx, current_position.y, current_position.z), + fr_mm_s + ); } void do_blocking_move_to_y(const_float_t ry, const_feedRate_t fr_mm_s/*=0.0*/) { - do_blocking_move_to(current_position.x, ry, current_position.z, fr_mm_s); + do_blocking_move_to( + LINEAR_AXIS_LIST(current_position.x, ry, current_position.z), + fr_mm_s + ); } void do_blocking_move_to_z(const_float_t rz, const_feedRate_t fr_mm_s/*=0.0*/) { do_blocking_move_to_xy_z(current_position, rz, fr_mm_s); } void do_blocking_move_to_xy(const_float_t rx, const_float_t ry, const_feedRate_t fr_mm_s/*=0.0*/) { - do_blocking_move_to(rx, ry, current_position.z, fr_mm_s); + do_blocking_move_to( + LINEAR_AXIS_LIST(rx, ry, current_position.z), + fr_mm_s + ); } void do_blocking_move_to_xy(const xy_pos_t &raw, const_feedRate_t fr_mm_s/*=0.0f*/) { do_blocking_move_to_xy(raw.x, raw.y, fr_mm_s); } void do_blocking_move_to_xy_z(const xy_pos_t &raw, const_float_t z, const_feedRate_t fr_mm_s/*=0.0f*/) { - do_blocking_move_to(raw.x, raw.y, z, fr_mm_s); + do_blocking_move_to( + LINEAR_AXIS_LIST(raw.x, raw.y, z), + fr_mm_s + ); } void do_z_clearance(const_float_t zclear, const bool lower_allowed/*=false*/) { @@ -589,8 +618,8 @@ void restore_feedrate_and_scaling() { // Software Endstops are based on the configured limits. soft_endstops_t soft_endstop = { true, false, - { X_MIN_POS, Y_MIN_POS, Z_MIN_POS }, - { X_MAX_POS, Y_MAX_POS, Z_MAX_POS } + LINEAR_AXIS_ARRAY(X_MIN_POS, Y_MIN_POS, Z_MIN_POS), + LINEAR_AXIS_ARRAY(X_MAX_BED, Y_MAX_BED, Z_MAX_POS) }; /** @@ -1176,9 +1205,12 @@ void prepare_line_to_destination() { if (TEST(b, a) && TERN(HOME_AFTER_DEACTIVATE, axis_is_trusted, axis_was_homed)(a)) CBI(b, a); }; - set_should(axis_bits, X_AXIS); // Clear test bits that are trusted - set_should(axis_bits, Y_AXIS); - set_should(axis_bits, Z_AXIS); + // Clear test bits that are trusted + LINEAR_AXIS_CODE( + set_should(axis_bits, X_AXIS), + set_should(axis_bits, Y_AXIS), + set_should(axis_bits, Z_AXIS) + ); return axis_bits; } @@ -1187,9 +1219,11 @@ void prepare_line_to_destination() { PGM_P home_first = GET_TEXT(MSG_HOME_FIRST); char msg[strlen_P(home_first)+1]; sprintf_P(msg, home_first, - TEST(axis_bits, X_AXIS) ? "X" : "", - TEST(axis_bits, Y_AXIS) ? "Y" : "", - TEST(axis_bits, Z_AXIS) ? "Z" : "" + LINEAR_AXIS_LIST( + TEST(axis_bits, X_AXIS) ? "X" : "", + TEST(axis_bits, Y_AXIS) ? "Y" : "", + TEST(axis_bits, Z_AXIS) ? "Z" : "" + ) ); SERIAL_ECHO_START(); SERIAL_ECHOLN(msg); @@ -1356,7 +1390,7 @@ void prepare_line_to_destination() { const feedRate_t home_fr_mm_s = fr_mm_s ?: homing_feedrate(axis); if (DEBUGGING(LEVELING)) { - DEBUG_ECHOPAIR("...(", AS_CHAR(axis_codes[axis]), ", ", distance, ", "); + DEBUG_ECHOPAIR("...(", AS_CHAR(AXIS_CHAR(axis)), ", ", distance, ", "); if (fr_mm_s) DEBUG_ECHO(fr_mm_s); else @@ -1441,12 +1475,12 @@ void prepare_line_to_destination() { * "trusted" position). */ void set_axis_never_homed(const AxisEnum axis) { - if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR(">>> set_axis_never_homed(", AS_CHAR(axis_codes[axis]), ")"); + if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR(">>> set_axis_never_homed(", AS_CHAR(AXIS_CHAR(axis)), ")"); set_axis_untrusted(axis); set_axis_unhomed(axis); - if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("<<< set_axis_never_homed(", AS_CHAR(axis_codes[axis]), ")"); + if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("<<< set_axis_never_homed(", AS_CHAR(AXIS_CHAR(axis)), ")"); TERN_(I2C_POSITION_ENCODERS, I2CPEM.unhomed(axis)); } @@ -1507,7 +1541,7 @@ void prepare_line_to_destination() { if (ABS(phaseDelta) * planner.steps_to_mm[axis] / phasePerUStep < 0.05f) SERIAL_ECHOLNPAIR("Selected home phase ", home_phase[axis], " too close to endstop trigger phase ", phaseCurrent, - ". Pick a different phase for ", AS_CHAR(axis_codes[axis])); + ". Pick a different phase for ", AS_CHAR(AXIS_CHAR(axis))); // Skip to next if target position is behind current. So it only moves away from endstop. if (phaseDelta < 0) phaseDelta += 1024; @@ -1518,7 +1552,7 @@ void prepare_line_to_destination() { // Optional debug messages if (DEBUGGING(LEVELING)) { DEBUG_ECHOLNPAIR( - "Endstop ", AS_CHAR(axis_codes[axis]), " hit at Phase:", phaseCurrent, + "Endstop ", AS_CHAR(AXIS_CHAR(axis)), " hit at Phase:", phaseCurrent, " Delta:", phaseDelta, " Distance:", mmDelta ); } @@ -1556,7 +1590,7 @@ void prepare_line_to_destination() { if (!_CAN_HOME(X) && !_CAN_HOME(Y) && !_CAN_HOME(Z)) return; #endif - if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR(">>> homeaxis(", AS_CHAR(axis_codes[axis]), ")"); + if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR(">>> homeaxis(", AS_CHAR(AXIS_CHAR(axis)), ")"); const int axis_home_dir = TERN0(DUAL_X_CARRIAGE, axis == X_AXIS) ? TOOL_X_HOME_DIR(active_extruder) : home_dir(axis); @@ -1634,7 +1668,7 @@ void prepare_line_to_destination() { case Z_AXIS: es = Z_ENDSTOP; break; } if (TEST(endstops.state(), es)) { - SERIAL_ECHO_MSG("Bad ", AS_CHAR(axis_codes[axis]), " Endstop?"); + SERIAL_ECHO_MSG("Bad ", AS_CHAR(AXIS_CHAR(axis)), " Endstop?"); kill(GET_TEXT(MSG_KILL_HOMING_FAILED)); } #endif @@ -1856,7 +1890,7 @@ void prepare_line_to_destination() { if (axis == Z_AXIS) fwretract.current_hop = 0.0; #endif - if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("<<< homeaxis(", AS_CHAR(axis_codes[axis]), ")"); + if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("<<< homeaxis(", AS_CHAR(AXIS_CHAR(axis)), ")"); } // homeaxis() @@ -1881,7 +1915,7 @@ void prepare_line_to_destination() { * Callers must sync the planner position after calling this! */ void set_axis_is_at_home(const AxisEnum axis) { - if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR(">>> set_axis_is_at_home(", AS_CHAR(axis_codes[axis]), ")"); + if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR(">>> set_axis_is_at_home(", AS_CHAR(AXIS_CHAR(axis)), ")"); set_axis_trusted(axis); set_axis_homed(axis); @@ -1931,10 +1965,10 @@ void set_axis_is_at_home(const AxisEnum axis) { if (DEBUGGING(LEVELING)) { #if HAS_HOME_OFFSET - DEBUG_ECHOLNPAIR("> home_offset[", AS_CHAR(axis_codes[axis]), "] = ", home_offset[axis]); + DEBUG_ECHOLNPAIR("> home_offset[", AS_CHAR(AXIS_CHAR(axis)), "] = ", home_offset[axis]); #endif DEBUG_POS("", current_position); - DEBUG_ECHOLNPAIR("<<< set_axis_is_at_home(", AS_CHAR(axis_codes[axis]), ")"); + DEBUG_ECHOLNPAIR("<<< set_axis_is_at_home(", AS_CHAR(AXIS_CHAR(axis)), ")"); } } diff --git a/Marlin/src/module/motion.h b/Marlin/src/module/motion.h index 67205a763602..0706b721b345 100644 --- a/Marlin/src/module/motion.h +++ b/Marlin/src/module/motion.h @@ -124,7 +124,7 @@ inline int8_t pgm_read_any(const int8_t *p) { return TERN(__IMXRT1062__, *p, pgm #define XYZ_DEFS(T, NAME, OPT) \ inline T NAME(const AxisEnum axis) { \ - static const XYZval NAME##_P DEFS_PROGMEM = { X_##OPT, Y_##OPT, Z_##OPT }; \ + static const XYZval NAME##_P DEFS_PROGMEM = LINEAR_AXIS_ARRAY(X_##OPT, Y_##OPT, Z_##OPT); \ return pgm_read_any(&NAME##_P[axis]); \ } XYZ_DEFS(float, base_min_pos, MIN_POS); @@ -264,7 +264,10 @@ void quickstop_stepper(); * no kinematic translation. Used for homing axes and cartesian/core syncing. */ void sync_plan_position(); -void sync_plan_position_e(); + +#if HAS_EXTRUDERS + void sync_plan_position_e(); +#endif /** * Move the planner to the current position from wherever it last moved @@ -295,7 +298,10 @@ inline void prepare_internal_move_to_destination(const_feedRate_t fr_mm_s=0.0f) /** * Blocking movement and shorthand functions */ -void do_blocking_move_to(const float rx, const float ry, const float rz, const_feedRate_t fr_mm_s=0.0f); +void do_blocking_move_to( + LINEAR_AXIS_LIST(const float rx, const float ry, const float rz), + const_feedRate_t fr_mm_s=0.0f +); void do_blocking_move_to(const xy_pos_t &raw, const_feedRate_t fr_mm_s=0.0f); void do_blocking_move_to(const xyz_pos_t &raw, const_feedRate_t fr_mm_s=0.0f); void do_blocking_move_to(const xyze_pos_t &raw, const_feedRate_t fr_mm_s=0.0f); @@ -322,7 +328,7 @@ void do_z_clearance(const_float_t zclear, const bool lower_allowed=false); /** * Homing and Trusted Axes */ -typedef IF<(LINEAR_AXES>8), uint16_t, uint8_t>::type linear_axis_bits_t; +typedef IF<(LINEAR_AXES > 8), uint16_t, uint8_t>::type linear_axis_bits_t; constexpr linear_axis_bits_t linear_bits = _BV(LINEAR_AXES) - 1; void set_axis_is_at_home(const AxisEnum axis); diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index 09db12cd7abd..c06e4be79b44 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -1345,10 +1345,12 @@ void Planner::check_axes_activity() { #if ANY(DISABLE_X, DISABLE_Y, DISABLE_Z, DISABLE_E) for (uint8_t b = block_buffer_tail; b != block_buffer_head; b = next_block_index(b)) { block_t *block = &block_buffer[b]; - if (ENABLED(DISABLE_X) && block->steps.x) axis_active.x = true; - if (ENABLED(DISABLE_Y) && block->steps.y) axis_active.y = true; - if (ENABLED(DISABLE_Z) && block->steps.z) axis_active.z = true; - if (ENABLED(DISABLE_E) && block->steps.e) axis_active.e = true; + LOGICAL_AXIS_CODE( + if (TERN0(DISABLE_E, block->steps.e)) axis_active.e = true, + if (TERN0(DISABLE_X, block->steps.x)) axis_active.x = true, + if (TERN0(DISABLE_Y, block->steps.y)) axis_active.y = true, + if (TERN0(DISABLE_Z, block->steps.z)) axis_active.z = true + ); } #endif } @@ -1369,10 +1371,12 @@ void Planner::check_axes_activity() { // // Disable inactive axes // - if (TERN0(DISABLE_X, !axis_active.x)) DISABLE_AXIS_X(); - if (TERN0(DISABLE_Y, !axis_active.y)) DISABLE_AXIS_Y(); - if (TERN0(DISABLE_Z, !axis_active.z)) DISABLE_AXIS_Z(); - if (TERN0(DISABLE_E, !axis_active.e)) disable_e_steppers(); + LOGICAL_AXIS_CODE( + if (TERN0(DISABLE_E, !axis_active.e)) disable_e_steppers(), + if (TERN0(DISABLE_X, !axis_active.x)) DISABLE_AXIS_X(), + if (TERN0(DISABLE_Y, !axis_active.y)) DISABLE_AXIS_Y(), + if (TERN0(DISABLE_Z, !axis_active.z)) DISABLE_AXIS_Z() + ); // // Update Fan speeds @@ -1823,16 +1827,12 @@ bool Planner::_populate_block(block_t * const block, bool split_move, OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) , feedRate_t fr_mm_s, const uint8_t extruder, const_float_t millimeters/*=0.0*/ ) { - - const int32_t da = target.a - position.a, - db = target.b - position.b, - dc = target.c - position.c; - - #if HAS_EXTRUDERS - int32_t de = target.e - position.e; - #else - constexpr int32_t de = 0; - #endif + int32_t LOGICAL_AXIS_LIST( + de = target.e - position.e, + da = target.a - position.a, + db = target.b - position.b, + dc = target.c - position.c + ); /* <-- add a slash to enable SERIAL_ECHOLNPAIR( @@ -1883,35 +1883,39 @@ bool Planner::_populate_block(block_t * const block, bool split_move, // Compute direction bit-mask for this block uint8_t dm = 0; #if CORE_IS_XY - if (da < 0) SBI(dm, X_HEAD); // Save the real Extruder (head) direction in X Axis + if (da < 0) SBI(dm, X_HEAD); // Save the toolhead's true direction in X if (db < 0) SBI(dm, Y_HEAD); // ...and Y if (dc < 0) SBI(dm, Z_AXIS); if (da + db < 0) SBI(dm, A_AXIS); // Motor A direction if (CORESIGN(da - db) < 0) SBI(dm, B_AXIS); // Motor B direction #elif CORE_IS_XZ - if (da < 0) SBI(dm, X_HEAD); // Save the real Extruder (head) direction in X Axis + if (da < 0) SBI(dm, X_HEAD); // Save the toolhead's true direction in X if (db < 0) SBI(dm, Y_AXIS); if (dc < 0) SBI(dm, Z_HEAD); // ...and Z if (da + dc < 0) SBI(dm, A_AXIS); // Motor A direction if (CORESIGN(da - dc) < 0) SBI(dm, C_AXIS); // Motor C direction #elif CORE_IS_YZ if (da < 0) SBI(dm, X_AXIS); - if (db < 0) SBI(dm, Y_HEAD); // Save the real Extruder (head) direction in Y Axis + if (db < 0) SBI(dm, Y_HEAD); // Save the toolhead's true direction in Y if (dc < 0) SBI(dm, Z_HEAD); // ...and Z if (db + dc < 0) SBI(dm, B_AXIS); // Motor B direction if (CORESIGN(db - dc) < 0) SBI(dm, C_AXIS); // Motor C direction #elif ENABLED(MARKFORGED_XY) - if (da < 0) SBI(dm, X_HEAD); // Save the real Extruder (head) direction in X Axis + if (da < 0) SBI(dm, X_HEAD); // Save the toolhead's true direction in X if (db < 0) SBI(dm, Y_HEAD); // ...and Y if (dc < 0) SBI(dm, Z_AXIS); if (da + db < 0) SBI(dm, A_AXIS); // Motor A direction if (db < 0) SBI(dm, B_AXIS); // Motor B direction #else - if (da < 0) SBI(dm, X_AXIS); - if (db < 0) SBI(dm, Y_AXIS); - if (dc < 0) SBI(dm, Z_AXIS); + LINEAR_AXIS_CODE( + if (da < 0) SBI(dm, X_AXIS), + if (db < 0) SBI(dm, Y_AXIS), + if (dc < 0) SBI(dm, Z_AXIS) + ); + #endif + #if HAS_EXTRUDERS + if (de < 0) SBI(dm, E_AXIS); #endif - if (de < 0) SBI(dm, E_AXIS); #if HAS_EXTRUDERS const float esteps_float = de * e_factor[extruder]; @@ -1947,7 +1951,7 @@ bool Planner::_populate_block(block_t * const block, bool split_move, block->steps.set(ABS(da), ABS(db), ABS(dc)); #else // default non-h-bot planning - block->steps.set(ABS(da), ABS(db), ABS(dc)); + block->steps.set(LINEAR_AXIS_LIST(ABS(da), ABS(db), ABS(dc))); #endif /** @@ -1990,41 +1994,51 @@ bool Planner::_populate_block(block_t * const block, bool split_move, steps_dist_mm.a = (da - db) * steps_to_mm[A_AXIS]; steps_dist_mm.b = db * steps_to_mm[B_AXIS]; #else - steps_dist_mm.a = da * steps_to_mm[A_AXIS]; - steps_dist_mm.b = db * steps_to_mm[B_AXIS]; - steps_dist_mm.c = dc * steps_to_mm[C_AXIS]; + LINEAR_AXIS_CODE( + steps_dist_mm.a = da * steps_to_mm[A_AXIS], + steps_dist_mm.b = db * steps_to_mm[B_AXIS], + steps_dist_mm.c = dc * steps_to_mm[C_AXIS] + ); #endif #if HAS_EXTRUDERS steps_dist_mm.e = esteps_float * steps_to_mm[E_AXIS_N(extruder)]; - #else - steps_dist_mm.e = 0.0f; #endif TERN_(LCD_SHOW_E_TOTAL, e_move_accumulator += steps_dist_mm.e); - if (block->steps.a < MIN_STEPS_PER_SEGMENT && block->steps.b < MIN_STEPS_PER_SEGMENT && block->steps.c < MIN_STEPS_PER_SEGMENT) { - block->millimeters = (0 - #if HAS_EXTRUDERS - + ABS(steps_dist_mm.e) - #endif - ); + if (true LINEAR_AXIS_GANG( + && block->steps.a < MIN_STEPS_PER_SEGMENT, + && block->steps.b < MIN_STEPS_PER_SEGMENT, + && block->steps.c < MIN_STEPS_PER_SEGMENT + ) + ) { + block->millimeters = TERN0(HAS_EXTRUDERS, ABS(steps_dist_mm.e)); } else { if (millimeters) block->millimeters = millimeters; - else + else { block->millimeters = SQRT( #if EITHER(CORE_IS_XY, MARKFORGED_XY) - sq(steps_dist_mm.head.x) + sq(steps_dist_mm.head.y) + sq(steps_dist_mm.z) + LINEAR_AXIS_GANG( + sq(steps_dist_mm.head.x), + sq(steps_dist_mm.head.y), + sq(steps_dist_mm.z) + ) #elif CORE_IS_XZ - sq(steps_dist_mm.head.x) + sq(steps_dist_mm.y) + sq(steps_dist_mm.head.z) + LINEAR_AXIS_GANG( + sq(steps_dist_mm.head.x), + sq(steps_dist_mm.y), + sq(steps_dist_mm.head.z) + ) #elif CORE_IS_YZ - sq(steps_dist_mm.x) + sq(steps_dist_mm.head.y) + sq(steps_dist_mm.head.z) + LINEAR_AXIS_GANG( + sq(steps_dist_mm.x), + sq(steps_dist_mm.head.y), + sq(steps_dist_mm.head.z) + ) #else - sq(steps_dist_mm.x) + sq(steps_dist_mm.y) + sq(steps_dist_mm.z) + LINEAR_AXIS_GANG( + sq(steps_dist_mm.x), + sq(steps_dist_mm.y), + sq(steps_dist_mm.z) + ) #endif ); + } /** * At this point at least one of the axes has more steps than @@ -2038,11 +2052,11 @@ bool Planner::_populate_block(block_t * const block, bool split_move, TERN_(BACKLASH_COMPENSATION, backlash.add_correction_steps(da, db, dc, dm, block)); } - #if HAS_EXTRUDERS - block->steps.e = esteps; - #endif + TERN_(HAS_EXTRUDERS, block->steps.e = esteps); - block->step_event_count = _MAX(block->steps.a, block->steps.b, block->steps.c, esteps); + block->step_event_count = _MAX(LOGICAL_AXIS_LIST( + esteps, block->steps.a, block->steps.b, block->steps.c + )); // Bail if this is a zero-length block if (block->step_event_count < MIN_STEPS_PER_SEGMENT) return false; @@ -2065,8 +2079,11 @@ bool Planner::_populate_block(block_t * const block, bool split_move, #endif #if ENABLED(AUTO_POWER_CONTROL) - if (block->steps.x || block->steps.y || block->steps.z) - powerManager.power_on(); + if (LINEAR_AXIS_GANG( + block->steps.x, + || block->steps.y, + || block->steps.z + )) powerManager.power_on(); #endif // Enable active axes @@ -2091,11 +2108,11 @@ bool Planner::_populate_block(block_t * const block, bool split_move, } if (block->steps.x) ENABLE_AXIS_X(); #else - if (block->steps.x) ENABLE_AXIS_X(); - if (block->steps.y) ENABLE_AXIS_Y(); - #if DISABLED(Z_LATE_ENABLE) - if (block->steps.z) ENABLE_AXIS_Z(); - #endif + LINEAR_AXIS_CODE( + if (block->steps.x) ENABLE_AXIS_X(), + if (block->steps.y) ENABLE_AXIS_Y(), + if (TERN(Z_LATE_ENABLE, 0, block->steps.z)) ENABLE_AXIS_Z() + ); #endif // Enable extruder(s) @@ -2281,7 +2298,9 @@ bool Planner::_populate_block(block_t * const block, bool split_move, // Compute and limit the acceleration rate for the trapezoid generator. const float steps_per_mm = block->step_event_count * inverse_millimeters; uint32_t accel; - if (!block->steps.a && !block->steps.b && !block->steps.c) { // Is this a retract / recover move? + if (LINEAR_AXIS_GANG( + !block->steps.a, && !block->steps.b, && !block->steps.c + )) { // Is this a retract / recover move? accel = CEIL(settings.retract_acceleration * steps_per_mm); // Convert to: acceleration steps/sec^2 TERN_(LIN_ADVANCE, block->use_advance_lead = false); // No linear advance for simple retract/recover } @@ -2346,16 +2365,20 @@ bool Planner::_populate_block(block_t * const block, bool split_move, // Limit acceleration per axis if (block->step_event_count <= acceleration_long_cutoff) { - LIMIT_ACCEL_LONG(A_AXIS, 0); - LIMIT_ACCEL_LONG(B_AXIS, 0); - LIMIT_ACCEL_LONG(C_AXIS, 0); - LIMIT_ACCEL_LONG(E_AXIS, E_INDEX_N(extruder)); + LOGICAL_AXIS_CODE( + LIMIT_ACCEL_LONG(E_AXIS, E_INDEX_N(extruder)), + LIMIT_ACCEL_LONG(A_AXIS, 0), + LIMIT_ACCEL_LONG(B_AXIS, 0), + LIMIT_ACCEL_LONG(C_AXIS, 0) + ); } else { - LIMIT_ACCEL_FLOAT(A_AXIS, 0); - LIMIT_ACCEL_FLOAT(B_AXIS, 0); - LIMIT_ACCEL_FLOAT(C_AXIS, 0); - LIMIT_ACCEL_FLOAT(E_AXIS, E_INDEX_N(extruder)); + LOGICAL_AXIS_CODE( + LIMIT_ACCEL_FLOAT(E_AXIS, E_INDEX_N(extruder)), + LIMIT_ACCEL_FLOAT(A_AXIS, 0), + LIMIT_ACCEL_FLOAT(B_AXIS, 0), + LIMIT_ACCEL_FLOAT(C_AXIS, 0) + ); } } block->acceleration_steps_per_s2 = accel; @@ -2419,7 +2442,7 @@ bool Planner::_populate_block(block_t * const block, bool split_move, #if HAS_DIST_MM_ARG cart_dist_mm #else - { steps_dist_mm.x, steps_dist_mm.y, steps_dist_mm.z, steps_dist_mm.e } + LOGICAL_AXIS_ARRAY(steps_dist_mm.e, steps_dist_mm.x, steps_dist_mm.y, steps_dist_mm.z) #endif ; @@ -2438,8 +2461,12 @@ bool Planner::_populate_block(block_t * const block, bool split_move, if (moves_queued && !UNEAR_ZERO(previous_nominal_speed_sqr)) { // Compute cosine of angle between previous and current path. (prev_unit_vec is negative) // NOTE: Max junction velocity is computed without sin() or acos() by trig half angle identity. - float junction_cos_theta = (-prev_unit_vec.x * unit_vec.x) + (-prev_unit_vec.y * unit_vec.y) - + (-prev_unit_vec.z * unit_vec.z) + (-prev_unit_vec.e * unit_vec.e); + float junction_cos_theta = LOGICAL_AXIS_GANG( + + (-prev_unit_vec.e * unit_vec.e), + (-prev_unit_vec.x * unit_vec.x), + + (-prev_unit_vec.y * unit_vec.y), + + (-prev_unit_vec.z * unit_vec.z) + ); // NOTE: Computed without any expensive trig, sin() or acos(), by trig half angle identity of cos(theta). if (junction_cos_theta > 0.999999f) { @@ -2754,7 +2781,8 @@ void Planner::buffer_sync_block(TERN_(LASER_SYNCHRONOUS_M106_M107, uint8_t sync_ * * Return 'false' if no segment was queued due to cleaning, cold extrusion, full queue, etc. */ -bool Planner::buffer_segment(const_float_t a, const_float_t b, const_float_t c, const_float_t e +bool Planner::buffer_segment( + LOGICAL_AXIS_LIST(const_float_t e, const_float_t a, const_float_t b, const_float_t c) OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) , const_feedRate_t fr_mm_s, const uint8_t extruder, const_float_t millimeters/*=0.0*/ ) { @@ -2773,21 +2801,25 @@ bool Planner::buffer_segment(const_float_t a, const_float_t b, const_float_t c, // The target position of the tool in absolute steps // Calculate target position in absolute steps const abce_long_t target = { - int32_t(LROUND(a * settings.axis_steps_per_mm[A_AXIS])), - int32_t(LROUND(b * settings.axis_steps_per_mm[B_AXIS])), - int32_t(LROUND(c * settings.axis_steps_per_mm[C_AXIS])), - int32_t(LROUND(e * settings.axis_steps_per_mm[E_AXIS_N(extruder)])) + LOGICAL_AXIS_LIST( + int32_t(LROUND(e * settings.axis_steps_per_mm[E_AXIS_N(extruder)])), + int32_t(LROUND(a * settings.axis_steps_per_mm[A_AXIS])), + int32_t(LROUND(b * settings.axis_steps_per_mm[B_AXIS])), + int32_t(LROUND(c * settings.axis_steps_per_mm[C_AXIS])) + ) }; #if HAS_POSITION_FLOAT - const xyze_pos_t target_float = { a, b, c, e }; + const xyze_pos_t target_float = LOGICAL_AXIS_ARRAY(e, a, b, c); #endif - // DRYRUN prevents E moves from taking place - if (DEBUGGING(DRYRUN) || TERN0(CANCEL_OBJECTS, cancelable.skipping)) { - position.e = target.e; - TERN_(HAS_POSITION_FLOAT, position_float.e = e); - } + #if HAS_EXTRUDERS + // DRYRUN prevents E moves from taking place + if (DEBUGGING(DRYRUN) || TERN0(CANCEL_OBJECTS, cancelable.skipping)) { + position.e = target.e; + TERN_(HAS_POSITION_FLOAT, position_float.e = e); + } + #endif /* <-- add a slash to enable SERIAL_ECHOPAIR(" buffer_segment FR:", fr_mm_s); @@ -2846,10 +2878,12 @@ bool Planner::buffer_segment(const_float_t a, const_float_t b, const_float_t c, * millimeters - the length of the movement, if known * inv_duration - the reciprocal if the duration of the movement, if known (kinematic only if feeedrate scaling is enabled) */ -bool Planner::buffer_line(const_float_t rx, const_float_t ry, const_float_t rz, const_float_t e, const_feedRate_t fr_mm_s, const uint8_t extruder, const float millimeters +bool Planner::buffer_line( + LOGICAL_AXIS_LIST(const_float_t e, const_float_t rx, const_float_t ry, const_float_t rz) + , const feedRate_t &fr_mm_s, const uint8_t extruder, const float millimeters OPTARG(SCARA_FEEDRATE_SCALING, const_float_t inv_duration) ) { - xyze_pos_t machine = { rx, ry, rz, e }; + xyze_pos_t machine = LOGICAL_AXIS_ARRAY(e, rx, ry, rz); TERN_(HAS_POSITION_MODIFIERS, apply_modifiers(machine)); #if IS_KINEMATIC @@ -2912,16 +2946,12 @@ bool Planner::buffer_line(const_float_t rx, const_float_t ry, const_float_t rz, FANS_LOOP(i) block->fan_speed[i] = thermalManager.fan_speed[i]; #endif - #if HAS_MULTI_EXTRUDER - block->extruder = extruder; - #endif + TERN_(HAS_MULTI_EXTRUDER, block->extruder = extruder); block->page_idx = page_idx; block->step_event_count = num_steps; - block->initial_rate = - block->final_rate = - block->nominal_rate = last_page_step_rate; // steps/s + block->initial_rate = block->final_rate = block->nominal_rate = last_page_step_rate; // steps/s block->accelerate_until = 0; block->decelerate_after = block->step_event_count; @@ -2965,13 +2995,19 @@ bool Planner::buffer_line(const_float_t rx, const_float_t ry, const_float_t rz, * The provided ABC position is in machine units. */ -void Planner::set_machine_position_mm(const_float_t a, const_float_t b, const_float_t c, const_float_t e) { +void Planner::set_machine_position_mm( + LOGICAL_AXIS_LIST(const_float_t e, const_float_t a, const_float_t b, const_float_t c) +) { TERN_(DISTINCT_E_FACTORS, last_extruder = active_extruder); - TERN_(HAS_POSITION_FLOAT, position_float.set(a, b, c, e)); - position.set(LROUND(a * settings.axis_steps_per_mm[A_AXIS]), - LROUND(b * settings.axis_steps_per_mm[B_AXIS]), - LROUND(c * settings.axis_steps_per_mm[C_AXIS]), - LROUND(e * settings.axis_steps_per_mm[E_AXIS_N(active_extruder)])); + TERN_(HAS_POSITION_FLOAT, position_float.set(LOGICAL_AXIS_LIST(e, a, b, c))); + position.set( + LOGICAL_AXIS_LIST( + LROUND(e * settings.axis_steps_per_mm[E_AXIS_N(active_extruder)]), + LROUND(a * settings.axis_steps_per_mm[A_AXIS]), + LROUND(b * settings.axis_steps_per_mm[B_AXIS]), + LROUND(c * settings.axis_steps_per_mm[C_AXIS]) + ) + ); if (has_blocks_queued()) { //previous_nominal_speed_sqr = 0.0; // Reset planner junction speeds. Assume start from rest. //previous_speed.reset(); @@ -2981,11 +3017,11 @@ void Planner::set_machine_position_mm(const_float_t a, const_float_t b, const_fl stepper.set_position(position); } -void Planner::set_position_mm(const_float_t rx, const_float_t ry, const_float_t rz, const_float_t e) { - xyze_pos_t machine = { rx, ry, rz, e }; - #if HAS_POSITION_MODIFIERS - apply_modifiers(machine, true); - #endif +void Planner::set_position_mm( + LOGICAL_AXIS_LIST(const_float_t e, const_float_t rx, const_float_t ry, const_float_t rz) +) { + xyze_pos_t machine = LOGICAL_AXIS_ARRAY(e, rx, ry, rz); + TERN_(HAS_POSITION_MODIFIERS, apply_modifiers(machine, true)); #if IS_KINEMATIC position_cart.set(rx, ry, rz, e); inverse_kinematics(machine); @@ -2995,23 +3031,27 @@ void Planner::set_position_mm(const_float_t rx, const_float_t ry, const_float_t #endif } -/** - * Setters for planner position (also setting stepper position). - */ -void Planner::set_e_position_mm(const_float_t e) { - const uint8_t axis_index = E_AXIS_N(active_extruder); - TERN_(DISTINCT_E_FACTORS, last_extruder = active_extruder); +#if HAS_EXTRUDERS - const float e_new = DIFF_TERN(FWRETRACT, e, fwretract.current_retract[active_extruder]); - position.e = LROUND(settings.axis_steps_per_mm[axis_index] * e_new); - TERN_(HAS_POSITION_FLOAT, position_float.e = e_new); - TERN_(IS_KINEMATIC, position_cart.e = e); + /** + * Setters for planner position (also setting stepper position). + */ + void Planner::set_e_position_mm(const_float_t e) { + const uint8_t axis_index = E_AXIS_N(active_extruder); + TERN_(DISTINCT_E_FACTORS, last_extruder = active_extruder); - if (has_blocks_queued()) - buffer_sync_block(); - else - stepper.set_axis_position(E_AXIS, position.e); -} + const float e_new = DIFF_TERN(FWRETRACT, e, fwretract.current_retract[active_extruder]); + position.e = LROUND(settings.axis_steps_per_mm[axis_index] * e_new); + TERN_(HAS_POSITION_FLOAT, position_float.e = e_new); + TERN_(IS_KINEMATIC, position_cart.e = e); + + if (has_blocks_queued()) + buffer_sync_block(); + else + stepper.set_axis_position(E_AXIS, position.e); + } + +#endif // Recalculate the steps/s^2 acceleration rates, based on the mm/s^2 void Planner::reset_acceleration_rates() { @@ -3041,11 +3081,11 @@ void Planner::refresh_positioning() { // Apply limits to a variable and give a warning if the value was out of range inline void limit_and_warn(float &val, const uint8_t axis, PGM_P const setting_name, const xyze_float_t &max_limit) { - const uint8_t lim_axis = axis > E_AXIS ? E_AXIS : axis; + const uint8_t lim_axis = TERN_(HAS_EXTRUDERS, axis > E_AXIS ? E_AXIS :) axis; const float before = val; LIMIT(val, 0.1, max_limit[lim_axis]); if (before != val) { - SERIAL_CHAR(axis_codes[lim_axis]); + SERIAL_CHAR(AXIS_CHAR(lim_axis)); SERIAL_ECHOPGM(" Max "); SERIAL_ECHOPGM_P(setting_name); SERIAL_ECHOLNPAIR(" limited to ", val); diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h index be004dd3f4c3..edeac9b7f942 100644 --- a/Marlin/src/module/planner.h +++ b/Marlin/src/module/planner.h @@ -76,7 +76,7 @@ // Feedrate for manual moves #ifdef MANUAL_FEEDRATE constexpr xyze_feedrate_t _mf = MANUAL_FEEDRATE, - manual_feedrate_mm_s { _mf.x / 60.0f, _mf.y / 60.0f, _mf.z / 60.0f, _mf.e / 60.0f }; + manual_feedrate_mm_s = LOGICAL_AXIS_ARRAY(_mf.e / 60.0f, _mf.x / 60.0f, _mf.y / 60.0f, _mf.z / 60.0f); #endif #if IS_KINEMATIC && HAS_JUNCTION_DEVIATION @@ -758,7 +758,8 @@ class Planner { * extruder - target extruder * millimeters - the length of the movement, if known */ - static bool buffer_segment(const_float_t a, const_float_t b, const_float_t c, const_float_t e + static bool buffer_segment( + LOGICAL_AXIS_LIST(const_float_t e, const_float_t a, const_float_t b, const_float_t c) OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) , const_feedRate_t fr_mm_s, const uint8_t extruder, const_float_t millimeters=0.0 ); @@ -767,9 +768,11 @@ class Planner { OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) , const_feedRate_t fr_mm_s, const uint8_t extruder, const_float_t millimeters=0.0 ) { - return buffer_segment(abce.a, abce.b, abce.c, abce.e + return buffer_segment( + LOGICAL_AXIS_LIST(abce.e, abce.a, abce.b, abce.c) OPTARG(HAS_DIST_MM_ARG, cart_dist_mm) - , fr_mm_s, extruder, millimeters); + , fr_mm_s, extruder, millimeters + ); } public: @@ -785,14 +788,18 @@ class Planner { * millimeters - the length of the movement, if known * inv_duration - the reciprocal if the duration of the movement, if known (kinematic only if feeedrate scaling is enabled) */ - static bool buffer_line(const_float_t rx, const_float_t ry, const_float_t rz, const_float_t e, const_feedRate_t fr_mm_s, const uint8_t extruder, const float millimeters=0.0 + static bool buffer_line( + LOGICAL_AXIS_LIST(const_float_t e, const_float_t rx, const_float_t ry, const_float_t rz) + , const feedRate_t &fr_mm_s, const uint8_t extruder, const float millimeters=0.0 OPTARG(SCARA_FEEDRATE_SCALING, const_float_t inv_duration=0.0) ); FORCE_INLINE static bool buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s, const uint8_t extruder, const float millimeters=0.0 OPTARG(SCARA_FEEDRATE_SCALING, const_float_t inv_duration=0.0) ) { - return buffer_line(cart.x, cart.y, cart.z, cart.e, fr_mm_s, extruder, millimeters + return buffer_line( + LOGICAL_AXIS_LIST(cart.e, cart.x, cart.y, cart.z) + , fr_mm_s, extruder, millimeters OPTARG(SCARA_FEEDRATE_SCALING, inv_duration) ); } @@ -814,9 +821,16 @@ class Planner { * * Clears previous speed values. */ - static void set_position_mm(const_float_t rx, const_float_t ry, const_float_t rz, const_float_t e); - FORCE_INLINE static void set_position_mm(const xyze_pos_t &cart) { set_position_mm(cart.x, cart.y, cart.z, cart.e); } - static void set_e_position_mm(const_float_t e); + static void set_position_mm( + LOGICAL_AXIS_LIST(const_float_t e, const_float_t rx, const_float_t ry, const_float_t rz) + ); + FORCE_INLINE static void set_position_mm(const xyze_pos_t &cart) { + set_position_mm(LOGICAL_AXIS_LIST(cart.e, cart.x, cart.y, cart.z, cart.i, cart.j, cart.k)); + } + + #if HAS_EXTRUDERS + static void set_e_position_mm(const_float_t e); + #endif /** * Set the planner.position and individual stepper positions. @@ -824,8 +838,12 @@ class Planner { * The supplied position is in machine space, and no additional * conversions are applied. */ - static void set_machine_position_mm(const_float_t a, const_float_t b, const_float_t c, const_float_t e); - FORCE_INLINE static void set_machine_position_mm(const abce_pos_t &abce) { set_machine_position_mm(abce.a, abce.b, abce.c, abce.e); } + static void set_machine_position_mm( + LOGICAL_AXIS_LIST(const_float_t e, const_float_t a, const_float_t b, const_float_t c) + ); + FORCE_INLINE static void set_machine_position_mm(const abce_pos_t &abce) { + set_machine_position_mm(LOGICAL_AXIS_LIST(abce.e, abce.a, abce.b, abce.c)); + } /** * Get an axis position according to stepper position(s) @@ -834,12 +852,10 @@ class Planner { static float get_axis_position_mm(const AxisEnum axis); static inline abce_pos_t get_axis_positions_mm() { - const abce_pos_t out = { - get_axis_position_mm(A_AXIS), - get_axis_position_mm(B_AXIS), - get_axis_position_mm(C_AXIS), - get_axis_position_mm(E_AXIS) - }; + const abce_pos_t out = LOGICAL_AXIS_ARRAY( + get_axis_position_mm(E_AXIS), + get_axis_position_mm(A_AXIS), get_axis_position_mm(B_AXIS), get_axis_position_mm(C_AXIS) + ); return out; } diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp index eae4728793fe..fc4fdc1f92a8 100644 --- a/Marlin/src/module/settings.cpp +++ b/Marlin/src/module/settings.cpp @@ -168,10 +168,10 @@ void M554_report(); #endif -typedef struct { uint16_t X, Y, Z, X2, Y2, Z2, Z3, Z4, E0, E1, E2, E3, E4, E5, E6, E7; } tmc_stepper_current_t; -typedef struct { uint32_t X, Y, Z, X2, Y2, Z2, Z3, Z4, E0, E1, E2, E3, E4, E5, E6, E7; } tmc_hybrid_threshold_t; -typedef struct { int16_t X, Y, Z, X2, Y2, Z2, Z3, Z4; } tmc_sgt_t; -typedef struct { bool X, Y, Z, X2, Y2, Z2, Z3, Z4, E0, E1, E2, E3, E4, E5, E6, E7; } tmc_stealth_enabled_t; +typedef struct { uint16_t LINEAR_AXIS_LIST(X, Y, Z), X2, Y2, Z2, Z3, Z4, E0, E1, E2, E3, E4, E5, E6, E7; } tmc_stepper_current_t; +typedef struct { uint32_t LINEAR_AXIS_LIST(X, Y, Z), X2, Y2, Z2, Z3, Z4, E0, E1, E2, E3, E4, E5, E6, E7; } tmc_hybrid_threshold_t; +typedef struct { int16_t LINEAR_AXIS_LIST(X, Y, Z), X2, Y2, Z2, Z3, Z4; } tmc_sgt_t; +typedef struct { bool LINEAR_AXIS_LIST(X, Y, Z), X2, Y2, Z2, Z3, Z4, E0, E1, E2, E3, E4, E5, E6, E7; } tmc_stealth_enabled_t; // Limit an index to an array size #define ALIM(I,ARR) _MIN(I, (signed)COUNT(ARR) - 1) @@ -654,7 +654,7 @@ void MarlinSettings::postprocess() { EEPROM_WRITE(dummyf); #endif #else - const xyze_pos_t planner_max_jerk = { 10, 10, 0.4, float(DEFAULT_EJERK) }; + const xyze_pos_t planner_max_jerk = LOGICAL_AXIS_ARRAY(float(DEFAULT_EJERK), 10, 10, 0.4); EEPROM_WRITE(planner_max_jerk); #endif @@ -1188,10 +1188,10 @@ void MarlinSettings::postprocess() { #endif #else const tmc_hybrid_threshold_t tmc_hybrid_threshold = { - .X = 100, .Y = 100, .Z = 3, + LINEAR_AXIS_LIST(.X = 100, .Y = 100, .Z = 3), .X2 = 100, .Y2 = 100, .Z2 = 3, .Z3 = 3, .Z4 = 3, - .E0 = 30, .E1 = 30, .E2 = 30, - .E3 = 30, .E4 = 30, .E5 = 30 + .E0 = 30, .E1 = 30, .E2 = 30, .E3 = 30, + .E4 = 30, .E5 = 30, .E6 = 30, .E7 = 30 }; #endif EEPROM_WRITE(tmc_hybrid_threshold); @@ -2604,7 +2604,7 @@ void MarlinSettings::reset() { #ifndef DEFAULT_ZJERK #define DEFAULT_ZJERK 0 #endif - planner.max_jerk.set(DEFAULT_XJERK, DEFAULT_YJERK, DEFAULT_ZJERK); + planner.max_jerk.set(LINEAR_AXIS_LIST(DEFAULT_XJERK, DEFAULT_YJERK, DEFAULT_ZJERK)); TERN_(HAS_CLASSIC_E_JERK, planner.max_jerk.e = DEFAULT_EJERK;); #endif @@ -3142,10 +3142,12 @@ void MarlinSettings::reset() { CONFIG_ECHO_HEADING("Maximum feedrates (units/s):"); CONFIG_ECHO_START(); SERIAL_ECHOLNPAIR_P( - PSTR(" M203 X"), LINEAR_UNIT(planner.settings.max_feedrate_mm_s[X_AXIS]) - , SP_Y_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Y_AXIS]) - , SP_Z_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Z_AXIS]) - #if DISABLED(DISTINCT_E_FACTORS) + LIST_N(DOUBLE(LINEAR_AXES), + PSTR(" M203 X"), LINEAR_UNIT(planner.settings.max_feedrate_mm_s[X_AXIS]), + SP_Y_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Y_AXIS]), + SP_Z_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Z_AXIS]) + ) + #if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS) , SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_feedrate_mm_s[E_AXIS]) #endif ); @@ -3162,10 +3164,12 @@ void MarlinSettings::reset() { CONFIG_ECHO_HEADING("Maximum Acceleration (units/s2):"); CONFIG_ECHO_START(); SERIAL_ECHOLNPAIR_P( - PSTR(" M201 X"), LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[X_AXIS]) - , SP_Y_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Y_AXIS]) - , SP_Z_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Z_AXIS]) - #if DISABLED(DISTINCT_E_FACTORS) + LIST_N(DOUBLE(LINEAR_AXES), + PSTR(" M201 X"), LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[X_AXIS]), + SP_Y_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Y_AXIS]), + SP_Z_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Z_AXIS]) + ) + #if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS) , SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_acceleration_mm_per_s2[E_AXIS]) #endif ); @@ -3894,9 +3898,11 @@ void MarlinSettings::reset() { CONFIG_ECHO_START(); SERIAL_ECHOLNPAIR_P( PSTR(" M425 F"), backlash.get_correction() - , SP_X_STR, LINEAR_UNIT(backlash.distance_mm.x) - , SP_Y_STR, LINEAR_UNIT(backlash.distance_mm.y) - , SP_Z_STR, LINEAR_UNIT(backlash.distance_mm.z) + , LIST_N(DOUBLE(LINEAR_AXES), + SP_X_STR, LINEAR_UNIT(backlash.distance_mm.x), + SP_Y_STR, LINEAR_UNIT(backlash.distance_mm.y), + SP_Z_STR, LINEAR_UNIT(backlash.distance_mm.z) + ) #ifdef BACKLASH_SMOOTHING_MM , PSTR(" S"), LINEAR_UNIT(backlash.smoothing_mm) #endif diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index 2e2afaeb90b6..bc6dbeaf255c 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -498,7 +498,7 @@ void Stepper::set_directions() { MIXER_STEPPER_LOOP(j) NORM_E_DIR(j); count_direction.e = 1; } - #else + #elif HAS_EXTRUDERS if (motor_direction(E_AXIS)) { REV_E_DIR(stepper_extruder); count_direction.e = -1; @@ -1627,7 +1627,7 @@ void Stepper::pulse_phase_isr() { PAGE_PULSE_PREP(X); PAGE_PULSE_PREP(Y); PAGE_PULSE_PREP(Z); - PAGE_PULSE_PREP(E); + TERN_(HAS_EXTRUDERS, PAGE_PULSE_PREP(E)); page_step_state.segment_steps++; @@ -1660,7 +1660,7 @@ void Stepper::pulse_phase_isr() { PAGE_PULSE_PREP(X); PAGE_PULSE_PREP(Y); PAGE_PULSE_PREP(Z); - PAGE_PULSE_PREP(E); + TERN_(HAS_EXTRUDERS, PAGE_PULSE_PREP(E)); page_step_state.segment_steps++; @@ -2103,13 +2103,15 @@ uint32_t Stepper::block_phase_isr() { #endif uint8_t axis_bits = 0; - if (X_MOVE_TEST) SBI(axis_bits, A_AXIS); - if (Y_MOVE_TEST) SBI(axis_bits, B_AXIS); - if (Z_MOVE_TEST) SBI(axis_bits, C_AXIS); - //if (!!current_block->steps.e) SBI(axis_bits, E_AXIS); - //if (!!current_block->steps.a) SBI(axis_bits, X_HEAD); - //if (!!current_block->steps.b) SBI(axis_bits, Y_HEAD); - //if (!!current_block->steps.c) SBI(axis_bits, Z_HEAD); + LINEAR_AXIS_CODE( + if (X_MOVE_TEST) SBI(axis_bits, A_AXIS), + if (Y_MOVE_TEST) SBI(axis_bits, B_AXIS), + if (Z_MOVE_TEST) SBI(axis_bits, C_AXIS) + ); + //if (current_block->steps.e) SBI(axis_bits, E_AXIS); + //if (current_block->steps.a) SBI(axis_bits, X_HEAD); + //if (current_block->steps.b) SBI(axis_bits, Y_HEAD); + //if (current_block->steps.c) SBI(axis_bits, Z_HEAD); axis_did_move = axis_bits; // No acceleration / deceleration time elapsed so far @@ -2606,9 +2608,13 @@ void Stepper::init() { #endif // Init direction bits for first moves - set_directions((INVERT_X_DIR ? _BV(X_AXIS) : 0) - | (INVERT_Y_DIR ? _BV(Y_AXIS) : 0) - | (INVERT_Z_DIR ? _BV(Z_AXIS) : 0)); + set_directions(0 + LINEAR_AXIS_GANG( + | TERN0(INVERT_X_DIR, _BV(X_AXIS)), + | TERN0(INVERT_Y_DIR, _BV(Y_AXIS)), + | TERN0(INVERT_Z_DIR, _BV(Z_AXIS)) + ) + ); #if HAS_MOTOR_CURRENT_SPI || HAS_MOTOR_CURRENT_PWM initialized = true; @@ -2625,7 +2631,9 @@ void Stepper::init() { * This allows get_axis_position_mm to correctly * derive the current XYZ position later on. */ -void Stepper::_set_position(const int32_t &a, const int32_t &b, const int32_t &c, const int32_t &e) { +void Stepper::_set_position( + LOGICAL_AXIS_LIST(const int32_t &e, const int32_t &a, const int32_t &b, const int32_t &c) +) { #if CORE_IS_XY // corexy positioning // these equations follow the form of the dA and dB equations on https://www.corexy.com/theory.html @@ -2640,9 +2648,9 @@ void Stepper::_set_position(const int32_t &a, const int32_t &b, const int32_t &c count_position.set(a - b, b, c); #else // default non-h-bot planning - count_position.set(a, b, c); + count_position.set(LINEAR_AXIS_LIST(a, b, c)); #endif - count_position.e = e; + TERN_(HAS_EXTRUDERS, count_position.e = e); } /** @@ -2665,10 +2673,13 @@ int32_t Stepper::position(const AxisEnum axis) { } // Set the current position in steps -void Stepper::set_position(const int32_t &a, const int32_t &b, const int32_t &c, const int32_t &e) { +//TODO: Test for LINEAR_AXES >= 4 +void Stepper::set_position( + LOGICAL_AXIS_LIST(const int32_t &e, const int32_t &a, const int32_t &b, const int32_t &c) +) { planner.synchronize(); const bool was_enabled = suspend(); - _set_position(a, b, c, e); + _set_position(LOGICAL_AXIS_LIST(e, a, b, c)); if (was_enabled) wake_up(); } @@ -2743,10 +2754,11 @@ void Stepper::report_a_position(const xyz_long_t &pos) { SERIAL_ECHOPAIR_P(PSTR(STR_COUNT_X), pos.x, SP_Y_LBL, pos.y); #endif #if ANY(CORE_IS_XZ, CORE_IS_YZ, DELTA) - SERIAL_ECHOLNPAIR(" C:", pos.z); - #else - SERIAL_ECHOLNPAIR_P(SP_Z_LBL, pos.z); + SERIAL_ECHOPAIR(" C:", pos.z); + #elif LINEAR_AXES >= 3 + SERIAL_ECHOPAIR_P(SP_Z_LBL, pos.z); #endif + SERIAL_EOL(); } void Stepper::report_positions() { @@ -2903,7 +2915,7 @@ void Stepper::report_positions() { DIR_WAIT_BEFORE(); - const xyz_byte_t old_dir = { X_DIR_READ(), Y_DIR_READ(), Z_DIR_READ() }; + const xyz_byte_t old_dir = LINEAR_AXIS_ARRAY(X_DIR_READ(), Y_DIR_READ(), Z_DIR_READ()); X_DIR_WRITE(INVERT_X_DIR ^ z_direction); Y_DIR_WRITE(INVERT_Y_DIR ^ z_direction); diff --git a/Marlin/src/module/stepper.h b/Marlin/src/module/stepper.h index 020f72e9e685..67ca6fa433e4 100644 --- a/Marlin/src/module/stepper.h +++ b/Marlin/src/module/stepper.h @@ -433,8 +433,12 @@ class Stepper { static int32_t position(const AxisEnum axis); // Set the current position in steps - static void set_position(const int32_t &a, const int32_t &b, const int32_t &c, const int32_t &e); - static inline void set_position(const xyze_long_t &abce) { set_position(abce.a, abce.b, abce.c, abce.e); } + static void set_position( + LOGICAL_AXIS_LIST(const int32_t &e, const int32_t &a, const int32_t &b, const int32_t &c) + ); + static inline void set_position(const xyze_long_t &abce) { + set_position(LOGICAL_AXIS_LIST(abce.e, abce.a, abce.b, abce.c)); + } static void set_axis_position(const AxisEnum a, const int32_t &v); // Report the positions of the steppers, in steps @@ -530,8 +534,12 @@ class Stepper { private: // Set the current position in steps - static void _set_position(const int32_t &a, const int32_t &b, const int32_t &c, const int32_t &e); - FORCE_INLINE static void _set_position(const abce_long_t &spos) { _set_position(spos.a, spos.b, spos.c, spos.e); } + static void _set_position( + LOGICAL_AXIS_LIST(const int32_t &e, const int32_t &a, const int32_t &b, const int32_t &c) + ); + FORCE_INLINE static void _set_position(const abce_long_t &spos) { + _set_position(LOGICAL_AXIS_LIST(spos.e, spos.a, spos.b, spos.c)); + } FORCE_INLINE static uint32_t calc_timer_interval(uint32_t step_rate, uint8_t *loops) { uint32_t timer; diff --git a/Marlin/src/module/stepper/trinamic.cpp b/Marlin/src/module/stepper/trinamic.cpp index 8c943048ba96..5acc8607878d 100644 --- a/Marlin/src/module/stepper/trinamic.cpp +++ b/Marlin/src/module/stepper/trinamic.cpp @@ -35,7 +35,9 @@ #include #include -enum StealthIndex : uint8_t { STEALTH_AXIS_XY, STEALTH_AXIS_Z, STEALTH_AXIS_E }; +enum StealthIndex : uint8_t { + LOGICAL_AXIS_LIST(STEALTH_AXIS_E, STEALTH_AXIS_X, STEALTH_AXIS_Y, STEALTH_AXIS_Z) +}; #define TMC_INIT(ST, STEALTH_INDEX) tmc_init(stepper##ST, ST##_CURRENT, ST##_MICROSTEPS, ST##_HYBRID_THRESHOLD, stealthchop_by_axis[STEALTH_INDEX], chopper_timing_##ST, ST##_INTERPOLATE) // IC = TMC model number @@ -351,7 +353,7 @@ enum StealthIndex : uint8_t { STEALTH_AXIS_XY, STEALTH_AXIS_Z, STEALTH_AXIS_E }; #endif #endif - enum TMCAxis : uint8_t { X, Y, Z, X2, Y2, Z2, Z3, Z4, E0, E1, E2, E3, E4, E5, E6, E7, TOTAL }; + enum TMCAxis : uint8_t { LINEAR_AXIS_LIST(X, Y, Z), X2, Y2, Z2, Z3, Z4, E0, E1, E2, E3, E4, E5, E6, E7, TOTAL }; void tmc_serial_begin() { #if HAS_TMC_HW_SERIAL @@ -716,19 +718,24 @@ void restore_trinamic_drivers() { } void reset_trinamic_drivers() { - static constexpr bool stealthchop_by_axis[] = { ENABLED(STEALTHCHOP_XY), ENABLED(STEALTHCHOP_Z), ENABLED(STEALTHCHOP_E) }; + static constexpr bool stealthchop_by_axis[] = LOGICAL_AXIS_ARRAY( + ENABLED(STEALTHCHOP_E), + ENABLED(STEALTHCHOP_XY), + ENABLED(STEALTHCHOP_XY), + ENABLED(STEALTHCHOP_Z) + ); #if AXIS_IS_TMC(X) - TMC_INIT(X, STEALTH_AXIS_XY); + TMC_INIT(X, STEALTH_AXIS_X); #endif #if AXIS_IS_TMC(X2) - TMC_INIT(X2, STEALTH_AXIS_XY); + TMC_INIT(X2, STEALTH_AXIS_X); #endif #if AXIS_IS_TMC(Y) - TMC_INIT(Y, STEALTH_AXIS_XY); + TMC_INIT(Y, STEALTH_AXIS_Y); #endif #if AXIS_IS_TMC(Y2) - TMC_INIT(Y2, STEALTH_AXIS_XY); + TMC_INIT(Y2, STEALTH_AXIS_Y); #endif #if AXIS_IS_TMC(Z) TMC_INIT(Z, STEALTH_AXIS_Z); @@ -792,7 +799,7 @@ void reset_trinamic_drivers() { stepperZ4.homing_threshold(CAT(TERN(Z4_SENSORLESS, Z4, Z), _STALL_SENSITIVITY)); #endif #endif - #endif + #endif // USE SENSORLESS #ifdef TMC_ADV TMC_ADV() diff --git a/buildroot/tests/mega2560 b/buildroot/tests/mega2560 index a3711ca0766e..ecf82267f49c 100755 --- a/buildroot/tests/mega2560 +++ b/buildroot/tests/mega2560 @@ -171,10 +171,12 @@ exec_test $1 $2 "Azteeg X3 | Mixing Extruder (x5) | Gradient Mix | Greek" "$3" # Test Laser features with 12864 LCD # restore_configs -opt_set MOTHERBOARD BOARD_RAMPS_14_EFB LCD_LANGUAGE en TEMP_SENSOR_COOLER 1 EXTRUDERS 0 TEMP_SENSOR_1 0 SERIAL_PORT_2 2 \ +opt_set MOTHERBOARD BOARD_RAMPS_14_EFB EXTRUDERS 0 LCD_LANGUAGE en TEMP_SENSOR_COOLER 1 TEMP_SENSOR_1 0 SERIAL_PORT_2 2 \ DEFAULT_AXIS_STEPS_PER_UNIT '{ 80, 80, 400 }' \ DEFAULT_MAX_FEEDRATE '{ 300, 300, 5 }' \ - DEFAULT_MAX_ACCELERATION '{ 3000, 3000, 100 }' + DEFAULT_MAX_ACCELERATION '{ 3000, 3000, 100 }' \ + MANUAL_FEEDRATE '{ 50*60, 50*60, 4*60 }' \ + AXIS_RELATIVE_MODES '{ false, false, false }' opt_enable REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER SDSUPPORT EEPROM_SETTINGS EEPROM_BOOT_SILENT EEPROM_AUTO_INIT \ LASER_FEATURE AIR_EVACUATION AIR_EVACUATION_PIN AIR_ASSIST AIR_ASSIST_PIN LASER_COOLANT_FLOW_METER MEATPACK_ON_SERIAL_PORT_1 @@ -184,10 +186,12 @@ exec_test $1 $2 "REPRAP MEGA2560 RAMPS | Laser Feature | Air Evacuation | Air As # Test Laser features with 44780 LCD # restore_configs -opt_set MOTHERBOARD BOARD_RAMPS_14_EFB LCD_LANGUAGE en TEMP_SENSOR_COOLER 1 EXTRUDERS 0 TEMP_SENSOR_1 0 \ +opt_set MOTHERBOARD BOARD_RAMPS_14_EFB EXTRUDERS 0 LCD_LANGUAGE en TEMP_SENSOR_COOLER 1 TEMP_SENSOR_1 0 \ DEFAULT_AXIS_STEPS_PER_UNIT '{ 80, 80, 400 }' \ DEFAULT_MAX_FEEDRATE '{ 300, 300, 5 }' \ - DEFAULT_MAX_ACCELERATION '{ 3000, 3000, 100 }' + DEFAULT_MAX_ACCELERATION '{ 3000, 3000, 100 }' \ + MANUAL_FEEDRATE '{ 50*60, 50*60, 4*60 }' \ + AXIS_RELATIVE_MODES '{ false, false, false }' opt_enable REPRAP_DISCOUNT_SMART_CONTROLLER SDSUPPORT EEPROM_SETTINGS EEPROM_BOOT_SILENT EEPROM_AUTO_INIT \ LASER_FEATURE AIR_EVACUATION AIR_EVACUATION_PIN AIR_ASSIST AIR_ASSIST_PIN LASER_COOLANT_FLOW_METER diff --git a/buildroot/tests/rambo b/buildroot/tests/rambo index 9869b96b3478..953e7e8efca9 100755 --- a/buildroot/tests/rambo +++ b/buildroot/tests/rambo @@ -48,6 +48,7 @@ opt_set MOTHERBOARD BOARD_RAMBO \ DEFAULT_AXIS_STEPS_PER_UNIT '{ 80, 80, 4000 }' \ DEFAULT_MAX_FEEDRATE '{ 300, 300, 5 }' \ DEFAULT_MAX_ACCELERATION '{ 3000, 3000, 100 }' \ + MANUAL_FEEDRATE '{ 50*60, 50*60, 4*60 }' \ AXIS_RELATIVE_MODES '{ false, false, false }' \ LEVEL_CORNERS_LEVELING_ORDER '{ LF, RF }' opt_enable USE_XMAX_PLUG USE_YMAX_PLUG USE_ZMAX_PLUG \ @@ -66,6 +67,7 @@ opt_set MOTHERBOARD BOARD_RAMBO EXTRUDERS 0 TEMP_SENSOR_BED 1 \ DEFAULT_AXIS_STEPS_PER_UNIT '{ 80, 80, 4000 }' \ DEFAULT_MAX_FEEDRATE '{ 300, 300, 5 }' \ DEFAULT_MAX_ACCELERATION '{ 3000, 3000, 100 }' \ + MANUAL_FEEDRATE '{ 50*60, 50*60, 4*60 }' \ AXIS_RELATIVE_MODES '{ false, false, false }' opt_enable REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER exec_test $1 $2 "Rambo heated bed only" "$3"