Browse Source

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

* More patches supporting EXTRUDERS 0
* Extend types in prep for more axes
vanilla_fb_2.0.x
Scott Lahteine 3 years ago
committed by Scott Lahteine
parent
commit
4194cdda5b
  1. 7
      Marlin/src/core/serial.cpp
  2. 7
      Marlin/src/core/serial.h
  3. 440
      Marlin/src/core/types.h
  4. 8
      Marlin/src/core/utility.h
  5. 43
      Marlin/src/feature/encoder_i2c.cpp
  6. 34
      Marlin/src/feature/tmc_util.cpp
  7. 14
      Marlin/src/feature/tmc_util.h
  8. 27
      Marlin/src/gcode/calibrate/G28.cpp
  9. 12
      Marlin/src/gcode/calibrate/G425.cpp
  10. 10
      Marlin/src/gcode/calibrate/M425.cpp
  11. 27
      Marlin/src/gcode/config/M200-M205.cpp
  12. 43
      Marlin/src/gcode/config/M92.cpp
  13. 24
      Marlin/src/gcode/control/M17_M18_M84.cpp
  14. 12
      Marlin/src/gcode/feature/pause/G61.cpp
  15. 18
      Marlin/src/gcode/feature/trinamic/M122.cpp
  16. 26
      Marlin/src/gcode/gcode.cpp
  17. 37
      Marlin/src/gcode/gcode.h
  18. 37
      Marlin/src/gcode/geometry/G92.cpp
  19. 2
      Marlin/src/gcode/host/M114.cpp
  20. 10
      Marlin/src/gcode/motion/G0_G1.cpp
  21. 31
      Marlin/src/gcode/motion/G2_G3.cpp
  22. 2
      Marlin/src/gcode/motion/M290.cpp
  23. 3
      Marlin/src/gcode/parser.cpp
  24. 2
      Marlin/src/gcode/parser.h
  25. 94
      Marlin/src/inc/Conditionals_LCD.h
  26. 20
      Marlin/src/inc/Conditionals_adv.h
  27. 249
      Marlin/src/inc/Conditionals_post.h
  28. 27
      Marlin/src/inc/SanityCheck.h
  29. 6
      Marlin/src/lcd/dogm/status_screen_DOGM.cpp
  30. 8
      Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp
  31. 10
      Marlin/src/lcd/marlinui.cpp
  32. 40
      Marlin/src/lcd/menu/menu_advanced.cpp
  33. 11
      Marlin/src/module/endstops.cpp
  34. 102
      Marlin/src/module/motion.cpp
  35. 14
      Marlin/src/module/motion.h
  36. 266
      Marlin/src/module/planner.cpp
  37. 50
      Marlin/src/module/planner.h
  38. 46
      Marlin/src/module/settings.cpp
  39. 56
      Marlin/src/module/stepper.cpp
  40. 16
      Marlin/src/module/stepper.h
  41. 23
      Marlin/src/module/stepper/trinamic.cpp
  42. 12
      buildroot/tests/mega2560
  43. 2
      buildroot/tests/rambo

7
Marlin/src/core/serial.cpp

@ -101,8 +101,11 @@ void print_bin(uint16_t val) {
}
}
void print_pos(const_float_t x, const_float_t y, const_float_t z, PGM_P const prefix/*=nullptr*/, PGM_P const suffix/*=nullptr*/) {
void print_pos(
LINEAR_AXIS_LIST(const_float_t x, const_float_t y, const_float_t z)
, PGM_P const prefix/*=nullptr*/, PGM_P const suffix/*=nullptr*/
) {
if (prefix) serialprintPGM(prefix);
SERIAL_ECHOPAIR_P(SP_X_STR, x, SP_Y_STR, y, SP_Z_STR, z);
SERIAL_ECHOPAIR_P(LIST_N(DOUBLE(LINEAR_AXES), SP_X_STR, x, SP_Y_STR, y, SP_Z_STR, z));
if (suffix) serialprintPGM(suffix); else SERIAL_EOL();
}

7
Marlin/src/core/serial.h

@ -310,10 +310,13 @@ void serialprint_truefalse(const bool tf);
void serial_spaces(uint8_t count);
void print_bin(const uint16_t val);
void print_pos(const_float_t x, const_float_t y, const_float_t z, PGM_P const prefix=nullptr, PGM_P const suffix=nullptr);
void print_pos(
LINEAR_AXIS_LIST(const_float_t x, const_float_t y, const_float_t z),
PGM_P const prefix=nullptr, PGM_P const suffix=nullptr
);
inline void print_pos(const xyz_pos_t &xyz, PGM_P const prefix=nullptr, PGM_P const suffix=nullptr) {
print_pos(xyz.x, xyz.y, xyz.z, prefix, suffix);
print_pos(LINEAR_AXIS_LIST(xyz.x, xyz.y, xyz.z), prefix, suffix);
}
#define SERIAL_POS(SUFFIX,VAR) do { print_pos(VAR, PSTR(" " STRINGIFY(VAR) "="), PSTR(" : " SUFFIX "\n")); }while(0)

440
Marlin/src/core/types.h

@ -39,6 +39,26 @@ struct IF { typedef R type; };
template <class L, class R>
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
//
@ -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
//
enum AxisEnum : uint8_t {
X_AXIS = 0, A_AXIS = X_AXIS,
Y_AXIS = 1, B_AXIS = Y_AXIS,
Z_AXIS = 2, C_AXIS = Z_AXIS,
E_AXIS,
X_HEAD, Y_HEAD, Z_HEAD,
E0_AXIS = E_AXIS,
E1_AXIS, E2_AXIS, E3_AXIS, E4_AXIS, E5_AXIS, E6_AXIS, E7_AXIS,
// Linear axes may be controlled directly or indirectly
LINEAR_AXIS_LIST(X_AXIS, Y_AXIS, Z_AXIS),
// Extruder axes may be considered distinctly
#define _EN_ITEM(N) E##N##_AXIS,
REPEAT(EXTRUDERS, _EN_ITEM)
#undef _EN_ITEM
// Core also keeps toolhead directions
#if IS_CORE
X_HEAD, Y_HEAD, Z_HEAD,
#endif
// Distinct axes, including all E and Core
NUM_AXIS_ENUMS,
// Most of the time we refer only to the single E_AXIS
#if HAS_EXTRUDERS
E_AXIS = E0_AXIS,
#endif
// A, B, and C are for DELTA, SCARA, etc.
A_AXIS = X_AXIS,
#if LINEAR_AXES >= 2
B_AXIS = Y_AXIS,
#endif
#if LINEAR_AXES >= 3
C_AXIS = Z_AXIS,
#endif
// To refer to all or none
ALL_AXES_ENUM = 0xFE, NO_AXIS_ENUM = 0xFF
};
typedef IF<(NUM_AXIS_ENUMS > 8), uint16_t, uint8_t>::type axis_bits_t;
//
// Loop over axes
//
@ -185,7 +232,7 @@ void toNative(xyz_pos_t &raw);
void toNative(xyze_pos_t &raw);
//
// XY coordinates, counters, etc.
// Paired XY coordinates, counters, flags, etc.
//
template<typename T>
struct XYval {
@ -197,10 +244,14 @@ struct XYval {
FI void set(const T px) { x = px; }
FI void set(const T px, const T py) { x = px; y = py; }
FI void set(const T (&arr)[XY]) { x = arr[0]; y = arr[1]; }
FI void set(const T (&arr)[XYZ]) { x = arr[0]; y = arr[1]; }
FI void set(const T (&arr)[XYZE]) { x = arr[0]; y = arr[1]; }
#if DISTINCT_AXES > LOGICAL_AXES
FI void set(const T (&arr)[DISTINCT_AXES]) { x = arr[0]; y = arr[1]; }
#if LINEAR_AXES > XY
FI void set(const T (&arr)[LINEAR_AXES]) { x = arr[0]; y = arr[1]; }
#endif
#if LOGICAL_AXES > LINEAR_AXES
FI void set(const T (&arr)[LOGICAL_AXES]) { x = arr[0]; y = arr[1]; }
#if DISTINCT_AXES > LOGICAL_AXES
FI void set(const T (&arr)[DISTINCT_AXES]) { x = arr[0]; y = arr[1]; }
#endif
#endif
FI void reset() { x = y = 0; }
FI T magnitude() const { return (T)sqrtf(x*x + y*y); }
@ -223,8 +274,8 @@ struct XYval {
FI operator XYZval<T>() const { return { x, y }; }
FI operator XYZEval<T>() { return { x, y }; }
FI operator XYZEval<T>() const { return { x, y }; }
FI T& operator[](const int i) { return pos[i]; }
FI const T& operator[](const int i) const { return pos[i]; }
FI T& operator[](const int n) { return pos[n]; }
FI const T& operator[](const int n) const { return pos[n]; }
FI XYval<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 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>
struct XYZval {
union {
struct { T x, y, z; };
struct { T a, b, c; };
T pos[3];
struct { T LINEAR_AXIS_LIST(x, y, z); };
struct { T LINEAR_AXIS_LIST(a, b, c); };
T pos[LINEAR_AXES];
};
FI void set(const T px) { x = px; }
FI void set(const T px, const T py) { x = px; y = py; }
FI void set(const T px, const T py, const T pz) { x = px; y = py; z = pz; }
FI void set(const XYval<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 T (&arr)[XY]) { x = arr[0]; y = arr[1]; }
FI void set(const T (&arr)[XYZ]) { x = arr[0]; y = arr[1]; z = arr[2]; }
FI void set(const T (&arr)[XYZE]) { x = arr[0]; y = arr[1]; z = arr[2]; }
#if DISTINCT_AXES > XYZE
FI void set(const T (&arr)[DISTINCT_AXES]) { x = arr[0]; y = arr[1]; z = arr[2]; }
FI void set(const T (&arr)[LINEAR_AXES]) { LINEAR_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2]); }
#if LINEAR_AXES >= XYZ
FI void set(LINEAR_AXIS_LIST(const T px, const T py, const T pz))
{ LINEAR_AXIS_CODE(x = px, y = py, z = pz); }
#endif
#if LOGICAL_AXES > LINEAR_AXES
FI void set(const T (&arr)[LOGICAL_AXES]) { LINEAR_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2]); }
FI void set(LOGICAL_AXIS_LIST(const T, const T px, const T py, const T pz))
{ LINEAR_AXIS_CODE(x = px, y = py, z = pz); }
#if DISTINCT_AXES > LOGICAL_AXES
FI void set(const T (&arr)[DISTINCT_AXES]) { LINEAR_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2]); }
#endif
#endif
FI void reset() { x = y = z = 0; }
FI T magnitude() const { return (T)sqrtf(x*x + y*y + z*z); }
FI void reset() { LINEAR_AXIS_GANG(x =, y =, z =) 0; }
FI T magnitude() const { return (T)sqrtf(LINEAR_AXIS_GANG(x*x, + y*y, + z*z)); }
FI operator T* () { return pos; }
FI operator bool() { return z || x || y; }
FI operator bool() { return LINEAR_AXIS_GANG(z, || x, || y); }
FI XYZval<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<int16_t> asInt() { return { 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<int32_t> asLong() { return { 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> ROUNDL() { return { 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<float> asFloat() { return { 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> reciprocal() const { return { _RECIP(x), _RECIP(y), _RECIP(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 LINEAR_AXIS_ARRAY(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 LINEAR_AXIS_ARRAY(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 LINEAR_AXIS_ARRAY(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 LINEAR_AXIS_ARRAY(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 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> asNative() const { XYZval<float> o = asFloat(); toNative(o); return o; }
FI operator XYval<T>&() { return *(XYval<T>*)this; }
FI operator const XYval<T>&() const { return *(const XYval<T>*)this; }
FI operator XYZEval<T>() const { return { x, y, z }; }
FI T& operator[](const int i) { return pos[i]; }
FI const T& operator[](const int i) const { return pos[i]; }
FI XYZval<T>& operator= (const T v) { set(v, v, v ); return *this; }
FI operator XYZEval<T>() const { return LINEAR_AXIS_ARRAY(x, y, z); }
FI T& operator[](const int n) { return pos[n]; }
FI const T& operator[](const int n) const { return pos[n]; }
FI XYZval<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 XYZEval<T> &rs) { set(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) { 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; ls.x -= rs.x; ls.y -= rs.y; 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) const { 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; ls.x *= rs.x; ls.y *= rs.y; 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) { XYZval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; 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) { 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; 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) 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) { 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; 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 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) { 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; 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) 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) { 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; 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 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) { 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; 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 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) { 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; 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) const { 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; _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) { XYZval<T> ls = *this; _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) { x -= rs.x; y -= rs.y; 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) { x /= rs.x; y /= rs.y; 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) { 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) { 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) { 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) { 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 int &v) { 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) { _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 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; LINEAR_AXIS_CODE(_LS(ls.x), _LS(ls.y), _LS(ls.z) ); return ls; }
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) { LINEAR_AXIS_CODE(x -= rs.x, y -= rs.y, NOOP ); 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) { LINEAR_AXIS_CODE(x /= rs.x, y /= rs.y, NOOP ); 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) { LINEAR_AXIS_CODE(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) { LINEAR_AXIS_CODE(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) { LINEAR_AXIS_CODE(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) { LINEAR_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z ); 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) { LINEAR_AXIS_CODE(x *= v, y *= v, z *= v ); 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) { LINEAR_AXIS_CODE(_LS(x), _LS(y), _LS(z) ); return *this; }
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) const { return x == rs.x && y == rs.y && z == rs.z; }
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 const XYZval<T> operator-() const { 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; 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>
struct XYZEval {
union {
struct{ T x, y, z, e; };
struct{ T a, b, c; };
T pos[4];
struct{ T LOGICAL_AXIS_LIST(e, x, y, z); };
struct{ T LINEAR_AXIS_LIST(a, b, c); };
T pos[LOGICAL_AXES];
};
FI void reset() { x = y = z = e = 0; }
FI T magnitude() const { return (T)sqrtf(x*x + y*y + z*z + e*e); }
FI void reset() { LOGICAL_AXIS_GANG(e =, x =, y =, z =) 0; }
FI T magnitude() const { return (T)sqrtf(LOGICAL_AXIS_GANG(+ e*e, + x*x, + y*y, + z*z)); }
FI operator T* () { return pos; }
FI operator bool() { return e || z || x || y; }
FI void set(const T px) { x = px; }
FI void set(const T px, const T py) { x = px; y = py; }
FI void set(const T px, const T py, const T pz) { x = px; y = py; z = pz; }
FI void set(const T px, const T py, const T pz, const T pe) { x = px; y = py; z = pz; e = pe; }
FI void set(const XYval<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 XYZval<T> pxyz) { x = pxyz.x; y = pxyz.y; z = pxyz.z; }
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]; }
FI operator bool() { return false LOGICAL_AXIS_GANG(|| e, || x, || y, || z); }
FI void set(const T px) { x = px; }
FI void set(const T px, const T py) { x = px; y = py; }
FI void set(const XYval<T> pxy) { x = pxy.x; y = pxy.y; }
FI void set(const XYZval<T> pxyz) { set(LINEAR_AXIS_LIST(pxyz.x, pxyz.y, pxyz.z)); }
#if LINEAR_AXES >= XYZ
FI void set(LINEAR_AXIS_LIST(const T px, const T py, const T pz)) {
LINEAR_AXIS_CODE(x = px, y = py, z = pz);
}
#endif
FI XYZEval<T> copy() const { return *this; }
FI XYZEval<T> ABS() const { return { T(_ABS(x)), T(_ABS(y)), T(_ABS(z)), T(_ABS(e)) }; }
FI XYZEval<int16_t> asInt() { return { int16_t(x), int16_t(y), int16_t(z), int16_t(e) }; }
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 XYZEval<int32_t> asLong() const { return { int32_t(x), int32_t(y), int32_t(z), int32_t(e) }; }
FI XYZEval<int32_t> ROUNDL() { return { int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(e)) }; }
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<float> asFloat() { return { static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(e) }; }
FI XYZEval<float> asFloat() const { return { static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(e) }; }
FI XYZEval<float> reciprocal() const { return { _RECIP(x), _RECIP(y), _RECIP(z), _RECIP(e) }; }
#if LOGICAL_AXES > LINEAR_AXES
FI void set(LOGICAL_AXIS_LIST(const T pe, const T px, const T py, const T pz)) {
LOGICAL_AXIS_CODE(e = pe, x = px, y = py, z = pz);
}
FI void set(const XYval<T> pxy, const T pe) { set(pxy); e = pe; }
FI void set(const XYZval<T> pxyz, const T pe) { set(pxyz); e = pe; }
#endif
FI XYZEval<T> copy() const { XYZEval<T> o = *this; return o; }
FI XYZEval<T> ABS() const { return LOGICAL_AXIS_ARRAY(T(_ABS(e)), T(_ABS(x)), T(_ABS(y)), T(_ABS(z))); }
FI XYZEval<int16_t> asInt() { return LOGICAL_AXIS_ARRAY(int16_t(e), int16_t(x), int16_t(y), int16_t(z)); }
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> asNative() const { XYZEval<float> o = asFloat(); toNative(o); return o; }
FI operator XYval<T>&() { return *(XYval<T>*)this; }
FI operator const XYval<T>&() const { return *(const XYval<T>*)this; }
FI operator XYZval<T>&() { return *(XYZval<T>*)this; }
FI operator const XYZval<T>&() const { return *(const XYZval<T>*)this; }
FI T& operator[](const int i) { return pos[i]; }
FI const T& operator[](const int i) const { return pos[i]; }
FI XYZEval<T>& operator= (const T v) { set(v, v, v, v); return *this; }
FI T& operator[](const int n) { return pos[n]; }
FI const T& operator[](const int n) const { return pos[n]; }
FI XYZEval<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 XYZval<T> &rs) { set(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) { 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) 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) 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 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) { 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 { 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) { 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 { 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) { 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 { 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) { XYZEval<T> ls = *this; 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) { 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; 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; 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; 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; 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; 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; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; ls.e /= rs.e; 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) { 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; 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; 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; 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; 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; 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; 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; _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; _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; _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; _LS(ls.x); _LS(ls.y); _LS(ls.z); _LS(ls.e); 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 XYZval<T> &rs) { 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) { 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 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) { x -= rs.x; y -= rs.y; z -= rs.z; e -= rs.e; 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) { x /= rs.x; y /= rs.y; z /= rs.z; e /= rs.e; return *this; }
FI XYZEval<T>& operator*=(const T &v) { x *= v; y *= v; z *= v; e *= 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) { _LS(x); _LS(y); _LS(z); _LS(e); return *this; }
FI bool operator==(const XYZval<T> &rs) { return x == rs.x && y == rs.y && z == rs.z; }
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) { 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) 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) 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 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) { 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 { 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) { 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 { 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) { 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 { 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) { 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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 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) { LINEAR_AXIS_CODE(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) { LINEAR_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z); 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) { 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) { 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) { LOGICAL_AXIS_CODE(e /= rs.e, x /= rs.x, y /= rs.y, z /= rs.z); 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) { LOGICAL_AXIS_CODE(_RS(e), _RS(x), _RS(y), _RS(z)); 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 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) const { return x == rs.x && y == rs.y && z == rs.z; }
FI bool operator!=(const XYZval<T> &rs) const { return !operator==(rs); }
FI XYZEval<T> operator-() { return { -x, -y, -z, -e }; }
FI const XYZEval<T> operator-() const { return { -x, -y, -z, -e }; }
FI XYZEval<T> operator-() { return LOGICAL_AXIS_ARRAY(-e, -x, -y, -z); }
FI const XYZEval<T> operator-() const { return LOGICAL_AXIS_ARRAY(-e, -x, -y, -z); }
};
#undef _RECIP
@ -514,6 +573,3 @@ struct XYZEval {
#undef _LS
#undef _RS
#undef FI
const xyze_char_t axis_codes { 'X', 'Y', 'Z', 'E' };
#define AXIS_CHAR(A) ((char)('X' + A))

8
Marlin/src/core/utility.h

@ -76,3 +76,11 @@ public:
// Converts from an uint8_t in the range of 0-255 to an uint8_t
// in the range 0-100 while avoiding rounding artifacts
constexpr uint8_t ui8_to_percent(const uint8_t i) { return (int(i) * 100 + 127) / 255; }
const xyze_char_t axis_codes LOGICAL_AXIS_ARRAY('E', 'X', 'Y', 'Z');
#if LINEAR_AXES <= XYZ
#define AXIS_CHAR(A) ((char)('X' + A))
#else
#define AXIS_CHAR(A) axis_codes[A]
#endif

43
Marlin/src/feature/encoder_i2c.cpp

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

34
Marlin/src/feature/tmc_util.cpp

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

14
Marlin/src/feature/tmc_util.h

@ -335,14 +335,20 @@ void tmc_print_current(TMC &st) {
#endif
void monitor_tmc_drivers();
void test_tmc_connection(const bool test_x=true, const bool test_y=true, const bool test_z=true, const bool test_e=true);
void test_tmc_connection(
LOGICAL_AXIS_LIST(const bool test_e=true, const bool test_x=true, const bool test_y=true, const bool test_z=true)
);
#if ENABLED(TMC_DEBUG)
#if ENABLED(MONITOR_DRIVER_STATUS)
void tmc_set_report_interval(const uint16_t update_interval);
#endif
void tmc_report_all(const bool print_x=true, const bool print_y=true, const bool print_z=true, const bool print_e=true);
void tmc_get_registers(const bool print_x, const bool print_y, const bool print_z, const bool print_e);
void tmc_report_all(
LOGICAL_AXIS_LIST(const bool print_e=true, const bool print_x=true, const bool print_y=true, const bool print_z=true)
);
void tmc_get_registers(
LOGICAL_AXIS_LIST(const bool print_e, const bool print_x, const bool print_y, const bool print_z)
);
#endif
/**
@ -355,7 +361,7 @@ void test_tmc_connection(const bool test_x=true, const bool test_y=true, const b
#if USE_SENSORLESS
// Track enabled status of stealthChop and only re-enable where applicable
struct sensorless_t { bool x, y, z, x2, y2, z2, z3, z4; };
struct sensorless_t { bool LINEAR_AXIS_LIST(x, y, z), x2, y2, z2, z3, z4; };
#if ENABLED(IMPROVE_HOMING_RELIABILITY)
extern millis_t sg_guard_period;

27
Marlin/src/gcode/calibrate/G28.cpp

@ -321,12 +321,23 @@ void GcodeSuite::G28() {
#else
#define _UNSAFE(A) (homeZ && TERN0(Z_SAFE_HOMING, axes_should_home(_BV(A##_AXIS))))
const bool homeZ = parser.seen_test('Z'),
needX = homeZ && TERN0(Z_SAFE_HOMING, axes_should_home(_BV(X_AXIS))),
needY = homeZ && TERN0(Z_SAFE_HOMING, axes_should_home(_BV(Y_AXIS))),
homeX = needX || parser.seen_test('X'), homeY = needY || parser.seen_test('Y'),
home_all = homeX == homeY && homeX == homeZ, // All or None
doX = home_all || homeX, doY = home_all || homeY, doZ = home_all || homeZ;
LINEAR_AXIS_LIST( // Other axes should be homed before Z safe-homing
needX = _UNSAFE(X), needY = _UNSAFE(Y), needZ = false // UNUSED
),
LINEAR_AXIS_LIST( // Home each axis if needed or flagged
homeX = needX || parser.seen_test('X'),
homeY = needY || parser.seen_test('Y'),
homeZZ = homeZ // UNUSED
),
// Home-all if all or none are flagged
home_all = true LINEAR_AXIS_GANG(&& homeX == homeX, && homeX == homeY, && homeX == homeZ),
LINEAR_AXIS_LIST(doX = home_all || homeX, doY = home_all || homeY, doZ = home_all || homeZ);
UNUSED(needZ);
UNUSED(homeZZ);
#if ENABLED(HOME_Z_FIRST)
@ -336,7 +347,7 @@ void GcodeSuite::G28() {
const float z_homing_height = parser.seenval('R') ? parser.value_linear_units() : Z_HOMING_HEIGHT;
if (z_homing_height && (doX || doY || TERN0(Z_SAFE_HOMING, doZ))) {
if (z_homing_height && (0 LINEAR_AXIS_GANG(|| doX, || doY, || TERN0(Z_SAFE_HOMING, doZ)))) {
// Raise Z before homing any other axes and z is not already high enough (never lower z)
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("Raise Z (before homing) by ", z_homing_height);
do_z_clearance(z_homing_height);
@ -469,7 +480,7 @@ void GcodeSuite::G28() {
#if HAS_CURRENT_HOME(Y2)
stepperY2.rms_current(tmc_save_current_Y2);
#endif
#endif
#endif // HAS_HOMING_CURRENT
ui.refresh();
@ -490,7 +501,7 @@ void GcodeSuite::G28() {
static constexpr AxisEnum L64XX_axis_xref[MAX_L64XX] = {
X_AXIS, Y_AXIS, Z_AXIS,
X_AXIS, Y_AXIS, Z_AXIS, Z_AXIS,
E_AXIS, E_AXIS, E_AXIS, E_AXIS, E_AXIS, E_AXIS
E_AXIS, E_AXIS, E_AXIS, E_AXIS, E_AXIS, E_AXIS, E_AXIS, E_AXIS
};
for (uint8_t j = 1; j <= L64XX::chain[0]; j++) {
const uint8_t cv = L64XX::chain[j];

12
Marlin/src/gcode/calibrate/G425.cpp

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

10
Marlin/src/gcode/calibrate/M425.cpp

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

27
Marlin/src/gcode/config/M200-M205.cpp

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

43
Marlin/src/gcode/config/M92.cpp

@ -25,10 +25,12 @@
void report_M92(const bool echo=true, const int8_t e=-1) {
if (echo) SERIAL_ECHO_START(); else SERIAL_CHAR(' ');
SERIAL_ECHOPAIR_P(PSTR(" M92 X"), LINEAR_UNIT(planner.settings.axis_steps_per_mm[X_AXIS]),
SP_Y_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[Y_AXIS]),
SP_Z_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[Z_AXIS]));
#if DISABLED(DISTINCT_E_FACTORS)
SERIAL_ECHOPAIR_P(LIST_N(DOUBLE(LINEAR_AXES),
PSTR(" M92 X"), LINEAR_UNIT(planner.settings.axis_steps_per_mm[X_AXIS]),
SP_Y_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[Y_AXIS]),
SP_Z_STR, LINEAR_UNIT(planner.settings.axis_steps_per_mm[Z_AXIS])
));
#if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS)
SERIAL_ECHOPAIR_P(SP_E_STR, VOLUMETRIC_UNIT(planner.settings.axis_steps_per_mm[E_AXIS]));
#endif
SERIAL_EOL();
@ -64,25 +66,28 @@ void GcodeSuite::M92() {
if (target_extruder < 0) return;
// No arguments? Show M92 report.
if (!parser.seen("XYZE" TERN_(MAGIC_NUMBERS_GCODE, "HL")))
return report_M92(true, target_extruder);
if (!parser.seen(
LOGICAL_AXIS_GANG("E", "X", "Y", "Z")
TERN_(MAGIC_NUMBERS_GCODE, "HL")
)) return report_M92(true, target_extruder);
LOOP_LOGICAL_AXES(i) {
if (parser.seenval(axis_codes[i])) {
if (i == E_AXIS) {
const float value = parser.value_per_axis_units((AxisEnum)(E_AXIS_N(target_extruder)));
if (value < 20) {
float factor = planner.settings.axis_steps_per_mm[E_AXIS_N(target_extruder)] / value; // increase e constants if M92 E14 is given for netfab.
#if HAS_CLASSIC_JERK && HAS_CLASSIC_E_JERK
planner.max_jerk.e *= factor;
#endif
planner.settings.max_feedrate_mm_s[E_AXIS_N(target_extruder)] *= factor;
planner.max_acceleration_steps_per_s2[E_AXIS_N(target_extruder)] *= factor;
}
planner.settings.axis_steps_per_mm[E_AXIS_N(target_extruder)] = value;
}
else {
if (TERN1(HAS_EXTRUDERS, i != E_AXIS))
planner.settings.axis_steps_per_mm[i] = parser.value_per_axis_units((AxisEnum)i);
else {
#if HAS_EXTRUDERS
const float value = parser.value_per_axis_units((AxisEnum)(E_AXIS_N(target_extruder)));
if (value < 20) {
float factor = planner.settings.axis_steps_per_mm[E_AXIS_N(target_extruder)] / value; // increase e constants if M92 E14 is given for netfab.
#if HAS_CLASSIC_JERK && HAS_CLASSIC_E_JERK
planner.max_jerk.e *= factor;
#endif
planner.settings.max_feedrate_mm_s[E_AXIS_N(target_extruder)] *= factor;
planner.max_acceleration_steps_per_s2[E_AXIS_N(target_extruder)] *= factor;
}
planner.settings.axis_steps_per_mm[E_AXIS_N(target_extruder)] = value;
#endif
}
}
}

24
Marlin/src/gcode/control/M17_M18_M84.cpp

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

12
Marlin/src/gcode/feature/pause/G61.cpp

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

18
Marlin/src/gcode/feature/trinamic/M122.cpp

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

26
Marlin/src/gcode/gcode.cpp

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

37
Marlin/src/gcode/gcode.h

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

37
Marlin/src/gcode/geometry/G92.cpp

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

2
Marlin/src/gcode/host/M114.cpp

@ -170,7 +170,7 @@
SERIAL_ECHOPGM("FromStp:");
get_cartesian_from_steppers(); // writes 'cartes' (with forward kinematics)
xyze_pos_t from_steppers = { cartes.x, cartes.y, cartes.z, planner.get_axis_position_mm(E_AXIS) };
xyze_pos_t from_steppers = LOGICAL_AXIS_ARRAY(planner.get_axis_position_mm(E_AXIS), cartes.x, cartes.y, cartes.z);
report_all_axis_pos(from_steppers);
const xyze_float_t diff = from_steppers - leveled;

10
Marlin/src/gcode/motion/G0_G1.cpp

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

31
Marlin/src/gcode/motion/G2_G3.cpp

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

2
Marlin/src/gcode/motion/M290.cpp

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

3
Marlin/src/gcode/parser.cpp

@ -248,7 +248,8 @@ void GCodeParser::parse(char *p) {
case 'R': if (!WITHIN(motion_mode_codenum, 2, 3)) return;
#endif
case 'X' ... 'Z': case 'E' ... 'F':
LOGICAL_AXIS_GANG(case 'E':, case 'X':, case 'Y':, case 'Z':)
case 'F':
if (motion_mode_codenum < 0) return;
command_letter = 'G';
codenum = motion_mode_codenum;

2
Marlin/src/gcode/parser.h

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

94
Marlin/src/inc/Conditionals_LCD.h

@ -537,12 +537,12 @@
* E_STEPPERS - Number of actual E stepper motors
* E_MANUAL - Number of E steppers for LCD move options
*/
#if EXTRUDERS
#define HAS_EXTRUDERS 1
#if EXTRUDERS > 1
#define HAS_MULTI_EXTRUDER 1
#endif
#define E_AXIS_N(E) AxisEnum(E_AXIS + E_INDEX_N(E))
#else
#undef EXTRUDERS
#define EXTRUDERS 0
@ -551,6 +551,7 @@
#undef SWITCHING_NOZZLE
#undef MIXING_EXTRUDER
#undef HOTEND_IDLE_TIMEOUT
#undef DISABLE_E
#endif
#if ENABLED(SWITCHING_EXTRUDER) // One stepper for every two EXTRUDERS
@ -604,6 +605,50 @@
#define E_MANUAL EXTRUDERS
#endif
/**
* Number of Linear Axes (e.g., XYZ)
* All the logical axes except for the tool (E) axis
*/
#ifndef LINEAR_AXES
#define LINEAR_AXES XYZ
#endif
/**
* Number of Logical Axes (e.g., XYZE)
* All the logical axes that can be commanded directly by G-code.
* Delta maps stepper-specific values to ABC steppers.
*/
#if HAS_EXTRUDERS
#define LOGICAL_AXES INCREMENT(LINEAR_AXES)
#else
#define LOGICAL_AXES LINEAR_AXES
#endif
/**
* DISTINCT_E_FACTORS is set to give extruders (some) individual settings.
*
* DISTINCT_AXES is the number of distinct addressable axes (not steppers).
* Includes all linear axes plus all distinguished extruders.
* The default behavior is to treat all extruders as a single E axis
* with shared motion and temperature settings.
*
* DISTINCT_E is the number of distinguished extruders. By default this
* well be 1 which indicates all extruders share the same settings.
*
* E_INDEX_N(E) should be used to get the E index of any item that might be
* distinguished.
*/
#if ENABLED(DISTINCT_E_FACTORS) && E_STEPPERS > 1
#define DISTINCT_AXES (LINEAR_AXES + E_STEPPERS)
#define DISTINCT_E E_STEPPERS
#define E_INDEX_N(E) (E)
#else
#undef DISTINCT_E_FACTORS
#define DISTINCT_AXES LOGICAL_AXES
#define DISTINCT_E 1
#define E_INDEX_N(E) 0
#endif
#if HOTENDS
#define HAS_HOTEND 1
#ifndef HOTEND_OVERSHOOT
@ -624,10 +669,6 @@
#define ARRAY_BY_HOTENDS(V...) ARRAY_N(HOTENDS, V)
#define ARRAY_BY_HOTENDS1(v1) ARRAY_N_1(HOTENDS, v1)
#if ENABLED(SWITCHING_EXTRUDER) && (DISABLED(SWITCHING_NOZZLE) || SWITCHING_EXTRUDER_SERVO_NR != SWITCHING_NOZZLE_SERVO_NR)
#define DO_SWITCH_EXTRUDER 1
#endif
/**
* Default hotend offsets, if not defined
*/
@ -653,39 +694,10 @@
#undef SINGLENOZZLE_STANDBY_FAN
#endif
/**
* Number of Linear Axes (e.g., XYZ)
* All the logical axes except for the tool (E) axis
*/
#ifndef LINEAR_AXES
#define LINEAR_AXES XYZ
#endif
/**
* Number of Logical Axes (e.g., XYZE)
* All the logical axes that can be commanded directly by G-code.
* Delta maps stepper-specific values to ABC steppers.
*/
#if HAS_EXTRUDERS
#define LOGICAL_AXES INCREMENT(LINEAR_AXES)
#else
#define LOGICAL_AXES LINEAR_AXES
#endif
/**
* DISTINCT_E_FACTORS affects whether Extruders use different settings
*/
#if ENABLED(DISTINCT_E_FACTORS) && E_STEPPERS > 1
#define DISTINCT_E E_STEPPERS
#define DISTINCT_AXES (LINEAR_AXES + E_STEPPERS)
#define E_INDEX_N(E) (E)
#else
#undef DISTINCT_E_FACTORS
#define DISTINCT_E 1
#define DISTINCT_AXES LOGICAL_AXES
#define E_INDEX_N(E) 0
// Switching extruder has its own servo?
#if ENABLED(SWITCHING_EXTRUDER) && (DISABLED(SWITCHING_NOZZLE) || SWITCHING_EXTRUDER_SERVO_NR != SWITCHING_NOZZLE_SERVO_NR)
#define DO_SWITCH_EXTRUDER 1
#endif
#define E_AXIS_N(E) AxisEnum(E_AXIS + E_INDEX_N(E))
/**
* The BLTouch Probe emulates a servo probe
@ -726,6 +738,9 @@
#define HAS_BED_PROBE 1
#endif
/**
* Fill in undefined Filament Sensor options
*/
#if ENABLED(FILAMENT_RUNOUT_SENSOR)
#if NUM_RUNOUT_SENSORS >= 1
#ifndef FIL_RUNOUT1_STATE
@ -834,6 +849,9 @@
#define Z_HOME_TO_MIN 1
#endif
/**
* Conditionals based on the type of Bed Probe
*/
#if HAS_BED_PROBE
#if DISABLED(NOZZLE_AS_PROBE)
#define HAS_PROBE_XY_OFFSET 1
@ -868,7 +886,7 @@
#endif
/**
* Set granular options based on the specific type of leveling
* Conditionals based on the type of Bed Leveling
*/
#if ENABLED(AUTO_BED_LEVELING_UBL)
#undef LCD_BED_LEVELING

20
Marlin/src/inc/Conditionals_adv.h

@ -103,6 +103,9 @@
#undef THERMAL_PROTECTION_PERIOD
#undef WATCH_TEMP_PERIOD
#undef SHOW_TEMP_ADC_VALUES
#undef LCD_SHOW_E_TOTAL
#undef MANUAL_E_MOVES_RELATIVE
#undef STEALTHCHOP_E
#endif
#if TEMP_SENSOR_BED == 0
@ -482,6 +485,23 @@
#endif
#endif
// Remove unused STEALTHCHOP flags
#if LINEAR_AXES < 6
#undef STEALTHCHOP_K
#if LINEAR_AXES < 5
#undef STEALTHCHOP_J
#if LINEAR_AXES < 4
#undef STEALTHCHOP_I
#if LINEAR_AXES < 3
#undef STEALTHCHOP_Z
#if LINEAR_AXES < 2
#undef STEALTHCHOP_Y
#endif
#endif
#endif
#endif
#endif
//
// SD Card connection methods
// Defined here so pins and sanity checks can use them

249
Marlin/src/inc/Conditionals_post.h

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

27
Marlin/src/inc/SanityCheck.h

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

6
Marlin/src/lcd/dogm/status_screen_DOGM.cpp

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

8
Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp

@ -666,10 +666,10 @@ const struct DGUS_VP_Variable ListOfVP[] PROGMEM = {
VPHELPER(VP_Z_MAX_SPEED, &planner.settings.max_feedrate_mm_s[Z_AXIS], ScreenHandler.HandleMaxSpeedChange_MKS, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<0>),
#if HOTENDS >= 1
VPHELPER(VP_E0_MAX_SPEED, &planner.settings.max_feedrate_mm_s[E0_AXIS], ScreenHandler.HandleExtruderMaxSpeedChange_MKS, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<0>),
VPHELPER(VP_E0_MAX_SPEED, &planner.settings.max_feedrate_mm_s[E_AXIS_N(0)], ScreenHandler.HandleExtruderMaxSpeedChange_MKS, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<0>),
#endif
#if HOTENDS >= 2
VPHELPER(VP_E1_MAX_SPEED, &planner.settings.max_feedrate_mm_s[E1_AXIS], ScreenHandler.HandleExtruderMaxSpeedChange_MKS, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<0>),
VPHELPER(VP_E1_MAX_SPEED, &planner.settings.max_feedrate_mm_s[E_AXIS_N(1)], ScreenHandler.HandleExtruderMaxSpeedChange_MKS, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<0>),
#endif
VPHELPER(VP_X_ACC_MAX_SPEED, (uint16_t *)&planner.settings.max_acceleration_mm_per_s2[X_AXIS], ScreenHandler.HandleMaxAccChange_MKS, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
@ -677,10 +677,10 @@ const struct DGUS_VP_Variable ListOfVP[] PROGMEM = {
VPHELPER(VP_Z_ACC_MAX_SPEED, (uint16_t *)&planner.settings.max_acceleration_mm_per_s2[Z_AXIS], ScreenHandler.HandleMaxAccChange_MKS, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
#if HOTENDS >= 1
VPHELPER(VP_E0_ACC_MAX_SPEED, (uint16_t *)&planner.settings.max_acceleration_mm_per_s2[E0_AXIS], ScreenHandler.HandleExtruderAccChange_MKS, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
VPHELPER(VP_E0_ACC_MAX_SPEED, (uint16_t *)&planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(0)], ScreenHandler.HandleExtruderAccChange_MKS, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
#endif
#if HOTENDS >= 2
VPHELPER(VP_E1_ACC_MAX_SPEED, (uint16_t *)&planner.settings.max_acceleration_mm_per_s2[E1_AXIS], ScreenHandler.HandleExtruderAccChange_MKS, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
VPHELPER(VP_E1_ACC_MAX_SPEED, (uint16_t *)&planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(1)], ScreenHandler.HandleExtruderAccChange_MKS, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
#endif
VPHELPER(VP_TRAVEL_SPEED, (uint16_t *)&planner.settings.travel_acceleration, ScreenHandler.HandleTravelAccChange_MKS, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<0>),

10
Marlin/src/lcd/marlinui.cpp

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

40
Marlin/src/lcd/menu/menu_advanced.cpp

@ -68,10 +68,7 @@ void menu_backlash();
START_MENU();
BACK_ITEM(MSG_ADVANCED_SETTINGS);
#define EDIT_DAC_PERCENT(A) EDIT_ITEM(uint8, MSG_DAC_PERCENT_##A, &driverPercent[_AXIS(A)], 0, 100, []{ stepper_dac.set_current_percents(driverPercent); })
EDIT_DAC_PERCENT(X);
EDIT_DAC_PERCENT(Y);
EDIT_DAC_PERCENT(Z);
EDIT_DAC_PERCENT(E);
LOGICAL_AXIS_CODE(EDIT_DAC_PERCENT(E), EDIT_DAC_PERCENT(X), EDIT_DAC_PERCENT(Y), EDIT_DAC_PERCENT(Z), EDIT_DAC_PERCENT(I), EDIT_DAC_PERCENT(J), EDIT_DAC_PERCENT(K));
ACTION_ITEM(MSG_DAC_EEPROM_WRITE, stepper_dac.commit_eeprom);
END_MENU();
}
@ -359,7 +356,7 @@ void menu_backlash();
#elif ENABLED(LIMITED_MAX_FR_EDITING)
DEFAULT_MAX_FEEDRATE
#else
{ 9999, 9999, 9999, 9999 }
LOGICAL_AXIS_ARRAY(9999, 9999, 9999, 9999)
#endif
;
#if ENABLED(LIMITED_MAX_FR_EDITING) && !defined(MAX_FEEDRATE_EDIT_VALUES)
@ -372,9 +369,7 @@ void menu_backlash();
BACK_ITEM(MSG_ADVANCED_SETTINGS);
#define EDIT_VMAX(N) EDIT_ITEM_FAST(float5, MSG_VMAX_##N, &planner.settings.max_feedrate_mm_s[_AXIS(N)], 1, max_fr_edit_scaled[_AXIS(N)])
EDIT_VMAX(A);
EDIT_VMAX(B);
EDIT_VMAX(C);
LINEAR_AXIS_CODE(EDIT_VMAX(A), EDIT_VMAX(B), EDIT_VMAX(C), EDIT_VMAX(I), EDIT_VMAX(J), EDIT_VMAX(K));
#if E_STEPPERS
EDIT_ITEM_FAST(float5, MSG_VMAX_E, &planner.settings.max_feedrate_mm_s[E_AXIS_N(active_extruder)], 1, max_fr_edit_scaled.e);
@ -404,7 +399,7 @@ void menu_backlash();
#elif ENABLED(LIMITED_MAX_ACCEL_EDITING)
DEFAULT_MAX_ACCELERATION
#else
{ 99000, 99000, 99000, 99000 }
LOGICAL_AXIS_ARRAY(99000, 99000, 99000, 99000)
#endif
;
#if ENABLED(LIMITED_MAX_ACCEL_EDITING) && !defined(MAX_ACCEL_EDIT_VALUES)
@ -419,16 +414,19 @@ void menu_backlash();
// M204 P Acceleration
EDIT_ITEM_FAST(float5_25, MSG_ACC, &planner.settings.acceleration, 25, max_accel);
// M204 R Retract Acceleration
EDIT_ITEM_FAST(float5, MSG_A_RETRACT, &planner.settings.retract_acceleration, 100, planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(active_extruder)]);
#if HAS_EXTRUDERS
// M204 R Retract Acceleration
EDIT_ITEM_FAST(float5, MSG_A_RETRACT, &planner.settings.retract_acceleration, 100, planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(active_extruder)]);
#endif
// M204 T Travel Acceleration
EDIT_ITEM_FAST(float5_25, MSG_A_TRAVEL, &planner.settings.travel_acceleration, 25, max_accel);
#define EDIT_AMAX(Q,L) EDIT_ITEM_FAST(long5_25, MSG_AMAX_##Q, &planner.settings.max_acceleration_mm_per_s2[_AXIS(Q)], L, max_accel_edit_scaled[_AXIS(Q)], []{ planner.reset_acceleration_rates(); })
EDIT_AMAX(A, 100);
EDIT_AMAX(B, 100);
EDIT_AMAX(C, 10);
LINEAR_AXIS_CODE(
EDIT_AMAX(A, 100), EDIT_AMAX(B, 100), EDIT_AMAX(C, 10),
EDIT_AMAX(I, 10), EDIT_AMAX(J, 10), EDIT_AMAX(K, 10)
);
#if ENABLED(DISTINCT_E_FACTORS)
EDIT_ITEM_FAST(long5_25, MSG_AMAX_E, &planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(active_extruder)], 100, max_accel_edit_scaled.e, []{ planner.reset_acceleration_rates(); });
@ -474,14 +472,14 @@ void menu_backlash();
#endif
;
#define EDIT_JERK(N) EDIT_ITEM_FAST(float3, MSG_V##N##_JERK, &planner.max_jerk[_AXIS(N)], 1, max_jerk_edit[_AXIS(N)])
EDIT_JERK(A);
EDIT_JERK(B);
#if ENABLED(DELTA)
EDIT_JERK(C);
#define EDIT_JERK_C() EDIT_JERK(C)
#else
EDIT_ITEM_FAST(float52sign, MSG_VC_JERK, &planner.max_jerk.c, 0.1f, max_jerk_edit.c);
#define EDIT_JERK_C() EDIT_ITEM_FAST(float52sign, MSG_VC_JERK, &planner.max_jerk.c, 0.1f, max_jerk_edit.c)
#endif
#if HAS_CLASSIC_E_JERK
LINEAR_AXIS_CODE(EDIT_JERK(A), EDIT_JERK(B), EDIT_JERK_C());
#if HAS_EXTRUDERS
EDIT_ITEM_FAST(float52sign, MSG_VE_JERK, &planner.max_jerk.e, 0.1f, max_jerk_edit.e);
#endif
@ -517,9 +515,7 @@ void menu_advanced_steps_per_mm() {
BACK_ITEM(MSG_ADVANCED_SETTINGS);
#define EDIT_QSTEPS(Q) EDIT_ITEM_FAST(float51, MSG_##Q##_STEPS, &planner.settings.axis_steps_per_mm[_AXIS(Q)], 5, 9999, []{ planner.refresh_positioning(); })
EDIT_QSTEPS(A);
EDIT_QSTEPS(B);
EDIT_QSTEPS(C);
LINEAR_AXIS_CODE(EDIT_QSTEPS(A), EDIT_QSTEPS(B), EDIT_QSTEPS(C));
#if ENABLED(DISTINCT_E_FACTORS)
LOOP_L_N(n, E_STEPPERS)

11
Marlin/src/module/endstops.cpp

@ -361,7 +361,8 @@ void Endstops::event_handler() {
prev_hit_state = hit_state;
if (hit_state) {
#if HAS_STATUS_MESSAGE
char chrX = ' ', chrY = ' ', chrZ = ' ', chrP = ' ';
char LINEAR_AXIS_LIST(chrX = ' ', chrY = ' ', chrZ = ' '),
chrP = ' ';
#define _SET_STOP_CHAR(A,C) (chr## A = C)
#else
#define _SET_STOP_CHAR(A,C) NOOP
@ -390,7 +391,13 @@ void Endstops::event_handler() {
#endif
SERIAL_EOL();
TERN_(HAS_STATUS_MESSAGE, ui.status_printf_P(0, PSTR(S_FMT " %c %c %c %c"), GET_TEXT(MSG_LCD_ENDSTOPS), chrX, chrY, chrZ, chrP));
TERN_(HAS_STATUS_MESSAGE,
ui.status_printf_P(0,
PSTR(S_FMT GANG_N_1(LINEAR_AXES, " %c") " %c"),
GET_TEXT(MSG_LCD_ENDSTOPS),
LINEAR_AXIS_LIST(chrX, chrY, chrZ), chrP
)
);
#if BOTH(SD_ABORT_ON_ENDSTOP_HIT, SDSUPPORT)
if (planner.abort_on_endstop_hit) {

102
Marlin/src/module/motion.cpp

@ -89,7 +89,7 @@ bool relative_mode; // = false;
#define Z_INIT_POS Z_HOME_POS
#endif
xyze_pos_t current_position = { X_HOME_POS, Y_HOME_POS, Z_INIT_POS };
xyze_pos_t current_position = LOGICAL_AXIS_ARRAY(0, X_HOME_POS, Y_HOME_POS, Z_INIT_POS);
/**
* Cartesian Destination
@ -195,16 +195,25 @@ inline void report_more_positions() {
// Report the logical position for a given machine position
inline void report_logical_position(const xyze_pos_t &rpos) {
const xyze_pos_t lpos = rpos.asLogical();
SERIAL_ECHOPAIR_P(X_LBL, lpos.x, SP_Y_LBL, lpos.y, SP_Z_LBL, lpos.z, SP_E_LBL, lpos.e);
SERIAL_ECHOPAIR_P(
LIST_N(DOUBLE(LINEAR_AXES), X_LBL, lpos.x, SP_Y_LBL, lpos.y, SP_Z_LBL, lpos.z)
#if HAS_EXTRUDERS
, SP_E_LBL, lpos.e
#endif
);
}
// Report the real current position according to the steppers.
// Forward kinematics and un-leveling are applied.
void report_real_position() {
get_cartesian_from_steppers();
xyze_pos_t npos = cartes;
npos.e = planner.get_axis_position_mm(E_AXIS);
xyze_pos_t npos = LOGICAL_AXIS_ARRAY(
planner.get_axis_position_mm(E_AXIS),
cartes.x, cartes.y, cartes.z
);
TERN_(HAS_POSITION_MODIFIERS, planner.unapply_modifiers(npos, true));
report_logical_position(npos);
report_more_positions();
}
@ -309,7 +318,9 @@ void sync_plan_position() {
planner.set_position_mm(current_position);
}
void sync_plan_position_e() { planner.set_e_position_mm(current_position.e); }
#if HAS_EXTRUDERS
void sync_plan_position_e() { planner.set_e_position_mm(current_position.e); }
#endif
/**
* Get the stepper positions in the cartes[] array.
@ -354,7 +365,10 @@ void get_cartesian_from_steppers() {
void set_current_from_steppers_for_axis(const AxisEnum axis) {
get_cartesian_from_steppers();
xyze_pos_t pos = cartes;
pos.e = planner.get_axis_position_mm(E_AXIS);
#if HAS_EXTRUDERS
pos.e = planner.get_axis_position_mm(E_AXIS);
#endif
#if HAS_POSITION_MODIFIERS
planner.unapply_modifiers(pos, true);
@ -442,9 +456,12 @@ void _internal_move_to_destination(const_feedRate_t fr_mm_s/*=0.0f*/
* - Delta may lower Z first to get into the free motion zone.
* - Before returning, wait for the planner buffer to empty.
*/
void do_blocking_move_to(const float rx, const float ry, const float rz, const_feedRate_t fr_mm_s/*=0.0*/) {
void do_blocking_move_to(
LINEAR_AXIS_LIST(const float rx, const float ry, const float rz),
const_feedRate_t fr_mm_s/*=0.0f*/
) {
DEBUG_SECTION(log_move, "do_blocking_move_to", DEBUGGING(LEVELING));
if (DEBUGGING(LEVELING)) DEBUG_XYZ("> ", rx, ry, rz);
if (DEBUGGING(LEVELING)) DEBUG_XYZ("> ", LINEAR_AXIS_LIST(rx, ry, rz));
const feedRate_t z_feedrate = fr_mm_s ?: homing_feedrate(Z_AXIS),
xy_feedrate = fr_mm_s ?: feedRate_t(XY_PROBE_FEEDRATE_MM_S);
@ -529,34 +546,46 @@ void do_blocking_move_to(const float rx, const float ry, const float rz, const_f
}
void do_blocking_move_to(const xy_pos_t &raw, const_feedRate_t fr_mm_s/*=0.0f*/) {
do_blocking_move_to(raw.x, raw.y, current_position.z, fr_mm_s);
do_blocking_move_to(LINEAR_AXIS_LIST(raw.x, raw.y, current_position.z, current_position.i), fr_mm_s);
}
void do_blocking_move_to(const xyz_pos_t &raw, const_feedRate_t fr_mm_s/*=0.0f*/) {
do_blocking_move_to(raw.x, raw.y, raw.z, fr_mm_s);
do_blocking_move_to(LINEAR_AXIS_LIST(raw.x, raw.y, raw.z), fr_mm_s);
}
void do_blocking_move_to(const xyze_pos_t &raw, const_feedRate_t fr_mm_s/*=0.0f*/) {
do_blocking_move_to(raw.x, raw.y, raw.z, fr_mm_s);
do_blocking_move_to(LINEAR_AXIS_LIST(raw.x, raw.y, raw.z), fr_mm_s);
}
void do_blocking_move_to_x(const_float_t rx, const_feedRate_t fr_mm_s/*=0.0*/) {
do_blocking_move_to(rx, current_position.y, current_position.z, fr_mm_s);
do_blocking_move_to(
LINEAR_AXIS_LIST(rx, current_position.y, current_position.z),
fr_mm_s
);
}
void do_blocking_move_to_y(const_float_t ry, const_feedRate_t fr_mm_s/*=0.0*/) {
do_blocking_move_to(current_position.x, ry, current_position.z, fr_mm_s);
do_blocking_move_to(
LINEAR_AXIS_LIST(current_position.x, ry, current_position.z),
fr_mm_s
);
}
void do_blocking_move_to_z(const_float_t rz, const_feedRate_t fr_mm_s/*=0.0*/) {
do_blocking_move_to_xy_z(current_position, rz, fr_mm_s);
}
void do_blocking_move_to_xy(const_float_t rx, const_float_t ry, const_feedRate_t fr_mm_s/*=0.0*/) {
do_blocking_move_to(rx, ry, current_position.z, fr_mm_s);
do_blocking_move_to(
LINEAR_AXIS_LIST(rx, ry, current_position.z),
fr_mm_s
);
}
void do_blocking_move_to_xy(const xy_pos_t &raw, const_feedRate_t fr_mm_s/*=0.0f*/) {
do_blocking_move_to_xy(raw.x, raw.y, fr_mm_s);
}
void do_blocking_move_to_xy_z(const xy_pos_t &raw, const_float_t z, const_feedRate_t fr_mm_s/*=0.0f*/) {
do_blocking_move_to(raw.x, raw.y, z, fr_mm_s);
do_blocking_move_to(
LINEAR_AXIS_LIST(raw.x, raw.y, z),
fr_mm_s
);
}
void do_z_clearance(const_float_t zclear, const bool lower_allowed/*=false*/) {
@ -589,8 +618,8 @@ void restore_feedrate_and_scaling() {
// Software Endstops are based on the configured limits.
soft_endstops_t soft_endstop = {
true, false,
{ X_MIN_POS, Y_MIN_POS, Z_MIN_POS },
{ X_MAX_POS, Y_MAX_POS, Z_MAX_POS }
LINEAR_AXIS_ARRAY(X_MIN_POS, Y_MIN_POS, Z_MIN_POS),
LINEAR_AXIS_ARRAY(X_MAX_BED, Y_MAX_BED, Z_MAX_POS)
};
/**
@ -1176,9 +1205,12 @@ void prepare_line_to_destination() {
if (TEST(b, a) && TERN(HOME_AFTER_DEACTIVATE, axis_is_trusted, axis_was_homed)(a))
CBI(b, a);
};
set_should(axis_bits, X_AXIS); // Clear test bits that are trusted
set_should(axis_bits, Y_AXIS);
set_should(axis_bits, Z_AXIS);
// Clear test bits that are trusted
LINEAR_AXIS_CODE(
set_should(axis_bits, X_AXIS),
set_should(axis_bits, Y_AXIS),
set_should(axis_bits, Z_AXIS)
);
return axis_bits;
}
@ -1187,9 +1219,11 @@ void prepare_line_to_destination() {
PGM_P home_first = GET_TEXT(MSG_HOME_FIRST);
char msg[strlen_P(home_first)+1];
sprintf_P(msg, home_first,
TEST(axis_bits, X_AXIS) ? "X" : "",
TEST(axis_bits, Y_AXIS) ? "Y" : "",
TEST(axis_bits, Z_AXIS) ? "Z" : ""
LINEAR_AXIS_LIST(
TEST(axis_bits, X_AXIS) ? "X" : "",
TEST(axis_bits, Y_AXIS) ? "Y" : "",
TEST(axis_bits, Z_AXIS) ? "Z" : ""
)
);
SERIAL_ECHO_START();
SERIAL_ECHOLN(msg);
@ -1356,7 +1390,7 @@ void prepare_line_to_destination() {
const feedRate_t home_fr_mm_s = fr_mm_s ?: homing_feedrate(axis);
if (DEBUGGING(LEVELING)) {
DEBUG_ECHOPAIR("...(", AS_CHAR(axis_codes[axis]), ", ", distance, ", ");
DEBUG_ECHOPAIR("...(", AS_CHAR(AXIS_CHAR(axis)), ", ", distance, ", ");
if (fr_mm_s)
DEBUG_ECHO(fr_mm_s);
else
@ -1441,12 +1475,12 @@ void prepare_line_to_destination() {
* "trusted" position).
*/
void set_axis_never_homed(const AxisEnum axis) {
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR(">>> set_axis_never_homed(", AS_CHAR(axis_codes[axis]), ")");
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR(">>> set_axis_never_homed(", AS_CHAR(AXIS_CHAR(axis)), ")");
set_axis_untrusted(axis);
set_axis_unhomed(axis);
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("<<< set_axis_never_homed(", AS_CHAR(axis_codes[axis]), ")");
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("<<< set_axis_never_homed(", AS_CHAR(AXIS_CHAR(axis)), ")");
TERN_(I2C_POSITION_ENCODERS, I2CPEM.unhomed(axis));
}
@ -1507,7 +1541,7 @@ void prepare_line_to_destination() {
if (ABS(phaseDelta) * planner.steps_to_mm[axis] / phasePerUStep < 0.05f)
SERIAL_ECHOLNPAIR("Selected home phase ", home_phase[axis],
" too close to endstop trigger phase ", phaseCurrent,
". Pick a different phase for ", AS_CHAR(axis_codes[axis]));
". Pick a different phase for ", AS_CHAR(AXIS_CHAR(axis)));
// Skip to next if target position is behind current. So it only moves away from endstop.
if (phaseDelta < 0) phaseDelta += 1024;
@ -1518,7 +1552,7 @@ void prepare_line_to_destination() {
// Optional debug messages
if (DEBUGGING(LEVELING)) {
DEBUG_ECHOLNPAIR(
"Endstop ", AS_CHAR(axis_codes[axis]), " hit at Phase:", phaseCurrent,
"Endstop ", AS_CHAR(AXIS_CHAR(axis)), " hit at Phase:", phaseCurrent,
" Delta:", phaseDelta, " Distance:", mmDelta
);
}
@ -1556,7 +1590,7 @@ void prepare_line_to_destination() {
if (!_CAN_HOME(X) && !_CAN_HOME(Y) && !_CAN_HOME(Z)) return;
#endif
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR(">>> homeaxis(", AS_CHAR(axis_codes[axis]), ")");
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR(">>> homeaxis(", AS_CHAR(AXIS_CHAR(axis)), ")");
const int axis_home_dir = TERN0(DUAL_X_CARRIAGE, axis == X_AXIS)
? TOOL_X_HOME_DIR(active_extruder) : home_dir(axis);
@ -1634,7 +1668,7 @@ void prepare_line_to_destination() {
case Z_AXIS: es = Z_ENDSTOP; break;
}
if (TEST(endstops.state(), es)) {
SERIAL_ECHO_MSG("Bad ", AS_CHAR(axis_codes[axis]), " Endstop?");
SERIAL_ECHO_MSG("Bad ", AS_CHAR(AXIS_CHAR(axis)), " Endstop?");
kill(GET_TEXT(MSG_KILL_HOMING_FAILED));
}
#endif
@ -1856,7 +1890,7 @@ void prepare_line_to_destination() {
if (axis == Z_AXIS) fwretract.current_hop = 0.0;
#endif
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("<<< homeaxis(", AS_CHAR(axis_codes[axis]), ")");
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("<<< homeaxis(", AS_CHAR(AXIS_CHAR(axis)), ")");
} // homeaxis()
@ -1881,7 +1915,7 @@ void prepare_line_to_destination() {
* Callers must sync the planner position after calling this!
*/
void set_axis_is_at_home(const AxisEnum axis) {
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR(">>> set_axis_is_at_home(", AS_CHAR(axis_codes[axis]), ")");
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR(">>> set_axis_is_at_home(", AS_CHAR(AXIS_CHAR(axis)), ")");
set_axis_trusted(axis);
set_axis_homed(axis);
@ -1931,10 +1965,10 @@ void set_axis_is_at_home(const AxisEnum axis) {
if (DEBUGGING(LEVELING)) {
#if HAS_HOME_OFFSET
DEBUG_ECHOLNPAIR("> home_offset[", AS_CHAR(axis_codes[axis]), "] = ", home_offset[axis]);
DEBUG_ECHOLNPAIR("> home_offset[", AS_CHAR(AXIS_CHAR(axis)), "] = ", home_offset[axis]);
#endif
DEBUG_POS("", current_position);
DEBUG_ECHOLNPAIR("<<< set_axis_is_at_home(", AS_CHAR(axis_codes[axis]), ")");
DEBUG_ECHOLNPAIR("<<< set_axis_is_at_home(", AS_CHAR(AXIS_CHAR(axis)), ")");
}
}

14
Marlin/src/module/motion.h

@ -124,7 +124,7 @@ inline int8_t pgm_read_any(const int8_t *p) { return TERN(__IMXRT1062__, *p, pgm
#define XYZ_DEFS(T, NAME, OPT) \
inline T NAME(const AxisEnum axis) { \
static const XYZval<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]); \
}
XYZ_DEFS(float, base_min_pos, MIN_POS);
@ -264,7 +264,10 @@ void quickstop_stepper();
* no kinematic translation. Used for homing axes and cartesian/core syncing.
*/
void sync_plan_position();
void sync_plan_position_e();
#if HAS_EXTRUDERS
void sync_plan_position_e();
#endif
/**
* Move the planner to the current position from wherever it last moved
@ -295,7 +298,10 @@ inline void prepare_internal_move_to_destination(const_feedRate_t fr_mm_s=0.0f)
/**
* Blocking movement and shorthand functions
*/
void do_blocking_move_to(const float rx, const float ry, const float rz, const_feedRate_t fr_mm_s=0.0f);
void do_blocking_move_to(
LINEAR_AXIS_LIST(const float rx, const float ry, const float rz),
const_feedRate_t fr_mm_s=0.0f
);
void do_blocking_move_to(const xy_pos_t &raw, const_feedRate_t fr_mm_s=0.0f);
void do_blocking_move_to(const xyz_pos_t &raw, const_feedRate_t fr_mm_s=0.0f);
void do_blocking_move_to(const xyze_pos_t &raw, const_feedRate_t fr_mm_s=0.0f);
@ -322,7 +328,7 @@ void do_z_clearance(const_float_t zclear, const bool lower_allowed=false);
/**
* Homing and Trusted Axes
*/
typedef IF<(LINEAR_AXES>8), uint16_t, uint8_t>::type linear_axis_bits_t;
typedef IF<(LINEAR_AXES > 8), uint16_t, uint8_t>::type linear_axis_bits_t;
constexpr linear_axis_bits_t linear_bits = _BV(LINEAR_AXES) - 1;
void set_axis_is_at_home(const AxisEnum axis);

266
Marlin/src/module/planner.cpp

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

50
Marlin/src/module/planner.h

@ -76,7 +76,7 @@
// Feedrate for manual moves
#ifdef MANUAL_FEEDRATE
constexpr xyze_feedrate_t _mf = MANUAL_FEEDRATE,
manual_feedrate_mm_s { _mf.x / 60.0f, _mf.y / 60.0f, _mf.z / 60.0f, _mf.e / 60.0f };
manual_feedrate_mm_s = LOGICAL_AXIS_ARRAY(_mf.e / 60.0f, _mf.x / 60.0f, _mf.y / 60.0f, _mf.z / 60.0f);
#endif
#if IS_KINEMATIC && HAS_JUNCTION_DEVIATION
@ -758,7 +758,8 @@ class Planner {
* extruder - target extruder
* millimeters - the length of the movement, if known
*/
static bool buffer_segment(const_float_t a, const_float_t b, const_float_t c, const_float_t e
static bool buffer_segment(
LOGICAL_AXIS_LIST(const_float_t e, const_float_t a, const_float_t b, const_float_t c)
OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm)
, const_feedRate_t fr_mm_s, const uint8_t extruder, const_float_t millimeters=0.0
);
@ -767,9 +768,11 @@ class Planner {
OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm)
, const_feedRate_t fr_mm_s, const uint8_t extruder, const_float_t millimeters=0.0
) {
return buffer_segment(abce.a, abce.b, abce.c, abce.e
return buffer_segment(
LOGICAL_AXIS_LIST(abce.e, abce.a, abce.b, abce.c)
OPTARG(HAS_DIST_MM_ARG, cart_dist_mm)
, fr_mm_s, extruder, millimeters);
, fr_mm_s, extruder, millimeters
);
}
public:
@ -785,14 +788,18 @@ class Planner {
* millimeters - the length of the movement, if known
* inv_duration - the reciprocal if the duration of the movement, if known (kinematic only if feeedrate scaling is enabled)
*/
static bool buffer_line(const_float_t rx, const_float_t ry, const_float_t rz, const_float_t e, const_feedRate_t fr_mm_s, const uint8_t extruder, const float millimeters=0.0
static bool buffer_line(
LOGICAL_AXIS_LIST(const_float_t e, const_float_t rx, const_float_t ry, const_float_t rz)
, const feedRate_t &fr_mm_s, const uint8_t extruder, const float millimeters=0.0
OPTARG(SCARA_FEEDRATE_SCALING, const_float_t inv_duration=0.0)
);
FORCE_INLINE static bool buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s, const uint8_t extruder, const float millimeters=0.0
OPTARG(SCARA_FEEDRATE_SCALING, const_float_t inv_duration=0.0)
) {
return buffer_line(cart.x, cart.y, cart.z, cart.e, fr_mm_s, extruder, millimeters
return buffer_line(
LOGICAL_AXIS_LIST(cart.e, cart.x, cart.y, cart.z)
, fr_mm_s, extruder, millimeters
OPTARG(SCARA_FEEDRATE_SCALING, inv_duration)
);
}
@ -814,9 +821,16 @@ class Planner {
*
* Clears previous speed values.
*/
static void set_position_mm(const_float_t rx, const_float_t ry, const_float_t rz, const_float_t e);
FORCE_INLINE static void set_position_mm(const xyze_pos_t &cart) { set_position_mm(cart.x, cart.y, cart.z, cart.e); }
static void set_e_position_mm(const_float_t e);
static void set_position_mm(
LOGICAL_AXIS_LIST(const_float_t e, const_float_t rx, const_float_t ry, const_float_t rz)
);
FORCE_INLINE static void set_position_mm(const xyze_pos_t &cart) {
set_position_mm(LOGICAL_AXIS_LIST(cart.e, cart.x, cart.y, cart.z, cart.i, cart.j, cart.k));
}
#if HAS_EXTRUDERS
static void set_e_position_mm(const_float_t e);
#endif
/**
* Set the planner.position and individual stepper positions.
@ -824,8 +838,12 @@ class Planner {
* The supplied position is in machine space, and no additional
* conversions are applied.
*/
static void set_machine_position_mm(const_float_t a, const_float_t b, const_float_t c, const_float_t e);
FORCE_INLINE static void set_machine_position_mm(const abce_pos_t &abce) { set_machine_position_mm(abce.a, abce.b, abce.c, abce.e); }
static void set_machine_position_mm(
LOGICAL_AXIS_LIST(const_float_t e, const_float_t a, const_float_t b, const_float_t c)
);
FORCE_INLINE static void set_machine_position_mm(const abce_pos_t &abce) {
set_machine_position_mm(LOGICAL_AXIS_LIST(abce.e, abce.a, abce.b, abce.c));
}
/**
* Get an axis position according to stepper position(s)
@ -834,12 +852,10 @@ class Planner {
static float get_axis_position_mm(const AxisEnum axis);
static inline abce_pos_t get_axis_positions_mm() {
const abce_pos_t out = {
get_axis_position_mm(A_AXIS),
get_axis_position_mm(B_AXIS),
get_axis_position_mm(C_AXIS),
get_axis_position_mm(E_AXIS)
};
const abce_pos_t out = LOGICAL_AXIS_ARRAY(
get_axis_position_mm(E_AXIS),
get_axis_position_mm(A_AXIS), get_axis_position_mm(B_AXIS), get_axis_position_mm(C_AXIS)
);
return out;
}

46
Marlin/src/module/settings.cpp

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

56
Marlin/src/module/stepper.cpp

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

16
Marlin/src/module/stepper.h

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

23
Marlin/src/module/stepper/trinamic.cpp

@ -35,7 +35,9 @@
#include <HardwareSerial.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)
// IC = TMC model number
@ -400,7 +402,7 @@ enum StealthIndex : uint8_t { STEALTH_AXIS_XY, STEALTH_AXIS_Z, STEALTH_AXIS_E };
#endif
#endif
enum TMCAxis : uint8_t { X, Y, Z, X2, Y2, Z2, Z3, Z4, E0, E1, E2, E3, E4, E5, E6, E7, TOTAL };
enum TMCAxis : uint8_t { LINEAR_AXIS_LIST(X, Y, Z), X2, Y2, Z2, Z3, Z4, E0, E1, E2, E3, E4, E5, E6, E7, TOTAL };
void tmc_serial_begin() {
#if HAS_TMC_HW_SERIAL
@ -765,19 +767,24 @@ void restore_trinamic_drivers() {
}
void reset_trinamic_drivers() {
static constexpr bool stealthchop_by_axis[] = { ENABLED(STEALTHCHOP_XY), ENABLED(STEALTHCHOP_Z), ENABLED(STEALTHCHOP_E) };
static constexpr bool stealthchop_by_axis[] = LOGICAL_AXIS_ARRAY(
ENABLED(STEALTHCHOP_E),
ENABLED(STEALTHCHOP_XY),
ENABLED(STEALTHCHOP_XY),
ENABLED(STEALTHCHOP_Z)
);
#if AXIS_IS_TMC(X)
TMC_INIT(X, STEALTH_AXIS_XY);
TMC_INIT(X, STEALTH_AXIS_X);
#endif
#if AXIS_IS_TMC(X2)
TMC_INIT(X2, STEALTH_AXIS_XY);
TMC_INIT(X2, STEALTH_AXIS_X);
#endif
#if AXIS_IS_TMC(Y)
TMC_INIT(Y, STEALTH_AXIS_XY);
TMC_INIT(Y, STEALTH_AXIS_Y);
#endif
#if AXIS_IS_TMC(Y2)
TMC_INIT(Y2, STEALTH_AXIS_XY);
TMC_INIT(Y2, STEALTH_AXIS_Y);
#endif
#if AXIS_IS_TMC(Z)
TMC_INIT(Z, STEALTH_AXIS_Z);
@ -841,7 +848,7 @@ void reset_trinamic_drivers() {
stepperZ4.homing_threshold(CAT(TERN(Z4_SENSORLESS, Z4, Z), _STALL_SENSITIVITY));
#endif
#endif
#endif
#endif // USE SENSORLESS
#ifdef TMC_ADV
TMC_ADV()

12
buildroot/tests/mega2560

@ -171,10 +171,12 @@ exec_test $1 $2 "Azteeg X3 | Mixing Extruder (x5) | Gradient Mix | Greek" "$3"
# Test Laser features with 12864 LCD
#
restore_configs
opt_set MOTHERBOARD BOARD_RAMPS_14_EFB LCD_LANGUAGE en TEMP_SENSOR_COOLER 1 EXTRUDERS 0 TEMP_SENSOR_1 0 SERIAL_PORT_2 2 \
opt_set MOTHERBOARD BOARD_RAMPS_14_EFB EXTRUDERS 0 LCD_LANGUAGE en TEMP_SENSOR_COOLER 1 TEMP_SENSOR_1 0 SERIAL_PORT_2 2 \
DEFAULT_AXIS_STEPS_PER_UNIT '{ 80, 80, 400 }' \
DEFAULT_MAX_FEEDRATE '{ 300, 300, 5 }' \
DEFAULT_MAX_ACCELERATION '{ 3000, 3000, 100 }'
DEFAULT_MAX_ACCELERATION '{ 3000, 3000, 100 }' \
MANUAL_FEEDRATE '{ 50*60, 50*60, 4*60 }' \
AXIS_RELATIVE_MODES '{ false, false, false }'
opt_enable REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER SDSUPPORT EEPROM_SETTINGS EEPROM_BOOT_SILENT EEPROM_AUTO_INIT \
LASER_FEATURE AIR_EVACUATION AIR_EVACUATION_PIN AIR_ASSIST AIR_ASSIST_PIN LASER_COOLANT_FLOW_METER MEATPACK_ON_SERIAL_PORT_1
@ -184,10 +186,12 @@ exec_test $1 $2 "REPRAP MEGA2560 RAMPS | Laser Feature | Air Evacuation | Air As
# Test Laser features with 44780 LCD
#
restore_configs
opt_set MOTHERBOARD BOARD_RAMPS_14_EFB LCD_LANGUAGE en TEMP_SENSOR_COOLER 1 EXTRUDERS 0 TEMP_SENSOR_1 0 \
opt_set MOTHERBOARD BOARD_RAMPS_14_EFB EXTRUDERS 0 LCD_LANGUAGE en TEMP_SENSOR_COOLER 1 TEMP_SENSOR_1 0 \
DEFAULT_AXIS_STEPS_PER_UNIT '{ 80, 80, 400 }' \
DEFAULT_MAX_FEEDRATE '{ 300, 300, 5 }' \
DEFAULT_MAX_ACCELERATION '{ 3000, 3000, 100 }'
DEFAULT_MAX_ACCELERATION '{ 3000, 3000, 100 }' \
MANUAL_FEEDRATE '{ 50*60, 50*60, 4*60 }' \
AXIS_RELATIVE_MODES '{ false, false, false }'
opt_enable REPRAP_DISCOUNT_SMART_CONTROLLER SDSUPPORT EEPROM_SETTINGS EEPROM_BOOT_SILENT EEPROM_AUTO_INIT \
LASER_FEATURE AIR_EVACUATION AIR_EVACUATION_PIN AIR_ASSIST AIR_ASSIST_PIN LASER_COOLANT_FLOW_METER

2
buildroot/tests/rambo

@ -48,6 +48,7 @@ opt_set MOTHERBOARD BOARD_RAMBO \
DEFAULT_AXIS_STEPS_PER_UNIT '{ 80, 80, 4000 }' \
DEFAULT_MAX_FEEDRATE '{ 300, 300, 5 }' \
DEFAULT_MAX_ACCELERATION '{ 3000, 3000, 100 }' \
MANUAL_FEEDRATE '{ 50*60, 50*60, 4*60 }' \
AXIS_RELATIVE_MODES '{ false, false, false }' \
LEVEL_CORNERS_LEVELING_ORDER '{ LF, RF }'
opt_enable USE_XMAX_PLUG USE_YMAX_PLUG USE_ZMAX_PLUG \
@ -66,6 +67,7 @@ opt_set MOTHERBOARD BOARD_RAMBO EXTRUDERS 0 TEMP_SENSOR_BED 1 \
DEFAULT_AXIS_STEPS_PER_UNIT '{ 80, 80, 4000 }' \
DEFAULT_MAX_FEEDRATE '{ 300, 300, 5 }' \
DEFAULT_MAX_ACCELERATION '{ 3000, 3000, 100 }' \
MANUAL_FEEDRATE '{ 50*60, 50*60, 4*60 }' \
AXIS_RELATIVE_MODES '{ false, false, false }'
opt_enable REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER
exec_test $1 $2 "Rambo heated bed only" "$3"

Loading…
Cancel
Save