🚸 Optional X-Axis (#25418)

Co-authored-by: alextrical <35117191+alextrical@users.noreply.github.com>
Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
This commit is contained in:
ellensp 2023-05-10 06:59:25 +12:00 committed by GitHub
parent 3e9848f49c
commit 1f9bfc5c74
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
54 changed files with 1201 additions and 925 deletions

View file

@ -324,10 +324,12 @@
//
// Endstop Names used by Endstops::report_states
//
#define STR_X_MIN "x_min"
#define STR_X_MAX "x_max"
#define STR_X2_MIN "x2_min"
#define STR_X2_MAX "x2_max"
#if HAS_X_AXIS
#define STR_X_MIN "x_min"
#define STR_X_MAX "x_max"
#define STR_X2_MIN "x2_min"
#define STR_X2_MAX "x2_max"
#endif
#if HAS_Y_AXIS
#define STR_Y_MIN "y_min"

View file

@ -96,10 +96,12 @@ void print_bin(uint16_t val) {
}
}
void print_pos(NUM_AXIS_ARGS(const_float_t), FSTR_P const prefix/*=nullptr*/, FSTR_P const suffix/*=nullptr*/) {
void print_pos(NUM_AXIS_ARGS_(const_float_t) FSTR_P const prefix/*=nullptr*/, FSTR_P const suffix/*=nullptr*/) {
if (prefix) serial_print(prefix);
SERIAL_ECHOPGM_P(
LIST_N(DOUBLE(NUM_AXES), SP_X_STR, x, SP_Y_STR, y, SP_Z_STR, z, SP_I_STR, i, SP_J_STR, j, SP_K_STR, k, SP_U_STR, u, SP_V_STR, v, SP_W_STR, w)
);
#if NUM_AXES
SERIAL_ECHOPGM_P(
LIST_N(DOUBLE(NUM_AXES), SP_X_STR, x, SP_Y_STR, y, SP_Z_STR, z, SP_I_STR, i, SP_J_STR, j, SP_K_STR, k, SP_U_STR, u, SP_V_STR, v, SP_W_STR, w)
);
#endif
if (suffix) serial_print(suffix); else SERIAL_EOL();
}

View file

@ -340,10 +340,10 @@ void serial_spaces(uint8_t count);
void serial_offset(const_float_t v, const uint8_t sp=0); // For v==0 draw space (sp==1) or plus (sp==2)
void print_bin(const uint16_t val);
void print_pos(NUM_AXIS_ARGS(const_float_t), FSTR_P const prefix=nullptr, FSTR_P const suffix=nullptr);
void print_pos(NUM_AXIS_ARGS_(const_float_t) FSTR_P const prefix=nullptr, FSTR_P const suffix=nullptr);
inline void print_pos(const xyze_pos_t &xyze, FSTR_P const prefix=nullptr, FSTR_P const suffix=nullptr) {
print_pos(NUM_AXIS_ELEM(xyze), prefix, suffix);
print_pos(NUM_AXIS_ELEM_(xyze) prefix, suffix);
}
#define SERIAL_POS(SUFFIX,VAR) do { print_pos(VAR, F(" " STRINGIFY(VAR) "="), F(" : " SUFFIX "\n")); }while(0)

View file

@ -36,31 +36,47 @@ template <class L, class R> struct IF<true, L, R> { typedef L type; };
#define ALL_AXIS_NAMES X, X2, Y, Y2, Z, Z2, Z3, Z4, I, J, K, U, V, W, E0, E1, E2, E3, E4, E5, E6, E7
#define NUM_AXIS_GANG(V...) GANG_N(NUM_AXES, V)
#define NUM_AXIS_CODE(V...) CODE_N(NUM_AXES, V)
#define NUM_AXIS_LIST(V...) LIST_N(NUM_AXES, V)
#define NUM_AXIS_LIST_1(V) LIST_N_1(NUM_AXES, V)
#define NUM_AXIS_ARRAY(V...) { NUM_AXIS_LIST(V) }
#define NUM_AXIS_ARRAY_1(V) { NUM_AXIS_LIST_1(V) }
#define NUM_AXIS_ARGS(T) NUM_AXIS_LIST(T x, T y, T z, T i, T j, T k, T u, T v, T w)
#define NUM_AXIS_ELEM(O) NUM_AXIS_LIST(O.x, O.y, O.z, O.i, O.j, O.k, O.u, O.v, O.w)
#define NUM_AXIS_DEFS(T,V) NUM_AXIS_LIST(T x=V, T y=V, T z=V, T i=V, T j=V, T k=V, T u=V, T v=V, T w=V)
#define MAIN_AXIS_NAMES NUM_AXIS_LIST(X, Y, Z, I, J, K, U, V, W)
#define MAIN_AXIS_MAP(F) MAP(F, MAIN_AXIS_NAMES)
#define STR_AXES_MAIN NUM_AXIS_GANG("X", "Y", "Z", STR_I, STR_J, STR_K, STR_U, STR_V, STR_W)
#define NUM_AXIS_GANG(V...) GANG_N(NUM_AXES, V)
#define NUM_AXIS_CODE(V...) CODE_N(NUM_AXES, V)
#define NUM_AXIS_LIST(V...) LIST_N(NUM_AXES, V)
#define NUM_AXIS_LIST_1(V) LIST_N_1(NUM_AXES, V)
#define NUM_AXIS_ARRAY(V...) { NUM_AXIS_LIST(V) }
#define NUM_AXIS_ARRAY_1(V) { NUM_AXIS_LIST_1(V) }
#define NUM_AXIS_ARGS(T) NUM_AXIS_LIST(T x, T y, T z, T i, T j, T k, T u, T v, T w)
#define NUM_AXIS_ELEM(O) NUM_AXIS_LIST(O.x, O.y, O.z, O.i, O.j, O.k, O.u, O.v, O.w)
#define NUM_AXIS_DEFS(T,V) NUM_AXIS_LIST(T x=V, T y=V, T z=V, T i=V, T j=V, T k=V, T u=V, T v=V, T w=V)
#define MAIN_AXIS_NAMES NUM_AXIS_LIST(X, Y, Z, I, J, K, U, V, W)
#define STR_AXES_MAIN NUM_AXIS_GANG("X", "Y", "Z", STR_I, STR_J, STR_K, STR_U, STR_V, STR_W)
#define LOGICAL_AXIS_GANG(E,V...) NUM_AXIS_GANG(V) GANG_ITEM_E(E)
#define LOGICAL_AXIS_CODE(E,V...) NUM_AXIS_CODE(V) CODE_ITEM_E(E)
#define LOGICAL_AXIS_LIST(E,V...) NUM_AXIS_LIST(V) LIST_ITEM_E(E)
#define LOGICAL_AXIS_LIST_1(V) NUM_AXIS_LIST_1(V) LIST_ITEM_E(V)
#if NUM_AXES
#define NUM_AXES_SEP ,
#define MAIN_AXIS_MAP(F) MAP(F, MAIN_AXIS_NAMES)
#define OPTARGS_LOGICAL(T) , LOGICAL_AXIS_ARGS(T)
#else
#define NUM_AXES_SEP
#define MAIN_AXIS_MAP(F)
#define OPTARGS_LOGICAL(T)
#endif
#define NUM_AXIS_GANG_(V...) NUM_AXIS_GANG(V) NUM_AXES_SEP
#define NUM_AXIS_LIST_(V...) NUM_AXIS_LIST(V) NUM_AXES_SEP
#define NUM_AXIS_LIST_1_(V...) NUM_AXIS_LIST_1(V) NUM_AXES_SEP
#define NUM_AXIS_ARGS_(T) NUM_AXIS_ARGS(T) NUM_AXES_SEP
#define NUM_AXIS_ELEM_(T) NUM_AXIS_ELEM(T) NUM_AXES_SEP
#define MAIN_AXIS_NAMES_ MAIN_AXIS_NAMES NUM_AXES_SEP
#define LOGICAL_AXIS_GANG(E,V...) NUM_AXIS_GANG(V) GANG_ITEM_E(E)
#define LOGICAL_AXIS_CODE(E,V...) NUM_AXIS_CODE(V) CODE_ITEM_E(E)
#define LOGICAL_AXIS_LIST(E,V...) NUM_AXIS_LIST(V) LIST_ITEM_E(E)
#define LOGICAL_AXIS_LIST_1(V) NUM_AXIS_LIST_1(V) LIST_ITEM_E(V)
#define LOGICAL_AXIS_ARRAY(E,V...) { LOGICAL_AXIS_LIST(E,V) }
#define LOGICAL_AXIS_ARRAY_1(V) { LOGICAL_AXIS_LIST_1(V) }
#define LOGICAL_AXIS_ARGS(T) LOGICAL_AXIS_LIST(T e, T x, T y, T z, T i, T j, T k, T u, T v, T w)
#define LOGICAL_AXIS_ELEM(O) LOGICAL_AXIS_LIST(O.e, O.x, O.y, O.z, O.i, O.j, O.k, O.u, O.v, O.w)
#define LOGICAL_AXIS_DECL(T,V) LOGICAL_AXIS_LIST(T e=V, T x=V, T y=V, T z=V, T i=V, T j=V, T k=V, T u=V, T v=V, T w=V)
#define LOGICAL_AXIS_NAMES LOGICAL_AXIS_LIST(E, X, Y, Z, I, J, K, U, V, W)
#define LOGICAL_AXIS_MAP(F) MAP(F, LOGICAL_AXIS_NAMES)
#define STR_AXES_LOGICAL LOGICAL_AXIS_GANG("E", "X", "Y", "Z", STR_I, STR_J, STR_K, STR_U, STR_V, STR_W)
#define LOGICAL_AXIS_ARGS(T) LOGICAL_AXIS_LIST(T e, T x, T y, T z, T i, T j, T k, T u, T v, T w)
#define LOGICAL_AXIS_ELEM(O) LOGICAL_AXIS_LIST(O.e, O.x, O.y, O.z, O.i, O.j, O.k, O.u, O.v, O.w)
#define LOGICAL_AXIS_DECL(T,V) LOGICAL_AXIS_LIST(T e=V, T x=V, T y=V, T z=V, T i=V, T j=V, T k=V, T u=V, T v=V, T w=V)
#define LOGICAL_AXIS_NAMES LOGICAL_AXIS_LIST(E, X, Y, Z, I, J, K, U, V, W)
#define LOGICAL_AXIS_MAP(F) MAP(F, LOGICAL_AXIS_NAMES)
#define STR_AXES_LOGICAL LOGICAL_AXIS_GANG("E", "X", "Y", "Z", STR_I, STR_J, STR_K, STR_U, STR_V, STR_W)
#define XYZ_GANG(V...) GANG_N(PRIMARY_LINEAR_AXES, V)
#define XYZ_CODE(V...) CODE_N(PRIMARY_LINEAR_AXES, V)
@ -75,8 +91,13 @@ template <class L, class R> struct IF<true, L, R> { typedef L type; };
#endif
#if HAS_EXTRUDERS
#define LIST_ITEM_E(N) , N
#define CODE_ITEM_E(N) ; N
#if NUM_AXES
#define LIST_ITEM_E(N) , N
#define CODE_ITEM_E(N) ; N
#else
#define LIST_ITEM_E(N) N
#define CODE_ITEM_E(N) N
#endif
#define GANG_ITEM_E(N) N
#else
#define LIST_ITEM_E(N)
@ -166,37 +187,38 @@ typedef struct AxisFlags {
enum AxisEnum : uint8_t {
// Linear axes may be controlled directly or indirectly
NUM_AXIS_LIST(X_AXIS, Y_AXIS, Z_AXIS, I_AXIS, J_AXIS, K_AXIS, U_AXIS, V_AXIS, W_AXIS)
NUM_AXIS_LIST_(X_AXIS, Y_AXIS, Z_AXIS, I_AXIS, J_AXIS, K_AXIS, U_AXIS, V_AXIS, W_AXIS)
// Extruder axes may be considered distinctly
#define _EN_ITEM(N) , E##N##_AXIS
#define _EN_ITEM(N) E##N##_AXIS,
REPEAT(EXTRUDERS, _EN_ITEM)
#undef _EN_ITEM
// Core also keeps toolhead directions
#if ANY(IS_CORE, MARKFORGED_XY, MARKFORGED_YX)
, X_HEAD, Y_HEAD, Z_HEAD
X_HEAD, Y_HEAD, Z_HEAD,
#endif
// Distinct axes, including all E and Core
, NUM_AXIS_ENUMS
NUM_AXIS_ENUMS,
// Most of the time we refer only to the single E_AXIS
#if HAS_EXTRUDERS
, E_AXIS = E0_AXIS
E_AXIS = E0_AXIS,
#endif
// A, B, and C are for DELTA, SCARA, etc.
, A_AXIS = X_AXIS
#if HAS_X_AXIS
A_AXIS = X_AXIS,
#endif
#if HAS_Y_AXIS
, B_AXIS = Y_AXIS
B_AXIS = Y_AXIS,
#endif
#if HAS_Z_AXIS
, C_AXIS = Z_AXIS
C_AXIS = Z_AXIS,
#endif
// To refer to all or none
, ALL_AXES_ENUM = 0xFE, NO_AXIS_ENUM = 0xFF
ALL_AXES_ENUM = 0xFE, NO_AXIS_ENUM = 0xFF
};
//
@ -336,7 +358,9 @@ struct XYval {
FI void reset() { x = y = 0; }
// Setters taking struct types and arrays
FI void set(const T px) { x = px; }
#if HAS_X_AXIS
FI void set(const T px) { x = px; }
#endif
#if HAS_Y_AXIS
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]; }
@ -453,9 +477,9 @@ struct XYval {
FI XYval<T>& operator<<=(const int &p) { _LS(x); _LS(y); return *this; }
// Exact comparisons. For floats a "NEAR" operation may be better.
FI bool operator==(const XYval<T> &rs) const { return NUM_AXIS_GANG(x == rs.x, && y == rs.y,,,,,,, ); }
FI bool operator==(const XYZval<T> &rs) const { return NUM_AXIS_GANG(x == rs.x, && y == rs.y,,,,,,, ); }
FI bool operator==(const XYZEval<T> &rs) const { return NUM_AXIS_GANG(x == rs.x, && y == rs.y,,,,,,, ); }
FI bool operator==(const XYval<T> &rs) const { return true NUM_AXIS_GANG(&& x == rs.x, && y == rs.y,,,,,,, ); }
FI bool operator==(const XYZval<T> &rs) const { return true NUM_AXIS_GANG(&& x == rs.x, && y == rs.y,,,,,,, ); }
FI bool operator==(const XYZEval<T> &rs) const { return true NUM_AXIS_GANG(&& x == rs.x, && y == rs.y,,,,,,, ); }
FI bool operator!=(const XYval<T> &rs) const { return !operator==(rs); }
FI bool operator!=(const XYZval<T> &rs) const { return !operator==(rs); }
FI bool operator!=(const XYZEval<T> &rs) const { return !operator==(rs); }
@ -467,23 +491,25 @@ struct XYval {
template<typename T>
struct XYZval {
union {
struct { T NUM_AXIS_ARGS(); };
struct { T NUM_AXIS_LIST(a, b, c, _i, _j, _k, _u, _v, _w); };
#if NUM_AXES
struct { T NUM_AXIS_ARGS(); };
struct { T NUM_AXIS_LIST(a, b, c, _i, _j, _k, _u, _v, _w); };
#endif
T pos[NUM_AXES];
};
// Set all to 0
FI void reset() { NUM_AXIS_GANG(x =, y =, z =, i =, j =, k =, u =, v =, w =) 0; }
FI void reset() { NUM_AXIS_CODE(x = 0, y = 0, z = 0, i = 0, j = 0, k = 0, u = 0, v = 0, w = 0); }
// Setters taking struct types and arrays
FI void set(const XYval<T> pxy) { NUM_AXIS_CODE(x = pxy.x, y = pxy.y,,,,,,,); }
FI void set(const XYval<T> pxy, const T pz) { NUM_AXIS_CODE(x = pxy.x, y = pxy.y, z = pz,,,,,,); }
FI void set(const T (&arr)[NUM_AXES]) { NUM_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); }
FI void set(const XYval<T> pxy) { NUM_AXIS_CODE(x = pxy.x, y = pxy.y,,,,,,,); }
FI void set(const XYval<T> pxy, const T pz) { NUM_AXIS_CODE(x = pxy.x, y = pxy.y, z = pz,,,,,,); }
FI void set(const T (&arr)[NUM_AXES]) { NUM_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); }
#if LOGICAL_AXES > NUM_AXES
FI void set(const T (&arr)[LOGICAL_AXES]) { NUM_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); }
FI void set(LOGICAL_AXIS_ARGS(const T)) { NUM_AXIS_CODE(a = x, b = y, c = z, _i = i, _j = j, _k = k, _u = u, _v = v, _w = w ); }
FI void set(const T (&arr)[LOGICAL_AXES]) { NUM_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); }
FI void set(LOGICAL_AXIS_ARGS(const T)) { NUM_AXIS_CODE(a = x, b = y, c = z, _i = i, _j = j, _k = k, _u = u, _v = v, _w = w ); }
#if DISTINCT_AXES > LOGICAL_AXES
FI void set(const T (&arr)[DISTINCT_AXES]) { NUM_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); }
FI void set(const T (&arr)[DISTINCT_AXES]) { NUM_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); }
#endif
#endif
@ -517,15 +543,15 @@ struct XYZval {
#endif
// Length reduced to one dimension
FI T magnitude() const { return (T)sqrtf(NUM_AXIS_GANG(x*x, + y*y, + z*z, + i*i, + j*j, + k*k, + u*u, + v*v, + w*w)); }
FI T magnitude() const { return (T)TERN(HAS_X_AXIS, sqrtf(NUM_AXIS_GANG(x*x, + y*y, + z*z, + i*i, + j*j, + k*k, + u*u, + v*v, + w*w)), 0); }
// Pointer to the data as a simple array
FI operator T* () { return pos; }
FI operator T* () { return (T*)this; }
// If any element is true then it's true
FI operator bool() { return NUM_AXIS_GANG(x, || y, || z, || i, || j, || k, || u, || v, || w); }
FI operator bool() { return 0 NUM_AXIS_GANG(|| x, || y, || z, || i, || j, || k, || u, || v, || w); }
// Smallest element
FI T small() const { return _MIN(NUM_AXIS_LIST(x, y, z, i, j, k, u, v, w)); }
FI T small() const { return TERN(HAS_X_AXIS,_MIN(NUM_AXIS_LIST(x, y, z, i, j, k, u, v, w));,0;) }
// Largest element
FI T large() const { return _MAX(NUM_AXIS_LIST(x, y, z, i, j, k, u, v, w)); }
FI T large() const { return TERN(HAS_X_AXIS,_MAX(NUM_AXIS_LIST(x, y, z, i, j, k, u, v, w));,0;) }
// Explicit copy and copies with conversion
FI XYZval<T> copy() const { XYZval<T> o = *this; return o; }
@ -634,10 +660,10 @@ struct XYZEval {
T pos[LOGICAL_AXES];
};
// Reset all to 0
FI void reset() { LOGICAL_AXIS_GANG(e =, x =, y =, z =, i =, j =, k =, u =, v =, w =) 0; }
FI void reset() { LOGICAL_AXIS_GANG(e =, x =, y =, z =, i =, j =, k =, u =, v =, w =) 0; }
// Setters taking struct types and arrays
FI void set(const XYval<T> pxy) { x = pxy.x; OPTCODE(HAS_Y_AXIS, y = pxy.y) }
FI void set(const XYval<T> pxy) { OPTCODE(HAS_X_AXIS, x = pxy.x) OPTCODE(HAS_Y_AXIS, y = pxy.y) }
FI void set(const XYZval<T> pxyz) { set(NUM_AXIS_ELEM(pxyz)); }
FI void set(const XYval<T> pxy, const T pz) { set(pxy); TERN_(HAS_Z_AXIS, z = pz); }
FI void set(const T (&arr)[NUM_AXES]) { NUM_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); }

View file

@ -195,8 +195,6 @@ void FWRetract::retract(const bool retracting E_OPTARG(bool swapping/*=false*/))
//*/
}
//extern const char SP_Z_STR[];
/**
* M207: Set firmware retraction values
*

View file

@ -773,8 +773,8 @@
}
}
static void tmc_debug_loop(const TMC_debug_enum n, LOGICAL_AXIS_ARGS(const bool)) {
if (x) {
static void tmc_debug_loop(const TMC_debug_enum n OPTARGS_LOGICAL(const bool)) {
if (TERN0(HAS_X_AXIS, x)) {
#if AXIS_IS_TMC(X)
tmc_status(stepperX, n);
#endif
@ -856,8 +856,8 @@
SERIAL_EOL();
}
static void drv_status_loop(const TMC_drv_status_enum n, LOGICAL_AXIS_ARGS(const bool)) {
if (x) {
static void drv_status_loop(const TMC_drv_status_enum n OPTARGS_LOGICAL(const bool)) {
if (TERN0(HAS_X_AXIS, x)) {
#if AXIS_IS_TMC(X)
tmc_parse_drv_status(stepperX, n);
#endif
@ -944,8 +944,8 @@
*/
void tmc_report_all(LOGICAL_AXIS_ARGS(const bool)) {
#define TMC_REPORT(LABEL, ITEM) do{ SERIAL_ECHOPGM(LABEL); tmc_debug_loop(ITEM, LOGICAL_AXIS_ARGS()); }while(0)
#define DRV_REPORT(LABEL, ITEM) do{ SERIAL_ECHOPGM(LABEL); drv_status_loop(ITEM, LOGICAL_AXIS_ARGS()); }while(0)
#define TMC_REPORT(LABEL, ITEM) do{ SERIAL_ECHOPGM(LABEL); tmc_debug_loop(ITEM OPTARGS_LOGICAL()); }while(0)
#define DRV_REPORT(LABEL, ITEM) do{ SERIAL_ECHOPGM(LABEL); drv_status_loop(ITEM OPTARGS_LOGICAL()); }while(0)
TMC_REPORT("\t", TMC_CODES);
#if HAS_DRIVER(TMC2209)
@ -1070,8 +1070,8 @@
}
#endif
static void tmc_get_registers(TMC_get_registers_enum n, LOGICAL_AXIS_ARGS(const bool)) {
if (x) {
static void tmc_get_registers(TMC_get_registers_enum n OPTARGS_LOGICAL(const bool)) {
if (TERN0(HAS_X_AXIS, x)) {
#if AXIS_IS_TMC(X)
tmc_get_registers(stepperX, n);
#endif
@ -1154,7 +1154,7 @@
}
void tmc_get_registers(LOGICAL_AXIS_ARGS(bool)) {
#define _TMC_GET_REG(LABEL, ITEM) do{ SERIAL_ECHOPGM(LABEL); tmc_get_registers(ITEM, LOGICAL_AXIS_ARGS()); }while(0)
#define _TMC_GET_REG(LABEL, ITEM) do{ SERIAL_ECHOPGM(LABEL); tmc_get_registers(ITEM OPTARGS_LOGICAL()); }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");
@ -1236,7 +1236,7 @@ static bool test_connection(TMC &st) {
void test_tmc_connection(LOGICAL_AXIS_ARGS(const bool)) {
uint8_t axis_connection = 0;
if (x) {
if (TERN0(HAS_X_AXIS, x)) {
#if AXIS_IS_TMC(X)
axis_connection += test_connection(stepperX);
#endif

View file

@ -348,7 +348,7 @@ void test_tmc_connection(LOGICAL_AXIS_DECL(const bool, true));
#if USE_SENSORLESS
// Track enabled status of stealthChop and only re-enable where applicable
struct sensorless_t { bool NUM_AXIS_ARGS(), x2, y2, z2, z3, z4; };
struct sensorless_t { bool NUM_AXIS_ARGS_() x2, y2, z2, z3, z4; };
#if ENABLED(IMPROVE_HOMING_RELIABILITY)
extern millis_t sg_guard_period;

View file

@ -206,20 +206,6 @@ void GcodeSuite::G28() {
DEBUG_SECTION(log_G28, "G28", DEBUGGING(LEVELING));
if (DEBUGGING(LEVELING)) log_machine_info();
TERN_(BD_SENSOR, bdl.config_state = 0);
/**
* Set the laser power to false to stop the planner from processing the current power setting.
*/
#if ENABLED(LASER_FEATURE)
planner.laser_inline.status.isPowered = false;
#endif
#if ENABLED(DUAL_X_CARRIAGE)
bool IDEX_saved_duplication_state = extruder_duplication_enabled;
DualXMode IDEX_saved_mode = dual_x_carriage_mode;
#endif
#if ENABLED(MARLIN_DEV_MODE)
if (parser.seen_test('S')) {
LOOP_NUM_AXES(a) set_axis_is_at_home((AxisEnum)a);
@ -230,12 +216,21 @@ void GcodeSuite::G28() {
}
#endif
/**
* Set the laser power to false to stop the planner from processing the current power setting.
*/
#if ENABLED(LASER_FEATURE)
planner.laser_inline.status.isPowered = false;
#endif
// Home (O)nly if position is unknown
if (!axes_should_home() && parser.seen_test('O')) {
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("> homing not needed, skip");
return;
}
TERN_(BD_SENSOR, bdl.config_state = 0);
#if ENABLED(FULL_REPORT_TO_HOST_FEATURE)
const M_StateEnum old_grblstate = M_State_grbl;
set_and_report_grblstate(M_HOMING);
@ -246,220 +241,322 @@ void GcodeSuite::G28() {
planner.synchronize(); // Wait for planner moves to finish!
SET_SOFT_ENDSTOP_LOOSE(false); // Reset a leftover 'loose' motion state
// Disable the leveling matrix before homing
#if CAN_SET_LEVELING_AFTER_G28
const bool leveling_restore_state = parser.boolval('L', TERN1(RESTORE_LEVELING_AFTER_G28, planner.leveling_active));
#endif
// Cancel any prior G29 session
TERN_(PROBE_MANUALLY, g29_in_progress = false);
// Disable leveling before homing
TERN_(HAS_LEVELING, set_bed_leveling_enabled(false));
// Reset to the XY plane
TERN_(CNC_WORKSPACE_PLANES, workspace_plane = PLANE_XY);
// Count this command as movement / activity
reset_stepper_timeout();
#define HAS_CURRENT_HOME(N) (defined(N##_CURRENT_HOME) && N##_CURRENT_HOME != N##_CURRENT)
#if HAS_CURRENT_HOME(X) || HAS_CURRENT_HOME(X2) || HAS_CURRENT_HOME(Y) || HAS_CURRENT_HOME(Y2) || (ENABLED(DELTA) && HAS_CURRENT_HOME(Z)) || HAS_CURRENT_HOME(I) || HAS_CURRENT_HOME(J) || HAS_CURRENT_HOME(K) || HAS_CURRENT_HOME(U) || HAS_CURRENT_HOME(V) || HAS_CURRENT_HOME(W)
#define HAS_HOMING_CURRENT 1
#endif
#if NUM_AXES
#if HAS_HOMING_CURRENT
auto debug_current = [](FSTR_P const s, const int16_t a, const int16_t b) {
DEBUG_ECHOF(s); DEBUG_ECHOLNPGM(" current: ", a, " -> ", b);
};
#if HAS_CURRENT_HOME(X)
const int16_t tmc_save_current_X = stepperX.getMilliamps();
stepperX.rms_current(X_CURRENT_HOME);
if (DEBUGGING(LEVELING)) debug_current(F(STR_X), tmc_save_current_X, X_CURRENT_HOME);
#endif
#if HAS_CURRENT_HOME(X2)
const int16_t tmc_save_current_X2 = stepperX2.getMilliamps();
stepperX2.rms_current(X2_CURRENT_HOME);
if (DEBUGGING(LEVELING)) debug_current(F(STR_X2), tmc_save_current_X2, X2_CURRENT_HOME);
#endif
#if HAS_CURRENT_HOME(Y)
const int16_t tmc_save_current_Y = stepperY.getMilliamps();
stepperY.rms_current(Y_CURRENT_HOME);
if (DEBUGGING(LEVELING)) debug_current(F(STR_Y), tmc_save_current_Y, Y_CURRENT_HOME);
#endif
#if HAS_CURRENT_HOME(Y2)
const int16_t tmc_save_current_Y2 = stepperY2.getMilliamps();
stepperY2.rms_current(Y2_CURRENT_HOME);
if (DEBUGGING(LEVELING)) debug_current(F(STR_Y2), tmc_save_current_Y2, Y2_CURRENT_HOME);
#endif
#if HAS_CURRENT_HOME(Z) && ENABLED(DELTA)
const int16_t tmc_save_current_Z = stepperZ.getMilliamps();
stepperZ.rms_current(Z_CURRENT_HOME);
if (DEBUGGING(LEVELING)) debug_current(F(STR_Z), tmc_save_current_Z, Z_CURRENT_HOME);
#endif
#if HAS_CURRENT_HOME(I)
const int16_t tmc_save_current_I = stepperI.getMilliamps();
stepperI.rms_current(I_CURRENT_HOME);
if (DEBUGGING(LEVELING)) debug_current(F(STR_I), tmc_save_current_I, I_CURRENT_HOME);
#endif
#if HAS_CURRENT_HOME(J)
const int16_t tmc_save_current_J = stepperJ.getMilliamps();
stepperJ.rms_current(J_CURRENT_HOME);
if (DEBUGGING(LEVELING)) debug_current(F(STR_J), tmc_save_current_J, J_CURRENT_HOME);
#endif
#if HAS_CURRENT_HOME(K)
const int16_t tmc_save_current_K = stepperK.getMilliamps();
stepperK.rms_current(K_CURRENT_HOME);
if (DEBUGGING(LEVELING)) debug_current(F(STR_K), tmc_save_current_K, K_CURRENT_HOME);
#endif
#if HAS_CURRENT_HOME(U)
const int16_t tmc_save_current_U = stepperU.getMilliamps();
stepperU.rms_current(U_CURRENT_HOME);
if (DEBUGGING(LEVELING)) debug_current(F(STR_U), tmc_save_current_U, U_CURRENT_HOME);
#endif
#if HAS_CURRENT_HOME(V)
const int16_t tmc_save_current_V = stepperV.getMilliamps();
stepperV.rms_current(V_CURRENT_HOME);
if (DEBUGGING(LEVELING)) debug_current(F(STR_V), tmc_save_current_V, V_CURRENT_HOME);
#endif
#if HAS_CURRENT_HOME(W)
const int16_t tmc_save_current_W = stepperW.getMilliamps();
stepperW.rms_current(W_CURRENT_HOME);
if (DEBUGGING(LEVELING)) debug_current(F(STR_W), tmc_save_current_W, W_CURRENT_HOME);
#endif
#if SENSORLESS_STALLGUARD_DELAY
safe_delay(SENSORLESS_STALLGUARD_DELAY); // Short delay needed to settle
#endif
#endif // HAS_HOMING_CURRENT
#if ENABLED(IMPROVE_HOMING_RELIABILITY)
motion_state_t saved_motion_state = begin_slow_homing();
#endif
// Always home with tool 0 active
#if HAS_MULTI_HOTEND
#if DISABLED(DELTA) || ENABLED(DELTA_HOME_TO_SAFE_ZONE)
const uint8_t old_tool_index = active_extruder;
#endif
// PARKING_EXTRUDER homing requires different handling of movement / solenoid activation, depending on the side of homing
#if ENABLED(PARKING_EXTRUDER)
const bool pe_final_change_must_unpark = parking_extruder_unpark_after_homing(old_tool_index, X_HOME_DIR + 1 == old_tool_index * 2);
#endif
tool_change(0, true);
#endif
TERN_(HAS_DUPLICATION_MODE, set_duplication_enabled(false));
remember_feedrate_scaling_off();
endstops.enable(true); // Enable endstops for next homing move
bool finalRaiseZ = false;
#if ENABLED(DELTA)
constexpr bool doZ = true; // for NANODLP_Z_SYNC if your DLP is on a DELTA
home_delta();
TERN_(IMPROVE_HOMING_RELIABILITY, end_slow_homing(saved_motion_state));
#elif ENABLED(AXEL_TPARA)
constexpr bool doZ = true; // for NANODLP_Z_SYNC if your DLP is on a TPARA
home_TPARA();
#else
#define _UNSAFE(A) (homeZ && TERN0(Z_SAFE_HOMING, axes_should_home(_BV(A##_AXIS))))
const bool homeZ = TERN0(HAS_Z_AXIS, parser.seen_test('Z')),
NUM_AXIS_LIST( // Other axes should be homed before Z safe-homing
needX = _UNSAFE(X), needY = _UNSAFE(Y), needZ = false, // UNUSED
needI = _UNSAFE(I), needJ = _UNSAFE(J), needK = _UNSAFE(K),
needU = _UNSAFE(U), needV = _UNSAFE(V), needW = _UNSAFE(W)
),
NUM_AXIS_LIST( // Home each axis if needed or flagged
homeX = needX || parser.seen_test('X'),
homeY = needY || parser.seen_test('Y'),
homeZZ = homeZ,
homeI = needI || parser.seen_test(AXIS4_NAME), homeJ = needJ || parser.seen_test(AXIS5_NAME),
homeK = needK || parser.seen_test(AXIS6_NAME), homeU = needU || parser.seen_test(AXIS7_NAME),
homeV = needV || parser.seen_test(AXIS8_NAME), homeW = needW || parser.seen_test(AXIS9_NAME)
),
home_all = NUM_AXIS_GANG( // Home-all if all or none are flagged
homeX == homeX, && homeY == homeX, && homeZ == homeX,
&& homeI == homeX, && homeJ == homeX, && homeK == homeX,
&& homeU == homeX, && homeV == homeX, && homeW == homeX
),
NUM_AXIS_LIST(
doX = home_all || homeX, doY = home_all || homeY, doZ = home_all || homeZ,
doI = home_all || homeI, doJ = home_all || homeJ, doK = home_all || homeK,
doU = home_all || homeU, doV = home_all || homeV, doW = home_all || homeW
);
#if !HAS_Y_AXIS
constexpr bool doY = false;
#if ENABLED(DUAL_X_CARRIAGE)
bool IDEX_saved_duplication_state = extruder_duplication_enabled;
DualXMode IDEX_saved_mode = dual_x_carriage_mode;
#endif
#if HAS_Z_AXIS
SET_SOFT_ENDSTOP_LOOSE(false); // Reset a leftover 'loose' motion state
UNUSED(needZ); UNUSED(homeZZ);
// Disable the leveling matrix before homing
#if CAN_SET_LEVELING_AFTER_G28
const bool leveling_restore_state = parser.boolval('L', TERN1(RESTORE_LEVELING_AFTER_G28, planner.leveling_active));
#endif
// Z may home first, e.g., when homing away from the bed.
// This is also permitted when homing with a Z endstop.
if (TERN0(HOME_Z_FIRST, doZ)) homeaxis(Z_AXIS);
// Cancel any prior G29 session
TERN_(PROBE_MANUALLY, g29_in_progress = false);
// 'R' to specify a specific raise. 'R0' indicates no raise, e.g., for recovery.resume
// When 'R0' is used, there should already be adequate clearance, e.g., from homing Z to max.
const bool seenR = parser.seenval('R');
// Disable leveling before homing
TERN_(HAS_LEVELING, set_bed_leveling_enabled(false));
// Use raise given by 'R' or Z_CLEARANCE_FOR_HOMING (above the probe trigger point)
float z_homing_height = seenR ? parser.value_linear_units() : Z_CLEARANCE_FOR_HOMING;
// Reset to the XY plane
TERN_(CNC_WORKSPACE_PLANES, workspace_plane = PLANE_XY);
// Check for any lateral motion that might require clearance
const bool may_skate = seenR || NUM_AXIS_GANG(doX, || doY, || TERN0(Z_SAFE_HOMING, doZ), || doI, || doJ, || doK, || doU, || doV, || doW);
#define HAS_CURRENT_HOME(N) (defined(N##_CURRENT_HOME) && N##_CURRENT_HOME != N##_CURRENT)
#if HAS_CURRENT_HOME(X) || HAS_CURRENT_HOME(X2) || HAS_CURRENT_HOME(Y) || HAS_CURRENT_HOME(Y2) || (ENABLED(DELTA) && HAS_CURRENT_HOME(Z)) || HAS_CURRENT_HOME(I) || HAS_CURRENT_HOME(J) || HAS_CURRENT_HOME(K) || HAS_CURRENT_HOME(U) || HAS_CURRENT_HOME(V) || HAS_CURRENT_HOME(W)
#define HAS_HOMING_CURRENT 1
#endif
if (seenR && z_homing_height == 0) {
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("R0 = No Z raise");
}
else {
bool with_probe = ENABLED(HOMING_Z_WITH_PROBE);
// Raise above the current Z (which should be synced in the planner)
// The "height" for Z is a coordinate. But if Z is not trusted/homed make it relative.
if (seenR || !TERN(HOME_AFTER_DEACTIVATE, axis_is_trusted, axis_was_homed)(Z_AXIS)) {
z_homing_height += current_position.z;
with_probe = false;
#if HAS_HOMING_CURRENT
auto debug_current = [](FSTR_P const s, const int16_t a, const int16_t b) {
DEBUG_ECHOF(s); DEBUG_ECHOLNPGM(" current: ", a, " -> ", b);
};
#if HAS_CURRENT_HOME(X)
const int16_t tmc_save_current_X = stepperX.getMilliamps();
stepperX.rms_current(X_CURRENT_HOME);
if (DEBUGGING(LEVELING)) debug_current(F(STR_X), tmc_save_current_X, X_CURRENT_HOME);
#endif
#if HAS_CURRENT_HOME(X2)
const int16_t tmc_save_current_X2 = stepperX2.getMilliamps();
stepperX2.rms_current(X2_CURRENT_HOME);
if (DEBUGGING(LEVELING)) debug_current(F(STR_X2), tmc_save_current_X2, X2_CURRENT_HOME);
#endif
#if HAS_CURRENT_HOME(Y)
const int16_t tmc_save_current_Y = stepperY.getMilliamps();
stepperY.rms_current(Y_CURRENT_HOME);
if (DEBUGGING(LEVELING)) debug_current(F(STR_Y), tmc_save_current_Y, Y_CURRENT_HOME);
#endif
#if HAS_CURRENT_HOME(Y2)
const int16_t tmc_save_current_Y2 = stepperY2.getMilliamps();
stepperY2.rms_current(Y2_CURRENT_HOME);
if (DEBUGGING(LEVELING)) debug_current(F(STR_Y2), tmc_save_current_Y2, Y2_CURRENT_HOME);
#endif
#if HAS_CURRENT_HOME(Z) && ENABLED(DELTA)
const int16_t tmc_save_current_Z = stepperZ.getMilliamps();
stepperZ.rms_current(Z_CURRENT_HOME);
if (DEBUGGING(LEVELING)) debug_current(F(STR_Z), tmc_save_current_Z, Z_CURRENT_HOME);
#endif
#if HAS_CURRENT_HOME(I)
const int16_t tmc_save_current_I = stepperI.getMilliamps();
stepperI.rms_current(I_CURRENT_HOME);
if (DEBUGGING(LEVELING)) debug_current(F(STR_I), tmc_save_current_I, I_CURRENT_HOME);
#endif
#if HAS_CURRENT_HOME(J)
const int16_t tmc_save_current_J = stepperJ.getMilliamps();
stepperJ.rms_current(J_CURRENT_HOME);
if (DEBUGGING(LEVELING)) debug_current(F(STR_J), tmc_save_current_J, J_CURRENT_HOME);
#endif
#if HAS_CURRENT_HOME(K)
const int16_t tmc_save_current_K = stepperK.getMilliamps();
stepperK.rms_current(K_CURRENT_HOME);
if (DEBUGGING(LEVELING)) debug_current(F(STR_K), tmc_save_current_K, K_CURRENT_HOME);
#endif
#if HAS_CURRENT_HOME(U)
const int16_t tmc_save_current_U = stepperU.getMilliamps();
stepperU.rms_current(U_CURRENT_HOME);
if (DEBUGGING(LEVELING)) debug_current(F(STR_U), tmc_save_current_U, U_CURRENT_HOME);
#endif
#if HAS_CURRENT_HOME(V)
const int16_t tmc_save_current_V = stepperV.getMilliamps();
stepperV.rms_current(V_CURRENT_HOME);
if (DEBUGGING(LEVELING)) debug_current(F(STR_V), tmc_save_current_V, V_CURRENT_HOME);
#endif
#if HAS_CURRENT_HOME(W)
const int16_t tmc_save_current_W = stepperW.getMilliamps();
stepperW.rms_current(W_CURRENT_HOME);
if (DEBUGGING(LEVELING)) debug_current(F(STR_W), tmc_save_current_W, W_CURRENT_HOME);
#endif
#if SENSORLESS_STALLGUARD_DELAY
safe_delay(SENSORLESS_STALLGUARD_DELAY); // Short delay needed to settle
#endif
#endif // HAS_HOMING_CURRENT
#if ENABLED(IMPROVE_HOMING_RELIABILITY)
motion_state_t saved_motion_state = begin_slow_homing();
#endif
// Always home with tool 0 active
#if HAS_MULTI_HOTEND
#if DISABLED(DELTA) || ENABLED(DELTA_HOME_TO_SAFE_ZONE)
const uint8_t old_tool_index = active_extruder;
#endif
// PARKING_EXTRUDER homing requires different handling of movement / solenoid activation, depending on the side of homing
#if ENABLED(PARKING_EXTRUDER)
const bool pe_final_change_must_unpark = parking_extruder_unpark_after_homing(old_tool_index, X_HOME_DIR + 1 == old_tool_index * 2);
#endif
tool_change(0, true);
#endif
TERN_(HAS_DUPLICATION_MODE, set_duplication_enabled(false));
remember_feedrate_scaling_off();
endstops.enable(true); // Enable endstops for next homing move
bool finalRaiseZ = false;
#if ENABLED(DELTA)
constexpr bool doZ = true; // for NANODLP_Z_SYNC if your DLP is on a DELTA
home_delta();
TERN_(IMPROVE_HOMING_RELIABILITY, end_slow_homing(saved_motion_state));
#elif ENABLED(AXEL_TPARA)
constexpr bool doZ = true; // for NANODLP_Z_SYNC if your DLP is on a TPARA
home_TPARA();
#else // !DELTA && !AXEL_TPARA
#define _UNSAFE(A) (homeZ && TERN0(Z_SAFE_HOMING, axes_should_home(_BV(A##_AXIS))))
const bool homeZ = TERN0(HAS_Z_AXIS, parser.seen_test('Z')),
NUM_AXIS_LIST_( // Other axes should be homed before Z safe-homing
needX = _UNSAFE(X), needY = _UNSAFE(Y), needZ = false, // UNUSED
needI = _UNSAFE(I), needJ = _UNSAFE(J), needK = _UNSAFE(K),
needU = _UNSAFE(U), needV = _UNSAFE(V), needW = _UNSAFE(W)
)
NUM_AXIS_LIST_( // Home each axis if needed or flagged
homeX = needX || parser.seen_test('X'),
homeY = needY || parser.seen_test('Y'),
homeZZ = homeZ,
homeI = needI || parser.seen_test(AXIS4_NAME), homeJ = needJ || parser.seen_test(AXIS5_NAME),
homeK = needK || parser.seen_test(AXIS6_NAME), homeU = needU || parser.seen_test(AXIS7_NAME),
homeV = needV || parser.seen_test(AXIS8_NAME), homeW = needW || parser.seen_test(AXIS9_NAME)
)
home_all = NUM_AXIS_GANG_( // Home-all if all or none are flagged
homeX == homeX, && homeY == homeX, && homeZ == homeX,
&& homeI == homeX, && homeJ == homeX, && homeK == homeX,
&& homeU == homeX, && homeV == homeX, && homeW == homeX
)
NUM_AXIS_LIST(
doX = home_all || homeX, doY = home_all || homeY, doZ = home_all || homeZ,
doI = home_all || homeI, doJ = home_all || homeJ, doK = home_all || homeK,
doU = home_all || homeU, doV = home_all || homeV, doW = home_all || homeW
);
#if !HAS_Y_AXIS
constexpr bool doY = false;
#endif
#if HAS_Z_AXIS
UNUSED(needZ); UNUSED(homeZZ);
// Z may home first, e.g., when homing away from the bed.
// This is also permitted when homing with a Z endstop.
if (TERN0(HOME_Z_FIRST, doZ)) homeaxis(Z_AXIS);
// 'R' to specify a specific raise. 'R0' indicates no raise, e.g., for recovery.resume
// When 'R0' is used, there should already be adequate clearance, e.g., from homing Z to max.
const bool seenR = parser.seenval('R');
// Use raise given by 'R' or Z_CLEARANCE_FOR_HOMING (above the probe trigger point)
float z_homing_height = seenR ? parser.value_linear_units() : Z_CLEARANCE_FOR_HOMING;
// Check for any lateral motion that might require clearance
const bool may_skate = seenR NUM_AXIS_GANG(|| doX, || doY, || TERN0(Z_SAFE_HOMING, doZ), || doI, || doJ, || doK, || doU, || doV, || doW);
if (seenR && z_homing_height == 0) {
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("R0 = No Z raise");
}
else {
bool with_probe = ENABLED(HOMING_Z_WITH_PROBE);
// Raise above the current Z (which should be synced in the planner)
// The "height" for Z is a coordinate. But if Z is not trusted/homed make it relative.
if (seenR || !TERN(HOME_AFTER_DEACTIVATE, axis_is_trusted, axis_was_homed)(Z_AXIS)) {
z_homing_height += current_position.z;
with_probe = false;
}
if (may_skate) {
// Apply Z clearance before doing any lateral motion
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Raise Z before homing:");
do_z_clearance(z_homing_height, with_probe);
}
}
if (may_skate) {
// Apply Z clearance before doing any lateral motion
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Raise Z before homing:");
do_z_clearance(z_homing_height, with_probe);
// Init BLTouch ahead of any lateral motion, even if not homing with the probe
TERN_(BLTOUCH, if (may_skate) bltouch.init());
#endif // HAS_Z_AXIS
// Diagonal move first if both are homing
TERN_(QUICK_HOME, if (doX && doY) quick_home_xy());
#if HAS_Y_AXIS
// Home Y (before X)
if (ENABLED(HOME_Y_BEFORE_X) && (doY || TERN0(CODEPENDENT_XY_HOMING, doX)))
homeaxis(Y_AXIS);
#endif
// Home X
#if HAS_X_AXIS
if (doX || (doY && ENABLED(CODEPENDENT_XY_HOMING) && DISABLED(HOME_Y_BEFORE_X))) {
#if ENABLED(DUAL_X_CARRIAGE)
// Always home the 2nd (right) extruder first
active_extruder = 1;
homeaxis(X_AXIS);
// Remember this extruder's position for later tool change
inactive_extruder_x = current_position.x;
// Home the 1st (left) extruder
active_extruder = 0;
homeaxis(X_AXIS);
// Consider the active extruder to be in its "parked" position
idex_set_parked();
#else
homeaxis(X_AXIS);
#endif
}
}
#endif // HAS_X_AXIS
// Init BLTouch ahead of any lateral motion, even if not homing with the probe
TERN_(BLTOUCH, if (may_skate) bltouch.init());
#if BOTH(FOAMCUTTER_XYUV, HAS_I_AXIS)
// Home I (after X)
if (doI) homeaxis(I_AXIS);
#endif
#endif // HAS_Z_AXIS
#if HAS_Y_AXIS
// Home Y (after X)
if (DISABLED(HOME_Y_BEFORE_X) && doY)
homeaxis(Y_AXIS);
#endif
// Diagonal move first if both are homing
TERN_(QUICK_HOME, if (doX && doY) quick_home_xy());
#if BOTH(FOAMCUTTER_XYUV, HAS_J_AXIS)
// Home J (after Y)
if (doJ) homeaxis(J_AXIS);
#endif
TERN_(IMPROVE_HOMING_RELIABILITY, end_slow_homing(saved_motion_state));
#if ENABLED(FOAMCUTTER_XYUV)
// Skip homing of unused Z axis for foamcutters
if (doZ) set_axis_is_at_home(Z_AXIS);
#elif HAS_Z_AXIS
// Home Z last if homing towards the bed
#if DISABLED(HOME_Z_FIRST)
if (doZ) {
#if EITHER(Z_MULTI_ENDSTOPS, Z_STEPPER_AUTO_ALIGN)
stepper.set_all_z_lock(false);
stepper.set_separate_multi_axis(false);
#endif
#if ENABLED(Z_SAFE_HOMING)
if (TERN1(POWER_LOSS_RECOVERY, !parser.seen_test('H'))) home_z_safely(); else homeaxis(Z_AXIS);
#else
homeaxis(Z_AXIS);
#endif
#if EITHER(Z_HOME_TO_MIN, ALLOW_Z_AFTER_HOMING)
finalRaiseZ = true;
#endif
}
#endif
SECONDARY_AXIS_CODE(
if (doI) homeaxis(I_AXIS),
if (doJ) homeaxis(J_AXIS),
if (doK) homeaxis(K_AXIS),
if (doU) homeaxis(U_AXIS),
if (doV) homeaxis(V_AXIS),
if (doW) homeaxis(W_AXIS)
);
#endif // HAS_Z_AXIS
sync_plan_position();
#if HAS_Y_AXIS
// Home Y (before X)
if (ENABLED(HOME_Y_BEFORE_X) && (doY || TERN0(CODEPENDENT_XY_HOMING, doX)))
homeaxis(Y_AXIS);
#endif
// Home X
if (doX || (doY && ENABLED(CODEPENDENT_XY_HOMING) && DISABLED(HOME_Y_BEFORE_X))) {
/**
* Preserve DXC mode across a G28 for IDEX printers in DXC_DUPLICATION_MODE.
* This is important because it lets a user use the LCD Panel to set an IDEX Duplication mode, and
* then print a standard GCode file that contains a single print that does a G28 and has no other
* IDEX specific commands in it.
*/
#if ENABLED(DUAL_X_CARRIAGE)
#if ENABLED(DUAL_X_CARRIAGE)
if (idex_is_duplicating()) {
TERN_(IMPROVE_HOMING_RELIABILITY, saved_motion_state = begin_slow_homing());
// Always home the 2nd (right) extruder first
active_extruder = 1;
@ -472,171 +569,83 @@ void GcodeSuite::G28() {
active_extruder = 0;
homeaxis(X_AXIS);
// Consider the active extruder to be in its "parked" position
// Consider the active extruder to be parked
idex_set_parked();
#else
dual_x_carriage_mode = IDEX_saved_mode;
set_duplication_enabled(IDEX_saved_duplication_state);
homeaxis(X_AXIS);
TERN_(IMPROVE_HOMING_RELIABILITY, end_slow_homing(saved_motion_state));
}
#endif // DUAL_X_CARRIAGE
endstops.not_homing();
// Clear endstop state for polled stallGuard endstops
TERN_(SPI_ENDSTOPS, endstops.clear_endstop_state());
#if HAS_HOMING_CURRENT
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Restore driver current...");
#if HAS_CURRENT_HOME(X)
stepperX.rms_current(tmc_save_current_X);
#endif
}
#if BOTH(FOAMCUTTER_XYUV, HAS_I_AXIS)
// Home I (after X)
if (doI) homeaxis(I_AXIS);
#endif
#if HAS_Y_AXIS
// Home Y (after X)
if (DISABLED(HOME_Y_BEFORE_X) && doY)
homeaxis(Y_AXIS);
#endif
#if BOTH(FOAMCUTTER_XYUV, HAS_J_AXIS)
// Home J (after Y)
if (doJ) homeaxis(J_AXIS);
#endif
TERN_(IMPROVE_HOMING_RELIABILITY, end_slow_homing(saved_motion_state));
#if ENABLED(FOAMCUTTER_XYUV)
// Skip homing of unused Z axis for foamcutters
if (doZ) set_axis_is_at_home(Z_AXIS);
#elif HAS_Z_AXIS
// Home Z last if homing towards the bed
#if DISABLED(HOME_Z_FIRST)
if (doZ) {
#if EITHER(Z_MULTI_ENDSTOPS, Z_STEPPER_AUTO_ALIGN)
stepper.set_all_z_lock(false);
stepper.set_separate_multi_axis(false);
#endif
#if ENABLED(Z_SAFE_HOMING)
if (TERN1(POWER_LOSS_RECOVERY, !parser.seen_test('H'))) home_z_safely(); else homeaxis(Z_AXIS);
#else
homeaxis(Z_AXIS);
#endif
#if EITHER(Z_HOME_TO_MIN, ALLOW_Z_AFTER_HOMING)
finalRaiseZ = true;
#endif
}
#if HAS_CURRENT_HOME(X2)
stepperX2.rms_current(tmc_save_current_X2);
#endif
#if HAS_CURRENT_HOME(Y)
stepperY.rms_current(tmc_save_current_Y);
#endif
#if HAS_CURRENT_HOME(Y2)
stepperY2.rms_current(tmc_save_current_Y2);
#endif
#if HAS_CURRENT_HOME(Z) && ENABLED(DELTA)
stepperZ.rms_current(tmc_save_current_Z);
#endif
#if HAS_CURRENT_HOME(I)
stepperI.rms_current(tmc_save_current_I);
#endif
#if HAS_CURRENT_HOME(J)
stepperJ.rms_current(tmc_save_current_J);
#endif
#if HAS_CURRENT_HOME(K)
stepperK.rms_current(tmc_save_current_K);
#endif
#if HAS_CURRENT_HOME(U)
stepperU.rms_current(tmc_save_current_U);
#endif
#if HAS_CURRENT_HOME(V)
stepperV.rms_current(tmc_save_current_V);
#endif
#if HAS_CURRENT_HOME(W)
stepperW.rms_current(tmc_save_current_W);
#endif
#if SENSORLESS_STALLGUARD_DELAY
safe_delay(SENSORLESS_STALLGUARD_DELAY); // Short delay needed to settle
#endif
#endif // HAS_HOMING_CURRENT
SECONDARY_AXIS_CODE(
if (doI) homeaxis(I_AXIS),
if (doJ) homeaxis(J_AXIS),
if (doK) homeaxis(K_AXIS),
if (doU) homeaxis(U_AXIS),
if (doV) homeaxis(V_AXIS),
if (doW) homeaxis(W_AXIS)
);
// Move to a height where we can use the full xy-area
TERN_(DELTA_HOME_TO_SAFE_ZONE, do_blocking_move_to_z(delta_clip_start_height));
#endif // HAS_Z_AXIS
// Move to the configured Z only if Z was homed to MIN, because machines that
// home to MAX historically expect 'G28 Z' to be safe to use at the end of a
// print, and do_move_after_z_homing is not very nuanced.
if (finalRaiseZ) do_move_after_z_homing();
sync_plan_position();
TERN_(CAN_SET_LEVELING_AFTER_G28, if (leveling_restore_state) set_bed_leveling_enabled());
#endif
/**
* Preserve DXC mode across a G28 for IDEX printers in DXC_DUPLICATION_MODE.
* This is important because it lets a user use the LCD Panel to set an IDEX Duplication mode, and
* then print a standard GCode file that contains a single print that does a G28 and has no other
* IDEX specific commands in it.
*/
#if ENABLED(DUAL_X_CARRIAGE)
if (idex_is_duplicating()) {
TERN_(IMPROVE_HOMING_RELIABILITY, saved_motion_state = begin_slow_homing());
// Always home the 2nd (right) extruder first
active_extruder = 1;
homeaxis(X_AXIS);
// Remember this extruder's position for later tool change
inactive_extruder_x = current_position.x;
// Home the 1st (left) extruder
active_extruder = 0;
homeaxis(X_AXIS);
// Consider the active extruder to be parked
idex_set_parked();
dual_x_carriage_mode = IDEX_saved_mode;
set_duplication_enabled(IDEX_saved_duplication_state);
TERN_(IMPROVE_HOMING_RELIABILITY, end_slow_homing(saved_motion_state));
}
#endif // DUAL_X_CARRIAGE
endstops.not_homing();
// Clear endstop state for polled stallGuard endstops
TERN_(SPI_ENDSTOPS, endstops.clear_endstop_state());
#if HAS_HOMING_CURRENT
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Restore driver current...");
#if HAS_CURRENT_HOME(X)
stepperX.rms_current(tmc_save_current_X);
// Restore the active tool after homing
#if HAS_MULTI_HOTEND && (DISABLED(DELTA) || ENABLED(DELTA_HOME_TO_SAFE_ZONE))
tool_change(old_tool_index, TERN(PARKING_EXTRUDER, !pe_final_change_must_unpark, DISABLED(DUAL_X_CARRIAGE))); // Do move if one of these
#endif
#if HAS_CURRENT_HOME(X2)
stepperX2.rms_current(tmc_save_current_X2);
#endif
#if HAS_CURRENT_HOME(Y)
stepperY.rms_current(tmc_save_current_Y);
#endif
#if HAS_CURRENT_HOME(Y2)
stepperY2.rms_current(tmc_save_current_Y2);
#endif
#if HAS_CURRENT_HOME(Z) && ENABLED(DELTA)
stepperZ.rms_current(tmc_save_current_Z);
#endif
#if HAS_CURRENT_HOME(I)
stepperI.rms_current(tmc_save_current_I);
#endif
#if HAS_CURRENT_HOME(J)
stepperJ.rms_current(tmc_save_current_J);
#endif
#if HAS_CURRENT_HOME(K)
stepperK.rms_current(tmc_save_current_K);
#endif
#if HAS_CURRENT_HOME(U)
stepperU.rms_current(tmc_save_current_U);
#endif
#if HAS_CURRENT_HOME(V)
stepperV.rms_current(tmc_save_current_V);
#endif
#if HAS_CURRENT_HOME(W)
stepperW.rms_current(tmc_save_current_W);
#endif
#if SENSORLESS_STALLGUARD_DELAY
safe_delay(SENSORLESS_STALLGUARD_DELAY); // Short delay needed to settle
#endif
#endif // HAS_HOMING_CURRENT
// Move to a height where we can use the full xy-area
TERN_(DELTA_HOME_TO_SAFE_ZONE, do_blocking_move_to_z(delta_clip_start_height));
restore_feedrate_and_scaling();
// Move to the configured Z only if Z was homed to MIN, because machines that
// home to MAX historically expect 'G28 Z' to be safe to use at the end of a
// print, and do_move_after_z_homing is not very nuanced.
if (finalRaiseZ) do_move_after_z_homing();
if (ENABLED(NANODLP_Z_SYNC) && (ENABLED(NANODLP_ALL_AXIS) || TERN0(HAS_Z_AXIS, doZ)))
SERIAL_ECHOLNPGM(STR_Z_MOVE_COMP);
TERN_(CAN_SET_LEVELING_AFTER_G28, if (leveling_restore_state) set_bed_leveling_enabled());
// Restore the active tool after homing
#if HAS_MULTI_HOTEND && (DISABLED(DELTA) || ENABLED(DELTA_HOME_TO_SAFE_ZONE))
tool_change(old_tool_index, TERN(PARKING_EXTRUDER, !pe_final_change_must_unpark, DISABLED(DUAL_X_CARRIAGE))); // Do move if one of these
#endif
restore_feedrate_and_scaling();
#endif // NUM_AXES
ui.refresh();
@ -645,9 +654,6 @@ void GcodeSuite::G28() {
report_current_position();
if (ENABLED(NANODLP_Z_SYNC) && (ENABLED(NANODLP_ALL_AXIS) || TERN0(HAS_Z_AXIS, doZ)))
SERIAL_ECHOLNPGM(STR_Z_MOVE_COMP);
TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(old_grblstate));
}

View file

@ -70,7 +70,7 @@
#define CALIBRATION_MEASUREMENT_CERTAIN 0.5 // mm
#endif
#if BOTH(CALIBRATION_MEASURE_LEFT, CALIBRATION_MEASURE_RIGHT)
#if ALL(HAS_X_AXIS, CALIBRATION_MEASURE_LEFT, CALIBRATION_MEASURE_RIGHT)
#define HAS_X_CENTER 1
#endif
#if ALL(HAS_Y_AXIS, CALIBRATION_MEASURE_FRONT, CALIBRATION_MEASURE_BACK)
@ -398,11 +398,13 @@ inline void probe_sides(measurements_t &m, const float uncertainty) {
#if AXIS_CAN_CALIBRATE(Z)
SERIAL_ECHOLNPGM(" Top: ", m.obj_side[TOP]);
#endif
#if ENABLED(CALIBRATION_MEASURE_LEFT)
SERIAL_ECHOLNPGM(" Left: ", m.obj_side[LEFT]);
#endif
#if ENABLED(CALIBRATION_MEASURE_RIGHT)
SERIAL_ECHOLNPGM(" Right: ", m.obj_side[RIGHT]);
#if HAS_X_AXIS
#if ENABLED(CALIBRATION_MEASURE_LEFT)
SERIAL_ECHOLNPGM(" Left: ", m.obj_side[LEFT]);
#endif
#if ENABLED(CALIBRATION_MEASURE_RIGHT)
SERIAL_ECHOLNPGM(" Right: ", m.obj_side[RIGHT]);
#endif
#endif
#if HAS_Y_AXIS
#if ENABLED(CALIBRATION_MEASURE_FRONT)

View file

@ -112,17 +112,19 @@ void GcodeSuite::M425_report(const bool forReplay/*=true*/) {
#ifdef BACKLASH_SMOOTHING_MM
, PSTR(" S"), LINEAR_UNIT(backlash.get_smoothing_mm())
#endif
, LIST_N(DOUBLE(NUM_AXES),
SP_X_STR, LINEAR_UNIT(backlash.get_distance_mm(X_AXIS)),
SP_Y_STR, LINEAR_UNIT(backlash.get_distance_mm(Y_AXIS)),
SP_Z_STR, LINEAR_UNIT(backlash.get_distance_mm(Z_AXIS)),
SP_I_STR, I_AXIS_UNIT(backlash.get_distance_mm(I_AXIS)),
SP_J_STR, J_AXIS_UNIT(backlash.get_distance_mm(J_AXIS)),
SP_K_STR, K_AXIS_UNIT(backlash.get_distance_mm(K_AXIS)),
SP_U_STR, U_AXIS_UNIT(backlash.get_distance_mm(U_AXIS)),
SP_V_STR, V_AXIS_UNIT(backlash.get_distance_mm(V_AXIS)),
SP_W_STR, W_AXIS_UNIT(backlash.get_distance_mm(W_AXIS))
)
#if NUM_AXES
, LIST_N(DOUBLE(NUM_AXES),
SP_X_STR, LINEAR_UNIT(backlash.get_distance_mm(X_AXIS)),
SP_Y_STR, LINEAR_UNIT(backlash.get_distance_mm(Y_AXIS)),
SP_Z_STR, LINEAR_UNIT(backlash.get_distance_mm(Z_AXIS)),
SP_I_STR, I_AXIS_UNIT(backlash.get_distance_mm(I_AXIS)),
SP_J_STR, J_AXIS_UNIT(backlash.get_distance_mm(J_AXIS)),
SP_K_STR, K_AXIS_UNIT(backlash.get_distance_mm(K_AXIS)),
SP_U_STR, U_AXIS_UNIT(backlash.get_distance_mm(U_AXIS)),
SP_V_STR, V_AXIS_UNIT(backlash.get_distance_mm(V_AXIS)),
SP_W_STR, W_AXIS_UNIT(backlash.get_distance_mm(W_AXIS))
)
#endif
);
}

View file

@ -143,22 +143,30 @@ void GcodeSuite::M201() {
void GcodeSuite::M201_report(const bool forReplay/*=true*/) {
report_heading_etc(forReplay, F(STR_MAX_ACCELERATION));
SERIAL_ECHOLNPGM_P(
LIST_N(DOUBLE(NUM_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]),
SP_I_STR, I_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[I_AXIS]),
SP_J_STR, J_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[J_AXIS]),
SP_K_STR, K_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[K_AXIS]),
SP_U_STR, U_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[U_AXIS]),
SP_V_STR, V_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[V_AXIS]),
SP_W_STR, W_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[W_AXIS])
)
#if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS)
, SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_acceleration_mm_per_s2[E_AXIS])
#endif
);
#if NUM_AXES
SERIAL_ECHOPGM_P(
LIST_N(DOUBLE(NUM_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]),
SP_I_STR, I_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[I_AXIS]),
SP_J_STR, J_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[J_AXIS]),
SP_K_STR, K_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[K_AXIS]),
SP_U_STR, U_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[U_AXIS]),
SP_V_STR, V_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[V_AXIS]),
SP_W_STR, W_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[W_AXIS])
)
);
#endif
#if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS)
SERIAL_ECHOPGM_P(SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_acceleration_mm_per_s2[E_AXIS]));
#endif
#if NUM_AXES || (HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS))
SERIAL_EOL();
#endif
#if ENABLED(DISTINCT_E_FACTORS)
LOOP_L_N(i, E_STEPPERS) {
report_echo_start(forReplay);
@ -191,22 +199,30 @@ void GcodeSuite::M203() {
void GcodeSuite::M203_report(const bool forReplay/*=true*/) {
report_heading_etc(forReplay, F(STR_MAX_FEEDRATES));
SERIAL_ECHOLNPGM_P(
LIST_N(DOUBLE(NUM_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]),
SP_I_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[I_AXIS]),
SP_J_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[J_AXIS]),
SP_K_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[K_AXIS]),
SP_U_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[U_AXIS]),
SP_V_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[V_AXIS]),
SP_W_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[W_AXIS])
)
#if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS)
, SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_feedrate_mm_s[E_AXIS])
#endif
);
#if NUM_AXES
SERIAL_ECHOPGM_P(
LIST_N(DOUBLE(NUM_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]),
SP_I_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[I_AXIS]),
SP_J_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[J_AXIS]),
SP_K_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[K_AXIS]),
SP_U_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[U_AXIS]),
SP_V_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[V_AXIS]),
SP_W_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[W_AXIS])
)
);
#endif
#if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS)
SERIAL_ECHOPGM_P(SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_feedrate_mm_s[E_AXIS]));
#endif
#if NUM_AXES || (HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS))
SERIAL_EOL();
#endif
#if ENABLED(DISTINCT_E_FACTORS)
LOOP_L_N(i, E_STEPPERS) {
if (!forReplay) SERIAL_ECHO_START();
@ -336,7 +352,7 @@ void GcodeSuite::M205_report(const bool forReplay/*=true*/) {
#if HAS_JUNCTION_DEVIATION
, PSTR(" J"), LINEAR_UNIT(planner.junction_deviation_mm)
#endif
#if HAS_CLASSIC_JERK
#if HAS_CLASSIC_JERK && NUM_AXES
, LIST_N(DOUBLE(NUM_AXES),
SP_X_STR, LINEAR_UNIT(planner.max_jerk.x),
SP_Y_STR, LINEAR_UNIT(planner.max_jerk.y),

View file

@ -95,7 +95,9 @@ void GcodeSuite::M217() {
#if ENABLED(TOOLCHANGE_PARK)
if (parser.seenval('W')) { toolchange_settings.enable_park = parser.value_linear_units(); }
if (parser.seenval('X')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.x = constrain(v, X_MIN_POS, X_MAX_POS); }
#if HAS_X_AXIS
if (parser.seenval('X')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.x = constrain(v, X_MIN_POS, X_MAX_POS); }
#endif
#if HAS_Y_AXIS
if (parser.seenval('Y')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.y = constrain(v, Y_MIN_POS, Y_MAX_POS); }
#endif
@ -183,25 +185,27 @@ void GcodeSuite::M217_report(const bool forReplay/*=true*/) {
#endif
#if ENABLED(TOOLCHANGE_PARK)
{
SERIAL_ECHOPGM(" W", LINEAR_UNIT(toolchange_settings.enable_park));
SERIAL_ECHOPGM_P(
SP_X_STR, LINEAR_UNIT(toolchange_settings.change_point.x)
#if HAS_Y_AXIS
, SP_Y_STR, LINEAR_UNIT(toolchange_settings.change_point.y)
#endif
#if SECONDARY_AXES >= 1
, LIST_N(DOUBLE(SECONDARY_AXES)
, SP_I_STR, I_AXIS_UNIT(toolchange_settings.change_point.i)
, SP_J_STR, J_AXIS_UNIT(toolchange_settings.change_point.j)
, SP_K_STR, K_AXIS_UNIT(toolchange_settings.change_point.k)
, SP_C_STR, U_AXIS_UNIT(toolchange_settings.change_point.u)
, PSTR(" H"), V_AXIS_UNIT(toolchange_settings.change_point.v)
, PSTR(" O"), W_AXIS_UNIT(toolchange_settings.change_point.w)
)
#endif
);
}
#if NUM_AXES
{
SERIAL_ECHOPGM_P(
SP_X_STR, LINEAR_UNIT(toolchange_settings.change_point.x)
#if HAS_Y_AXIS
, SP_Y_STR, LINEAR_UNIT(toolchange_settings.change_point.y)
#endif
#if SECONDARY_AXES >= 1
, LIST_N(DOUBLE(SECONDARY_AXES)
, SP_I_STR, I_AXIS_UNIT(toolchange_settings.change_point.i)
, SP_J_STR, J_AXIS_UNIT(toolchange_settings.change_point.j)
, SP_K_STR, K_AXIS_UNIT(toolchange_settings.change_point.k)
, SP_C_STR, U_AXIS_UNIT(toolchange_settings.change_point.u)
, PSTR(" H"), V_AXIS_UNIT(toolchange_settings.change_point.v)
, PSTR(" O"), W_AXIS_UNIT(toolchange_settings.change_point.w)
)
#endif
);
}
#endif
#endif
#if ENABLED(TOOLCHANGE_FS_PRIME_FIRST_USED)

View file

@ -46,9 +46,15 @@ void GcodeSuite::M218() {
const int8_t target_extruder = get_target_extruder_from_command();
if (target_extruder < 0) return;
if (parser.seenval('X')) hotend_offset[target_extruder].x = parser.value_linear_units();
if (parser.seenval('Y')) hotend_offset[target_extruder].y = parser.value_linear_units();
if (parser.seenval('Z')) hotend_offset[target_extruder].z = parser.value_linear_units();
#if HAS_X_AXIS
if (parser.seenval('X')) hotend_offset[target_extruder].x = parser.value_linear_units();
#endif
#if HAS_Y_AXIS
if (parser.seenval('Y')) hotend_offset[target_extruder].y = parser.value_linear_units();
#endif
#if HAS_Z_AXIS
if (parser.seenval('Z')) hotend_offset[target_extruder].z = parser.value_linear_units();
#endif
#if ENABLED(DELTA)
if (target_extruder == active_extruder)

View file

@ -92,21 +92,27 @@ void GcodeSuite::M92() {
void GcodeSuite::M92_report(const bool forReplay/*=true*/, const int8_t e/*=-1*/) {
report_heading_etc(forReplay, F(STR_STEPS_PER_UNIT));
SERIAL_ECHOPGM_P(LIST_N(DOUBLE(NUM_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]),
SP_I_STR, I_AXIS_UNIT(planner.settings.axis_steps_per_mm[I_AXIS]),
SP_J_STR, J_AXIS_UNIT(planner.settings.axis_steps_per_mm[J_AXIS]),
SP_K_STR, K_AXIS_UNIT(planner.settings.axis_steps_per_mm[K_AXIS]),
SP_U_STR, U_AXIS_UNIT(planner.settings.axis_steps_per_mm[U_AXIS]),
SP_V_STR, V_AXIS_UNIT(planner.settings.axis_steps_per_mm[V_AXIS]),
SP_W_STR, W_AXIS_UNIT(planner.settings.axis_steps_per_mm[W_AXIS])
));
#if NUM_AXES
SERIAL_ECHOPGM_P(LIST_N(DOUBLE(NUM_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]),
SP_I_STR, I_AXIS_UNIT(planner.settings.axis_steps_per_mm[I_AXIS]),
SP_J_STR, J_AXIS_UNIT(planner.settings.axis_steps_per_mm[J_AXIS]),
SP_K_STR, K_AXIS_UNIT(planner.settings.axis_steps_per_mm[K_AXIS]),
SP_U_STR, U_AXIS_UNIT(planner.settings.axis_steps_per_mm[U_AXIS]),
SP_V_STR, V_AXIS_UNIT(planner.settings.axis_steps_per_mm[V_AXIS]),
SP_W_STR, W_AXIS_UNIT(planner.settings.axis_steps_per_mm[W_AXIS])
));
#endif
#if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS)
SERIAL_ECHOPGM_P(SP_E_STR, VOLUMETRIC_UNIT(planner.settings.axis_steps_per_mm[E_AXIS]));
#endif
SERIAL_EOL();
#if NUM_AXES || (HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS))
SERIAL_EOL();
#endif
#if ENABLED(DISTINCT_E_FACTORS)
LOOP_L_N(i, E_STEPPERS) {

View file

@ -48,17 +48,19 @@ inline stepper_flags_t selected_axis_bits() {
selected.bits = e_axis_mask;
}
#endif
selected.bits |= NUM_AXIS_GANG(
(parser.seen_test('X') << X_AXIS),
| (parser.seen_test('Y') << Y_AXIS),
| (parser.seen_test('Z') << Z_AXIS),
| (parser.seen_test(AXIS4_NAME) << I_AXIS),
| (parser.seen_test(AXIS5_NAME) << J_AXIS),
| (parser.seen_test(AXIS6_NAME) << K_AXIS),
| (parser.seen_test(AXIS7_NAME) << U_AXIS),
| (parser.seen_test(AXIS8_NAME) << V_AXIS),
| (parser.seen_test(AXIS9_NAME) << W_AXIS)
);
#if NUM_AXES
selected.bits |= NUM_AXIS_GANG(
(parser.seen_test('X') << X_AXIS),
| (parser.seen_test('Y') << Y_AXIS),
| (parser.seen_test('Z') << Z_AXIS),
| (parser.seen_test(AXIS4_NAME) << I_AXIS),
| (parser.seen_test(AXIS5_NAME) << J_AXIS),
| (parser.seen_test(AXIS6_NAME) << K_AXIS),
| (parser.seen_test(AXIS7_NAME) << U_AXIS),
| (parser.seen_test(AXIS8_NAME) << V_AXIS),
| (parser.seen_test(AXIS9_NAME) << W_AXIS)
);
#endif
return selected;
}

View file

@ -50,16 +50,19 @@ void GcodeSuite::G60() {
{
const xyze_pos_t &pos = stored_position[slot];
DEBUG_ECHOPGM(STR_SAVED_POS " S", slot, " :");
DEBUG_ECHOLNPGM_P(
LIST_N(DOUBLE(NUM_AXES),
SP_X_LBL, pos.x, SP_Y_LBL, pos.y, SP_Z_LBL, pos.z,
SP_I_LBL, pos.i, SP_J_LBL, pos.j, SP_K_LBL, pos.k,
SP_U_LBL, pos.u, SP_V_LBL, pos.v, SP_W_LBL, pos.w
)
#if HAS_EXTRUDERS
, SP_E_LBL, pos.e
#endif
);
#if NUM_AXES
DEBUG_ECHOPGM_P(
LIST_N(DOUBLE(NUM_AXES),
SP_X_LBL, pos.x, SP_Y_LBL, pos.y, SP_Z_LBL, pos.z,
SP_I_LBL, pos.i, SP_J_LBL, pos.j, SP_K_LBL, pos.k,
SP_U_LBL, pos.u, SP_V_LBL, pos.v, SP_W_LBL, pos.w
)
);
#endif
#if HAS_EXTRUDERS
DEBUG_ECHOPGM_P(SP_E_LBL, pos.e);
#endif
DEBUG_EOL();
}
#endif
}

View file

@ -57,10 +57,12 @@ static void set_stealth_status(const bool enable, const int8_t eindex) {
LOOP_LOGICAL_AXES(i) if (parser.seen(AXIS_CHAR(i))) {
switch (i) {
case X_AXIS:
TERN_(X_HAS_STEALTHCHOP, if (index < 0 || index == 0) TMC_SET_STEALTH(X));
TERN_(X2_HAS_STEALTHCHOP, if (index < 0 || index == 1) TMC_SET_STEALTH(X2));
break;
#if HAS_X_AXIS
case X_AXIS:
TERN_(X_HAS_STEALTHCHOP, if (index < 0 || index == 0) TMC_SET_STEALTH(X));
TERN_(X2_HAS_STEALTHCHOP, if (index < 0 || index == 1) TMC_SET_STEALTH(X2));
break;
#endif
#if HAS_Y_AXIS
case Y_AXIS:
@ -198,13 +200,13 @@ void GcodeSuite::M569_report(const bool forReplay/*=true*/) {
if (chop_x2 || chop_y2 || chop_z2) {
say_M569(forReplay, F("I1"));
if (chop_x2) SERIAL_ECHOPGM_P(SP_X_STR);
#if HAS_Y_AXIS
if (chop_y2) SERIAL_ECHOPGM_P(SP_Y_STR);
#endif
#if HAS_Z_AXIS
if (chop_z2) SERIAL_ECHOPGM_P(SP_Z_STR);
#endif
NUM_AXIS_CODE(
if (chop_x2) SERIAL_ECHOPGM_P(SP_X_STR),
if (chop_y2) SERIAL_ECHOPGM_P(SP_Y_STR),
if (chop_z2) SERIAL_ECHOPGM_P(SP_Z_STR),
NOOP, NOOP, NOOP,
NOOP, NOOP, NOOP
);
SERIAL_EOL();
}

View file

@ -35,7 +35,7 @@
#define M91x_USE(ST) (AXIS_DRIVER_TYPE(ST, TMC2130) || AXIS_DRIVER_TYPE(ST, TMC2160) || AXIS_DRIVER_TYPE(ST, TMC2208) || AXIS_DRIVER_TYPE(ST, TMC2209) || AXIS_DRIVER_TYPE(ST, TMC2660) || AXIS_DRIVER_TYPE(ST, TMC5130) || AXIS_DRIVER_TYPE(ST, TMC5160))
#define M91x_USE_E(N) (E_STEPPERS > N && M91x_USE(E##N))
#if M91x_USE(X) || M91x_USE(X2)
#if HAS_X_AXIS && (M91x_USE(X) || M91x_USE(X2))
#define M91x_SOME_X 1
#endif
#if HAS_Y_AXIS && (M91x_USE(Y) || M91x_USE(Y2))

View file

@ -796,10 +796,14 @@
#define NUM_AXES 3
#elif defined(Y_DRIVER_TYPE)
#define NUM_AXES 2
#else
#elif defined(X_DRIVER_TYPE)
#define NUM_AXES 1
#else
#define NUM_AXES 0
#endif
#if NUM_AXES >= 1
#define HAS_X_AXIS 1
#endif
#define HAS_X_AXIS 1
#if NUM_AXES >= XY
#define HAS_Y_AXIS 1
#endif
@ -825,6 +829,23 @@
#define HAS_W_AXIS 1
#endif
#if !HAS_X_AXIS
#undef ENDSTOPPULLUP_XMIN
#undef ENDSTOPPULLUP_XMAX
#undef X_MIN_ENDSTOP_INVERTING
#undef X_MAX_ENDSTOP_INVERTING
#undef X2_DRIVER_TYPE
#undef X_ENABLE_ON
#undef DISABLE_X
#undef INVERT_X_DIR
#undef X_HOME_DIR
#undef X_MIN_POS
#undef X_MAX_POS
#undef MANUAL_X_HOME_POS
#undef MIN_SOFTWARE_ENDSTOPS
#undef MAX_SOFTWARE_ENDSTOPS
#endif
#if !HAS_Y_AXIS
#undef AVOID_OBSTACLES
#undef ENDSTOPPULLUP_YMIN
@ -1318,10 +1339,12 @@
#endif // FILAMENT_SWITCH_AND_MOTION
// Homing to Min or Max
#if X_HOME_DIR > 0
#define X_HOME_TO_MAX 1
#elif X_HOME_DIR < 0
#define X_HOME_TO_MIN 1
#if HAS_X_AXIS
#if X_HOME_DIR > 0
#define X_HOME_TO_MAX 1
#elif X_HOME_DIR < 0
#define X_HOME_TO_MIN 1
#endif
#endif
#if HAS_Y_AXIS
#if Y_HOME_DIR > 0

View file

@ -94,8 +94,26 @@
#endif
// Some options are disallowed without required axes
#if !HAS_X_AXIS
//#define LCD_SHOW_E_TOTAL
#define NO_WORKSPACE_OFFSETS
#undef AUTOTEMP
#undef CALIBRATION_MEASURE_LEFT
#undef CALIBRATION_MEASURE_RIGHT
#undef CALIBRATION_MEASURE_XMAX
#undef CALIBRATION_MEASURE_XMIN
#undef DISABLE_IDLE_X
#undef INPUT_SHAPING_X
#undef SAFE_BED_LEVELING_START_X
#undef SHAPING_BUFFER_X
#undef SHAPING_FREQ_X
#undef STEALTHCHOP_X
#endif
#if !HAS_Y_AXIS
#undef ARC_SUPPORT
#undef CALIBRATION_MEASURE_BACK
#undef CALIBRATION_MEASURE_FRONT
#undef CALIBRATION_MEASURE_YMAX
#undef CALIBRATION_MEASURE_YMIN
#undef DISABLE_IDLE_Y

View file

@ -105,7 +105,9 @@
#define HAS_ROTATIONAL_AXES 1
#endif
#define X_MAX_LENGTH (X_MAX_POS - (X_MIN_POS))
#if HAS_X_AXIS
#define X_MAX_LENGTH (X_MAX_POS - (X_MIN_POS))
#endif
#if HAS_Y_AXIS
#define Y_MAX_LENGTH (Y_MAX_POS - (Y_MIN_POS))
#endif
@ -134,7 +136,7 @@
#endif
// Defined only if the sanity-check is bypassed
#ifndef X_BED_SIZE
#if HAS_X_AXIS && !defined(X_BED_SIZE)
#define X_BED_SIZE X_MAX_LENGTH
#endif
#if HAS_Y_AXIS && !defined(Y_BED_SIZE)
@ -165,7 +167,9 @@
#endif
// Define center values for future use
#define _X_HALF_BED ((X_BED_SIZE) / 2)
#if HAS_X_AXIS
#define _X_HALF_BED ((X_BED_SIZE) / 2)
#endif
#if HAS_Y_AXIS
#define _Y_HALF_BED ((Y_BED_SIZE) / 2)
#endif
@ -188,7 +192,9 @@
#define _W_HALF_WMAX ((W_BED_SIZE) / 2)
#endif
#define X_CENTER TERN(BED_CENTER_AT_0_0, 0, _X_HALF_BED)
#if HAS_X_AXIS
#define X_CENTER TERN(BED_CENTER_AT_0_0, 0, _X_HALF_BED)
#endif
#if HAS_Y_AXIS
#define Y_CENTER TERN(BED_CENTER_AT_0_0, 0, _Y_HALF_BED)
#define XY_CENTER { X_CENTER, Y_CENTER }
@ -213,8 +219,10 @@
#endif
// Get the linear boundaries of the bed
#define X_MIN_BED (X_CENTER - _X_HALF_BED)
#define X_MAX_BED (X_MIN_BED + X_BED_SIZE)
#if HAS_X_AXIS
#define X_MIN_BED (X_CENTER - _X_HALF_BED)
#define X_MAX_BED (X_MIN_BED + X_BED_SIZE)
#endif
#if HAS_Y_AXIS
#define Y_MIN_BED (Y_CENTER - _Y_HALF_BED)
#define Y_MAX_BED (Y_MIN_BED + Y_BED_SIZE)
@ -292,14 +300,16 @@
/**
* Set the home position based on settings or manual overrides
*/
#ifdef MANUAL_X_HOME_POS
#define X_HOME_POS MANUAL_X_HOME_POS
#else
#define X_END_POS TERN(X_HOME_TO_MIN, X_MIN_POS, X_MAX_POS)
#if ENABLED(BED_CENTER_AT_0_0)
#define X_HOME_POS TERN(DELTA, 0, X_END_POS)
#if HAS_X_AXIS
#ifdef MANUAL_X_HOME_POS
#define X_HOME_POS MANUAL_X_HOME_POS
#else
#define X_HOME_POS TERN(DELTA, X_MIN_POS + (X_BED_SIZE) * 0.5, X_END_POS)
#define X_END_POS TERN(X_HOME_TO_MIN, X_MIN_POS, X_MAX_POS)
#if ENABLED(BED_CENTER_AT_0_0)
#define X_HOME_POS TERN(DELTA, 0, X_END_POS)
#else
#define X_HOME_POS TERN(DELTA, X_MIN_POS + (X_BED_SIZE) * 0.5, X_END_POS)
#endif
#endif
#endif
@ -1021,30 +1031,32 @@
*/
// Steppers
#if PIN_EXISTS(X_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(X))
#define HAS_X_ENABLE 1
#endif
#if PIN_EXISTS(X_DIR)
#define HAS_X_DIR 1
#endif
#if PIN_EXISTS(X_STEP)
#define HAS_X_STEP 1
#endif
#if PIN_EXISTS(X_MS1)
#define HAS_X_MS_PINS 1
#endif
#if HAS_X_AXIS
#if PIN_EXISTS(X_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(X))
#define HAS_X_ENABLE 1
#endif
#if PIN_EXISTS(X_DIR)
#define HAS_X_DIR 1
#endif
#if PIN_EXISTS(X_STEP)
#define HAS_X_STEP 1
#endif
#if PIN_EXISTS(X_MS1)
#define HAS_X_MS_PINS 1
#endif
#if PIN_EXISTS(X2_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(X2))
#define HAS_X2_ENABLE 1
#endif
#if PIN_EXISTS(X2_DIR)
#define HAS_X2_DIR 1
#endif
#if PIN_EXISTS(X2_STEP)
#define HAS_X2_STEP 1
#endif
#if PIN_EXISTS(X2_MS1)
#define HAS_X2_MS_PINS 1
#if PIN_EXISTS(X2_ENABLE) || (ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(X2))
#define HAS_X2_ENABLE 1
#endif
#if PIN_EXISTS(X2_DIR)
#define HAS_X2_DIR 1
#endif
#if PIN_EXISTS(X2_STEP)
#define HAS_X2_STEP 1
#endif
#if PIN_EXISTS(X2_MS1)
#define HAS_X2_MS_PINS 1
#endif
#endif
/**

View file

@ -260,7 +260,7 @@ static_assert(COUNT(arm) == LOGICAL_AXES, "AXIS_RELATIVE_MODES must contain " _L
* Validate bed size
*/
#if !defined(X_BED_SIZE) || !defined(Y_BED_SIZE)
#error "X_BED_SIZE and Y_BED_SIZE are now required!"
#error "X_BED_SIZE and Y_BED_SIZE are required!"
#else
#if HAS_X_AXIS
static_assert(X_MAX_LENGTH >= X_BED_SIZE, "Movement bounds (X_MIN_POS, X_MAX_POS) are too narrow to contain X_BED_SIZE.");
@ -3372,9 +3372,11 @@ static_assert(COUNT(sanity_arr_3) >= LOGICAL_AXES, "DEFAULT_MAX_ACCELERATION re
static_assert(COUNT(sanity_arr_3) <= DISTINCT_AXES, "DEFAULT_MAX_ACCELERATION has too many elements." _EXTRA_NOTE);
static_assert(_PLUS_TEST(3), "DEFAULT_MAX_ACCELERATION values must be positive.");
constexpr float sanity_arr_4[] = HOMING_FEEDRATE_MM_M;
static_assert(COUNT(sanity_arr_4) == NUM_AXES, "HOMING_FEEDRATE_MM_M requires " _NUM_AXES_STR "elements (and no others).");
static_assert(_PLUS_TEST(4), "HOMING_FEEDRATE_MM_M values must be positive.");
#if NUM_AXES
constexpr float sanity_arr_4[] = HOMING_FEEDRATE_MM_M;
static_assert(COUNT(sanity_arr_4) == NUM_AXES, "HOMING_FEEDRATE_MM_M requires " _NUM_AXES_STR "elements (and no others).");
static_assert(_PLUS_TEST(4), "HOMING_FEEDRATE_MM_M values must be positive.");
#endif
#ifdef MAX_ACCEL_EDIT_VALUES
constexpr float sanity_arr_5[] = MAX_ACCEL_EDIT_VALUES;
@ -3571,7 +3573,7 @@ static_assert(_PLUS_TEST(4), "HOMING_FEEDRATE_MM_M values must be positive.");
#if ENABLED(DUAL_X_CARRIAGE)
#error "DUAL_X_CARRIAGE requires both MIN_ and MAX_SOFTWARE_ENDSTOPS."
#elif HAS_HOTEND_OFFSET
#error "MIN_ and MAX_SOFTWARE_ENDSTOPS are both required with offset hotends."
#error "Multi-hotends with offset requires both MIN_ and MAX_SOFTWARE_ENDSTOPS."
#endif
#endif

View file

@ -975,7 +975,7 @@ void MarlinUI::draw_status_screen() {
#else // !HAS_DUAL_MIXING
const bool show_e_total = TERN0(LCD_SHOW_E_TOTAL, printingIsActive());
const bool show_e_total = TERN1(HAS_X_AXIS, TERN0(LCD_SHOW_E_TOTAL, printingIsActive()));
if (show_e_total) {
#if ENABLED(LCD_SHOW_E_TOTAL)
@ -986,10 +986,14 @@ void MarlinUI::draw_status_screen() {
#endif
}
else {
const xy_pos_t lpos = current_position.asLogical();
_draw_axis_value(X_AXIS, ftostr4sign(lpos.x), blink);
lcd_put_u8str(F(" "));
_draw_axis_value(Y_AXIS, ftostr4sign(lpos.y), blink);
#if HAS_X_AXIS
const xy_pos_t lpos = current_position.asLogical();
_draw_axis_value(X_AXIS, ftostr4sign(lpos.x), blink);
#endif
#if HAS_Y_AXIS
TERN_(HAS_X_AXIS, lcd_put_u8str(F(" ")));
_draw_axis_value(Y_AXIS, ftostr4sign(lpos.y), blink);
#endif
}
#endif // !HAS_DUAL_MIXING
@ -1065,8 +1069,10 @@ void MarlinUI::draw_status_screen() {
//
// Z Coordinate
//
lcd_moveto(LCD_WIDTH - 9, 0);
_draw_axis_value(Z_AXIS, ftostr52sp(LOGICAL_Z_POSITION(current_position.z)), blink);
#if HAS_Z_AXIS
lcd_moveto(LCD_WIDTH - 9, 0);
_draw_axis_value(Z_AXIS, ftostr52sp(LOGICAL_Z_POSITION(current_position.z)), blink);
#endif
#if HAS_LEVELING && (HAS_MULTI_HOTEND || !HAS_HEATED_BED)
lcd_put_lchar(LCD_WIDTH - 1, 0, planner.leveling_active || blink ? '_' : ' ');

View file

@ -820,11 +820,17 @@ void MarlinUI::draw_status_screen() {
// Line 1 - XYZ coordinates
//
lcd_moveto(0, 0);
const xyz_pos_t lpos = current_position.asLogical();
_draw_axis_value(X_AXIS, ftostr4sign(lpos.x), blink); lcd.write(' ');
_draw_axis_value(Y_AXIS, ftostr4sign(lpos.y), blink); lcd.write(' ');
_draw_axis_value(Z_AXIS, ftostr52sp(lpos.z), blink);
#if NUM_AXES
lcd_moveto(0, 0);
const xyz_pos_t lpos = current_position.asLogical();
_draw_axis_value(X_AXIS, ftostr4sign(lpos.x), blink);
#if HAS_Y_AXIS
lcd.write(' '); _draw_axis_value(Y_AXIS, ftostr4sign(lpos.y), blink);
#endif
#if HAS_Z_AXIS
lcd.write(' '); _draw_axis_value(Z_AXIS, ftostr52sp(lpos.z), blink);
#endif
#endif
#if HAS_LEVELING && !HAS_HEATED_BED
lcd.write(planner.leveling_active || blink ? '_' : ' ');

View file

@ -510,20 +510,24 @@ FORCE_INLINE void _draw_axis_value(const AxisEnum axis, const char *value, const
* Use the PAGE_CONTAINS macros to avoid pointless draw calls.
*/
void MarlinUI::draw_status_screen() {
constexpr int xystorage = TERN(INCH_MODE_SUPPORT, 8, 5);
static char xstring[TERN(LCD_SHOW_E_TOTAL, 12, xystorage)];
#if HAS_Y_AXIS
static char ystring[xystorage];
#endif
#if HAS_Z_AXIS
static char zstring[8];
#if NUM_AXES
constexpr int xystorage = TERN(INCH_MODE_SUPPORT, 8, 5);
#if EITHER(HAS_X_AXIS, LCD_SHOW_E_TOTAL)
static char xstring[TERN(LCD_SHOW_E_TOTAL, 12, xystorage)];
#endif
#if HAS_Y_AXIS
static char ystring[xystorage];
#endif
#if HAS_Z_AXIS
static char zstring[8];
#endif
#endif
#if ENABLED(FILAMENT_LCD_DISPLAY)
static char wstring[5], mstring[4];
#endif
const bool show_e_total = TERN0(LCD_SHOW_E_TOTAL, printingIsActive());
const bool show_e_total = TERN1(HAS_X_AXIS, TERN0(LCD_SHOW_E_TOTAL, printingIsActive()));
#if HAS_PRINT_PROGRESS
static u8g_uint_t progress_bar_solid_width = 0;
@ -544,10 +548,9 @@ void MarlinUI::draw_status_screen() {
draw_bits = new_bits;
#endif
const xyz_pos_t lpos = current_position.asLogical();
const bool is_inch = parser.using_inch_units();
#if HAS_Z_AXIS
strcpy(zstring, is_inch ? ftostr42_52(LINEAR_UNIT(lpos.z)) : ftostr52sp(lpos.z));
#if NUM_AXES
const xyz_pos_t lpos = current_position.asLogical();
const bool is_inch = parser.using_inch_units();
#endif
if (show_e_total) {
@ -557,10 +560,12 @@ void MarlinUI::draw_status_screen() {
#endif
}
else {
strcpy(xstring, is_inch ? ftostr53_63(LINEAR_UNIT(lpos.x)) : ftostr4sign(lpos.x));
TERN_(HAS_X_AXIS, strcpy(xstring, is_inch ? ftostr53_63(LINEAR_UNIT(lpos.x)) : ftostr4sign(lpos.x)));
TERN_(HAS_Y_AXIS, strcpy(ystring, is_inch ? ftostr53_63(LINEAR_UNIT(lpos.y)) : ftostr4sign(lpos.y)));
}
TERN_(HAS_Z_AXIS, strcpy(zstring, is_inch ? ftostr42_52(LINEAR_UNIT(lpos.z)) : ftostr52sp(lpos.z)));
#if ENABLED(FILAMENT_LCD_DISPLAY)
strcpy(wstring, ftostr12ns(filwidth.measured_mm));
strcpy(mstring, i16tostr3rj(planner.volumetric_percent(parser.volumetric_enabled)));
@ -839,15 +844,13 @@ void MarlinUI::draw_status_screen() {
#endif
}
else {
_draw_axis_value(X_AXIS, xstring, blink);
TERN_(HAS_X_AXIS, _draw_axis_value(X_AXIS, xstring, blink));
TERN_(HAS_Y_AXIS, _draw_axis_value(Y_AXIS, ystring, blink));
}
#endif
#if HAS_Z_AXIS
_draw_axis_value(Z_AXIS, zstring, blink);
#endif
TERN_(HAS_Z_AXIS, _draw_axis_value(Z_AXIS, zstring, blink));
#if NONE(XYZ_NO_FRAME, XYZ_HOLLOW_FRAME)
u8g.setColorIndex(1); // black on white

View file

@ -2365,14 +2365,16 @@ void CrealityDWINClass::Menu_Item_Handler(const uint8_t menu, const uint8_t item
else
Draw_Menu(Motion, MOTION_SPEED);
break;
case SPEED_X:
if (draw) {
Draw_Menu_Item(row, ICON_MaxSpeedX, F("X Axis"));
Draw_Float(planner.settings.max_feedrate_mm_s[X_AXIS], row, false, 1);
}
else
Modify_Value(planner.settings.max_feedrate_mm_s[X_AXIS], 0, default_max_feedrate[X_AXIS] * 2, 1);
break;
#if HAS_X_AXIS
case SPEED_X:
if (draw) {
Draw_Menu_Item(row, ICON_MaxSpeedX, F("X Axis"));
Draw_Float(planner.settings.max_feedrate_mm_s[X_AXIS], row, false, 1);
}
else
Modify_Value(planner.settings.max_feedrate_mm_s[X_AXIS], 0, default_max_feedrate[X_AXIS] * 2, 1);
break;
#endif
#if HAS_Y_AXIS
case SPEED_Y:

View file

@ -308,14 +308,14 @@ void MarlinUI::draw_status_screen() {
// Axis values
const xyz_pos_t lpos = current_position.asLogical();
const bool show_e_total = TERN0(LCD_SHOW_E_TOTAL, printingIsActive()); UNUSED(show_e_total);
const bool show_e_total = TERN1(HAS_X_AXIS, TERN0(LCD_SHOW_E_TOTAL, printingIsActive()));
constexpr int16_t cpy = TERN(DWIN_MARLINUI_PORTRAIT, 195, 117);
if (show_e_total) {
TERN_(LCD_SHOW_E_TOTAL, _draw_e_value(e_move_accumulator, TERN(DWIN_MARLINUI_PORTRAIT, 6, 75), cpy));
}
else {
_draw_axis_value(X_AXIS, ftostr4sign(lpos.x), blink, TERN(DWIN_MARLINUI_PORTRAIT, 6, 75), cpy);
TERN_(HAS_X_AXIS, _draw_axis_value(X_AXIS, ftostr4sign(lpos.x), blink, TERN(DWIN_MARLINUI_PORTRAIT, 6, 75), cpy));
TERN_(HAS_Y_AXIS, _draw_axis_value(Y_AXIS, ftostr4sign(lpos.y), blink, TERN(DWIN_MARLINUI_PORTRAIT, 95, 184), cpy));
}
TERN_(HAS_Z_AXIS, _draw_axis_value(Z_AXIS, ftostr52sp(lpos.z), blink, TERN(DWIN_MARLINUI_PORTRAIT, 165, 300), cpy));

View file

@ -162,10 +162,12 @@ void DGUSScreenHandler::HandleManualMove(DGUS_VP_Variable &var, void *val_ptr) {
switch (var.VP) {
default: return;
case VP_MOVE_X:
axiscode = 'X';
if (!ExtUI::canMove(ExtUI::axis_t::X)) goto cannotmove;
break;
#if HAS_X_AXIS
case VP_MOVE_X:
axiscode = 'X';
if (!ExtUI::canMove(ExtUI::axis_t::X)) goto cannotmove;
break;
#endif
#if HAS_Y_AXIS
case VP_MOVE_Y:

View file

@ -162,10 +162,12 @@ void DGUSScreenHandler::HandleManualMove(DGUS_VP_Variable &var, void *val_ptr) {
switch (var.VP) {
default: return;
case VP_MOVE_X:
axiscode = 'X';
if (!ExtUI::canMove(ExtUI::axis_t::X)) goto cannotmove;
break;
#if HAS_X_AXIS
case VP_MOVE_X:
axiscode = 'X';
if (!ExtUI::canMove(ExtUI::axis_t::X)) goto cannotmove;
break;
#endif
#if HAS_Y_AXIS
case VP_MOVE_Y:

View file

@ -743,10 +743,12 @@ void DGUSScreenHandler::HandleManualMove(DGUS_VP_Variable &var, void *val_ptr) {
switch (var.VP) { // switch X Y Z or Home
default: return;
case VP_MOVE_X:
axiscode = 'X';
if (!ExtUI::canMove(ExtUI::axis_t::X)) goto cannotmove;
break;
#if HAS_X_AXIS
case VP_MOVE_X:
axiscode = 'X';
if (!ExtUI::canMove(ExtUI::axis_t::X)) goto cannotmove;
break;
#endif
#if HAS_Y_AXIS
case VP_MOVE_Y:
@ -773,10 +775,12 @@ void DGUSScreenHandler::HandleManualMove(DGUS_VP_Variable &var, void *val_ptr) {
movevalue = 0; // ignore value sent from display, this VP is _ONLY_ for homing.
break;
case VP_X_HOME:
axiscode = 'X';
movevalue = 0;
break;
#if HAS_X_AXIS
case VP_X_HOME:
axiscode = 'X';
movevalue = 0;
break;
#endif
#if HAS_Y_AXIS
case VP_Y_HOME:

View file

@ -162,10 +162,12 @@ void DGUSScreenHandler::HandleManualMove(DGUS_VP_Variable &var, void *val_ptr) {
switch (var.VP) {
default: return;
case VP_MOVE_X:
axiscode = 'X';
if (!ExtUI::canMove(ExtUI::axis_t::X)) goto cannotmove;
break;
#if HAS_X_AXIS
case VP_MOVE_X:
axiscode = 'X';
if (!ExtUI::canMove(ExtUI::axis_t::X)) goto cannotmove;
break;
#endif
#if HAS_Y_AXIS
case VP_MOVE_Y:

View file

@ -77,8 +77,10 @@ bool BaseMoveAxisScreen::onTouchHeld(const uint8_t tag) {
#define UI_DECREMENT_AXIS(axis) setManualFeedrate(axis, increment); UI_DECREMENT(AxisPosition_mm, axis);
const float increment = getIncrement();
switch (tag) {
case 2: UI_DECREMENT_AXIS(X); break;
case 3: UI_INCREMENT_AXIS(X); break;
#if HAS_X_AXIS
case 2: UI_DECREMENT_AXIS(X); break;
case 3: UI_INCREMENT_AXIS(X); break;
#endif
#if HAS_EXTRUDERS
// For extruders, also update relative distances.
case 8: UI_DECREMENT_AXIS(E0); mydata.e_rel[0] -= increment; break;

View file

@ -124,8 +124,10 @@ void lv_draw_acceleration_settings() {
lv_screen_menu_item_1_edit(scr, machine_menu.TravelAcceleration, PARA_UI_POS_X, y, event_handler, ID_ACCE_TRAVEL, 2, public_buf_l);
y += PARA_UI_POS_Y;
itoa(planner.settings.max_acceleration_mm_per_s2[X_AXIS], public_buf_l, 10);
lv_screen_menu_item_1_edit(scr, machine_menu.X_Acceleration, PARA_UI_POS_X, y, event_handler, ID_ACCE_X, 3, public_buf_l);
#if HAS_X_AXIS
itoa(planner.settings.max_acceleration_mm_per_s2[X_AXIS], public_buf_l, 10);
lv_screen_menu_item_1_edit(scr, machine_menu.X_Acceleration, PARA_UI_POS_X, y, event_handler, ID_ACCE_X, 3, public_buf_l);
#endif
lv_big_button_create(scr, "F:/bmp_back70x40.bin", machine_menu.next, PARA_UI_TURN_PAGE_POS_X, PARA_UI_TURN_PAGE_POS_Y, event_handler, ID_ACCE_DOWN, true);
}

View file

@ -194,7 +194,9 @@
void mks_hardware_test() {
if (millis() % 2000 < 1000) {
thermalManager.fan_speed[0] = 255;
WRITE(X_DIR_PIN, LOW);
#if HAS_X_AXIS
WRITE(X_DIR_PIN, LOW);
#endif
#if HAS_Y_AXIS
WRITE(Y_DIR_PIN, LOW);
#endif
@ -219,7 +221,9 @@
}
else {
thermalManager.fan_speed[0] = 0;
WRITE(X_DIR_PIN, HIGH);
#if HAS_X_AXIS
WRITE(X_DIR_PIN, HIGH);
#endif
#if HAS_Y_AXIS
WRITE(Y_DIR_PIN, HIGH);
#endif

View file

@ -375,7 +375,7 @@ namespace ExtUI {
bool canMove(const axis_t axis) {
switch (axis) {
#if IS_KINEMATIC || ENABLED(NO_MOTION_BEFORE_HOMING)
case X: return !axis_should_home(X_AXIS);
OPTCODE(HAS_X_AXIS, case X: return !axis_should_home(X_AXIS))
OPTCODE(HAS_Y_AXIS, case Y: return !axis_should_home(Y_AXIS))
OPTCODE(HAS_Z_AXIS, case Z: return !axis_should_home(Z_AXIS))
#else
@ -773,7 +773,9 @@ namespace ExtUI {
bool babystepAxis_steps(const int16_t steps, const axis_t axis) {
switch (axis) {
#if ENABLED(BABYSTEP_XY)
case X: babystep.add_steps(X_AXIS, steps); break;
#if HAS_X_AXIS
case X: babystep.add_steps(X_AXIS, steps); break;
#endif
#if HAS_Y_AXIS
case Y: babystep.add_steps(Y_AXIS, steps); break;
#endif
@ -818,7 +820,7 @@ namespace ExtUI {
if (e != active_extruder)
hotend_offset[e][axis] += mm;
normalizeNozzleOffset(X);
TERN_(HAS_X_AXIS, normalizeNozzleOffset(X));
TERN_(HAS_Y_AXIS, normalizeNozzleOffset(Y));
TERN_(HAS_Z_AXIS, normalizeNozzleOffset(Z));
}

View file

@ -506,7 +506,7 @@ void MarlinUI::init() {
ui.manual_move.menu_scale = REPRAPWORLD_KEYPAD_MOVE_STEP;
ui.encoderPosition = dir;
switch (axis) {
case X_AXIS:
TERN_(HAS_X_AXIS, case X_AXIS:)
TERN_(HAS_Y_AXIS, case Y_AXIS:)
TERN_(HAS_Z_AXIS, case Z_AXIS:)
lcd_move_axis(axis);

View file

@ -475,9 +475,23 @@ void menu_backlash();
// M201 / M204 Accelerations
void menu_advanced_acceleration() {
float max_accel = planner.settings.max_acceleration_mm_per_s2[A_AXIS];
TERN_(HAS_Y_AXIS, NOLESS(max_accel, planner.settings.max_acceleration_mm_per_s2[B_AXIS]));
TERN_(HAS_Z_AXIS, NOLESS(max_accel, planner.settings.max_acceleration_mm_per_s2[C_AXIS]));
float max_accel = (
#if NUM_AXES
_MAX(NUM_AXIS_LIST(
planner.settings.max_acceleration_mm_per_s2[A_AXIS],
planner.settings.max_acceleration_mm_per_s2[B_AXIS],
planner.settings.max_acceleration_mm_per_s2[C_AXIS],
planner.settings.max_acceleration_mm_per_s2[I_AXIS],
planner.settings.max_acceleration_mm_per_s2[J_AXIS],
planner.settings.max_acceleration_mm_per_s2[K_AXIS],
planner.settings.max_acceleration_mm_per_s2[U_AXIS],
planner.settings.max_acceleration_mm_per_s2[V_AXIS],
planner.settings.max_acceleration_mm_per_s2[W_AXIS]
))
#else
0
#endif
);
// M201 settings
constexpr xyze_ulong_t max_accel_edit =

View file

@ -50,7 +50,9 @@ void menu_backlash() {
EDIT_ITEM_FAST_N(float43, _AXIS(N), MSG_BACKLASH_N, &editable.decimal, 0.0f, 9.9f, []{ backlash.set_distance_mm(_AXIS(N), editable.decimal); }); \
} while (0);
if (_CAN_CALI(A)) EDIT_BACKLASH_DISTANCE(A);
#if HAS_X_AXIS && _CAN_CALI(A)
EDIT_BACKLASH_DISTANCE(A);
#endif
#if HAS_Y_AXIS && _CAN_CALI(B)
EDIT_BACKLASH_DISTANCE(B);
#endif

View file

@ -28,7 +28,7 @@
#if HAS_MARLINUI_MENU
#define HAS_LARGE_AREA ((X_BED_SIZE) >= 1000 || TERN0(HAS_Y_AXIS, (Y_BED_SIZE) >= 1000) || TERN0(HAS_Z_AXIS, (Z_MAX_POS) >= 1000))
#define HAS_LARGE_AREA (TERN0(HAS_X_AXIS, (X_BED_SIZE) >= 1000) || TERN0(HAS_Y_AXIS, (Y_BED_SIZE) >= 1000) || TERN0(HAS_Z_AXIS, (Z_MAX_POS) >= 1000))
#if ENABLED(LARGE_MOVE_ITEMS)
#define HAS_LARGE_MOVES true
#elif ENABLED(SLIM_LCD_MENUS)
@ -214,7 +214,9 @@ void menu_move() {
// Move submenu for each axis
if (NONE(IS_KINEMATIC, NO_MOTION_BEFORE_HOMING) || all_axes_homed()) {
if (TERN1(DELTA, current_position.z <= delta_clip_start_height)) {
SUBMENU_N(X_AXIS, MSG_MOVE_N, []{ _menu_move_distance(X_AXIS, []{ lcd_move_axis(X_AXIS); }); });
#if HAS_X_AXIS
SUBMENU_N(X_AXIS, MSG_MOVE_N, []{ _menu_move_distance(X_AXIS, []{ lcd_move_axis(X_AXIS); }); });
#endif
#if HAS_Y_AXIS
SUBMENU_N(Y_AXIS, MSG_MOVE_N, []{ _menu_move_distance(Y_AXIS, []{ lcd_move_axis(Y_AXIS); }); });
#endif

View file

@ -50,9 +50,9 @@ struct vector_3 {
float pos[3];
};
vector_3(const_float_t _x, const_float_t _y, const_float_t _z) : x(_x), y(_y), z(_z) {}
vector_3(const xy_float_t &in) { x = in.x; TERN_(HAS_Y_AXIS, y = in.y); }
vector_3(const xyz_float_t &in) { x = in.x; TERN_(HAS_Y_AXIS, y = in.y); TERN_(HAS_Z_AXIS, z = in.z); }
vector_3(const xyze_float_t &in) { x = in.x; TERN_(HAS_Y_AXIS, y = in.y); TERN_(HAS_Z_AXIS, z = in.z); }
vector_3(const xy_float_t &in) { TERN_(HAS_X_AXIS, x = in.x); TERN_(HAS_Y_AXIS, y = in.y); }
vector_3(const xyz_float_t &in) { TERN_(HAS_X_AXIS, x = in.x); TERN_(HAS_Y_AXIS, y = in.y); TERN_(HAS_Z_AXIS, z = in.z); }
vector_3(const xyze_float_t &in) { TERN_(HAS_X_AXIS, x = in.x); TERN_(HAS_Y_AXIS, y = in.y); TERN_(HAS_Z_AXIS, z = in.z); }
vector_3() { x = y = z = 0; }
// Factory method
@ -75,8 +75,8 @@ struct vector_3 {
vector_3 operator-(const vector_3 &v) { return vector_3(x - v.x, y - v.y, z - v.z); }
vector_3 operator*(const float &v) { return vector_3(x * v, y * v, z * v); }
operator xy_float_t() { return xy_float_t({ x OPTARG(HAS_Y_AXIS, y) }); }
operator xyz_float_t() { return xyz_float_t({ x OPTARG(HAS_Y_AXIS, y) OPTARG(HAS_Z_AXIS, z) }); }
operator xy_float_t() { return xy_float_t({ TERN_(HAS_X_AXIS, x) OPTARG(HAS_Y_AXIS, y) }); }
operator xyz_float_t() { return xyz_float_t({ TERN_(HAS_X_AXIS, x) OPTARG(HAS_Y_AXIS, y) OPTARG(HAS_Z_AXIS, z) }); }
void debug(FSTR_P const title);
};

View file

@ -300,7 +300,7 @@ void Endstops::event_handler() {
prev_hit_state = hit_state;
if (hit_state) {
#if HAS_STATUS_MESSAGE
char NUM_AXIS_LIST(chrX = ' ', chrY = ' ', chrZ = ' ', chrI = ' ', chrJ = ' ', chrK = ' ', chrU = ' ', chrV = ' ', chrW = ' '),
char NUM_AXIS_LIST_(chrX = ' ', chrY = ' ', chrZ = ' ', chrI = ' ', chrJ = ' ', chrK = ' ', chrU = ' ', chrV = ' ', chrW = ' ')
chrP = ' ';
#define _SET_STOP_CHAR(A,C) (chr## A = C)
#else
@ -348,7 +348,7 @@ void Endstops::event_handler() {
ui.status_printf(0,
F(S_FMT GANG_N_1(NUM_AXES, " %c") " %c"),
GET_TEXT(MSG_LCD_ENDSTOPS),
NUM_AXIS_LIST(chrX, chrY, chrZ, chrI, chrJ, chrK, chrU, chrV, chrW), chrP
NUM_AXIS_LIST_(chrX, chrY, chrZ, chrI, chrJ, chrK, chrU, chrV, chrW) chrP
)
);
@ -367,19 +367,23 @@ void Endstops::event_handler() {
}
}
#pragma GCC diagnostic push
#if GCC_VERSION <= 50000
#pragma GCC diagnostic ignored "-Wunused-function"
#if NUM_AXES
#pragma GCC diagnostic push
#if GCC_VERSION <= 50000
#pragma GCC diagnostic ignored "-Wunused-function"
#endif
static void print_es_state(const bool is_hit, FSTR_P const flabel=nullptr) {
if (flabel) SERIAL_ECHOF(flabel);
SERIAL_ECHOPGM(": ");
SERIAL_ECHOLNF(is_hit ? F(STR_ENDSTOP_HIT) : F(STR_ENDSTOP_OPEN));
}
#pragma GCC diagnostic pop
#endif
static void print_es_state(const bool is_hit, FSTR_P const flabel=nullptr) {
if (flabel) SERIAL_ECHOF(flabel);
SERIAL_ECHOPGM(": ");
SERIAL_ECHOLNF(is_hit ? F(STR_ENDSTOP_HIT) : F(STR_ENDSTOP_OPEN));
}
#pragma GCC diagnostic pop
void __O2 Endstops::report_states() {
TERN_(BLTOUCH, bltouch._set_SW_mode());
SERIAL_ECHOLNPGM(STR_M119_REPORT);

View file

@ -203,22 +203,24 @@ 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_ECHOPGM_P(
LIST_N(DOUBLE(NUM_AXES),
X_LBL, lpos.x,
SP_Y_LBL, lpos.y,
SP_Z_LBL, lpos.z,
SP_I_LBL, lpos.i,
SP_J_LBL, lpos.j,
SP_K_LBL, lpos.k,
SP_U_LBL, lpos.u,
SP_V_LBL, lpos.v,
SP_W_LBL, lpos.w
)
#if HAS_EXTRUDERS
, SP_E_LBL, lpos.e
#endif
);
#if NUM_AXES
SERIAL_ECHOPGM_P(
LIST_N(DOUBLE(NUM_AXES),
X_LBL, lpos.x,
SP_Y_LBL, lpos.y,
SP_Z_LBL, lpos.z,
SP_I_LBL, lpos.i,
SP_J_LBL, lpos.j,
SP_K_LBL, lpos.k,
SP_U_LBL, lpos.u,
SP_V_LBL, lpos.v,
SP_W_LBL, lpos.w
)
);
#endif
#if HAS_EXTRUDERS
SERIAL_ECHOPGM_P(SP_E_LBL, lpos.e);
#endif
}
// Report the real current position according to the steppers.
@ -367,7 +369,7 @@ void report_current_position_projected() {
#else // CARTESIAN
// Return true if the given position is within the machine bounds.
bool position_is_reachable(const_float_t rx, const_float_t ry) {
bool position_is_reachable(TERN_(HAS_X_AXIS, const_float_t rx) OPTARG(HAS_Y_AXIS, const_float_t ry)) {
if (TERN0(HAS_Y_AXIS, !COORDINATE_OKAY(ry, Y_MIN_POS - fslop, Y_MAX_POS + fslop))) return false;
#if ENABLED(DUAL_X_CARRIAGE)
if (active_extruder)
@ -375,7 +377,8 @@ void report_current_position_projected() {
else
return COORDINATE_OKAY(rx, X1_MIN_POS - fslop, X1_MAX_POS + fslop);
#else
return COORDINATE_OKAY(rx, X_MIN_POS - fslop, X_MAX_POS + fslop);
if (TERN0(HAS_X_AXIS, !COORDINATE_OKAY(rx, X_MIN_POS - fslop, X_MAX_POS + fslop))) return false;
return true;
#endif
}
@ -567,7 +570,7 @@ 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(NUM_AXIS_ARGS(const_float_t), const_feedRate_t fr_mm_s/*=0.0f*/) {
void do_blocking_move_to(NUM_AXIS_ARGS_(const_float_t) const_feedRate_t fr_mm_s/*=0.0f*/) {
DEBUG_SECTION(log_move, "do_blocking_move_to", DEBUGGING(LEVELING));
if (DEBUGGING(LEVELING)) DEBUG_XYZ("> ", NUM_AXIS_ARGS());
@ -642,7 +645,7 @@ void do_blocking_move_to(NUM_AXIS_ARGS(const_float_t), const_feedRate_t fr_mm_s/
if (current_position.z < z) { current_position.z = z; line_to_current_position(z_feedrate); }
#endif
current_position.set(x OPTARG(HAS_Y_AXIS, y)); line_to_current_position(xy_feedrate);
current_position.set(TERN_(HAS_X_AXIS, x) OPTARG(HAS_Y_AXIS, y)); line_to_current_position(xy_feedrate);
#if SECONDARY_AXES
secondary_axis_moves(SECONDARY_AXIS_LIST(i, j, k, u, v, w), fr_mm_s);
@ -659,30 +662,33 @@ void do_blocking_move_to(NUM_AXIS_ARGS(const_float_t), const_feedRate_t fr_mm_s/
}
void do_blocking_move_to(const xy_pos_t &raw, const_feedRate_t fr_mm_s/*=0.0f*/) {
do_blocking_move_to(NUM_AXIS_LIST(raw.x, raw.y, current_position.z, current_position.i, current_position.j, current_position.k,
current_position.u, current_position.v, current_position.w), fr_mm_s);
do_blocking_move_to(NUM_AXIS_LIST_(raw.x, raw.y, current_position.z, current_position.i, current_position.j, current_position.k,
current_position.u, current_position.v, current_position.w) 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(NUM_AXIS_ELEM(raw), fr_mm_s);
do_blocking_move_to(NUM_AXIS_ELEM_(raw) 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(NUM_AXIS_ELEM(raw), fr_mm_s);
}
void do_blocking_move_to_x(const_float_t rx, const_feedRate_t fr_mm_s/*=0.0*/) {
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("do_blocking_move_to_x(", rx, ", ", fr_mm_s, ")");
do_blocking_move_to(
NUM_AXIS_LIST(rx, current_position.y, current_position.z, current_position.i, current_position.j, current_position.k,
current_position.u, current_position.v, current_position.w),
fr_mm_s
);
do_blocking_move_to(NUM_AXIS_ELEM_(raw) fr_mm_s);
}
#if HAS_X_AXIS
void do_blocking_move_to_x(const_float_t rx, const_feedRate_t fr_mm_s/*=0.0*/) {
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("do_blocking_move_to_x(", rx, ", ", fr_mm_s, ")");
do_blocking_move_to(
NUM_AXIS_LIST_(rx, current_position.y, current_position.z, current_position.i, current_position.j, current_position.k,
current_position.u, current_position.v, current_position.w)
fr_mm_s
);
}
#endif
#if HAS_Y_AXIS
void do_blocking_move_to_y(const_float_t ry, const_feedRate_t fr_mm_s/*=0.0*/) {
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("do_blocking_move_to_y(", ry, ", ", fr_mm_s, ")");
do_blocking_move_to(
NUM_AXIS_LIST(current_position.x, ry, current_position.z, current_position.i, current_position.j, current_position.k,
current_position.u, current_position.v, current_position.w),
NUM_AXIS_LIST_(current_position.x, ry, current_position.z, current_position.i, current_position.j, current_position.k,
current_position.u, current_position.v, current_position.w)
fr_mm_s
);
}
@ -701,7 +707,7 @@ void do_blocking_move_to_x(const_float_t rx, const_feedRate_t fr_mm_s/*=0.0*/) {
}
void do_blocking_move_to_xyz_i(const xyze_pos_t &raw, const_float_t i, const_feedRate_t fr_mm_s/*=0.0f*/) {
do_blocking_move_to(
NUM_AXIS_LIST(raw.x, raw.y, raw.z, i, raw.j, raw.k, raw.u, raw.v, raw.w),
NUM_AXIS_LIST_(raw.x, raw.y, raw.z, i, raw.j, raw.k, raw.u, raw.v, raw.w)
fr_mm_s
);
}
@ -713,7 +719,7 @@ void do_blocking_move_to_x(const_float_t rx, const_feedRate_t fr_mm_s/*=0.0*/) {
}
void do_blocking_move_to_xyzi_j(const xyze_pos_t &raw, const_float_t j, const_feedRate_t fr_mm_s/*=0.0f*/) {
do_blocking_move_to(
NUM_AXIS_LIST(raw.x, raw.y, raw.z, raw.i, j, raw.k, raw.u, raw.v, raw.w),
NUM_AXIS_LIST_(raw.x, raw.y, raw.z, raw.i, j, raw.k, raw.u, raw.v, raw.w)
fr_mm_s
);
}
@ -725,7 +731,7 @@ void do_blocking_move_to_x(const_float_t rx, const_feedRate_t fr_mm_s/*=0.0*/) {
}
void do_blocking_move_to_xyzij_k(const xyze_pos_t &raw, const_float_t k, const_feedRate_t fr_mm_s/*=0.0f*/) {
do_blocking_move_to(
NUM_AXIS_LIST(raw.x, raw.y, raw.z, raw.i, raw.j, k, raw.u, raw.v, raw.w),
NUM_AXIS_LIST_(raw.x, raw.y, raw.z, raw.i, raw.j, k, raw.u, raw.v, raw.w)
fr_mm_s
);
}
@ -737,7 +743,7 @@ void do_blocking_move_to_x(const_float_t rx, const_feedRate_t fr_mm_s/*=0.0*/) {
}
void do_blocking_move_to_xyzijk_u(const xyze_pos_t &raw, const_float_t u, const_feedRate_t fr_mm_s/*=0.0f*/) {
do_blocking_move_to(
NUM_AXIS_LIST(raw.x, raw.y, raw.z, raw.i, raw.j, raw.k, u, raw.v, raw.w),
NUM_AXIS_LIST_(raw.x, raw.y, raw.z, raw.i, raw.j, raw.k, u, raw.v, raw.w)
fr_mm_s
);
}
@ -749,7 +755,7 @@ void do_blocking_move_to_x(const_float_t rx, const_feedRate_t fr_mm_s/*=0.0*/) {
}
void do_blocking_move_to_xyzijku_v(const xyze_pos_t &raw, const_float_t v, const_feedRate_t fr_mm_s/*=0.0f*/) {
do_blocking_move_to(
NUM_AXIS_LIST(raw.x, raw.y, raw.z, raw.i, raw.j, raw.k, raw.u, v, raw.w),
NUM_AXIS_LIST_(raw.x, raw.y, raw.z, raw.i, raw.j, raw.k, raw.u, v, raw.w)
fr_mm_s
);
}
@ -761,7 +767,7 @@ void do_blocking_move_to_x(const_float_t rx, const_feedRate_t fr_mm_s/*=0.0*/) {
}
void do_blocking_move_to_xyzijkuv_w(const xyze_pos_t &raw, const_float_t w, const_feedRate_t fr_mm_s/*=0.0f*/) {
do_blocking_move_to(
NUM_AXIS_LIST(raw.x, raw.y, raw.z, raw.i, raw.j, raw.k, raw.u, raw.v, w),
NUM_AXIS_LIST_(raw.x, raw.y, raw.z, raw.i, raw.j, raw.k, raw.u, raw.v, w)
fr_mm_s
);
}
@ -771,8 +777,8 @@ void do_blocking_move_to_x(const_float_t rx, const_feedRate_t fr_mm_s/*=0.0*/) {
void do_blocking_move_to_xy(const_float_t rx, const_float_t ry, const_feedRate_t fr_mm_s/*=0.0*/) {
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("do_blocking_move_to_xy(", rx, ", ", ry, ", ", fr_mm_s, ")");
do_blocking_move_to(
NUM_AXIS_LIST(rx, ry, current_position.z, current_position.i, current_position.j, current_position.k,
current_position.u, current_position.v, current_position.w),
NUM_AXIS_LIST_(rx, ry, current_position.z, current_position.i, current_position.j, current_position.k,
current_position.u, current_position.v, current_position.w)
fr_mm_s
);
}
@ -784,8 +790,8 @@ void do_blocking_move_to_x(const_float_t rx, const_feedRate_t fr_mm_s/*=0.0*/) {
#if HAS_Z_AXIS
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(
NUM_AXIS_LIST(raw.x, raw.y, z, current_position.i, current_position.j, current_position.k,
current_position.u, current_position.v, current_position.w),
NUM_AXIS_LIST_(raw.x, raw.y, z, current_position.i, current_position.j, current_position.k,
current_position.u, current_position.v, current_position.w)
fr_mm_s
);
}
@ -966,14 +972,16 @@ void restore_feedrate_and_scaling() {
#else
if (axis_was_homed(X_AXIS)) {
#if !HAS_SOFTWARE_ENDSTOPS || ENABLED(MIN_SOFTWARE_ENDSTOP_X)
NOLESS(target.x, soft_endstop.min.x);
#endif
#if !HAS_SOFTWARE_ENDSTOPS || ENABLED(MAX_SOFTWARE_ENDSTOP_X)
NOMORE(target.x, soft_endstop.max.x);
#endif
}
#if HAS_X_AXIS
if (axis_was_homed(X_AXIS)) {
#if !HAS_SOFTWARE_ENDSTOPS || ENABLED(MIN_SOFTWARE_ENDSTOP_X)
NOLESS(target.x, soft_endstop.min.x);
#endif
#if !HAS_SOFTWARE_ENDSTOPS || ENABLED(MAX_SOFTWARE_ENDSTOP_X)
NOMORE(target.x, soft_endstop.max.x);
#endif
}
#endif
#if HAS_Y_AXIS
if (axis_was_homed(Y_AXIS)) {
@ -1079,82 +1087,90 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) {
* Get distance from displacements along axes and, if required, update move type.
*/
float get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXES, bool &is_cartesian_move)) {
if (!(NUM_AXIS_GANG(diff.x, || diff.y, /* skip z */, || diff.i, || diff.j, || diff.k, || diff.u, || diff.v, || diff.w)))
return TERN0(HAS_Z_AXIS, ABS(diff.z));
#if NUM_AXES
#if ENABLED(ARTICULATED_ROBOT_ARM)
if (!(NUM_AXIS_GANG(diff.x, || diff.y, /* skip z */, || diff.i, || diff.j, || diff.k, || diff.u, || diff.v, || diff.w)))
return TERN0(HAS_Z_AXIS, ABS(diff.z));
// For articulated robots, interpreting feedrate like LinuxCNC would require inverse kinematics. As a workaround, pretend that motors sit on n mutually orthogonal
// axes and assume that we could think of distance as magnitude of an n-vector in an n-dimensional Euclidian space.
const float distance_sqr = NUM_AXIS_GANG(
sq(diff.x), + sq(diff.y), + sq(diff.z),
+ sq(diff.i), + sq(diff.j), + sq(diff.k),
+ sq(diff.u), + sq(diff.v), + sq(diff.w)
);
#if ENABLED(ARTICULATED_ROBOT_ARM)
#elif ENABLED(FOAMCUTTER_XYUV)
// For articulated robots, interpreting feedrate like LinuxCNC would require inverse kinematics. As a workaround, pretend that motors sit on n mutually orthogonal
// axes and assume that we could think of distance as magnitude of an n-vector in an n-dimensional Euclidian space.
const float distance_sqr = NUM_AXIS_GANG(
sq(diff.x), + sq(diff.y), + sq(diff.z),
+ sq(diff.i), + sq(diff.j), + sq(diff.k),
+ sq(diff.u), + sq(diff.v), + sq(diff.w)
);
const float distance_sqr = (
#if HAS_J_AXIS
_MAX(sq(diff.x) + sq(diff.y), sq(diff.i) + sq(diff.j)) // Special 5 axis kinematics. Return the larger of plane X/Y or I/J
#else
sq(diff.x) + sq(diff.y) // Foamcutter with only two axes (XY)
#elif ENABLED(FOAMCUTTER_XYUV)
const float distance_sqr = (
#if HAS_J_AXIS
_MAX(sq(diff.x) + sq(diff.y), sq(diff.i) + sq(diff.j)) // Special 5 axis kinematics. Return the larger of plane X/Y or I/J
#else
sq(diff.x) + sq(diff.y) // Foamcutter with only two axes (XY)
#endif
);
#else
/**
* Calculate distance for feedrate interpretation in accordance with NIST RS274NGC interpreter - version 3) and its default CANON_XYZ feed reference mode.
* Assume:
* - X, Y, Z are the primary linear axes;
* - U, V, W are secondary linear axes;
* - A, B, C are rotational axes.
*
* Then:
* - dX, dY, dZ are the displacements of the primary linear axes;
* - dU, dV, dW are the displacements of linear axes;
* - dA, dB, dC are the displacements of rotational axes.
*
* The time it takes to execute a move command with feedrate F is t = D/F,
* plus any time for acceleration and deceleration.
* Here, D is the total distance, calculated as follows:
*
* D^2 = dX^2 + dY^2 + dZ^2
* if D^2 == 0 (none of XYZ move but any secondary linear axes move, whether other axes are moved or not):
* D^2 = dU^2 + dV^2 + dW^2
* if D^2 == 0 (only rotational axes are moved):
* D^2 = dA^2 + dB^2 + dC^2
*/
float distance_sqr = XYZ_GANG(sq(diff.x), + sq(diff.y), + sq(diff.z));
#if SECONDARY_LINEAR_AXES
if (UNEAR_ZERO(distance_sqr)) {
// Move does not involve any primary linear axes (xyz) but might involve secondary linear axes
distance_sqr = (
SECONDARY_AXIS_GANG(
IF_DISABLED(AXIS4_ROTATES, + sq(diff.i)),
IF_DISABLED(AXIS5_ROTATES, + sq(diff.j)),
IF_DISABLED(AXIS6_ROTATES, + sq(diff.k)),
IF_DISABLED(AXIS7_ROTATES, + sq(diff.u)),
IF_DISABLED(AXIS8_ROTATES, + sq(diff.v)),
IF_DISABLED(AXIS9_ROTATES, + sq(diff.w))
)
);
}
#endif
);
#if HAS_ROTATIONAL_AXES
if (UNEAR_ZERO(distance_sqr)) {
// Move involves only rotational axes. Calculate angular distance in accordance with LinuxCNC
is_cartesian_move = false;
distance_sqr = ROTATIONAL_AXIS_GANG(sq(diff.i), + sq(diff.j), + sq(diff.k), + sq(diff.u), + sq(diff.v), + sq(diff.w));
}
#endif
#endif
return SQRT(distance_sqr);
#else
/**
* Calculate distance for feedrate interpretation in accordance with NIST RS274NGC interpreter - version 3) and its default CANON_XYZ feed reference mode.
* Assume:
* - X, Y, Z are the primary linear axes;
* - U, V, W are secondary linear axes;
* - A, B, C are rotational axes.
*
* Then:
* - dX, dY, dZ are the displacements of the primary linear axes;
* - dU, dV, dW are the displacements of linear axes;
* - dA, dB, dC are the displacements of rotational axes.
*
* The time it takes to execute a move command with feedrate F is t = D/F,
* plus any time for acceleration and deceleration.
* Here, D is the total distance, calculated as follows:
*
* D^2 = dX^2 + dY^2 + dZ^2
* if D^2 == 0 (none of XYZ move but any secondary linear axes move, whether other axes are moved or not):
* D^2 = dU^2 + dV^2 + dW^2
* if D^2 == 0 (only rotational axes are moved):
* D^2 = dA^2 + dB^2 + dC^2
*/
float distance_sqr = XYZ_GANG(sq(diff.x), + sq(diff.y), + sq(diff.z));
#if SECONDARY_LINEAR_AXES
if (UNEAR_ZERO(distance_sqr)) {
// Move does not involve any primary linear axes (xyz) but might involve secondary linear axes
distance_sqr = (
SECONDARY_AXIS_GANG(
IF_DISABLED(AXIS4_ROTATES, + sq(diff.i)),
IF_DISABLED(AXIS5_ROTATES, + sq(diff.j)),
IF_DISABLED(AXIS6_ROTATES, + sq(diff.k)),
IF_DISABLED(AXIS7_ROTATES, + sq(diff.u)),
IF_DISABLED(AXIS8_ROTATES, + sq(diff.v)),
IF_DISABLED(AXIS9_ROTATES, + sq(diff.w))
)
);
}
#endif
#if HAS_ROTATIONAL_AXES
if (UNEAR_ZERO(distance_sqr)) {
// Move involves only rotational axes. Calculate angular distance in accordance with LinuxCNC
is_cartesian_move = false;
distance_sqr = ROTATIONAL_AXIS_GANG(sq(diff.i), + sq(diff.j), + sq(diff.k), + sq(diff.u), + sq(diff.v), + sq(diff.w));
}
#endif
return 0;
#endif
return SQRT(distance_sqr);
}
#if IS_KINEMATIC
@ -1702,7 +1718,9 @@ void prepare_line_to_destination() {
#if ENABLED(SPI_ENDSTOPS)
switch (axis) {
case X_AXIS: if (ENABLED(X_SPI_SENSORLESS)) endstops.tmc_spi_homing.x = true; break;
#if HAS_X_AXIS
case X_AXIS: if (ENABLED(X_SPI_SENSORLESS)) endstops.tmc_spi_homing.x = true; break;
#endif
#if HAS_Y_AXIS
case Y_AXIS: if (ENABLED(Y_SPI_SENSORLESS)) endstops.tmc_spi_homing.y = true; break;
#endif
@ -1796,7 +1814,9 @@ void prepare_line_to_destination() {
#if ENABLED(SPI_ENDSTOPS)
switch (axis) {
case X_AXIS: if (ENABLED(X_SPI_SENSORLESS)) endstops.tmc_spi_homing.x = false; break;
#if HAS_X_AXIS
case X_AXIS: if (ENABLED(X_SPI_SENSORLESS)) endstops.tmc_spi_homing.x = false; break;
#endif
#if HAS_Y_AXIS
case Y_AXIS: if (ENABLED(Y_SPI_SENSORLESS)) endstops.tmc_spi_homing.y = false; break;
#endif

View file

@ -153,9 +153,9 @@ inline float home_bump_mm(const AxisEnum axis) {
extern xyz_pos_t hotend_offset[HOTENDS];
void reset_hotend_offsets();
#elif HOTENDS
constexpr xyz_pos_t hotend_offset[HOTENDS] = { { 0 } };
constexpr xyz_pos_t hotend_offset[HOTENDS] = { { TERN_(HAS_X_AXIS, 0) } };
#else
constexpr xyz_pos_t hotend_offset[1] = { { 0 } };
constexpr xyz_pos_t hotend_offset[1] = { { TERN_(HAS_X_AXIS, 0) } };
#endif
#if HAS_SOFTWARE_ENDSTOPS
@ -169,10 +169,12 @@ inline float home_bump_mm(const AxisEnum axis) {
amin = -100000; amax = 100000; // "No limits"
#if HAS_SOFTWARE_ENDSTOPS
if (enabled()) switch (axis) {
case X_AXIS:
TERN_(MIN_SOFTWARE_ENDSTOP_X, amin = min.x);
TERN_(MAX_SOFTWARE_ENDSTOP_X, amax = max.x);
break;
#if HAS_X_AXIS
case X_AXIS:
TERN_(MIN_SOFTWARE_ENDSTOP_X, amin = min.x);
TERN_(MAX_SOFTWARE_ENDSTOP_X, amax = max.x);
break;
#endif
#if HAS_Y_AXIS
case Y_AXIS:
TERN_(MIN_SOFTWARE_ENDSTOP_Y, amin = min.y);
@ -350,12 +352,14 @@ 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(NUM_AXIS_ARGS(const_float_t), const_feedRate_t fr_mm_s=0.0f);
void do_blocking_move_to(NUM_AXIS_ARGS_(const_float_t) 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);
void do_blocking_move_to_x(const_float_t rx, const_feedRate_t fr_mm_s=0.0f);
#if HAS_X_AXIS
void do_blocking_move_to_x(const_float_t rx, const_feedRate_t fr_mm_s=0.0f);
#endif
#if HAS_Y_AXIS
void do_blocking_move_to_y(const_float_t ry, const_feedRate_t fr_mm_s=0.0f);
#endif
@ -515,8 +519,10 @@ void home_if_needed(const bool keeplev=false);
FORCE_INLINE void toNative(xyz_pos_t&) {}
FORCE_INLINE void toNative(xyze_pos_t&) {}
#endif
#define LOGICAL_X_POSITION(POS) NATIVE_TO_LOGICAL(POS, X_AXIS)
#define RAW_X_POSITION(POS) LOGICAL_TO_NATIVE(POS, X_AXIS)
#if HAS_X_AXIS
#define LOGICAL_X_POSITION(POS) NATIVE_TO_LOGICAL(POS, X_AXIS)
#define RAW_X_POSITION(POS) LOGICAL_TO_NATIVE(POS, X_AXIS)
#endif
#if HAS_Y_AXIS
#define LOGICAL_Y_POSITION(POS) NATIVE_TO_LOGICAL(POS, Y_AXIS)
#define RAW_Y_POSITION(POS) LOGICAL_TO_NATIVE(POS, Y_AXIS)
@ -569,9 +575,9 @@ void home_if_needed(const bool keeplev=false);
#else
// Return true if the given position is within the machine bounds.
bool position_is_reachable(const_float_t rx, const_float_t ry);
bool position_is_reachable(TERN_(HAS_X_AXIS, const_float_t rx) OPTARG(HAS_Y_AXIS, const_float_t ry));
inline bool position_is_reachable(const xy_pos_t &pos) {
return position_is_reachable(pos.x, pos.y);
return position_is_reachable(TERN_(HAS_X_AXIS, pos.x) OPTARG(HAS_Y_AXIS, pos.y));
}
#endif

View file

@ -1903,7 +1903,9 @@ bool Planner::_populate_block(
/* <-- add a slash to enable
SERIAL_ECHOLNPGM(
" _populate_block FR:", fr_mm_s,
" A:", target.a, " (", da, " steps)"
#if HAS_X_AXIS
" A:", target.a, " (", da, " steps)"
#endif
#if HAS_Y_AXIS
" B:", target.b, " (", db, " steps)"
#endif
@ -2204,11 +2206,17 @@ bool Planner::_populate_block(
TERN_(HAS_EXTRUDERS, block->steps.e = esteps);
block->step_event_count = _MAX(LOGICAL_AXIS_LIST(esteps,
block->steps.a, block->steps.b, block->steps.c,
block->steps.i, block->steps.j, block->steps.k,
block->steps.u, block->steps.v, block->steps.w
));
block->step_event_count = (
#if NUM_AXES
_MAX(LOGICAL_AXIS_LIST(esteps,
block->steps.a, block->steps.b, block->steps.c,
block->steps.i, block->steps.j, block->steps.k,
block->steps.u, block->steps.v, block->steps.w
))
#elif HAS_EXTRUDERS
esteps
#endif
);
// Bail if this is a zero-length block
if (block->step_event_count < MIN_STEPS_PER_SEGMENT) return false;
@ -2474,8 +2482,8 @@ bool Planner::_populate_block(
#if ENABLED(LIN_ADVANCE)
bool use_advance_lead = false;
#endif
if (NUM_AXIS_GANG(
!block->steps.a, && !block->steps.b, && !block->steps.c,
if (true NUM_AXIS_GANG(
&& !block->steps.a, && !block->steps.b, && !block->steps.c,
&& !block->steps.i, && !block->steps.j, && !block->steps.k,
&& !block->steps.u, && !block->steps.v, && !block->steps.w)
) { // Is this a retract / recover move?

View file

@ -182,7 +182,7 @@ public:
static bool set_deployed(const bool, const bool=false) { return false; }
static bool can_reach(const_float_t rx, const_float_t ry, const bool=true) { return position_is_reachable(rx, ry); }
static bool can_reach(const_float_t rx, const_float_t ry, const bool=true) { return position_is_reachable(TERN_(HAS_X_AXIS, rx) OPTARG(HAS_Y_AXIS, ry)); }
#endif // !HAS_BED_PROBE

View file

@ -181,10 +181,10 @@
#define _EN_ITEM(N) , E##N
#define _EN1_ITEM(N) , E##N:1
typedef struct { uint16_t MAIN_AXIS_NAMES, X2, Y2, Z2, Z3, Z4 REPEAT(E_STEPPERS, _EN_ITEM); } per_stepper_uint16_t;
typedef struct { uint32_t MAIN_AXIS_NAMES, X2, Y2, Z2, Z3, Z4 REPEAT(E_STEPPERS, _EN_ITEM); } per_stepper_uint32_t;
typedef struct { int16_t MAIN_AXIS_NAMES, X2, Y2, Z2, Z3, Z4; } mot_stepper_int16_t;
typedef struct { bool NUM_AXIS_LIST(X:1, Y:1, Z:1, I:1, J:1, K:1, U:1, V:1, W:1), X2:1, Y2:1, Z2:1, Z3:1, Z4:1 REPEAT(E_STEPPERS, _EN1_ITEM); } per_stepper_bool_t;
typedef struct { uint16_t MAIN_AXIS_NAMES_ X2, Y2, Z2, Z3, Z4 REPEAT(E_STEPPERS, _EN_ITEM); } per_stepper_uint16_t;
typedef struct { uint32_t MAIN_AXIS_NAMES_ X2, Y2, Z2, Z3, Z4 REPEAT(E_STEPPERS, _EN_ITEM); } per_stepper_uint32_t;
typedef struct { int16_t MAIN_AXIS_NAMES_ X2, Y2, Z2, Z3, Z4; } mot_stepper_int16_t;
typedef struct { bool NUM_AXIS_LIST_(X:1, Y:1, Z:1, I:1, J:1, K:1, U:1, V:1, W:1) X2:1, Y2:1, Z2:1, Z3:1, Z4:1 REPEAT(E_STEPPERS, _EN1_ITEM); } per_stepper_bool_t;
#undef _EN_ITEM
@ -225,7 +225,9 @@ typedef struct SettingsDataStruct {
//
// Home Offset
//
xyz_pos_t home_offset; // M206 XYZ / M665 TPZ
#if NUM_AXES
xyz_pos_t home_offset; // M206 XYZ / M665 TPZ
#endif
//
// Hotend Offset
@ -264,8 +266,9 @@ typedef struct SettingsDataStruct {
//
// HAS_BED_PROBE
//
xyz_pos_t probe_offset; // M851 X Y Z
#if NUM_AXES
xyz_pos_t probe_offset; // M851 X Y Z
#endif
//
// ABL_PLANAR
@ -475,7 +478,9 @@ typedef struct SettingsDataStruct {
//
// CNC_COORDINATE_SYSTEMS
//
xyz_pos_t coordinate_system[MAX_COORDINATE_SYSTEMS]; // G54-G59.3
#if NUM_AXES
xyz_pos_t coordinate_system[MAX_COORDINATE_SYSTEMS]; // G54-G59.3
#endif
//
// SKEW_CORRECTION
@ -501,9 +506,11 @@ typedef struct SettingsDataStruct {
//
// BACKLASH_COMPENSATION
//
xyz_float_t backlash_distance_mm; // M425 X Y Z
uint8_t backlash_correction; // M425 F
float backlash_smoothing_mm; // M425 S
#if NUM_AXES
xyz_float_t backlash_distance_mm; // M425 X Y Z
uint8_t backlash_correction; // M425 F
float backlash_smoothing_mm; // M425 S
#endif
//
// EXTENSIBLE_UI
@ -813,6 +820,7 @@ void MarlinSettings::postprocess() {
//
// Home Offset
//
#if NUM_AXES
{
_FIELD_TEST(home_offset);
@ -825,6 +833,7 @@ void MarlinSettings::postprocess() {
EEPROM_WRITE(home_offset);
#endif
}
#endif // NUM_AXES
//
// Hotend Offsets, if any
@ -905,6 +914,7 @@ void MarlinSettings::postprocess() {
//
// Probe XYZ Offsets
//
#if NUM_AXES
{
_FIELD_TEST(probe_offset);
#if HAS_BED_PROBE
@ -914,6 +924,7 @@ void MarlinSettings::postprocess() {
#endif
EEPROM_WRITE(zpo);
}
#endif
//
// Planar Bed Leveling matrix
@ -1364,7 +1375,7 @@ void MarlinSettings::postprocess() {
#else
#define _EN_ITEM(N) , .E##N = 30
const per_stepper_uint32_t tmc_hybrid_threshold = {
NUM_AXIS_LIST(.X = 100, .Y = 100, .Z = 3, .I = 3, .J = 3, .K = 3, .U = 3, .V = 3, .W = 3),
NUM_AXIS_LIST_(.X = 100, .Y = 100, .Z = 3, .I = 3, .J = 3, .K = 3, .U = 3, .V = 3, .W = 3)
.X2 = 100, .Y2 = 100, .Z2 = 3, .Z3 = 3, .Z4 = 3
REPEAT(E_STEPPERS, _EN_ITEM)
};
@ -1462,13 +1473,13 @@ void MarlinSettings::postprocess() {
//
// CNC Coordinate Systems
//
_FIELD_TEST(coordinate_system);
#if DISABLED(CNC_COORDINATE_SYSTEMS)
const xyz_pos_t coordinate_system[MAX_COORDINATE_SYSTEMS] = { { 0 } };
#if NUM_AXES
_FIELD_TEST(coordinate_system);
#if DISABLED(CNC_COORDINATE_SYSTEMS)
const xyz_pos_t coordinate_system[MAX_COORDINATE_SYSTEMS] = { { 0 } };
#endif
EEPROM_WRITE(TERN(CNC_COORDINATE_SYSTEMS, gcode.coordinate_system, coordinate_system));
#endif
EEPROM_WRITE(TERN(CNC_COORDINATE_SYSTEMS, gcode.coordinate_system, coordinate_system));
//
// Skew correction factors
@ -1503,6 +1514,7 @@ void MarlinSettings::postprocess() {
//
// Backlash Compensation
//
#if NUM_AXES
{
#if ENABLED(BACKLASH_GCODE)
xyz_float_t backlash_distance_mm;
@ -1522,6 +1534,7 @@ void MarlinSettings::postprocess() {
EEPROM_WRITE(backlash_correction);
EEPROM_WRITE(backlash_smoothing_mm);
}
#endif // NUM_AXES
//
// Extensible UI User Data
@ -1775,6 +1788,7 @@ void MarlinSettings::postprocess() {
//
// Home Offset (M206 / M665)
//
#if NUM_AXES
{
_FIELD_TEST(home_offset);
@ -1787,6 +1801,7 @@ void MarlinSettings::postprocess() {
EEPROM_READ(home_offset);
#endif
}
#endif // NUM_AXES
//
// Hotend Offsets, if any
@ -1862,6 +1877,7 @@ void MarlinSettings::postprocess() {
//
// Probe Z Offset
//
#if NUM_AXES
{
_FIELD_TEST(probe_offset);
#if HAS_BED_PROBE
@ -1871,6 +1887,7 @@ void MarlinSettings::postprocess() {
#endif
EEPROM_READ(zpo);
}
#endif
//
// Planar Bed Leveling matrix
@ -2439,6 +2456,7 @@ void MarlinSettings::postprocess() {
//
// CNC Coordinate System
//
#if NUM_AXES
{
_FIELD_TEST(coordinate_system);
#if ENABLED(CNC_COORDINATE_SYSTEMS)
@ -2449,6 +2467,7 @@ void MarlinSettings::postprocess() {
EEPROM_READ(coordinate_system);
#endif
}
#endif
//
// Skew correction factors
@ -2494,6 +2513,7 @@ void MarlinSettings::postprocess() {
//
// Backlash Compensation
//
#if NUM_AXES
{
xyz_float_t backlash_distance_mm;
uint8_t backlash_correction;
@ -2512,6 +2532,7 @@ void MarlinSettings::postprocess() {
#endif
#endif
}
#endif // NUM_AXES
//
// Extensible UI User Data
@ -2903,7 +2924,7 @@ void MarlinSettings::reset() {
planner.settings.min_travel_feedrate_mm_s = feedRate_t(DEFAULT_MINTRAVELFEEDRATE);
#if HAS_CLASSIC_JERK
#ifndef DEFAULT_XJERK
#if HAS_X_AXIS && !defined(DEFAULT_XJERK)
#define DEFAULT_XJERK 0
#endif
#if HAS_Y_AXIS && !defined(DEFAULT_YJERK)

View file

@ -398,7 +398,7 @@ xyze_int8_t Stepper::count_direction{0};
if (extruder_duplication_enabled || ALWAYS) { X_STEP_WRITE(v); X2_STEP_WRITE(v); } \
else if (last_moved_extruder) X2_STEP_WRITE(v); else X_STEP_WRITE(v); \
}while(0)
#else
#elif HAS_X_AXIS
#define X_APPLY_DIR(v,Q) X_DIR_WRITE(v)
#define X_APPLY_STEP(v,Q) X_STEP_WRITE(v)
#endif
@ -3407,19 +3407,21 @@ int32_t Stepper::triggered_position(const AxisEnum axis) {
#endif
void Stepper::report_a_position(const xyz_long_t &pos) {
SERIAL_ECHOLNPGM_P(
LIST_N(DOUBLE(NUM_AXES),
TERN(SAYS_A, PSTR(STR_COUNT_A), PSTR(STR_COUNT_X)), pos.x,
TERN(SAYS_B, PSTR("B:"), SP_Y_LBL), pos.y,
TERN(SAYS_C, PSTR("C:"), SP_Z_LBL), pos.z,
SP_I_LBL, pos.i,
SP_J_LBL, pos.j,
SP_K_LBL, pos.k,
SP_U_LBL, pos.u,
SP_V_LBL, pos.v,
SP_W_LBL, pos.w
)
);
#if NUM_AXES
SERIAL_ECHOLNPGM_P(
LIST_N(DOUBLE(NUM_AXES),
TERN(SAYS_A, PSTR(STR_COUNT_A), PSTR(STR_COUNT_X)), pos.x,
TERN(SAYS_B, PSTR("B:"), SP_Y_LBL), pos.y,
TERN(SAYS_C, PSTR("C:"), SP_Z_LBL), pos.z,
SP_I_LBL, pos.i,
SP_J_LBL, pos.j,
SP_K_LBL, pos.k,
SP_U_LBL, pos.u,
SP_V_LBL, pos.v,
SP_W_LBL, pos.w
)
);
#endif
}
void Stepper::report_positions() {

View file

@ -83,7 +83,7 @@ typedef struct {
// All the stepper enable pins
constexpr pin_t ena_pins[] = {
NUM_AXIS_LIST(X_ENABLE_PIN, Y_ENABLE_PIN, Z_ENABLE_PIN, I_ENABLE_PIN, J_ENABLE_PIN, K_ENABLE_PIN, U_ENABLE_PIN, V_ENABLE_PIN, W_ENABLE_PIN),
NUM_AXIS_LIST_(X_ENABLE_PIN, Y_ENABLE_PIN, Z_ENABLE_PIN, I_ENABLE_PIN, J_ENABLE_PIN, K_ENABLE_PIN, U_ENABLE_PIN, V_ENABLE_PIN, W_ENABLE_PIN)
LIST_N(E_STEPPERS, E0_ENABLE_PIN, E1_ENABLE_PIN, E2_ENABLE_PIN, E3_ENABLE_PIN, E4_ENABLE_PIN, E5_ENABLE_PIN, E6_ENABLE_PIN, E7_ENABLE_PIN)
};

View file

@ -83,21 +83,23 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset
#define INVERT_DIR(AXIS, D) (TERN_(INVERT_## AXIS ##_DIR, !)(D))
// X Stepper
#ifndef X_ENABLE_INIT
#define X_ENABLE_INIT() SET_OUTPUT(X_ENABLE_PIN)
#define X_ENABLE_WRITE(STATE) WRITE(X_ENABLE_PIN,STATE)
#define X_ENABLE_READ() bool(READ(X_ENABLE_PIN))
#if HAS_X_AXIS
#ifndef X_ENABLE_INIT
#define X_ENABLE_INIT() SET_OUTPUT(X_ENABLE_PIN)
#define X_ENABLE_WRITE(STATE) WRITE(X_ENABLE_PIN,STATE)
#define X_ENABLE_READ() bool(READ(X_ENABLE_PIN))
#endif
#ifndef X_DIR_INIT
#define X_DIR_INIT() SET_OUTPUT(X_DIR_PIN)
#define X_DIR_WRITE(STATE) WRITE(X_DIR_PIN,INVERT_DIR(X, STATE))
#define X_DIR_READ() INVERT_DIR(X, bool(READ(X_DIR_PIN)))
#endif
#define X_STEP_INIT() SET_OUTPUT(X_STEP_PIN)
#ifndef X_STEP_WRITE
#define X_STEP_WRITE(STATE) WRITE(X_STEP_PIN,STATE)
#endif
#define X_STEP_READ() bool(READ(X_STEP_PIN))
#endif
#ifndef X_DIR_INIT
#define X_DIR_INIT() SET_OUTPUT(X_DIR_PIN)
#define X_DIR_WRITE(STATE) WRITE(X_DIR_PIN,INVERT_DIR(X, STATE))
#define X_DIR_READ() INVERT_DIR(X, bool(READ(X_DIR_PIN)))
#endif
#define X_STEP_INIT() SET_OUTPUT(X_STEP_PIN)
#ifndef X_STEP_WRITE
#define X_STEP_WRITE(STATE) WRITE(X_STEP_PIN,STATE)
#endif
#define X_STEP_READ() bool(READ(X_STEP_PIN))
// Y Stepper
#if HAS_Y_AXIS
@ -977,8 +979,13 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset
#define AFTER_CHANGE(N,TF) NOOP
#endif
#define ENABLE_AXIS_X() if (SHOULD_ENABLE(x)) { ENABLE_STEPPER_X(); ENABLE_STEPPER_X2(); AFTER_CHANGE(x, true); }
#define DISABLE_AXIS_X() if (SHOULD_DISABLE(x)) { DISABLE_STEPPER_X(); DISABLE_STEPPER_X2(); AFTER_CHANGE(x, false); set_axis_untrusted(X_AXIS); }
#if HAS_X_AXIS
#define ENABLE_AXIS_X() if (SHOULD_ENABLE(x)) { ENABLE_STEPPER_X(); ENABLE_STEPPER_X2(); AFTER_CHANGE(x, true); }
#define DISABLE_AXIS_X() if (SHOULD_DISABLE(x)) { DISABLE_STEPPER_X(); DISABLE_STEPPER_X2(); AFTER_CHANGE(x, false); set_axis_untrusted(X_AXIS); }
#else
#define ENABLE_AXIS_X() NOOP
#define DISABLE_AXIS_X() NOOP
#endif
#if HAS_Y_AXIS
#define ENABLE_AXIS_Y() if (SHOULD_ENABLE(y)) { ENABLE_STEPPER_Y(); ENABLE_STEPPER_Y2(); AFTER_CHANGE(y, true); }

View file

@ -493,7 +493,7 @@ enum StealthIndex : uint8_t {
#endif
#define _EN_ITEM(N) , E##N
enum TMCAxis : uint8_t { MAIN_AXIS_NAMES, X2, Y2, Z2, Z3, Z4 REPEAT(EXTRUDERS, _EN_ITEM), TOTAL };
enum TMCAxis : uint8_t { MAIN_AXIS_NAMES_ X2, Y2, Z2, Z3, Z4 REPEAT(EXTRUDERS, _EN_ITEM), TOTAL };
#undef _EN_ITEM
void tmc_serial_begin() {

View file

@ -77,7 +77,7 @@
#define TMC_CLASS_E(N) TMC_CLASS(E##N, E)
#endif
#ifndef CHOPPER_TIMING_X
#if HAS_X_AXIS && !defined(CHOPPER_TIMING_X)
#define CHOPPER_TIMING_X CHOPPER_TIMING
#endif
#if HAS_Y_AXIS && !defined(CHOPPER_TIMING_Y)

View file

@ -24,44 +24,51 @@
//
// Prepare a list of protected pins for M42/M43
//
#if HAS_X_AXIS
#if PIN_EXISTS(X_MIN)
#define _X_MIN X_MIN_PIN,
#else
#define _X_MIN
#endif
#if PIN_EXISTS(X_MAX)
#define _X_MAX X_MAX_PIN,
#else
#define _X_MAX
#endif
#if PIN_EXISTS(X_CS) && AXIS_HAS_SPI(X)
#define _X_CS X_CS_PIN,
#else
#define _X_CS
#endif
#if PIN_EXISTS(X_MS1)
#define _X_MS1 X_MS1_PIN,
#else
#define _X_MS1
#endif
#if PIN_EXISTS(X_MS2)
#define _X_MS2 X_MS2_PIN,
#else
#define _X_MS2
#endif
#if PIN_EXISTS(X_MS3)
#define _X_MS3 X_MS3_PIN,
#else
#define _X_MS3
#endif
#if PIN_EXISTS(X_ENABLE)
#define _X_ENABLE_PIN X_ENABLE_PIN,
#else
#define _X_ENABLE_PIN
#endif
#if PIN_EXISTS(X_MIN)
#define _X_MIN X_MIN_PIN,
#else
#define _X_MIN
#endif
#if PIN_EXISTS(X_MAX)
#define _X_MAX X_MAX_PIN,
#else
#define _X_MAX
#endif
#if PIN_EXISTS(X_CS) && AXIS_HAS_SPI(X)
#define _X_CS X_CS_PIN,
#else
#define _X_CS
#endif
#if PIN_EXISTS(X_MS1)
#define _X_MS1 X_MS1_PIN,
#else
#define _X_MS1
#endif
#if PIN_EXISTS(X_MS2)
#define _X_MS2 X_MS2_PIN,
#else
#define _X_MS2
#endif
#if PIN_EXISTS(X_MS3)
#define _X_MS3 X_MS3_PIN,
#else
#define _X_MS3
#endif
#if PIN_EXISTS(X_ENABLE)
#define _X_ENABLE_PIN X_ENABLE_PIN,
#else
#define _X_ENABLE_PIN
#endif
#define _X_PINS X_STEP_PIN, X_DIR_PIN, _X_ENABLE_PIN _X_MIN _X_MAX _X_MS1 _X_MS2 _X_MS3 _X_CS
#define _X_PINS X_STEP_PIN, X_DIR_PIN, _X_ENABLE_PIN _X_MIN _X_MAX _X_MS1 _X_MS2 _X_MS3 _X_CS
#else
#define _X_PINS
#endif
#if HAS_Y_AXIS

View file

@ -71,6 +71,19 @@ opt_enable VIKI2 BOOT_MARLIN_LOGO_ANIMATED SDSUPPORT AUTO_REPORT_SD_STATUS \
FILAMENT_RUNOUT_SENSOR NOZZLE_PARK_FEATURE ADVANCED_PAUSE_FEATURE Z_SAFE_HOMING FIL_RUNOUT3_PULLUP
exec_test $1 $2 "Z Servo Probe | Multiple runout sensors (x5)" "$3"
#
# Extruder Only. No XYZ axes at all.
#
restore_configs
opt_set DEFAULT_AXIS_STEPS_PER_UNIT '{ 4000 }' \
DEFAULT_MAX_FEEDRATE '{ 5 }' \
DEFAULT_MAX_ACCELERATION '{ 100 }' \
MANUAL_FEEDRATE '{ 4*60 }' \
AXIS_RELATIVE_MODES '{ false }' \
HOMING_BUMP_MM '{}' HOMING_BUMP_DIVISOR '{}' HOMING_FEEDRATE_MM_M '{}'
opt_enable REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER
opt_disable X_DRIVER_TYPE Y_DRIVER_TYPE Z_DRIVER_TYPE
exec_test $1 $2 "E Axis Only | DOGM MarlinUI" "$3"
#
# Mixing Extruder with 5 steppers, Greek

View file

@ -36,9 +36,10 @@ platform_packages = framework-arduinoststm32@https://github.com/stm32d
board = marlin_BTT_EBB42_V1_1
board_build.offset = 0x0000
board_upload.offset_address = 0x08000000
build_flags = ${stm32_variant.build_flags} ${stm32g0_I2C2.build_flags}
upload_protocol = stlink
build_flags = ${stm32_variant.build_flags} ${stm32g0_I2C2.build_flags} -flto
debug_tool = stlink
upload_protocol = dfu
upload_command = dfu-util -a 0 -s 0x08000000:leave -D "$SOURCE"
#
# BigTreeTech SKR Mini E3 V3.0 (STM32G0B1RET6 ARM Cortex-M0+)