♻️ Refactor Linear / Logical / Distinct Axes (#21953)

* More patches supporting EXTRUDERS 0
* Extend types in prep for more axes
2.0.x
Scott Lahteine 4 years ago committed by Scott Lahteine
parent f5f999d7bf
commit 4194cdda5b

@ -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); 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(); if (suffix) serialprintPGM(suffix); else SERIAL_EOL();
} }

@ -310,10 +310,13 @@ void serialprint_truefalse(const bool tf);
void serial_spaces(uint8_t count); void serial_spaces(uint8_t count);
void print_bin(const uint16_t val); 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) { 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) #define SERIAL_POS(SUFFIX,VAR) do { print_pos(VAR, PSTR(" " STRINGIFY(VAR) "="), PSTR(" : " SUFFIX "\n")); }while(0)

@ -39,6 +39,26 @@ struct IF { typedef R type; };
template <class L, class R> template <class L, class R>
struct IF<true, L, R> { typedef L type; }; struct IF<true, L, R> { 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 // Enumerated axis indices
// //
@ -47,16 +67,43 @@ struct IF<true, L, R> { typedef L type; };
// - X_HEAD, Y_HEAD, and Z_HEAD should be used for Steppers on Core kinematics // - X_HEAD, Y_HEAD, and Z_HEAD should be used for Steppers on Core kinematics
// //
enum AxisEnum : uint8_t { enum AxisEnum : uint8_t {
X_AXIS = 0, A_AXIS = X_AXIS,
Y_AXIS = 1, B_AXIS = Y_AXIS, // Linear axes may be controlled directly or indirectly
Z_AXIS = 2, C_AXIS = Z_AXIS, LINEAR_AXIS_LIST(X_AXIS, Y_AXIS, Z_AXIS),
E_AXIS,
X_HEAD, Y_HEAD, Z_HEAD, // Extruder axes may be considered distinctly
E0_AXIS = E_AXIS, #define _EN_ITEM(N) E##N##_AXIS,
E1_AXIS, E2_AXIS, E3_AXIS, E4_AXIS, E5_AXIS, E6_AXIS, E7_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 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 // Loop over axes
// //
@ -185,7 +232,7 @@ void toNative(xyz_pos_t &raw);
void toNative(xyze_pos_t &raw); void toNative(xyze_pos_t &raw);
// //
// XY coordinates, counters, etc. // Paired XY coordinates, counters, flags, etc.
// //
template<typename T> template<typename T>
struct XYval { struct XYval {
@ -197,10 +244,14 @@ struct XYval {
FI void set(const T px) { x = px; } 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) { x = px; y = py; }
FI void set(const T (&arr)[XY]) { x = arr[0]; y = arr[1]; } 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]; } #if LINEAR_AXES > XY
FI void set(const T (&arr)[XYZE]) { x = arr[0]; y = arr[1]; } FI void set(const T (&arr)[LINEAR_AXES]) { x = arr[0]; y = arr[1]; }
#if DISTINCT_AXES > LOGICAL_AXES #endif
FI void set(const T (&arr)[DISTINCT_AXES]) { x = arr[0]; y = arr[1]; } #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 #endif
FI void reset() { x = y = 0; } FI void reset() { x = y = 0; }
FI T magnitude() const { return (T)sqrtf(x*x + y*y); } FI T magnitude() const { return (T)sqrtf(x*x + y*y); }
@ -223,8 +274,8 @@ struct XYval {
FI operator XYZval<T>() const { return { x, y }; } FI operator XYZval<T>() const { return { x, y }; }
FI operator XYZEval<T>() { return { x, y }; } FI operator XYZEval<T>() { return { x, y }; }
FI operator XYZEval<T>() const { return { x, y }; } FI operator XYZEval<T>() const { return { x, y }; }
FI T& operator[](const int i) { return pos[i]; } FI T& operator[](const int n) { return pos[n]; }
FI const T& operator[](const int i) const { return pos[i]; } FI const T& operator[](const int n) const { return pos[n]; }
FI XYval<T>& operator= (const T v) { set(v, v ); return *this; } FI XYval<T>& operator= (const T v) { set(v, v ); return *this; }
FI XYval<T>& operator= (const XYZval<T> &rs) { set(rs.x, rs.y); return *this; } FI XYval<T>& operator= (const XYZval<T> &rs) { set(rs.x, rs.y); return *this; }
FI XYval<T>& operator= (const XYZEval<T> &rs) { set(rs.x, rs.y); return *this; } FI XYval<T>& operator= (const XYZEval<T> &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<typename T> template<typename T>
struct XYZval { struct XYZval {
union { union {
struct { T x, y, z; }; struct { T LINEAR_AXIS_LIST(x, y, z); };
struct { T a, b, c; }; struct { T LINEAR_AXIS_LIST(a, b, c); };
T pos[3]; T pos[LINEAR_AXES];
}; };
FI void set(const T px) { x = px; } 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) { 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<T> pxy) { x = pxy.x; y = pxy.y; }
FI void set(const XYval<T> pxy, const T pz) { x = pxy.x; y = pxy.y; z = pz; } FI void set(const XYval<T> 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)[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)[LINEAR_AXES]) { LINEAR_AXIS_CODE(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 LINEAR_AXES >= XYZ
#if DISTINCT_AXES > XYZE FI void set(LINEAR_AXIS_LIST(const T px, const T py, const T pz))
FI void set(const T (&arr)[DISTINCT_AXES]) { x = arr[0]; y = arr[1]; z = arr[2]; } { LINEAR_AXIS_CODE(x = px, y = py, z = pz); }
#endif #endif
FI void reset() { x = y = z = 0; } #if LOGICAL_AXES > LINEAR_AXES
FI T magnitude() const { return (T)sqrtf(x*x + y*y + z*z); } 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() { 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 T* () { return pos; }
FI operator bool() { return z || x || y; } FI operator bool() { return LINEAR_AXIS_GANG(z, || x, || y); }
FI XYZval<T> copy() const { XYZval<T> o = *this; return o; } FI XYZval<T> copy() const { XYZval<T> o = *this; return o; }
FI XYZval<T> ABS() const { return { T(_ABS(x)), T(_ABS(y)), T(_ABS(z)) }; } FI XYZval<T> ABS() const { return LINEAR_AXIS_ARRAY(T(_ABS(x)), T(_ABS(y)), T(_ABS(z))); }
FI XYZval<int16_t> asInt() { return { int16_t(x), int16_t(y), int16_t(z) }; } FI XYZval<int16_t> asInt() { return LINEAR_AXIS_ARRAY(int16_t(x), int16_t(y), int16_t(z)); }
FI XYZval<int16_t> asInt() const { return { int16_t(x), int16_t(y), int16_t(z) }; } FI XYZval<int16_t> asInt() const { return LINEAR_AXIS_ARRAY(int16_t(x), int16_t(y), int16_t(z)); }
FI XYZval<int32_t> asLong() { return { int32_t(x), int32_t(y), int32_t(z) }; } FI XYZval<int32_t> asLong() { return LINEAR_AXIS_ARRAY(int32_t(x), int32_t(y), int32_t(z)); }
FI XYZval<int32_t> asLong() const { return { int32_t(x), int32_t(y), int32_t(z) }; } FI XYZval<int32_t> asLong() const { return LINEAR_AXIS_ARRAY(int32_t(x), int32_t(y), int32_t(z)); }
FI XYZval<int32_t> ROUNDL() { return { int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)) }; } FI XYZval<int32_t> ROUNDL() { return LINEAR_AXIS_ARRAY(int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z))); }
FI XYZval<int32_t> ROUNDL() const { return { int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)) }; } FI XYZval<int32_t> ROUNDL() const { return LINEAR_AXIS_ARRAY(int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z))); }
FI XYZval<float> asFloat() { return { static_cast<float>(x), static_cast<float>(y), static_cast<float>(z) }; } FI XYZval<float> asFloat() { return LINEAR_AXIS_ARRAY(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z)); }
FI XYZval<float> asFloat() const { return { static_cast<float>(x), static_cast<float>(y), static_cast<float>(z) }; } FI XYZval<float> asFloat() const { return LINEAR_AXIS_ARRAY(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z)); }
FI XYZval<float> reciprocal() const { return { _RECIP(x), _RECIP(y), _RECIP(z) }; } FI XYZval<float> reciprocal() const { return LINEAR_AXIS_ARRAY(_RECIP(x), _RECIP(y), _RECIP(z)); }
FI XYZval<float> asLogical() const { XYZval<float> o = asFloat(); toLogical(o); return o; } FI XYZval<float> asLogical() const { XYZval<float> o = asFloat(); toLogical(o); return o; }
FI XYZval<float> asNative() const { XYZval<float> o = asFloat(); toNative(o); return o; } FI XYZval<float> asNative() const { XYZval<float> o = asFloat(); toNative(o); return o; }
FI operator XYval<T>&() { return *(XYval<T>*)this; } FI operator XYval<T>&() { return *(XYval<T>*)this; }
FI operator const XYval<T>&() const { return *(const XYval<T>*)this; } FI operator const XYval<T>&() const { return *(const XYval<T>*)this; }
FI operator XYZEval<T>() const { return { x, y, z }; } FI operator XYZEval<T>() const { return LINEAR_AXIS_ARRAY(x, y, z); }
FI T& operator[](const int i) { return pos[i]; } FI T& operator[](const int n) { return pos[n]; }
FI const T& operator[](const int i) const { return pos[i]; } FI const T& operator[](const int n) const { return pos[n]; }
FI XYZval<T>& operator= (const T v) { set(v, v, v ); return *this; } FI XYZval<T>& operator= (const T v) { set(ARRAY_N_1(LINEAR_AXES, v)); return *this; }
FI XYZval<T>& operator= (const XYval<T> &rs) { set(rs.x, rs.y ); return *this; } FI XYZval<T>& operator= (const XYval<T> &rs) { set(rs.x, rs.y ); return *this; }
FI XYZval<T>& operator= (const XYZEval<T> &rs) { set(rs.x, rs.y, rs.z); return *this; } FI XYZval<T>& operator= (const XYZEval<T> &rs) { set(LINEAR_AXIS_LIST(rs.x, rs.y, rs.z)); return *this; }
FI XYZval<T> operator+ (const XYval<T> &rs) const { XYZval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; } FI XYZval<T> operator+ (const XYval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, NOOP ); return ls; }
FI XYZval<T> operator+ (const XYval<T> &rs) { XYZval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; } FI XYZval<T> operator+ (const XYval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, NOOP ); return ls; }
FI XYZval<T> operator- (const XYval<T> &rs) const { XYZval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; } FI XYZval<T> operator- (const XYval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, NOOP ); return ls; }
FI XYZval<T> operator- (const XYval<T> &rs) { XYZval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; } FI XYZval<T> operator- (const XYval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, NOOP ); return ls; }
FI XYZval<T> operator* (const XYval<T> &rs) const { XYZval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; } FI XYZval<T> operator* (const XYval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, NOOP ); return ls; }
FI XYZval<T> operator* (const XYval<T> &rs) { XYZval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; } FI XYZval<T> operator* (const XYval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, NOOP ); return ls; }
FI XYZval<T> operator/ (const XYval<T> &rs) const { XYZval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; } FI XYZval<T> operator/ (const XYval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, NOOP ); return ls; }
FI XYZval<T> operator/ (const XYval<T> &rs) { XYZval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; } FI XYZval<T> operator/ (const XYval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, NOOP ); return ls; }
FI XYZval<T> operator+ (const XYZval<T> &rs) const { XYZval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; ls.z += rs.z; return ls; } FI XYZval<T> operator+ (const XYZval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z); return ls; }
FI XYZval<T> operator+ (const XYZval<T> &rs) { XYZval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; ls.z += rs.z; return ls; } FI XYZval<T> operator+ (const XYZval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z); return ls; }
FI XYZval<T> operator- (const XYZval<T> &rs) const { XYZval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; ls.z -= rs.z; return ls; } FI XYZval<T> operator- (const XYZval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z); return ls; }
FI XYZval<T> operator- (const XYZval<T> &rs) { XYZval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; ls.z -= rs.z; return ls; } FI XYZval<T> operator- (const XYZval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z); return ls; }
FI XYZval<T> operator* (const XYZval<T> &rs) const { XYZval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; ls.z *= rs.z; return ls; } FI XYZval<T> operator* (const XYZval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z); return ls; }
FI XYZval<T> operator* (const XYZval<T> &rs) { XYZval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; ls.z *= rs.z; return ls; } FI XYZval<T> operator* (const XYZval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z); return ls; }
FI XYZval<T> operator/ (const XYZval<T> &rs) const { XYZval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; return ls; } FI XYZval<T> operator/ (const XYZval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z); return ls; }
FI XYZval<T> operator/ (const XYZval<T> &rs) { XYZval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; return ls; } FI XYZval<T> operator/ (const XYZval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z); return ls; }
FI XYZval<T> operator+ (const XYZEval<T> &rs) const { XYZval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; ls.z += rs.z; return ls; } FI XYZval<T> operator+ (const XYZEval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z); return ls; }
FI XYZval<T> operator+ (const XYZEval<T> &rs) { XYZval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; ls.z += rs.z; return ls; } FI XYZval<T> operator+ (const XYZEval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z); return ls; }
FI XYZval<T> operator- (const XYZEval<T> &rs) const { XYZval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; ls.z -= rs.z; return ls; } FI XYZval<T> operator- (const XYZEval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z); return ls; }
FI XYZval<T> operator- (const XYZEval<T> &rs) { XYZval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; ls.z -= rs.z; return ls; } FI XYZval<T> operator- (const XYZEval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z); return ls; }
FI XYZval<T> operator* (const XYZEval<T> &rs) const { XYZval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; ls.z *= rs.z; return ls; } FI XYZval<T> operator* (const XYZEval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z); return ls; }
FI XYZval<T> operator* (const XYZEval<T> &rs) { XYZval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; ls.z *= rs.z; return ls; } FI XYZval<T> operator* (const XYZEval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z); return ls; }
FI XYZval<T> operator/ (const XYZEval<T> &rs) const { XYZval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; return ls; } FI XYZval<T> operator/ (const XYZEval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z); return ls; }
FI XYZval<T> operator/ (const XYZEval<T> &rs) { XYZval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; return ls; } FI XYZval<T> operator/ (const XYZEval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z); return ls; }
FI XYZval<T> operator* (const float &v) const { XYZval<T> ls = *this; ls.x *= v; ls.y *= v; ls.z *= v; return ls; } FI XYZval<T> operator* (const float &v) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v ); return ls; }
FI XYZval<T> operator* (const float &v) { XYZval<T> ls = *this; ls.x *= v; ls.y *= v; ls.z *= v; return ls; } FI XYZval<T> operator* (const float &v) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v ); return ls; }
FI XYZval<T> operator* (const int &v) const { XYZval<T> ls = *this; ls.x *= v; ls.y *= v; ls.z *= v; return ls; } FI XYZval<T> operator* (const int &v) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v ); return ls; }
FI XYZval<T> operator* (const int &v) { XYZval<T> ls = *this; ls.x *= v; ls.y *= v; ls.z *= v; return ls; } FI XYZval<T> operator* (const int &v) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v ); return ls; }
FI XYZval<T> operator/ (const float &v) const { XYZval<T> ls = *this; ls.x /= v; ls.y /= v; ls.z /= v; return ls; } FI XYZval<T> operator/ (const float &v) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v ); return ls; }
FI XYZval<T> operator/ (const float &v) { XYZval<T> ls = *this; ls.x /= v; ls.y /= v; ls.z /= v; return ls; } FI XYZval<T> operator/ (const float &v) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v ); return ls; }
FI XYZval<T> operator/ (const int &v) const { XYZval<T> ls = *this; ls.x /= v; ls.y /= v; ls.z /= v; return ls; } FI XYZval<T> operator/ (const int &v) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v ); return ls; }
FI XYZval<T> operator/ (const int &v) { XYZval<T> ls = *this; ls.x /= v; ls.y /= v; ls.z /= v; return ls; } FI XYZval<T> operator/ (const int &v) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v ); return ls; }
FI XYZval<T> operator>>(const int &v) const { XYZval<T> ls = *this; _RS(ls.x); _RS(ls.y); _RS(ls.z); return ls; } FI XYZval<T> operator>>(const int &v) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(_RS(ls.x), _RS(ls.y), _RS(ls.z) ); return ls; }
FI XYZval<T> operator>>(const int &v) { XYZval<T> ls = *this; _RS(ls.x); _RS(ls.y); _RS(ls.z); return ls; } FI XYZval<T> operator>>(const int &v) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(_RS(ls.x), _RS(ls.y), _RS(ls.z) ); return ls; }
FI XYZval<T> operator<<(const int &v) const { XYZval<T> ls = *this; _LS(ls.x); _LS(ls.y); _LS(ls.z); return ls; } FI XYZval<T> operator<<(const int &v) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(_LS(ls.x), _LS(ls.y), _LS(ls.z) ); return ls; }
FI XYZval<T> operator<<(const int &v) { XYZval<T> ls = *this; _LS(ls.x); _LS(ls.y); _LS(ls.z); return ls; } FI XYZval<T> operator<<(const int &v) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(_LS(ls.x), _LS(ls.y), _LS(ls.z) ); return ls; }
FI XYZval<T>& operator+=(const XYval<T> &rs) { x += rs.x; y += rs.y; return *this; } FI XYZval<T>& operator+=(const XYval<T> &rs) { LINEAR_AXIS_CODE(x += rs.x, y += rs.y, NOOP ); return *this; }
FI XYZval<T>& operator-=(const XYval<T> &rs) { x -= rs.x; y -= rs.y; return *this; } FI XYZval<T>& operator-=(const XYval<T> &rs) { LINEAR_AXIS_CODE(x -= rs.x, y -= rs.y, NOOP ); return *this; }
FI XYZval<T>& operator*=(const XYval<T> &rs) { x *= rs.x; y *= rs.y; return *this; } FI XYZval<T>& operator*=(const XYval<T> &rs) { LINEAR_AXIS_CODE(x *= rs.x, y *= rs.y, NOOP ); return *this; }
FI XYZval<T>& operator/=(const XYval<T> &rs) { x /= rs.x; y /= rs.y; return *this; } FI XYZval<T>& operator/=(const XYval<T> &rs) { LINEAR_AXIS_CODE(x /= rs.x, y /= rs.y, NOOP ); return *this; }
FI XYZval<T>& operator+=(const XYZval<T> &rs) { x += rs.x; y += rs.y; z += rs.z; return *this; } FI XYZval<T>& operator+=(const XYZval<T> &rs) { LINEAR_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z ); return *this; }
FI XYZval<T>& operator-=(const XYZval<T> &rs) { x -= rs.x; y -= rs.y; z -= rs.z; return *this; } FI XYZval<T>& operator-=(const XYZval<T> &rs) { LINEAR_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z ); return *this; }
FI XYZval<T>& operator*=(const XYZval<T> &rs) { x *= rs.x; y *= rs.y; z *= rs.z; return *this; } FI XYZval<T>& operator*=(const XYZval<T> &rs) { LINEAR_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z ); return *this; }
FI XYZval<T>& operator/=(const XYZval<T> &rs) { x /= rs.x; y /= rs.y; z /= rs.z; return *this; } FI XYZval<T>& operator/=(const XYZval<T> &rs) { LINEAR_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z ); return *this; }
FI XYZval<T>& operator+=(const XYZEval<T> &rs) { x += rs.x; y += rs.y; z += rs.z; return *this; } FI XYZval<T>& operator+=(const XYZEval<T> &rs) { LINEAR_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z ); return *this; }
FI XYZval<T>& operator-=(const XYZEval<T> &rs) { x -= rs.x; y -= rs.y; z -= rs.z; return *this; } FI XYZval<T>& operator-=(const XYZEval<T> &rs) { LINEAR_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z ); return *this; }
FI XYZval<T>& operator*=(const XYZEval<T> &rs) { x *= rs.x; y *= rs.y; z *= rs.z; return *this; } FI XYZval<T>& operator*=(const XYZEval<T> &rs) { LINEAR_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z ); return *this; }
FI XYZval<T>& operator/=(const XYZEval<T> &rs) { x /= rs.x; y /= rs.y; z /= rs.z; return *this; } FI XYZval<T>& operator/=(const XYZEval<T> &rs) { LINEAR_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z ); return *this; }
FI XYZval<T>& operator*=(const float &v) { x *= v; y *= v; z *= v; return *this; } FI XYZval<T>& operator*=(const float &v) { LINEAR_AXIS_CODE(x *= v, y *= v, z *= v ); return *this; }
FI XYZval<T>& operator*=(const int &v) { x *= v; y *= v; z *= v; return *this; } FI XYZval<T>& operator*=(const int &v) { LINEAR_AXIS_CODE(x *= v, y *= v, z *= v ); return *this; }
FI XYZval<T>& operator>>=(const int &v) { _RS(x); _RS(y); _RS(z); return *this; } FI XYZval<T>& operator>>=(const int &v) { LINEAR_AXIS_CODE(_RS(x), _RS(y), _RS(z) ); return *this; }
FI XYZval<T>& operator<<=(const int &v) { _LS(x); _LS(y); _LS(z); return *this; } FI XYZval<T>& operator<<=(const int &v) { LINEAR_AXIS_CODE(_LS(x), _LS(y), _LS(z) ); return *this; }
FI bool operator==(const XYZEval<T> &rs) { return x == rs.x && y == rs.y && z == rs.z; } FI bool operator==(const XYZEval<T> &rs) { return true LINEAR_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z); }
FI bool operator==(const XYZEval<T> &rs) const { return true LINEAR_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z); }
FI bool operator!=(const XYZEval<T> &rs) { return !operator==(rs); } FI bool operator!=(const XYZEval<T> &rs) { return !operator==(rs); }
FI bool operator==(const XYZEval<T> &rs) const { return x == rs.x && y == rs.y && z == rs.z; }
FI bool operator!=(const XYZEval<T> &rs) const { return !operator==(rs); } FI bool operator!=(const XYZEval<T> &rs) const { return !operator==(rs); }
FI XYZval<T> operator-() { XYZval<T> o = *this; o.x = -x; o.y = -y; o.z = -z; return o; } FI XYZval<T> operator-() { XYZval<T> o = *this; LINEAR_AXIS_CODE(o.x = -x, o.y = -y, o.z = -z); return o; }
FI const XYZval<T> operator-() const { XYZval<T> o = *this; o.x = -x; o.y = -y; o.z = -z; return o; } FI const XYZval<T> operator-() const { XYZval<T> 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<typename T> template<typename T>
struct XYZEval { struct XYZEval {
union { union {
struct{ T x, y, z, e; }; struct{ T LOGICAL_AXIS_LIST(e, x, y, z); };
struct{ T a, b, c; }; struct{ T LINEAR_AXIS_LIST(a, b, c); };
T pos[4]; T pos[LOGICAL_AXES];
}; };
FI void reset() { x = y = z = e = 0; } FI void reset() { LOGICAL_AXIS_GANG(e =, x =, y =, z =) 0; }
FI T magnitude() const { return (T)sqrtf(x*x + y*y + z*z + e*e); } 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 T* () { return pos; }
FI operator bool() { return e || z || x || y; } 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) { x = px; }
FI void set(const T px, const T py) { x = px; y = py; } 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<T> pxy) { x = pxy.x; y = pxy.y; }
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 XYZval<T> pxyz) { set(LINEAR_AXIS_LIST(pxyz.x, pxyz.y, pxyz.z)); }
FI void set(const XYval<T> pxy) { x = pxy.x; y = pxy.y; } #if LINEAR_AXES >= XYZ
FI void set(const XYval<T> pxy, const T pz) { x = pxy.x; y = pxy.y; z = pz; } FI void set(LINEAR_AXIS_LIST(const T px, const T py, const T pz)) {
FI void set(const XYZval<T> pxyz) { x = pxyz.x; y = pxyz.y; z = pxyz.z; } LINEAR_AXIS_CODE(x = px, y = py, z = pz);
FI void set(const XYval<T> pxy, const T pz, const T pe) { x = pxy.x; y = pxy.y; z = pz; e = pe; } }
FI void set(const XYval<T> pxy, const XYval<T> pze) { x = pxy.x; y = pxy.y; z = pze.z; e = pze.e; }
FI void set(const XYZval<T> 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]; }
#endif #endif
FI XYZEval<T> copy() const { return *this; } #if LOGICAL_AXES > LINEAR_AXES
FI XYZEval<T> ABS() const { return { T(_ABS(x)), T(_ABS(y)), T(_ABS(z)), T(_ABS(e)) }; } FI void set(LOGICAL_AXIS_LIST(const T pe, const T px, const T py, const T pz)) {
FI XYZEval<int16_t> asInt() { return { int16_t(x), int16_t(y), int16_t(z), int16_t(e) }; } LOGICAL_AXIS_CODE(e = pe, x = px, y = py, z = pz);
FI XYZEval<int16_t> asInt() const { return { int16_t(x), int16_t(y), int16_t(z), int16_t(e) }; } }
FI XYZEval<int32_t> asLong() { return { int32_t(x), int32_t(y), int32_t(z), int32_t(e) }; } FI void set(const XYval<T> pxy, const T pe) { set(pxy); e = pe; }
FI XYZEval<int32_t> asLong() const { return { int32_t(x), int32_t(y), int32_t(z), int32_t(e) }; } FI void set(const XYZval<T> pxyz, const T pe) { set(pxyz); e = pe; }
FI XYZEval<int32_t> ROUNDL() { return { int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(e)) }; } #endif
FI XYZEval<int32_t> ROUNDL() const { return { int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(e)) }; } FI XYZEval<T> copy() const { XYZEval<T> o = *this; return o; }
FI XYZEval<float> asFloat() { return { static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(e) }; } FI XYZEval<T> ABS() const { return LOGICAL_AXIS_ARRAY(T(_ABS(e)), T(_ABS(x)), T(_ABS(y)), T(_ABS(z))); }
FI XYZEval<float> asFloat() const { return { static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(e) }; } FI XYZEval<int16_t> asInt() { return LOGICAL_AXIS_ARRAY(int16_t(e), int16_t(x), int16_t(y), int16_t(z)); }
FI XYZEval<float> reciprocal() const { return { _RECIP(x), _RECIP(y), _RECIP(z), _RECIP(e) }; } FI XYZEval<int16_t> asInt() const { return LOGICAL_AXIS_ARRAY(int16_t(e), int16_t(x), int16_t(y), int16_t(z)); }
FI XYZEval<int32_t> asLong() { return LOGICAL_AXIS_ARRAY(int32_t(e), int32_t(x), int32_t(y), int32_t(z)); }
FI XYZEval<int32_t> asLong() const { return LOGICAL_AXIS_ARRAY(int32_t(e), int32_t(x), int32_t(y), int32_t(z)); }
FI XYZEval<int32_t> ROUNDL() { return LOGICAL_AXIS_ARRAY(int32_t(LROUND(e)), int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z))); }
FI XYZEval<int32_t> ROUNDL() const { return LOGICAL_AXIS_ARRAY(int32_t(LROUND(e)), int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z))); }
FI XYZEval<float> asFloat() { return LOGICAL_AXIS_ARRAY(static_cast<float>(e), static_cast<float>(x), static_cast<float>(y), static_cast<float>(z)); }
FI XYZEval<float> asFloat() const { return LOGICAL_AXIS_ARRAY(static_cast<float>(e), static_cast<float>(x), static_cast<float>(y), static_cast<float>(z)); }
FI XYZEval<float> reciprocal() const { return LOGICAL_AXIS_ARRAY(_RECIP(e), _RECIP(x), _RECIP(y), _RECIP(z)); }
FI XYZEval<float> asLogical() const { XYZEval<float> o = asFloat(); toLogical(o); return o; } FI XYZEval<float> asLogical() const { XYZEval<float> o = asFloat(); toLogical(o); return o; }
FI XYZEval<float> asNative() const { XYZEval<float> o = asFloat(); toNative(o); return o; } FI XYZEval<float> asNative() const { XYZEval<float> o = asFloat(); toNative(o); return o; }
FI operator XYval<T>&() { return *(XYval<T>*)this; } FI operator XYval<T>&() { return *(XYval<T>*)this; }
FI operator const XYval<T>&() const { return *(const XYval<T>*)this; } FI operator const XYval<T>&() const { return *(const XYval<T>*)this; }
FI operator XYZval<T>&() { return *(XYZval<T>*)this; } FI operator XYZval<T>&() { return *(XYZval<T>*)this; }
FI operator const XYZval<T>&() const { return *(const XYZval<T>*)this; } FI operator const XYZval<T>&() const { return *(const XYZval<T>*)this; }
FI T& operator[](const int i) { return pos[i]; } FI T& operator[](const int n) { return pos[n]; }
FI const T& operator[](const int i) const { return pos[i]; } FI const T& operator[](const int n) const { return pos[n]; }
FI XYZEval<T>& operator= (const T v) { set(v, v, v, v); return *this; } FI XYZEval<T>& operator= (const T v) { set(LIST_N_1(LINEAR_AXES, v)); return *this; }
FI XYZEval<T>& operator= (const XYval<T> &rs) { set(rs.x, rs.y); return *this; } FI XYZEval<T>& operator= (const XYval<T> &rs) { set(rs.x, rs.y); return *this; }
FI XYZEval<T>& operator= (const XYZval<T> &rs) { set(rs.x, rs.y, rs.z); return *this; } FI XYZEval<T>& operator= (const XYZval<T> &rs) { set(LINEAR_AXIS_LIST(rs.x, rs.y, rs.z)); return *this; }
FI XYZEval<T> operator+ (const XYval<T> &rs) const { XYZEval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; } FI XYZEval<T> operator+ (const XYval<T> &rs) const { XYZEval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; }
FI XYZEval<T> operator+ (const XYval<T> &rs) { XYZEval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; } FI XYZEval<T> operator+ (const XYval<T> &rs) { XYZEval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; }
FI XYZEval<T> operator- (const XYval<T> &rs) const { XYZEval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; } FI XYZEval<T> operator- (const XYval<T> &rs) const { XYZEval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; }
FI XYZEval<T> operator- (const XYval<T> &rs) { XYZEval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; } FI XYZEval<T> operator- (const XYval<T> &rs) { XYZEval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; }
FI XYZEval<T> operator* (const XYval<T> &rs) const { XYZEval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; } FI XYZEval<T> operator* (const XYval<T> &rs) const { XYZEval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; }
FI XYZEval<T> operator* (const XYval<T> &rs) { XYZEval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; } FI XYZEval<T> operator* (const XYval<T> &rs) { XYZEval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; }
FI XYZEval<T> operator/ (const XYval<T> &rs) const { XYZEval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; } FI XYZEval<T> operator/ (const XYval<T> &rs) const { XYZEval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; }
FI XYZEval<T> operator/ (const XYval<T> &rs) { XYZEval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; } FI XYZEval<T> operator/ (const XYval<T> &rs) { XYZEval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; }
FI XYZEval<T> operator+ (const XYZval<T> &rs) const { XYZEval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; ls.z += rs.z; return ls; } FI XYZEval<T> operator+ (const XYZval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z); return ls; }
FI XYZEval<T> operator+ (const XYZval<T> &rs) { XYZEval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; ls.z += rs.z; return ls; } FI XYZEval<T> operator+ (const XYZval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z); return ls; }
FI XYZEval<T> operator- (const XYZval<T> &rs) const { XYZEval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; ls.z -= rs.z; return ls; } FI XYZEval<T> operator- (const XYZval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z); return ls; }
FI XYZEval<T> operator- (const XYZval<T> &rs) { XYZEval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; ls.z -= rs.z; return ls; } FI XYZEval<T> operator- (const XYZval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z); return ls; }
FI XYZEval<T> operator* (const XYZval<T> &rs) const { XYZEval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; ls.z *= rs.z; return ls; } FI XYZEval<T> operator* (const XYZval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z); return ls; }
FI XYZEval<T> operator* (const XYZval<T> &rs) { XYZEval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; ls.z *= rs.z; return ls; } FI XYZEval<T> operator* (const XYZval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z); return ls; }
FI XYZEval<T> operator/ (const XYZval<T> &rs) const { XYZEval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; return ls; } FI XYZEval<T> operator/ (const XYZval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z); return ls; }
FI XYZEval<T> operator/ (const XYZval<T> &rs) { XYZEval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; return ls; } FI XYZEval<T> operator/ (const XYZval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z); return ls; }
FI XYZEval<T> operator+ (const XYZEval<T> &rs) const { XYZEval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; ls.z += rs.z; ls.e += rs.e; return ls; } FI XYZEval<T> operator+ (const XYZEval<T> &rs) const { XYZEval<T> 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<T> operator+ (const XYZEval<T> &rs) { XYZEval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; ls.z += rs.z; ls.e += rs.e; return ls; } FI XYZEval<T> operator+ (const XYZEval<T> &rs) { XYZEval<T> 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<T> operator- (const XYZEval<T> &rs) const { XYZEval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; ls.z -= rs.z; ls.e -= rs.e; return ls; } FI XYZEval<T> operator- (const XYZEval<T> &rs) const { XYZEval<T> 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<T> operator- (const XYZEval<T> &rs) { XYZEval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; ls.z -= rs.z; ls.e -= rs.e; return ls; } FI XYZEval<T> operator- (const XYZEval<T> &rs) { XYZEval<T> 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<T> operator* (const XYZEval<T> &rs) const { XYZEval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; ls.z *= rs.z; ls.e *= rs.e; return ls; } FI XYZEval<T> operator* (const XYZEval<T> &rs) const { XYZEval<T> 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<T> operator* (const XYZEval<T> &rs) { XYZEval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; ls.z *= rs.z; ls.e *= rs.e; return ls; } FI XYZEval<T> operator* (const XYZEval<T> &rs) { XYZEval<T> 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<T> operator/ (const XYZEval<T> &rs) const { XYZEval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; ls.e /= rs.e; return ls; } FI XYZEval<T> operator/ (const XYZEval<T> &rs) const { XYZEval<T> 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<T> operator/ (const XYZEval<T> &rs) { XYZEval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; ls.e /= rs.e; return ls; } FI XYZEval<T> operator/ (const XYZEval<T> &rs) { XYZEval<T> 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<T> operator* (const float &v) const { XYZEval<T> ls = *this; ls.x *= v; ls.y *= v; ls.z *= v; ls.e *= v; return ls; } FI XYZEval<T> operator* (const float &v) const { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e *= v, ls.x *= v, ls.y *= v, ls.z *= v ); return ls; }
FI XYZEval<T> operator* (const float &v) { XYZEval<T> ls = *this; ls.x *= v; ls.y *= v; ls.z *= v; ls.e *= v; return ls; } FI XYZEval<T> operator* (const float &v) { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e *= v, ls.x *= v, ls.y *= v, ls.z *= v ); return ls; }
FI XYZEval<T> operator* (const int &v) const { XYZEval<T> ls = *this; ls.x *= v; ls.y *= v; ls.z *= v; ls.e *= v; return ls; } FI XYZEval<T> operator* (const int &v) const { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e *= v, ls.x *= v, ls.y *= v, ls.z *= v ); return ls; }
FI XYZEval<T> operator* (const int &v) { XYZEval<T> ls = *this; ls.x *= v; ls.y *= v; ls.z *= v; ls.e *= v; return ls; } FI XYZEval<T> operator* (const int &v) { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e *= v, ls.x *= v, ls.y *= v, ls.z *= v ); return ls; }
FI XYZEval<T> operator/ (const float &v) const { XYZEval<T> ls = *this; ls.x /= v; ls.y /= v; ls.z /= v; ls.e /= v; return ls; } FI XYZEval<T> operator/ (const float &v) const { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e /= v, ls.x /= v, ls.y /= v, ls.z /= v ); return ls; }
FI XYZEval<T> operator/ (const float &v) { XYZEval<T> ls = *this; ls.x /= v; ls.y /= v; ls.z /= v; ls.e /= v; return ls; } FI XYZEval<T> operator/ (const float &v) { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e /= v, ls.x /= v, ls.y /= v, ls.z /= v ); return ls; }
FI XYZEval<T> operator/ (const int &v) const { XYZEval<T> ls = *this; ls.x /= v; ls.y /= v; ls.z /= v; ls.e /= v; return ls; } FI XYZEval<T> operator/ (const int &v) const { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e /= v, ls.x /= v, ls.y /= v, ls.z /= v ); return ls; }
FI XYZEval<T> operator/ (const int &v) { XYZEval<T> ls = *this; ls.x /= v; ls.y /= v; ls.z /= v; ls.e /= v; return ls; } FI XYZEval<T> operator/ (const int &v) { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e /= v, ls.x /= v, ls.y /= v, ls.z /= v ); return ls; }
FI XYZEval<T> operator>>(const int &v) const { XYZEval<T> ls = *this; _RS(ls.x); _RS(ls.y); _RS(ls.z); _RS(ls.e); return ls; } FI XYZEval<T> operator>>(const int &v) const { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(_RS(ls.e), _RS(ls.x), _RS(ls.y), _RS(ls.z) ); return ls; }
FI XYZEval<T> operator>>(const int &v) { XYZEval<T> ls = *this; _RS(ls.x); _RS(ls.y); _RS(ls.z); _RS(ls.e); return ls; } FI XYZEval<T> operator>>(const int &v) { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(_RS(ls.e), _RS(ls.x), _RS(ls.y), _RS(ls.z) ); return ls; }
FI XYZEval<T> operator<<(const int &v) const { XYZEval<T> ls = *this; _LS(ls.x); _LS(ls.y); _LS(ls.z); _LS(ls.e); return ls; } FI XYZEval<T> operator<<(const int &v) const { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(_LS(ls.e), _LS(ls.x), _LS(ls.y), _LS(ls.z) ); return ls; }
FI XYZEval<T> operator<<(const int &v) { XYZEval<T> ls = *this; _LS(ls.x); _LS(ls.y); _LS(ls.z); _LS(ls.e); return ls; } FI XYZEval<T> operator<<(const int &v) { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(_LS(ls.e), _LS(ls.x), _LS(ls.y), _LS(ls.z) ); return ls; }
FI XYZEval<T>& operator+=(const XYval<T> &rs) { x += rs.x; y += rs.y; return *this; } FI XYZEval<T>& operator+=(const XYval<T> &rs) { x += rs.x; y += rs.y; return *this; }
FI XYZEval<T>& operator-=(const XYval<T> &rs) { x -= rs.x; y -= rs.y; return *this; } FI XYZEval<T>& operator-=(const XYval<T> &rs) { x -= rs.x; y -= rs.y; return *this; }
FI XYZEval<T>& operator*=(const XYval<T> &rs) { x *= rs.x; y *= rs.y; return *this; } FI XYZEval<T>& operator*=(const XYval<T> &rs) { x *= rs.x; y *= rs.y; return *this; }
FI XYZEval<T>& operator/=(const XYval<T> &rs) { x /= rs.x; y /= rs.y; return *this; } FI XYZEval<T>& operator/=(const XYval<T> &rs) { x /= rs.x; y /= rs.y; return *this; }
FI XYZEval<T>& operator+=(const XYZval<T> &rs) { x += rs.x; y += rs.y; z += rs.z; return *this; } FI XYZEval<T>& operator+=(const XYZval<T> &rs) { LINEAR_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z); return *this; }
FI XYZEval<T>& operator-=(const XYZval<T> &rs) { x -= rs.x; y -= rs.y; z -= rs.z; return *this; } FI XYZEval<T>& operator-=(const XYZval<T> &rs) { LINEAR_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z); return *this; }
FI XYZEval<T>& operator*=(const XYZval<T> &rs) { x *= rs.x; y *= rs.y; z *= rs.z; return *this; } FI XYZEval<T>& operator*=(const XYZval<T> &rs) { LINEAR_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z); return *this; }
FI XYZEval<T>& operator/=(const XYZval<T> &rs) { x /= rs.x; y /= rs.y; z /= rs.z; return *this; } FI XYZEval<T>& operator/=(const XYZval<T> &rs) { LINEAR_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z); return *this; }
FI XYZEval<T>& operator+=(const XYZEval<T> &rs) { x += rs.x; y += rs.y; z += rs.z; e += rs.e; return *this; } FI XYZEval<T>& operator+=(const XYZEval<T> &rs) { LOGICAL_AXIS_CODE(e += rs.e, x += rs.x, y += rs.y, z += rs.z); return *this; }
FI XYZEval<T>& operator-=(const XYZEval<T> &rs) { x -= rs.x; y -= rs.y; z -= rs.z; e -= rs.e; return *this; } FI XYZEval<T>& operator-=(const XYZEval<T> &rs) { LOGICAL_AXIS_CODE(e -= rs.e, x -= rs.x, y -= rs.y, z -= rs.z); return *this; }
FI XYZEval<T>& operator*=(const XYZEval<T> &rs) { x *= rs.x; y *= rs.y; z *= rs.z; e *= rs.e; return *this; } FI XYZEval<T>& operator*=(const XYZEval<T> &rs) { LOGICAL_AXIS_CODE(e *= rs.e, x *= rs.x, y *= rs.y, z *= rs.z); return *this; }
FI XYZEval<T>& operator/=(const XYZEval<T> &rs) { x /= rs.x; y /= rs.y; z /= rs.z; e /= rs.e; return *this; } FI XYZEval<T>& operator/=(const XYZEval<T> &rs) { LOGICAL_AXIS_CODE(e /= rs.e, x /= rs.x, y /= rs.y, z /= rs.z); return *this; }
FI XYZEval<T>& operator*=(const T &v) { x *= v; y *= v; z *= v; e *= v; return *this; } FI XYZEval<T>& operator*=(const T &v) { LOGICAL_AXIS_CODE(e *= v, x *= v, y *= v, z *= v); return *this; }
FI XYZEval<T>& operator>>=(const int &v) { _RS(x); _RS(y); _RS(z); _RS(e); return *this; } FI XYZEval<T>& operator>>=(const int &v) { LOGICAL_AXIS_CODE(_RS(e), _RS(x), _RS(y), _RS(z)); return *this; }
FI XYZEval<T>& operator<<=(const int &v) { _LS(x); _LS(y); _LS(z); _LS(e); return *this; } FI XYZEval<T>& operator<<=(const int &v) { LOGICAL_AXIS_CODE(_LS(e), _LS(x), _LS(y), _LS(z)); return *this; }
FI bool operator==(const XYZval<T> &rs) { return x == rs.x && y == rs.y && z == rs.z; } FI bool operator==(const XYZval<T> &rs) { return true LINEAR_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z); }
FI bool operator==(const XYZval<T> &rs) const { return true LINEAR_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z); }
FI bool operator!=(const XYZval<T> &rs) { return !operator==(rs); } FI bool operator!=(const XYZval<T> &rs) { return !operator==(rs); }
FI bool operator==(const XYZval<T> &rs) const { return x == rs.x && y == rs.y && z == rs.z; }
FI bool operator!=(const XYZval<T> &rs) const { return !operator==(rs); } FI bool operator!=(const XYZval<T> &rs) const { return !operator==(rs); }
FI XYZEval<T> operator-() { return { -x, -y, -z, -e }; } FI XYZEval<T> operator-() { return LOGICAL_AXIS_ARRAY(-e, -x, -y, -z); }
FI const XYZEval<T> operator-() const { return { -x, -y, -z, -e }; } FI const XYZEval<T> operator-() const { return LOGICAL_AXIS_ARRAY(-e, -x, -y, -z); }
}; };
#undef _RECIP #undef _RECIP
@ -514,6 +573,3 @@ struct XYZEval {
#undef _LS #undef _LS
#undef _RS #undef _RS
#undef FI #undef FI
const xyze_char_t axis_codes { 'X', 'Y', 'Z', 'E' };
#define AXIS_CHAR(A) ((char)('X' + A))

@ -76,3 +76,11 @@ public:
// Converts from an uint8_t in the range of 0-255 to an uint8_t // Converts from an uint8_t in the range of 0-255 to an uint8_t
// in the range 0-100 while avoiding rounding artifacts // 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; } 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

@ -327,7 +327,7 @@ int32_t I2CPositionEncoder::get_raw_count() {
} }
bool I2CPositionEncoder::test_axis() { 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; if (!(encoderAxis == X_AXIS || encoderAxis == Y_AXIS || encoderAxis == Z_AXIS)) return false;
const float startPosition = soft_endstop.min[encoderAxis] + 10, const float startPosition = soft_endstop.min[encoderAxis] + 10,
@ -345,9 +345,12 @@ bool I2CPositionEncoder::test_axis() {
endCoord[encoderAxis] = endPosition; endCoord[encoderAxis] = endPosition;
planner.synchronize(); planner.synchronize();
startCoord.e = planner.get_axis_position_mm(E_AXIS);
planner.buffer_line(startCoord, fr_mm_s, 0); #if HAS_EXTRUDERS
planner.synchronize(); 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 the module isn't currently trusted, wait until it is (or until it should be if things are working)
if (!trusted) { if (!trusted) {
@ -357,7 +360,7 @@ bool I2CPositionEncoder::test_axis() {
} }
if (trusted) { // if trusted, commence test 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.buffer_line(endCoord, fr_mm_s, 0);
planner.synchronize(); planner.synchronize();
} }
@ -402,7 +405,7 @@ void I2CPositionEncoder::calibrate_steps_mm(const uint8_t iter) {
planner.synchronize(); planner.synchronize();
LOOP_L_N(i, iter) { 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.buffer_line(startCoord, fr_mm_s, 0);
planner.synchronize(); planner.synchronize();
@ -411,7 +414,7 @@ void I2CPositionEncoder::calibrate_steps_mm(const uint8_t iter) {
//do_blocking_move_to(endCoord); //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.buffer_line(endCoord, fr_mm_s, 0);
planner.synchronize(); planner.synchronize();
@ -497,9 +500,7 @@ void I2CPositionEncodersMgr::init() {
encoders[i].set_active(encoders[i].passes_test(true)); encoders[i].set_active(encoders[i].passes_test(true));
#if I2CPE_ENC_1_AXIS == E_AXIS TERN_(HAS_EXTRUDERS, if (I2CPE_ENC_1_AXIS == E_AXIS) encoders[i].set_homed());
encoders[i].set_homed();
#endif
#endif #endif
#if I2CPE_ENCODER_CNT > 1 #if I2CPE_ENCODER_CNT > 1
@ -528,9 +529,7 @@ void I2CPositionEncodersMgr::init() {
encoders[i].set_active(encoders[i].passes_test(true)); encoders[i].set_active(encoders[i].passes_test(true));
#if I2CPE_ENC_2_AXIS == E_AXIS TERN_(HAS_EXTRUDERS, if (I2CPE_ENC_2_AXIS == E_AXIS) encoders[i].set_homed());
encoders[i].set_homed();
#endif
#endif #endif
#if I2CPE_ENCODER_CNT > 2 #if I2CPE_ENCODER_CNT > 2
@ -557,11 +556,9 @@ void I2CPositionEncodersMgr::init() {
encoders[i].set_ec_threshold(I2CPE_ENC_3_EC_THRESH); encoders[i].set_ec_threshold(I2CPE_ENC_3_EC_THRESH);
#endif #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 TERN_(HAS_EXTRUDERS, if (I2CPE_ENC_3_AXIS == E_AXIS) encoders[i].set_homed());
encoders[i].set_homed();
#endif
#endif #endif
#if I2CPE_ENCODER_CNT > 3 #if I2CPE_ENCODER_CNT > 3
@ -590,9 +587,7 @@ void I2CPositionEncodersMgr::init() {
encoders[i].set_active(encoders[i].passes_test(true)); encoders[i].set_active(encoders[i].passes_test(true));
#if I2CPE_ENC_4_AXIS == E_AXIS TERN_(HAS_EXTRUDERS, if (I2CPE_ENC_4_AXIS == E_AXIS) encoders[i].set_homed());
encoders[i].set_homed();
#endif
#endif #endif
#if I2CPE_ENCODER_CNT > 4 #if I2CPE_ENCODER_CNT > 4
@ -621,9 +616,7 @@ void I2CPositionEncodersMgr::init() {
encoders[i].set_active(encoders[i].passes_test(true)); encoders[i].set_active(encoders[i].passes_test(true));
#if I2CPE_ENC_5_AXIS == E_AXIS TERN_(HAS_EXTRUDERS, if (I2CPE_ENC_5_AXIS == E_AXIS) encoders[i].set_homed());
encoders[i].set_homed();
#endif
#endif #endif
#if I2CPE_ENCODER_CNT > 5 #if I2CPE_ENCODER_CNT > 5
@ -652,9 +645,7 @@ void I2CPositionEncodersMgr::init() {
encoders[i].set_active(encoders[i].passes_test(true)); encoders[i].set_active(encoders[i].passes_test(true));
#if I2CPE_ENC_6_AXIS == E_AXIS TERN_(HAS_EXTRUDERS, if (I2CPE_ENC_6_AXIS == E_AXIS) encoders[i].set_homed());
encoders[i].set_homed();
#endif
#endif #endif
} }

@ -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 (print_x) {
#if AXIS_IS_TMC(X) #if AXIS_IS_TMC(X)
tmc_status(stepperX, i); tmc_status(stepperX, i);
@ -821,7 +824,10 @@
SERIAL_EOL(); 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 (print_x) {
#if AXIS_IS_TMC(X) #if AXIS_IS_TMC(X)
tmc_parse_drv_status(stepperX, i); tmc_parse_drv_status(stepperX, i);
@ -889,9 +895,12 @@
* M122 report functions * 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*/) { void tmc_report_all(
#define TMC_REPORT(LABEL, ITEM) do{ SERIAL_ECHOPGM(LABEL); tmc_debug_loop(ITEM, print_x, print_y, print_z, print_e); }while(0) LOGICAL_AXIS_LIST(const bool print_e/*=true*/, const bool print_x/*=true*/, const bool print_y/*=true*/, const bool print_z/*=true*/)
#define DRV_REPORT(LABEL, ITEM) do{ SERIAL_ECHOPGM(LABEL); drv_status_loop(ITEM, print_x, print_y, print_z, print_e); }while(0) ) {
#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); TMC_REPORT("\t", TMC_CODES);
#if HAS_DRIVER(TMC2209) #if HAS_DRIVER(TMC2209)
TMC_REPORT("Address\t", TMC_UART_ADDR); TMC_REPORT("Address\t", TMC_UART_ADDR);
@ -1015,7 +1024,10 @@
} }
#endif #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 (print_x) {
#if AXIS_IS_TMC(X) #if AXIS_IS_TMC(X)
tmc_get_registers(stepperX, i); tmc_get_registers(stepperX, i);
@ -1079,8 +1091,10 @@
SERIAL_EOL(); SERIAL_EOL();
} }
void tmc_get_registers(bool print_x, bool print_y, bool print_z, bool print_e) { void tmc_get_registers(
#define _TMC_GET_REG(LABEL, ITEM) do{ SERIAL_ECHOPGM(LABEL); tmc_get_registers(ITEM, print_x, print_y, print_z, print_e); }while(0) 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) #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("\t", TMC_AXIS_CODES);
TMC_GET_REG(GCONF, "\t\t"); TMC_GET_REG(GCONF, "\t\t");
@ -1214,7 +1228,9 @@ static bool test_connection(TMC &st) {
return test_result; 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; uint8_t axis_connection = 0;
if (test_x) { if (test_x) {

@ -335,14 +335,20 @@ void tmc_print_current(TMC &st) {
#endif #endif
void monitor_tmc_drivers(); 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(TMC_DEBUG)
#if ENABLED(MONITOR_DRIVER_STATUS) #if ENABLED(MONITOR_DRIVER_STATUS)
void tmc_set_report_interval(const uint16_t update_interval); void tmc_set_report_interval(const uint16_t update_interval);
#endif #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_report_all(
void tmc_get_registers(const bool print_x, const bool print_y, const bool print_z, const bool print_e); 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 #endif
/** /**
@ -355,7 +361,7 @@ void test_tmc_connection(const bool test_x=true, const bool test_y=true, const b
#if USE_SENSORLESS #if USE_SENSORLESS
// Track enabled status of stealthChop and only re-enable where applicable // 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) #if ENABLED(IMPROVE_HOMING_RELIABILITY)
extern millis_t sg_guard_period; extern millis_t sg_guard_period;

@ -321,12 +321,23 @@ void GcodeSuite::G28() {
#else #else
#define _UNSAFE(A) (homeZ && TERN0(Z_SAFE_HOMING, axes_should_home(_BV(A##_AXIS))))
const bool homeZ = parser.seen_test('Z'), const bool homeZ = parser.seen_test('Z'),
needX = homeZ && TERN0(Z_SAFE_HOMING, axes_should_home(_BV(X_AXIS))), LINEAR_AXIS_LIST( // Other axes should be homed before Z safe-homing
needY = homeZ && TERN0(Z_SAFE_HOMING, axes_should_home(_BV(Y_AXIS))), needX = _UNSAFE(X), needY = _UNSAFE(Y), needZ = false // UNUSED
homeX = needX || parser.seen_test('X'), homeY = needY || parser.seen_test('Y'), ),
home_all = homeX == homeY && homeX == homeZ, // All or None LINEAR_AXIS_LIST( // Home each axis if needed or flagged
doX = home_all || homeX, doY = home_all || homeY, doZ = home_all || homeZ; 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) #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; 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) // 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); if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("Raise Z (before homing) by ", z_homing_height);
do_z_clearance(z_homing_height); do_z_clearance(z_homing_height);
@ -469,7 +480,7 @@ void GcodeSuite::G28() {
#if HAS_CURRENT_HOME(Y2) #if HAS_CURRENT_HOME(Y2)
stepperY2.rms_current(tmc_save_current_Y2); stepperY2.rms_current(tmc_save_current_Y2);
#endif #endif
#endif #endif // HAS_HOMING_CURRENT
ui.refresh(); ui.refresh();
@ -490,7 +501,7 @@ void GcodeSuite::G28() {
static constexpr AxisEnum L64XX_axis_xref[MAX_L64XX] = { static constexpr AxisEnum L64XX_axis_xref[MAX_L64XX] = {
X_AXIS, Y_AXIS, Z_AXIS, X_AXIS, Y_AXIS, Z_AXIS,
X_AXIS, Y_AXIS, Z_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++) { for (uint8_t j = 1; j <= L64XX::chain[0]; j++) {
const uint8_t cv = L64XX::chain[j]; const uint8_t cv = L64XX::chain[j];

@ -307,9 +307,11 @@ inline void probe_sides(measurements_t &m, const float uncertainty) {
// The difference between the known and the measured location // The difference between the known and the measured location
// of the calibration object is the positional error // of the calibration object is the positional error
m.pos_error.x = TERN0(HAS_X_CENTER, true_center.x - m.obj_center.x); LINEAR_AXIS_CODE(
m.pos_error.y = TERN0(HAS_Y_CENTER, true_center.y - m.obj_center.y); m.pos_error.x = TERN0(HAS_X_CENTER, true_center.x - m.obj_center.x),
m.pos_error.z = true_center.z - m.obj_center.z; 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) #if ENABLED(CALIBRATION_REPORTING)
@ -455,7 +457,9 @@ inline void calibrate_backlash(measurements_t &m, const float uncertainty) {
// New scope for TEMPORARY_BACKLASH_CORRECTION // New scope for TEMPORARY_BACKLASH_CORRECTION
TEMPORARY_BACKLASH_CORRECTION(all_on); TEMPORARY_BACKLASH_CORRECTION(all_on);
TEMPORARY_BACKLASH_SMOOTHING(0.0f); 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();
current_position -= move; calibration_move(); current_position -= move; calibration_move();
} }

@ -48,10 +48,12 @@ void GcodeSuite::M425() {
auto axis_can_calibrate = [](const uint8_t a) { auto axis_can_calibrate = [](const uint8_t a) {
switch (a) { switch (a) {
default: default: return false;
case X_AXIS: return AXIS_CAN_CALIBRATE(X); LINEAR_AXIS_CODE(
case Y_AXIS: return AXIS_CAN_CALIBRATE(Y); case X_AXIS: return AXIS_CAN_CALIBRATE(X),
case Z_AXIS: return AXIS_CAN_CALIBRATE(Z); case Y_AXIS: return AXIS_CAN_CALIBRATE(Y),
case Z_AXIS: return AXIS_CAN_CALIBRATE(Z)
);
} }
}; };

@ -88,7 +88,7 @@ void GcodeSuite::M201() {
LOOP_LOGICAL_AXES(i) { LOOP_LOGICAL_AXES(i) {
if (parser.seenval(axis_codes[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)); planner.set_max_acceleration(a, parser.value_axis_units((AxisEnum)a));
} }
} }
@ -106,7 +106,7 @@ void GcodeSuite::M203() {
LOOP_LOGICAL_AXES(i) LOOP_LOGICAL_AXES(i)
if (parser.seenval(axis_codes[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)); planner.set_max_feedrate(a, parser.value_axis_units((AxisEnum)a));
} }
} }
@ -165,17 +165,16 @@ void GcodeSuite::M205() {
} }
#endif #endif
#if HAS_CLASSIC_JERK #if HAS_CLASSIC_JERK
if (parser.seenval('X')) planner.set_max_jerk(X_AXIS, parser.value_linear_units()); bool seenZ = false;
if (parser.seenval('Y')) planner.set_max_jerk(Y_AXIS, parser.value_linear_units()); LOGICAL_AXIS_CODE(
if (parser.seenval('Z')) { if (parser.seenval('E')) planner.set_max_jerk(E_AXIS, parser.value_linear_units()),
planner.set_max_jerk(Z_AXIS, parser.value_linear_units()); if (parser.seenval('X')) planner.set_max_jerk(X_AXIS, parser.value_linear_units()),
#if HAS_MESH && DISABLED(LIMITED_JERK_EDITING) if (parser.seenval('Y')) planner.set_max_jerk(Y_AXIS, parser.value_linear_units()),
if (planner.max_jerk.z <= 0.1f) if ((seenZ = parser.seenval('Z'))) planner.set_max_jerk(Z_AXIS, parser.value_linear_units())
SERIAL_ECHOLNPGM("WARNING! Low Z Jerk may lead to unwanted pauses."); );
#endif #if HAS_MESH && DISABLED(LIMITED_JERK_EDITING)
} if (seenZ && planner.max_jerk.z <= 0.1f)
#if HAS_CLASSIC_E_JERK SERIAL_ECHOLNPGM("WARNING! Low Z Jerk may lead to unwanted pauses.");
if (parser.seenval('E')) planner.set_max_jerk(E_AXIS, parser.value_linear_units());
#endif #endif
#endif #endif // HAS_CLASSIC_JERK
} }

@ -25,10 +25,12 @@
void report_M92(const bool echo=true, const int8_t e=-1) { void report_M92(const bool echo=true, const int8_t e=-1) {
if (echo) SERIAL_ECHO_START(); else SERIAL_CHAR(' '); if (echo) SERIAL_ECHO_START(); else SERIAL_CHAR(' ');
SERIAL_ECHOPAIR_P(PSTR(" M92 X"), LINEAR_UNIT(planner.settings.axis_steps_per_mm[X_AXIS]), SERIAL_ECHOPAIR_P(LIST_N(DOUBLE(LINEAR_AXES),
SP_Y_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[Y_AXIS]), PSTR(" M92 X"), LINEAR_UNIT(planner.settings.axis_steps_per_mm[X_AXIS]),
SP_Z_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[Z_AXIS])); SP_Y_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[Y_AXIS]),
#if DISABLED(DISTINCT_E_FACTORS) 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])); SERIAL_ECHOPAIR_P(SP_E_STR, VOLUMETRIC_UNIT(planner.settings.axis_steps_per_mm[E_AXIS]));
#endif #endif
SERIAL_EOL(); SERIAL_EOL();
@ -64,25 +66,28 @@ void GcodeSuite::M92() {
if (target_extruder < 0) return; if (target_extruder < 0) return;
// No arguments? Show M92 report. // No arguments? Show M92 report.
if (!parser.seen("XYZE" TERN_(MAGIC_NUMBERS_GCODE, "HL"))) if (!parser.seen(
return report_M92(true, target_extruder); LOGICAL_AXIS_GANG("E", "X", "Y", "Z")
TERN_(MAGIC_NUMBERS_GCODE, "HL")
)) return report_M92(true, target_extruder);
LOOP_LOGICAL_AXES(i) { LOOP_LOGICAL_AXES(i) {
if (parser.seenval(axis_codes[i])) { if (parser.seenval(axis_codes[i])) {
if (i == E_AXIS) { if (TERN1(HAS_EXTRUDERS, 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 {
planner.settings.axis_steps_per_mm[i] = parser.value_per_axis_units((AxisEnum)i); 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
} }
} }
} }

@ -33,11 +33,13 @@
* M17: Enable stepper motors * M17: Enable stepper motors
*/ */
void GcodeSuite::M17() { void GcodeSuite::M17() {
if (parser.seen("XYZE")) { if (parser.seen(LOGICAL_AXIS_GANG("E", "X", "Y", "Z"))) {
if (parser.seen_test('X')) ENABLE_AXIS_X(); LOGICAL_AXIS_CODE(
if (parser.seen_test('Y')) ENABLE_AXIS_Y(); if (TERN0(HAS_E_STEPPER_ENABLE, parser.seen_test('E'))) enable_e_steppers(),
if (parser.seen_test('Z')) ENABLE_AXIS_Z(); if (parser.seen_test('X')) ENABLE_AXIS_X(),
if (TERN0(HAS_E_STEPPER_ENABLE, parser.seen_test('E'))) enable_e_steppers(); if (parser.seen_test('Y')) ENABLE_AXIS_Y(),
if (parser.seen_test('Z')) ENABLE_AXIS_Z()
);
} }
else { else {
LCD_MESSAGEPGM(MSG_NO_MOVE); LCD_MESSAGEPGM(MSG_NO_MOVE);
@ -54,12 +56,14 @@ void GcodeSuite::M18_M84() {
stepper_inactive_time = parser.value_millis_from_seconds(); stepper_inactive_time = parser.value_millis_from_seconds();
} }
else { else {
if (parser.seen("XYZE")) { if (parser.seen(LOGICAL_AXIS_GANG("E", "X", "Y", "Z"))) {
planner.synchronize(); planner.synchronize();
if (parser.seen_test('X')) DISABLE_AXIS_X(); LOGICAL_AXIS_CODE(
if (parser.seen_test('Y')) DISABLE_AXIS_Y(); if (TERN0(HAS_E_STEPPER_ENABLE, parser.seen_test('E'))) disable_e_steppers(),
if (parser.seen_test('Z')) DISABLE_AXIS_Z(); if (parser.seen_test('X')) DISABLE_AXIS_X(),
if (TERN0(HAS_E_STEPPER_ENABLE, parser.seen_test('E'))) disable_e_steppers(); if (parser.seen_test('Y')) DISABLE_AXIS_Y(),
if (parser.seen_test('Z')) DISABLE_AXIS_Z()
);
} }
else else
planner.finish_and_disable(); planner.finish_and_disable();

@ -68,7 +68,7 @@ void GcodeSuite::G61(void) {
SYNC_E(stored_position[slot].e); SYNC_E(stored_position[slot].e);
} }
else { else {
if (parser.seen("XYZ")) { if (parser.seen(LINEAR_AXIS_GANG("X", "Y", "Z"))) {
DEBUG_ECHOPAIR(STR_RESTORING_POS " S", slot); DEBUG_ECHOPAIR(STR_RESTORING_POS " S", slot);
LOOP_LINEAR_AXES(i) { LOOP_LINEAR_AXES(i) {
destination[i] = parser.seen(AXIS_CHAR(i)) destination[i] = parser.seen(AXIS_CHAR(i))
@ -81,10 +81,12 @@ void GcodeSuite::G61(void) {
// Move to the saved position // Move to the saved position
prepare_line_to_destination(); prepare_line_to_destination();
} }
if (parser.seen_test('E')) { #if HAS_EXTRUDERS
DEBUG_ECHOLNPAIR(STR_RESTORING_POS " S", slot, " E", current_position.e, "=>", stored_position[slot].e); if (parser.seen_test('E')) {
SYNC_E(stored_position[slot].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; feedrate_mm_s = saved_feedrate;

@ -49,13 +49,21 @@ void GcodeSuite::M122() {
tmc_set_report_interval(interval); tmc_set_report_interval(interval);
#endif #endif
if (parser.seen_test('V')) if (parser.seen_test('V')) {
tmc_get_registers(print_axis.x, print_axis.y, print_axis.z, print_axis.e); tmc_get_registers(
else LOGICAL_AXIS_LIST(print_axis.e, print_axis.x, print_axis.y, print_axis.z)
tmc_report_all(print_axis.x, print_axis.y, print_axis.z, print_axis.e); );
}
else {
tmc_report_all(
LOGICAL_AXIS_LIST(print_axis.e, print_axis.x, print_axis.y, print_axis.z)
);
}
#endif #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 #endif // HAS_TRINAMIC_CONFIG

@ -74,11 +74,11 @@ millis_t GcodeSuite::previous_move_ms = 0,
// Relative motion mode for each logical axis // Relative motion mode for each logical axis
static constexpr xyze_bool_t ar_init = AXIS_RELATIVE_MODES; static constexpr xyze_bool_t ar_init = AXIS_RELATIVE_MODES;
uint8_t GcodeSuite::axis_relative = ( uint8_t GcodeSuite::axis_relative = 0 LOGICAL_AXIS_GANG(
(ar_init.x ? _BV(REL_X) : 0) | (ar_init.e << REL_E),
| (ar_init.y ? _BV(REL_Y) : 0) | (ar_init.x << REL_X),
| (ar_init.z ? _BV(REL_Z) : 0) | (ar_init.y << REL_Y),
| (ar_init.e ? _BV(REL_E) : 0) | (ar_init.z << REL_Z)
); );
#if EITHER(HAS_AUTO_REPORTING, HOST_KEEPALIVE_FEATURE) #if EITHER(HAS_AUTO_REPORTING, HOST_KEEPALIVE_FEATURE)
@ -161,13 +161,15 @@ void GcodeSuite::get_destination_from_command() {
destination[i] = current_position[i]; destination[i] = current_position[i];
} }
// Get new E position, whether absolute or relative #if HAS_EXTRUDERS
if ( (seen.e = parser.seenval('E')) ) { // Get new E position, whether absolute or relative
const float v = parser.value_axis_units(E_AXIS); if ( (seen.e = parser.seenval('E')) ) {
destination.e = axis_is_relative(E_AXIS) ? current_position.e + v : v; 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; else
destination.e = current_position.e;
#endif
#if ENABLED(POWER_LOSS_RECOVERY) && !PIN_EXISTS(POWER_LOSS) #if ENABLED(POWER_LOSS_RECOVERY) && !PIN_EXISTS(POWER_LOSS)
// Only update power loss recovery on moves with E // Only update power loss recovery on moves with E

@ -314,7 +314,12 @@
#define HAS_FAST_MOVES 1 #define HAS_FAST_MOVES 1
#endif #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[]; extern const char G28_STR[];
@ -324,23 +329,27 @@ public:
static uint8_t axis_relative; static uint8_t axis_relative;
static inline bool axis_is_relative(const AxisEnum a) { static inline bool axis_is_relative(const AxisEnum a) {
if (a == E_AXIS) { #if HAS_EXTRUDERS
if (TEST(axis_relative, E_MODE_REL)) return true; if (a == E_AXIS) {
if (TEST(axis_relative, E_MODE_ABS)) return false; if (TEST(axis_relative, E_MODE_REL)) return true;
} if (TEST(axis_relative, E_MODE_ABS)) return false;
}
#endif
return TEST(axis_relative, a); return TEST(axis_relative, a);
} }
static inline void set_relative_mode(const bool rel) { 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; axis_relative = rel ? (0 LOGICAL_AXIS_GANG(| _BV(REL_E), | _BV(REL_X), | _BV(REL_Y), | _BV(REL_Z))) : 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);
} }
#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) #if ENABLED(CNC_WORKSPACE_PLANES)
/** /**

@ -48,7 +48,10 @@
*/ */
void GcodeSuite::G92() { 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 #if USE_GCODE_SUBCODES
const uint8_t subcode_G92 = parser.subcode; 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) case 9: // G92.9 - Set Current Position directly (like Marlin 1.0)
LOOP_LOGICAL_AXES(i) { LOOP_LOGICAL_AXES(i) {
if (parser.seenval(axis_codes[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); current_position[i] = parser.value_axis_units((AxisEnum)i);
} }
} }
@ -83,20 +90,26 @@ void GcodeSuite::G92() {
LOOP_LOGICAL_AXES(i) { LOOP_LOGICAL_AXES(i) {
if (parser.seenval(axis_codes[i])) { if (parser.seenval(axis_codes[i])) {
const float l = parser.value_axis_units((AxisEnum)i), // Given axis coordinate value, converted to millimeters 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? d = v - current_position[i]; // How much is the current axis position altered by?
if (!NEAR_ZERO(d)) { if (!NEAR_ZERO(d)) {
#if HAS_POSITION_SHIFT && !IS_SCARA // When using workspaces... #if HAS_POSITION_SHIFT && !IS_SCARA // When using workspaces...
if (i == E_AXIS) { if (TERN1(HAS_EXTRUDERS, i != E_AXIS)) {
sync_E = true; position_shift[i] += d; // ...most axes offset the workspace...
current_position.e = v; // ...E is still set directly
}
else {
position_shift[i] += d; // ...but other axes offset the workspace.
update_workspace_offset((AxisEnum)i); update_workspace_offset((AxisEnum)i);
} }
else {
#if HAS_EXTRUDERS
sync_E = true;
current_position.e = v; // ...but E is set directly
#endif
}
#else // Without workspaces... #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) current_position[i] = v; // ...set Current Position directly (like Marlin 1.0)
#endif #endif
} }
@ -111,8 +124,10 @@ void GcodeSuite::G92() {
coordinate_system[active_coordinate_system] = position_shift; coordinate_system[active_coordinate_system] = position_shift;
#endif #endif
if (sync_XYZE) sync_plan_position(); if (sync_XYZE) sync_plan_position();
else if (sync_E) sync_plan_position_e(); #if HAS_EXTRUDERS
else if (sync_E) sync_plan_position_e();
#endif
IF_DISABLED(DIRECT_STEPPING, report_current_position()); IF_DISABLED(DIRECT_STEPPING, report_current_position());
} }

@ -170,7 +170,7 @@
SERIAL_ECHOPGM("FromStp:"); SERIAL_ECHOPGM("FromStp:");
get_cartesian_from_steppers(); // writes 'cartes' (with forward kinematics) 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); report_all_axis_pos(from_steppers);
const xyze_float_t diff = from_steppers - leveled; const xyze_float_t diff = from_steppers - leveled;

@ -49,9 +49,11 @@ void GcodeSuite::G0_G1(TERN_(HAS_FAST_MOVES, const bool fast_move/*=false*/)) {
if (IsRunning() if (IsRunning()
#if ENABLED(NO_MOTION_BEFORE_HOMING) #if ENABLED(NO_MOTION_BEFORE_HOMING)
&& !homing_needed_error( && !homing_needed_error(
(parser.seen_test('X') ? _BV(X_AXIS) : 0) LINEAR_AXIS_GANG(
| (parser.seen_test('Y') ? _BV(Y_AXIS) : 0) (parser.seen_test('X') ? _BV(X_AXIS) : 0),
| (parser.seen_test('Z') ? _BV(Z_AXIS) : 0) ) | (parser.seen_test('Y') ? _BV(Y_AXIS) : 0),
| (parser.seen_test('Z') ? _BV(Z_AXIS) : 0))
)
#endif #endif
) { ) {
TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_RUNNING)); 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) { if (MIN_AUTORETRACT <= MAX_AUTORETRACT) {
// When M209 Autoretract is enabled, convert E-only moves to firmware retract/recover moves // 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; const float echange = destination.e - current_position.e;
// Is this a retract or recover move? // Is this a retract or recover move?
if (WITHIN(ABS(echange), MIN_AUTORETRACT, MAX_AUTORETRACT) && fwretract.retracted[active_extruder] == (echange > 0.0)) { if (WITHIN(ABS(echange), MIN_AUTORETRACT, MAX_AUTORETRACT) && fwretract.retracted[active_extruder] == (echange > 0.0)) {

@ -109,23 +109,32 @@ void plan_arc(
#endif #endif
} }
float linear_travel = cart[l_axis] - start_L, float linear_travel = cart[l_axis] - start_L;
extruder_travel = cart.e - current_position.e;
#if HAS_EXTRUDERS
float extruder_travel = cart.e - current_position.e;
#endif
// If circling around... // If circling around...
if (ENABLED(ARC_P_CIRCLES) && circles) { if (ENABLED(ARC_P_CIRCLES) && circles) {
const float total_angular = angular_travel + circles * RADIANS(360), // Total rotation with all circles and remainder 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 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 l_per_circle = linear_travel * part_per_circle; // L movement per circle
e_per_circle = extruder_travel * part_per_circle; // E 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 xyze_pos_t temp_position = current_position; // for plan_arc to compare to current_position
for (uint16_t n = circles; n--;) { 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 temp_position[l_axis] += l_per_circle; // Destination L axis
plan_arc(temp_position, offset, clockwise, 0); // Plan a single whole circle plan_arc(temp_position, offset, clockwise, 0); // Plan a single whole circle
} }
linear_travel = cart[l_axis] - current_position[l_axis]; 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, const float flat_mm = radius * angular_travel,
@ -179,16 +188,19 @@ void plan_arc(
xyze_pos_t raw; xyze_pos_t raw;
const float theta_per_segment = angular_travel / segments, const float theta_per_segment = angular_travel / segments,
linear_per_segment = linear_travel / segments, linear_per_segment = linear_travel / segments,
extruder_per_segment = extruder_travel / segments,
sq_theta_per_segment = sq(theta_per_segment), sq_theta_per_segment = sq(theta_per_segment),
sin_T = theta_per_segment - sq_theta_per_segment * theta_per_segment / 6, 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 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 // Initialize the linear axis
raw[l_axis] = current_position[l_axis]; raw[l_axis] = current_position[l_axis];
// Initialize the extruder axis // Initialize the extruder axis
raw.e = current_position.e; TERN_(HAS_EXTRUDERS, raw.e = current_position.e);
#if ENABLED(SCARA_FEEDRATE_SCALING) #if ENABLED(SCARA_FEEDRATE_SCALING)
const float inv_duration = scaled_fr_mm_s / seg_length; const float inv_duration = scaled_fr_mm_s / seg_length;
@ -240,7 +252,8 @@ void plan_arc(
#else #else
raw[l_axis] += linear_per_segment; raw[l_axis] += linear_per_segment;
#endif #endif
raw.e += extruder_per_segment;
TERN_(HAS_EXTRUDERS, raw.e += extruder_per_segment);
apply_motion_limits(raw); apply_motion_limits(raw);

@ -87,7 +87,7 @@ void GcodeSuite::M290() {
} }
#endif #endif
if (!parser.seen("XYZ") || parser.seen('R')) { if (!parser.seen(LINEAR_AXIS_GANG("X", "Y", "Z")) || parser.seen('R')) {
SERIAL_ECHO_START(); SERIAL_ECHO_START();
#if ENABLED(BABYSTEP_ZPROBE_OFFSET) #if ENABLED(BABYSTEP_ZPROBE_OFFSET)

@ -248,7 +248,8 @@ void GCodeParser::parse(char *p) {
case 'R': if (!WITHIN(motion_mode_codenum, 2, 3)) return; case 'R': if (!WITHIN(motion_mode_codenum, 2, 3)) return;
#endif #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; if (motion_mode_codenum < 0) return;
command_letter = 'G'; command_letter = 'G';
codenum = motion_mode_codenum; codenum = motion_mode_codenum;

@ -226,7 +226,7 @@ public:
// Seen any axis parameter // Seen any axis parameter
static inline bool seen_axis() { static inline bool seen_axis() {
return seen("XYZE"); return seen(LOGICAL_AXIS_GANG("E", "X", "Y", "Z"));
} }
#if ENABLED(GCODE_QUOTED_STRINGS) #if ENABLED(GCODE_QUOTED_STRINGS)

@ -537,12 +537,12 @@
* E_STEPPERS - Number of actual E stepper motors * E_STEPPERS - Number of actual E stepper motors
* E_MANUAL - Number of E steppers for LCD move options * E_MANUAL - Number of E steppers for LCD move options
*/ */
#if EXTRUDERS #if EXTRUDERS
#define HAS_EXTRUDERS 1 #define HAS_EXTRUDERS 1
#if EXTRUDERS > 1 #if EXTRUDERS > 1
#define HAS_MULTI_EXTRUDER 1 #define HAS_MULTI_EXTRUDER 1
#endif #endif
#define E_AXIS_N(E) AxisEnum(E_AXIS + E_INDEX_N(E))
#else #else
#undef EXTRUDERS #undef EXTRUDERS
#define EXTRUDERS 0 #define EXTRUDERS 0
@ -551,6 +551,7 @@
#undef SWITCHING_NOZZLE #undef SWITCHING_NOZZLE
#undef MIXING_EXTRUDER #undef MIXING_EXTRUDER
#undef HOTEND_IDLE_TIMEOUT #undef HOTEND_IDLE_TIMEOUT
#undef DISABLE_E
#endif #endif
#if ENABLED(SWITCHING_EXTRUDER) // One stepper for every two EXTRUDERS #if ENABLED(SWITCHING_EXTRUDER) // One stepper for every two EXTRUDERS
@ -604,6 +605,50 @@
#define E_MANUAL EXTRUDERS #define E_MANUAL EXTRUDERS
#endif #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 #if HOTENDS
#define HAS_HOTEND 1 #define HAS_HOTEND 1
#ifndef HOTEND_OVERSHOOT #ifndef HOTEND_OVERSHOOT
@ -624,10 +669,6 @@
#define ARRAY_BY_HOTENDS(V...) ARRAY_N(HOTENDS, V) #define ARRAY_BY_HOTENDS(V...) ARRAY_N(HOTENDS, V)
#define ARRAY_BY_HOTENDS1(v1) ARRAY_N_1(HOTENDS, v1) #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 * Default hotend offsets, if not defined
*/ */
@ -653,40 +694,11 @@
#undef SINGLENOZZLE_STANDBY_FAN #undef SINGLENOZZLE_STANDBY_FAN
#endif #endif
/** // Switching extruder has its own servo?
* Number of Linear Axes (e.g., XYZ) #if ENABLED(SWITCHING_EXTRUDER) && (DISABLED(SWITCHING_NOZZLE) || SWITCHING_EXTRUDER_SERVO_NR != SWITCHING_NOZZLE_SERVO_NR)
* All the logical axes except for the tool (E) axis #define DO_SWITCH_EXTRUDER 1
*/
#ifndef LINEAR_AXES
#define LINEAR_AXES XYZ
#endif #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
#endif
#define E_AXIS_N(E) AxisEnum(E_AXIS + E_INDEX_N(E))
/** /**
* The BLTouch Probe emulates a servo probe * The BLTouch Probe emulates a servo probe
* and uses "special" angles for its state. * and uses "special" angles for its state.
@ -726,6 +738,9 @@
#define HAS_BED_PROBE 1 #define HAS_BED_PROBE 1
#endif #endif
/**
* Fill in undefined Filament Sensor options
*/
#if ENABLED(FILAMENT_RUNOUT_SENSOR) #if ENABLED(FILAMENT_RUNOUT_SENSOR)
#if NUM_RUNOUT_SENSORS >= 1 #if NUM_RUNOUT_SENSORS >= 1
#ifndef FIL_RUNOUT1_STATE #ifndef FIL_RUNOUT1_STATE
@ -834,6 +849,9 @@
#define Z_HOME_TO_MIN 1 #define Z_HOME_TO_MIN 1
#endif #endif
/**
* Conditionals based on the type of Bed Probe
*/
#if HAS_BED_PROBE #if HAS_BED_PROBE
#if DISABLED(NOZZLE_AS_PROBE) #if DISABLED(NOZZLE_AS_PROBE)
#define HAS_PROBE_XY_OFFSET 1 #define HAS_PROBE_XY_OFFSET 1
@ -868,7 +886,7 @@
#endif #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) #if ENABLED(AUTO_BED_LEVELING_UBL)
#undef LCD_BED_LEVELING #undef LCD_BED_LEVELING

@ -103,6 +103,9 @@
#undef THERMAL_PROTECTION_PERIOD #undef THERMAL_PROTECTION_PERIOD
#undef WATCH_TEMP_PERIOD #undef WATCH_TEMP_PERIOD
#undef SHOW_TEMP_ADC_VALUES #undef SHOW_TEMP_ADC_VALUES
#undef LCD_SHOW_E_TOTAL
#undef MANUAL_E_MOVES_RELATIVE
#undef STEALTHCHOP_E
#endif #endif
#if TEMP_SENSOR_BED == 0 #if TEMP_SENSOR_BED == 0
@ -482,6 +485,23 @@
#endif #endif
#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 // SD Card connection methods
// Defined here so pins and sanity checks can use them // Defined here so pins and sanity checks can use them

@ -1563,133 +1563,137 @@
#endif #endif
// Extruder steppers and solenoids // Extruder steppers and solenoids
#if PIN_EXISTS(E0_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E0)) #if HAS_EXTRUDERS
#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(E1_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E1)) #if PIN_EXISTS(E0_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E0))
#define HAS_E1_ENABLE 1 #define HAS_E0_ENABLE 1
#endif #endif
#if PIN_EXISTS(E1_DIR) #if PIN_EXISTS(E0_DIR)
#define HAS_E1_DIR 1 #define HAS_E0_DIR 1
#endif #endif
#if PIN_EXISTS(E1_STEP) #if PIN_EXISTS(E0_STEP)
#define HAS_E1_STEP 1 #define HAS_E0_STEP 1
#endif #endif
#if PIN_EXISTS(E1_MS1) #if PIN_EXISTS(E0_MS1)
#define HAS_E1_MS_PINS 1 #define HAS_E0_MS_PINS 1
#endif #endif
#if PIN_EXISTS(SOL1) #if PIN_EXISTS(SOL0)
#define HAS_SOLENOID_1 1 #define HAS_SOLENOID_0 1
#endif #endif
#if PIN_EXISTS(E2_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E2)) #if PIN_EXISTS(E1_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E1))
#define HAS_E2_ENABLE 1 #define HAS_E1_ENABLE 1
#endif #endif
#if PIN_EXISTS(E2_DIR) #if PIN_EXISTS(E1_DIR)
#define HAS_E2_DIR 1 #define HAS_E1_DIR 1
#endif #endif
#if PIN_EXISTS(E2_STEP) #if PIN_EXISTS(E1_STEP)
#define HAS_E2_STEP 1 #define HAS_E1_STEP 1
#endif #endif
#if PIN_EXISTS(E2_MS1) #if PIN_EXISTS(E1_MS1)
#define HAS_E2_MS_PINS 1 #define HAS_E1_MS_PINS 1
#endif #endif
#if PIN_EXISTS(SOL2) #if PIN_EXISTS(SOL1)
#define HAS_SOLENOID_2 1 #define HAS_SOLENOID_1 1
#endif #endif
#if PIN_EXISTS(E3_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E3)) #if PIN_EXISTS(E2_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E2))
#define HAS_E3_ENABLE 1 #define HAS_E2_ENABLE 1
#endif #endif
#if PIN_EXISTS(E3_DIR) #if PIN_EXISTS(E2_DIR)
#define HAS_E3_DIR 1 #define HAS_E2_DIR 1
#endif #endif
#if PIN_EXISTS(E3_STEP) #if PIN_EXISTS(E2_STEP)
#define HAS_E3_STEP 1 #define HAS_E2_STEP 1
#endif #endif
#if PIN_EXISTS(E3_MS1) #if PIN_EXISTS(E2_MS1)
#define HAS_E3_MS_PINS 1 #define HAS_E2_MS_PINS 1
#endif #endif
#if PIN_EXISTS(SOL3) #if PIN_EXISTS(SOL2)
#define HAS_SOLENOID_3 1 #define HAS_SOLENOID_2 1
#endif #endif
#if PIN_EXISTS(E4_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E4)) #if PIN_EXISTS(E3_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E3))
#define HAS_E4_ENABLE 1 #define HAS_E3_ENABLE 1
#endif #endif
#if PIN_EXISTS(E4_DIR) #if PIN_EXISTS(E3_DIR)
#define HAS_E4_DIR 1 #define HAS_E3_DIR 1
#endif #endif
#if PIN_EXISTS(E4_STEP) #if PIN_EXISTS(E3_STEP)
#define HAS_E4_STEP 1 #define HAS_E3_STEP 1
#endif #endif
#if PIN_EXISTS(E4_MS1) #if PIN_EXISTS(E3_MS1)
#define HAS_E4_MS_PINS 1 #define HAS_E3_MS_PINS 1
#endif #endif
#if PIN_EXISTS(SOL4) #if PIN_EXISTS(SOL3)
#define HAS_SOLENOID_4 1 #define HAS_SOLENOID_3 1
#endif #endif
#if PIN_EXISTS(E5_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E5)) #if PIN_EXISTS(E4_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E4))
#define HAS_E5_ENABLE 1 #define HAS_E4_ENABLE 1
#endif #endif
#if PIN_EXISTS(E5_DIR) #if PIN_EXISTS(E4_DIR)
#define HAS_E5_DIR 1 #define HAS_E4_DIR 1
#endif #endif
#if PIN_EXISTS(E5_STEP) #if PIN_EXISTS(E4_STEP)
#define HAS_E5_STEP 1 #define HAS_E4_STEP 1
#endif #endif
#if PIN_EXISTS(E5_MS1) #if PIN_EXISTS(E4_MS1)
#define HAS_E5_MS_PINS 1 #define HAS_E4_MS_PINS 1
#endif #endif
#if PIN_EXISTS(SOL5) #if PIN_EXISTS(SOL4)
#define HAS_SOLENOID_5 1 #define HAS_SOLENOID_4 1
#endif #endif
#if PIN_EXISTS(E6_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E6)) #if PIN_EXISTS(E5_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E5))
#define HAS_E6_ENABLE 1 #define HAS_E5_ENABLE 1
#endif #endif
#if PIN_EXISTS(E6_DIR) #if PIN_EXISTS(E5_DIR)
#define HAS_E6_DIR 1 #define HAS_E5_DIR 1
#endif #endif
#if PIN_EXISTS(E6_STEP) #if PIN_EXISTS(E5_STEP)
#define HAS_E6_STEP 1 #define HAS_E5_STEP 1
#endif #endif
#if PIN_EXISTS(E6_MS1) #if PIN_EXISTS(E5_MS1)
#define HAS_E6_MS_PINS 1 #define HAS_E5_MS_PINS 1
#endif #endif
#if PIN_EXISTS(SOL6) #if PIN_EXISTS(SOL5)
#define HAS_SOLENOID_6 1 #define HAS_SOLENOID_5 1
#endif #endif
#if PIN_EXISTS(E7_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E7)) #if PIN_EXISTS(E6_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E6))
#define HAS_E7_ENABLE 1 #define HAS_E6_ENABLE 1
#endif #endif
#if PIN_EXISTS(E7_DIR) #if PIN_EXISTS(E6_DIR)
#define HAS_E7_DIR 1 #define HAS_E6_DIR 1
#endif #endif
#if PIN_EXISTS(E7_STEP) #if PIN_EXISTS(E6_STEP)
#define HAS_E7_STEP 1 #define HAS_E6_STEP 1
#endif #endif
#if PIN_EXISTS(E7_MS1) #if PIN_EXISTS(E6_MS1)
#define HAS_E7_MS_PINS 1 #define HAS_E6_MS_PINS 1
#endif #endif
#if PIN_EXISTS(SOL7) #if PIN_EXISTS(SOL6)
#define HAS_SOLENOID_7 1 #define HAS_SOLENOID_6 1
#endif #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 // Trinamic Stepper Drivers
@ -2348,7 +2352,10 @@
#if PIN_EXISTS(DIGIPOTSS) #if PIN_EXISTS(DIGIPOTSS)
#define HAS_MOTOR_CURRENT_SPI 1 #define HAS_MOTOR_CURRENT_SPI 1
#endif #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 #define HAS_MOTOR_CURRENT_PWM 1
#endif #endif

@ -1600,11 +1600,12 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS
* Homing * Homing
*/ */
constexpr float hbm[] = HOMING_BUMP_MM; constexpr float hbm[] = HOMING_BUMP_MM;
static_assert(COUNT(hbm) == XYZ, "HOMING_BUMP_MM requires X, Y, and Z elements."); static_assert(COUNT(hbm) == LINEAR_AXES, "HOMING_BUMP_MM requires one element per linear axis.");
static_assert(hbm[X_AXIS] >= 0, "HOMING_BUMP_MM.X must be greater than or equal to 0."); LINEAR_AXIS_CODE(
static_assert(hbm[Y_AXIS] >= 0, "HOMING_BUMP_MM.Y must be greater than or equal to 0."); static_assert(hbm[X_AXIS] >= 0, "HOMING_BUMP_MM.X 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(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(CODEPENDENT_XY_HOMING)
#if ENABLED(QUICK_HOME) #if ENABLED(QUICK_HOME)
#error "QUICK_HOME is incompatible with CODEPENDENT_XY_HOMING." #error "QUICK_HOME is incompatible with CODEPENDENT_XY_HOMING."
@ -1983,12 +1984,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." #error "HEATER_0_PIN not defined for this board."
#elif !ANY_PIN(TEMP_0, MAX6675_SS) #elif !ANY_PIN(TEMP_0, MAX6675_SS)
#error "TEMP_0_PIN or MAX6675_SS not defined for this board." #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)) #endif
#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)) #if HAS_EXTRUDERS
#error "E0_STEP_PIN, E0_DIR_PIN, or E0_ENABLE_PIN not defined for this board." #if ((defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__)) && !PINS_EXIST(E0_STEP, E0_DIR))
#elif EXTRUDERS && TEMP_SENSOR_0 == 0 #error "E0_STEP_PIN or E0_DIR_PIN not defined for this board."
#error "TEMP_SENSOR_0 is required if there are any extruders." #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 #endif
/** /**

@ -856,8 +856,10 @@ void MarlinUI::draw_status_screen() {
#else #else
if (show_e_total) { if (show_e_total) {
_draw_axis_value(E_AXIS, xstring, true); #if ENABLED(LCD_SHOW_E_TOTAL)
lcd_put_u8str_P(PSTR(" ")); _draw_axis_value(E_AXIS, xstring, true);
lcd_put_u8str_P(PSTR(" "));
#endif
} }
else { else {
_draw_axis_value(X_AXIS, xstring, blink); _draw_axis_value(X_AXIS, xstring, blink);

@ -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>), VPHELPER(VP_Z_MAX_SPEED, &planner.settings.max_feedrate_mm_s[Z_AXIS], ScreenHandler.HandleMaxSpeedChange_MKS, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<0>),
#if HOTENDS >= 1 #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 #endif
#if HOTENDS >= 2 #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 #endif
VPHELPER(VP_X_ACC_MAX_SPEED, (uint16_t *)&planner.settings.max_acceleration_mm_per_s2[X_AXIS], ScreenHandler.HandleMaxAccChange_MKS, ScreenHandler.DGUSLCD_SendWordValueToDisplay), 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), 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 #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 #endif
#if HOTENDS >= 2 #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 #endif
VPHELPER(VP_TRAVEL_SPEED, (uint16_t *)&planner.settings.travel_acceleration, ScreenHandler.HandleTravelAccChange_MKS, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<0>), VPHELPER(VP_TRAVEL_SPEED, (uint16_t *)&planner.settings.travel_acceleration, ScreenHandler.HandleTravelAccChange_MKS, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<0>),

@ -712,13 +712,15 @@ void MarlinUI::quick_feedback(const bool clear_buttons/*=true*/) {
// Add a manual move to the queue? // Add a manual move to the queue?
if (axis != NO_AXIS_ENUM && ELAPSED(millis(), start_time) && !planner.is_full()) { 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 IS_KINEMATIC
#if HAS_MULTI_EXTRUDER #if HAS_MULTI_EXTRUDER
REMEMBER(ae, active_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 #endif
// Apply a linear offset to a single axis // Apply a linear offset to a single axis
@ -744,7 +746,9 @@ void MarlinUI::quick_feedback(const bool clear_buttons/*=true*/) {
#else #else
// For Cartesian / Core motion simply move to the current_position // 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); //SERIAL_ECHOLNPAIR("Add planner.move with Axis ", AS_CHAR(axis_codes[axis]), " at FR ", fr_mm_s);

@ -68,10 +68,7 @@ void menu_backlash();
START_MENU(); START_MENU();
BACK_ITEM(MSG_ADVANCED_SETTINGS); 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); }) #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); 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));
EDIT_DAC_PERCENT(Y);
EDIT_DAC_PERCENT(Z);
EDIT_DAC_PERCENT(E);
ACTION_ITEM(MSG_DAC_EEPROM_WRITE, stepper_dac.commit_eeprom); ACTION_ITEM(MSG_DAC_EEPROM_WRITE, stepper_dac.commit_eeprom);
END_MENU(); END_MENU();
} }
@ -359,7 +356,7 @@ void menu_backlash();
#elif ENABLED(LIMITED_MAX_FR_EDITING) #elif ENABLED(LIMITED_MAX_FR_EDITING)
DEFAULT_MAX_FEEDRATE DEFAULT_MAX_FEEDRATE
#else #else
{ 9999, 9999, 9999, 9999 } LOGICAL_AXIS_ARRAY(9999, 9999, 9999, 9999)
#endif #endif
; ;
#if ENABLED(LIMITED_MAX_FR_EDITING) && !defined(MAX_FEEDRATE_EDIT_VALUES) #if ENABLED(LIMITED_MAX_FR_EDITING) && !defined(MAX_FEEDRATE_EDIT_VALUES)
@ -372,9 +369,7 @@ void menu_backlash();
BACK_ITEM(MSG_ADVANCED_SETTINGS); 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)]) #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); LINEAR_AXIS_CODE(EDIT_VMAX(A), EDIT_VMAX(B), EDIT_VMAX(C), EDIT_VMAX(I), EDIT_VMAX(J), EDIT_VMAX(K));
EDIT_VMAX(B);
EDIT_VMAX(C);
#if E_STEPPERS #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); 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) #elif ENABLED(LIMITED_MAX_ACCEL_EDITING)
DEFAULT_MAX_ACCELERATION DEFAULT_MAX_ACCELERATION
#else #else
{ 99000, 99000, 99000, 99000 } LOGICAL_AXIS_ARRAY(99000, 99000, 99000, 99000)
#endif #endif
; ;
#if ENABLED(LIMITED_MAX_ACCEL_EDITING) && !defined(MAX_ACCEL_EDIT_VALUES) #if ENABLED(LIMITED_MAX_ACCEL_EDITING) && !defined(MAX_ACCEL_EDIT_VALUES)
@ -419,16 +414,19 @@ void menu_backlash();
// M204 P Acceleration // M204 P Acceleration
EDIT_ITEM_FAST(float5_25, MSG_ACC, &planner.settings.acceleration, 25, max_accel); EDIT_ITEM_FAST(float5_25, MSG_ACC, &planner.settings.acceleration, 25, max_accel);
// M204 R Retract Acceleration #if HAS_EXTRUDERS
EDIT_ITEM_FAST(float5, MSG_A_RETRACT, &planner.settings.retract_acceleration, 100, planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(active_extruder)]); // 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 // M204 T Travel Acceleration
EDIT_ITEM_FAST(float5_25, MSG_A_TRAVEL, &planner.settings.travel_acceleration, 25, max_accel); 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(); }) #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); LINEAR_AXIS_CODE(
EDIT_AMAX(B, 100); EDIT_AMAX(A, 100), EDIT_AMAX(B, 100), EDIT_AMAX(C, 10),
EDIT_AMAX(C, 10); EDIT_AMAX(I, 10), EDIT_AMAX(J, 10), EDIT_AMAX(K, 10)
);
#if ENABLED(DISTINCT_E_FACTORS) #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(); }); 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 #endif
; ;
#define EDIT_JERK(N) EDIT_ITEM_FAST(float3, MSG_V##N##_JERK, &planner.max_jerk[_AXIS(N)], 1, max_jerk_edit[_AXIS(N)]) #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) #if ENABLED(DELTA)
EDIT_JERK(C); #define EDIT_JERK_C() EDIT_JERK(C)
#else #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 #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); EDIT_ITEM_FAST(float52sign, MSG_VE_JERK, &planner.max_jerk.e, 0.1f, max_jerk_edit.e);
#endif #endif
@ -517,9 +515,7 @@ void menu_advanced_steps_per_mm() {
BACK_ITEM(MSG_ADVANCED_SETTINGS); 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(); }) #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); LINEAR_AXIS_CODE(EDIT_QSTEPS(A), EDIT_QSTEPS(B), EDIT_QSTEPS(C));
EDIT_QSTEPS(B);
EDIT_QSTEPS(C);
#if ENABLED(DISTINCT_E_FACTORS) #if ENABLED(DISTINCT_E_FACTORS)
LOOP_L_N(n, E_STEPPERS) LOOP_L_N(n, E_STEPPERS)

@ -361,7 +361,8 @@ void Endstops::event_handler() {
prev_hit_state = hit_state; prev_hit_state = hit_state;
if (hit_state) { if (hit_state) {
#if HAS_STATUS_MESSAGE #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) #define _SET_STOP_CHAR(A,C) (chr## A = C)
#else #else
#define _SET_STOP_CHAR(A,C) NOOP #define _SET_STOP_CHAR(A,C) NOOP
@ -390,7 +391,13 @@ void Endstops::event_handler() {
#endif #endif
SERIAL_EOL(); 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 BOTH(SD_ABORT_ON_ENDSTOP_HIT, SDSUPPORT)
if (planner.abort_on_endstop_hit) { if (planner.abort_on_endstop_hit) {

@ -89,7 +89,7 @@ bool relative_mode; // = false;
#define Z_INIT_POS Z_HOME_POS #define Z_INIT_POS Z_HOME_POS
#endif #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 * Cartesian Destination
@ -195,16 +195,25 @@ inline void report_more_positions() {
// Report the logical position for a given machine position // Report the logical position for a given machine position
inline void report_logical_position(const xyze_pos_t &rpos) { inline void report_logical_position(const xyze_pos_t &rpos) {
const xyze_pos_t lpos = rpos.asLogical(); 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. // Report the real current position according to the steppers.
// Forward kinematics and un-leveling are applied. // Forward kinematics and un-leveling are applied.
void report_real_position() { void report_real_position() {
get_cartesian_from_steppers(); get_cartesian_from_steppers();
xyze_pos_t npos = cartes; xyze_pos_t npos = LOGICAL_AXIS_ARRAY(
npos.e = planner.get_axis_position_mm(E_AXIS); planner.get_axis_position_mm(E_AXIS),
cartes.x, cartes.y, cartes.z
);
TERN_(HAS_POSITION_MODIFIERS, planner.unapply_modifiers(npos, true)); TERN_(HAS_POSITION_MODIFIERS, planner.unapply_modifiers(npos, true));
report_logical_position(npos); report_logical_position(npos);
report_more_positions(); report_more_positions();
} }
@ -309,7 +318,9 @@ void sync_plan_position() {
planner.set_position_mm(current_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. * 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) { void set_current_from_steppers_for_axis(const AxisEnum axis) {
get_cartesian_from_steppers(); get_cartesian_from_steppers();
xyze_pos_t pos = cartes; 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 #if HAS_POSITION_MODIFIERS
planner.unapply_modifiers(pos, true); 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. * - Delta may lower Z first to get into the free motion zone.
* - Before returning, wait for the planner buffer to empty. * - 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)); 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), const feedRate_t z_feedrate = fr_mm_s ?: homing_feedrate(Z_AXIS),
xy_feedrate = fr_mm_s ?: feedRate_t(XY_PROBE_FEEDRATE_MM_S); 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*/) { 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*/) { 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*/) { 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*/) { 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*/) { 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*/) { 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); 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*/) { 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*/) { 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); 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*/) { 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*/) { 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. // Software Endstops are based on the configured limits.
soft_endstops_t soft_endstop = { soft_endstops_t soft_endstop = {
true, false, true, false,
{ X_MIN_POS, Y_MIN_POS, Z_MIN_POS }, LINEAR_AXIS_ARRAY(X_MIN_POS, Y_MIN_POS, Z_MIN_POS),
{ X_MAX_POS, Y_MAX_POS, Z_MAX_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)) if (TEST(b, a) && TERN(HOME_AFTER_DEACTIVATE, axis_is_trusted, axis_was_homed)(a))
CBI(b, a); CBI(b, a);
}; };
set_should(axis_bits, X_AXIS); // Clear test bits that are trusted // Clear test bits that are trusted
set_should(axis_bits, Y_AXIS); LINEAR_AXIS_CODE(
set_should(axis_bits, Z_AXIS); set_should(axis_bits, X_AXIS),
set_should(axis_bits, Y_AXIS),
set_should(axis_bits, Z_AXIS)
);
return axis_bits; return axis_bits;
} }
@ -1187,9 +1219,11 @@ void prepare_line_to_destination() {
PGM_P home_first = GET_TEXT(MSG_HOME_FIRST); PGM_P home_first = GET_TEXT(MSG_HOME_FIRST);
char msg[strlen_P(home_first)+1]; char msg[strlen_P(home_first)+1];
sprintf_P(msg, home_first, sprintf_P(msg, home_first,
TEST(axis_bits, X_AXIS) ? "X" : "", LINEAR_AXIS_LIST(
TEST(axis_bits, Y_AXIS) ? "Y" : "", TEST(axis_bits, X_AXIS) ? "X" : "",
TEST(axis_bits, Z_AXIS) ? "Z" : "" TEST(axis_bits, Y_AXIS) ? "Y" : "",
TEST(axis_bits, Z_AXIS) ? "Z" : ""
)
); );
SERIAL_ECHO_START(); SERIAL_ECHO_START();
SERIAL_ECHOLN(msg); 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); const feedRate_t home_fr_mm_s = fr_mm_s ?: homing_feedrate(axis);
if (DEBUGGING(LEVELING)) { if (DEBUGGING(LEVELING)) {
DEBUG_ECHOPAIR("...(", AS_CHAR(axis_codes[axis]), ", ", distance, ", "); DEBUG_ECHOPAIR("...(", AS_CHAR(AXIS_CHAR(axis)), ", ", distance, ", ");
if (fr_mm_s) if (fr_mm_s)
DEBUG_ECHO(fr_mm_s); DEBUG_ECHO(fr_mm_s);
else else
@ -1441,12 +1475,12 @@ void prepare_line_to_destination() {
* "trusted" position). * "trusted" position).
*/ */
void set_axis_never_homed(const AxisEnum axis) { 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_untrusted(axis);
set_axis_unhomed(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)); 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) if (ABS(phaseDelta) * planner.steps_to_mm[axis] / phasePerUStep < 0.05f)
SERIAL_ECHOLNPAIR("Selected home phase ", home_phase[axis], SERIAL_ECHOLNPAIR("Selected home phase ", home_phase[axis],
" too close to endstop trigger phase ", phaseCurrent, " 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. // Skip to next if target position is behind current. So it only moves away from endstop.
if (phaseDelta < 0) phaseDelta += 1024; if (phaseDelta < 0) phaseDelta += 1024;
@ -1518,7 +1552,7 @@ void prepare_line_to_destination() {
// Optional debug messages // Optional debug messages
if (DEBUGGING(LEVELING)) { if (DEBUGGING(LEVELING)) {
DEBUG_ECHOLNPAIR( 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 " Delta:", phaseDelta, " Distance:", mmDelta
); );
} }
@ -1556,7 +1590,7 @@ void prepare_line_to_destination() {
if (!_CAN_HOME(X) && !_CAN_HOME(Y) && !_CAN_HOME(Z)) return; if (!_CAN_HOME(X) && !_CAN_HOME(Y) && !_CAN_HOME(Z)) return;
#endif #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) const int axis_home_dir = TERN0(DUAL_X_CARRIAGE, axis == X_AXIS)
? TOOL_X_HOME_DIR(active_extruder) : home_dir(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; case Z_AXIS: es = Z_ENDSTOP; break;
} }
if (TEST(endstops.state(), es)) { 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)); kill(GET_TEXT(MSG_KILL_HOMING_FAILED));
} }
#endif #endif
@ -1856,7 +1890,7 @@ void prepare_line_to_destination() {
if (axis == Z_AXIS) fwretract.current_hop = 0.0; if (axis == Z_AXIS) fwretract.current_hop = 0.0;
#endif #endif
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("<<< homeaxis(", AS_CHAR(axis_codes[axis]), ")"); if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("<<< homeaxis(", AS_CHAR(AXIS_CHAR(axis)), ")");
} // homeaxis() } // homeaxis()
@ -1881,7 +1915,7 @@ void prepare_line_to_destination() {
* Callers must sync the planner position after calling this! * Callers must sync the planner position after calling this!
*/ */
void set_axis_is_at_home(const AxisEnum axis) { 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_trusted(axis);
set_axis_homed(axis); set_axis_homed(axis);
@ -1931,10 +1965,10 @@ void set_axis_is_at_home(const AxisEnum axis) {
if (DEBUGGING(LEVELING)) { if (DEBUGGING(LEVELING)) {
#if HAS_HOME_OFFSET #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 #endif
DEBUG_POS("", current_position); 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)), ")");
} }
} }

@ -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) \ #define XYZ_DEFS(T, NAME, OPT) \
inline T NAME(const AxisEnum axis) { \ inline T NAME(const AxisEnum axis) { \
static const XYZval<T> NAME##_P DEFS_PROGMEM = { X_##OPT, Y_##OPT, Z_##OPT }; \ static const XYZval<T> NAME##_P DEFS_PROGMEM = LINEAR_AXIS_ARRAY(X_##OPT, Y_##OPT, Z_##OPT); \
return pgm_read_any(&NAME##_P[axis]); \ return pgm_read_any(&NAME##_P[axis]); \
} }
XYZ_DEFS(float, base_min_pos, MIN_POS); 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. * no kinematic translation. Used for homing axes and cartesian/core syncing.
*/ */
void sync_plan_position(); 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 * 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 * 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 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 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); 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 * 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; constexpr linear_axis_bits_t linear_bits = _BV(LINEAR_AXES) - 1;
void set_axis_is_at_home(const AxisEnum axis); void set_axis_is_at_home(const AxisEnum axis);

@ -1345,10 +1345,12 @@ void Planner::check_axes_activity() {
#if ANY(DISABLE_X, DISABLE_Y, DISABLE_Z, DISABLE_E) #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)) { for (uint8_t b = block_buffer_tail; b != block_buffer_head; b = next_block_index(b)) {
block_t *block = &block_buffer[b]; block_t *block = &block_buffer[b];
if (ENABLED(DISABLE_X) && block->steps.x) axis_active.x = true; LOGICAL_AXIS_CODE(
if (ENABLED(DISABLE_Y) && block->steps.y) axis_active.y = true; if (TERN0(DISABLE_E, block->steps.e)) axis_active.e = true,
if (ENABLED(DISABLE_Z) && block->steps.z) axis_active.z = true; if (TERN0(DISABLE_X, block->steps.x)) axis_active.x = true,
if (ENABLED(DISABLE_E) && block->steps.e) axis_active.e = true; if (TERN0(DISABLE_Y, block->steps.y)) axis_active.y = true,
if (TERN0(DISABLE_Z, block->steps.z)) axis_active.z = true
);
} }
#endif #endif
} }
@ -1369,10 +1371,12 @@ void Planner::check_axes_activity() {
// //
// Disable inactive axes // Disable inactive axes
// //
if (TERN0(DISABLE_X, !axis_active.x)) DISABLE_AXIS_X(); LOGICAL_AXIS_CODE(
if (TERN0(DISABLE_Y, !axis_active.y)) DISABLE_AXIS_Y(); if (TERN0(DISABLE_E, !axis_active.e)) disable_e_steppers(),
if (TERN0(DISABLE_Z, !axis_active.z)) DISABLE_AXIS_Z(); if (TERN0(DISABLE_X, !axis_active.x)) DISABLE_AXIS_X(),
if (TERN0(DISABLE_E, !axis_active.e)) disable_e_steppers(); if (TERN0(DISABLE_Y, !axis_active.y)) DISABLE_AXIS_Y(),
if (TERN0(DISABLE_Z, !axis_active.z)) DISABLE_AXIS_Z()
);
// //
// Update Fan speeds // 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) 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*/ , feedRate_t fr_mm_s, const uint8_t extruder, const_float_t millimeters/*=0.0*/
) { ) {
int32_t LOGICAL_AXIS_LIST(
const int32_t da = target.a - position.a, de = target.e - position.e,
db = target.b - position.b, da = target.a - position.a,
dc = target.c - position.c; 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
/* <-- add a slash to enable /* <-- add a slash to enable
SERIAL_ECHOLNPAIR( SERIAL_ECHOLNPAIR(
@ -1883,35 +1883,39 @@ bool Planner::_populate_block(block_t * const block, bool split_move,
// Compute direction bit-mask for this block // Compute direction bit-mask for this block
uint8_t dm = 0; uint8_t dm = 0;
#if CORE_IS_XY #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 (db < 0) SBI(dm, Y_HEAD); // ...and Y
if (dc < 0) SBI(dm, Z_AXIS); if (dc < 0) SBI(dm, Z_AXIS);
if (da + db < 0) SBI(dm, A_AXIS); // Motor A direction if (da + db < 0) SBI(dm, A_AXIS); // Motor A direction
if (CORESIGN(da - db) < 0) SBI(dm, B_AXIS); // Motor B direction if (CORESIGN(da - db) < 0) SBI(dm, B_AXIS); // Motor B direction
#elif CORE_IS_XZ #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 (db < 0) SBI(dm, Y_AXIS);
if (dc < 0) SBI(dm, Z_HEAD); // ...and Z if (dc < 0) SBI(dm, Z_HEAD); // ...and Z
if (da + dc < 0) SBI(dm, A_AXIS); // Motor A direction if (da + dc < 0) SBI(dm, A_AXIS); // Motor A direction
if (CORESIGN(da - dc) < 0) SBI(dm, C_AXIS); // Motor C direction if (CORESIGN(da - dc) < 0) SBI(dm, C_AXIS); // Motor C direction
#elif CORE_IS_YZ #elif CORE_IS_YZ
if (da < 0) SBI(dm, X_AXIS); 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 (dc < 0) SBI(dm, Z_HEAD); // ...and Z
if (db + dc < 0) SBI(dm, B_AXIS); // Motor B direction if (db + dc < 0) SBI(dm, B_AXIS); // Motor B direction
if (CORESIGN(db - dc) < 0) SBI(dm, C_AXIS); // Motor C direction if (CORESIGN(db - dc) < 0) SBI(dm, C_AXIS); // Motor C direction
#elif ENABLED(MARKFORGED_XY) #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 (db < 0) SBI(dm, Y_HEAD); // ...and Y
if (dc < 0) SBI(dm, Z_AXIS); if (dc < 0) SBI(dm, Z_AXIS);
if (da + db < 0) SBI(dm, A_AXIS); // Motor A direction if (da + db < 0) SBI(dm, A_AXIS); // Motor A direction
if (db < 0) SBI(dm, B_AXIS); // Motor B direction if (db < 0) SBI(dm, B_AXIS); // Motor B direction
#else #else
if (da < 0) SBI(dm, X_AXIS); LINEAR_AXIS_CODE(
if (db < 0) SBI(dm, Y_AXIS); if (da < 0) SBI(dm, X_AXIS),
if (dc < 0) SBI(dm, Z_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 #endif
if (de < 0) SBI(dm, E_AXIS);
#if HAS_EXTRUDERS #if HAS_EXTRUDERS
const float esteps_float = de * e_factor[extruder]; 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)); block->steps.set(ABS(da), ABS(db), ABS(dc));
#else #else
// default non-h-bot planning // 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 #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.a = (da - db) * steps_to_mm[A_AXIS];
steps_dist_mm.b = db * steps_to_mm[B_AXIS]; steps_dist_mm.b = db * steps_to_mm[B_AXIS];
#else #else
steps_dist_mm.a = da * steps_to_mm[A_AXIS]; LINEAR_AXIS_CODE(
steps_dist_mm.b = db * steps_to_mm[B_AXIS]; steps_dist_mm.a = da * steps_to_mm[A_AXIS],
steps_dist_mm.c = dc * steps_to_mm[C_AXIS]; steps_dist_mm.b = db * steps_to_mm[B_AXIS],
steps_dist_mm.c = dc * steps_to_mm[C_AXIS]
);
#endif #endif
#if HAS_EXTRUDERS #if HAS_EXTRUDERS
steps_dist_mm.e = esteps_float * steps_to_mm[E_AXIS_N(extruder)]; steps_dist_mm.e = esteps_float * steps_to_mm[E_AXIS_N(extruder)];
#else
steps_dist_mm.e = 0.0f;
#endif #endif
TERN_(LCD_SHOW_E_TOTAL, e_move_accumulator += steps_dist_mm.e); 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) { if (true LINEAR_AXIS_GANG(
block->millimeters = (0 && block->steps.a < MIN_STEPS_PER_SEGMENT,
#if HAS_EXTRUDERS && block->steps.b < MIN_STEPS_PER_SEGMENT,
+ ABS(steps_dist_mm.e) && block->steps.c < MIN_STEPS_PER_SEGMENT
#endif )
); ) {
block->millimeters = TERN0(HAS_EXTRUDERS, ABS(steps_dist_mm.e));
} }
else { else {
if (millimeters) if (millimeters)
block->millimeters = millimeters; block->millimeters = millimeters;
else else {
block->millimeters = SQRT( block->millimeters = SQRT(
#if EITHER(CORE_IS_XY, MARKFORGED_XY) #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 #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 #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 #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 #endif
); );
}
/** /**
* At this point at least one of the axes has more steps than * 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)); TERN_(BACKLASH_COMPENSATION, backlash.add_correction_steps(da, db, dc, dm, block));
} }
#if HAS_EXTRUDERS TERN_(HAS_EXTRUDERS, block->steps.e = esteps);
block->steps.e = esteps;
#endif
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 // Bail if this is a zero-length block
if (block->step_event_count < MIN_STEPS_PER_SEGMENT) return false; 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 #endif
#if ENABLED(AUTO_POWER_CONTROL) #if ENABLED(AUTO_POWER_CONTROL)
if (block->steps.x || block->steps.y || block->steps.z) if (LINEAR_AXIS_GANG(
powerManager.power_on(); block->steps.x,
|| block->steps.y,
|| block->steps.z
)) powerManager.power_on();
#endif #endif
// Enable active axes // 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(); if (block->steps.x) ENABLE_AXIS_X();
#else #else
if (block->steps.x) ENABLE_AXIS_X(); LINEAR_AXIS_CODE(
if (block->steps.y) ENABLE_AXIS_Y(); if (block->steps.x) ENABLE_AXIS_X(),
#if DISABLED(Z_LATE_ENABLE) if (block->steps.y) ENABLE_AXIS_Y(),
if (block->steps.z) ENABLE_AXIS_Z(); if (TERN(Z_LATE_ENABLE, 0, block->steps.z)) ENABLE_AXIS_Z()
#endif );
#endif #endif
// Enable extruder(s) // Enable extruder(s)
@ -2283,7 +2300,9 @@ bool Planner::_populate_block(block_t * const block, bool split_move,
// Compute and limit the acceleration rate for the trapezoid generator. // Compute and limit the acceleration rate for the trapezoid generator.
const float steps_per_mm = block->step_event_count * inverse_millimeters; const float steps_per_mm = block->step_event_count * inverse_millimeters;
uint32_t accel; 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 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 TERN_(LIN_ADVANCE, block->use_advance_lead = false); // No linear advance for simple retract/recover
} }
@ -2348,16 +2367,20 @@ bool Planner::_populate_block(block_t * const block, bool split_move,
// Limit acceleration per axis // Limit acceleration per axis
if (block->step_event_count <= acceleration_long_cutoff) { if (block->step_event_count <= acceleration_long_cutoff) {
LIMIT_ACCEL_LONG(A_AXIS, 0); LOGICAL_AXIS_CODE(
LIMIT_ACCEL_LONG(B_AXIS, 0); LIMIT_ACCEL_LONG(E_AXIS, E_INDEX_N(extruder)),
LIMIT_ACCEL_LONG(C_AXIS, 0); LIMIT_ACCEL_LONG(A_AXIS, 0),
LIMIT_ACCEL_LONG(E_AXIS, E_INDEX_N(extruder)); LIMIT_ACCEL_LONG(B_AXIS, 0),
LIMIT_ACCEL_LONG(C_AXIS, 0)
);
} }
else { else {
LIMIT_ACCEL_FLOAT(A_AXIS, 0); LOGICAL_AXIS_CODE(
LIMIT_ACCEL_FLOAT(B_AXIS, 0); LIMIT_ACCEL_FLOAT(E_AXIS, E_INDEX_N(extruder)),
LIMIT_ACCEL_FLOAT(C_AXIS, 0); LIMIT_ACCEL_FLOAT(A_AXIS, 0),
LIMIT_ACCEL_FLOAT(E_AXIS, E_INDEX_N(extruder)); LIMIT_ACCEL_FLOAT(B_AXIS, 0),
LIMIT_ACCEL_FLOAT(C_AXIS, 0)
);
} }
} }
block->acceleration_steps_per_s2 = accel; block->acceleration_steps_per_s2 = accel;
@ -2421,7 +2444,7 @@ bool Planner::_populate_block(block_t * const block, bool split_move,
#if HAS_DIST_MM_ARG #if HAS_DIST_MM_ARG
cart_dist_mm cart_dist_mm
#else #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 #endif
; ;
@ -2440,8 +2463,12 @@ bool Planner::_populate_block(block_t * const block, bool split_move,
if (moves_queued && !UNEAR_ZERO(previous_nominal_speed_sqr)) { if (moves_queued && !UNEAR_ZERO(previous_nominal_speed_sqr)) {
// Compute cosine of angle between previous and current path. (prev_unit_vec is negative) // 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. // 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) float junction_cos_theta = LOGICAL_AXIS_GANG(
+ (-prev_unit_vec.z * unit_vec.z) + (-prev_unit_vec.e * unit_vec.e); + (-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). // NOTE: Computed without any expensive trig, sin() or acos(), by trig half angle identity of cos(theta).
if (junction_cos_theta > 0.999999f) { if (junction_cos_theta > 0.999999f) {
@ -2756,7 +2783,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. * 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) 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*/ , const_feedRate_t fr_mm_s, const uint8_t extruder, const_float_t millimeters/*=0.0*/
) { ) {
@ -2775,21 +2803,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 // The target position of the tool in absolute steps
// Calculate target position in absolute steps // Calculate target position in absolute steps
const abce_long_t target = { const abce_long_t target = {
int32_t(LROUND(a * settings.axis_steps_per_mm[A_AXIS])), LOGICAL_AXIS_LIST(
int32_t(LROUND(b * settings.axis_steps_per_mm[B_AXIS])), int32_t(LROUND(e * settings.axis_steps_per_mm[E_AXIS_N(extruder)])),
int32_t(LROUND(c * settings.axis_steps_per_mm[C_AXIS])), int32_t(LROUND(a * settings.axis_steps_per_mm[A_AXIS])),
int32_t(LROUND(e * settings.axis_steps_per_mm[E_AXIS_N(extruder)])) 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 #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 #endif
// DRYRUN prevents E moves from taking place #if HAS_EXTRUDERS
if (DEBUGGING(DRYRUN) || TERN0(CANCEL_OBJECTS, cancelable.skipping)) { // DRYRUN prevents E moves from taking place
position.e = target.e; if (DEBUGGING(DRYRUN) || TERN0(CANCEL_OBJECTS, cancelable.skipping)) {
TERN_(HAS_POSITION_FLOAT, position_float.e = e); position.e = target.e;
} TERN_(HAS_POSITION_FLOAT, position_float.e = e);
}
#endif
/* <-- add a slash to enable /* <-- add a slash to enable
SERIAL_ECHOPAIR(" buffer_segment FR:", fr_mm_s); SERIAL_ECHOPAIR(" buffer_segment FR:", fr_mm_s);
@ -2848,10 +2880,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 * 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) * 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) 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)); TERN_(HAS_POSITION_MODIFIERS, apply_modifiers(machine));
#if IS_KINEMATIC #if IS_KINEMATIC
@ -2914,16 +2948,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]; FANS_LOOP(i) block->fan_speed[i] = thermalManager.fan_speed[i];
#endif #endif
#if HAS_MULTI_EXTRUDER TERN_(HAS_MULTI_EXTRUDER, block->extruder = extruder);
block->extruder = extruder;
#endif
block->page_idx = page_idx; block->page_idx = page_idx;
block->step_event_count = num_steps; block->step_event_count = num_steps;
block->initial_rate = block->initial_rate = block->final_rate = block->nominal_rate = last_page_step_rate; // steps/s
block->final_rate =
block->nominal_rate = last_page_step_rate; // steps/s
block->accelerate_until = 0; block->accelerate_until = 0;
block->decelerate_after = block->step_event_count; block->decelerate_after = block->step_event_count;
@ -2967,13 +2997,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. * 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_(DISTINCT_E_FACTORS, last_extruder = active_extruder);
TERN_(HAS_POSITION_FLOAT, position_float.set(a, b, c, e)); TERN_(HAS_POSITION_FLOAT, position_float.set(LOGICAL_AXIS_LIST(e, a, b, c)));
position.set(LROUND(a * settings.axis_steps_per_mm[A_AXIS]), position.set(
LROUND(b * settings.axis_steps_per_mm[B_AXIS]), LOGICAL_AXIS_LIST(
LROUND(c * settings.axis_steps_per_mm[C_AXIS]), LROUND(e * settings.axis_steps_per_mm[E_AXIS_N(active_extruder)]),
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()) { if (has_blocks_queued()) {
//previous_nominal_speed_sqr = 0.0; // Reset planner junction speeds. Assume start from rest. //previous_nominal_speed_sqr = 0.0; // Reset planner junction speeds. Assume start from rest.
//previous_speed.reset(); //previous_speed.reset();
@ -2983,11 +3019,11 @@ void Planner::set_machine_position_mm(const_float_t a, const_float_t b, const_fl
stepper.set_position(position); 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) { void Planner::set_position_mm(
xyze_pos_t machine = { rx, ry, rz, e }; LOGICAL_AXIS_LIST(const_float_t e, const_float_t rx, const_float_t ry, const_float_t rz)
#if HAS_POSITION_MODIFIERS ) {
apply_modifiers(machine, true); xyze_pos_t machine = LOGICAL_AXIS_ARRAY(e, rx, ry, rz);
#endif TERN_(HAS_POSITION_MODIFIERS, apply_modifiers(machine, true));
#if IS_KINEMATIC #if IS_KINEMATIC
position_cart.set(rx, ry, rz, e); position_cart.set(rx, ry, rz, e);
inverse_kinematics(machine); inverse_kinematics(machine);
@ -2997,23 +3033,27 @@ void Planner::set_position_mm(const_float_t rx, const_float_t ry, const_float_t
#endif #endif
} }
/** #if HAS_EXTRUDERS
* 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);
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); * Setters for planner position (also setting stepper position).
TERN_(HAS_POSITION_FLOAT, position_float.e = e_new); */
TERN_(IS_KINEMATIC, position_cart.e = e); 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()) const float e_new = DIFF_TERN(FWRETRACT, e, fwretract.current_retract[active_extruder]);
buffer_sync_block(); position.e = LROUND(settings.axis_steps_per_mm[axis_index] * e_new);
else TERN_(HAS_POSITION_FLOAT, position_float.e = e_new);
stepper.set_axis_position(E_AXIS, position.e); 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 // Recalculate the steps/s^2 acceleration rates, based on the mm/s^2
void Planner::reset_acceleration_rates() { void Planner::reset_acceleration_rates() {
@ -3043,11 +3083,11 @@ void Planner::refresh_positioning() {
// Apply limits to a variable and give a warning if the value was out of range // 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) { 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; const float before = val;
LIMIT(val, 0.1, max_limit[lim_axis]); LIMIT(val, 0.1, max_limit[lim_axis]);
if (before != val) { if (before != val) {
SERIAL_CHAR(axis_codes[lim_axis]); SERIAL_CHAR(AXIS_CHAR(lim_axis));
SERIAL_ECHOPGM(" Max "); SERIAL_ECHOPGM(" Max ");
SERIAL_ECHOPGM_P(setting_name); SERIAL_ECHOPGM_P(setting_name);
SERIAL_ECHOLNPAIR(" limited to ", val); SERIAL_ECHOLNPAIR(" limited to ", val);

@ -76,7 +76,7 @@
// Feedrate for manual moves // Feedrate for manual moves
#ifdef MANUAL_FEEDRATE #ifdef MANUAL_FEEDRATE
constexpr xyze_feedrate_t _mf = 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 #endif
#if IS_KINEMATIC && HAS_JUNCTION_DEVIATION #if IS_KINEMATIC && HAS_JUNCTION_DEVIATION
@ -758,7 +758,8 @@ class Planner {
* extruder - target extruder * extruder - target extruder
* millimeters - the length of the movement, if known * 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) 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 , 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) 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 , 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) OPTARG(HAS_DIST_MM_ARG, cart_dist_mm)
, fr_mm_s, extruder, millimeters); , fr_mm_s, extruder, millimeters
);
} }
public: public:
@ -785,14 +788,18 @@ class Planner {
* millimeters - the length of the movement, if known * 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) * 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) 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 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) 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) OPTARG(SCARA_FEEDRATE_SCALING, inv_duration)
); );
} }
@ -814,9 +821,16 @@ class Planner {
* *
* Clears previous speed values. * 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); static void set_position_mm(
FORCE_INLINE static void set_position_mm(const xyze_pos_t &cart) { set_position_mm(cart.x, cart.y, cart.z, cart.e); } LOGICAL_AXIS_LIST(const_float_t e, const_float_t rx, const_float_t ry, const_float_t rz)
static void set_e_position_mm(const_float_t e); );
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. * Set the planner.position and individual stepper positions.
@ -824,8 +838,12 @@ class Planner {
* The supplied position is in machine space, and no additional * The supplied position is in machine space, and no additional
* conversions are applied. * 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); static void set_machine_position_mm(
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); } 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) * 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 float get_axis_position_mm(const AxisEnum axis);
static inline abce_pos_t get_axis_positions_mm() { static inline abce_pos_t get_axis_positions_mm() {
const abce_pos_t out = { const abce_pos_t out = LOGICAL_AXIS_ARRAY(
get_axis_position_mm(A_AXIS), get_axis_position_mm(E_AXIS),
get_axis_position_mm(B_AXIS), get_axis_position_mm(A_AXIS), get_axis_position_mm(B_AXIS), get_axis_position_mm(C_AXIS)
get_axis_position_mm(C_AXIS), );
get_axis_position_mm(E_AXIS)
};
return out; return out;
} }

@ -168,10 +168,10 @@
void M554_report(); void M554_report();
#endif #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 { 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 X, Y, Z, X2, Y2, Z2, Z3, Z4, E0, E1, E2, E3, E4, E5, E6, E7; } tmc_hybrid_threshold_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 X, Y, Z, X2, Y2, Z2, Z3, Z4; } tmc_sgt_t; typedef struct { int16_t LINEAR_AXIS_LIST(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 { 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 // Limit an index to an array size
#define ALIM(I,ARR) _MIN(I, (signed)COUNT(ARR) - 1) #define ALIM(I,ARR) _MIN(I, (signed)COUNT(ARR) - 1)
@ -654,7 +654,7 @@ void MarlinSettings::postprocess() {
EEPROM_WRITE(dummyf); EEPROM_WRITE(dummyf);
#endif #endif
#else #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); EEPROM_WRITE(planner_max_jerk);
#endif #endif
@ -1188,10 +1188,10 @@ void MarlinSettings::postprocess() {
#endif #endif
#else #else
const tmc_hybrid_threshold_t tmc_hybrid_threshold = { 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, .X2 = 100, .Y2 = 100, .Z2 = 3, .Z3 = 3, .Z4 = 3,
.E0 = 30, .E1 = 30, .E2 = 30, .E0 = 30, .E1 = 30, .E2 = 30, .E3 = 30,
.E3 = 30, .E4 = 30, .E5 = 30 .E4 = 30, .E5 = 30, .E6 = 30, .E7 = 30
}; };
#endif #endif
EEPROM_WRITE(tmc_hybrid_threshold); EEPROM_WRITE(tmc_hybrid_threshold);
@ -2604,7 +2604,7 @@ void MarlinSettings::reset() {
#ifndef DEFAULT_ZJERK #ifndef DEFAULT_ZJERK
#define DEFAULT_ZJERK 0 #define DEFAULT_ZJERK 0
#endif #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;); TERN_(HAS_CLASSIC_E_JERK, planner.max_jerk.e = DEFAULT_EJERK;);
#endif #endif
@ -3142,10 +3142,12 @@ void MarlinSettings::reset() {
CONFIG_ECHO_HEADING("Maximum feedrates (units/s):"); CONFIG_ECHO_HEADING("Maximum feedrates (units/s):");
CONFIG_ECHO_START(); CONFIG_ECHO_START();
SERIAL_ECHOLNPAIR_P( SERIAL_ECHOLNPAIR_P(
PSTR(" M203 X"), LINEAR_UNIT(planner.settings.max_feedrate_mm_s[X_AXIS]) LIST_N(DOUBLE(LINEAR_AXES),
, SP_Y_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Y_AXIS]) PSTR(" M203 X"), LINEAR_UNIT(planner.settings.max_feedrate_mm_s[X_AXIS]),
, SP_Z_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Z_AXIS]) SP_Y_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Y_AXIS]),
#if DISABLED(DISTINCT_E_FACTORS) 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]) , SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_feedrate_mm_s[E_AXIS])
#endif #endif
); );
@ -3162,10 +3164,12 @@ void MarlinSettings::reset() {
CONFIG_ECHO_HEADING("Maximum Acceleration (units/s2):"); CONFIG_ECHO_HEADING("Maximum Acceleration (units/s2):");
CONFIG_ECHO_START(); CONFIG_ECHO_START();
SERIAL_ECHOLNPAIR_P( SERIAL_ECHOLNPAIR_P(
PSTR(" M201 X"), LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[X_AXIS]) LIST_N(DOUBLE(LINEAR_AXES),
, SP_Y_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Y_AXIS]) PSTR(" M201 X"), LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[X_AXIS]),
, SP_Z_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Z_AXIS]) SP_Y_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Y_AXIS]),
#if DISABLED(DISTINCT_E_FACTORS) 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]) , SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_acceleration_mm_per_s2[E_AXIS])
#endif #endif
); );
@ -3894,9 +3898,11 @@ void MarlinSettings::reset() {
CONFIG_ECHO_START(); CONFIG_ECHO_START();
SERIAL_ECHOLNPAIR_P( SERIAL_ECHOLNPAIR_P(
PSTR(" M425 F"), backlash.get_correction() PSTR(" M425 F"), backlash.get_correction()
, SP_X_STR, LINEAR_UNIT(backlash.distance_mm.x) , LIST_N(DOUBLE(LINEAR_AXES),
, SP_Y_STR, LINEAR_UNIT(backlash.distance_mm.y) SP_X_STR, LINEAR_UNIT(backlash.distance_mm.x),
, SP_Z_STR, LINEAR_UNIT(backlash.distance_mm.z) SP_Y_STR, LINEAR_UNIT(backlash.distance_mm.y),
SP_Z_STR, LINEAR_UNIT(backlash.distance_mm.z)
)
#ifdef BACKLASH_SMOOTHING_MM #ifdef BACKLASH_SMOOTHING_MM
, PSTR(" S"), LINEAR_UNIT(backlash.smoothing_mm) , PSTR(" S"), LINEAR_UNIT(backlash.smoothing_mm)
#endif #endif

@ -498,7 +498,7 @@ void Stepper::set_directions() {
MIXER_STEPPER_LOOP(j) NORM_E_DIR(j); MIXER_STEPPER_LOOP(j) NORM_E_DIR(j);
count_direction.e = 1; count_direction.e = 1;
} }
#else #elif HAS_EXTRUDERS
if (motor_direction(E_AXIS)) { if (motor_direction(E_AXIS)) {
REV_E_DIR(stepper_extruder); REV_E_DIR(stepper_extruder);
count_direction.e = -1; count_direction.e = -1;
@ -1627,7 +1627,7 @@ void Stepper::pulse_phase_isr() {
PAGE_PULSE_PREP(X); PAGE_PULSE_PREP(X);
PAGE_PULSE_PREP(Y); PAGE_PULSE_PREP(Y);
PAGE_PULSE_PREP(Z); PAGE_PULSE_PREP(Z);
PAGE_PULSE_PREP(E); TERN_(HAS_EXTRUDERS, PAGE_PULSE_PREP(E));
page_step_state.segment_steps++; page_step_state.segment_steps++;
@ -1660,7 +1660,7 @@ void Stepper::pulse_phase_isr() {
PAGE_PULSE_PREP(X); PAGE_PULSE_PREP(X);
PAGE_PULSE_PREP(Y); PAGE_PULSE_PREP(Y);
PAGE_PULSE_PREP(Z); PAGE_PULSE_PREP(Z);
PAGE_PULSE_PREP(E); TERN_(HAS_EXTRUDERS, PAGE_PULSE_PREP(E));
page_step_state.segment_steps++; page_step_state.segment_steps++;
@ -2103,13 +2103,15 @@ uint32_t Stepper::block_phase_isr() {
#endif #endif
uint8_t axis_bits = 0; uint8_t axis_bits = 0;
if (X_MOVE_TEST) SBI(axis_bits, A_AXIS); LINEAR_AXIS_CODE(
if (Y_MOVE_TEST) SBI(axis_bits, B_AXIS); if (X_MOVE_TEST) SBI(axis_bits, A_AXIS),
if (Z_MOVE_TEST) SBI(axis_bits, C_AXIS); if (Y_MOVE_TEST) SBI(axis_bits, B_AXIS),
//if (!!current_block->steps.e) SBI(axis_bits, E_AXIS); if (Z_MOVE_TEST) SBI(axis_bits, C_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.e) SBI(axis_bits, E_AXIS);
//if (!!current_block->steps.c) SBI(axis_bits, Z_HEAD); //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; axis_did_move = axis_bits;
// No acceleration / deceleration time elapsed so far // No acceleration / deceleration time elapsed so far
@ -2606,9 +2608,13 @@ void Stepper::init() {
#endif #endif
// Init direction bits for first moves // Init direction bits for first moves
set_directions((INVERT_X_DIR ? _BV(X_AXIS) : 0) set_directions(0
| (INVERT_Y_DIR ? _BV(Y_AXIS) : 0) LINEAR_AXIS_GANG(
| (INVERT_Z_DIR ? _BV(Z_AXIS) : 0)); | 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 #if HAS_MOTOR_CURRENT_SPI || HAS_MOTOR_CURRENT_PWM
initialized = true; initialized = true;
@ -2625,7 +2631,9 @@ void Stepper::init() {
* This allows get_axis_position_mm to correctly * This allows get_axis_position_mm to correctly
* derive the current XYZ position later on. * 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 #if CORE_IS_XY
// corexy positioning // corexy positioning
// these equations follow the form of the dA and dB equations on https://www.corexy.com/theory.html // 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); count_position.set(a - b, b, c);
#else #else
// default non-h-bot planning // default non-h-bot planning
count_position.set(a, b, c); count_position.set(LINEAR_AXIS_LIST(a, b, c));
#endif #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 // 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(); planner.synchronize();
const bool was_enabled = suspend(); 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(); 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); SERIAL_ECHOPAIR_P(PSTR(STR_COUNT_X), pos.x, SP_Y_LBL, pos.y);
#endif #endif
#if ANY(CORE_IS_XZ, CORE_IS_YZ, DELTA) #if ANY(CORE_IS_XZ, CORE_IS_YZ, DELTA)
SERIAL_ECHOLNPAIR(" C:", pos.z); SERIAL_ECHOPAIR(" C:", pos.z);
#else #elif LINEAR_AXES >= 3
SERIAL_ECHOLNPAIR_P(SP_Z_LBL, pos.z); SERIAL_ECHOPAIR_P(SP_Z_LBL, pos.z);
#endif #endif
SERIAL_EOL();
} }
void Stepper::report_positions() { void Stepper::report_positions() {
@ -2903,7 +2915,7 @@ void Stepper::report_positions() {
DIR_WAIT_BEFORE(); 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); X_DIR_WRITE(INVERT_X_DIR ^ z_direction);
Y_DIR_WRITE(INVERT_Y_DIR ^ z_direction); Y_DIR_WRITE(INVERT_Y_DIR ^ z_direction);

@ -433,8 +433,12 @@ class Stepper {
static int32_t position(const AxisEnum axis); static int32_t position(const AxisEnum axis);
// Set the current position in steps // 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 void set_position(
static inline void set_position(const xyze_long_t &abce) { set_position(abce.a, abce.b, abce.c, abce.e); } 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); static void set_axis_position(const AxisEnum a, const int32_t &v);
// Report the positions of the steppers, in steps // Report the positions of the steppers, in steps
@ -530,8 +534,12 @@ class Stepper {
private: private:
// Set the current position in steps // 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 void _set_position(
FORCE_INLINE static void _set_position(const abce_long_t &spos) { _set_position(spos.a, spos.b, spos.c, spos.e); } 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) { FORCE_INLINE static uint32_t calc_timer_interval(uint32_t step_rate, uint8_t *loops) {
uint32_t timer; uint32_t timer;

@ -35,7 +35,9 @@
#include <HardwareSerial.h> #include <HardwareSerial.h>
#include <SPI.h> #include <SPI.h>
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) #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 // IC = TMC model number
@ -400,7 +402,7 @@ enum StealthIndex : uint8_t { STEALTH_AXIS_XY, STEALTH_AXIS_Z, STEALTH_AXIS_E };
#endif #endif
#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() { void tmc_serial_begin() {
#if HAS_TMC_HW_SERIAL #if HAS_TMC_HW_SERIAL
@ -765,19 +767,24 @@ void restore_trinamic_drivers() {
} }
void reset_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) #if AXIS_IS_TMC(X)
TMC_INIT(X, STEALTH_AXIS_XY); TMC_INIT(X, STEALTH_AXIS_X);
#endif #endif
#if AXIS_IS_TMC(X2) #if AXIS_IS_TMC(X2)
TMC_INIT(X2, STEALTH_AXIS_XY); TMC_INIT(X2, STEALTH_AXIS_X);
#endif #endif
#if AXIS_IS_TMC(Y) #if AXIS_IS_TMC(Y)
TMC_INIT(Y, STEALTH_AXIS_XY); TMC_INIT(Y, STEALTH_AXIS_Y);
#endif #endif
#if AXIS_IS_TMC(Y2) #if AXIS_IS_TMC(Y2)
TMC_INIT(Y2, STEALTH_AXIS_XY); TMC_INIT(Y2, STEALTH_AXIS_Y);
#endif #endif
#if AXIS_IS_TMC(Z) #if AXIS_IS_TMC(Z)
TMC_INIT(Z, STEALTH_AXIS_Z); TMC_INIT(Z, STEALTH_AXIS_Z);
@ -841,7 +848,7 @@ void reset_trinamic_drivers() {
stepperZ4.homing_threshold(CAT(TERN(Z4_SENSORLESS, Z4, Z), _STALL_SENSITIVITY)); stepperZ4.homing_threshold(CAT(TERN(Z4_SENSORLESS, Z4, Z), _STALL_SENSITIVITY));
#endif #endif
#endif #endif
#endif #endif // USE SENSORLESS
#ifdef TMC_ADV #ifdef TMC_ADV
TMC_ADV() TMC_ADV()

@ -171,10 +171,12 @@ exec_test $1 $2 "Azteeg X3 | Mixing Extruder (x5) | Gradient Mix | Greek" "$3"
# Test Laser features with 12864 LCD # Test Laser features with 12864 LCD
# #
restore_configs 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_AXIS_STEPS_PER_UNIT '{ 80, 80, 400 }' \
DEFAULT_MAX_FEEDRATE '{ 300, 300, 5 }' \ 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 \ 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 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 # Test Laser features with 44780 LCD
# #
restore_configs 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_AXIS_STEPS_PER_UNIT '{ 80, 80, 400 }' \
DEFAULT_MAX_FEEDRATE '{ 300, 300, 5 }' \ 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 \ 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 LASER_FEATURE AIR_EVACUATION AIR_EVACUATION_PIN AIR_ASSIST AIR_ASSIST_PIN LASER_COOLANT_FLOW_METER

@ -48,6 +48,7 @@ opt_set MOTHERBOARD BOARD_RAMBO \
DEFAULT_AXIS_STEPS_PER_UNIT '{ 80, 80, 4000 }' \ DEFAULT_AXIS_STEPS_PER_UNIT '{ 80, 80, 4000 }' \
DEFAULT_MAX_FEEDRATE '{ 300, 300, 5 }' \ 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 }' \ AXIS_RELATIVE_MODES '{ false, false, false }' \
LEVEL_CORNERS_LEVELING_ORDER '{ LF, RF }' LEVEL_CORNERS_LEVELING_ORDER '{ LF, RF }'
opt_enable USE_XMAX_PLUG USE_YMAX_PLUG USE_ZMAX_PLUG \ 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_AXIS_STEPS_PER_UNIT '{ 80, 80, 4000 }' \
DEFAULT_MAX_FEEDRATE '{ 300, 300, 5 }' \ 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 }' AXIS_RELATIVE_MODES '{ false, false, false }'
opt_enable REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER opt_enable REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER
exec_test $1 $2 "Rambo heated bed only" "$3" exec_test $1 $2 "Rambo heated bed only" "$3"

Loading…
Cancel
Save