From c8619f5b05f807f0ae4f5eb4ddece51b56a85abd Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Mon, 30 Oct 2023 11:37:01 +0100 Subject: [PATCH 01/47] Update planner.c First experimental checkin for constant jerk motions --- planner.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/planner.c b/planner.c index 474aee0..19e1b65 100644 --- a/planner.c +++ b/planner.c @@ -355,6 +355,19 @@ static inline float limit_acceleration_by_axis_maximum (float *unit_vec) return limit_value; } +static inline float limit_jerk_by_axis_maximum (float *unit_vec) +{ + uint_fast8_t idx = N_AXIS; + float limit_value = SOME_LARGE_VALUE; + + do { + if (unit_vec[--idx] != 0.0f) // Avoid divide by zero. + limit_value = min(limit_value, fabsf(settings.axis[idx].jerk / unit_vec[idx])); + } while(idx); + + return limit_value; +} + static inline float limit_max_rate_by_axis_maximum (float *unit_vec) { uint_fast8_t idx = N_AXIS; @@ -469,7 +482,7 @@ bool plan_buffer_line (float *target, plan_line_data_t *pl_data) // behave as if its doing a G93 inverse time mode move. if(!block->condition.inverse_time && - !block->condition.rapid_motion && + !block->condition.rapid_motion &&el (motion.mask & settings.steppers.is_rotational.mask) && (motion.mask & ~settings.steppers.is_rotational.mask)) { @@ -493,7 +506,7 @@ bool plan_buffer_line (float *target, plan_line_data_t *pl_data) #endif // Calculate the unit vector of the line move and the block maximum feed rate and acceleration scaled - // down such that no individual axes maximum values are exceeded with respect to the line direction. + // down such that no individual axes maximum values are exceeded with respect to the line direction.l #if N_AXIS > 3 && ROTARY_FIX // NOTE: This calculation assumes all block motion axes are orthogonal (Cartesian), and if also rotational, then // motion mode must be inverse time mode. Operates on the absolute value of the unit vector. @@ -503,7 +516,8 @@ bool plan_buffer_line (float *target, plan_line_data_t *pl_data) #endif block->millimeters = convert_delta_vector_to_unit_vector(unit_vec); - block->acceleration = limit_acceleration_by_axis_maximum(unit_vec); + block->max_acceleration = limit_acceleration_by_axis_maximum(unit_vec); + block->jerk = limit_jerk_by_axis_maximum(unit_vec); block->rapid_rate = limit_max_rate_by_axis_maximum(unit_vec); // Store programmed rate. @@ -517,6 +531,11 @@ bool plan_buffer_line (float *target, plan_line_data_t *pl_data) if (block->condition.inverse_time) block->programmed_rate *= block->millimeters; } + // Calculate effective acceleration over block. Since jerk acceleration takes longer to execute due to ramp up and + // ramp down of the acceleration at the start and end of a ramp we need to adjust the acceleration value the planner + // uses so it still calculates reasonable entry and exit speeds. We do this by adding 2x the time it takes to reach + // full acceleration to the trapezoidal acceleration time and dividing the programmed rate by the value obtained. + block->acceleration = block->programmed_rate / ((block->programmed_rate / block->max_acceleration) + 2.0f * (block->max_acceleration / block->jerk)) // TODO: Need to check this method handling zero junction speeds when starting from rest. if ((block_buffer_head == block_buffer_tail) || (block->condition.system_motion)) { From f00347979ca5b901910926ce44b46ffe2174f7b2 Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Mon, 30 Oct 2023 11:37:55 +0100 Subject: [PATCH 02/47] Update planner.h First experimental checkin for constant jerk motions --- planner.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/planner.h b/planner.h index 185a88a..3b7c166 100644 --- a/planner.h +++ b/planner.h @@ -61,7 +61,9 @@ typedef struct plan_block { float entry_speed_sqr; // The current planned entry speed at block junction in (mm/min)^2 float max_entry_speed_sqr; // Maximum allowable entry speed based on the minimum of junction limit and // neighboring nominal speeds with overrides in (mm/min)^2 - float acceleration; // Axis-limit adjusted line acceleration in (mm/min^2). Does not change. + float acceleration; // Effective acceleration over plannerblock calculated from trapezoidal movement plan. + float max_acceleration // Axis-limit adjusted line acceleration in (mm/min^2). Does not change. + float jerk // Axis-limit adjusted jerk value in (mm/min^3). Does not change. float millimeters; // The remaining distance for this block to be executed in (mm). // NOTE: This value may be altered by stepper algorithm during execution. From 699e94391d88c68aa6923593c4f8e25269799b63 Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Mon, 30 Oct 2023 11:38:25 +0100 Subject: [PATCH 03/47] Update stepper.c First experimental checkin for constant jerk motions --- stepper.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/stepper.c b/stepper.c index 2a553f9..3c77649 100644 --- a/stepper.c +++ b/stepper.c @@ -891,6 +891,7 @@ void st_prep_buffer (void) float dt_max = DT_SEGMENT; // Maximum segment time float dt = 0.0f; // Initialize segment time float time_var = dt_max; // Time worker variable + float last_segment_accel = 0.0f; // Acceleration value of last computed segment. Initialize as 0.0 float mm_var; // mm - Distance worker variable float speed_var; // Speed worker variable float mm_remaining = pl_block->millimeters; // New segment distance from end of block. @@ -919,7 +920,14 @@ void st_prep_buffer (void) case Ramp_Accel: // NOTE: Acceleration ramp only computes during first do-while loop. - speed_var = pl_block->acceleration * time_var; + if (((mm_remaining - prep.accelerate_until) / (prep.current_speed + 1.0f)) <= (pl_block->max_acceleration / pl_block->jerk)) { //+1.0f to avoid divide by 0 speed, minor effect on jerk ramp + // Check if we are on ramp up or ramp down. Ramp down if time to end of acceleration is less than time needed to reach 0 acceleration. + // Then limit acceleration change by jerk up to max acceleration and update for next segment. + last_segment_accel = max(last_segment_accel - pl_block->jerk * time_var, 0.0f); + } else { + last_segment_accel = min(last_segment_accel + pl_block->jerk * time_var, pl_block->max_acceleration); + } + speed_var = last_segment_accel * time_var; mm_remaining -= time_var * (prep.current_speed + 0.5f * speed_var); if (mm_remaining < prep.accelerate_until) { // End of acceleration ramp. // Acceleration-cruise, acceleration-deceleration ramp junction, or end of block. @@ -947,7 +955,14 @@ void st_prep_buffer (void) default: // case Ramp_Decel: // NOTE: mm_var used as a misc worker variable to prevent errors when near zero speed. - speed_var = pl_block->acceleration * time_var; // Used as delta speed (mm/min) + if (((prep.decelerate_after - mm_remaining) / (prep.current_speed + 1.0f)) <= (pl_block->max_acceleration / pl_block->jerk)) { //+1.0f to avoid divide by 0 speed, minor effect on jerk ramp + // Check if we are on ramp up or ramp down. Ramp down if time to end of acceleration is less than time needed to reach 0 acceleration. + // Then limit acceleration change by jerk up to max acceleration and update for next segment. + last_segment_accel = max(last_segment_accel - pl_block->jerk * time_var, 0.0f); + } else { + last_segment_accel = min(last_segment_accel + pl_block->jerk * time_var, pl_block->max_acceleration); + } + speed_var = last_segment_accel * time_var; // Used as delta speed (mm/min) if (prep.current_speed > speed_var) { // Check if at or below zero speed. // Compute distance from end of segment to end of block. mm_var = mm_remaining - time_var * (prep.current_speed - 0.5f * speed_var); // (mm) From 2484538ade99943055a33dc51a6736f8b45640da Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Mon, 30 Oct 2023 11:41:05 +0100 Subject: [PATCH 04/47] Update planner.c --- planner.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/planner.c b/planner.c index 19e1b65..e26f89c 100644 --- a/planner.c +++ b/planner.c @@ -482,7 +482,7 @@ bool plan_buffer_line (float *target, plan_line_data_t *pl_data) // behave as if its doing a G93 inverse time mode move. if(!block->condition.inverse_time && - !block->condition.rapid_motion &&el + !block->condition.rapid_motion && (motion.mask & settings.steppers.is_rotational.mask) && (motion.mask & ~settings.steppers.is_rotational.mask)) { From 4c3cf5eac3e2514032a46a2a4cbb6e3323744746 Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Mon, 30 Oct 2023 14:17:02 +0100 Subject: [PATCH 05/47] Added Axis settings for jerk --- config.h | 29 +++++++++++++++++++++++++++++ settings.c | 9 +++++++++ settings.h | 3 ++- 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/config.h b/config.h index d013d2c..09c2d5b 100644 --- a/config.h +++ b/config.h @@ -1823,6 +1823,35 @@ Timezone offset from UTC in hours, allowed range is -12.0 - 12.0. #endif ///@} +/*! @name 12x - Setting_AxisJerk +*/ +///@{ +#if !defined DEFAULT_X_JERK|| defined __DOXYGEN__ +#define DEFAULT_X_Jerk 100.0f // mm/sec^2 +#endif +#if !defined DEFAULT_Y_JERK|| defined __DOXYGEN__ +#define DEFAULT_Y_JERK 100.0f // mm/sec^2 +#endif +#if !defined DEFAULT_Z_JERK || defined __DOXYGEN__ +#define DEFAULT_Z_JERK 100.0f // mm/sec^2 +#endif +#if (defined A_AXIS && !defined DEFAULT_A_JERK) || defined __DOXYGEN__ +#define DEFAULT_A_JERK 100.0f // mm/sec^2 +#endif +#if (defined B_AXIS && !defined DEFAULT_B_JERK) || defined __DOXYGEN__ +#define DEFAULT_B_JERK 100.0f // mm/sec^2 +#endif +#if (defined C_AXIS && !defined DEFAULT_C_JERK) || defined __DOXYGEN__ +#define DEFAULT_C_JERK 100.0f // mm/sec^2 +#endif +#if (defined U_AXIS && !defined DEFAULT_U_JERK) || defined __DOXYGEN__ +#define DEFAULT_U_JERK 100.0f // mm/sec^2 +#endif +#if (defined V_AXIS && !defined DEFAULT_V_JERK) || defined __DOXYGEN__ +#define DEFAULT_V_JERK 100.0f // mm/sec^2 +#endif +///@} + /*! @name 13x - Setting_AxisMaxTravel __NOTE:__ Must be a positive values. */ diff --git a/settings.c b/settings.c index 6e3099f..d37454a 100644 --- a/settings.c +++ b/settings.c @@ -202,6 +202,7 @@ PROGMEM const settings_t defaults = { .axis[X_AXIS].steps_per_mm = DEFAULT_X_STEPS_PER_MM, .axis[X_AXIS].max_rate = DEFAULT_X_MAX_RATE, .axis[X_AXIS].acceleration = (DEFAULT_X_ACCELERATION * 60.0f * 60.0f), + .axis[X_AXIS].jerk = (DEFAULT_X_JERK * 60.0f * 60.0f * 60f), .axis[X_AXIS].max_travel = (-DEFAULT_X_MAX_TRAVEL), .axis[X_AXIS].dual_axis_offset = 0.0f, #if ENABLE_BACKLASH_COMPENSATION @@ -212,6 +213,7 @@ PROGMEM const settings_t defaults = { .axis[Y_AXIS].max_rate = DEFAULT_Y_MAX_RATE, .axis[Y_AXIS].max_travel = (-DEFAULT_Y_MAX_TRAVEL), .axis[Y_AXIS].acceleration = (DEFAULT_Y_ACCELERATION * 60.0f * 60.0f), + .axis[Y_AXIS].jerk = (DEFAULT_Y_JERK * 60.0f * 60.0f * 60f), .axis[Y_AXIS].dual_axis_offset = 0.0f, #if ENABLE_BACKLASH_COMPENSATION .axis[Y_AXIS].backlash = 0.0f, @@ -220,6 +222,7 @@ PROGMEM const settings_t defaults = { .axis[Z_AXIS].steps_per_mm = DEFAULT_Z_STEPS_PER_MM, .axis[Z_AXIS].max_rate = DEFAULT_Z_MAX_RATE, .axis[Z_AXIS].acceleration = (DEFAULT_Z_ACCELERATION * 60.0f * 60.0f), + .axis[Z_AXIS].jerk = (DEFAULT_Z_JERK * 60.0f * 60.0f * 60f), .axis[Z_AXIS].max_travel = (-DEFAULT_Z_MAX_TRAVEL), .axis[Z_AXIS].dual_axis_offset = 0.0f, #if ENABLE_BACKLASH_COMPENSATION @@ -230,6 +233,7 @@ PROGMEM const settings_t defaults = { .axis[A_AXIS].steps_per_mm = DEFAULT_A_STEPS_PER_MM, .axis[A_AXIS].max_rate = DEFAULT_A_MAX_RATE, .axis[A_AXIS].acceleration =(DEFAULT_A_ACCELERATION * 60.0f * 60.0f), + .axis[A_AXIS].jerk = (DEFAULT_A_JERK * 60.0f * 60.0f * 60f), .axis[A_AXIS].max_travel = (-DEFAULT_A_MAX_TRAVEL), .axis[A_AXIS].dual_axis_offset = 0.0f, #if ENABLE_BACKLASH_COMPENSATION @@ -242,6 +246,7 @@ PROGMEM const settings_t defaults = { .axis[B_AXIS].steps_per_mm = DEFAULT_B_STEPS_PER_MM, .axis[B_AXIS].max_rate = DEFAULT_B_MAX_RATE, .axis[B_AXIS].acceleration = (DEFAULT_B_ACCELERATION * 60.0f * 60.0f), + .axis[B_AXIS].jerk = (DEFAULT_B_JERK * 60.0f * 60.0f * 60f), .axis[B_AXIS].max_travel = (-DEFAULT_B_MAX_TRAVEL), .axis[B_AXIS].dual_axis_offset = 0.0f, #if ENABLE_BACKLASH_COMPENSATION @@ -253,6 +258,7 @@ PROGMEM const settings_t defaults = { #ifdef C_AXIS .axis[C_AXIS].steps_per_mm = DEFAULT_C_STEPS_PER_MM, .axis[C_AXIS].acceleration = (DEFAULT_C_ACCELERATION * 60.0f * 60.0f), + .axis[C_AXIS].jerk = (DEFAULT_C_JERK * 60.0f * 60.0f * 60f), .axis[C_AXIS].max_rate = DEFAULT_C_MAX_RATE, .axis[C_AXIS].max_travel = (-DEFAULT_C_MAX_TRAVEL), .axis[C_AXIS].dual_axis_offset = 0.0f, @@ -265,6 +271,7 @@ PROGMEM const settings_t defaults = { #ifdef U_AXIS .axis[U_AXIS].steps_per_mm = DEFAULT_U_STEPS_PER_MM, .axis[U_AXIS].acceleration = (DEFAULT_U_ACCELERATION * 60.0f * 60.0f), + .axis[U_AXIS].jerk = (DEFAULT_U_JERK * 60.0f * 60.0f * 60f), .axis[U_AXIS].max_rate = DEFAULT_U_MAX_RATE, .axis[U_AXIS].max_travel = (-DEFAULT_U_MAX_TRAVEL), .axis[U_AXIS].dual_axis_offset = 0.0f, @@ -276,6 +283,7 @@ PROGMEM const settings_t defaults = { #ifdef V_AXIS .axis[V_AXIS].steps_per_mm = DEFAULT_V_STEPS_PER_MM, .axis[V_AXIS].acceleration = (DEFAULT_V_ACCELERATION * 60.0f * 60.0f), + .axis[V_AXIS].jerk = (DEFAULT_V_JERK * 60.0f * 60.0f * 60f), .axis[V_AXIS].max_rate = DEFAULT_V_MAX_RATE, .axis[V_AXIS].max_travel = (-DEFAULT_V_MAX_TRAVEL), .axis[V_AXIS].dual_axis_offset = 0.0f, @@ -552,6 +560,7 @@ PROGMEM static const setting_detail_t setting_detail[] = { { Setting_AxisStepsPerMM, Group_Axis0, "-axis travel resolution", axis_steps, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, { Setting_AxisMaxRate, Group_Axis0, "-axis maximum rate", axis_rate, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, { Setting_AxisAcceleration, Group_Axis0, "-axis acceleration", axis_accel, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, + { Setting_AxisJerk, Group_Axis0, "-axis jerk", axis_jerk, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsExtended, set_axis_setting, get_float, NULL, AXIS_OPTS }, { Setting_AxisMaxTravel, Group_Axis0, "-axis maximum travel", axis_dist, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, #if ENABLE_BACKLASH_COMPENSATION { Setting_AxisBacklash, Group_Axis0, "-axis backlash compensation", axis_dist, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsExtendedFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, diff --git a/settings.h b/settings.h index b30591d..7ab7a72 100644 --- a/settings.h +++ b/settings.h @@ -419,7 +419,7 @@ typedef enum { // Calculated base values for driver/plugin stepper settings Setting_AxisExtended0 = Setting_AxisSettingsBase2, Setting_AxisExtended1 = Setting_AxisSettingsBase2 + AXIS_SETTINGS_INCREMENT, - Setting_AxisExtended2 = Setting_AxisSettingsBase2 + 2 * AXIS_SETTINGS_INCREMENT, + Setting_AxisJerk = Setting_AxisSettingsBase2 + 2 * AXIS_SETTINGS_INCREMENT, Setting_AxisExtended3 = Setting_AxisSettingsBase2 + 3 * AXIS_SETTINGS_INCREMENT, Setting_AxisExtended4 = Setting_AxisSettingsBase2 + 4 * AXIS_SETTINGS_INCREMENT, Setting_AxisExtended5 = Setting_AxisSettingsBase2 + 5 * AXIS_SETTINGS_INCREMENT, @@ -630,6 +630,7 @@ typedef struct { float steps_per_mm; float max_rate; float acceleration; + float jerk; float max_travel; float dual_axis_offset; #if ENABLE_BACKLASH_COMPENSATION From 418e063b3599fbb9972740420e440fa79d93a45c Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Mon, 30 Oct 2023 22:08:46 +0100 Subject: [PATCH 06/47] Decel Ramp Calculations Updated --- planner.c | 2 +- stepper.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/planner.c b/planner.c index e26f89c..176d19a 100644 --- a/planner.c +++ b/planner.c @@ -506,7 +506,7 @@ bool plan_buffer_line (float *target, plan_line_data_t *pl_data) #endif // Calculate the unit vector of the line move and the block maximum feed rate and acceleration scaled - // down such that no individual axes maximum values are exceeded with respect to the line direction.l + // down such that no individual axes maximum values are exceeded with respect to the line direction. #if N_AXIS > 3 && ROTARY_FIX // NOTE: This calculation assumes all block motion axes are orthogonal (Cartesian), and if also rotational, then // motion mode must be inverse time mode. Operates on the absolute value of the unit vector. diff --git a/stepper.c b/stepper.c index 3c77649..4aa2008 100644 --- a/stepper.c +++ b/stepper.c @@ -955,8 +955,8 @@ void st_prep_buffer (void) default: // case Ramp_Decel: // NOTE: mm_var used as a misc worker variable to prevent errors when near zero speed. - if (((prep.decelerate_after - mm_remaining) / (prep.current_speed + 1.0f)) <= (pl_block->max_acceleration / pl_block->jerk)) { //+1.0f to avoid divide by 0 speed, minor effect on jerk ramp - // Check if we are on ramp up or ramp down. Ramp down if time to end of acceleration is less than time needed to reach 0 acceleration. + if ((mm_remaining / (prep.current_speed + 1.0f)) <= (pl_block->max_acceleration / pl_block->jerk)) { //+1.0f to avoid divide by 0 speed, minor effect on jerk ramp + // Check if we are on ramp up or ramp down. Ramp down if time to end of deceleration is less than time needed to reach 0 acceleration. // Then limit acceleration change by jerk up to max acceleration and update for next segment. last_segment_accel = max(last_segment_accel - pl_block->jerk * time_var, 0.0f); } else { From fb082f35812be462831ea476eb45544a5370b02e Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Thu, 2 Nov 2023 14:49:33 +0100 Subject: [PATCH 07/47] added missing semicolons --- planner.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/planner.h b/planner.h index 3b7c166..a51f19e 100644 --- a/planner.h +++ b/planner.h @@ -62,8 +62,8 @@ typedef struct plan_block { float max_entry_speed_sqr; // Maximum allowable entry speed based on the minimum of junction limit and // neighboring nominal speeds with overrides in (mm/min)^2 float acceleration; // Effective acceleration over plannerblock calculated from trapezoidal movement plan. - float max_acceleration // Axis-limit adjusted line acceleration in (mm/min^2). Does not change. - float jerk // Axis-limit adjusted jerk value in (mm/min^3). Does not change. + float max_acceleration; // Axis-limit adjusted line acceleration in (mm/min^2). Does not change. + float jerk; // Axis-limit adjusted jerk value in (mm/min^3). Does not change. float millimeters; // The remaining distance for this block to be executed in (mm). // NOTE: This value may be altered by stepper algorithm during execution. From f00bb4d269275a87bdfcbdcca697568ecf56001b Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Thu, 2 Nov 2023 18:01:51 +0100 Subject: [PATCH 08/47] Update planner.c missing semicolon --- planner.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/planner.c b/planner.c index 176d19a..bfb92e8 100644 --- a/planner.c +++ b/planner.c @@ -535,7 +535,7 @@ bool plan_buffer_line (float *target, plan_line_data_t *pl_data) // ramp down of the acceleration at the start and end of a ramp we need to adjust the acceleration value the planner // uses so it still calculates reasonable entry and exit speeds. We do this by adding 2x the time it takes to reach // full acceleration to the trapezoidal acceleration time and dividing the programmed rate by the value obtained. - block->acceleration = block->programmed_rate / ((block->programmed_rate / block->max_acceleration) + 2.0f * (block->max_acceleration / block->jerk)) + block->acceleration = block->programmed_rate / ((block->programmed_rate / block->max_acceleration) + 2.0f * (block->max_acceleration / block->jerk)); // TODO: Need to check this method handling zero junction speeds when starting from rest. if ((block_buffer_head == block_buffer_tail) || (block->condition.system_motion)) { From b7969318296e94ab5134e1f4ac5aeccc28b4e1fe Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Thu, 2 Nov 2023 18:05:22 +0100 Subject: [PATCH 09/47] Update settings.c bugfixing float variables --- settings.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/settings.c b/settings.c index d37454a..aad597d 100644 --- a/settings.c +++ b/settings.c @@ -202,8 +202,8 @@ PROGMEM const settings_t defaults = { .axis[X_AXIS].steps_per_mm = DEFAULT_X_STEPS_PER_MM, .axis[X_AXIS].max_rate = DEFAULT_X_MAX_RATE, .axis[X_AXIS].acceleration = (DEFAULT_X_ACCELERATION * 60.0f * 60.0f), - .axis[X_AXIS].jerk = (DEFAULT_X_JERK * 60.0f * 60.0f * 60f), - .axis[X_AXIS].max_travel = (-DEFAULT_X_MAX_TRAVEL), + .axis[X_AXIS].jerk = (DEFAULT_X_JERK * 60.0f * 60.0f * 60.0f), + .axis[X_AXIS].max_travel = (DEFAULT_X_MAX_TRAVEL), .axis[X_AXIS].dual_axis_offset = 0.0f, #if ENABLE_BACKLASH_COMPENSATION .axis[X_AXIS].backlash = 0.0f, @@ -213,7 +213,7 @@ PROGMEM const settings_t defaults = { .axis[Y_AXIS].max_rate = DEFAULT_Y_MAX_RATE, .axis[Y_AXIS].max_travel = (-DEFAULT_Y_MAX_TRAVEL), .axis[Y_AXIS].acceleration = (DEFAULT_Y_ACCELERATION * 60.0f * 60.0f), - .axis[Y_AXIS].jerk = (DEFAULT_Y_JERK * 60.0f * 60.0f * 60f), + .axis[Y_AXIS].jerk = (DEFAULT_Y_JERK * 60.0f * 60.0f * 60.0f), .axis[Y_AXIS].dual_axis_offset = 0.0f, #if ENABLE_BACKLASH_COMPENSATION .axis[Y_AXIS].backlash = 0.0f, @@ -222,7 +222,7 @@ PROGMEM const settings_t defaults = { .axis[Z_AXIS].steps_per_mm = DEFAULT_Z_STEPS_PER_MM, .axis[Z_AXIS].max_rate = DEFAULT_Z_MAX_RATE, .axis[Z_AXIS].acceleration = (DEFAULT_Z_ACCELERATION * 60.0f * 60.0f), - .axis[Z_AXIS].jerk = (DEFAULT_Z_JERK * 60.0f * 60.0f * 60f), + .axis[Z_AXIS].jerk = (DEFAULT_Z_JERK * 60.0f * 60.0f * 60.0f), .axis[Z_AXIS].max_travel = (-DEFAULT_Z_MAX_TRAVEL), .axis[Z_AXIS].dual_axis_offset = 0.0f, #if ENABLE_BACKLASH_COMPENSATION @@ -233,7 +233,7 @@ PROGMEM const settings_t defaults = { .axis[A_AXIS].steps_per_mm = DEFAULT_A_STEPS_PER_MM, .axis[A_AXIS].max_rate = DEFAULT_A_MAX_RATE, .axis[A_AXIS].acceleration =(DEFAULT_A_ACCELERATION * 60.0f * 60.0f), - .axis[A_AXIS].jerk = (DEFAULT_A_JERK * 60.0f * 60.0f * 60f), + .axis[A_AXIS].jerk = (DEFAULT_A_JERK * 60.0f * 60.0f * 60.0f), .axis[A_AXIS].max_travel = (-DEFAULT_A_MAX_TRAVEL), .axis[A_AXIS].dual_axis_offset = 0.0f, #if ENABLE_BACKLASH_COMPENSATION @@ -246,7 +246,7 @@ PROGMEM const settings_t defaults = { .axis[B_AXIS].steps_per_mm = DEFAULT_B_STEPS_PER_MM, .axis[B_AXIS].max_rate = DEFAULT_B_MAX_RATE, .axis[B_AXIS].acceleration = (DEFAULT_B_ACCELERATION * 60.0f * 60.0f), - .axis[B_AXIS].jerk = (DEFAULT_B_JERK * 60.0f * 60.0f * 60f), + .axis[B_AXIS].jerk = (DEFAULT_B_JERK * 60.0f * 60.0f * 60.0f), .axis[B_AXIS].max_travel = (-DEFAULT_B_MAX_TRAVEL), .axis[B_AXIS].dual_axis_offset = 0.0f, #if ENABLE_BACKLASH_COMPENSATION @@ -258,7 +258,7 @@ PROGMEM const settings_t defaults = { #ifdef C_AXIS .axis[C_AXIS].steps_per_mm = DEFAULT_C_STEPS_PER_MM, .axis[C_AXIS].acceleration = (DEFAULT_C_ACCELERATION * 60.0f * 60.0f), - .axis[C_AXIS].jerk = (DEFAULT_C_JERK * 60.0f * 60.0f * 60f), + .axis[C_AXIS].jerk = (DEFAULT_C_JERK * 60.0f * 60.0f * 60.0f), .axis[C_AXIS].max_rate = DEFAULT_C_MAX_RATE, .axis[C_AXIS].max_travel = (-DEFAULT_C_MAX_TRAVEL), .axis[C_AXIS].dual_axis_offset = 0.0f, @@ -271,7 +271,7 @@ PROGMEM const settings_t defaults = { #ifdef U_AXIS .axis[U_AXIS].steps_per_mm = DEFAULT_U_STEPS_PER_MM, .axis[U_AXIS].acceleration = (DEFAULT_U_ACCELERATION * 60.0f * 60.0f), - .axis[U_AXIS].jerk = (DEFAULT_U_JERK * 60.0f * 60.0f * 60f), + .axis[U_AXIS].jerk = (DEFAULT_U_JERK * 60.0f * 60.0f * 60.0f), .axis[U_AXIS].max_rate = DEFAULT_U_MAX_RATE, .axis[U_AXIS].max_travel = (-DEFAULT_U_MAX_TRAVEL), .axis[U_AXIS].dual_axis_offset = 0.0f, @@ -283,7 +283,7 @@ PROGMEM const settings_t defaults = { #ifdef V_AXIS .axis[V_AXIS].steps_per_mm = DEFAULT_V_STEPS_PER_MM, .axis[V_AXIS].acceleration = (DEFAULT_V_ACCELERATION * 60.0f * 60.0f), - .axis[V_AXIS].jerk = (DEFAULT_V_JERK * 60.0f * 60.0f * 60f), + .axis[V_AXIS].jerk = (DEFAULT_V_JERK * 60.0f * 60.0f * 60.0f), .axis[V_AXIS].max_rate = DEFAULT_V_MAX_RATE, .axis[V_AXIS].max_travel = (-DEFAULT_V_MAX_TRAVEL), .axis[V_AXIS].dual_axis_offset = 0.0f, From 9951e03833e86e40962c6eea8f8be7d8b5a7ffe6 Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Thu, 2 Nov 2023 18:08:14 +0100 Subject: [PATCH 10/47] Update config.h DEFAULT_X_JERK capitalization --- config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.h b/config.h index 09c2d5b..65f628b 100644 --- a/config.h +++ b/config.h @@ -1827,7 +1827,7 @@ Timezone offset from UTC in hours, allowed range is -12.0 - 12.0. */ ///@{ #if !defined DEFAULT_X_JERK|| defined __DOXYGEN__ -#define DEFAULT_X_Jerk 100.0f // mm/sec^2 +#define DEFAULT_X_JERK 100.0f // mm/sec^2 #endif #if !defined DEFAULT_Y_JERK|| defined __DOXYGEN__ #define DEFAULT_Y_JERK 100.0f // mm/sec^2 From 06ac1ead8a375dbc741e30a385997ab01f0ee276 Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Thu, 2 Nov 2023 19:27:18 +0100 Subject: [PATCH 11/47] Update settings.c static char added for axis_jerk --- settings.c | 1 + 1 file changed, 1 insertion(+) diff --git a/settings.c b/settings.c index aad597d..321473e 100644 --- a/settings.c +++ b/settings.c @@ -434,6 +434,7 @@ static char spindle_types[100] = ""; static char axis_dist[4] = "mm"; static char axis_rate[8] = "mm/min"; static char axis_accel[10] = "mm/sec^2"; +static char axis_jerk[15] = "mm/sec^3"; #if DELTA_ROBOT static char axis_steps[9] = "step/rev"; #else From f295c361d7085e9ba879301297a9fde2f8c467a2 Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Fri, 15 Dec 2023 11:39:19 +0100 Subject: [PATCH 12/47] Update settings.c --- settings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.c b/settings.c index 321473e..68c0701 100644 --- a/settings.c +++ b/settings.c @@ -203,7 +203,7 @@ PROGMEM const settings_t defaults = { .axis[X_AXIS].max_rate = DEFAULT_X_MAX_RATE, .axis[X_AXIS].acceleration = (DEFAULT_X_ACCELERATION * 60.0f * 60.0f), .axis[X_AXIS].jerk = (DEFAULT_X_JERK * 60.0f * 60.0f * 60.0f), - .axis[X_AXIS].max_travel = (DEFAULT_X_MAX_TRAVEL), + .axis[X_AXIS].max_travel = (-DEFAULT_X_MAX_TRAVEL), .axis[X_AXIS].dual_axis_offset = 0.0f, #if ENABLE_BACKLASH_COMPENSATION .axis[X_AXIS].backlash = 0.0f, From 92e750dc0596bee4700839f0733e86ad0c9a696b Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Mon, 18 Dec 2023 23:30:26 +0100 Subject: [PATCH 13/47] adjusted end of accel calculation --- stepper.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/stepper.c b/stepper.c index 4aa2008..121c5cc 100644 --- a/stepper.c +++ b/stepper.c @@ -920,7 +920,8 @@ void st_prep_buffer (void) case Ramp_Accel: // NOTE: Acceleration ramp only computes during first do-while loop. - if (((mm_remaining - prep.accelerate_until) / (prep.current_speed + 1.0f)) <= (pl_block->max_acceleration / pl_block->jerk)) { //+1.0f to avoid divide by 0 speed, minor effect on jerk ramp + if (((mm_remaining - prep.accelerate_until) / (prep.current_speed + 1.0f)) <= (last_segment_accel / pl_block->jerk)) { + //+1.0f to avoid divide by 0 speed, minor effect on jerk ramp // Check if we are on ramp up or ramp down. Ramp down if time to end of acceleration is less than time needed to reach 0 acceleration. // Then limit acceleration change by jerk up to max acceleration and update for next segment. last_segment_accel = max(last_segment_accel - pl_block->jerk * time_var, 0.0f); @@ -955,7 +956,8 @@ void st_prep_buffer (void) default: // case Ramp_Decel: // NOTE: mm_var used as a misc worker variable to prevent errors when near zero speed. - if ((mm_remaining / (prep.current_speed + 1.0f)) <= (pl_block->max_acceleration / pl_block->jerk)) { //+1.0f to avoid divide by 0 speed, minor effect on jerk ramp + if ((mm_remaining / (prep.current_speed + 1.0f)) <= (last_segment_accel / pl_block->jerk)) { + //+1.0f to avoid divide by 0 speed, minor effect on jerk ramp // Check if we are on ramp up or ramp down. Ramp down if time to end of deceleration is less than time needed to reach 0 acceleration. // Then limit acceleration change by jerk up to max acceleration and update for next segment. last_segment_accel = max(last_segment_accel - pl_block->jerk * time_var, 0.0f); From 2361610bda09520b02a5736008c7441860851a55 Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Tue, 19 Dec 2023 01:28:41 +0100 Subject: [PATCH 14/47] cleaned up config and added settings description --- config.h | 18 +++++++++--------- settings.c | 3 ++- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/config.h b/config.h index 3c8fe6e..a0e6dc9 100644 --- a/config.h +++ b/config.h @@ -1831,32 +1831,32 @@ Timezone offset from UTC in hours, allowed range is -12.0 - 12.0. #endif ///@} -/*! @name 12x - Setting_AxisJerk +/*! @name 22x - Setting_AxisJerk */ ///@{ #if !defined DEFAULT_X_JERK|| defined __DOXYGEN__ -#define DEFAULT_X_JERK 100.0f // mm/sec^2 +#define DEFAULT_X_JERK 100.0f // mm/sec^3 #endif #if !defined DEFAULT_Y_JERK|| defined __DOXYGEN__ -#define DEFAULT_Y_JERK 100.0f // mm/sec^2 +#define DEFAULT_Y_JERK 100.0f // mm/sec^3 #endif #if !defined DEFAULT_Z_JERK || defined __DOXYGEN__ -#define DEFAULT_Z_JERK 100.0f // mm/sec^2 +#define DEFAULT_Z_JERK 100.0f // mm/sec^3 #endif #if (defined A_AXIS && !defined DEFAULT_A_JERK) || defined __DOXYGEN__ -#define DEFAULT_A_JERK 100.0f // mm/sec^2 +#define DEFAULT_A_JERK 100.0f // mm/sec^3 #endif #if (defined B_AXIS && !defined DEFAULT_B_JERK) || defined __DOXYGEN__ -#define DEFAULT_B_JERK 100.0f // mm/sec^2 +#define DEFAULT_B_JERK 100.0f // mm/sec^3 #endif #if (defined C_AXIS && !defined DEFAULT_C_JERK) || defined __DOXYGEN__ -#define DEFAULT_C_JERK 100.0f // mm/sec^2 +#define DEFAULT_C_JERK 100.0f // mm/sec^3 #endif #if (defined U_AXIS && !defined DEFAULT_U_JERK) || defined __DOXYGEN__ -#define DEFAULT_U_JERK 100.0f // mm/sec^2 +#define DEFAULT_U_JERK 100.0f // mm/sec^3 #endif #if (defined V_AXIS && !defined DEFAULT_V_JERK) || defined __DOXYGEN__ -#define DEFAULT_V_JERK 100.0f // mm/sec^2 +#define DEFAULT_V_JERK 100.0f // mm/sec^3 #endif ///@} diff --git a/settings.c b/settings.c index b7ab307..6156363 100644 --- a/settings.c +++ b/settings.c @@ -567,7 +567,7 @@ PROGMEM static const setting_detail_t setting_detail[] = { { Setting_AxisStepsPerMM, Group_Axis0, "-axis travel resolution", axis_steps, Format_Decimal, "#####0.000##", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, { Setting_AxisMaxRate, Group_Axis0, "-axis maximum rate", axis_rate, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, { Setting_AxisAcceleration, Group_Axis0, "-axis acceleration", axis_accel, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, - { Setting_AxisJerk, Group_Axis0, "-axis jerk", axis_jerk, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsExtended, set_axis_setting, get_float, NULL, AXIS_OPTS }, + { Setting_AxisJerk, Group_Axis0, "-axis jerk", axis_jerk, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsExtendedFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, { Setting_AxisMaxTravel, Group_Axis0, "-axis maximum travel", axis_dist, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, #if ENABLE_BACKLASH_COMPENSATION { Setting_AxisBacklash, Group_Axis0, "-axis backlash compensation", axis_dist, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsExtendedFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, @@ -757,6 +757,7 @@ PROGMEM static const setting_descr_t setting_descr[] = { { (setting_id_t)(Setting_AxisStepsPerMM + 1), "Travel resolution in steps per degree." }, // "Hack" to get correct description for rotary axes { Setting_AxisMaxRate, "Maximum rate. Used as G0 rapid rate." }, { Setting_AxisAcceleration, "Acceleration. Used for motion planning to not exceed motor torque and lose steps." }, + { Setting_AxisJerk, "Maximum rate of acceleration change - smoothes out acceleration profile up to max axis acceleration."}, { Setting_AxisMaxTravel, "Maximum axis travel distance from homing switch. Determines valid machine space for soft-limits and homing search distances." }, #if ENABLE_BACKLASH_COMPENSATION { Setting_AxisBacklash, "Backlash distance to compensate for." }, From 5bb5945ad8859a7bb91921481741aeec0acd84b7 Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Tue, 19 Dec 2023 14:17:46 +0100 Subject: [PATCH 15/47] added set_axis_setting functions for jerk settings --- settings.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/settings.c b/settings.c index 6156363..3bffc4d 100644 --- a/settings.c +++ b/settings.c @@ -1347,6 +1347,10 @@ static const char *set_axis_setting_unit (setting_id_t setting_id, uint_fast8_t unit = is_rotary ? "deg/sec^2" : "mm/sec^2"; break; + case Setting_AxisJerk: + unit = is_rotary ? "deg/sec^3" : "mm/sec^3"; + break; + case Setting_AxisMaxTravel: case Setting_AxisBacklash: unit = is_rotary ? "deg" : "mm"; @@ -1454,6 +1458,10 @@ static status_code_t set_axis_setting (setting_id_t setting, float value) case Setting_AxisAcceleration: settings.axis[idx].acceleration = override_backup.acceleration[idx] = value * 60.0f * 60.0f; // Convert to mm/min^2 for grbl internal use. break; + + case Setting_AxisJerk: + settings.axis[idx].jerk = value * 60.0f * 60.0f *60.0f; // Convert to mm/min^3 for grbl internal use. + break; case Setting_AxisMaxTravel: if(settings.axis[idx].max_travel != -value) { @@ -1517,6 +1525,10 @@ static float get_float (setting_id_t setting) case Setting_AxisAcceleration: value = settings.axis[idx].acceleration / (60.0f * 60.0f); // Convert from mm/min^2 to mm/sec^2. break; + + case Setting_AxisJerk: + value = settings.axis[idx].acceleration / (60.0f * 60.0f * 60.0f); // Convert from mm/min^3 to mm/sec^3. + break; case Setting_AxisMaxTravel: value = -settings.axis[idx].max_travel; // Store as negative for grbl internal use. From 86672922490a233b87be5e3a9c960e1f2b4069f6 Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Tue, 19 Dec 2023 15:00:15 +0100 Subject: [PATCH 16/47] fixed typo --- settings.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/settings.c b/settings.c index 3bffc4d..94f9e9a 100644 --- a/settings.c +++ b/settings.c @@ -1460,7 +1460,7 @@ static status_code_t set_axis_setting (setting_id_t setting, float value) break; case Setting_AxisJerk: - settings.axis[idx].jerk = value * 60.0f * 60.0f *60.0f; // Convert to mm/min^3 for grbl internal use. + settings.axis[idx].jerk = value * 60.0f * 60.0f * 60.0f; // Convert to mm/min^3 for grbl internal use. break; case Setting_AxisMaxTravel: @@ -1527,7 +1527,7 @@ static float get_float (setting_id_t setting) break; case Setting_AxisJerk: - value = settings.axis[idx].acceleration / (60.0f * 60.0f * 60.0f); // Convert from mm/min^3 to mm/sec^3. + value = settings.axis[idx].jerk / (60.0f * 60.0f * 60.0f); // Convert from mm/min^3 to mm/sec^3. break; case Setting_AxisMaxTravel: From 04708e92ffffa635ac89aab61b48ae3d9e5d8611 Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Tue, 19 Dec 2023 20:22:39 +0100 Subject: [PATCH 17/47] included extended axis setting in get_float check --- settings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.c b/settings.c index 94f9e9a..48f296a 100644 --- a/settings.c +++ b/settings.c @@ -1508,7 +1508,7 @@ static float get_float (setting_id_t setting) { float value = 0.0f; - if (setting >= Setting_AxisSettingsBase && setting <= Setting_AxisSettingsMax) { + if (setting >= Setting_AxisSettingsBase && setting <= Setting_AxisSettingsMax2) { uint_fast8_t idx; From 5cbb222b68cb3de242e758677ff3d11d4102ae17 Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Sat, 30 Dec 2023 19:44:48 +0100 Subject: [PATCH 18/47] Added Min/Max calculations for Jerk --- settings.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/settings.c b/settings.c index 97087e7..ff8ff61 100644 --- a/settings.c +++ b/settings.c @@ -759,7 +759,11 @@ PROGMEM static const setting_descr_t setting_descr[] = { { (setting_id_t)(Setting_AxisStepsPerMM + 1), "Travel resolution in steps per degree." }, // "Hack" to get correct description for rotary axes { Setting_AxisMaxRate, "Maximum rate. Used as G0 rapid rate." }, { Setting_AxisAcceleration, "Acceleration. Used for motion planning to not exceed motor torque and lose steps." }, - { Setting_AxisJerk, "Maximum rate of acceleration change - smoothes out acceleration profile up to max axis acceleration."}, + { Setting_AxisJerk, "Maximum rate of acceleration change - smoothes out acceleration profile up to max axis acceleration.\\n\\n" + "Minimum value of x10 Acceleration setting to ensure decent acceleration times.\\n" + "Maximum is calcualted by current acceleration and stepper segment time.\\n" + "At Maximum value motion is effectively trapezoidal instead of constant jerk.\\n\\n" + "Can be increased by adjusting ACCELERATION_TICKS_PER_SECOND to a larger value before compiling."}, { Setting_AxisMaxTravel, "Maximum axis travel distance from homing switch. Determines valid machine space for soft-limits and homing search distances." }, #if ENABLE_BACKLASH_COMPENSATION { Setting_AxisBacklash, "Backlash distance to compensate for." }, @@ -1459,10 +1463,16 @@ static status_code_t set_axis_setting (setting_id_t setting, float value) case Setting_AxisAcceleration: settings.axis[idx].acceleration = override_backup.acceleration[idx] = value * 60.0f * 60.0f; // Convert to mm/min^2 for grbl internal use. + settings.axis[idx].jerk = (settings.axis[idx].acceleration * 10.0f * 60.0f); //reset jerk to axis minimum. break; case Setting_AxisJerk: - settings.axis[idx].jerk = value * 60.0f * 60.0f * 60.0f; // Convert to mm/min^3 for grbl internal use. + if ((value * 60.0f * 60.0f) < (settings.axis[idx].acceleration * 10.0f)) //ensuring that the acceleration time is limited to at maximum 100ms (or 10 stepper segments). + settings.axis[idx].jerk = settings.axis[idx].acceleration * 10.0f * 60.0f; // mm/min^2 -> mm/min^3 + else if ((settings.axis[idx].acceleration / (value * 60.0f * 60.0f * 60.0f)) < (1.0f / ACCELERATION_TICKS_PER_SECOND)) // Limit Jerk if Value is so large that it reverts back to trapezoidal. + settings.axis[idx].jerk = settings.axis[idx].acceleration * ACCELERATION_TICKS_PER_SECOND * 60.0f; // mm/min^2 -> mm/min^3 + else + settings.axis[idx].jerk = value * 60.0f * 60.0f * 60.0f; // Convert to mm/min^3 for grbl internal use. break; case Setting_AxisMaxTravel: From 4c28e420785c8e8e01b0e7b5fa19af3ba0a4681a Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Tue, 2 Jan 2024 15:35:18 +0100 Subject: [PATCH 19/47] Implemented preliminary G187 support for up to 5 Profiles --- gcode.c | 18 ++++++++++++++++++ gcode.h | 3 ++- settings.c | 29 ++++++++++++++++++++++++++--- 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/gcode.c b/gcode.c index 07aad75..3d43f19 100644 --- a/gcode.c +++ b/gcode.c @@ -1130,6 +1130,13 @@ status_code_t gc_execute_block (char *block) gc_block.modal.scaling_active = int_value == 51; break; + case 187: + word_bit.modal_group.G0 = On; + gc_block.non_modal_command = (non_modal_t)int_value; + if(mantissa != 0) + FAIL(Status_GcodeUnsupportedCommand); + break; + default: FAIL(Status_GcodeUnsupportedCommand); // [Unsupported G command] } // end G-value switch @@ -2234,6 +2241,17 @@ status_code_t gc_execute_block (char *block) } while(idx); break; + case NonModal_SetAccelerationProfile: + uint_fast8_t idx = N_AXIS; + if (!gc_block.values.p) + gc_block.values.p = 1.0f; + else if (gc_block.values.p < 1.0f) + FAIL(Status_NegativeValue); + do { + idx--; + settings_override_acceleration(idx, (settings.axis[idx].acceleration * AccelerationProfile[gc_block.values.p]), (settings.axis[idx].jerk * AccelerationProfile[gc_block.values.p])); + } while(idx); + break; default: // At this point, the rest of the explicit axis commands treat the axis values as the traditional diff --git a/gcode.h b/gcode.h index a5ba6b6..3c19cb9 100644 --- a/gcode.h +++ b/gcode.h @@ -56,7 +56,8 @@ typedef enum { NonModal_SetCoordinateOffset = 92, //!< 92 - G92 NonModal_ResetCoordinateOffset = 102, //!< 102 - G92.1 NonModal_ClearCoordinateOffset = 112, //!< 112 - G92.2 - NonModal_RestoreCoordinateOffset = 122 //!< 122 - G92.3 + NonModal_RestoreCoordinateOffset = 122, //!< 122 - G92.3 + NonModal_SetAccelerationProfile = 187 //!< 187 - G187 } non_modal_t; /*! Modal Group G1: Motion modes diff --git a/settings.c b/settings.c index ff8ff61..faab20f 100644 --- a/settings.c +++ b/settings.c @@ -829,6 +829,7 @@ static setting_details_t setting_details = { static struct { bool valid; float acceleration[N_AXIS]; + float jerk[N_AXIS]; } override_backup = { .valid = false }; static void save_override_backup (void) @@ -838,6 +839,7 @@ static void save_override_backup (void) do { idx--; override_backup.acceleration[idx] = settings.axis[idx].acceleration; + override_backup.jerk[idx] = settings.axis[idx].jerk; } while(idx); override_backup.valid = true; @@ -850,12 +852,13 @@ static void restore_override_backup (void) if(override_backup.valid) do { idx--; settings.axis[idx].acceleration = override_backup.acceleration[idx]; + settings.axis[idx].jerk = override_backup.jerk[idx]; } while(idx); } // Temporarily override acceleration, if 0 restore to setting value. // Note: only allowed when current state is idle. -bool settings_override_acceleration (uint8_t axis, float acceleration) +bool settings_override_acceleration (uint8_t axis, float acceleration, float jerk) { sys_state_t state = state_get(); @@ -868,12 +871,32 @@ bool settings_override_acceleration (uint8_t axis, float acceleration) } else { if(!override_backup.valid) save_override_backup(); - settings.axis[axis].acceleration = acceleration * 60.0f * 60.0f; // Limit max to setting value? + settings.axis[axis].acceleration = (override_backup.acceleration[axis] >= (acceleration * 60.0f * 60.0f)) ? (acceleration * 60.0f * 60.0f) : override_backup.aceceleration[axis]; // Limited to max setting value + } + if(jerk <= 0.0f) { + if(override_backup.valid) + settings.axis[axis].jerk = override_backup.jerk[axis]; + } else { + if(!override_backup.valid) + save_override_backup(); + settings.axis[axis].jerk = (override_backup.jerk[axis] >= (jerk * 60.0f * 60.0f * 60.0f)) ? (jerk * 60.0f * 60.0f * 60.0f) : override_backup.jerk[axis]; // Limited to max setting value } - return true; } +//Acceleration Profiles for G187 P[x] in percent of maximum machine acceleration. +float AccelerationProfile(uint8_t Profile) { + static const float lookup[5] = { + 1.0f, // 100% - Roughing - Max Acceleration Default + 0.8f, // 80% - Semi Roughing + 0.6f, // 60% - Semi Finish + 0.4f, // 40% - Finish + 0.2f, // 20% - Slow AF Mode + }; + Profile = lookup[Profile]; + return Profile; +} + // --- static setting_details_t *settingsd = &setting_details; From 554812d5f13a27cc94c4d9ab5b03f1188b7b52e0 Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Tue, 2 Jan 2024 15:45:05 +0100 Subject: [PATCH 20/47] Unittype and Brackets Hotfix for G187 --- gcode.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/gcode.c b/gcode.c index 3d43f19..fa49685 100644 --- a/gcode.c +++ b/gcode.c @@ -2242,16 +2242,19 @@ status_code_t gc_execute_block (char *block) break; case NonModal_SetAccelerationProfile: - uint_fast8_t idx = N_AXIS; if (!gc_block.values.p) gc_block.values.p = 1.0f; else if (gc_block.values.p < 1.0f) FAIL(Status_NegativeValue); + else if (gc_block.values.p > 5.0f) + FAIL(Status_GcodeValueOutOfRange); + uint8_t idx = N_AXIS; do { idx--; - settings_override_acceleration(idx, (settings.axis[idx].acceleration * AccelerationProfile[gc_block.values.p]), (settings.axis[idx].jerk * AccelerationProfile[gc_block.values.p])); + settings_override_acceleration(idx, (settings.axis[idx].acceleration * AccelerationProfile(gc_block.values.p)), (settings.axis[idx].jerk * AccelerationProfile(gc_block.values.p))); } while(idx); break; + default: // At this point, the rest of the explicit axis commands treat the axis values as the traditional From 299a7cd1aa241aef9983e9cfd98348a2ed301745 Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Tue, 2 Jan 2024 16:20:59 +0100 Subject: [PATCH 21/47] Calculation adjustment for G187 --- gcode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gcode.c b/gcode.c index fa49685..43b7dae 100644 --- a/gcode.c +++ b/gcode.c @@ -2251,10 +2251,10 @@ status_code_t gc_execute_block (char *block) uint8_t idx = N_AXIS; do { idx--; - settings_override_acceleration(idx, (settings.axis[idx].acceleration * AccelerationProfile(gc_block.values.p)), (settings.axis[idx].jerk * AccelerationProfile(gc_block.values.p))); + settings_override_acceleration(idx, ((settings.axis[idx].acceleration / (60.0f * 60.0f)) * AccelerationProfile(gc_block.values.p)), ((settings.axis[idx].jerk / (60.0f * 60.0f * 60.0f)) * AccelerationProfile(gc_block.values.p))); } while(idx); break; - + default: // At this point, the rest of the explicit axis commands treat the axis values as the traditional From dec93aa379f6026bdfb367bc467d145162faeeea Mon Sep 17 00:00:00 2001 From: andrew_marles Date: Tue, 2 Jan 2024 09:38:02 -0800 Subject: [PATCH 22/47] Fixed some typos and syntax errors. --- gcode.c | 12 ++++++------ settings.c | 2 +- settings.h | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/gcode.c b/gcode.c index 43b7dae..27e6e76 100644 --- a/gcode.c +++ b/gcode.c @@ -2242,12 +2242,12 @@ status_code_t gc_execute_block (char *block) break; case NonModal_SetAccelerationProfile: - if (!gc_block.values.p) - gc_block.values.p = 1.0f; - else if (gc_block.values.p < 1.0f) - FAIL(Status_NegativeValue); - else if (gc_block.values.p > 5.0f) - FAIL(Status_GcodeValueOutOfRange); + if (!gc_block.values.p){ + gc_block.values.p = 1.0f;} + else if (gc_block.values.p < 1.0f){ + FAIL(Status_NegativeValue);} + else if (gc_block.values.p > 5.0f){ + FAIL(Status_GcodeValueOutOfRange);} uint8_t idx = N_AXIS; do { idx--; diff --git a/settings.c b/settings.c index faab20f..d5827ac 100644 --- a/settings.c +++ b/settings.c @@ -871,7 +871,7 @@ bool settings_override_acceleration (uint8_t axis, float acceleration, float jer } else { if(!override_backup.valid) save_override_backup(); - settings.axis[axis].acceleration = (override_backup.acceleration[axis] >= (acceleration * 60.0f * 60.0f)) ? (acceleration * 60.0f * 60.0f) : override_backup.aceceleration[axis]; // Limited to max setting value + settings.axis[axis].acceleration = (override_backup.acceleration[axis] >= (acceleration * 60.0f * 60.0f)) ? (acceleration * 60.0f * 60.0f) : override_backup.acceleration[axis]; // Limited to max setting value } if(jerk <= 0.0f) { if(override_backup.valid) diff --git a/settings.h b/settings.h index f5ecbc3..5868ffb 100644 --- a/settings.h +++ b/settings.h @@ -958,7 +958,7 @@ void settings_write_coord_data(coord_system_id_t id, float (*coord_data)[N_AXIS] bool settings_read_coord_data(coord_system_id_t id, float (*coord_data)[N_AXIS]); // Temporarily override acceleration, if 0 restore to configured setting value -bool settings_override_acceleration (uint8_t axis, float acceleration); +bool settings_override_acceleration (uint8_t axis, float acceleration, float jerk); void settings_register (setting_details_t *details); setting_details_t *settings_get_details (void); From 4cc7aaf171d0851ee2b9bf199499dd4fcccfbda2 Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Thu, 4 Jan 2024 00:30:18 +0100 Subject: [PATCH 23/47] Added compiletime check for added acceleration profile code --- config.h | 1 + gcode.c | 2 ++ gcode.h | 4 ++++ settings.c | 2 ++ 4 files changed, 9 insertions(+) diff --git a/config.h b/config.h index c5fbb7a..f4ad7bf 100644 --- a/config.h +++ b/config.h @@ -190,6 +190,7 @@ or EMI triggering the related interrupt falsely or too many times. // ADVANCED CONFIGURATION OPTIONS: #define ENABLE_PATH_BLENDING Off // Do NOT enable unless working on adding this feature! +#define ENABLE_ACCELERATION_PROFILES Off // Enable to allow G-Code changeable acceleration profiles. // Enables code for debugging purposes. Not for general use and always in constant flux. //#define DEBUG // Uncomment to enable. Default disabled. diff --git a/gcode.c b/gcode.c index 27e6e76..b83490d 100644 --- a/gcode.c +++ b/gcode.c @@ -1130,12 +1130,14 @@ status_code_t gc_execute_block (char *block) gc_block.modal.scaling_active = int_value == 51; break; +#if ENABLE_ACCELERATION_PROFILES case 187: word_bit.modal_group.G0 = On; gc_block.non_modal_command = (non_modal_t)int_value; if(mantissa != 0) FAIL(Status_GcodeUnsupportedCommand); break; +#endif default: FAIL(Status_GcodeUnsupportedCommand); // [Unsupported G command] } // end G-value switch diff --git a/gcode.h b/gcode.h index 3c19cb9..208535b 100644 --- a/gcode.h +++ b/gcode.h @@ -56,8 +56,12 @@ typedef enum { NonModal_SetCoordinateOffset = 92, //!< 92 - G92 NonModal_ResetCoordinateOffset = 102, //!< 102 - G92.1 NonModal_ClearCoordinateOffset = 112, //!< 112 - G92.2 + #if ENABLE_ACCELERATION_PROFILES NonModal_RestoreCoordinateOffset = 122, //!< 122 - G92.3 NonModal_SetAccelerationProfile = 187 //!< 187 - G187 + #else + NonModal_RestoreCoordinateOffset = 122 //!< 122 - G92.3 + #endif } non_modal_t; /*! Modal Group G1: Motion modes diff --git a/settings.c b/settings.c index d5827ac..fab733f 100644 --- a/settings.c +++ b/settings.c @@ -884,6 +884,7 @@ bool settings_override_acceleration (uint8_t axis, float acceleration, float jer return true; } +#if ENABLE_ACCELERATION_PROFILES //Acceleration Profiles for G187 P[x] in percent of maximum machine acceleration. float AccelerationProfile(uint8_t Profile) { static const float lookup[5] = { @@ -896,6 +897,7 @@ float AccelerationProfile(uint8_t Profile) { Profile = lookup[Profile]; return Profile; } +#endif // --- From 9f95af13a245646d65659407356ebb5177714216 Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Thu, 4 Jan 2024 00:33:10 +0100 Subject: [PATCH 24/47] Encapsulated G-Code Function with compiletime option --- gcode.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gcode.c b/gcode.c index b83490d..c1c03d7 100644 --- a/gcode.c +++ b/gcode.c @@ -2242,7 +2242,8 @@ status_code_t gc_execute_block (char *block) gc_block.values.xyz[idx] = gc_state.g92_coord_offset[idx]; } while(idx); break; - + +#if ENABLE_ACCELERATION_PROFILES case NonModal_SetAccelerationProfile: if (!gc_block.values.p){ gc_block.values.p = 1.0f;} @@ -2256,7 +2257,7 @@ status_code_t gc_execute_block (char *block) settings_override_acceleration(idx, ((settings.axis[idx].acceleration / (60.0f * 60.0f)) * AccelerationProfile(gc_block.values.p)), ((settings.axis[idx].jerk / (60.0f * 60.0f * 60.0f)) * AccelerationProfile(gc_block.values.p))); } while(idx); break; - +#endif default: // At this point, the rest of the explicit axis commands treat the axis values as the traditional From e645ddbdd95ab8a263a06b69e74c67a273de1913 Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Sun, 7 Jan 2024 20:58:26 +0100 Subject: [PATCH 25/47] Added compile time option for jerk controlled motion --- config.h | 2 ++ planner.c | 10 ++++++++-- planner.h | 4 +++- settings.c | 44 ++++++++++++++++++++++++++++++++++++++------ settings.h | 10 ++++++++++ stepper.c | 16 ++++++++++++++-- 6 files changed, 75 insertions(+), 11 deletions(-) diff --git a/config.h b/config.h index f4ad7bf..f3a1d1e 100644 --- a/config.h +++ b/config.h @@ -189,8 +189,10 @@ or EMI triggering the related interrupt falsely or too many times. // --------------------------------------------------------------------------------------- // ADVANCED CONFIGURATION OPTIONS: +// EXPERIMENTAL OPTIONS #define ENABLE_PATH_BLENDING Off // Do NOT enable unless working on adding this feature! #define ENABLE_ACCELERATION_PROFILES Off // Enable to allow G-Code changeable acceleration profiles. +#define ENABLE_JERK_ACCELERATION Off // Enable to use 3rd order Acceleration calculations. May need more processing power, tiny chips beware. // Enables code for debugging purposes. Not for general use and always in constant flux. //#define DEBUG // Uncomment to enable. Default disabled. diff --git a/planner.c b/planner.c index bfb92e8..a195897 100644 --- a/planner.c +++ b/planner.c @@ -354,7 +354,7 @@ static inline float limit_acceleration_by_axis_maximum (float *unit_vec) return limit_value; } - +#if ENABLE_JERK_ACCELERATION static inline float limit_jerk_by_axis_maximum (float *unit_vec) { uint_fast8_t idx = N_AXIS; @@ -367,7 +367,7 @@ static inline float limit_jerk_by_axis_maximum (float *unit_vec) return limit_value; } - +#endif static inline float limit_max_rate_by_axis_maximum (float *unit_vec) { uint_fast8_t idx = N_AXIS; @@ -516,8 +516,12 @@ bool plan_buffer_line (float *target, plan_line_data_t *pl_data) #endif block->millimeters = convert_delta_vector_to_unit_vector(unit_vec); +#if ENABLE_ACCELERATION_PROFILES block->max_acceleration = limit_acceleration_by_axis_maximum(unit_vec); block->jerk = limit_jerk_by_axis_maximum(unit_vec); +#else + block->acceleration = limit_acceleration_by_axis_maximum(unit_vec); +#endif block->rapid_rate = limit_max_rate_by_axis_maximum(unit_vec); // Store programmed rate. @@ -531,11 +535,13 @@ bool plan_buffer_line (float *target, plan_line_data_t *pl_data) if (block->condition.inverse_time) block->programmed_rate *= block->millimeters; } +#if ENABLE_ACCELERATION_PROFILES // Calculate effective acceleration over block. Since jerk acceleration takes longer to execute due to ramp up and // ramp down of the acceleration at the start and end of a ramp we need to adjust the acceleration value the planner // uses so it still calculates reasonable entry and exit speeds. We do this by adding 2x the time it takes to reach // full acceleration to the trapezoidal acceleration time and dividing the programmed rate by the value obtained. block->acceleration = block->programmed_rate / ((block->programmed_rate / block->max_acceleration) + 2.0f * (block->max_acceleration / block->jerk)); +#endif // TODO: Need to check this method handling zero junction speeds when starting from rest. if ((block_buffer_head == block_buffer_tail) || (block->condition.system_motion)) { diff --git a/planner.h b/planner.h index acb509b..fc03307 100644 --- a/planner.h +++ b/planner.h @@ -61,9 +61,11 @@ typedef struct plan_block { float entry_speed_sqr; // The current planned entry speed at block junction in (mm/min)^2 float max_entry_speed_sqr; // Maximum allowable entry speed based on the minimum of junction limit and // neighboring nominal speeds with overrides in (mm/min)^2 - float acceleration; // Effective acceleration over plannerblock calculated from trapezoidal movement plan. + float acceleration; // Effective acceleration over plannerblock calculated from trapezoidal movement plan. Does not change in trapezoidal mode. +#if ENABLE_JERK_ACCELERATION float max_acceleration; // Axis-limit adjusted line acceleration in (mm/min^2). Does not change. float jerk; // Axis-limit adjusted jerk value in (mm/min^3). Does not change. +#endif float millimeters; // The remaining distance for this block to be executed in (mm). // NOTE: This value may be altered by stepper algorithm during execution. diff --git a/settings.c b/settings.c index fab733f..56817d3 100644 --- a/settings.c +++ b/settings.c @@ -204,7 +204,9 @@ PROGMEM const settings_t defaults = { .axis[X_AXIS].steps_per_mm = DEFAULT_X_STEPS_PER_MM, .axis[X_AXIS].max_rate = DEFAULT_X_MAX_RATE, .axis[X_AXIS].acceleration = (DEFAULT_X_ACCELERATION * 60.0f * 60.0f), +#if ENABLE_JERK_ACCELERATION .axis[X_AXIS].jerk = (DEFAULT_X_JERK * 60.0f * 60.0f * 60.0f), +#endif .axis[X_AXIS].max_travel = (-DEFAULT_X_MAX_TRAVEL), .axis[X_AXIS].dual_axis_offset = 0.0f, #if ENABLE_BACKLASH_COMPENSATION @@ -215,7 +217,9 @@ PROGMEM const settings_t defaults = { .axis[Y_AXIS].max_rate = DEFAULT_Y_MAX_RATE, .axis[Y_AXIS].max_travel = (-DEFAULT_Y_MAX_TRAVEL), .axis[Y_AXIS].acceleration = (DEFAULT_Y_ACCELERATION * 60.0f * 60.0f), +#if ENABLE_JERK_ACCELERATION .axis[Y_AXIS].jerk = (DEFAULT_Y_JERK * 60.0f * 60.0f * 60.0f), +#endif .axis[Y_AXIS].dual_axis_offset = 0.0f, #if ENABLE_BACKLASH_COMPENSATION .axis[Y_AXIS].backlash = 0.0f, @@ -224,7 +228,9 @@ PROGMEM const settings_t defaults = { .axis[Z_AXIS].steps_per_mm = DEFAULT_Z_STEPS_PER_MM, .axis[Z_AXIS].max_rate = DEFAULT_Z_MAX_RATE, .axis[Z_AXIS].acceleration = (DEFAULT_Z_ACCELERATION * 60.0f * 60.0f), +#if ENABLE_JERK_ACCELERATION .axis[Z_AXIS].jerk = (DEFAULT_Z_JERK * 60.0f * 60.0f * 60.0f), +#endif .axis[Z_AXIS].max_travel = (-DEFAULT_Z_MAX_TRAVEL), .axis[Z_AXIS].dual_axis_offset = 0.0f, #if ENABLE_BACKLASH_COMPENSATION @@ -235,7 +241,9 @@ PROGMEM const settings_t defaults = { .axis[A_AXIS].steps_per_mm = DEFAULT_A_STEPS_PER_MM, .axis[A_AXIS].max_rate = DEFAULT_A_MAX_RATE, .axis[A_AXIS].acceleration =(DEFAULT_A_ACCELERATION * 60.0f * 60.0f), +#if ENABLE_JERK_ACCELERATION .axis[A_AXIS].jerk = (DEFAULT_A_JERK * 60.0f * 60.0f * 60.0f), +#endif .axis[A_AXIS].max_travel = (-DEFAULT_A_MAX_TRAVEL), .axis[A_AXIS].dual_axis_offset = 0.0f, #if ENABLE_BACKLASH_COMPENSATION @@ -248,7 +256,9 @@ PROGMEM const settings_t defaults = { .axis[B_AXIS].steps_per_mm = DEFAULT_B_STEPS_PER_MM, .axis[B_AXIS].max_rate = DEFAULT_B_MAX_RATE, .axis[B_AXIS].acceleration = (DEFAULT_B_ACCELERATION * 60.0f * 60.0f), +#if ENABLE_JERK_ACCELERATION .axis[B_AXIS].jerk = (DEFAULT_B_JERK * 60.0f * 60.0f * 60.0f), +#endif .axis[B_AXIS].max_travel = (-DEFAULT_B_MAX_TRAVEL), .axis[B_AXIS].dual_axis_offset = 0.0f, #if ENABLE_BACKLASH_COMPENSATION @@ -260,7 +270,9 @@ PROGMEM const settings_t defaults = { #ifdef C_AXIS .axis[C_AXIS].steps_per_mm = DEFAULT_C_STEPS_PER_MM, .axis[C_AXIS].acceleration = (DEFAULT_C_ACCELERATION * 60.0f * 60.0f), +#if ENABLE_JERK_ACCELERATION .axis[C_AXIS].jerk = (DEFAULT_C_JERK * 60.0f * 60.0f * 60.0f), +#endif .axis[C_AXIS].max_rate = DEFAULT_C_MAX_RATE, .axis[C_AXIS].max_travel = (-DEFAULT_C_MAX_TRAVEL), .axis[C_AXIS].dual_axis_offset = 0.0f, @@ -273,7 +285,9 @@ PROGMEM const settings_t defaults = { #ifdef U_AXIS .axis[U_AXIS].steps_per_mm = DEFAULT_U_STEPS_PER_MM, .axis[U_AXIS].acceleration = (DEFAULT_U_ACCELERATION * 60.0f * 60.0f), +#if ENABLE_JERK_ACCELERATION .axis[U_AXIS].jerk = (DEFAULT_U_JERK * 60.0f * 60.0f * 60.0f), +#endif .axis[U_AXIS].max_rate = DEFAULT_U_MAX_RATE, .axis[U_AXIS].max_travel = (-DEFAULT_U_MAX_TRAVEL), .axis[U_AXIS].dual_axis_offset = 0.0f, @@ -285,7 +299,9 @@ PROGMEM const settings_t defaults = { #ifdef V_AXIS .axis[V_AXIS].steps_per_mm = DEFAULT_V_STEPS_PER_MM, .axis[V_AXIS].acceleration = (DEFAULT_V_ACCELERATION * 60.0f * 60.0f), +#if ENABLE_JERK_ACCELERATION .axis[V_AXIS].jerk = (DEFAULT_V_JERK * 60.0f * 60.0f * 60.0f), +#endif .axis[V_AXIS].max_rate = DEFAULT_V_MAX_RATE, .axis[V_AXIS].max_travel = (-DEFAULT_V_MAX_TRAVEL), .axis[V_AXIS].dual_axis_offset = 0.0f, @@ -440,7 +456,9 @@ static char spindle_types[100] = ""; static char axis_dist[4] = "mm"; static char axis_rate[8] = "mm/min"; static char axis_accel[10] = "mm/sec^2"; +#if ENABLE_JERK_ACCELERATION static char axis_jerk[15] = "mm/sec^3"; +#endif #if DELTA_ROBOT static char axis_steps[9] = "step/rev"; #else @@ -569,7 +587,9 @@ PROGMEM static const setting_detail_t setting_detail[] = { { Setting_AxisStepsPerMM, Group_Axis0, "-axis travel resolution", axis_steps, Format_Decimal, "#####0.000##", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, { Setting_AxisMaxRate, Group_Axis0, "-axis maximum rate", axis_rate, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, { Setting_AxisAcceleration, Group_Axis0, "-axis acceleration", axis_accel, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, +#if ENABLE_JERK_ACCELERATION { Setting_AxisJerk, Group_Axis0, "-axis jerk", axis_jerk, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsExtendedFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, +#endif { Setting_AxisMaxTravel, Group_Axis0, "-axis maximum travel", axis_dist, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, #if ENABLE_BACKLASH_COMPENSATION { Setting_AxisBacklash, Group_Axis0, "-axis backlash compensation", axis_dist, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsExtendedFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, @@ -759,11 +779,13 @@ PROGMEM static const setting_descr_t setting_descr[] = { { (setting_id_t)(Setting_AxisStepsPerMM + 1), "Travel resolution in steps per degree." }, // "Hack" to get correct description for rotary axes { Setting_AxisMaxRate, "Maximum rate. Used as G0 rapid rate." }, { Setting_AxisAcceleration, "Acceleration. Used for motion planning to not exceed motor torque and lose steps." }, +#if ENABLE_JERK_ACCELERATION { Setting_AxisJerk, "Maximum rate of acceleration change - smoothes out acceleration profile up to max axis acceleration.\\n\\n" "Minimum value of x10 Acceleration setting to ensure decent acceleration times.\\n" "Maximum is calcualted by current acceleration and stepper segment time.\\n" "At Maximum value motion is effectively trapezoidal instead of constant jerk.\\n\\n" "Can be increased by adjusting ACCELERATION_TICKS_PER_SECOND to a larger value before compiling."}, +#endif { Setting_AxisMaxTravel, "Maximum axis travel distance from homing switch. Determines valid machine space for soft-limits and homing search distances." }, #if ENABLE_BACKLASH_COMPENSATION { Setting_AxisBacklash, "Backlash distance to compensate for." }, @@ -829,7 +851,9 @@ static setting_details_t setting_details = { static struct { bool valid; float acceleration[N_AXIS]; +#if ENABLE_JERK_ACCELERATION float jerk[N_AXIS]; +#endif } override_backup = { .valid = false }; static void save_override_backup (void) @@ -839,7 +863,9 @@ static void save_override_backup (void) do { idx--; override_backup.acceleration[idx] = settings.axis[idx].acceleration; +#if ENABLE_JERK_ACCELERATION override_backup.jerk[idx] = settings.axis[idx].jerk; +#endif } while(idx); override_backup.valid = true; @@ -852,7 +878,9 @@ static void restore_override_backup (void) if(override_backup.valid) do { idx--; settings.axis[idx].acceleration = override_backup.acceleration[idx]; +#if ENABLE_JERK_ACCELERATION settings.axis[idx].jerk = override_backup.jerk[idx]; +#endif } while(idx); } @@ -873,6 +901,7 @@ bool settings_override_acceleration (uint8_t axis, float acceleration, float jer save_override_backup(); settings.axis[axis].acceleration = (override_backup.acceleration[axis] >= (acceleration * 60.0f * 60.0f)) ? (acceleration * 60.0f * 60.0f) : override_backup.acceleration[axis]; // Limited to max setting value } +#if ENABLE_JERK_ACCELERATION if(jerk <= 0.0f) { if(override_backup.valid) settings.axis[axis].jerk = override_backup.jerk[axis]; @@ -881,6 +910,7 @@ bool settings_override_acceleration (uint8_t axis, float acceleration, float jer save_override_backup(); settings.axis[axis].jerk = (override_backup.jerk[axis] >= (jerk * 60.0f * 60.0f * 60.0f)) ? (jerk * 60.0f * 60.0f * 60.0f) : override_backup.jerk[axis]; // Limited to max setting value } +#endif return true; } @@ -1377,11 +1407,11 @@ static const char *set_axis_setting_unit (setting_id_t setting_id, uint_fast8_t case Setting_AxisAcceleration: unit = is_rotary ? "deg/sec^2" : "mm/sec^2"; break; - +#if ENABLE_JERK_ACCELERATION case Setting_AxisJerk: unit = is_rotary ? "deg/sec^3" : "mm/sec^3"; break; - +#endif case Setting_AxisMaxTravel: case Setting_AxisBacklash: unit = is_rotary ? "deg" : "mm"; @@ -1488,9 +1518,11 @@ static status_code_t set_axis_setting (setting_id_t setting, float value) case Setting_AxisAcceleration: settings.axis[idx].acceleration = override_backup.acceleration[idx] = value * 60.0f * 60.0f; // Convert to mm/min^2 for grbl internal use. +#if ENABLE_JERK_ACCELERATION settings.axis[idx].jerk = (settings.axis[idx].acceleration * 10.0f * 60.0f); //reset jerk to axis minimum. +#endif break; - +#if ENABLE_JERK_ACCELERATION case Setting_AxisJerk: if ((value * 60.0f * 60.0f) < (settings.axis[idx].acceleration * 10.0f)) //ensuring that the acceleration time is limited to at maximum 100ms (or 10 stepper segments). settings.axis[idx].jerk = settings.axis[idx].acceleration * 10.0f * 60.0f; // mm/min^2 -> mm/min^3 @@ -1499,7 +1531,7 @@ static status_code_t set_axis_setting (setting_id_t setting, float value) else settings.axis[idx].jerk = value * 60.0f * 60.0f * 60.0f; // Convert to mm/min^3 for grbl internal use. break; - +#endif case Setting_AxisMaxTravel: if(settings.axis[idx].max_travel != -value) { bit_false(sys.homed.mask, bit(idx)); @@ -1562,11 +1594,11 @@ static float get_float (setting_id_t setting) case Setting_AxisAcceleration: value = settings.axis[idx].acceleration / (60.0f * 60.0f); // Convert from mm/min^2 to mm/sec^2. break; - +#if ENABLE_JERK_ACCELERATION case Setting_AxisJerk: value = settings.axis[idx].jerk / (60.0f * 60.0f * 60.0f); // Convert from mm/min^3 to mm/sec^3. break; - +#endif case Setting_AxisMaxTravel: value = -settings.axis[idx].max_travel; // Store as negative for grbl internal use. break; diff --git a/settings.h b/settings.h index 5868ffb..1de8c57 100644 --- a/settings.h +++ b/settings.h @@ -441,7 +441,11 @@ typedef enum { // Calculated base values for driver/plugin stepper settings Setting_AxisExtended0 = Setting_AxisSettingsBase2, Setting_AxisExtended1 = Setting_AxisSettingsBase2 + AXIS_SETTINGS_INCREMENT, +#if ENABLE_JERK_ACCELERATION Setting_AxisJerk = Setting_AxisSettingsBase2 + 2 * AXIS_SETTINGS_INCREMENT, +#else + Setting_AxisExtended2 = Setting_AxisSettingsBase2 + 2 * AXIS_SETTINGS_INCREMENT, +#endif Setting_AxisExtended3 = Setting_AxisSettingsBase2 + 3 * AXIS_SETTINGS_INCREMENT, Setting_AxisExtended4 = Setting_AxisSettingsBase2 + 4 * AXIS_SETTINGS_INCREMENT, Setting_AxisExtended5 = Setting_AxisSettingsBase2 + 5 * AXIS_SETTINGS_INCREMENT, @@ -614,7 +618,9 @@ typedef struct { float steps_per_mm; float max_rate; float acceleration; +#if ENABLE_JERK_ACCELERATION float jerk; +#endif float max_travel; float dual_axis_offset; #if ENABLE_BACKLASH_COMPENSATION @@ -958,7 +964,11 @@ void settings_write_coord_data(coord_system_id_t id, float (*coord_data)[N_AXIS] bool settings_read_coord_data(coord_system_id_t id, float (*coord_data)[N_AXIS]); // Temporarily override acceleration, if 0 restore to configured setting value +#if ENABLE_JERK_ACCELERATION bool settings_override_acceleration (uint8_t axis, float acceleration, float jerk); +#else +bool settings_override_acceleration (uint8_t axis, float acceleration); +#endif void settings_register (setting_details_t *details); setting_details_t *settings_get_details (void); diff --git a/stepper.c b/stepper.c index a06a38c..36553e6 100644 --- a/stepper.c +++ b/stepper.c @@ -892,7 +892,9 @@ void st_prep_buffer (void) float dt_max = DT_SEGMENT; // Maximum segment time float dt = 0.0f; // Initialize segment time float time_var = dt_max; // Time worker variable +#if ENABLE_JERK_ACCELERATION float last_segment_accel = 0.0f; // Acceleration value of last computed segment. Initialize as 0.0 +#endif float mm_var; // mm - Distance worker variable float speed_var; // Speed worker variable float mm_remaining = pl_block->millimeters; // New segment distance from end of block. @@ -921,15 +923,20 @@ void st_prep_buffer (void) case Ramp_Accel: // NOTE: Acceleration ramp only computes during first do-while loop. +#if ENABLE_JERK_ACCELERATION if (((mm_remaining - prep.accelerate_until) / (prep.current_speed + 1.0f)) <= (last_segment_accel / pl_block->jerk)) { //+1.0f to avoid divide by 0 speed, minor effect on jerk ramp // Check if we are on ramp up or ramp down. Ramp down if time to end of acceleration is less than time needed to reach 0 acceleration. // Then limit acceleration change by jerk up to max acceleration and update for next segment. - last_segment_accel = max(last_segment_accel - pl_block->jerk * time_var, 0.0f); + // Minimum acceleration jerk per time_var to ensure acceleartion completes. Acceleration change at end of ramp is in acceptable jerk range. + last_segment_accel = max(last_segment_accel - pl_block->jerk * time_var, pl_block->jerk * time_var); } else { last_segment_accel = min(last_segment_accel + pl_block->jerk * time_var, pl_block->max_acceleration); } speed_var = last_segment_accel * time_var; +#else + speed_var = pl_block->acceleration * time_var; +#endif mm_remaining -= time_var * (prep.current_speed + 0.5f * speed_var); if (mm_remaining < prep.accelerate_until) { // End of acceleration ramp. // Acceleration-cruise, acceleration-deceleration ramp junction, or end of block. @@ -957,15 +964,20 @@ void st_prep_buffer (void) default: // case Ramp_Decel: // NOTE: mm_var used as a misc worker variable to prevent errors when near zero speed. +#if ENABLE_JERK_ACCELERATION if ((mm_remaining / (prep.current_speed + 1.0f)) <= (last_segment_accel / pl_block->jerk)) { //+1.0f to avoid divide by 0 speed, minor effect on jerk ramp // Check if we are on ramp up or ramp down. Ramp down if time to end of deceleration is less than time needed to reach 0 acceleration. // Then limit acceleration change by jerk up to max acceleration and update for next segment. - last_segment_accel = max(last_segment_accel - pl_block->jerk * time_var, 0.0f); + // Minimum acceleration of jerk per time_var to ensure acceleration completes. Acceleration change at end of ramp is in acceptable jerk range. + last_segment_accel = max(last_segment_accel - pl_block->jerk * time_var, pl_block->jerk * time_var); } else { last_segment_accel = min(last_segment_accel + pl_block->jerk * time_var, pl_block->max_acceleration); } speed_var = last_segment_accel * time_var; // Used as delta speed (mm/min) +#else + speed_var = pl_block->acceleration * time_var; // Used as delta speed (mm/min) +#endif if (prep.current_speed > speed_var) { // Check if at or below zero speed. // Compute distance from end of segment to end of block. mm_var = mm_remaining - time_var * (prep.current_speed - 0.5f * speed_var); // (mm) From bc003a2f64024061d78651f5d507894f3d9a009a Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Sun, 7 Jan 2024 21:23:27 +0100 Subject: [PATCH 26/47] Included default jerk values in compile option --- config.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config.h b/config.h index f3a1d1e..62ee289 100644 --- a/config.h +++ b/config.h @@ -1848,6 +1848,7 @@ Timezone offset from UTC in hours, allowed range is -12.0 - 12.0. /*! @name 22x - Setting_AxisJerk */ ///@{ +#if ENABLE_JERK_ACCELERATION #if !defined DEFAULT_X_JERK|| defined __DOXYGEN__ #define DEFAULT_X_JERK 100.0f // mm/sec^3 #endif @@ -1872,6 +1873,7 @@ Timezone offset from UTC in hours, allowed range is -12.0 - 12.0. #if (defined V_AXIS && !defined DEFAULT_V_JERK) || defined __DOXYGEN__ #define DEFAULT_V_JERK 100.0f // mm/sec^3 #endif +#endif ///@} /*! @name 13x - Setting_AxisMaxTravel From fb396fc290adb17c21a8224b5c87424e557b1f4e Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Mon, 8 Jan 2024 00:47:17 +0100 Subject: [PATCH 27/47] settings_override_acceleration declaration adjusted for compile option --- settings.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/settings.c b/settings.c index 56817d3..3bd6bba 100644 --- a/settings.c +++ b/settings.c @@ -886,7 +886,11 @@ static void restore_override_backup (void) // Temporarily override acceleration, if 0 restore to setting value. // Note: only allowed when current state is idle. +#if ENABLE_JERK_ACCELERATION bool settings_override_acceleration (uint8_t axis, float acceleration, float jerk) +#else +bool settings_override_acceleration (uint8_t axis, float acceleration) +#endif { sys_state_t state = state_get(); From ba26451c57a39f2e787d33db1bfd0969d454507e Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Mon, 8 Jan 2024 21:22:53 +0100 Subject: [PATCH 28/47] added AccelerationProfile function to settings.h --- settings.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/settings.h b/settings.h index 1de8c57..f3f057e 100644 --- a/settings.h +++ b/settings.h @@ -970,6 +970,10 @@ bool settings_override_acceleration (uint8_t axis, float acceleration, float jer bool settings_override_acceleration (uint8_t axis, float acceleration); #endif +#if ENABLE_ACCELERATION_PROFILES +float AccelerationProfile(uint8_t Profile); +#endif + void settings_register (setting_details_t *details); setting_details_t *settings_get_details (void); bool settings_is_group_available (setting_group_t group); From f6bf39c52cea2726e9fcf8805e55fa0d8cf66702 Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Wed, 10 Jan 2024 23:27:45 +0100 Subject: [PATCH 29/47] Updated AccelerationProfile implementation to not alter settingsvalues --- gcode.c | 6 +----- planner.c | 14 ++++++++++---- settings.c | 16 +--------------- settings.h | 7 ++----- 4 files changed, 14 insertions(+), 29 deletions(-) diff --git a/gcode.c b/gcode.c index c1c03d7..c6f77a3 100644 --- a/gcode.c +++ b/gcode.c @@ -2251,11 +2251,7 @@ status_code_t gc_execute_block (char *block) FAIL(Status_NegativeValue);} else if (gc_block.values.p > 5.0f){ FAIL(Status_GcodeValueOutOfRange);} - uint8_t idx = N_AXIS; - do { - idx--; - settings_override_acceleration(idx, ((settings.axis[idx].acceleration / (60.0f * 60.0f)) * AccelerationProfile(gc_block.values.p)), ((settings.axis[idx].jerk / (60.0f * 60.0f * 60.0f)) * AccelerationProfile(gc_block.values.p))); - } while(idx); + ActiveAccelProfile = gc_block.values.p; break; #endif default: diff --git a/planner.c b/planner.c index a195897..008db7a 100644 --- a/planner.c +++ b/planner.c @@ -351,9 +351,12 @@ static inline float limit_acceleration_by_axis_maximum (float *unit_vec) if (unit_vec[--idx] != 0.0f) // Avoid divide by zero. limit_value = min(limit_value, fabsf(settings.axis[idx].acceleration / unit_vec[idx])); } while(idx); - +#if ENABLE_ACCELERATION_PROFILES + limit_value *= AccelerationProfile(ActiveAccelProfile); +#endif return limit_value; } + #if ENABLE_JERK_ACCELERATION static inline float limit_jerk_by_axis_maximum (float *unit_vec) { @@ -364,10 +367,13 @@ static inline float limit_jerk_by_axis_maximum (float *unit_vec) if (unit_vec[--idx] != 0.0f) // Avoid divide by zero. limit_value = min(limit_value, fabsf(settings.axis[idx].jerk / unit_vec[idx])); } while(idx); - +#if ENABLE_ACCELERATION_PROFILES + limit_value *= AccelerationProfile(ActiveAccelProfile); +#endif return limit_value; } #endif + static inline float limit_max_rate_by_axis_maximum (float *unit_vec) { uint_fast8_t idx = N_AXIS; @@ -516,7 +522,7 @@ bool plan_buffer_line (float *target, plan_line_data_t *pl_data) #endif block->millimeters = convert_delta_vector_to_unit_vector(unit_vec); -#if ENABLE_ACCELERATION_PROFILES +#if ENABLE_JERK_ACCELERATION block->max_acceleration = limit_acceleration_by_axis_maximum(unit_vec); block->jerk = limit_jerk_by_axis_maximum(unit_vec); #else @@ -535,7 +541,7 @@ bool plan_buffer_line (float *target, plan_line_data_t *pl_data) if (block->condition.inverse_time) block->programmed_rate *= block->millimeters; } -#if ENABLE_ACCELERATION_PROFILES +#if ENABLE_JERK_ACCELERATION // Calculate effective acceleration over block. Since jerk acceleration takes longer to execute due to ramp up and // ramp down of the acceleration at the start and end of a ramp we need to adjust the acceleration value the planner // uses so it still calculates reasonable entry and exit speeds. We do this by adding 2x the time it takes to reach diff --git a/settings.c b/settings.c index 3bd6bba..6ba547c 100644 --- a/settings.c +++ b/settings.c @@ -886,11 +886,7 @@ static void restore_override_backup (void) // Temporarily override acceleration, if 0 restore to setting value. // Note: only allowed when current state is idle. -#if ENABLE_JERK_ACCELERATION -bool settings_override_acceleration (uint8_t axis, float acceleration, float jerk) -#else bool settings_override_acceleration (uint8_t axis, float acceleration) -#endif { sys_state_t state = state_get(); @@ -905,22 +901,12 @@ bool settings_override_acceleration (uint8_t axis, float acceleration) save_override_backup(); settings.axis[axis].acceleration = (override_backup.acceleration[axis] >= (acceleration * 60.0f * 60.0f)) ? (acceleration * 60.0f * 60.0f) : override_backup.acceleration[axis]; // Limited to max setting value } -#if ENABLE_JERK_ACCELERATION - if(jerk <= 0.0f) { - if(override_backup.valid) - settings.axis[axis].jerk = override_backup.jerk[axis]; - } else { - if(!override_backup.valid) - save_override_backup(); - settings.axis[axis].jerk = (override_backup.jerk[axis] >= (jerk * 60.0f * 60.0f * 60.0f)) ? (jerk * 60.0f * 60.0f * 60.0f) : override_backup.jerk[axis]; // Limited to max setting value - } -#endif return true; } #if ENABLE_ACCELERATION_PROFILES //Acceleration Profiles for G187 P[x] in percent of maximum machine acceleration. -float AccelerationProfile(uint8_t Profile) { +float LookupProfile(uint8_t Profile) { static const float lookup[5] = { 1.0f, // 100% - Roughing - Max Acceleration Default 0.8f, // 80% - Semi Roughing diff --git a/settings.h b/settings.h index f3f057e..3a40c69 100644 --- a/settings.h +++ b/settings.h @@ -964,14 +964,11 @@ void settings_write_coord_data(coord_system_id_t id, float (*coord_data)[N_AXIS] bool settings_read_coord_data(coord_system_id_t id, float (*coord_data)[N_AXIS]); // Temporarily override acceleration, if 0 restore to configured setting value -#if ENABLE_JERK_ACCELERATION -bool settings_override_acceleration (uint8_t axis, float acceleration, float jerk); -#else bool settings_override_acceleration (uint8_t axis, float acceleration); -#endif #if ENABLE_ACCELERATION_PROFILES -float AccelerationProfile(uint8_t Profile); +extern uint8_t ActiveAccelProfile = 1; +float AccelerationProfile (uint8_t Profile); #endif void settings_register (setting_details_t *details); From a53770489626b588a5b395dc6e9baef119f5b59d Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Wed, 10 Jan 2024 23:37:52 +0100 Subject: [PATCH 30/47] reverted settings_override_acceleration to original --- settings.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/settings.c b/settings.c index 6ba547c..e56ca22 100644 --- a/settings.c +++ b/settings.c @@ -851,9 +851,6 @@ static setting_details_t setting_details = { static struct { bool valid; float acceleration[N_AXIS]; -#if ENABLE_JERK_ACCELERATION - float jerk[N_AXIS]; -#endif } override_backup = { .valid = false }; static void save_override_backup (void) @@ -863,9 +860,6 @@ static void save_override_backup (void) do { idx--; override_backup.acceleration[idx] = settings.axis[idx].acceleration; -#if ENABLE_JERK_ACCELERATION - override_backup.jerk[idx] = settings.axis[idx].jerk; -#endif } while(idx); override_backup.valid = true; @@ -878,9 +872,6 @@ static void restore_override_backup (void) if(override_backup.valid) do { idx--; settings.axis[idx].acceleration = override_backup.acceleration[idx]; -#if ENABLE_JERK_ACCELERATION - settings.axis[idx].jerk = override_backup.jerk[idx]; -#endif } while(idx); } From 2bef5f707158aab7b56bcbbce8510af282715b52 Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Thu, 11 Jan 2024 14:52:30 +0100 Subject: [PATCH 31/47] adjusted last_segment_accel handling at end of accel ramps --- stepper.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/stepper.c b/stepper.c index 36553e6..ce77bd0 100644 --- a/stepper.c +++ b/stepper.c @@ -944,6 +944,9 @@ void st_prep_buffer (void) time_var = 2.0f * (pl_block->millimeters - mm_remaining) / (prep.current_speed + prep.maximum_speed); prep.ramp_type = mm_remaining == prep.decelerate_after ? Ramp_Decel : Ramp_Cruise; prep.current_speed = prep.maximum_speed; +#if ENABLE_JERK_ACCELERATION + last_segment_accel = 0.0f; // reset acceleration variable to 0 for next accel ramp +#endif } else // Acceleration only. prep.current_speed += speed_var; break; @@ -991,6 +994,9 @@ void st_prep_buffer (void) time_var = 2.0f * (mm_remaining - prep.mm_complete) / (prep.current_speed + prep.exit_speed); mm_remaining = prep.mm_complete; prep.current_speed = prep.exit_speed; +#if ENABLE_JERK_ACCELERATION + last_segment_accel = 0.0f; // reset acceleration variable to 0 for next accel ramp +#endif } dt += time_var; // Add computed ramp time to total segment time. From b6135c421873990eb4d56838a8bc336a0e328edb Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Sun, 14 Jan 2024 14:20:10 +0100 Subject: [PATCH 32/47] Changed ActiveAccelProfile declaration/definition because of compiler warning --- planner.c | 4 ++-- settings.c | 2 ++ settings.h | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/planner.c b/planner.c index 008db7a..0ade5f7 100644 --- a/planner.c +++ b/planner.c @@ -352,7 +352,7 @@ static inline float limit_acceleration_by_axis_maximum (float *unit_vec) limit_value = min(limit_value, fabsf(settings.axis[idx].acceleration / unit_vec[idx])); } while(idx); #if ENABLE_ACCELERATION_PROFILES - limit_value *= AccelerationProfile(ActiveAccelProfile); + limit_value *= LookupProfile(ActiveAccelProfile); #endif return limit_value; } @@ -368,7 +368,7 @@ static inline float limit_jerk_by_axis_maximum (float *unit_vec) limit_value = min(limit_value, fabsf(settings.axis[idx].jerk / unit_vec[idx])); } while(idx); #if ENABLE_ACCELERATION_PROFILES - limit_value *= AccelerationProfile(ActiveAccelProfile); + limit_value *= LookupProfileProfile(ActiveAccelProfile); #endif return limit_value; } diff --git a/settings.c b/settings.c index 52e8495..d97798c 100644 --- a/settings.c +++ b/settings.c @@ -896,6 +896,8 @@ bool settings_override_acceleration (uint8_t axis, float acceleration) } #if ENABLE_ACCELERATION_PROFILES +ActiveAccelProfile = 1; // Initialize machine with 100% Profile + //Acceleration Profiles for G187 P[x] in percent of maximum machine acceleration. float LookupProfile(uint8_t Profile) { static const float lookup[5] = { diff --git a/settings.h b/settings.h index 3a40c69..e1d0e00 100644 --- a/settings.h +++ b/settings.h @@ -967,7 +967,7 @@ bool settings_read_coord_data(coord_system_id_t id, float (*coord_data)[N_AXIS]) bool settings_override_acceleration (uint8_t axis, float acceleration); #if ENABLE_ACCELERATION_PROFILES -extern uint8_t ActiveAccelProfile = 1; +extern uint8_t ActiveAccelProfile; float AccelerationProfile (uint8_t Profile); #endif From aa9a0c45797fed824fa0da665ea231777aa31db1 Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Sun, 14 Jan 2024 14:48:39 +0100 Subject: [PATCH 33/47] Fixed typos and brackets --- settings.c | 15 ++++++++++----- settings.h | 2 +- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/settings.c b/settings.c index d97798c..e1a1bbc 100644 --- a/settings.c +++ b/settings.c @@ -1393,11 +1393,13 @@ static const char *set_axis_setting_unit (setting_id_t setting_id, uint_fast8_t case Setting_AxisAcceleration: unit = is_rotary ? "deg/sec^2" : "mm/sec^2"; break; + #if ENABLE_JERK_ACCELERATION case Setting_AxisJerk: unit = is_rotary ? "deg/sec^3" : "mm/sec^3"; break; #endif + case Setting_AxisMaxTravel: case Setting_AxisBacklash: unit = is_rotary ? "deg" : "mm"; @@ -1504,20 +1506,21 @@ static status_code_t set_axis_setting (setting_id_t setting, float value) case Setting_AxisAcceleration: settings.axis[idx].acceleration = override_backup.acceleration[idx] = value * 60.0f * 60.0f; // Convert to mm/min^2 for grbl internal use. -#if ENABLE_JERK_ACCELERATION - settings.axis[idx].jerk = (settings.axis[idx].acceleration * 10.0f * 60.0f); //reset jerk to axis minimum. -#endif break; + #if ENABLE_JERK_ACCELERATION case Setting_AxisJerk: - if ((value * 60.0f * 60.0f) < (settings.axis[idx].acceleration * 10.0f)) //ensuring that the acceleration time is limited to at maximum 100ms (or 10 stepper segments). + if ((value * 60.0f * 60.0f) < (settings.axis[idx].acceleration * 10.0f)) { //ensuring that the acceleration ramp time is limited to at maximum 100ms (or 10 stepper segments). settings.axis[idx].jerk = settings.axis[idx].acceleration * 10.0f * 60.0f; // mm/min^2 -> mm/min^3 - else if ((settings.axis[idx].acceleration / (value * 60.0f * 60.0f * 60.0f)) < (1.0f / ACCELERATION_TICKS_PER_SECOND)) // Limit Jerk if Value is so large that it reverts back to trapezoidal. + } + else if ((settings.axis[idx].acceleration / (value * 60.0f * 60.0f * 60.0f)) < (1.0f / ACCELERATION_TICKS_PER_SECOND)) { // Limit Jerk if value is so large that it reverts back to trapezoidal. settings.axis[idx].jerk = settings.axis[idx].acceleration * ACCELERATION_TICKS_PER_SECOND * 60.0f; // mm/min^2 -> mm/min^3 + } else settings.axis[idx].jerk = value * 60.0f * 60.0f * 60.0f; // Convert to mm/min^3 for grbl internal use. break; #endif + case Setting_AxisMaxTravel: if(settings.axis[idx].max_travel != -value) { bit_false(sys.homed.mask, bit(idx)); @@ -1580,11 +1583,13 @@ static float get_float (setting_id_t setting) case Setting_AxisAcceleration: value = settings.axis[idx].acceleration / (60.0f * 60.0f); // Convert from mm/min^2 to mm/sec^2. break; + #if ENABLE_JERK_ACCELERATION case Setting_AxisJerk: value = settings.axis[idx].jerk / (60.0f * 60.0f * 60.0f); // Convert from mm/min^3 to mm/sec^3. break; #endif + case Setting_AxisMaxTravel: value = -settings.axis[idx].max_travel; // Store as negative for grbl internal use. break; diff --git a/settings.h b/settings.h index e1d0e00..7301ecc 100644 --- a/settings.h +++ b/settings.h @@ -968,7 +968,7 @@ bool settings_override_acceleration (uint8_t axis, float acceleration); #if ENABLE_ACCELERATION_PROFILES extern uint8_t ActiveAccelProfile; -float AccelerationProfile (uint8_t Profile); +float LookupProfile (uint8_t Profile); #endif void settings_register (setting_details_t *details); From c8876e2d92208f66ba972982ca95ab7fd182f462 Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Sun, 14 Jan 2024 14:53:50 +0100 Subject: [PATCH 34/47] fixed limit_jerk_by_axis_maximum --- planner.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/planner.c b/planner.c index 0ade5f7..eec3450 100644 --- a/planner.c +++ b/planner.c @@ -368,7 +368,7 @@ static inline float limit_jerk_by_axis_maximum (float *unit_vec) limit_value = min(limit_value, fabsf(settings.axis[idx].jerk / unit_vec[idx])); } while(idx); #if ENABLE_ACCELERATION_PROFILES - limit_value *= LookupProfileProfile(ActiveAccelProfile); + limit_value *= LookupProfile(ActiveAccelProfile); #endif return limit_value; } From b7d54d75eed8fe76beae5d94066d8339775a45ca Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Thu, 31 Oct 2024 21:22:09 +0100 Subject: [PATCH 35/47] added acceleration profiles to gc_state, adjusted g187 and m2/30 handling accordingly --- gcode.c | 13 +++++++++++-- planner.c | 4 ++-- settings.c | 9 +++------ 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/gcode.c b/gcode.c index 7f6b495..b691687 100644 --- a/gcode.c +++ b/gcode.c @@ -325,6 +325,9 @@ void gc_init (void) #if NGC_PARAMETERS_ENABLE ngc_modal_state_invalidate(); #endif +#if ENABLE_ACCELERATION_PROFILES + gc_state.modal.activeaccelprofile = 1.0f; // Initialize machine with 100% Profile +#endif // if(settings.flags.lathe_mode) // gc_state.modal.plane_select = PlaneSelect_ZX; @@ -2448,13 +2451,16 @@ status_code_t gc_execute_block (char *block) #if ENABLE_ACCELERATION_PROFILES case NonModal_SetAccelerationProfile: - if (!gc_block.values.p){ + if (gc_block.words.e){ + FAIL(Status_GcodeUnsupportedCommand); + break;} + else if (!gc_block.word.p){ gc_block.values.p = 1.0f;} else if (gc_block.values.p < 1.0f){ FAIL(Status_NegativeValue);} else if (gc_block.values.p > 5.0f){ FAIL(Status_GcodeValueOutOfRange);} - ActiveAccelProfile = gc_block.values.p; + gc_state.modal.activeaccelprofile = gc_block.values.p; break; #endif default: @@ -3874,6 +3880,9 @@ status_code_t gc_execute_block (char *block) gc_state.modal.coolant = (coolant_state_t){0}; gc_state.modal.override_ctrl.feed_rate_disable = Off; gc_state.modal.override_ctrl.spindle_rpm_disable = Off; + #if ENABLE_ACCELERATION_PROFILES + gc_state.modal.activeaccelprofile = 1.0f; + #endif idx = N_SYS_SPINDLE; spindle_ptrs_t *spindle; diff --git a/planner.c b/planner.c index ab8372e..0799e7a 100644 --- a/planner.c +++ b/planner.c @@ -349,7 +349,7 @@ static inline float limit_acceleration_by_axis_maximum (float *unit_vec) limit_value = min(limit_value, fabsf(settings.axis[idx].acceleration / unit_vec[idx])); } while(idx); #if ENABLE_ACCELERATION_PROFILES - limit_value *= LookupProfile(ActiveAccelProfile); + limit_value *= lookupprofile(gc_state.modal.activeaccelprofile); #endif return limit_value; } @@ -365,7 +365,7 @@ static inline float limit_jerk_by_axis_maximum (float *unit_vec) limit_value = min(limit_value, fabsf(settings.axis[idx].jerk / unit_vec[idx])); } while(idx); #if ENABLE_ACCELERATION_PROFILES - limit_value *= LookupProfile(ActiveAccelProfile); + limit_value *= lookupprofile(gc_state.modal.activeaccelprofile); #endif return limit_value; } diff --git a/settings.c b/settings.c index ae05b7c..b307888 100644 --- a/settings.c +++ b/settings.c @@ -805,7 +805,7 @@ PROGMEM static const setting_descr_t setting_descr[] = { #if ENABLE_JERK_ACCELERATION { Setting_AxisJerk, "Maximum rate of acceleration change - smoothes out acceleration profile up to max axis acceleration.\\n\\n" "Minimum value of x10 Acceleration setting to ensure decent acceleration times.\\n" - "Maximum is calcualted by current acceleration and stepper segment time.\\n" + "Maximum is calculated by current acceleration and stepper segment time.\\n" "At Maximum value motion is effectively trapezoidal instead of constant jerk.\\n\\n" "Can be increased by adjusting ACCELERATION_TICKS_PER_SECOND to a larger value before compiling."}, #endif @@ -932,10 +932,8 @@ bool settings_override_acceleration (uint8_t axis, float acceleration) } #if ENABLE_ACCELERATION_PROFILES -ActiveAccelProfile = 1; // Initialize machine with 100% Profile - //Acceleration Profiles for G187 P[x] in percent of maximum machine acceleration. -float LookupProfile(uint8_t Profile) { +float lookupprofile(uint8_t profile) { static const float lookup[5] = { 1.0f, // 100% - Roughing - Max Acceleration Default 0.8f, // 80% - Semi Roughing @@ -943,8 +941,7 @@ float LookupProfile(uint8_t Profile) { 0.4f, // 40% - Finish 0.2f, // 20% - Slow AF Mode }; - Profile = lookup[Profile]; - return Profile; + return lookup[profile]; } #endif From 88cf48a5a114cdc2073a13df8ce31e9b8bef0243 Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Thu, 31 Oct 2024 21:36:39 +0100 Subject: [PATCH 36/47] adjusted settings.h to last commit too --- settings.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/settings.h b/settings.h index d353cb9..53edf8b 100644 --- a/settings.h +++ b/settings.h @@ -1072,8 +1072,7 @@ bool settings_read_coord_data(coord_system_id_t id, float (*coord_data)[N_AXIS]) bool settings_override_acceleration (uint8_t axis, float acceleration); #if ENABLE_ACCELERATION_PROFILES -extern uint8_t ActiveAccelProfile; -float LookupProfile (uint8_t Profile); +float lookupprofile (uint8_t profile); #endif void settings_register (setting_details_t *details); From a6ae08ea97a4160c9bc46e0397b2a6d9e3754ba9 Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Tue, 10 Dec 2024 21:10:16 +0100 Subject: [PATCH 37/47] Resolve merge conflict for new setting structure --- settings.c | 3155 +++++++++++++++++++++++++++------------------------- settings.h | 8 +- 2 files changed, 1663 insertions(+), 1500 deletions(-) diff --git a/settings.c b/settings.c index b307888..38a1146 100644 --- a/settings.c +++ b/settings.c @@ -54,7 +54,8 @@ const settings_restore_t settings_all = { PROGMEM const settings_t defaults = { - .version = SETTINGS_VERSION, + .version.id = SETTINGS_VERSION, + .version.build = (GRBL_BUILD - 20000000UL), #if DEFAULT_LASER_MODE .mode = Mode_Laser, @@ -83,10 +84,13 @@ PROGMEM const settings_t defaults = { .flags.force_initialization_alarm = DEFAULT_FORCE_INITIALIZATION_ALARM, .flags.restore_overrides = DEFAULT_RESET_OVERRIDES, .flags.no_restore_position_after_M6 = DEFAULT_TOOLCHANGE_NO_RESTORE_POSITION, + .flags.no_unlock_after_estop = DEFAULT_NO_UNLOCK_AFTER_ESTOP, .probe.disable_probe_pullup = DEFAULT_PROBE_SIGNAL_DISABLE_PULLUP, .probe.allow_feed_override = DEFAULT_ALLOW_FEED_OVERRIDE_DURING_PROBE_CYCLES, .probe.invert_probe_pin = DEFAULT_PROBE_SIGNAL_INVERT, + .probe.invert_toolsetter_input = DEFAULT_TOOLSETTER_SIGNAL_INVERT, + .probe.disable_toolsetter_pullup = DEFAULT_TOOLSETTER_SIGNAL_DISABLE_PULLUP, .steppers.pulse_microseconds = DEFAULT_STEP_PULSE_MICROSECONDS, .steppers.pulse_delay_microseconds = DEFAULT_STEP_PULSE_DELAY, @@ -119,8 +123,6 @@ PROGMEM const settings_t defaults = { .homing.flags.value = 0, #endif .homing.dir_mask.value = DEFAULT_HOMING_DIR_MASK, - .homing.feed_rate = DEFAULT_HOMING_FEED_RATE, - .homing.seek_rate = DEFAULT_HOMING_SEEK_RATE, .homing.debounce_delay = DEFAULT_HOMING_DEBOUNCE_DELAY, .homing.pulloff = DEFAULT_HOMING_PULLOFF, .homing.locate_cycles = DEFAULT_N_HOMING_LOCATE_CYCLE, @@ -146,64 +148,64 @@ PROGMEM const settings_t defaults = { .status_report.run_substate = DEFAULT_REPORT_RUN_SUBSTATE, .status_report.when_homing = DEFAULT_REPORT_WHEN_HOMING, .limits.flags.hard_enabled = DEFAULT_HARD_LIMIT_ENABLE, - .limits.flags.soft_enabled = DEFAULT_SOFT_LIMIT_ENABLE, .limits.flags.jog_soft_limited = DEFAULT_JOG_LIMIT_ENABLE, .limits.flags.check_at_init = DEFAULT_CHECK_LIMITS_AT_INIT, .limits.flags.hard_disabled_rotary = DEFAULT_HARD_LIMITS_DISABLE_FOR_ROTARY, .limits.flags.two_switches = DEFAULT_LIMITS_TWO_SWITCHES_ON_AXES, .limits.invert.mask = DEFAULT_LIMIT_SIGNALS_INVERT_MASK, - .limits.disable_pullup.mask = DEFAULT_LIMIT_SIGNALS_PULLUP_DISABLE_MASK, + .limits.disable_pullup.mask = DEFAULT_LIMIT_SIGNALS_PULLUP_DISABLE_MASK, + .limits.soft_enabled.mask = (DEFAULT_SOFT_LIMIT_ENABLE ? AXES_BITMASK : 0), .control_invert.mask = DEFAULT_CONTROL_SIGNALS_INVERT_MASK, .control_disable_pullup.mask = DEFAULT_DISABLE_CONTROL_PINS_PULL_UP_MASK, - .spindle.rpm_max = DEFAULT_SPINDLE_RPM_MAX, - .spindle.rpm_min = DEFAULT_SPINDLE_RPM_MIN, - .spindle.flags.pwm_disable = false, - .spindle.flags.enable_rpm_controlled = DEFAULT_SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED, - .spindle.invert.on = DEFAULT_INVERT_SPINDLE_ENABLE_PIN, - .spindle.invert.ccw = DEFAULT_INVERT_SPINDLE_CCW_PIN, - .spindle.invert.pwm = DEFAULT_INVERT_SPINDLE_PWM_PIN, - .spindle.pwm_freq = DEFAULT_SPINDLE_PWM_FREQ, - .spindle.pwm_off_value = DEFAULT_SPINDLE_PWM_OFF_VALUE, - .spindle.pwm_min_value = DEFAULT_SPINDLE_PWM_MIN_VALUE, - .spindle.pwm_max_value = DEFAULT_SPINDLE_PWM_MAX_VALUE, - .spindle.at_speed_tolerance = DEFAULT_SPINDLE_AT_SPEED_TOLERANCE, + .spindle.ref_id = DEFAULT_SPINDLE, + .spindle.encoder_spindle = DEFAULT_SPINDLE, .spindle.ppr = DEFAULT_SPINDLE_PPR, - .spindle.pid.p_gain = DEFAULT_SPINDLE_P_GAIN, - .spindle.pid.i_gain = DEFAULT_SPINDLE_I_GAIN, - .spindle.pid.d_gain = DEFAULT_SPINDLE_D_GAIN, - .spindle.pid.i_max_error = DEFAULT_SPINDLE_I_MAX, + + .pwm_spindle.rpm_max = DEFAULT_SPINDLE_RPM_MAX, + .pwm_spindle.rpm_min = DEFAULT_SPINDLE_RPM_MIN, + .pwm_spindle.flags.pwm_disable = false, + .pwm_spindle.flags.enable_rpm_controlled = DEFAULT_SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED, + .pwm_spindle.flags.laser_mode_disable = DEFAULT_PWM_SPINDLE_DISABLE_LASER_MODE, + .pwm_spindle.invert.on = DEFAULT_INVERT_SPINDLE_ENABLE_PIN, + .pwm_spindle.invert.ccw = DEFAULT_INVERT_SPINDLE_CCW_PIN, + .pwm_spindle.invert.pwm = DEFAULT_INVERT_SPINDLE_PWM_PIN, + .pwm_spindle.pwm_freq = DEFAULT_SPINDLE_PWM_FREQ, + .pwm_spindle.pwm_off_value = DEFAULT_SPINDLE_PWM_OFF_VALUE, + .pwm_spindle.pwm_min_value = DEFAULT_SPINDLE_PWM_MIN_VALUE, + .pwm_spindle.pwm_max_value = DEFAULT_SPINDLE_PWM_MAX_VALUE, + .pwm_spindle.at_speed_tolerance = DEFAULT_SPINDLE_AT_SPEED_TOLERANCE, #if ENABLE_SPINDLE_LINEARIZATION #if SPINDLE_NPWM_PIECES > 0 - .spindle.pwm_piece[0] = { .rpm = DEFAULT_RPM_POINT01, .start = DEFAULT_RPM_LINE_A1, .end = DEFAULT_RPM_LINE_B1 }, + .pwm_spindle.pwm_piece[0] = { .rpm = DEFAULT_RPM_POINT01, .start = DEFAULT_RPM_LINE_A1, .end = DEFAULT_RPM_LINE_B1 }, #endif #if SPINDLE_NPWM_PIECES > 1 - .spindle.pwm_piece[1] = { .rpm = DEFAULT_RPM_POINT12, .start = DEFAULT_RPM_LINE_A2, .end = DEFAULT_RPM_LINE_B2 }, + .pwm_spindle.pwm_piece[1] = { .rpm = DEFAULT_RPM_POINT12, .start = DEFAULT_RPM_LINE_A2, .end = DEFAULT_RPM_LINE_B2 }, #endif #if SPINDLE_NPWM_PIECES > 2 - .spindle.pwm_piece[2] = { .rpm = DEFAULT_RPM_POINT23, .start = DEFAULT_RPM_LINE_A3, .end = DEFAULT_RPM_LINE_B3 }, + .pwm_spindle.pwm_piece[2] = { .rpm = DEFAULT_RPM_POINT23, .start = DEFAULT_RPM_LINE_A3, .end = DEFAULT_RPM_LINE_B3 }, #endif #if SPINDLE_NPWM_PIECES > 3 - .spindle.pwm_piece[3] = { .rpm = DEFAULT_RPM_POINT34, .start = DEFAULT_RPM_LINE_A4, .end = DEFAULT_RPM_LINE_B4 }, + .pwm_spindle.pwm_piece[3] = { .rpm = DEFAULT_RPM_POINT34, .start = DEFAULT_RPM_LINE_A4, .end = DEFAULT_RPM_LINE_B4 }, #endif #else #if SPINDLE_NPWM_PIECES > 0 - .spindle.pwm_piece[0] = { .rpm = NAN, .start = 0.0f, .end = 0.0f }, + .pwm_spindle.pwm_piece[0] = { .rpm = NAN, .start = 0.0f, .end = 0.0f }, #endif #if SPINDLE_NPWM_PIECES > 1 - .spindle.pwm_piece[1] = { .rpm = NAN, .start = 0.0f, .end = 0.0f }, + .pwm_spindle.pwm_piece[1] = { .rpm = NAN, .start = 0.0f, .end = 0.0f }, #endif #if SPINDLE_NPWM_PIECES > 2 - .spindle.pwm_piece[2] = { .rpm = NAN, .start = 0.0f, .end = 0.0f }, + .pwm_spindle.pwm_piece[2] = { .rpm = NAN, .start = 0.0f, .end = 0.0f }, #endif #if SPINDLE_NPWM_PIECES > 3 - .spindle.pwm_piece[3] = { .rpm = NAN, .start = 0.0f, .end = 0.0f }, + .pwm_spindle.pwm_piece[3] = { .rpm = NAN, .start = 0.0f, .end = 0.0f }, #endif #endif - .coolant_invert.flood = DEFAULT_INVERT_COOLANT_FLOOD_PIN, - .coolant_invert.mist = DEFAULT_INVERT_COOLANT_MIST_PIN, + .coolant.invert.flood = DEFAULT_INVERT_COOLANT_FLOOD_PIN, + .coolant.invert.mist = DEFAULT_INVERT_COOLANT_MIST_PIN, .axis[X_AXIS].steps_per_mm = DEFAULT_X_STEPS_PER_MM, .axis[X_AXIS].max_rate = DEFAULT_X_MAX_RATE, @@ -213,6 +215,8 @@ PROGMEM const settings_t defaults = { #endif .axis[X_AXIS].max_travel = (-DEFAULT_X_MAX_TRAVEL), .axis[X_AXIS].dual_axis_offset = 0.0f, + .axis[X_AXIS].homing_feed_rate = DEFAULT_HOMING_FEED_RATE, + .axis[X_AXIS].homing_seek_rate = DEFAULT_HOMING_SEEK_RATE, #if ENABLE_BACKLASH_COMPENSATION .axis[X_AXIS].backlash = 0.0f, #endif @@ -225,7 +229,9 @@ PROGMEM const settings_t defaults = { .axis[Y_AXIS].jerk = (DEFAULT_Y_JERK * 60.0f * 60.0f * 60.0f), #endif .axis[Y_AXIS].dual_axis_offset = 0.0f, -#if ENABLE_BACKLASH_COMPENSATION + .axis[Y_AXIS].homing_feed_rate = DEFAULT_HOMING_FEED_RATE, + .axis[Y_AXIS].homing_seek_rate = DEFAULT_HOMING_SEEK_RATE, + #if ENABLE_BACKLASH_COMPENSATION .axis[Y_AXIS].backlash = 0.0f, #endif @@ -237,6 +243,8 @@ PROGMEM const settings_t defaults = { #endif .axis[Z_AXIS].max_travel = (-DEFAULT_Z_MAX_TRAVEL), .axis[Z_AXIS].dual_axis_offset = 0.0f, + .axis[Z_AXIS].homing_feed_rate = DEFAULT_HOMING_FEED_RATE, + .axis[Z_AXIS].homing_seek_rate = DEFAULT_HOMING_SEEK_RATE, #if ENABLE_BACKLASH_COMPENSATION .axis[Z_AXIS].backlash = 0.0f, #endif @@ -250,6 +258,8 @@ PROGMEM const settings_t defaults = { #endif .axis[A_AXIS].max_travel = (-DEFAULT_A_MAX_TRAVEL), .axis[A_AXIS].dual_axis_offset = 0.0f, + .axis[A_AXIS].homing_feed_rate = DEFAULT_HOMING_FEED_RATE, + .axis[A_AXIS].homing_seek_rate = DEFAULT_HOMING_SEEK_RATE, #if ENABLE_BACKLASH_COMPENSATION .axis[A_AXIS].backlash = 0.0f, #endif @@ -265,6 +275,8 @@ PROGMEM const settings_t defaults = { #endif .axis[B_AXIS].max_travel = (-DEFAULT_B_MAX_TRAVEL), .axis[B_AXIS].dual_axis_offset = 0.0f, + .axis[B_AXIS].homing_feed_rate = DEFAULT_HOMING_FEED_RATE, + .axis[B_AXIS].homing_seek_rate = DEFAULT_HOMING_SEEK_RATE, #if ENABLE_BACKLASH_COMPENSATION .axis[B_AXIS].backlash = 0.0f, #endif @@ -280,6 +292,8 @@ PROGMEM const settings_t defaults = { .axis[C_AXIS].max_rate = DEFAULT_C_MAX_RATE, .axis[C_AXIS].max_travel = (-DEFAULT_C_MAX_TRAVEL), .axis[C_AXIS].dual_axis_offset = 0.0f, + .axis[C_AXIS].homing_feed_rate = DEFAULT_HOMING_FEED_RATE, + .axis[C_AXIS].homing_seek_rate = DEFAULT_HOMING_SEEK_RATE, #if ENABLE_BACKLASH_COMPENSATION .axis[C_AXIS].backlash = 0.0f, #endif @@ -295,6 +309,8 @@ PROGMEM const settings_t defaults = { .axis[U_AXIS].max_rate = DEFAULT_U_MAX_RATE, .axis[U_AXIS].max_travel = (-DEFAULT_U_MAX_TRAVEL), .axis[U_AXIS].dual_axis_offset = 0.0f, + .axis[U_AXIS].homing_feed_rate = DEFAULT_HOMING_FEED_RATE, + .axis[U_AXIS].homing_seek_rate = DEFAULT_HOMING_SEEK_RATE, #if ENABLE_BACKLASH_COMPENSATION .axis[U_AXIS].backlash = 0.0f, #endif @@ -309,6 +325,8 @@ PROGMEM const settings_t defaults = { .axis[V_AXIS].max_rate = DEFAULT_V_MAX_RATE, .axis[V_AXIS].max_travel = (-DEFAULT_V_MAX_TRAVEL), .axis[V_AXIS].dual_axis_offset = 0.0f, + .axis[V_AXIS].homing_feed_rate = DEFAULT_HOMING_FEED_RATE, + .axis[V_AXIS].homing_seek_rate = DEFAULT_HOMING_SEEK_RATE, #if ENABLE_BACKLASH_COMPENSATION .axis[V_AXIS].backlash = 0.0f, #endif @@ -334,8 +352,8 @@ PROGMEM const settings_t defaults = { .safety_door.spindle_on_delay = DEFAULT_SAFETY_DOOR_SPINDLE_DELAY, .safety_door.coolant_on_delay = DEFAULT_SAFETY_DOOR_COOLANT_DELAY, - .rgb_strip0_length = DEFAULT_RGB_STRIP0_LENGTH, - .rgb_strip1_length = DEFAULT_RGB_STRIP1_LENGTH + .rgb_strip.length0 = DEFAULT_RGB_STRIP0_LENGTH, + .rgb_strip.length1 = DEFAULT_RGB_STRIP1_LENGTH }; static bool group_is_available (const setting_group_detail_t *group) @@ -392,73 +410,9 @@ PROGMEM static const setting_group_detail_t setting_group_detail [] = { #endif }; -static status_code_t set_probe_invert (setting_id_t id, uint_fast16_t int_value); -static status_code_t set_report_mask (setting_id_t id, uint_fast16_t int_value); -static status_code_t set_report_inches (setting_id_t id, uint_fast16_t int_value); -static status_code_t set_control_invert (setting_id_t id, uint_fast16_t int_value); -static status_code_t set_spindle_invert (setting_id_t id, uint_fast16_t int_value); -static status_code_t set_pwm_mode (setting_id_t id, uint_fast16_t int_value); -static status_code_t set_pwm_options (setting_id_t id, uint_fast16_t int_value); -static status_code_t set_spindle_type (setting_id_t id, uint_fast16_t int_value); -static status_code_t set_encoder_spindle (setting_id_t id, uint_fast16_t int_value); -static status_code_t set_control_disable_pullup (setting_id_t id, uint_fast16_t int_value); -static status_code_t set_probe_disable_pullup (setting_id_t id, uint_fast16_t int_value); -static status_code_t set_soft_limits_enable (setting_id_t id, uint_fast16_t int_value); -static status_code_t set_hard_limits_enable (setting_id_t id, uint_fast16_t int_value); -static status_code_t set_jog_soft_limited (setting_id_t id, uint_fast16_t int_value); -static status_code_t set_homing_enable (setting_id_t id, uint_fast16_t int_value); -static status_code_t set_enable_legacy_rt_commands (setting_id_t id, uint_fast16_t int_value); -static status_code_t set_homing_cycle (setting_id_t id, uint_fast16_t int_value); -#if !LATHE_UVW_OPTION -static status_code_t set_mode (setting_id_t id, uint_fast16_t int_value); -#endif -static status_code_t set_sleep_enable (setting_id_t id, uint_fast16_t int_value); -static status_code_t set_hold_actions (setting_id_t id, uint_fast16_t int_value); -static status_code_t set_force_initialization_alarm (setting_id_t id, uint_fast16_t int_value); -static status_code_t set_probe_allow_feed_override (setting_id_t id, uint_fast16_t int_value); -static status_code_t set_tool_change_mode (setting_id_t id, uint_fast16_t int_value); -static status_code_t set_tool_change_probing_distance (setting_id_t id, float value); -static status_code_t set_tool_restore_pos (setting_id_t id, uint_fast16_t int_value); -static status_code_t set_ganged_dir_invert (setting_id_t id, uint_fast16_t int_value); -static status_code_t set_stepper_energize_mask (setting_id_t id, uint_fast16_t int_value); -static status_code_t set_report_interval (setting_id_t setting, uint_fast16_t int_value); -static status_code_t set_estop_unlock (setting_id_t id, uint_fast16_t int_value); -#if COMPATIBILITY_LEVEL <= 1 -static status_code_t set_offset_lock (setting_id_t id, uint_fast16_t int_value); -#endif -#ifndef NO_SAFETY_DOOR_SUPPORT -static status_code_t set_parking_enable (setting_id_t id, uint_fast16_t int_value); -static status_code_t set_restore_overrides (setting_id_t id, uint_fast16_t int_value); -#endif -#if ENABLE_SPINDLE_LINEARIZATION -static status_code_t set_linear_piece (setting_id_t id, char *svalue); -static char *get_linear_piece (setting_id_t id); -#endif -#if N_AXIS > 3 -static status_code_t set_rotary_axes (setting_id_t id, uint_fast16_t int_value); -static status_code_t set_rotary_wrap_axes (setting_id_t id, uint_fast16_t int_value); -#endif -#if COMPATIBILITY_LEVEL > 2 -static status_code_t set_enable_invert_mask (setting_id_t id, uint_fast16_t int_value); -#endif -#if COMPATIBILITY_LEVEL > 1 -static status_code_t set_limits_invert_mask (setting_id_t id, uint_fast16_t int_value); -#endif -static status_code_t set_axis_setting (setting_id_t setting, float value); -#if COMPATIBILITY_LEVEL <= 1 -static status_code_t set_g92_disable_persistence (setting_id_t id, uint_fast16_t int_value); -#endif -static float get_float (setting_id_t setting); -static uint32_t get_int (setting_id_t id); -static bool is_setting_available (const setting_detail_t *setting); -static bool is_group_available (const setting_detail_t *setting); -#if NGC_EXPRESSIONS_ENABLE -static status_code_t set_ngc_debug_out (setting_id_t id, uint_fast16_t int_value); -#endif - static bool machine_mode_changed = false; #if COMPATIBILITY_LEVEL <= 1 -static char homing_options[] = "Enable,Enable single axis commands,Homing on startup required,Set machine origin to 0,Two switches shares one input pin,Allow manual,Override locks,Keep homed status on reset,Use limit switches"; +static char homing_options[] = "Enable,Enable single axis commands,Homing on startup required,Set machine origin to 0,Two switches shares one input,Allow manual,Override locks,Keep homed status on reset,Use limit switches,Per axis feedrates"; #endif static char control_signals[] = "Reset,Feed hold,Cycle start,Safety door,Block delete,Optional stop,EStop,Probe connected,Motor fault,Motor warning,Limits override,Single step blocks"; static char spindle_signals[] = "Spindle enable,Spindle direction,PWM"; @@ -501,1678 +455,1890 @@ static char axis_steps[9] = "step/mm"; #endif #define AXIS_OPTS { .subgroups = On, .increment = 1 } -PROGMEM static const setting_detail_t setting_detail[] = { - { Setting_PulseMicroseconds, Group_Stepper, "Step pulse time", "microseconds", Format_Decimal, "#0.0", "2.0", NULL, Setting_IsLegacy, &settings.steppers.pulse_microseconds, NULL, NULL }, - { Setting_StepperIdleLockTime, Group_Stepper, "Step idle delay", "milliseconds", Format_Int16, "####0", NULL, "65535", Setting_IsLegacy, &settings.steppers.idle_lock_time, NULL, NULL }, - { Setting_StepInvertMask, Group_Stepper, "Step pulse invert", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsLegacy, &settings.steppers.step_invert.mask, NULL, NULL }, - { Setting_DirInvertMask, Group_Stepper, "Step direction invert", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsLegacy, &settings.steppers.dir_invert.mask, NULL, NULL }, -#if COMPATIBILITY_LEVEL <= 2 - { Setting_InvertStepperEnable, Group_Stepper, "Invert stepper enable pin(s)", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsLegacy, &settings.steppers.enable_invert.mask, NULL, NULL }, -#else - { Setting_InvertStepperEnable, Group_Stepper, "Invert stepper enable pins", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsLegacyFn, set_enable_invert_mask, get_int, NULL }, -#endif -#if COMPATIBILITY_LEVEL <= 1 - { Setting_LimitPinsInvertMask, Group_Limits, "Invert limit pins", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsLegacy, &settings.limits.invert.mask, NULL, NULL }, -#else - { Setting_LimitPinsInvertMask, Group_Limits, "Invert limit pins", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsLegacyFn, set_limits_invert_mask, get_int, NULL }, +// Acceleration override + +static struct { + bool valid; + float acceleration[N_AXIS]; +} override_backup = { .valid = false }; + +static void save_override_backup (void) +{ + uint_fast8_t idx = N_AXIS; + + do { + idx--; + override_backup.acceleration[idx] = settings.axis[idx].acceleration; + } while(idx); + + override_backup.valid = true; +} + +static void restore_override_backup (void) +{ + uint_fast8_t idx = N_AXIS; + + if(override_backup.valid) do { + idx--; + settings.axis[idx].acceleration = override_backup.acceleration[idx]; + } while(idx); +} + +// Temporarily override acceleration, if 0 restore to setting value. +// Note: only allowed when current state is idle. +bool settings_override_acceleration (uint8_t axis, float acceleration) +{ + sys_state_t state = state_get(); + + if(!(state == STATE_IDLE || (state & (STATE_HOMING|STATE_ALARM)))) + return false; + + if(acceleration <= 0.0f) { + if(override_backup.valid) + settings.axis[axis].acceleration = override_backup.acceleration[axis]; + } else { + if(!override_backup.valid) + save_override_backup(); + settings.axis[axis].acceleration = (override_backup.acceleration[axis] >= (acceleration * 60.0f * 60.0f)) ? (acceleration * 60.0f * 60.0f) : override_backup.acceleration[axis]; // Limited to max setting value + } + + return true; +} + +#if ENABLE_ACCELERATION_PROFILES +//Acceleration Profiles for G187 P[x] in percent of maximum machine acceleration. +float lookupprofile(uint8_t profile) { + static const float lookup[5] = { + 1.0f, // 100% - Roughing - Max Acceleration Default + 0.8f, // 80% - Semi Roughing + 0.6f, // 60% - Semi Finish + 0.4f, // 40% - Finish + 0.2f, // 20% - Slow AF Mode + }; + return lookup[profile]; +} #endif - { Setting_InvertProbePin, Group_Probing, "Invert probe pin", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsLegacyFn, set_probe_invert, get_int, is_setting_available }, - { Setting_SpindlePWMBehaviour, Group_Spindle, "Deprecated", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsLegacyFn, set_pwm_mode, get_int, is_setting_available }, - { Setting_GangedDirInvertMask, Group_Stepper, "Ganged axes direction invert", NULL, Format_Bitfield, ganged_axes, NULL, NULL, Setting_IsExtendedFn, set_ganged_dir_invert, get_int, is_setting_available }, - { Setting_SpindlePWMOptions, Group_Spindle, "PWM Spindle", NULL, Format_XBitfield, "Enable,RPM controls spindle enable signal,Disable laser mode capability", NULL, NULL, Setting_IsExtendedFn, set_pwm_options, get_int, is_setting_available }, -#if COMPATIBILITY_LEVEL <= 1 - { Setting_StatusReportMask, Group_General, "Status report options", NULL, Format_Bitfield, "Position in machine coordinate,Buffer state,Line numbers,Feed & speed,Pin state,Work coordinate offset,Overrides,Probe coordinates,Buffer sync on WCO change,Parser state,Alarm substatus,Run substatus,Enable when homing", NULL, NULL, Setting_IsExtendedFn, set_report_mask, get_int, NULL }, -#else - { Setting_StatusReportMask, Group_General, "Status report options", NULL, Format_Bitfield, "Position in machine coordinate,Buffer state", NULL, NULL, Setting_IsLegacyFn, set_report_mask, get_int, NULL }, + +// --- + +static void homing_pulloff_init (float pulloff) +{ + coord_data_t distance; + uint_fast8_t idx = N_AXIS; + + do { + distance.values[--idx] = pulloff; + } while(idx); + + limits_homing_pulloff(&distance); +} + +#if COMPATIBILITY_LEVEL > 2 + +static status_code_t set_enable_invert_mask (setting_id_t id, uint_fast16_t int_value) +{ + settings.steppers.enable_invert.mask = int_value ? 0 : AXES_BITMASK; + + return Status_OK; +} + #endif - { Setting_JunctionDeviation, Group_General, "Junction deviation", "mm", Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacy, &settings.junction_deviation, NULL, NULL }, - { Setting_ArcTolerance, Group_General, "Arc tolerance", "mm", Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacy, &settings.arc_tolerance, NULL, NULL }, - { Setting_ReportInches, Group_General, "Report in inches", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsLegacyFn, set_report_inches, get_int, NULL }, - { Setting_ControlInvertMask, Group_ControlSignals, "Invert control pins", NULL, Format_Bitfield, control_signals, NULL, NULL, Setting_IsExpandedFn, set_control_invert, get_int, NULL }, - { Setting_CoolantInvertMask, Group_Coolant, "Invert coolant pins", NULL, Format_Bitfield, coolant_signals, NULL, NULL, Setting_IsExtended, &settings.coolant_invert.mask, NULL, NULL }, - { Setting_SpindleInvertMask, Group_Spindle, "Invert spindle signals", NULL, Format_Bitfield, spindle_signals, NULL, NULL, Setting_IsExtendedFn, set_spindle_invert, get_int, is_setting_available, { .reboot_required = On } }, - { Setting_ControlPullUpDisableMask, Group_ControlSignals, "Pullup disable control pins", NULL, Format_Bitfield, control_signals, NULL, NULL, Setting_IsExtendedFn, set_control_disable_pullup, get_int, NULL }, - { Setting_LimitPullUpDisableMask, Group_Limits, "Pullup disable limit pins", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtended, &settings.limits.disable_pullup.mask, NULL, NULL }, - { Setting_ProbePullUpDisable, Group_Probing, "Pullup disable probe pin", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_probe_disable_pullup, get_int, is_setting_available }, - { Setting_SoftLimitsEnable, Group_Limits, "Soft limits enable", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsLegacyFn, set_soft_limits_enable, get_int, NULL }, -#if COMPATIBILITY_LEVEL <= 1 - #if N_AXIS > 3 - { Setting_HardLimitsEnable, Group_Limits, "Hard limits enable", NULL, Format_XBitfield, "Enable,Strict mode,Disable for rotary axes", NULL, NULL, Setting_IsExpandedFn, set_hard_limits_enable, get_int, NULL }, - #else - { Setting_HardLimitsEnable, Group_Limits, "Hard limits enable", NULL, Format_XBitfield, "Enable,Strict mode", NULL, NULL, Setting_IsExpandedFn, set_hard_limits_enable, get_int, NULL }, - #endif -#else - { Setting_HardLimitsEnable, Group_Limits, "Hard limits enable", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsLegacyFn, set_hard_limits_enable, get_int, NULL }, + +#if COMPATIBILITY_LEVEL > 1 + +static status_code_t set_limits_invert_mask (setting_id_t id, uint_fast16_t int_value) +{ + settings.limits.invert.mask = (int_value ? ~(DEFAULT_LIMIT_SIGNALS_INVERT_MASK) : DEFAULT_LIMIT_SIGNALS_INVERT_MASK) & AXES_BITMASK; + + return Status_OK; +} + #endif + +static status_code_t set_probe_invert (setting_id_t id, uint_fast16_t int_value) +{ + if(!hal.probe.configure) + return Status_SettingDisabled; + + settings.probe.invert_probe_pin = (int_value & 0b01); + + if(hal.driver_cap.toolsetter) + settings.probe.invert_toolsetter_input = !!(int_value & 0b10); + + ioport_setting_changed(id); + + hal.probe.configure(false, false); + + return Status_OK; +} + +static status_code_t set_ganged_dir_invert (setting_id_t id, uint_fast16_t int_value) +{ + if(!hal.stepper.get_ganged) + return Status_SettingDisabled; + + settings.steppers.ganged_dir_invert.mask = int_value & hal.stepper.get_ganged(false).mask; + + return Status_OK; +} + +static status_code_t set_stepper_energize_mask (setting_id_t id, uint_fast16_t int_value) +{ + settings.steppers.energize.mask = int_value; + + hal.stepper.enable(settings.steppers.energize, true); + + return Status_OK; +} + +static status_code_t set_report_interval (setting_id_t setting, uint_fast16_t int_value) +{ + if((settings.report_interval = int_value) == 0) + sys.flags.auto_reporting = Off; + + return Status_OK; +} + +static status_code_t set_report_mask (setting_id_t id, uint_fast16_t int_value) +{ #if COMPATIBILITY_LEVEL <= 1 - { Setting_HomingEnable, Group_Homing, "Homing cycle", NULL, Format_XBitfield, homing_options, NULL, NULL, Setting_IsExpandedFn, set_homing_enable, get_int, NULL }, + settings.status_report.mask = int_value; #else - { Setting_HomingEnable, Group_Homing, "Homing cycle enable", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsLegacyFn, set_homing_enable, get_int, NULL }, -#endif - { Setting_HomingDirMask, Group_Homing, "Homing direction invert", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsLegacy, &settings.homing.dir_mask.value, NULL, NULL }, - { Setting_HomingFeedRate, Group_Homing, "Homing locate feed rate", "mm/min", Format_Decimal, "#####0.0", NULL, NULL, Setting_IsLegacy, &settings.homing.feed_rate, NULL, NULL }, - { Setting_HomingSeekRate, Group_Homing, "Homing search seek rate", "mm/min", Format_Decimal, "#####0.0", NULL, NULL, Setting_IsLegacy, &settings.homing.seek_rate, NULL, NULL }, - { Setting_HomingDebounceDelay, Group_Homing, "Homing switch debounce delay", "milliseconds", Format_Int16, "##0", NULL, NULL, Setting_IsLegacy, &settings.homing.debounce_delay, NULL, NULL }, - { Setting_HomingPulloff, Group_Homing, "Homing switch pull-off distance", "mm", Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacy, &settings.homing.pulloff, NULL, NULL }, - { Setting_G73Retract, Group_General, "G73 Retract distance", "mm", Format_Decimal, "#####0.000", NULL, NULL, Setting_IsExtended, &settings.g73_retract, NULL, NULL }, - { Setting_PulseDelayMicroseconds, Group_Stepper, "Pulse delay", "microseconds", Format_Decimal, "#0.0", NULL, "10", Setting_IsExtended, &settings.steppers.pulse_delay_microseconds, NULL, NULL }, - { Setting_RpmMax, Group_Spindle, "Maximum spindle speed", "RPM", Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacy, &settings.spindle.rpm_max, NULL, is_setting_available }, - { Setting_RpmMin, Group_Spindle, "Minimum spindle speed", "RPM", Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacy, &settings.spindle.rpm_min, NULL, is_setting_available }, -#if !LATHE_UVW_OPTION - { Setting_Mode, Group_General, "Mode of operation", NULL, Format_RadioButtons, "Normal,Laser mode,Lathe mode", NULL, NULL, Setting_IsLegacyFn, set_mode, get_int, NULL }, -#endif - { Setting_PWMFreq, Group_Spindle, "Spindle PWM frequency", "Hz", Format_Decimal, "#####0", NULL, NULL, Setting_IsExtended, &settings.spindle.pwm_freq, NULL, is_setting_available }, - { Setting_PWMOffValue, Group_Spindle, "Spindle PWM off value", "percent", Format_Decimal, "##0.0", NULL, "100", Setting_IsExtended, &settings.spindle.pwm_off_value, NULL, is_setting_available }, - { Setting_PWMMinValue, Group_Spindle, "Spindle PWM min value", "percent", Format_Decimal, "##0.0", NULL, "100", Setting_IsExtended, &settings.spindle.pwm_min_value, NULL, is_setting_available }, - { Setting_PWMMaxValue, Group_Spindle, "Spindle PWM max value", "percent", Format_Decimal, "##0.0", NULL, "100", Setting_IsExtended, &settings.spindle.pwm_max_value, NULL, is_setting_available }, - { Setting_SteppersEnergize, Group_Stepper, "Steppers to keep enabled", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_stepper_energize_mask, get_int, NULL }, - { Setting_SpindlePPR, Group_Spindle, "Spindle pulses per revolution (PPR)", NULL, Format_Int16, "###0", NULL, NULL, Setting_IsExtended, &settings.spindle.ppr, NULL, is_setting_available, { .reboot_required = On } }, - { Setting_EnableLegacyRTCommands, Group_General, "Enable legacy RT commands", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_enable_legacy_rt_commands, get_int, NULL }, - { Setting_JogSoftLimited, Group_Jogging, "Limit jog commands", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_jog_soft_limited, get_int, NULL }, -#ifndef NO_SAFETY_DOOR_SUPPORT - { Setting_ParkingEnable, Group_SafetyDoor, "Parking cycle", NULL, Format_XBitfield, "Enable,Enable parking override control,Deactivate upon init", NULL, NULL, Setting_IsExtendedFn, set_parking_enable, get_int, is_setting_available }, - { Setting_ParkingAxis, Group_SafetyDoor, "Parking axis", NULL, Format_RadioButtons, "X,Y,Z", NULL, NULL, Setting_IsExtended, &settings.parking.axis, NULL, is_setting_available }, -#endif - { Setting_HomingLocateCycles, Group_Homing, "Homing passes", NULL, Format_Int8, "##0", "1", "128", Setting_IsExtended, &settings.homing.locate_cycles, NULL, NULL }, - { Setting_HomingCycle_1, Group_Homing, "Axes homing, first pass", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_homing_cycle, get_int, NULL }, - { Setting_HomingCycle_2, Group_Homing, "Axes homing, second pass", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_homing_cycle, get_int, NULL }, - { Setting_HomingCycle_3, Group_Homing, "Axes homing, third pass", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_homing_cycle, get_int, NULL }, -#ifdef A_AXIS - { Setting_HomingCycle_4, Group_Homing, "Axes homing, fourth pass", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_homing_cycle, get_int, NULL }, -#endif -#ifdef B_AXIS - { Setting_HomingCycle_5, Group_Homing, "Axes homing, fifth pass", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_homing_cycle, get_int, NULL }, -#endif -#ifdef C_AXIS - { Setting_HomingCycle_6, Group_Homing, "Axes homing, sixth pass", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_homing_cycle, get_int, NULL }, + int_value &= 0b11; + settings.status_report.mask = (settings.status_report.mask & ~0b11) | int_value; #endif -#ifndef NO_SAFETY_DOOR_SUPPORT - { Setting_ParkingPulloutIncrement, Group_SafetyDoor, "Parking pull-out distance", "mm", Format_Decimal, "###0.0", NULL, NULL, Setting_IsExtended, &settings.parking.pullout_increment, NULL, is_setting_available }, - { Setting_ParkingPulloutRate, Group_SafetyDoor, "Parking pull-out rate", "mm/min", Format_Decimal, "###0.0", NULL, NULL, Setting_IsExtended, &settings.parking.pullout_rate, NULL, is_setting_available }, - { Setting_ParkingTarget, Group_SafetyDoor, "Parking target", "mm", Format_Decimal, "-###0.0", "-100000", NULL, Setting_IsExtended, &settings.parking.target, NULL, is_setting_available }, - { Setting_ParkingFastRate, Group_SafetyDoor, "Parking fast rate", "mm/min", Format_Decimal, "###0.0", NULL, NULL, Setting_IsExtended, &settings.parking.rate, NULL, is_setting_available }, - { Setting_RestoreOverrides, Group_General, "Restore overrides", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_restore_overrides, get_int, is_setting_available }, - { Setting_DoorOptions, Group_SafetyDoor, "Safety door options", NULL, Format_Bitfield, "Ignore when idle,Keep coolant state on open", NULL, NULL, Setting_IsExtended, &settings.safety_door.flags.value, NULL, is_setting_available }, + + return Status_OK; +} + +static status_code_t set_report_inches (setting_id_t id, uint_fast16_t int_value) +{ + settings.flags.report_inches = int_value != 0; + report_init(); + system_flag_wco_change(); // Make sure WCO is immediately updated. + + return Status_OK; +} + +#if NGC_EXPRESSIONS_ENABLE + +static status_code_t set_ngc_debug_out (setting_id_t id, uint_fast16_t int_value) +{ + settings.flags.ngc_debug_out = int_value != 0; + report_init(); + system_flag_wco_change(); // Make sure WCO is immediately updated. + + return Status_OK; +} + #endif - { Setting_SleepEnable, Group_General, "Sleep enable", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_sleep_enable, get_int, is_setting_available }, - { Setting_HoldActions, Group_General, "Feed hold actions", NULL, Format_Bitfield, "Disable laser during hold,Restore spindle and coolant state on resume", NULL, NULL, Setting_IsExtendedFn, set_hold_actions, get_int, NULL }, - { Setting_ForceInitAlarm, Group_General, "Force init alarm", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_force_initialization_alarm, get_int, NULL }, - { Setting_ProbingFeedOverride, Group_Probing, "Probing feed override", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_probe_allow_feed_override, get_int, is_setting_available }, -#if ENABLE_SPINDLE_LINEARIZATION - { Setting_LinearSpindlePiece1, Group_Spindle, "Spindle linearisation, 1st point", NULL, Format_String, "x(39)", NULL, "39", Setting_IsExtendedFn, set_linear_piece, get_linear_piece, NULL }, - #if SPINDLE_NPWM_PIECES > 1 - { Setting_LinearSpindlePiece2, Group_Spindle, "Spindle linearisation, 2nd point", NULL, Format_String, "x(39)", NULL, "39", Setting_IsExtendedFn, set_linear_piece, get_linear_piece, NULL }, - #endif - #if SPINDLE_NPWM_PIECES > 2 - { Setting_LinearSpindlePiece3, Group_Spindle, "Spindle linearisation, 3rd point", NULL, Format_String, "x(39)", NULL, "39", Setting_IsExtendedFn, set_linear_piece, get_linear_piece, NULL }, - #endif - #if SPINDLE_NPWM_PIECES > 3 - { Setting_LinearSpindlePiece4, Group_Spindle, "Spindle linearisation, 4th point", NULL, Format_String, "x(39)", NULL, "39", Setting_IsExtendedFn, set_linear_piece, get_linear_piece, NULL }, - #endif -#endif - { Setting_SpindlePGain, Group_Spindle_ClosedLoop, "Spindle P-gain", NULL, Format_Decimal, "###0.000", NULL, NULL, Setting_IsExtended, &settings.spindle.pid.p_gain, NULL, is_group_available }, - { Setting_SpindleIGain, Group_Spindle_ClosedLoop, "Spindle I-gain", NULL, Format_Decimal, "###0.000", NULL, NULL, Setting_IsExtended, &settings.spindle.pid.i_gain, NULL, is_group_available }, - { Setting_SpindleDGain, Group_Spindle_ClosedLoop, "Spindle D-gain", NULL, Format_Decimal, "###0.000", NULL, NULL, Setting_IsExtended, &settings.spindle.pid.d_gain, NULL, is_group_available }, - { Setting_SpindleMaxError, Group_Spindle_ClosedLoop, "Spindle PID max error", NULL, Format_Decimal, "###0.000", NULL, NULL, Setting_IsExtended, &settings.spindle.pid.max_error, NULL, is_group_available }, - { Setting_SpindleIMaxError, Group_Spindle_ClosedLoop, "Spindle PID max I error", NULL, Format_Decimal, "###0.000", NULL, NULL, Setting_IsExtended, &settings.spindle.pid.i_max_error, NULL, is_group_available }, - { Setting_PositionPGain, Group_Spindle_Sync, "Spindle sync P-gain", NULL, Format_Decimal, "###0.000", NULL, NULL, Setting_IsExtended, &settings.position.pid.p_gain, NULL, is_group_available }, - { Setting_PositionIGain, Group_Spindle_Sync, "Spindle sync I-gain", NULL, Format_Decimal, "###0.000", NULL, NULL, Setting_IsExtended, &settings.position.pid.i_gain, NULL, is_group_available }, - { Setting_PositionDGain, Group_Spindle_Sync, "Spindle sync D-gain", NULL, Format_Decimal, "###0.000", NULL, NULL, Setting_IsExtended, &settings.position.pid.d_gain, NULL, is_group_available }, - { Setting_PositionIMaxError, Group_Spindle_Sync, "Spindle sync PID max I error", NULL, Format_Decimal, "###0.000", NULL, NULL, Setting_IsExtended, &settings.position.pid.i_max_error, NULL, is_group_available }, - { Setting_AxisStepsPerMM, Group_Axis0, "-axis travel resolution", axis_steps, Format_Decimal, "#####0.000##", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, - { Setting_AxisMaxRate, Group_Axis0, "-axis maximum rate", axis_rate, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, - { Setting_AxisAcceleration, Group_Axis0, "-axis acceleration", axis_accel, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, -#if ENABLE_JERK_ACCELERATION - { Setting_AxisJerk, Group_Axis0, "-axis jerk", axis_jerk, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsExtendedFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, -#endif - { Setting_AxisMaxTravel, Group_Axis0, "-axis maximum travel", axis_dist, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, -#if ENABLE_BACKLASH_COMPENSATION - { Setting_AxisBacklash, Group_Axis0, "-axis backlash compensation", axis_dist, Format_Decimal, "#####0.000##", NULL, NULL, Setting_IsExtendedFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, -#endif - { Setting_AxisAutoSquareOffset, Group_Axis0, "-axis dual axis offset", "mm", Format_Decimal, "-0.000", "-10", "10", Setting_IsExtendedFn, set_axis_setting, get_float, is_setting_available, AXIS_OPTS }, - { Setting_SpindleAtSpeedTolerance, Group_Spindle, "Spindle at speed tolerance", "percent", Format_Decimal, "##0.0", NULL, NULL, Setting_IsExtended, &settings.spindle.at_speed_tolerance, NULL, is_setting_available }, - { Setting_ToolChangeMode, Group_Toolchange, "Tool change mode", NULL, Format_RadioButtons, "Normal,Manual touch off,Manual touch off @ G59.3,Automatic touch off @ G59.3,Ignore M6", NULL, NULL, Setting_IsExtendedFn, set_tool_change_mode, get_int, NULL }, - { Setting_ToolChangeProbingDistance, Group_Toolchange, "Tool change probing distance", "mm", Format_Decimal, "#####0.0", NULL, NULL, Setting_IsExtendedFn, set_tool_change_probing_distance, get_float, NULL }, - { Setting_ToolChangeFeedRate, Group_Toolchange, "Tool change locate feed rate", "mm/min", Format_Decimal, "#####0.0", NULL, NULL, Setting_IsExtended, &settings.tool_change.feed_rate, NULL, NULL }, - { Setting_ToolChangeSeekRate, Group_Toolchange, "Tool change search seek rate", "mm/min", Format_Decimal, "#####0.0", NULL, NULL, Setting_IsExtended, &settings.tool_change.seek_rate, NULL, NULL }, - { Setting_ToolChangePulloffRate, Group_Toolchange, "Tool change probe pull-off rate", "mm/min", Format_Decimal, "#####0.0", NULL, NULL, Setting_IsExtended, &settings.tool_change.pulloff_rate, NULL, NULL }, - { Setting_ToolChangeRestorePosition, Group_Toolchange, "Restore position after M6", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_tool_restore_pos, get_int, NULL }, - { Setting_DualAxisLengthFailPercent, Group_Limits_DualAxis, "Dual axis length fail", "percent", Format_Decimal, "##0.0", "0", "100", Setting_IsExtended, &settings.homing.dual_axis.fail_length_percent, NULL, is_setting_available }, - { Setting_DualAxisLengthFailMin, Group_Limits_DualAxis, "Dual axis length fail min", "mm", Format_Decimal, "#####0.000", NULL, NULL, Setting_IsExtended, &settings.homing.dual_axis.fail_distance_min, NULL, is_setting_available }, - { Setting_DualAxisLengthFailMax, Group_Limits_DualAxis, "Dual axis length fail max", "mm", Format_Decimal, "#####0.000", NULL, NULL, Setting_IsExtended, &settings.homing.dual_axis.fail_distance_max, NULL, is_setting_available }, + +static status_code_t set_control_invert (setting_id_t id, uint_fast16_t int_value) +{ + settings.control_invert.mask = (int_value & hal.signals_cap.mask) | limits_override.mask; + + ioport_setting_changed(id); + system_init_switches(); + + return Status_OK; +} + +static status_code_t set_pwm_mode (setting_id_t id, uint_fast16_t int_value) +{ + settings.pwm_spindle.flags.enable_rpm_controlled = int_value != 0; + + return Status_OK; +} + +static status_code_t set_pwm_options (setting_id_t id, uint_fast16_t int_value) +{ + if(int_value & 0x001) { + if(int_value > 0b111) + return Status_SettingValueOutOfRange; + settings.pwm_spindle.flags.pwm_disable = Off; + settings.pwm_spindle.flags.enable_rpm_controlled = !!(int_value & 0b010); + settings.pwm_spindle.flags.laser_mode_disable = !!(int_value & 0b100); + } else { + settings.pwm_spindle.flags.pwm_disable = On; + settings.pwm_spindle.flags.enable_rpm_controlled = settings.pwm_spindle.flags.laser_mode_disable = Off; + } + + return Status_OK; +} + +typedef struct { + uint8_t ref_id; + spindle_id_t spindle_id; +} spindle_map_t; + +static bool get_spindle_ref_id (spindle_info_t *spindle, void *map) +{ + bool ok; + + if((ok = spindle->id == ((spindle_map_t *)map)->spindle_id)) + ((spindle_map_t *)map)->ref_id = spindle->ref_id; + + return ok; +} + +static status_code_t set_default_spindle (setting_id_t id, uint_fast16_t int_value) +{ + status_code_t status; + spindle_map_t spindle = { .spindle_id = int_value }; + + if((status = spindle_enumerate_spindles(get_spindle_ref_id, &spindle) ? Status_OK : Status_SettingValueOutOfRange) == Status_OK) { + + settings.spindle.ref_id = spindle.ref_id; + + spindle_select(spindle.spindle_id); + } + + return status; +} + +static status_code_t set_encoder_spindle (setting_id_t id, uint_fast16_t int_value) +{ + status_code_t status; + spindle_map_t spindle = { .spindle_id = int_value }; + + if((status = spindle_enumerate_spindles(get_spindle_ref_id, &spindle) ? Status_OK : Status_SettingValueOutOfRange) == Status_OK) + settings.spindle.encoder_spindle = spindle.ref_id; + + return status; +} + +static status_code_t set_spindle_invert (setting_id_t id, uint_fast16_t int_value) +{ + settings.pwm_spindle.invert.mask = int_value; + if(settings.pwm_spindle.invert.pwm && !spindle_get_caps(false).pwm_invert) { + settings.pwm_spindle.invert.pwm = Off; + return Status_SettingDisabled; + } + + return Status_OK; +} + +static status_code_t set_control_disable_pullup (setting_id_t id, uint_fast16_t int_value) +{ + settings.control_disable_pullup.mask = int_value & (hal.signals_cap.mask & ~limits_override.mask); + + ioport_setting_changed(id); + + return Status_OK; +} + +static status_code_t set_probe_disable_pullup (setting_id_t id, uint_fast16_t int_value) +{ + if(!hal.probe.configure) + return Status_SettingDisabled; + + settings.probe.disable_probe_pullup = (int_value & 0b01); + + if(hal.driver_cap.toolsetter) + settings.probe.disable_toolsetter_pullup = !!(int_value & 0b10); + + ioport_setting_changed(id); + + return Status_OK; +} + +static void tmp_set_soft_limits (void) +{ + sys.soft_limits.mask = 0; + + if(settings.limits.soft_enabled.mask) { + uint_fast8_t idx = N_AXIS; + do { + idx--; + if(bit_istrue(settings.limits.soft_enabled.mask, bit(idx)) && settings.axis[idx].max_travel < -0.0f) + bit_true(sys.soft_limits.mask, bit(idx)); + } while(idx); + } +} + +static status_code_t set_soft_limits_enable (setting_id_t id, uint_fast16_t int_value) +{ + if(int_value && !settings.homing.flags.enabled) + return Status_SoftLimitError; + + settings.limits.soft_enabled.mask = int_value ? AXES_BITMASK : 0; + + tmp_set_soft_limits(); + + return Status_OK; +} + +static status_code_t set_estop_unlock (setting_id_t id, uint_fast16_t int_value) +{ + if(!hal.signals_cap.e_stop) + return Status_SettingDisabled; + + settings.flags.no_unlock_after_estop = int_value == 0; + + return Status_OK; +} + #if COMPATIBILITY_LEVEL <= 1 - { Setting_DisableG92Persistence, Group_General, "Disable G92 persistence", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_g92_disable_persistence, get_int, NULL }, -#endif -#if N_AXIS > 3 - { Settings_RotaryAxes, Group_Stepper, "Rotary axes", NULL, Format_Bitfield, rotary_axes, NULL, NULL, Setting_IsExtendedFn, set_rotary_axes, get_int, NULL }, -#endif -#ifndef NO_SAFETY_DOOR_SUPPORT - { Setting_DoorSpindleOnDelay, Group_SafetyDoor, "Spindle on delay", "s", Format_Decimal, "#0.0", "0.5", "20", Setting_IsExtended, &settings.safety_door.spindle_on_delay, NULL, is_setting_available }, - { Setting_DoorCoolantOnDelay, Group_SafetyDoor, "Coolant on delay", "s", Format_Decimal, "#0.0", "0.5", "20", Setting_IsExtended, &settings.safety_door.coolant_on_delay, NULL, is_setting_available }, -#endif - { Setting_SpindleOnDelay, Group_Spindle, "Spindle on delay", "s", Format_Decimal, "#0.0", "0.5", "20", Setting_IsExtended, &settings.safety_door.spindle_on_delay, NULL, is_setting_available }, - { Setting_SpindleType, Group_Spindle, "Default spindle", NULL, Format_RadioButtons, spindle_types, NULL, NULL, Setting_IsExtendedFn, set_spindle_type, get_int, is_setting_available }, - { Setting_PlannerBlocks, Group_General, "Planner buffer blocks", NULL, Format_Int16, "####0", "30", "1000", Setting_IsExtended, &settings.planner_buffer_blocks, NULL, NULL, { .reboot_required = On } }, - { Setting_AutoReportInterval, Group_General, "Autoreport interval", "ms", Format_Int16, "###0", "100", "1000", Setting_IsExtendedFn, set_report_interval, get_int, NULL, { .reboot_required = On, .allow_null = On } }, -// { Setting_TimeZoneOffset, Group_General, "Timezone offset", NULL, Format_Decimal, "-#0.00", "0", "12", Setting_IsExtended, &settings.timezone, NULL, NULL }, - { Setting_UnlockAfterEStop, Group_General, "Unlock required after E-Stop", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_estop_unlock, get_int, is_setting_available }, -#if NGC_EXPRESSIONS_ENABLE - { Setting_NGCDebugOut, Group_General, "Output NGC debug messages", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_ngc_debug_out, get_int, NULL }, + +static status_code_t set_offset_lock (setting_id_t id, uint_fast16_t int_value) +{ + settings.parking.flags.offset_lock = int_value & 0b111; // TODO: remove + settings.offset_lock.mask &= ~0b111; // TODO: remove + settings.offset_lock.mask |= settings.parking.flags.offset_lock; + + return Status_OK; +} + #endif + +static inline void tmp_set_hard_limits (void) +{ + sys.hard_limits.mask = settings.limits.flags.hard_enabled ? AXES_BITMASK : 0; + #if N_AXIS > 3 + if(settings.limits.flags.hard_disabled_rotary) + sys.hard_limits.mask &= ~settings.steppers.is_rotary.mask; + #endif +} + +static status_code_t set_hard_limits_enable (setting_id_t id, uint_fast16_t int_value) +{ + if((settings.limits.flags.hard_enabled = bit_istrue(int_value, bit(0)))) { #if COMPATIBILITY_LEVEL <= 1 - { Setting_OffsetLock, Group_General, "Lock coordinate systems", NULL, Format_Bitfield, "G59.1,G59.2,G59.3", NULL, NULL, Setting_IsExtendedFn, set_offset_lock, get_int, NULL }, -#endif - { Setting_EncoderSpindle, Group_Spindle, "Encoder spindle", NULL, Format_RadioButtons, spindle_types, NULL, NULL, Setting_IsExtendedFn, set_encoder_spindle, get_int, is_setting_available }, -#if N_AXIS > 3 - { Setting_RotaryWrap, Group_Stepper, "Fast rotary go to G28", NULL, Format_Bitfield, rotary_axes, NULL, NULL, Setting_IsExtendedFn, set_rotary_wrap_axes, get_int, NULL }, + settings.limits.flags.check_at_init = bit_istrue(int_value, bit(1)); + #if N_AXIS > 3 + settings.limits.flags.hard_disabled_rotary = bit_istrue(int_value, bit(2)); + #endif #endif - { Setting_FSOptions, Group_General, "File systems options", NULL, Format_Bitfield, fs_options, NULL, NULL, Setting_IsExtended, &settings.fs_options.mask, NULL, is_setting_available }, - { Setting_HomePinsInvertMask, Group_Limits, "Invert home pins", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtended, &settings.home_invert.mask, NULL, is_setting_available }, - { Setting_HoldCoolantOnDelay, Group_Coolant, "Coolant on delay", "s", Format_Decimal, "#0.0", "0.5", "20", Setting_IsExtended, &settings.safety_door.coolant_on_delay, NULL, is_setting_available } -}; + } else + settings.limits.flags.check_at_init = settings.limits.flags.hard_disabled_rotary = Off; -#ifndef NO_SETTINGS_DESCRIPTIONS + tmp_set_hard_limits(); + hal.limits.enable(settings.limits.flags.hard_enabled, (axes_signals_t){0}); // Change immediately. NOTE: Nice to have but could be problematic later. -PROGMEM static const setting_descr_t setting_descr[] = { - { Setting_PulseMicroseconds, "Sets time length per step. Minimum 2 microseconds.\\n\\n" - "This needs to be reduced from the default value of 10 when max. step rates exceed approximately 80 kHz." - }, - { Setting_StepperIdleLockTime, "Sets a short hold delay when stopping to let dynamics settle before disabling steppers. Value 255 keeps motors enabled." }, - { Setting_StepInvertMask, "Inverts the step signals (active low)." }, - { Setting_DirInvertMask, "Inverts the direction signals (active low)." }, -#if COMPATIBILITY_LEVEL <= 2 - { Setting_InvertStepperEnable, "Inverts the stepper driver enable signals. Most drivers uses active low enable requiring inversion.\\n\\n" - "NOTE: If the stepper drivers shares the same enable signal only X is used." - }, + return Status_OK; +} + +static status_code_t set_jog_soft_limited (setting_id_t id, uint_fast16_t int_value) +{ + if (int_value && !settings.homing.flags.enabled) + return Status_SoftLimitError; + + settings.limits.flags.jog_soft_limited = int_value != 0; + + return Status_OK; +} + +static status_code_t set_homing_enable (setting_id_t id, uint_fast16_t int_value) +{ + homing_flags_t homing; + + homing.value = int_value; + + if(homing.enabled) { +#if COMPATIBILITY_LEVEL > 1 + settings.homing.flags.enabled = On; + settings.homing.flags.init_lock = DEFAULT_HOMING_INIT_LOCK; + settings.homing.flags.single_axis_commands = DEFAULT_HOMING_SINGLE_AXIS_COMMANDS; + settings.homing.flags.force_set_origin = DEFAULT_HOMING_FORCE_SET_ORIGIN; + settings.homing.flags.manual = DEFAULT_HOMING_ALLOW_MANUAL; + settings.homing.flags.override_locks = DEFAULT_HOMING_OVERRIDE_LOCKS; + settings.homing.flags.keep_on_reset = DEFAULT_HOMING_KEEP_STATUS_ON_RESET; + settings.homing.flags.use_limit_switches = DEFAULT_HOMING_USE_LIMIT_SWITCHES; + settings.limits.flags.two_switches = DEFAULT_LIMITS_TWO_SWITCHES_ON_AXES; #else - { Setting_InvertStepperEnable, "Inverts the stepper driver enable signals. Drivers using active high enable require inversion.\\n\\n" }, + settings.homing.flags.value = int_value & 0b1111; + settings.limits.flags.two_switches = homing.two_switches; + settings.homing.flags.manual = homing.manual; + settings.homing.flags.override_locks = homing.override_locks; + settings.homing.flags.keep_on_reset = homing.keep_on_reset; + settings.homing.flags.use_limit_switches = homing.use_limit_switches; #endif - { Setting_LimitPinsInvertMask, "Inverts the axis limit input signals." }, - { Setting_InvertProbePin, "Inverts the probe input pin signal." }, - { Setting_SpindlePWMOptions, "Enable controls PWM output availability.\\n" - "When `RPM controls spindle enable signal` is checked and M3 or M4 is active S0 switches it off and S > 0 switches it on." - }, - { Setting_GangedDirInvertMask, "Inverts the direction signals for the second motor used for ganged axes.\\n\\n" - "NOTE: This inversion will be applied in addition to the inversion from setting $3." - }, - { Setting_StatusReportMask, "Specifies optional data included in status reports and if report is sent when homing.\\n" - "If Run substatus is enabled it may be used for simple probe protection.\\n\\n" - "NOTE: Parser state will be sent separately after the status report and only on changes." - }, - { Setting_JunctionDeviation, "Sets how fast Grbl travels through consecutive motions. Lower value slows it down." }, - { Setting_ArcTolerance, "Sets the G2 and G3 arc tracing accuracy based on radial error. Beware: A very small value may effect performance." }, - { Setting_ReportInches, "Enables inch units when returning any position and rate value that is not a settings value." }, - { Setting_ControlInvertMask, "Inverts the control signals (active low).\\n" - "NOTE: Block delete, Optional stop, EStop and Probe connected are optional signals, availability is driver dependent." - }, - { Setting_CoolantInvertMask, "Inverts the coolant and mist signals (active low)." }, - { Setting_SpindleInvertMask, "Inverts the spindle on, counterclockwise and PWM signals (active low)." }, - { Setting_ControlPullUpDisableMask, "Disable the control signals pullup resistors. Potentially enables pulldown resistor if available.\\n" - "NOTE: Block delete, Optional stop and EStop are optional signals, availability is driver dependent." - }, - { Setting_LimitPullUpDisableMask, "Disable the limit signals pullup resistors. Potentially enables pulldown resistor if available."}, - { Setting_ProbePullUpDisable, "Disable the probe signal pullup resistor. Potentially enables pulldown resistor if available." }, - { Setting_SoftLimitsEnable, "Enables soft limits checks within machine travel and sets alarm when exceeded. Requires homing." }, - { Setting_HardLimitsEnable, "When enabled immediately halts motion and throws an alarm when a limit switch is triggered. In strict mode only homing is possible when a switch is engaged." }, - { Setting_HomingEnable, "Enables homing cycle. Requires limit switches on axes to be automatically homed.\\n\\n" - "When `Enable single axis commands` is checked, single axis homing can be performed by $H commands.\\n\\n" - "When `Allow manual` is checked, axes not homed automatically may be homed manually by $H or $H commands.\\n\\n" - "`Override locks` is for allowing a soft reset to disable `Homing on startup required`." - }, - { Setting_HomingDirMask, "Homing searches for a switch in the positive direction. Set axis bit to search in negative direction." }, - { Setting_HomingFeedRate, "Feed rate to slowly engage limit switch to determine its location accurately." }, - { Setting_HomingSeekRate, "Seek rate to quickly find the limit switch before the slower locating phase." }, - { Setting_HomingDebounceDelay, "Sets a short delay between phases of homing cycle to let a switch debounce." }, - { Setting_HomingPulloff, "Retract distance after triggering switch to disengage it. Homing will fail if switch isn't cleared." }, - { Setting_G73Retract, "G73 retract distance (for chip breaking drilling)." }, - { Setting_PulseDelayMicroseconds, "Step pulse delay.\\n\\n" - "Normally leave this at 0 as there is an implicit delay on direction changes when AMASS is active." - }, - { Setting_RpmMax, "Maximum spindle speed, can be overridden by spindle plugins." }, - { Setting_RpmMin, "Minimum spindle speed, can be overridden by spindle plugins.\\n\\n" - "When set > 0 $35 (PWM min value) may have to be set to get the configured RPM."}, -#if !LATHE_UVW_OPTION - { Setting_Mode, "Laser mode: consecutive G1/2/3 commands will not halt when spindle speed is changed.\\n" - "Lathe mode: allows use of G7, G8, G96 and G97." - }, -#endif - { Setting_PWMFreq, "Spindle PWM frequency." }, - { Setting_PWMOffValue, "Spindle PWM off value in percent (duty cycle)." }, - { Setting_PWMMinValue, "Spindle PWM min value in percent (duty cycle)." }, - { Setting_PWMMaxValue, "Spindle PWM max value in percent (duty cycle)." }, - { Setting_SteppersEnergize, "Specifies which steppers not to disable when stopped." }, - { Setting_SpindlePPR, "Spindle encoder pulses per revolution." }, - { Setting_EnableLegacyRTCommands, "Enables \"normal\" processing of ?, ! and ~ characters when part of $-setting or comment. If disabled then they are added to the input string instead." }, - { Setting_JogSoftLimited, "Limit jog commands to machine limits for homed axes." }, - { Setting_ParkingEnable, "Enables parking cycle, requires parking axis homed." }, - { Setting_ParkingAxis, "Define which axis that performs the parking motion." }, - { Setting_HomingLocateCycles, "Number of homing passes. Minimum 1, maximum 128." }, - { Setting_HomingCycle_1, "Axes to home in first pass." }, - { Setting_HomingCycle_2, "Axes to home in second pass." }, - { Setting_HomingCycle_3, "Axes to home in third pass." }, -#ifdef A_AXIS - { Setting_HomingCycle_4, "Axes to home in fourth pass." }, -#endif -#ifdef B_AXIS - { Setting_HomingCycle_5, "Axes to home in fifth pass." }, -#endif -#ifdef C_AXIS - { Setting_HomingCycle_6, "Axes to home in sixth pass." }, -#endif - { Setting_JogStepSpeed, "Step jogging speed in millimeters per minute." }, - { Setting_JogSlowSpeed, "Slow jogging speed in millimeters per minute." }, - { Setting_JogFastSpeed, "Fast jogging speed in millimeters per minute." }, - { Setting_JogStepDistance, "Jog distance for single step jogging." }, - { Setting_JogSlowDistance, "Jog distance before automatic stop." }, - { Setting_JogFastDistance, "Jog distance before automatic stop." }, -#ifndef NO_SAFETY_DOOR_SUPPORT - { Setting_ParkingPulloutIncrement, "Spindle pull-out and plunge distance in mm.Incremental distance." }, - { Setting_ParkingPulloutRate, "Spindle pull-out/plunge slow feed rate in mm/min." }, - { Setting_ParkingTarget, "Parking axis target. In mm, as machine coordinate [-max_travel, 0]." }, - { Setting_ParkingFastRate, "Parking fast rate to target after pull-out in mm/min." }, - { Setting_RestoreOverrides, "Restore overrides to default values at program end." }, - { Setting_DoorOptions, "Enable this if it is desirable to open the safety door when in IDLE mode (eg. for jogging)." }, -#endif - { Setting_SleepEnable, "Enable sleep mode." }, - { Setting_HoldActions, "Actions taken during feed hold and on resume from feed hold." }, - { Setting_ForceInitAlarm, "Starts Grbl in alarm mode after a cold reset." }, - { Setting_ProbingFeedOverride, "Allow feed override during probing." }, -#if ENABLE_SPINDLE_LINEARIZATION - { Setting_LinearSpindlePiece1, "Comma separated list of values: RPM_MIN, RPM_LINE_A1, RPM_LINE_B1, set to blank to disable." }, - #if SPINDLE_NPWM_PIECES > 1 - { Setting_LinearSpindlePiece2, "Comma separated list of values: RPM_POINT12, RPM_LINE_A2, RPM_LINE_B2, set to blank to disable." }, - #endif - #if SPINDLE_NPWM_PIECES > 2 - { Setting_LinearSpindlePiece3, "Comma separated list of values: RPM_POINT23, RPM_LINE_A3, RPM_LINE_B3, set to blank to disable." }, - #endif - #if SPINDLE_NPWM_PIECES > 3 - { Setting_LinearSpindlePiece4, "Comma separated list of values: RPM_POINT34, RPM_LINE_A4, RPM_LINE_B4, set to blank to disable." }, - #endif -#endif - { Setting_SpindlePGain, "" }, - { Setting_SpindleIGain, "" }, - { Setting_SpindleDGain, "" }, - { Setting_SpindleMaxError, "" }, - { Setting_SpindleIMaxError, "Spindle PID max integrator error." }, - { Setting_PositionPGain, "" }, - { Setting_PositionIGain, "" }, - { Setting_PositionDGain, "" }, - { Setting_PositionIMaxError, "Spindle sync PID max integrator error." }, - { Setting_AxisStepsPerMM, "Travel resolution in steps per millimeter." }, - { (setting_id_t)(Setting_AxisStepsPerMM + 1), "Travel resolution in steps per degree." }, // "Hack" to get correct description for rotary axes - { Setting_AxisMaxRate, "Maximum rate. Used as G0 rapid rate." }, - { Setting_AxisAcceleration, "Acceleration. Used for motion planning to not exceed motor torque and lose steps." }, -#if ENABLE_JERK_ACCELERATION - { Setting_AxisJerk, "Maximum rate of acceleration change - smoothes out acceleration profile up to max axis acceleration.\\n\\n" - "Minimum value of x10 Acceleration setting to ensure decent acceleration times.\\n" - "Maximum is calculated by current acceleration and stepper segment time.\\n" - "At Maximum value motion is effectively trapezoidal instead of constant jerk.\\n\\n" - "Can be increased by adjusting ACCELERATION_TICKS_PER_SECOND to a larger value before compiling."}, -#endif - { Setting_AxisMaxTravel, "Maximum axis travel distance from homing switch. Determines valid machine space for soft-limits and homing search distances." }, -#if ENABLE_BACKLASH_COMPENSATION - { Setting_AxisBacklash, "Backlash distance to compensate for." }, -#endif - { Setting_AxisAutoSquareOffset, "Offset between sides to compensate for homing switches inaccuracies." }, - { Setting_SpindleAtSpeedTolerance, "Spindle at speed tolerance as percentage deviation from programmed speed, set to 0 to disable.\\n" - "If not within tolerance when checked after spindle on delay ($392) alarm 14 is raised." - }, - { Setting_ToolChangeMode, "Normal: allows jogging for manual touch off. Set new position manually.\\n\\n" - "Manual touch off: retracts tool axis to home position for tool change, use jogging or $TPW for touch off.\\n\\n" - "Manual touch off @ G59.3: retracts tool axis to home position then to G59.3 position for tool change, use jogging or $TPW for touch off.\\n\\n" - "Automatic touch off @ G59.3: retracts tool axis to home position for tool change, then to G59.3 position for automatic touch off.\\n\\n" - "All modes except \"Normal\" and \"Ignore M6\" returns the tool (controlled point) to original position after touch off." - }, - { Setting_ToolChangeProbingDistance, "Maximum probing distance for automatic or $TPW touch off." }, - { Setting_ToolChangeFeedRate, "Feed rate to slowly engage tool change sensor to determine the tool offset accurately." }, - { Setting_ToolChangeSeekRate, "Seek rate to quickly find the tool change sensor before the slower locating phase." }, - { Setting_ToolChangePulloffRate, "Pull-off rate for the retract move before the slower locating phase." }, - { Setting_ToolChangeRestorePosition, "When set the spindle is moved so that the controlled point (tool tip) is the same as before the M6 command, if not the spindle is only moved to the Z home position." }, - { Setting_DualAxisLengthFailPercent, "Dual axis length fail in percent of axis max travel." }, - { Setting_DualAxisLengthFailMin, "Dual axis length fail minimum distance." }, - { Setting_DualAxisLengthFailMax, "Dual axis length fail minimum distance." }, -#if COMPATIBILITY_LEVEL <= 1 - { Setting_DisableG92Persistence, "Disables save/restore of G92 offset to non-volatile storage (NVS)." }, -#endif -#if N_AXIS > 3 - { Settings_RotaryAxes, "Designates axes as rotary, interpretation some other relevant axis settings is changed accordingly." }, -#endif -#ifndef NO_SAFETY_DOOR_SUPPORT - { Setting_DoorSpindleOnDelay, "Delay to allow spindle to spin up after safety door is opened or feed hold is canceled." }, - { Setting_DoorCoolantOnDelay, "Delay to allow coolant to restart after safety door is opened or feed hold is canceled." }, -#else - { Setting_DoorSpindleOnDelay, "Delay to allow spindle to spin up when spindle at speed tolerance is > 0." }, -#endif - { Setting_SpindleOnDelay, "Delay to allow spindle to restart after feed hold is canceled." }, - { Setting_SpindleType, "Spindle selected on startup." }, - { Setting_PlannerBlocks, "Number of blocks in the planner buffer." }, - { Setting_AutoReportInterval, "Interval the real time report will be sent, set to 0 to disable." }, - { Setting_TimeZoneOffset, "Offset in hours from UTC." }, - { Setting_UnlockAfterEStop, "If set unlock (by sending $X) is required after resetting a cleared E-Stop condition." }, -#if COMPATIBILITY_LEVEL <= 1 - { Setting_OffsetLock, "Lock coordinate systems against accidental changes." }, -#endif -#if NGC_EXPRESSIONS_ENABLE - { Setting_NGCDebugOut, "Example: (debug, metric mode: #<_metric>, coord system: #5220)" }, -#endif - { Setting_EncoderSpindle, "Specifies which spindle has the encoder attached." }, -#if N_AXIS > 3 - { Setting_RotaryWrap, "Perform fast move to angle stored in G28 position.\\n" - "Use:\\n" - " G91G280\\n" - " G90\\n" - }, -#endif - { Setting_FSOptions, "Auto mount SD card on startup." }, - { Setting_HomePinsInvertMask, "Inverts the axis home input signals." }, - { Setting_HoldCoolantOnDelay, "Delay to allow coolant to restart after feed hold is canceled." } -}; + } else { + settings.homing.flags.value = 0; + settings.limits.flags.soft_enabled = Off; // Force disable soft-limits. + settings.limits.flags.jog_soft_limited = Off; + } -#endif + return Status_OK; +} -static setting_details_t setting_details = { - .groups = setting_group_detail, - .n_groups = sizeof(setting_group_detail) / sizeof(setting_group_detail_t), - .settings = setting_detail, - .n_settings = sizeof(setting_detail) / sizeof(setting_detail_t), -#ifndef NO_SETTINGS_DESCRIPTIONS - .descriptions = setting_descr, - .n_descriptions = sizeof(setting_descr) / sizeof(setting_descr_t), -#endif - .save = settings_write_global -}; +static status_code_t set_enable_legacy_rt_commands (setting_id_t id, uint_fast16_t int_value) +{ + settings.flags.legacy_rt_commands = int_value != 0; -// Acceleration override + return Status_OK; +} -static struct { - bool valid; - float acceleration[N_AXIS]; -} override_backup = { .valid = false }; +static status_code_t set_homing_cycle (setting_id_t id, uint_fast16_t int_value) +{ + settings.homing.cycle[id - Setting_HomingCycle_1].mask = int_value; + limits_set_homing_axes(); -static void save_override_backup (void) + return Status_OK; +} + +#if !LATHE_UVW_OPTION + +static status_code_t set_mode (setting_id_t id, uint_fast16_t int_value) { - uint_fast8_t idx = N_AXIS; + switch((machine_mode_t)int_value) { - do { - idx--; - override_backup.acceleration[idx] = settings.axis[idx].acceleration; - } while(idx); + case Mode_Standard: + gc_state.modal.diameter_mode = false; + break; - override_backup.valid = true; + case Mode_Laser: + if(!spindle_get_caps(false).laser) + return Status_SettingDisabledLaser; + gc_state.modal.diameter_mode = false; + break; + + case Mode_Lathe: + break; + + default: // Mode_Standard + return Status_InvalidStatement; + } + + machine_mode_changed = true; + settings.mode = (machine_mode_t)int_value; + + return Status_OK; } -static void restore_override_backup (void) +#endif // LATHE_UVW_OPTION + +#ifndef NO_SAFETY_DOOR_SUPPORT + +static status_code_t set_parking_enable (setting_id_t id, uint_fast16_t int_value) { - uint_fast8_t idx = N_AXIS; + settings.parking.flags.value = bit_istrue(int_value, bit(0)) ? (int_value & 0x07) : 0; - if(override_backup.valid) do { - idx--; - settings.axis[idx].acceleration = override_backup.acceleration[idx]; - } while(idx); + return Status_OK; } -// Temporarily override acceleration, if 0 restore to setting value. -// Note: only allowed when current state is idle. -bool settings_override_acceleration (uint8_t axis, float acceleration) +static status_code_t set_restore_overrides (setting_id_t id, uint_fast16_t int_value) { - sys_state_t state = state_get(); + settings.flags.restore_overrides = int_value != 0; - if(!(state == STATE_IDLE || (state & (STATE_HOMING|STATE_ALARM)))) - return false; + return Status_OK; +} - if(acceleration <= 0.0f) { - if(override_backup.valid) - settings.axis[axis].acceleration = override_backup.acceleration[axis]; - } else { - if(!override_backup.valid) - save_override_backup(); - settings.axis[axis].acceleration = (override_backup.acceleration[axis] >= (acceleration * 60.0f * 60.0f)) ? (acceleration * 60.0f * 60.0f) : override_backup.acceleration[axis]; // Limited to max setting value - } - return true; -} - -#if ENABLE_ACCELERATION_PROFILES -//Acceleration Profiles for G187 P[x] in percent of maximum machine acceleration. -float lookupprofile(uint8_t profile) { - static const float lookup[5] = { - 1.0f, // 100% - Roughing - Max Acceleration Default - 0.8f, // 80% - Semi Roughing - 0.6f, // 60% - Semi Finish - 0.4f, // 40% - Finish - 0.2f, // 20% - Slow AF Mode - }; - return lookup[profile]; -} -#endif - -// --- - -static setting_details_t *settingsd = &setting_details; - -void settings_register (setting_details_t *details) -{ - settingsd->next = details; - settingsd = details; -} - -setting_details_t *settings_get_details (void) -{ - return &setting_details; -} - -#if COMPATIBILITY_LEVEL > 2 +#endif // NO_SAFETY_DOOR_SUPPORT -static status_code_t set_enable_invert_mask (setting_id_t id, uint_fast16_t int_value) +static status_code_t set_homing_cycle (setting_id_t id, uint_fast16_t int_value) { - settings.steppers.enable_invert.mask = int_value ? 0 : AXES_BITMASK; + settings.homing.cycle[id - Setting_HomingCycle_1].mask = int_value; + limits_set_homing_axes(); return Status_OK; } -#endif - -#if COMPATIBILITY_LEVEL > 1 - -static status_code_t set_limits_invert_mask (setting_id_t id, uint_fast16_t int_value) +static status_code_t set_homing_pulloff (setting_id_t id, float value) { - settings.limits.invert.mask = (int_value ? ~(DEFAULT_LIMIT_SIGNALS_INVERT_MASK) : DEFAULT_LIMIT_SIGNALS_INVERT_MASK) & AXES_BITMASK; + settings.homing.pulloff = value; + + homing_pulloff_init(value); return Status_OK; } -#endif - -static status_code_t set_probe_invert (setting_id_t id, uint_fast16_t int_value) +static status_code_t set_homing_feedrates (setting_id_t id, float value) { - if(!hal.probe.configure) - return Status_SettingDisabled; - - settings.probe.invert_probe_pin = int_value != 0; - - ioport_setting_changed(id); + uint_fast8_t idx = N_AXIS; - hal.probe.configure(false, false); + if(!settings.homing.flags.per_axis_feedrates) switch(id) { - return Status_OK; -} + case Setting_HomingFeedRate: + do { + settings.axis[--idx].homing_feed_rate = value; + } while(idx); + break; -static status_code_t set_ganged_dir_invert (setting_id_t id, uint_fast16_t int_value) -{ - if(!hal.stepper.get_ganged) - return Status_SettingDisabled; + case Setting_HomingSeekRate: + do { + settings.axis[--idx].homing_seek_rate = value; + } while(idx); + break; - settings.steppers.ganged_dir_invert.mask = int_value & hal.stepper.get_ganged(false).mask; + default: + break; + } - return Status_OK; + return settings.homing.flags.per_axis_feedrates ? Status_SettingDisabled : Status_OK; } -static status_code_t set_stepper_energize_mask (setting_id_t id, uint_fast16_t int_value) +static status_code_t set_homing_enable (setting_id_t id, uint_fast16_t int_value) { - settings.steppers.energize.mask = int_value; + bool reset_feeds = !settings.homing.flags.enabled || settings.homing.flags.per_axis_feedrates; - hal.stepper.enable(settings.steppers.energize, true); + settings.homing.flags.value = int_value; - return Status_OK; -} + if(settings.homing.flags.enabled) { +#if COMPATIBILITY_LEVEL > 1 + settings.homing.flags.enabled = On; + settings.homing.flags.init_lock = DEFAULT_HOMING_INIT_LOCK; + settings.homing.flags.single_axis_commands = DEFAULT_HOMING_SINGLE_AXIS_COMMANDS; + settings.homing.flags.force_set_origin = DEFAULT_HOMING_FORCE_SET_ORIGIN; + settings.homing.flags.manual = DEFAULT_HOMING_ALLOW_MANUAL; + settings.homing.flags.override_locks = DEFAULT_HOMING_OVERRIDE_LOCKS; + settings.homing.flags.keep_on_reset = DEFAULT_HOMING_KEEP_STATUS_ON_RESET; + settings.homing.flags.use_limit_switches = DEFAULT_HOMING_USE_LIMIT_SWITCHES; + settings.limits.flags.two_switches = DEFAULT_LIMITS_TWO_SWITCHES_ON_AXES; +#else + settings.limits.flags.two_switches = settings.homing.flags.two_switches; + settings.homing.flags.two_switches = Off; +#endif + } else { + settings.homing.flags.enabled = On; + set_soft_limits_enable(Setting_SoftLimitsEnable, 0); // Force disable soft-limits. + settings.homing.flags.value = 0; + settings.limits.flags.jog_soft_limited = Off; + } -static status_code_t set_report_interval (setting_id_t setting, uint_fast16_t int_value) -{ - if((settings.report_interval = int_value) == 0) - sys.flags.auto_reporting = Off; + if(settings.homing.flags.enabled && reset_feeds && !settings.homing.flags.per_axis_feedrates) { + set_homing_feedrates(Setting_HomingFeedRate, settings.axis[0].homing_feed_rate); + set_homing_feedrates(Setting_HomingSeekRate, settings.axis[0].homing_seek_rate); + } + + settings.homing.flags.use_limit_switches &= hal.homing.get_state != NULL; return Status_OK; } -static status_code_t set_report_mask (setting_id_t id, uint_fast16_t int_value) +static status_code_t set_sleep_enable (setting_id_t id, uint_fast16_t int_value) { -#if COMPATIBILITY_LEVEL <= 1 - settings.status_report.mask = int_value; -#else - int_value &= 0b11; - settings.status_report.mask = (settings.status_report.mask & ~0b11) | int_value; -#endif + settings.flags.sleep_enable = int_value != 0; return Status_OK; } -static status_code_t set_report_inches (setting_id_t id, uint_fast16_t int_value) +static status_code_t set_hold_actions (setting_id_t id, uint_fast16_t int_value) { - settings.flags.report_inches = int_value != 0; - report_init(); - system_flag_wco_change(); // Make sure WCO is immediately updated. + settings.flags.disable_laser_during_hold = bit_istrue(int_value, bit(0)); + settings.flags.restore_after_feed_hold = bit_istrue(int_value, bit(1)); return Status_OK; } -#if NGC_EXPRESSIONS_ENABLE - -static status_code_t set_ngc_debug_out (setting_id_t id, uint_fast16_t int_value) +#if COMPATIBILITY_LEVEL <= 1 +static status_code_t set_g92_disable_persistence (setting_id_t id, uint_fast16_t int_value) { - settings.flags.ngc_debug_out = int_value != 0; - report_init(); - system_flag_wco_change(); // Make sure WCO is immediately updated. + settings.flags.g92_is_volatile = int_value != 0; return Status_OK; } - #endif -static status_code_t set_control_invert (setting_id_t id, uint_fast16_t int_value) +static status_code_t set_force_initialization_alarm (setting_id_t id, uint_fast16_t int_value) { - settings.control_invert.mask = (int_value & hal.signals_cap.mask) | limits_override.mask; - - ioport_setting_changed(id); - system_init_switches(); + settings.flags.force_initialization_alarm = int_value != 0; return Status_OK; } -static status_code_t set_pwm_mode (setting_id_t id, uint_fast16_t int_value) +static status_code_t set_probe_allow_feed_override (setting_id_t id, uint_fast16_t int_value) { - settings.spindle.flags.enable_rpm_controlled = int_value != 0; + settings.probe.allow_feed_override = int_value != 0; return Status_OK; } -static status_code_t set_pwm_options (setting_id_t id, uint_fast16_t int_value) +static status_code_t set_tool_change_mode (setting_id_t id, uint_fast16_t int_value) { - if(int_value & 0x001) { - if(int_value > 0b111) - return Status_SettingValueOutOfRange; - settings.spindle.flags.pwm_disable = Off; - settings.spindle.flags.enable_rpm_controlled = !!(int_value & 0b010); - settings.spindle.flags.laser_mode_disable = !!(int_value & 0b100); - } else { - settings.spindle.flags.pwm_disable = On; - settings.spindle.flags.enable_rpm_controlled = settings.spindle.flags.laser_mode_disable = Off; - } + if(!hal.driver_cap.atc && hal.stream.suspend_read && int_value <= ToolChange_Ignore) { +#if COMPATIBILITY_LEVEL > 1 + if((toolchange_mode_t)int_value == ToolChange_Manual_G59_3 || (toolchange_mode_t)int_value == ToolChange_SemiAutomatic) + return Status_InvalidStatement; +#endif + settings.tool_change.mode = (toolchange_mode_t)int_value; + tc_init(); + } else + return Status_InvalidStatement; return Status_OK; } -static status_code_t set_spindle_type (setting_id_t id, uint_fast16_t int_value) +static status_code_t set_tool_change_probing_distance (setting_id_t id, float value) { - if(spindle_get_count() < 2) - return Status_SettingDisabled; - else if(int_value >= spindle_get_count()) - return Status_SettingValueOutOfRange; - - settings.spindle.flags.type = int_value; + if(hal.driver_cap.atc) + return Status_InvalidStatement; - spindle_select(settings.spindle.flags.type); + settings.tool_change.probing_distance = value; return Status_OK; } -static status_code_t set_encoder_spindle (setting_id_t id, uint_fast16_t int_value) +static status_code_t set_tool_restore_pos (setting_id_t id, uint_fast16_t int_value) { - if(spindle_get_count() < 2) - return Status_SettingDisabled; - else if(int_value >= spindle_get_count()) - return Status_SettingValueOutOfRange; + if(hal.driver_cap.atc) + return Status_InvalidStatement; - settings.offset_lock.encoder_spindle = int_value; + settings.flags.no_restore_position_after_M6 = int_value == 0; return Status_OK; } -static status_code_t set_spindle_invert (setting_id_t id, uint_fast16_t int_value) +static inline void set_axis_unit (const setting_detail_t *setting, const char *unit) { - settings.spindle.invert.mask = int_value; - if(settings.spindle.invert.pwm && !spindle_get_caps(false).pwm_invert) { - settings.spindle.invert.pwm = Off; - return Status_SettingDisabled; - } - - return Status_OK; + // TODO: add length check + if(unit) + strcpy((char *)setting->unit, unit); } -static status_code_t set_control_disable_pullup (setting_id_t id, uint_fast16_t int_value) -{ - settings.control_disable_pullup.mask = int_value & (hal.signals_cap.mask & ~limits_override.mask); +#if N_AXIS > 3 - ioport_setting_changed(id); +static status_code_t set_rotary_axes (setting_id_t id, uint_fast16_t int_value) +{ + settings.steppers.is_rotary.mask = (int_value << 3) & AXES_BITMASK; return Status_OK; } -static status_code_t set_probe_disable_pullup (setting_id_t id, uint_fast16_t int_value) +static status_code_t set_rotary_wrap_axes (setting_id_t id, uint_fast16_t int_value) { - if(!hal.probe.configure) - return Status_SettingDisabled; - - settings.probe.disable_probe_pullup = int_value != 0; - - ioport_setting_changed(id); + settings.steppers.rotary_wrap.mask = (int_value << 3) & AXES_BITMASK; return Status_OK; } -static void tmp_set_soft_limits (void) +static inline bool axis_is_rotary (uint_fast8_t axis_idx) { - sys.soft_limits.mask = 0; - - if(settings.limits.flags.soft_enabled) { - uint_fast8_t idx = N_AXIS; - do { - if(settings.axis[--idx].max_travel < -0.0f) - bit_true(sys.soft_limits.mask, bit(idx)); - } while(idx); - } + return bit_istrue(settings.steppers.is_rotary.mask, bit(axis_idx)); } -static status_code_t set_soft_limits_enable (setting_id_t id, uint_fast16_t int_value) +static const char *set_axis_setting_unit (setting_id_t setting_id, uint_fast8_t axis_idx) { - if(int_value && !settings.homing.flags.enabled) - return Status_SoftLimitError; + char *unit = NULL; - settings.limits.flags.soft_enabled = int_value != 0; + bool is_rotary = axis_is_rotary(axis_idx); - tmp_set_soft_limits(); + switch(setting_id) { - return Status_OK; -} + case Setting_AxisStepsPerMM: + unit = is_rotary ? "step/deg" : "step/mm"; + break; -static status_code_t set_estop_unlock (setting_id_t id, uint_fast16_t int_value) -{ - if(!hal.signals_cap.e_stop) - return Status_SettingDisabled; + case Setting_AxisMaxRate: + unit = is_rotary ? "deg/min" : "mm/min"; + break; - settings.flags.no_unlock_after_estop = int_value == 0; + case Setting_AxisAcceleration: + unit = is_rotary ? "deg/sec^2" : "mm/sec^2"; + break; - return Status_OK; -} +#if ENABLE_JERK_ACCELERATION + case Setting_AxisJerk: + unit = is_rotary ? "deg/sec^3" : "mm/sec^3"; + break; +#endif -#if COMPATIBILITY_LEVEL <= 1 + case Setting_AxisMaxTravel: + case Setting_AxisBacklash: + unit = is_rotary ? "deg" : "mm"; + break; -static status_code_t set_offset_lock (setting_id_t id, uint_fast16_t int_value) -{ - settings.parking.flags.offset_lock = int_value & 0b111; // TODO: remove - settings.offset_lock.mask &= ~0b111; // TODO: remove - settings.offset_lock.mask |= settings.parking.flags.offset_lock; + default: + break; + } - return Status_OK; + return unit; } #endif -static inline void tmp_set_hard_limits (void) +#if ENABLE_SPINDLE_LINEARIZATION + +static status_code_t set_linear_piece (setting_id_t id, char *svalue) { - sys.hard_limits.mask = settings.limits.flags.hard_enabled ? AXES_BITMASK : 0; - #if N_AXIS > 3 - if(settings.limits.flags.hard_disabled_rotary) - sys.hard_limits.mask &= ~settings.steppers.is_rotary.mask; - #endif -} + uint32_t idx = id - Setting_LinearSpindlePiece1; + float rpm, start, end; -static status_code_t set_hard_limits_enable (setting_id_t id, uint_fast16_t int_value) -{ - if((settings.limits.flags.hard_enabled = bit_istrue(int_value, bit(0)))) { -#if COMPATIBILITY_LEVEL <= 1 - settings.limits.flags.check_at_init = bit_istrue(int_value, bit(1)); - #if N_AXIS > 3 - settings.limits.flags.hard_disabled_rotary = bit_istrue(int_value, bit(2)); - #endif -#endif + if(*svalue == '\0' || (svalue[0] == '0' && svalue[1] == '\0')) { + settings.spindle.pwm_piece[idx].rpm = NAN; + settings.spindle.pwm_piece[idx].start = + settings.spindle.pwm_piece[idx].end = 0.0f; + } else if(sscanf(svalue, "%f,%f,%f", &rpm, &start, &end) == 3) { + settings.spindle.pwm_piece[idx].rpm = rpm; + settings.spindle.pwm_piece[idx].start = start; + settings.spindle.pwm_piece[idx].end = end; +//?? if(idx == 0) +// settings.spindle.rpm_min = rpm; } else - settings.limits.flags.check_at_init = settings.limits.flags.hard_disabled_rotary = Off; - - tmp_set_hard_limits(); - hal.limits.enable(settings.limits.flags.hard_enabled, (axes_signals_t){0}); // Change immediately. NOTE: Nice to have but could be problematic later. + return Status_SettingValueOutOfRange; return Status_OK; } -static status_code_t set_jog_soft_limited (setting_id_t id, uint_fast16_t int_value) +static char *get_linear_piece (setting_id_t id) { - if (int_value && !settings.homing.flags.enabled) - return Status_SoftLimitError; - - settings.limits.flags.jog_soft_limited = int_value != 0; + static char buf[40]; - return Status_OK; -} + uint32_t idx = id - Setting_LinearSpindlePiece1; -static status_code_t set_homing_enable (setting_id_t id, uint_fast16_t int_value) -{ - homing_flags_t homing; + if(isnan(settings.spindle.pwm_piece[idx].rpm)) + *buf = '\0'; + else + snprintf(buf, sizeof(buf), "%g,%g,%g", settings.spindle.pwm_piece[idx].rpm, settings.spindle.pwm_piece[idx].start, settings.spindle.pwm_piece[idx].end); - homing.value = int_value; + return buf; +} - if(homing.enabled) { -#if COMPATIBILITY_LEVEL > 1 - settings.homing.flags.enabled = On; - settings.homing.flags.init_lock = DEFAULT_HOMING_INIT_LOCK; - settings.homing.flags.single_axis_commands = DEFAULT_HOMING_SINGLE_AXIS_COMMANDS; - settings.homing.flags.force_set_origin = DEFAULT_HOMING_FORCE_SET_ORIGIN; - settings.homing.flags.manual = DEFAULT_HOMING_ALLOW_MANUAL; - settings.homing.flags.override_locks = DEFAULT_HOMING_OVERRIDE_LOCKS; - settings.homing.flags.keep_on_reset = DEFAULT_HOMING_KEEP_STATUS_ON_RESET; - settings.homing.flags.use_limit_switches = DEFAULT_HOMING_USE_LIMIT_SWITCHES; - settings.limits.flags.two_switches = DEFAULT_LIMITS_TWO_SWITCHES_ON_AXES; -#else - settings.homing.flags.value = int_value & 0b1111; - settings.limits.flags.two_switches = homing.two_switches; - settings.homing.flags.manual = homing.manual; - settings.homing.flags.override_locks = homing.override_locks; - settings.homing.flags.keep_on_reset = homing.keep_on_reset; - settings.homing.flags.use_limit_switches = homing.use_limit_switches; #endif - } else { - settings.homing.flags.value = 0; - settings.limits.flags.soft_enabled = Off; // Force disable soft-limits. - settings.limits.flags.jog_soft_limited = Off; - } - - return Status_OK; -} -static status_code_t set_enable_legacy_rt_commands (setting_id_t id, uint_fast16_t int_value) +inline static setting_id_t normalize_id (setting_id_t id) { - settings.flags.legacy_rt_commands = int_value != 0; + if((id > Setting_AxisSettingsBase && id <= Setting_AxisSettingsMax) || + (id > Setting_AxisSettingsBase1 && id <= Setting_AxisSettingsMax1) || + (id > Setting_AxisSettingsBase2 && id <= Setting_AxisSettingsMax2)) + id -= id % AXIS_SETTINGS_INCREMENT; + else if(id > Setting_EncoderSettingsBase && id <= Setting_EncoderSettingsMax) + id = (setting_id_t)(Setting_EncoderSettingsBase + (id % ENCODER_SETTINGS_INCREMENT)); + else if(id > Setting_ModbusTCPBase && id <= Setting_ModbusTCPMax) + id = (setting_id_t)(Setting_ModbusTCPBase + (id % MODBUS_TCP_SETTINGS_INCREMENT)); + else if((id > Setting_Macro0 && id <= Setting_Macro9) || + (id > Setting_MacroPort0 && id <= Setting_MacroPort9) || + (id > Setting_ButtonAction0 && id <= Setting_ButtonAction9) || + (id > Setting_Action0 && id <= Setting_Action9) || + (id > Setting_ActionPort0 && id <= Setting_ActionPort9) || + (id > Setting_SpindleToolStart0 && id <= Setting_SpindleToolStart7)) + id = (setting_id_t)(id - (id % 10)); - return Status_OK; + return id; } -static status_code_t set_homing_cycle (setting_id_t id, uint_fast16_t int_value) +setting_id_t settings_get_axis_base (setting_id_t id, uint_fast8_t *idx) { - settings.homing.cycle[id - Setting_HomingCycle_1].mask = int_value; - limits_set_homing_axes(); + setting_id_t base = normalize_id(id); + *idx = id - base; - return Status_OK; + return *idx < N_AXIS ? base : Setting_SettingsMax; } -#if !LATHE_UVW_OPTION - -static status_code_t set_mode (setting_id_t id, uint_fast16_t int_value) +static status_code_t set_axis_setting (setting_id_t setting, float value) { - switch((machine_mode_t)int_value) { + uint_fast8_t idx; + status_code_t status = Status_OK; - case Mode_Standard: - gc_state.modal.diameter_mode = false; - break; + switch(settings_get_axis_base(setting, &idx)) { - case Mode_Laser: - if(!spindle_get_caps(false).laser) - return Status_SettingDisabledLaser; - gc_state.modal.diameter_mode = false; + case Setting_AxisStepsPerMM: + if (hal.max_step_rate && value * settings.axis[idx].max_rate > (float)hal.max_step_rate * 60.0f) + status = Status_MaxStepRateExceeded; + else { + if(settings.axis[idx].steps_per_mm > 0.0f && settings.axis[idx].steps_per_mm != value) { + float comp = value / settings.axis[idx].steps_per_mm; + sys.position[idx] *= comp; + sys.home_position[idx] *= comp; + sys.probe_position[idx] *= comp; + sys.tlo_reference[idx] *= comp; + sync_position(); + } + settings.axis[idx].steps_per_mm = value; + } break; - case Mode_Lathe: + case Setting_AxisMaxRate: + if (hal.max_step_rate && value * settings.axis[idx].steps_per_mm > (float)hal.max_step_rate * 60.0f) + status = Status_MaxStepRateExceeded; + else + settings.axis[idx].max_rate = value; break; - default: // Mode_Standard - return Status_InvalidStatement; - } + case Setting_AxisAcceleration: + settings.axis[idx].acceleration = override_backup.acceleration[idx] = value * 60.0f * 60.0f; // Convert to mm/min^2 for grbl internal use. + break; - machine_mode_changed = true; - settings.mode = (machine_mode_t)int_value; +#if ENABLE_JERK_ACCELERATION + case Setting_AxisJerk: + if ((value * 60.0f * 60.0f) < (settings.axis[idx].acceleration * 10.0f)) { //ensuring that the acceleration ramp time is limited to at maximum 100ms (or 10 stepper segments). + settings.axis[idx].jerk = settings.axis[idx].acceleration * 10.0f * 60.0f; // mm/min^2 -> mm/min^3 + } + else if ((settings.axis[idx].acceleration / (value * 60.0f * 60.0f * 60.0f)) < (1.0f / ACCELERATION_TICKS_PER_SECOND)) { // Limit Jerk if value is so large that it reverts back to trapezoidal. + settings.axis[idx].jerk = settings.axis[idx].acceleration * ACCELERATION_TICKS_PER_SECOND * 60.0f; // mm/min^2 -> mm/min^3 + } + else + settings.axis[idx].jerk = value * 60.0f * 60.0f * 60.0f; // Convert to mm/min^3 for grbl internal use. + break; +#endif - return Status_OK; -} + case Setting_AxisMaxTravel: + if(settings.axis[idx].max_travel != -value) { + bit_false(sys.homed.mask, bit(idx)); + system_add_rt_report(Report_Homed); + } + settings.axis[idx].max_travel = -value; // Store as negative for grbl internal use. + if(settings.homing.flags.init_lock && (sys.homing.mask & sys.homed.mask) != sys.homing.mask) { + system_raise_alarm(Alarm_HomingRequired); + grbl.report.feedback_message(Message_HomingCycleRequired); + } + tmp_set_soft_limits(); + break; -#endif // LATHE_UVW_OPTION + case Setting_AxisBacklash: +#if ENABLE_BACKLASH_COMPENSATION + if(settings.axis[idx].backlash != value) { + axes_signals_t axes; + axes.mask = bit(idx); + settings.axis[idx].backlash = value; + mc_backlash_init(axes); + } +#else + status = Status_SettingDisabled; +#endif + break; -#ifndef NO_SAFETY_DOOR_SUPPORT + case Setting_AxisAutoSquareOffset: + if(hal.stepper.get_ganged && bit_istrue(hal.stepper.get_ganged(true).mask, bit(idx))) + settings.axis[idx].dual_axis_offset = value; + else + status = Status_SettingDisabled; + break; -static status_code_t set_parking_enable (setting_id_t id, uint_fast16_t int_value) -{ - settings.parking.flags.value = bit_istrue(int_value, bit(0)) ? (int_value & 0x07) : 0; + case Setting_AxisHomingFeedRate: + if(settings.homing.flags.per_axis_feedrates) + settings.axis[idx].homing_feed_rate = value; + else + status = Status_SettingDisabled; + break; - return Status_OK; -} + case Setting_AxisHomingSeekRate: + if(settings.homing.flags.per_axis_feedrates) + settings.axis[idx].homing_seek_rate = value; + else + status = Status_SettingDisabled; + break; -static status_code_t set_restore_overrides (setting_id_t id, uint_fast16_t int_value) -{ - settings.flags.restore_overrides = int_value != 0; + default: + status = Status_SettingDisabled; + break; + } - return Status_OK; + return status; } -#endif // NO_SAFETY_DOOR_SUPPORT - -static status_code_t set_sleep_enable (setting_id_t id, uint_fast16_t int_value) +static float get_float (setting_id_t setting) { - settings.flags.sleep_enable = int_value != 0; + float value = 0.0f; - return Status_OK; -} + if(setting >= Setting_AxisSettingsBase && setting <= Setting_AxisSettingsMax) { -static status_code_t set_hold_actions (setting_id_t id, uint_fast16_t int_value) -{ - settings.flags.disable_laser_during_hold = bit_istrue(int_value, bit(0)); - settings.flags.restore_after_feed_hold = bit_istrue(int_value, bit(1)); + uint_fast8_t idx; - return Status_OK; -} + switch(settings_get_axis_base(setting, &idx)) { -#if COMPATIBILITY_LEVEL <= 1 -static status_code_t set_g92_disable_persistence (setting_id_t id, uint_fast16_t int_value) -{ - settings.flags.g92_is_volatile = int_value != 0; + case Setting_AxisStepsPerMM: + value = settings.axis[idx].steps_per_mm; + break; - return Status_OK; -} -#endif + case Setting_AxisMaxRate: + value = settings.axis[idx].max_rate; + break; -static status_code_t set_force_initialization_alarm (setting_id_t id, uint_fast16_t int_value) -{ - settings.flags.force_initialization_alarm = int_value != 0; + case Setting_AxisAcceleration: + value = settings.axis[idx].acceleration / (60.0f * 60.0f); // Convert from mm/min^2 to mm/sec^2. + break; - return Status_OK; -} +#if ENABLE_JERK_ACCELERATION + case Setting_AxisJerk: + value = settings.axis[idx].jerk / (60.0f * 60.0f * 60.0f); // Convert from mm/min^3 to mm/sec^3. + break; +#endif -static status_code_t set_probe_allow_feed_override (setting_id_t id, uint_fast16_t int_value) -{ - settings.probe.allow_feed_override = int_value != 0; - - return Status_OK; -} + case Setting_AxisMaxTravel: + value = -settings.axis[idx].max_travel; // Store as negative for grbl internal use. + break; -static status_code_t set_tool_change_mode (setting_id_t id, uint_fast16_t int_value) -{ - if(!hal.driver_cap.atc && hal.stream.suspend_read && int_value <= ToolChange_Ignore) { -#if COMPATIBILITY_LEVEL > 1 - if((toolchange_mode_t)int_value == ToolChange_Manual_G59_3 || (toolchange_mode_t)int_value == ToolChange_SemiAutomatic) - return Status_InvalidStatement; +#if ENABLE_BACKLASH_COMPENSATION + case Setting_AxisBacklash: + value = settings.axis[idx].backlash; + break; #endif - settings.tool_change.mode = (toolchange_mode_t)int_value; - tc_init(); - } else - return Status_InvalidStatement; - return Status_OK; -} - -static status_code_t set_tool_change_probing_distance (setting_id_t id, float value) -{ - if(hal.driver_cap.atc) - return Status_InvalidStatement; + case Setting_AxisAutoSquareOffset: + value = settings.axis[idx].dual_axis_offset; + break; - settings.tool_change.probing_distance = value; + case Setting_AxisHomingFeedRate: + value = settings.axis[idx].homing_feed_rate; + break; - return Status_OK; -} + case Setting_AxisHomingSeekRate: + value = settings.axis[idx].homing_seek_rate; + break; -static status_code_t set_tool_restore_pos (setting_id_t id, uint_fast16_t int_value) -{ - if(hal.driver_cap.atc) - return Status_InvalidStatement; + default: + break; + } + } else switch(setting) { - settings.flags.no_restore_position_after_M6 = int_value == 0; + case Setting_HomingFeedRate: + value = settings.axis[0].homing_feed_rate; + break; - return Status_OK; -} + case Setting_HomingSeekRate: + value = settings.axis[0].homing_seek_rate; + break; -static inline void set_axis_unit (const setting_detail_t *setting, const char *unit) -{ - // TODO: add length check - if(unit) - strcpy((char *)setting->unit, unit); -} + case Setting_HomingPulloff: + value = settings.homing.pulloff; + break; -#if N_AXIS > 3 + case Setting_ToolChangeProbingDistance: + value = settings.tool_change.probing_distance; + break; -static status_code_t set_rotary_axes (setting_id_t id, uint_fast16_t int_value) -{ - settings.steppers.is_rotary.mask = (int_value << 3) & AXES_BITMASK; + default: + break; + } - return Status_OK; + return value; } -static status_code_t set_rotary_wrap_axes (setting_id_t id, uint_fast16_t int_value) +static uint32_t get_int (setting_id_t id) { - settings.steppers.rotary_wrap.mask = (int_value << 3) & AXES_BITMASK; + uint32_t value = 0; - return Status_OK; -} + switch(id) { -static inline bool axis_is_rotary (uint_fast8_t axis_idx) -{ - return bit_istrue(settings.steppers.is_rotary.mask, bit(axis_idx)); -} +#if COMPATIBILITY_LEVEL > 2 + case Setting_InvertStepperEnable: + value = settings.steppers.enable_invert.mask ? 0 : 1; + break; +#endif -static const char *set_axis_setting_unit (setting_id_t setting_id, uint_fast8_t axis_idx) -{ - char *unit = NULL; +#if COMPATIBILITY_LEVEL > 1 + case Setting_LimitPinsInvertMask: + value = settings.limits.invert.mask == DEFAULT_LIMIT_SIGNALS_INVERT_MASK ? 0 : 1; + break; +#endif - bool is_rotary = axis_is_rotary(axis_idx); + case Setting_SpindlePWMOptions: + value = settings.pwm_spindle.flags.pwm_disable + ? 0 + : (0b001 | + (settings.pwm_spindle.flags.enable_rpm_controlled ? 0b010 : 0) | + (settings.pwm_spindle.flags.laser_mode_disable ? 0b100 : 0)); + break; - switch(setting_id) { + case Setting_Mode: + value = settings.mode; + break; - case Setting_AxisStepsPerMM: - unit = is_rotary ? "step/deg" : "step/mm"; + case Setting_InvertProbePin: + value = settings.probe.invert_probe_pin; + if(hal.driver_cap.toolsetter && settings.probe.invert_toolsetter_input) + value |= 0b10; break; - case Setting_AxisMaxRate: - unit = is_rotary ? "deg/min" : "mm/min"; + case Setting_GangedDirInvertMask: + value = settings.steppers.ganged_dir_invert.mask; break; - case Setting_AxisAcceleration: - unit = is_rotary ? "deg/sec^2" : "mm/sec^2"; + case Setting_StatusReportMask: +#if COMPATIBILITY_LEVEL <= 1 + value = settings.status_report.mask; +#else + value = settings.status_report.mask & 0b11; +#endif break; -#if ENABLE_JERK_ACCELERATION - case Setting_AxisJerk: - unit = is_rotary ? "deg/sec^3" : "mm/sec^3"; + case Setting_ReportInches: + value = settings.flags.report_inches; break; -#endif - case Setting_AxisMaxTravel: - case Setting_AxisBacklash: - unit = is_rotary ? "deg" : "mm"; + case Setting_ControlInvertMask: + value = settings.control_invert.mask & (hal.signals_cap.mask & ~limits_override.mask); break; - default: + case Setting_SpindleInvertMask: + value = settings.pwm_spindle.invert.mask; break; - } - return unit; -} + case Setting_ControlPullUpDisableMask: + value = settings.control_disable_pullup.mask; + break; -#endif + case Setting_ProbePullUpDisable: + value = settings.probe.disable_probe_pullup; + if(hal.driver_cap.toolsetter && settings.probe.disable_toolsetter_pullup) + value |= 0b10; + break; -#if ENABLE_SPINDLE_LINEARIZATION + case Setting_SoftLimitsEnable: + value = settings.limits.soft_enabled.mask != 0; + break; -static status_code_t set_linear_piece (setting_id_t id, char *svalue) -{ - uint32_t idx = id - Setting_LinearSpindlePiece1; - float rpm, start, end; + case Setting_HardLimitsEnable: + value = ((settings.limits.flags.hard_enabled & bit(0)) ? bit(0) | + (settings.limits.flags.check_at_init ? bit(1) : 0) | + (settings.limits.flags.hard_disabled_rotary ? bit(2) : 0) : 0); + break; - if(*svalue == '\0' || (svalue[0] == '0' && svalue[1] == '\0')) { - settings.spindle.pwm_piece[idx].rpm = NAN; - settings.spindle.pwm_piece[idx].start = - settings.spindle.pwm_piece[idx].end = 0.0f; - } else if(sscanf(svalue, "%f,%f,%f", &rpm, &start, &end) == 3) { - settings.spindle.pwm_piece[idx].rpm = rpm; - settings.spindle.pwm_piece[idx].start = start; - settings.spindle.pwm_piece[idx].end = end; -//?? if(idx == 0) -// settings.spindle.rpm_min = rpm; - } else - return Status_SettingValueOutOfRange; + case Setting_JogSoftLimited: + value = settings.limits.flags.jog_soft_limited; + break; - return Status_OK; -} + case Setting_HomingEnable:; +#if COMPATIBILITY_LEVEL <= 1 + homing_settings_flags_t homing = { .value = settings.homing.flags.value }; + homing.two_switches = settings.limits.flags.two_switches; + value = homing.value; +#else + value = settings.homing.flags.enabled; +#endif + break; -static char *get_linear_piece (setting_id_t id) -{ - static char buf[40]; + case Setting_SteppersEnergize: + value = settings.steppers.energize.mask; + break; - uint32_t idx = id - Setting_LinearSpindlePiece1; + case Setting_EnableLegacyRTCommands: + value = settings.flags.legacy_rt_commands; + break; - if(isnan(settings.spindle.pwm_piece[idx].rpm)) - *buf = '\0'; - else - snprintf(buf, sizeof(buf), "%g,%g,%g", settings.spindle.pwm_piece[idx].rpm, settings.spindle.pwm_piece[idx].start, settings.spindle.pwm_piece[idx].end); + case Setting_ParkingEnable: + value = settings.parking.flags.value; + break; - return buf; -} + case Setting_HomingCycle_1: + case Setting_HomingCycle_2: + case Setting_HomingCycle_3: + case Setting_HomingCycle_4: + case Setting_HomingCycle_5: + case Setting_HomingCycle_6: + value = settings.homing.cycle[id - Setting_HomingCycle_1].mask; + break; -#endif + case Setting_RestoreOverrides: + value = settings.flags.restore_overrides; + break; -inline static setting_id_t normalize_id (setting_id_t id) -{ - if((id > Setting_AxisSettingsBase && id <= Setting_AxisSettingsMax) || - (id > Setting_AxisSettingsBase2 && id <= Setting_AxisSettingsMax2)) - id -= id % AXIS_SETTINGS_INCREMENT; - else if(id > Setting_EncoderSettingsBase && id <= Setting_EncoderSettingsMax) - id = (setting_id_t)(Setting_EncoderSettingsBase + (id % ENCODER_SETTINGS_INCREMENT)); - else if(id > Setting_ModbusTCPBase && id <= Setting_ModbusTCPMax) - id = (setting_id_t)(Setting_ModbusTCPBase + (id % MODBUS_TCP_SETTINGS_INCREMENT)); - else if((id > Setting_Macro0 && id <= Setting_Macro9) || - (id > Setting_MacroPort0 && id <= Setting_MacroPort9) || - (id > Setting_ButtonAction0 && id <= Setting_ButtonAction9) || - (id > Setting_Action0 && id <= Setting_Action9) || - (id > Setting_ActionPort0 && id <= Setting_ActionPort9) || - (id > Setting_SpindleToolStart0 && id <= Setting_SpindleToolStart7)) - id = (setting_id_t)(id - (id % 10)); + case Setting_SleepEnable: + value = settings.flags.sleep_enable; + break; - return id; -} + case Setting_HoldActions: + value = (settings.flags.disable_laser_during_hold ? bit(0) : 0) | (settings.flags.restore_after_feed_hold ? bit(1) : 0); + break; -setting_id_t settings_get_axis_base (setting_id_t id, uint_fast8_t *idx) -{ - setting_id_t base = normalize_id(id); - *idx = id - base; + case Setting_ForceInitAlarm: + value = settings.flags.force_initialization_alarm; + break; - return *idx < N_AXIS ? base : Setting_SettingsMax; -} + case Setting_ProbingFeedOverride: + value = settings.probe.allow_feed_override; + break; -static status_code_t set_axis_setting (setting_id_t setting, float value) -{ - uint_fast8_t idx; - status_code_t status = Status_OK; + case Setting_ToolChangeMode: + value = settings.tool_change.mode; + break; - switch(settings_get_axis_base(setting, &idx)) { + case Setting_ToolChangeRestorePosition: + value = settings.flags.no_restore_position_after_M6 ? 0 : 1; + break; - case Setting_AxisStepsPerMM: - if (hal.max_step_rate && value * settings.axis[idx].max_rate > (float)hal.max_step_rate * 60.0f) - status = Status_MaxStepRateExceeded; - else { - if(settings.axis[idx].steps_per_mm > 0.0f && settings.axis[idx].steps_per_mm != value) { - float comp = value / settings.axis[idx].steps_per_mm; - sys.position[idx] *= comp; - sys.home_position[idx] *= comp; - sys.probe_position[idx] *= comp; - sys.tlo_reference[idx] *= comp; - sync_position(); - } - settings.axis[idx].steps_per_mm = value; + case Setting_DisableG92Persistence: + value = settings.flags.g92_is_volatile; + break; + + case Setting_SpindleType: + { + spindle_id_t spindle_id; + spindle_get_id(settings.spindle.ref_id, &spindle_id); + value = (uint32_t)spindle_id; } break; - case Setting_AxisMaxRate: - if (hal.max_step_rate && value * settings.axis[idx].steps_per_mm > (float)hal.max_step_rate * 60.0f) - status = Status_MaxStepRateExceeded; - else - settings.axis[idx].max_rate = value; + case Setting_AutoReportInterval: + value = settings.report_interval; break; - case Setting_AxisAcceleration: - settings.axis[idx].acceleration = override_backup.acceleration[idx] = value * 60.0f * 60.0f; // Convert to mm/min^2 for grbl internal use. +#if N_AXIS > 3 + case Settings_RotaryAxes: + value = (settings.steppers.is_rotary.mask & AXES_BITMASK) >> 3; break; -#if ENABLE_JERK_ACCELERATION - case Setting_AxisJerk: - if ((value * 60.0f * 60.0f) < (settings.axis[idx].acceleration * 10.0f)) { //ensuring that the acceleration ramp time is limited to at maximum 100ms (or 10 stepper segments). - settings.axis[idx].jerk = settings.axis[idx].acceleration * 10.0f * 60.0f; // mm/min^2 -> mm/min^3 - } - else if ((settings.axis[idx].acceleration / (value * 60.0f * 60.0f * 60.0f)) < (1.0f / ACCELERATION_TICKS_PER_SECOND)) { // Limit Jerk if value is so large that it reverts back to trapezoidal. - settings.axis[idx].jerk = settings.axis[idx].acceleration * ACCELERATION_TICKS_PER_SECOND * 60.0f; // mm/min^2 -> mm/min^3 - } - else - settings.axis[idx].jerk = value * 60.0f * 60.0f * 60.0f; // Convert to mm/min^3 for grbl internal use. + case Setting_RotaryWrap: + value = (settings.steppers.rotary_wrap.mask & AXES_BITMASK) >> 3; break; -#endif +#endif - case Setting_AxisMaxTravel: - if(settings.axis[idx].max_travel != -value) { - bit_false(sys.homed.mask, bit(idx)); - system_add_rt_report(Report_Homed); - } - settings.axis[idx].max_travel = -value; // Store as negative for grbl internal use. - if(settings.homing.flags.init_lock && (sys.homing.mask & sys.homed.mask) != sys.homing.mask) { - system_raise_alarm(Alarm_HomingRequired); - grbl.report.feedback_message(Message_HomingCycleRequired); - } - tmp_set_soft_limits(); + case Setting_UnlockAfterEStop: + value = settings.flags.no_unlock_after_estop ? 0 : 1; break; - case Setting_AxisBacklash: -#if ENABLE_BACKLASH_COMPENSATION - if(settings.axis[idx].backlash != value) { - axes_signals_t axes; - axes.mask = bit(idx); - settings.axis[idx].backlash = value; - mc_backlash_init(axes); + case Setting_EncoderSpindle: + { + spindle_id_t spindle_id; + spindle_get_id(settings.spindle.encoder_spindle, &spindle_id); + value = (uint32_t)spindle_id; } -#else - status = Status_SettingDisabled; -#endif break; - case Setting_AxisAutoSquareOffset: - if(hal.stepper.get_ganged && bit_istrue(hal.stepper.get_ganged(true).mask, bit(idx))) - settings.axis[idx].dual_axis_offset = value; - else - status = Status_SettingDisabled; +#if NGC_EXPRESSIONS_ENABLE + case Setting_NGCDebugOut: + value = settings.flags.ngc_debug_out; break; +#endif default: - status = Status_SettingDisabled; break; } - return status; + return value; } -static float get_float (setting_id_t setting) +inline static uint8_t get_decimal_places (const char *format) { - float value = 0.0f; + char *dp = format == NULL ? NULL : strchr(format, '.'); - if (setting >= Setting_AxisSettingsBase && setting <= Setting_AxisSettingsMax2) { + return dp ? strchr(format, '\0') - dp - 1 : 1; +} - uint_fast8_t idx; +char *setting_get_value (const setting_detail_t *setting, uint_fast16_t offset) +{ + char *value = NULL; - switch(settings_get_axis_base(setting, &idx)) { + if(setting == NULL) + return NULL; - case Setting_AxisStepsPerMM: - value = settings.axis[idx].steps_per_mm; - break; + switch(setting->type) { - case Setting_AxisMaxRate: - value = settings.axis[idx].max_rate; - break; + case Setting_NonCore: + case Setting_IsExtended: + case Setting_IsLegacy: + case Setting_IsExpanded: + switch(setting->datatype) { - case Setting_AxisAcceleration: - value = settings.axis[idx].acceleration / (60.0f * 60.0f); // Convert from mm/min^2 to mm/sec^2. - break; + case Format_Decimal: + value = ftoa(*((float *)(setting->value)), get_decimal_places(setting->format)); + break; -#if ENABLE_JERK_ACCELERATION - case Setting_AxisJerk: - value = settings.axis[idx].jerk / (60.0f * 60.0f * 60.0f); // Convert from mm/min^3 to mm/sec^3. - break; -#endif + case Format_Int8: + case Format_Bool: + case Format_Bitfield: + case Format_XBitfield: + case Format_AxisMask: + case Format_RadioButtons: + value = uitoa(*((uint8_t *)(setting->value))); + break; - case Setting_AxisMaxTravel: - value = -settings.axis[idx].max_travel; // Store as negative for grbl internal use. - break; + case Format_Int16: + value = uitoa(*((uint16_t *)(setting->value))); + break; -#if ENABLE_BACKLASH_COMPENSATION - case Setting_AxisBacklash: - value = settings.axis[idx].backlash; - break; -#endif + case Format_Integer: + value = uitoa(*((uint32_t *)(setting->value))); + break; - case Setting_AxisAutoSquareOffset: - value = settings.axis[idx].dual_axis_offset; - break; + case Format_Password: + value = hal.stream.state.webui_connected ? PASSWORD_MASK : ((char *)(setting->value)); + break; - default: // for stopping compiler warning - break; - } - } else switch(setting) { + case Format_String: + case Format_IPv4: + value = ((char *)(setting->value)); + break; - case Setting_ToolChangeProbingDistance: - value = settings.tool_change.probing_distance; + default: + break; + } break; - default: + case Setting_NonCoreFn: + case Setting_IsExtendedFn: + case Setting_IsLegacyFn: + case Setting_IsExpandedFn:; + + setting_id_t id = (setting_id_t)(setting->id + offset); + + switch(setting->datatype) { + + case Format_Decimal: + value = ftoa(((setting_get_float_ptr)(setting->get_value))(id), get_decimal_places(setting->format)); + break; + + case Format_Password: + value = hal.stream.state.webui_connected ? "********" : ((setting_get_string_ptr)(setting->get_value))(id); + break; + + case Format_String: + case Format_IPv4: + value = ((setting_get_string_ptr)(setting->get_value))(id); + break; + + default: + value = uitoa(((setting_get_int_ptr)(setting->get_value))(id)); + break; + } break; } return value; } -static uint32_t get_int (setting_id_t id) +uint32_t setting_get_int_value (const setting_detail_t *setting, uint_fast16_t offset) { uint32_t value = 0; - switch(id) { + if(setting) switch(setting->type) { -#if COMPATIBILITY_LEVEL > 2 - case Setting_InvertStepperEnable: - value = settings.steppers.enable_invert.mask ? 0 : 1; + case Setting_NonCore: + case Setting_IsExtended: + case Setting_IsLegacy: + case Setting_IsExpanded: + switch(setting->datatype) { + + case Format_Int8: + case Format_Bool: + case Format_Bitfield: + case Format_XBitfield: + case Format_AxisMask: + case Format_RadioButtons: + value = *((uint8_t *)(setting->value)); + break; + + case Format_Int16: + value = *((uint16_t *)(setting->value)); + break; + + case Format_Integer: + value = *((uint32_t *)(setting->value)); + break; + + default: + break; + } + break; + + case Setting_NonCoreFn: + case Setting_IsExtendedFn: + case Setting_IsLegacyFn: + case Setting_IsExpandedFn: + switch(setting->datatype) { + + case Format_Decimal: + case Format_String: + case Format_Password: + case Format_IPv4: + break; + + default: + value = ((setting_get_int_ptr)(setting->get_value))((setting_id_t)(setting->id + offset)); + break; + } + break; + } + + return value; +} + +float setting_get_float_value (const setting_detail_t *setting, uint_fast16_t offset) +{ + float value = NAN; + + if(setting && setting->datatype == Format_Decimal) switch(setting->type) { + + case Setting_NonCore: + case Setting_IsExtended: + case Setting_IsLegacy: + case Setting_IsExpanded: + value = *((float *)(setting->value)); + break; + + case Setting_NonCoreFn: + case Setting_IsExtendedFn: + case Setting_IsLegacyFn: + case Setting_IsExpandedFn: + value = ((setting_get_float_ptr)(setting->get_value))((setting_id_t)(setting->id + offset)); break; + + default: + break; + } + + return value; +} + +static bool is_group_available (const setting_detail_t *setting) +{ + return settings_is_group_available(setting->group); +} + +static bool is_setting_available (const setting_detail_t *setting) +{ + bool available = false; + + if(setting) switch(normalize_id(setting->id)) { + + case Setting_GangedDirInvertMask: + available = hal.stepper.get_ganged && hal.stepper.get_ganged(false).mask != 0; + break; + + case Setting_ProbingFeedOverride: +// case Setting_ToolChangeProbingDistance: +// case Setting_ToolChangeFeedRate: +// case Setting_ToolChangeSeekRate: + available = hal.probe.get_state != NULL; + break; + + case Setting_SpindlePWMBehaviour: + available = false; + break; + + case Setting_SpindlePWMOptions: + available = hal.driver_cap.pwm_spindle && spindle_get_caps(false).laser; + break; + + case Setting_SpindleInvertMask: + available = spindle_get_caps(false).gpio_controlled; + break; + + case Setting_PWMFreq: + case Setting_PWMOffValue: + case Setting_PWMMinValue: + case Setting_PWMMaxValue: + available = hal.driver_cap.pwm_spindle; + break; + + case Setting_SpindleType: + available = spindle_get_count() > 1; + break; + + case Setting_SpindlePPR: + available = hal.driver_cap.spindle_encoder; + break; + + case Setting_RpmMax: + case Setting_RpmMin: + available = spindle_get_caps(false).variable; + break; + + case Setting_SleepEnable: + available = SLEEP_DURATION > 0.0f; + break; + + case Setting_DualAxisLengthFailPercent: + case Setting_DualAxisLengthFailMin: + case Setting_DualAxisLengthFailMax: + case Setting_AxisAutoSquareOffset: + available = hal.stepper.get_ganged && hal.stepper.get_ganged(true).mask != 0; +// available = hal.stepper.get_ganged && bit_istrue(hal.stepper.get_ganged(true).mask, setting->id - Setting_AxisAutoSquareOffset); + break; + + case Setting_AxisHomingFeedRate: + case Setting_AxisHomingSeekRate: + available = settings.homing.flags.per_axis_feedrates; + break; + +#ifndef NO_SAFETY_DOOR_SUPPORT + + case Setting_ParkingEnable: + case Setting_ParkingAxis: + case Setting_ParkingPulloutIncrement: + case Setting_ParkingPulloutRate: + case Setting_ParkingTarget: + case Setting_ParkingFastRate: + case Setting_RestoreOverrides: + case Setting_DoorOptions: + available = hal.signals_cap.safety_door_ajar; + break; + + case Setting_DoorSpindleOnDelay: + available = hal.signals_cap.safety_door_ajar && spindle_get_count() && !spindle_get_caps(true).at_speed; + break; + + case Setting_DoorCoolantOnDelay: + available = hal.signals_cap.safety_door_ajar && hal.coolant_cap.mask; + break; +#endif + + case Setting_SpindleAtSpeedTolerance: + available = spindle_get_caps(true).at_speed || hal.driver_cap.spindle_encoder; + break; + + case Setting_SpindleOnDelay: + available = !hal.signals_cap.safety_door_ajar && spindle_get_count() && !spindle_get_caps(true).at_speed; + break; + + case Setting_AutoReportInterval: + available = hal.get_elapsed_ticks != NULL; + break; + + case Setting_TimeZoneOffset: + available = hal.rtc.set_datetime != NULL; + break; + + case Setting_UnlockAfterEStop: + available = hal.signals_cap.e_stop; + break; + + case Setting_EncoderSpindle: + available = hal.driver_cap.spindle_encoder && spindle_get_count() > 1; + break; + + case Setting_FSOptions: + available = hal.driver_cap.sd_card || hal.driver_cap.littlefs; + break; + + case Setting_HomePinsInvertMask: + available = hal.homing.get_state != NULL && hal.home_cap.a.mask != 0; + break; + + case Setting_HoldCoolantOnDelay: + available = !hal.signals_cap.safety_door_ajar && hal.coolant_cap.mask; + break; + + default: + break; + } + + return available; +} + +static bool toolsetter_available (const setting_detail_t *setting) +{ + bool available = false; + +#if COMPATIBILITY_LEVEL <= 1 + + if(hal.probe.get_state && hal.driver_cap.toolsetter) switch(setting->id) { + + case Setting_InvertProbePin: + available = true; + break; + + case Setting_ProbePullUpDisable: + available = hal.signals_pullup_disable_cap.probe_triggered; + break; + + default: + break; + } + +#endif + + return available; +} + +static bool no_toolsetter_available (const setting_detail_t *setting) +{ +#if COMPATIBILITY_LEVEL <= 1 + + bool available = false; + + if(hal.probe.get_state && !hal.driver_cap.toolsetter) switch(setting->id) { + + case Setting_InvertProbePin: + available = true; + break; + + case Setting_ProbePullUpDisable: + available = hal.signals_pullup_disable_cap.probe_triggered; + break; + + default: + break; + } + + return available; + +#else + + return !!hal.probe.get_state; + +#endif +} + +PROGMEM static const setting_detail_t setting_detail[] = { + { Setting_PulseMicroseconds, Group_Stepper, "Step pulse time", "microseconds", Format_Decimal, "#0.0", "2.0", NULL, Setting_IsLegacy, &settings.steppers.pulse_microseconds, NULL, NULL }, + { Setting_StepperIdleLockTime, Group_Stepper, "Step idle delay", "milliseconds", Format_Int16, "####0", NULL, "65535", Setting_IsLegacy, &settings.steppers.idle_lock_time, NULL, NULL }, + { Setting_StepInvertMask, Group_Stepper, "Step pulse invert", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsLegacy, &settings.steppers.step_invert.mask, NULL, NULL }, + { Setting_DirInvertMask, Group_Stepper, "Step direction invert", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsLegacy, &settings.steppers.dir_invert.mask, NULL, NULL }, +#if COMPATIBILITY_LEVEL <= 2 + { Setting_InvertStepperEnable, Group_Stepper, "Invert stepper enable output(s)", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsLegacy, &settings.steppers.enable_invert.mask, NULL, NULL }, +#else + { Setting_InvertStepperEnable, Group_Stepper, "Invert stepper enable output", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsLegacyFn, set_enable_invert_mask, get_int, NULL }, +#endif +#if COMPATIBILITY_LEVEL <= 1 + { Setting_LimitPinsInvertMask, Group_Limits, "Invert limit inputs", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsLegacy, &settings.limits.invert.mask, NULL, NULL }, +#else + { Setting_LimitPinsInvertMask, Group_Limits, "Invert limit inputs", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsLegacyFn, set_limits_invert_mask, get_int, NULL }, +#endif + { Setting_InvertProbePin, Group_Probing, "Invert probe input", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsLegacyFn, set_probe_invert, get_int, no_toolsetter_available }, + { Setting_InvertProbePin, Group_Probing, "Invert probe inputs", NULL, Format_Bitfield, "Probe,Toolsetter", NULL, NULL, Setting_IsLegacyFn, set_probe_invert, get_int, toolsetter_available }, + { Setting_SpindlePWMBehaviour, Group_Spindle, "Deprecated", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsLegacyFn, set_pwm_mode, get_int, is_setting_available }, + { Setting_GangedDirInvertMask, Group_Stepper, "Ganged axes direction invert", NULL, Format_Bitfield, ganged_axes, NULL, NULL, Setting_IsExtendedFn, set_ganged_dir_invert, get_int, is_setting_available }, + { Setting_SpindlePWMOptions, Group_Spindle, "PWM Spindle", NULL, Format_XBitfield, "Enable,RPM controls spindle enable signal,Disable laser mode capability", NULL, NULL, Setting_IsExtendedFn, set_pwm_options, get_int, is_setting_available }, +#if COMPATIBILITY_LEVEL <= 1 + { Setting_StatusReportMask, Group_General, "Status report options", NULL, Format_Bitfield, "Position in machine coordinate,Buffer state,Line numbers,Feed & speed,Pin state,Work coordinate offset,Overrides,Probe coordinates,Buffer sync on WCO change,Parser state,Alarm substatus,Run substatus,Enable when homing", NULL, NULL, Setting_IsExtendedFn, set_report_mask, get_int, NULL }, +#else + { Setting_StatusReportMask, Group_General, "Status report options", NULL, Format_Bitfield, "Position in machine coordinate,Buffer state", NULL, NULL, Setting_IsLegacyFn, set_report_mask, get_int, NULL }, +#endif + { Setting_JunctionDeviation, Group_General, "Junction deviation", "mm", Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacy, &settings.junction_deviation, NULL, NULL }, + { Setting_ArcTolerance, Group_General, "Arc tolerance", "mm", Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacy, &settings.arc_tolerance, NULL, NULL }, + { Setting_ReportInches, Group_General, "Report in inches", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsLegacyFn, set_report_inches, get_int, NULL }, + { Setting_ControlInvertMask, Group_ControlSignals, "Invert control inputs", NULL, Format_Bitfield, control_signals, NULL, NULL, Setting_IsExpandedFn, set_control_invert, get_int, NULL }, + { Setting_CoolantInvertMask, Group_Coolant, "Invert coolant outputs", NULL, Format_Bitfield, coolant_signals, NULL, NULL, Setting_IsExtended, &settings.coolant.invert.mask, NULL, NULL }, + { Setting_SpindleInvertMask, Group_Spindle, "Invert spindle signals", NULL, Format_Bitfield, spindle_signals, NULL, NULL, Setting_IsExtendedFn, set_spindle_invert, get_int, is_setting_available, { .reboot_required = On } }, + { Setting_ControlPullUpDisableMask, Group_ControlSignals, "Pullup disable control inputs", NULL, Format_Bitfield, control_signals, NULL, NULL, Setting_IsExtendedFn, set_control_disable_pullup, get_int, NULL }, + { Setting_LimitPullUpDisableMask, Group_Limits, "Pullup disable limit inputs", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtended, &settings.limits.disable_pullup.mask, NULL, NULL }, + { Setting_ProbePullUpDisable, Group_Probing, "Pullup disable probe input", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_probe_disable_pullup, get_int, no_toolsetter_available }, + { Setting_ProbePullUpDisable, Group_Probing, "Pullup disable probe inputs", NULL, Format_Bitfield, "Probe,Toolsetter", NULL, NULL, Setting_IsLegacyFn, set_probe_disable_pullup, get_int, toolsetter_available }, + { Setting_SoftLimitsEnable, Group_Limits, "Soft limits enable", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsLegacyFn, set_soft_limits_enable, get_int, NULL }, +#if COMPATIBILITY_LEVEL <= 1 + #if N_AXIS > 3 + { Setting_HardLimitsEnable, Group_Limits, "Hard limits enable", NULL, Format_XBitfield, "Enable,Strict mode,Disable for rotary axes", NULL, NULL, Setting_IsExpandedFn, set_hard_limits_enable, get_int, NULL }, + #else + { Setting_HardLimitsEnable, Group_Limits, "Hard limits enable", NULL, Format_XBitfield, "Enable,Strict mode", NULL, NULL, Setting_IsExpandedFn, set_hard_limits_enable, get_int, NULL }, + #endif +#else + { Setting_HardLimitsEnable, Group_Limits, "Hard limits enable", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsLegacyFn, set_hard_limits_enable, get_int, NULL }, +#endif +#if COMPATIBILITY_LEVEL <= 1 + { Setting_HomingEnable, Group_Homing, "Homing cycle", NULL, Format_XBitfield, homing_options, NULL, NULL, Setting_IsExpandedFn, set_homing_enable, get_int, NULL }, +#else + { Setting_HomingEnable, Group_Homing, "Homing cycle enable", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsLegacyFn, set_homing_enable, get_int, NULL }, +#endif + { Setting_HomingDirMask, Group_Homing, "Homing direction invert", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsLegacy, &settings.homing.dir_mask.value, NULL, NULL }, + { Setting_HomingFeedRate, Group_Homing, "Homing locate feed rate", "mm/min", Format_Decimal, "#####0.0", NULL, NULL, Setting_IsLegacyFn, set_homing_feedrates, get_float, NULL }, + { Setting_HomingSeekRate, Group_Homing, "Homing search seek rate", "mm/min", Format_Decimal, "#####0.0", NULL, NULL, Setting_IsLegacyFn, set_homing_feedrates, get_float, NULL }, + { Setting_HomingDebounceDelay, Group_Homing, "Homing switch debounce delay", "milliseconds", Format_Int16, "##0", NULL, NULL, Setting_IsLegacy, &settings.homing.debounce_delay, NULL, NULL }, + { Setting_HomingPulloff, Group_Homing, "Homing switch pull-off distance", "mm", Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_homing_pulloff, get_float, NULL }, + { Setting_G73Retract, Group_General, "G73 Retract distance", "mm", Format_Decimal, "#####0.000", NULL, NULL, Setting_IsExtended, &settings.g73_retract, NULL, NULL }, + { Setting_PulseDelayMicroseconds, Group_Stepper, "Pulse delay", "microseconds", Format_Decimal, "#0.0", NULL, "20", Setting_IsExtended, &settings.steppers.pulse_delay_microseconds, NULL, NULL }, + { Setting_RpmMax, Group_Spindle, "Maximum spindle speed", "RPM", Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacy, &settings.pwm_spindle.rpm_max, NULL, is_setting_available }, + { Setting_RpmMin, Group_Spindle, "Minimum spindle speed", "RPM", Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacy, &settings.pwm_spindle.rpm_min, NULL, is_setting_available }, +#if !LATHE_UVW_OPTION + { Setting_Mode, Group_General, "Mode of operation", NULL, Format_RadioButtons, "Normal,Laser mode,Lathe mode", NULL, NULL, Setting_IsLegacyFn, set_mode, get_int, NULL }, +#endif + { Setting_PWMFreq, Group_Spindle, "Spindle PWM frequency", "Hz", Format_Decimal, "#####0", NULL, NULL, Setting_IsExtended, &settings.pwm_spindle.pwm_freq, NULL, is_setting_available }, + { Setting_PWMOffValue, Group_Spindle, "Spindle PWM off value", "percent", Format_Decimal, "##0.0", NULL, "100", Setting_IsExtended, &settings.pwm_spindle.pwm_off_value, NULL, is_setting_available }, + { Setting_PWMMinValue, Group_Spindle, "Spindle PWM min value", "percent", Format_Decimal, "##0.0", NULL, "100", Setting_IsExtended, &settings.pwm_spindle.pwm_min_value, NULL, is_setting_available }, + { Setting_PWMMaxValue, Group_Spindle, "Spindle PWM max value", "percent", Format_Decimal, "##0.0", NULL, "100", Setting_IsExtended, &settings.pwm_spindle.pwm_max_value, NULL, is_setting_available }, + { Setting_SteppersEnergize, Group_Stepper, "Steppers to keep enabled", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_stepper_energize_mask, get_int, NULL }, + { Setting_SpindlePPR, Group_Spindle, "Spindle pulses per revolution (PPR)", NULL, Format_Int16, "###0", NULL, NULL, Setting_IsExtended, &settings.spindle.ppr, NULL, is_setting_available, { .reboot_required = On } }, + { Setting_EnableLegacyRTCommands, Group_General, "Enable legacy RT commands", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_enable_legacy_rt_commands, get_int, NULL }, + { Setting_JogSoftLimited, Group_Jogging, "Limit jog commands", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_jog_soft_limited, get_int, NULL }, +#ifndef NO_SAFETY_DOOR_SUPPORT + { Setting_ParkingEnable, Group_SafetyDoor, "Parking cycle", NULL, Format_XBitfield, "Enable,Enable parking override control,Deactivate upon init", NULL, NULL, Setting_IsExtendedFn, set_parking_enable, get_int, is_setting_available }, + { Setting_ParkingAxis, Group_SafetyDoor, "Parking axis", NULL, Format_RadioButtons, "X,Y,Z", NULL, NULL, Setting_IsExtended, &settings.parking.axis, NULL, is_setting_available }, +#endif + { Setting_HomingLocateCycles, Group_Homing, "Homing passes", NULL, Format_Int8, "##0", "1", "128", Setting_IsExtended, &settings.homing.locate_cycles, NULL, NULL }, + { Setting_HomingCycle_1, Group_Homing, "Axes homing, first pass", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_homing_cycle, get_int, NULL }, + { Setting_HomingCycle_2, Group_Homing, "Axes homing, second pass", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_homing_cycle, get_int, NULL }, + { Setting_HomingCycle_3, Group_Homing, "Axes homing, third pass", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_homing_cycle, get_int, NULL }, +#ifdef A_AXIS + { Setting_HomingCycle_4, Group_Homing, "Axes homing, fourth pass", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_homing_cycle, get_int, NULL }, +#endif +#ifdef B_AXIS + { Setting_HomingCycle_5, Group_Homing, "Axes homing, fifth pass", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_homing_cycle, get_int, NULL }, +#endif +#ifdef C_AXIS + { Setting_HomingCycle_6, Group_Homing, "Axes homing, sixth pass", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_homing_cycle, get_int, NULL }, +#endif +#ifndef NO_SAFETY_DOOR_SUPPORT + { Setting_ParkingPulloutIncrement, Group_SafetyDoor, "Parking pull-out distance", "mm", Format_Decimal, "###0.0", NULL, NULL, Setting_IsExtended, &settings.parking.pullout_increment, NULL, is_setting_available }, + { Setting_ParkingPulloutRate, Group_SafetyDoor, "Parking pull-out rate", "mm/min", Format_Decimal, "###0.0", NULL, NULL, Setting_IsExtended, &settings.parking.pullout_rate, NULL, is_setting_available }, + { Setting_ParkingTarget, Group_SafetyDoor, "Parking target", "mm", Format_Decimal, "-###0.0", "-100000", NULL, Setting_IsExtended, &settings.parking.target, NULL, is_setting_available }, + { Setting_ParkingFastRate, Group_SafetyDoor, "Parking fast rate", "mm/min", Format_Decimal, "###0.0", NULL, NULL, Setting_IsExtended, &settings.parking.rate, NULL, is_setting_available }, + { Setting_RestoreOverrides, Group_General, "Restore overrides", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_restore_overrides, get_int, is_setting_available }, + { Setting_DoorOptions, Group_SafetyDoor, "Safety door options", NULL, Format_Bitfield, "Ignore when idle,Keep coolant state on open", NULL, NULL, Setting_IsExtended, &settings.safety_door.flags.value, NULL, is_setting_available }, +#endif + { Setting_SleepEnable, Group_General, "Sleep enable", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_sleep_enable, get_int, is_setting_available }, + { Setting_HoldActions, Group_General, "Feed hold actions", NULL, Format_Bitfield, "Disable laser during hold,Restore spindle and coolant state on resume", NULL, NULL, Setting_IsExtendedFn, set_hold_actions, get_int, NULL }, + { Setting_ForceInitAlarm, Group_General, "Force init alarm", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_force_initialization_alarm, get_int, NULL }, + { Setting_ProbingFeedOverride, Group_Probing, "Probing feed override", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_probe_allow_feed_override, get_int, is_setting_available }, +#if ENABLE_SPINDLE_LINEARIZATION + { Setting_LinearSpindlePiece1, Group_Spindle, "Spindle linearisation, 1st point", NULL, Format_String, "x(39)", NULL, "39", Setting_IsExtendedFn, set_linear_piece, get_linear_piece, NULL }, + #if SPINDLE_NPWM_PIECES > 1 + { Setting_LinearSpindlePiece2, Group_Spindle, "Spindle linearisation, 2nd point", NULL, Format_String, "x(39)", NULL, "39", Setting_IsExtendedFn, set_linear_piece, get_linear_piece, NULL }, + #endif + #if SPINDLE_NPWM_PIECES > 2 + { Setting_LinearSpindlePiece3, Group_Spindle, "Spindle linearisation, 3rd point", NULL, Format_String, "x(39)", NULL, "39", Setting_IsExtendedFn, set_linear_piece, get_linear_piece, NULL }, + #endif + #if SPINDLE_NPWM_PIECES > 3 + { Setting_LinearSpindlePiece4, Group_Spindle, "Spindle linearisation, 4th point", NULL, Format_String, "x(39)", NULL, "39", Setting_IsExtendedFn, set_linear_piece, get_linear_piece, NULL }, + #endif +#endif + { Setting_PositionPGain, Group_Spindle_Sync, "Spindle sync P-gain", NULL, Format_Decimal, "###0.000", NULL, NULL, Setting_IsExtended, &settings.position.pid.p_gain, NULL, is_group_available }, + { Setting_PositionIGain, Group_Spindle_Sync, "Spindle sync I-gain", NULL, Format_Decimal, "###0.000", NULL, NULL, Setting_IsExtended, &settings.position.pid.i_gain, NULL, is_group_available }, + { Setting_PositionDGain, Group_Spindle_Sync, "Spindle sync D-gain", NULL, Format_Decimal, "###0.000", NULL, NULL, Setting_IsExtended, &settings.position.pid.d_gain, NULL, is_group_available }, + { Setting_PositionIMaxError, Group_Spindle_Sync, "Spindle sync PID max I error", NULL, Format_Decimal, "###0.000", NULL, NULL, Setting_IsExtended, &settings.position.pid.i_max_error, NULL, is_group_available }, + { Setting_AxisStepsPerMM, Group_Axis0, "-axis travel resolution", axis_steps, Format_Decimal, "#####0.000##", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, + { Setting_AxisMaxRate, Group_Axis0, "-axis maximum rate", axis_rate, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, + { Setting_AxisAcceleration, Group_Axis0, "-axis acceleration", axis_accel, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, + { Setting_AxisMaxTravel, Group_Axis0, "-axis maximum travel", axis_dist, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, +#if ENABLE_BACKLASH_COMPENSATION + { Setting_AxisBacklash, Group_Axis0, "-axis backlash compensation", axis_dist, Format_Decimal, "#####0.000##", NULL, NULL, Setting_IsExtendedFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, +#endif + { Setting_AxisAutoSquareOffset, Group_Axis0, "-axis dual axis offset", "mm", Format_Decimal, "-0.000", "-10", "10", Setting_IsExtendedFn, set_axis_setting, get_float, is_setting_available, AXIS_OPTS }, + { Setting_AxisHomingFeedRate, Group_Axis0, "-axis homing locate feed rate", axis_rate, Format_Decimal, "###0", NULL, NULL, Setting_NonCoreFn, set_axis_setting, get_float, is_setting_available, AXIS_OPTS }, + { Setting_AxisHomingSeekRate, Group_Axis0, "-axis homing search seek rate", axis_rate, Format_Decimal, "###0", NULL, NULL, Setting_NonCoreFn, set_axis_setting, get_float, is_setting_available, AXIS_OPTS }, + { Setting_SpindleAtSpeedTolerance, Group_Spindle, "Spindle at speed tolerance", "percent", Format_Decimal, "##0.0", NULL, NULL, Setting_IsExtended, &settings.pwm_spindle.at_speed_tolerance, NULL, is_setting_available }, + { Setting_ToolChangeMode, Group_Toolchange, "Tool change mode", NULL, Format_RadioButtons, "Normal,Manual touch off,Manual touch off @ G59.3,Automatic touch off @ G59.3,Ignore M6", NULL, NULL, Setting_IsExtendedFn, set_tool_change_mode, get_int, NULL }, + { Setting_ToolChangeProbingDistance, Group_Toolchange, "Tool change probing distance", "mm", Format_Decimal, "#####0.0", NULL, NULL, Setting_IsExtendedFn, set_tool_change_probing_distance, get_float, NULL }, + { Setting_ToolChangeFeedRate, Group_Toolchange, "Tool change locate feed rate", "mm/min", Format_Decimal, "#####0.0", NULL, NULL, Setting_IsExtended, &settings.tool_change.feed_rate, NULL, NULL }, + { Setting_ToolChangeSeekRate, Group_Toolchange, "Tool change search seek rate", "mm/min", Format_Decimal, "#####0.0", NULL, NULL, Setting_IsExtended, &settings.tool_change.seek_rate, NULL, NULL }, + { Setting_ToolChangePulloffRate, Group_Toolchange, "Tool change probe pull-off rate", "mm/min", Format_Decimal, "#####0.0", NULL, NULL, Setting_IsExtended, &settings.tool_change.pulloff_rate, NULL, NULL }, + { Setting_ToolChangeRestorePosition, Group_Toolchange, "Restore position after M6", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_tool_restore_pos, get_int, NULL }, + { Setting_DualAxisLengthFailPercent, Group_Limits_DualAxis, "Dual axis length fail", "percent", Format_Decimal, "##0.0", "0", "100", Setting_IsExtended, &settings.homing.dual_axis.fail_length_percent, NULL, is_setting_available }, + { Setting_DualAxisLengthFailMin, Group_Limits_DualAxis, "Dual axis length fail min", "mm", Format_Decimal, "#####0.000", NULL, NULL, Setting_IsExtended, &settings.homing.dual_axis.fail_distance_min, NULL, is_setting_available }, + { Setting_DualAxisLengthFailMax, Group_Limits_DualAxis, "Dual axis length fail max", "mm", Format_Decimal, "#####0.000", NULL, NULL, Setting_IsExtended, &settings.homing.dual_axis.fail_distance_max, NULL, is_setting_available }, +#if COMPATIBILITY_LEVEL <= 1 + { Setting_DisableG92Persistence, Group_General, "Disable G92 persistence", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_g92_disable_persistence, get_int, NULL }, +#endif +#if N_AXIS > 3 + { Settings_RotaryAxes, Group_Stepper, "Rotary axes", NULL, Format_Bitfield, rotary_axes, NULL, NULL, Setting_IsExtendedFn, set_rotary_axes, get_int, NULL }, +#endif +#ifndef NO_SAFETY_DOOR_SUPPORT + { Setting_DoorSpindleOnDelay, Group_SafetyDoor, "Spindle on delay", "s", Format_Decimal, "#0.0", "0.5", "20", Setting_IsExtended, &settings.safety_door.spindle_on_delay, NULL, is_setting_available }, + { Setting_DoorCoolantOnDelay, Group_SafetyDoor, "Coolant on delay", "s", Format_Decimal, "#0.0", "0.5", "20", Setting_IsExtended, &settings.safety_door.coolant_on_delay, NULL, is_setting_available }, +#endif + { Setting_SpindleOnDelay, Group_Spindle, "Spindle on delay", "s", Format_Decimal, "#0.0", "0.5", "20", Setting_IsExtended, &settings.safety_door.spindle_on_delay, NULL, is_setting_available }, + { Setting_SpindleType, Group_Spindle, "Default spindle", NULL, Format_RadioButtons, spindle_types, NULL, NULL, Setting_IsExtendedFn, set_default_spindle, get_int, is_setting_available }, + { Setting_PlannerBlocks, Group_General, "Planner buffer blocks", NULL, Format_Int16, "####0", "30", "1000", Setting_IsExtended, &settings.planner_buffer_blocks, NULL, NULL, { .reboot_required = On } }, + { Setting_AutoReportInterval, Group_General, "Autoreport interval", "ms", Format_Int16, "###0", "100", "1000", Setting_IsExtendedFn, set_report_interval, get_int, NULL, { .reboot_required = On, .allow_null = On } }, +// { Setting_TimeZoneOffset, Group_General, "Timezone offset", NULL, Format_Decimal, "-#0.00", "0", "12", Setting_IsExtended, &settings.timezone, NULL, NULL }, + { Setting_UnlockAfterEStop, Group_General, "Unlock required after E-Stop", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_estop_unlock, get_int, is_setting_available }, +#if NGC_EXPRESSIONS_ENABLE + { Setting_NGCDebugOut, Group_General, "Output NGC debug messages", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_ngc_debug_out, get_int, NULL }, +#endif +#if COMPATIBILITY_LEVEL <= 1 + { Setting_OffsetLock, Group_General, "Lock coordinate systems", NULL, Format_Bitfield, "G59.1,G59.2,G59.3", NULL, NULL, Setting_IsExtended, &settings.offset_lock.mask, NULL, NULL }, +#endif + { Setting_EncoderSpindle, Group_Spindle, "Encoder spindle", NULL, Format_RadioButtons, spindle_types, NULL, NULL, Setting_IsExtendedFn, set_encoder_spindle, get_int, is_setting_available }, +#if N_AXIS > 3 + { Setting_RotaryWrap, Group_Stepper, "Fast rotary go to G28", NULL, Format_Bitfield, rotary_axes, NULL, NULL, Setting_IsExtendedFn, set_rotary_wrap_axes, get_int, NULL }, +#endif + { Setting_FSOptions, Group_General, "File systems options", NULL, Format_Bitfield, fs_options, NULL, NULL, Setting_IsExtended, &settings.fs_options.mask, NULL, is_setting_available }, + { Setting_HomePinsInvertMask, Group_Limits, "Invert home inputs", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtended, &settings.home_invert.mask, NULL, is_setting_available }, + { Setting_HoldCoolantOnDelay, Group_Coolant, "Coolant on delay", "s", Format_Decimal, "#0.0", "0.5", "20", Setting_IsExtended, &settings.safety_door.coolant_on_delay, NULL, is_setting_available } +}; + +#ifndef NO_SETTINGS_DESCRIPTIONS + +PROGMEM static const setting_descr_t setting_descr[] = { + { Setting_PulseMicroseconds, "Sets time length per step. Minimum 2 microseconds.\\n\\n" + "This needs to be reduced from the default value of 10 when max. step rates exceed approximately 80 kHz." + }, + { Setting_StepperIdleLockTime, "Sets a short hold delay when stopping to let dynamics settle before disabling steppers. Value 255 keeps motors enabled." }, + { Setting_StepInvertMask, "Inverts the step signals (active low)." }, + { Setting_DirInvertMask, "Inverts the direction signals (active low)." }, +#if COMPATIBILITY_LEVEL <= 2 + { Setting_InvertStepperEnable, "Inverts the stepper driver enable signals. Most drivers uses active low enable requiring inversion.\\n\\n" + "NOTE: If the stepper drivers shares the same enable signal only X is used." + }, +#else + { Setting_InvertStepperEnable, "Inverts the stepper driver enable signals. Drivers using active high enable require inversion.\\n\\n" }, +#endif + { Setting_LimitPinsInvertMask, "Inverts the axis limit input signals." }, + { Setting_InvertProbePin, "Inverts the probe input signal(s)." }, + { Setting_SpindlePWMOptions, "Enable controls PWM output availability.\\n" + "When `RPM controls spindle enable signal` is checked and M3 or M4 is active S0 switches it off and S > 0 switches it on." + }, + { Setting_GangedDirInvertMask, "Inverts the direction signals for the second motor used for ganged axes.\\n\\n" + "NOTE: This inversion will be applied in addition to the inversion from setting $3." + }, + { Setting_StatusReportMask, "Specifies optional data included in status reports and if report is sent when homing.\\n" + "If Run substatus is enabled it may be used for simple probe protection.\\n\\n" + "NOTE: Parser state will be sent separately after the status report and only on changes." + }, + { Setting_JunctionDeviation, "Sets how fast grblHAL travels through consecutive motions. Lower value slows it down." }, + { Setting_ArcTolerance, "Sets the G2 and G3 arc tracing accuracy based on radial error. Beware: A very small value may effect performance." }, + { Setting_ReportInches, "Enables inch units when returning any position and rate value that is not a settings value." }, + { Setting_ControlInvertMask, "Inverts the control signals (active low).\\n" + "NOTE: Block delete, Optional stop, EStop and Probe connected are optional signals, availability is driver dependent." + }, + { Setting_CoolantInvertMask, "Inverts the coolant and mist signals (active low)." }, + { Setting_SpindleInvertMask, "Inverts the spindle on, counterclockwise and PWM signals (active low)." }, + { Setting_ControlPullUpDisableMask, "Disable the control signals pullup resistors. Potentially enables pulldown resistor if available.\\n" + "NOTE: Block delete, Optional stop and EStop are optional signals, availability is driver dependent." + }, + { Setting_LimitPullUpDisableMask, "Disable the limit signals pullup resistors. Potentially enables pulldown resistors if available."}, + { Setting_ProbePullUpDisable, "Disable the probe signal pullup resistor(s). Potentially enables pulldown resistor(s) if available." }, + { Setting_SoftLimitsEnable, "Enables soft limits checks within machine travel and sets alarm when exceeded. Requires homing." }, + { Setting_HardLimitsEnable, "When enabled immediately halts motion and throws an alarm when a limit switch is triggered. In strict mode only homing is possible when a switch is engaged." }, + { Setting_HomingEnable, "Enables homing cycle. Requires limit switches on axes to be automatically homed.\\n\\n" + "When `Enable single axis commands` is checked, single axis homing can be performed by $H commands.\\n\\n" + "When `Allow manual` is checked, axes not homed automatically may be homed manually by $H or $H commands.\\n\\n" + "`Override locks` is for allowing a soft reset to disable `Homing on startup required`." + }, + { Setting_HomingDirMask, "Homing searches for a switch in the positive direction. Set axis bit to search in negative direction." }, + { Setting_HomingFeedRate, "Feed rate to slowly engage limit switch to determine its location accurately." }, + { Setting_HomingSeekRate, "Seek rate to quickly find the limit switch before the slower locating phase." }, + { Setting_HomingDebounceDelay, "Sets a short delay between phases of homing cycle to let a switch debounce." }, + { Setting_HomingPulloff, "Retract distance after triggering switch to disengage it. Homing will fail if switch isn't cleared." }, + { Setting_G73Retract, "G73 retract distance (for chip breaking drilling)." }, + { Setting_PulseDelayMicroseconds, "Step pulse delay.\\n\\n" + "Normally leave this at 0 as there is an implicit delay on direction changes when AMASS is active." + }, + { Setting_RpmMax, "Maximum spindle speed, can be overridden by spindle plugins." }, + { Setting_RpmMin, "Minimum spindle speed, can be overridden by spindle plugins.\\n\\n" + "When set > 0 $35 (PWM min value) may have to be set to get the configured RPM."}, +#if !LATHE_UVW_OPTION + { Setting_Mode, "Laser mode: consecutive G1/2/3 commands will not halt when spindle speed is changed.\\n" + "Lathe mode: allows use of G7, G8, G96 and G97." + }, +#endif + { Setting_PWMFreq, "Spindle PWM frequency." }, + { Setting_PWMOffValue, "Spindle PWM off value in percent (duty cycle)." }, + { Setting_PWMMinValue, "Spindle PWM min value in percent (duty cycle)." }, + { Setting_PWMMaxValue, "Spindle PWM max value in percent (duty cycle)." }, + { Setting_SteppersEnergize, "Specifies which steppers not to disable when stopped." }, + { Setting_SpindlePPR, "Spindle encoder pulses per revolution." }, + { Setting_EnableLegacyRTCommands, "Enables \"normal\" processing of ?, ! and ~ characters when part of $-setting or comment. If disabled then they are added to the input string instead." }, + { Setting_JogSoftLimited, "Limit jog commands to machine limits for homed axes." }, + { Setting_ParkingEnable, "Enables parking cycle, requires parking axis homed." }, + { Setting_ParkingAxis, "Define which axis that performs the parking motion." }, + { Setting_HomingLocateCycles, "Number of homing passes. Minimum 1, maximum 128." }, + { Setting_HomingCycle_1, "Axes to home in first pass." }, + { Setting_HomingCycle_2, "Axes to home in second pass." }, + { Setting_HomingCycle_3, "Axes to home in third pass." }, +#ifdef A_AXIS + { Setting_HomingCycle_4, "Axes to home in fourth pass." }, +#endif +#ifdef B_AXIS + { Setting_HomingCycle_5, "Axes to home in fifth pass." }, +#endif +#ifdef C_AXIS + { Setting_HomingCycle_6, "Axes to home in sixth pass." }, +#endif + { Setting_JogStepSpeed, "Step jogging speed in millimeters per minute." }, + { Setting_JogSlowSpeed, "Slow jogging speed in millimeters per minute." }, + { Setting_JogFastSpeed, "Fast jogging speed in millimeters per minute." }, + { Setting_JogStepDistance, "Jog distance for single step jogging." }, + { Setting_JogSlowDistance, "Jog distance before automatic stop." }, + { Setting_JogFastDistance, "Jog distance before automatic stop." }, +#ifndef NO_SAFETY_DOOR_SUPPORT + { Setting_ParkingPulloutIncrement, "Spindle pull-out and plunge distance in mm.Incremental distance." }, + { Setting_ParkingPulloutRate, "Spindle pull-out/plunge slow feed rate in mm/min." }, + { Setting_ParkingTarget, "Parking axis target. In mm, as machine coordinate [-max_travel, 0]." }, + { Setting_ParkingFastRate, "Parking fast rate to target after pull-out in mm/min." }, + { Setting_RestoreOverrides, "Restore overrides to default values at program end." }, + { Setting_DoorOptions, "Enable this if it is desirable to open the safety door when in IDLE mode (eg. for jogging)." }, +#endif + { Setting_SleepEnable, "Enable sleep mode." }, + { Setting_HoldActions, "Actions taken during feed hold and on resume from feed hold." }, + { Setting_ForceInitAlarm, "Start in alarm mode after a cold reset." }, + { Setting_ProbingFeedOverride, "Allow feed override during probing." }, +#if ENABLE_SPINDLE_LINEARIZATION + { Setting_LinearSpindlePiece1, "Comma separated list of values: RPM_MIN, RPM_LINE_A1, RPM_LINE_B1, set to blank to disable." }, + #if SPINDLE_NPWM_PIECES > 1 + { Setting_LinearSpindlePiece2, "Comma separated list of values: RPM_POINT12, RPM_LINE_A2, RPM_LINE_B2, set to blank to disable." }, + #endif + #if SPINDLE_NPWM_PIECES > 2 + { Setting_LinearSpindlePiece3, "Comma separated list of values: RPM_POINT23, RPM_LINE_A3, RPM_LINE_B3, set to blank to disable." }, + #endif + #if SPINDLE_NPWM_PIECES > 3 + { Setting_LinearSpindlePiece4, "Comma separated list of values: RPM_POINT34, RPM_LINE_A4, RPM_LINE_B4, set to blank to disable." }, + #endif +#endif + { Setting_PositionPGain, "" }, + { Setting_PositionIGain, "" }, + { Setting_PositionDGain, "" }, + { Setting_PositionIMaxError, "Spindle sync PID max integrator error." }, + { Setting_AxisStepsPerMM, "Travel resolution in steps per millimeter." }, + { (setting_id_t)(Setting_AxisStepsPerMM + 1), "Travel resolution in steps per degree." }, // "Hack" to get correct description for rotary axes + { Setting_AxisMaxRate, "Maximum rate. Used as G0 rapid rate." }, + { Setting_AxisAcceleration, "Acceleration. Used for motion planning to not exceed motor torque and lose steps." }, +#if ENABLE_JERK_ACCELERATION + { Setting_AxisJerk, "Maximum rate of acceleration change - smoothes out acceleration profile up to max axis acceleration.\\n\\n" + "Minimum value of x10 Acceleration setting to ensure decent acceleration times.\\n" + "Maximum is calculated by current acceleration and stepper segment time.\\n" + "At Maximum value motion is effectively trapezoidal instead of constant jerk.\\n\\n" + "Can be increased by adjusting ACCELERATION_TICKS_PER_SECOND to a larger value before compiling."}, +#endif + { Setting_AxisMaxTravel, "Maximum axis travel distance from homing switch. Determines valid machine space for soft-limits and homing search distances." }, +#if ENABLE_BACKLASH_COMPENSATION + { Setting_AxisBacklash, "Backlash distance to compensate for." }, +#endif + { Setting_AxisAutoSquareOffset, "Offset between sides to compensate for homing switches inaccuracies." }, + { Setting_AxisHomingFeedRate, "Feed rate to slowly engage limit switch to determine its location accurately." }, + { Setting_AxisHomingSeekRate, "Seek rate to quickly find the limit switch before the slower locating phase." }, + { Setting_SpindleAtSpeedTolerance, "Spindle at speed tolerance as percentage deviation from programmed speed, set to 0 to disable.\\n" + "If not within tolerance when checked after spindle on delay ($392) alarm 14 is raised." + }, + { Setting_ToolChangeMode, "Normal: allows jogging for manual touch off. Set new position manually.\\n\\n" + "Manual touch off: retracts tool axis to home position for tool change, use jogging or $TPW for touch off.\\n\\n" + "Manual touch off @ G59.3: retracts tool axis to home position then to G59.3 position for tool change, use jogging or $TPW for touch off.\\n\\n" + "Automatic touch off @ G59.3: retracts tool axis to home position for tool change, then to G59.3 position for automatic touch off.\\n\\n" + "All modes except \"Normal\" and \"Ignore M6\" returns the tool (controlled point) to original position after touch off." + }, + { Setting_ToolChangeProbingDistance, "Maximum probing distance for automatic or $TPW touch off." }, + { Setting_ToolChangeFeedRate, "Feed rate to slowly engage tool change sensor to determine the tool offset accurately." }, + { Setting_ToolChangeSeekRate, "Seek rate to quickly find the tool change sensor before the slower locating phase." }, + { Setting_ToolChangePulloffRate, "Pull-off rate for the retract move before the slower locating phase." }, + { Setting_ToolChangeRestorePosition, "When set the spindle is moved so that the controlled point (tool tip) is the same as before the M6 command, if not the spindle is only moved to the Z home position." }, + { Setting_DualAxisLengthFailPercent, "Dual axis length fail in percent of axis max travel." }, + { Setting_DualAxisLengthFailMin, "Dual axis length fail minimum distance." }, + { Setting_DualAxisLengthFailMax, "Dual axis length fail minimum distance." }, +#if COMPATIBILITY_LEVEL <= 1 + { Setting_DisableG92Persistence, "Disables save/restore of G92 offset to non-volatile storage (NVS)." }, #endif - -#if COMPATIBILITY_LEVEL > 1 - case Setting_LimitPinsInvertMask: - value = settings.limits.invert.mask == DEFAULT_LIMIT_SIGNALS_INVERT_MASK ? 0 : 1; - break; +#if N_AXIS > 3 + { Settings_RotaryAxes, "Designates axes as rotary, interpretation some other relevant axis settings is changed accordingly." }, #endif - - case Setting_SpindlePWMOptions: - value = settings.spindle.flags.pwm_disable ? 0 : (0b001 | - (settings.spindle.flags.enable_rpm_controlled ? 0b010 : 0) | - (settings.spindle.flags.laser_mode_disable ? 0b100 : 0)); - break; - - case Setting_Mode: - value = settings.mode; - break; - - case Setting_InvertProbePin: - value = settings.probe.invert_probe_pin; - break; - - case Setting_GangedDirInvertMask: - value = settings.steppers.ganged_dir_invert.mask; - break; - - case Setting_StatusReportMask: -#if COMPATIBILITY_LEVEL <= 1 - value = settings.status_report.mask; +#ifndef NO_SAFETY_DOOR_SUPPORT + { Setting_DoorSpindleOnDelay, "Delay to allow spindle to spin up after safety door is opened or feed hold is canceled." }, + { Setting_DoorCoolantOnDelay, "Delay to allow coolant to restart after safety door is opened or feed hold is canceled." }, #else - value = settings.status_report.mask & 0b11; + { Setting_DoorSpindleOnDelay, "Delay to allow spindle to spin up when spindle at speed tolerance is > 0." }, #endif - break; - - case Setting_ReportInches: - value = settings.flags.report_inches; - break; - - case Setting_ControlInvertMask: - value = settings.control_invert.mask & (hal.signals_cap.mask & ~limits_override.mask); - break; - - case Setting_SpindleInvertMask: - value = settings.spindle.invert.mask; - break; - - case Setting_ControlPullUpDisableMask: - value = settings.control_disable_pullup.mask; - break; - - case Setting_ProbePullUpDisable: - value = settings.probe.disable_probe_pullup; - break; - - case Setting_SoftLimitsEnable: - value = settings.limits.flags.soft_enabled; - break; - - case Setting_HardLimitsEnable: - value = ((settings.limits.flags.hard_enabled & bit(0)) ? bit(0) | - (settings.limits.flags.check_at_init ? bit(1) : 0) | - (settings.limits.flags.hard_disabled_rotary ? bit(2) : 0) : 0); - break; - - case Setting_JogSoftLimited: - value = settings.limits.flags.jog_soft_limited; - break; - - case Setting_HomingEnable:; + { Setting_SpindleOnDelay, "Delay to allow spindle to restart after feed hold is canceled." }, + { Setting_SpindleType, "Spindle selected on startup." }, + { Setting_PlannerBlocks, "Number of blocks in the planner buffer." }, + { Setting_AutoReportInterval, "Interval the real time report will be sent, set to 0 to disable." }, + { Setting_TimeZoneOffset, "Offset in hours from UTC." }, + { Setting_UnlockAfterEStop, "If set unlock (by sending $X) is required after resetting a cleared E-Stop condition." }, #if COMPATIBILITY_LEVEL <= 1 - homing_flags_t homing; - homing.value = settings.homing.flags.value & 0b1111; - homing.two_switches = settings.limits.flags.two_switches; - homing.manual = settings.homing.flags.manual; - homing.override_locks = settings.homing.flags.override_locks; - homing.keep_on_reset = settings.homing.flags.keep_on_reset; - homing.use_limit_switches = settings.homing.flags.use_limit_switches; - value = homing.value; -#else - value = settings.homing.flags.enabled; -#endif - break; - - case Setting_SteppersEnergize: - value = settings.steppers.energize.mask; - break; - - case Setting_EnableLegacyRTCommands: - value = settings.flags.legacy_rt_commands; - break; - - case Setting_ParkingEnable: - value = settings.parking.flags.value; - break; - - case Setting_HomingCycle_1: - case Setting_HomingCycle_2: - case Setting_HomingCycle_3: - case Setting_HomingCycle_4: - case Setting_HomingCycle_5: - case Setting_HomingCycle_6: - value = settings.homing.cycle[id - Setting_HomingCycle_1].mask; - break; - - case Setting_RestoreOverrides: - value = settings.flags.restore_overrides; - break; - - case Setting_SleepEnable: - value = settings.flags.sleep_enable; - break; - - case Setting_HoldActions: - value = (settings.flags.disable_laser_during_hold ? bit(0) : 0) | (settings.flags.restore_after_feed_hold ? bit(1) : 0); - break; - - case Setting_ForceInitAlarm: - value = settings.flags.force_initialization_alarm; - break; - - case Setting_ProbingFeedOverride: - value = settings.probe.allow_feed_override; - break; - - case Setting_ToolChangeMode: - value = settings.tool_change.mode; - break; - - case Setting_ToolChangeRestorePosition: - value = settings.flags.no_restore_position_after_M6 ? 0 : 1; - break; - - case Setting_DisableG92Persistence: - value = settings.flags.g92_is_volatile; - break; - - case Setting_SpindleType: - value = settings.spindle.flags.type; - break; - - case Setting_AutoReportInterval: - value = settings.report_interval; - break; - -#if N_AXIS > 3 - case Settings_RotaryAxes: - value = (settings.steppers.is_rotary.mask & AXES_BITMASK) >> 3; - break; - - case Setting_RotaryWrap: - value = (settings.steppers.rotary_wrap.mask & AXES_BITMASK) >> 3; - break; + { Setting_OffsetLock, "Lock coordinate systems against accidental changes." }, #endif - - case Setting_UnlockAfterEStop: - value = settings.flags.no_unlock_after_estop ? 0 : 1; - break; - - case Setting_OffsetLock: - value = settings.offset_lock.mask & 0b111; - break; - - case Setting_EncoderSpindle: - value = settings.offset_lock.encoder_spindle; - break; - #if NGC_EXPRESSIONS_ENABLE - case Setting_NGCDebugOut: - value = settings.flags.ngc_debug_out; - break; + { Setting_NGCDebugOut, "Example: (debug, metric mode: #<_metric>, coord system: #5220)" }, #endif + { Setting_EncoderSpindle, "Specifies which spindle has the encoder attached." }, +#if N_AXIS > 3 + { Setting_RotaryWrap, "Perform fast move to angle stored in G28 position.\\n" + "Use:\\n" + " G91G280\\n" + " G90\\n" + }, +#endif + { Setting_FSOptions, "Auto mount SD card on startup." }, + { Setting_HomePinsInvertMask, "Inverts the axis home input signals." }, + { Setting_HoldCoolantOnDelay, "Delay to allow coolant to restart after feed hold is canceled." } +}; - default: - break; - } - - return value; -} - -inline static uint8_t get_decimal_places (const char *format) -{ - char *dp = format == NULL ? NULL : strchr(format, '.'); - - return dp ? strchr(format, '\0') - dp - 1 : 1; -} - -char *setting_get_value (const setting_detail_t *setting, uint_fast16_t offset) -{ - char *value = NULL; - - if(setting == NULL) - return NULL; - - switch(setting->type) { - - case Setting_NonCore: - case Setting_IsExtended: - case Setting_IsLegacy: - case Setting_IsExpanded: - switch(setting->datatype) { - - case Format_Decimal: - value = ftoa(*((float *)(setting->value)), get_decimal_places(setting->format)); - break; - - case Format_Int8: - case Format_Bool: - case Format_Bitfield: - case Format_XBitfield: - case Format_AxisMask: - case Format_RadioButtons: - value = uitoa(*((uint8_t *)(setting->value))); - break; - - case Format_Int16: - value = uitoa(*((uint16_t *)(setting->value))); - break; - - case Format_Integer: - value = uitoa(*((uint32_t *)(setting->value))); - break; - - case Format_Password: - value = hal.stream.state.webui_connected ? PASSWORD_MASK : ((char *)(setting->value)); - break; - - case Format_String: - case Format_IPv4: - value = ((char *)(setting->value)); - break; - - default: - break; - } - break; - - case Setting_NonCoreFn: - case Setting_IsExtendedFn: - case Setting_IsLegacyFn: - case Setting_IsExpandedFn:; - - setting_id_t id = (setting_id_t)(setting->id + offset); - - switch(setting->datatype) { - - case Format_Decimal: - value = ftoa(((setting_get_float_ptr)(setting->get_value))(id), get_decimal_places(setting->format)); - break; - - case Format_Password: - value = hal.stream.state.webui_connected ? "********" : ((setting_get_string_ptr)(setting->get_value))(id); - break; - - case Format_String: - case Format_IPv4: - value = ((setting_get_string_ptr)(setting->get_value))(id); - break; +#endif - default: - value = uitoa(((setting_get_int_ptr)(setting->get_value))(id)); - break; - } - break; - } +static setting_details_t setting_details = { + .groups = setting_group_detail, + .n_groups = sizeof(setting_group_detail) / sizeof(setting_group_detail_t), + .settings = setting_detail, + .n_settings = sizeof(setting_detail) / sizeof(setting_detail_t), +#ifndef NO_SETTINGS_DESCRIPTIONS + .descriptions = setting_descr, + .n_descriptions = sizeof(setting_descr) / sizeof(setting_descr_t), +#endif + .save = settings_write_global +}; - return value; -} +static setting_details_t *settingsd = &setting_details; -uint32_t setting_get_int_value (const setting_detail_t *setting, uint_fast16_t offset) +void settings_register (setting_details_t *details) { - uint32_t value = 0; - - if(setting) switch(setting->type) { - - case Setting_NonCore: - case Setting_IsExtended: - case Setting_IsLegacy: - case Setting_IsExpanded: - switch(setting->datatype) { - - case Format_Int8: - case Format_Bool: - case Format_Bitfield: - case Format_XBitfield: - case Format_AxisMask: - case Format_RadioButtons: - value = *((uint8_t *)(setting->value)); - break; - - case Format_Int16: - value = *((uint16_t *)(setting->value)); - break; - - case Format_Integer: - value = *((uint32_t *)(setting->value)); - break; - - default: - break; - } - break; - - case Setting_NonCoreFn: - case Setting_IsExtendedFn: - case Setting_IsLegacyFn: - case Setting_IsExpandedFn: - switch(setting->datatype) { - - case Format_Decimal: - case Format_String: - case Format_Password: - case Format_IPv4: - break; - - default: - value = ((setting_get_int_ptr)(setting->get_value))((setting_id_t)(setting->id + offset)); - break; - } - break; - } - - return value; + settingsd->next = details; + settingsd = details; } -float setting_get_float_value (const setting_detail_t *setting, uint_fast16_t offset) +setting_details_t *settings_get_details (void) { - float value = NAN; - - if(setting && setting->datatype == Format_Decimal) switch(setting->type) { - - case Setting_NonCore: - case Setting_IsExtended: - case Setting_IsLegacy: - case Setting_IsExpanded: - value = *((float *)(setting->value)); - break; - - case Setting_NonCoreFn: - case Setting_IsExtendedFn: - case Setting_IsLegacyFn: - case Setting_IsExpandedFn: - value = ((setting_get_float_ptr)(setting->get_value))((setting_id_t)(setting->id + offset)); - break; - - default: - break; - } - - return value; + return &setting_details; } -static bool is_setting_available (const setting_detail_t *setting) -{ - bool available = false; - - if(setting) switch(normalize_id(setting->id)) { - - case Setting_GangedDirInvertMask: - available = hal.stepper.get_ganged && hal.stepper.get_ganged(false).mask != 0; - break; - - case Setting_InvertProbePin: - case Setting_ProbePullUpDisable: - case Setting_ProbingFeedOverride: -// case Setting_ToolChangeProbingDistance: -// case Setting_ToolChangeFeedRate: -// case Setting_ToolChangeSeekRate: - available = hal.probe.get_state != NULL; - break; - - case Setting_SpindlePWMBehaviour: - available = false; - break; - - case Setting_SpindlePWMOptions: - available = hal.driver_cap.pwm_spindle && spindle_get_caps(false).laser; - break; - - case Setting_SpindleInvertMask: - available = spindle_get_caps(false).gpio_controlled; - break; - - case Setting_PWMFreq: - case Setting_PWMOffValue: - case Setting_PWMMinValue: - case Setting_PWMMaxValue: - available = hal.driver_cap.pwm_spindle; - break; - - case Setting_SpindleType: - available = spindle_get_count() > 1; - break; - - case Setting_SpindlePPR: - available = hal.driver_cap.spindle_encoder; - break; - - case Setting_RpmMax: - case Setting_RpmMin: - available = spindle_get_caps(false).variable; - break; - - case Setting_SleepEnable: - available = SLEEP_DURATION > 0.0f; - break; - - case Setting_DualAxisLengthFailPercent: - case Setting_DualAxisLengthFailMin: - case Setting_DualAxisLengthFailMax: - case Setting_AxisAutoSquareOffset: - available = hal.stepper.get_ganged && hal.stepper.get_ganged(true).mask != 0; -// available = hal.stepper.get_ganged && bit_istrue(hal.stepper.get_ganged(true).mask, setting->id - Setting_AxisAutoSquareOffset); - break; - -#ifndef NO_SAFETY_DOOR_SUPPORT - - case Setting_ParkingEnable: - case Setting_ParkingAxis: - case Setting_ParkingPulloutIncrement: - case Setting_ParkingPulloutRate: - case Setting_ParkingTarget: - case Setting_ParkingFastRate: - case Setting_RestoreOverrides: - case Setting_DoorOptions: - available = hal.signals_cap.safety_door_ajar; - break; - - case Setting_DoorSpindleOnDelay: - available = hal.signals_cap.safety_door_ajar && spindle_get_count() && !spindle_get_caps(true).at_speed; - break; - - case Setting_DoorCoolantOnDelay: - available = hal.signals_cap.safety_door_ajar && hal.coolant_cap.mask; - break; -#endif - - case Setting_SpindleAtSpeedTolerance: - available = spindle_get_caps(true).at_speed || hal.driver_cap.spindle_encoder; - break; - - case Setting_SpindleOnDelay: - available = !hal.signals_cap.safety_door_ajar && spindle_get_count() && !spindle_get_caps(true).at_speed; - break; - - case Setting_AutoReportInterval: - available = hal.get_elapsed_ticks != NULL; - break; - - case Setting_TimeZoneOffset: - available = hal.rtc.set_datetime != NULL; - break; - - case Setting_UnlockAfterEStop: - available = hal.signals_cap.e_stop; - break; - - case Setting_EncoderSpindle: - available = hal.driver_cap.spindle_encoder && spindle_get_count() > 1; - break; - - case Setting_FSOptions: - available = hal.driver_cap.sd_card || hal.driver_cap.littlefs; - break; - - case Setting_HomePinsInvertMask: - available = hal.homing.get_state != NULL && hal.home_cap.a.mask != 0; - break; - - case Setting_HoldCoolantOnDelay: - available = !hal.signals_cap.safety_door_ajar && hal.coolant_cap.mask; - break; - - default: - break; - } - - return available; -} +/**/ // Write build info to persistent storage void settings_write_build_info (char *line) @@ -2331,7 +2497,7 @@ bool read_global_settings () settings.control_invert.mask |= limits_override.mask; settings.control_disable_pullup.mask &= ~limits_override.mask; - return ok && settings.version == SETTINGS_VERSION; + return ok && settings.version.id == SETTINGS_VERSION; } @@ -2349,10 +2515,14 @@ void settings_write_global (void) #if N_SPINDLE > 1 -static void get_default_spindle (spindle_info_t *spindle, void *data) +static bool get_default_spindle (spindle_info_t *spindle, void *data) { - if(spindle->ref_id == (uint8_t)((uint32_t)data)) - settings.spindle.flags.type = spindle->id; + bool ok; + + if((ok = spindle->ref_id == (uint8_t)((uint32_t)data))) + settings.spindle.ref_id = spindle->ref_id; + + return ok; } #endif @@ -2374,8 +2544,8 @@ void settings_restore (settings_restore_t restore) settings.control_invert.mask = (settings.control_invert.mask & hal.signals_cap.mask) | limits_override.mask; settings.control_disable_pullup.mask &= (hal.signals_cap.mask & ~limits_override.mask); - settings.spindle.invert.ccw &= spindle_get_caps(false).direction; - settings.spindle.invert.pwm &= spindle_get_caps(false).pwm_invert; + settings.pwm_spindle.invert.ccw &= spindle_get_caps(false).direction; + settings.pwm_spindle.invert.pwm &= spindle_get_caps(false).pwm_invert; #if ENABLE_BACKLASH_COMPENSATION if(sys.driver_started) mc_backlash_init((axes_signals_t){AXES_BITMASK}); @@ -2430,11 +2600,6 @@ inline static bool is_available (const setting_detail_t *setting) return setting->is_available == NULL || setting->is_available(setting); } -static bool is_group_available (const setting_detail_t *setting) -{ - return settings_is_group_available(setting->group); -} - bool settings_is_group_available (setting_group_t id) { const setting_group_detail_t *group = setting_get_group_details(id); @@ -3089,13 +3254,11 @@ void settings_init (void) hal.probe.configure(false, false); } - settings.offset_lock.mask &= ~0b111; // TODO: remove - settings.offset_lock.mask |= settings.parking.flags.offset_lock; // TODO: remove - xbar_set_homing_source(); tmp_set_soft_limits(); tmp_set_hard_limits(); + homing_pulloff_init(settings.homing.pulloff); if(spindle_get_count() == 0) spindle_add_null(); @@ -3119,7 +3282,7 @@ void settings_init (void) #if COMPATIBILITY_LEVEL <= 1 if(hal.homing.get_state == NULL) { - homing_flags_t homing; + homing_settings_flags_t homing; homing.value = -1; homing.use_limit_switches = Off; setting_remove_elements(Setting_HomingEnable, homing.value); @@ -3135,11 +3298,11 @@ void settings_init (void) details->on_changed(&settings, changed); } while((details = details->next)); - setting_details.on_changed = hal.settings_changed; - // Sanity checks for spindle configuration - if(settings.spindle.flags.type >= spindle_get_count()) - settings.spindle.flags.type = 0; - if(settings.offset_lock.encoder_spindle >= spindle_get_count()) - settings.offset_lock.encoder_spindle = 0; + if(!settings.flags.settings_downgrade && settings.version.build != (GRBL_BUILD - 20000000UL)) { + settings.version.build = (GRBL_BUILD - 20000000UL); + settings_write_global(); + } + + setting_details.on_changed = hal.settings_changed; } diff --git a/settings.h b/settings.h index 53edf8b..add4970 100644 --- a/settings.h +++ b/settings.h @@ -521,17 +521,17 @@ typedef enum { // Calculated base values for driver/plugin stepper settings Setting_AxisExtended0 = Setting_AxisSettingsBase2, Setting_AxisExtended1 = Setting_AxisSettingsBase2 + AXIS_SETTINGS_INCREMENT, -#if ENABLE_JERK_ACCELERATION - Setting_AxisJerk = Setting_AxisSettingsBase2 + 2 * AXIS_SETTINGS_INCREMENT, -#else Setting_AxisExtended2 = Setting_AxisSettingsBase2 + 2 * AXIS_SETTINGS_INCREMENT, -#endif Setting_AxisExtended3 = Setting_AxisSettingsBase2 + 3 * AXIS_SETTINGS_INCREMENT, Setting_AxisExtended4 = Setting_AxisSettingsBase2 + 4 * AXIS_SETTINGS_INCREMENT, Setting_AxisExtended5 = Setting_AxisSettingsBase2 + 5 * AXIS_SETTINGS_INCREMENT, Setting_AxisExtended6 = Setting_AxisSettingsBase2 + 6 * AXIS_SETTINGS_INCREMENT, Setting_AxisExtended7 = Setting_AxisSettingsBase2 + 7 * AXIS_SETTINGS_INCREMENT, +#if ENABLE_JERK_ACCELERATION + Setting_AxisJerk = Setting_AxisSettingsBase2 + 8 * AXIS_SETTINGS_INCREMENT, +#else Setting_AxisExtended8 = Setting_AxisSettingsBase2 + 8 * AXIS_SETTINGS_INCREMENT, +#endif Setting_AxisExtended9 = Setting_AxisSettingsBase2 + 9 * AXIS_SETTINGS_INCREMENT, // Calculated base values for encoder settings From e504964dae3c87566d46ef2e84482e5c6a345eb9 Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Tue, 10 Dec 2024 22:15:25 +0100 Subject: [PATCH 38/47] moved acceleration factor to plan_block_t structure, moved lookup function to plan_data_init, renamed lookup fuction and adjusted the acceleration limit functions to new structure --- gcode.c | 2 +- planner.c | 10 ++++++++-- planner.h | 6 ++++++ settings.c | 2 +- settings.h | 8 ++------ 5 files changed, 18 insertions(+), 10 deletions(-) diff --git a/gcode.c b/gcode.c index d9102d4..4ee2e94 100644 --- a/gcode.c +++ b/gcode.c @@ -362,7 +362,7 @@ void gc_init (bool stop) ngc_modal_state_invalidate(); #endif #if ENABLE_ACCELERATION_PROFILES - gc_state.modal.activeaccelprofile = 1.0f; // Initialize machine with 100% Profile + gc_state.modal.acceleration_profile = 1.0f; // Initialize machine with 100% Profile #endif // if(settings.flags.lathe_mode) diff --git a/planner.c b/planner.c index a9017eb..981a956 100644 --- a/planner.c +++ b/planner.c @@ -349,7 +349,7 @@ static inline float limit_acceleration_by_axis_maximum (float *unit_vec) limit_value = min(limit_value, fabsf(settings.axis[idx].acceleration / unit_vec[idx])); } while(idx); #if ENABLE_ACCELERATION_PROFILES - limit_value *= lookupprofile(gc_state.modal.activeaccelprofile); + limit_value *= block->acceleration_factor; #endif return limit_value; } @@ -365,7 +365,7 @@ static inline float limit_jerk_by_axis_maximum (float *unit_vec) limit_value = min(limit_value, fabsf(settings.axis[idx].jerk / unit_vec[idx])); } while(idx); #if ENABLE_ACCELERATION_PROFILES - limit_value *= lookupprofile(gc_state.modal.activeaccelprofile); + limit_value *= block->acceleration_factor; #endif return limit_value; } @@ -531,6 +531,9 @@ bool plan_buffer_line (float *target, plan_line_data_t *pl_data) #ifdef KINEMATICS_API block->rate_multiplier = pl_data->rate_multiplier; #endif +#ifdef ENABLE_ACCELERATION_PROFILES + block->acceleration_factor = pl_data->acceleration_factor; +#endif // Store programmed rate. if (block->condition.rapid_motion) @@ -735,4 +738,7 @@ void plan_data_init (plan_line_data_t *plan_data) #ifdef KINEMATICS_API plan_data->rate_multiplier = 1.0f; #endif +#ifdef ENABLE_ACCELERATION_PROFILES + plan_data->acceleration_factor = lookupfactor(gc_state.modal.acceleration_profile); +#endif } diff --git a/planner.h b/planner.h index 39191c8..e26f211 100644 --- a/planner.h +++ b/planner.h @@ -77,6 +77,9 @@ typedef struct plan_block { float programmed_rate; // Programmed rate of this block (mm/min). #ifdef KINEMATICS_API float rate_multiplier; // Rate multiplier of this block. +#endif +#ifdef ENABLE_ACCELERATION_PROFILES + float current_accel_profile; // Stores the currently used acceleration profile . #endif // Stored spindle speed data used by spindle overrides and resuming methods. spindle_t spindle; // Block spindle parameters. Copied from pl_line_data. @@ -93,6 +96,9 @@ typedef struct { #ifdef KINEMATICS_API float rate_multiplier; // Feed rate multiplier. #endif +#ifdef ENABLE_ACCELERATION_PROFILES + float current_accel_profile; // Stores the currently used acceleration profile . +#endif #if ENABLE_PATH_BLENDING float path_tolerance; //!< Path blending tolerance. float cam_tolerance; //!< Naive CAM tolerance. diff --git a/settings.c b/settings.c index 38a1146..649ba0c 100644 --- a/settings.c +++ b/settings.c @@ -507,7 +507,7 @@ bool settings_override_acceleration (uint8_t axis, float acceleration) #if ENABLE_ACCELERATION_PROFILES //Acceleration Profiles for G187 P[x] in percent of maximum machine acceleration. -float lookupprofile(uint8_t profile) { +float lookupfactor(uint8_t profile) { static const float lookup[5] = { 1.0f, // 100% - Roughing - Max Acceleration Default 0.8f, // 80% - Semi Roughing diff --git a/settings.h b/settings.h index a32758d..ad4d328 100644 --- a/settings.h +++ b/settings.h @@ -535,11 +535,7 @@ typedef enum { Setting_AxisExtended5 = Setting_AxisSettingsBase2 + 5 * AXIS_SETTINGS_INCREMENT, Setting_AxisExtended6 = Setting_AxisSettingsBase2 + 6 * AXIS_SETTINGS_INCREMENT, Setting_AxisExtended7 = Setting_AxisSettingsBase2 + 7 * AXIS_SETTINGS_INCREMENT, -#if ENABLE_JERK_ACCELERATION - Setting_AxisJerk = Setting_AxisSettingsBase2 + 8 * AXIS_SETTINGS_INCREMENT, -#else - Setting_AxisExtended8 = Setting_AxisSettingsBase2 + 8 * AXIS_SETTINGS_INCREMENT, -#endif + Setting_AxisExtended8 = Setting_AxisSettingsBase2 + 8 * AXIS_SETTINGS_INCREMENT,s Setting_AxisExtended9 = Setting_AxisSettingsBase2 + 9 * AXIS_SETTINGS_INCREMENT, // Calculated base values for encoder settings @@ -1089,7 +1085,7 @@ bool settings_read_coord_data(coord_system_id_t id, float (*coord_data)[N_AXIS]) bool settings_override_acceleration (uint8_t axis, float acceleration); #if ENABLE_ACCELERATION_PROFILES -float lookupprofile (uint8_t profile); +float lookupfactor (uint8_t profile); #endif void settings_register (setting_details_t *details); From c4969f1dc02d020aa5de682961164d99b27c1483 Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Tue, 10 Dec 2024 22:24:39 +0100 Subject: [PATCH 39/47] missed 2 variable names --- gcode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gcode.c b/gcode.c index 4ee2e94..6eb0144 100644 --- a/gcode.c +++ b/gcode.c @@ -2382,7 +2382,7 @@ status_code_t gc_execute_block (char *block) FAIL(Status_NegativeValue);} else if (gc_block.values.p > 5.0f){ FAIL(Status_GcodeValueOutOfRange);} - gc_state.modal.activeaccelprofile = gc_block.values.p; + gc_state.modal.acceleration_profile = gc_block.values.p; break; #endif default: @@ -3846,7 +3846,7 @@ status_code_t gc_execute_block (char *block) gc_state.modal.override_ctrl.feed_rate_disable = Off; gc_state.modal.override_ctrl.spindle_rpm_disable = Off; #if ENABLE_ACCELERATION_PROFILES - gc_state.modal.activeaccelprofile = 1.0f; + gc_state.modal.acceleration_profile = 1.0f; #endif #if N_SYS_SPINDLE > 1 From 33795245fec1a67eaef6993176b52dc1706fa23d Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Tue, 10 Dec 2024 23:05:45 +0100 Subject: [PATCH 40/47] file didnt want to push. found a typo --- planner.h | 4 ++-- settings.c | 8 ++++---- settings.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/planner.h b/planner.h index e26f211..4cb7213 100644 --- a/planner.h +++ b/planner.h @@ -79,7 +79,7 @@ typedef struct plan_block { float rate_multiplier; // Rate multiplier of this block. #endif #ifdef ENABLE_ACCELERATION_PROFILES - float current_accel_profile; // Stores the currently used acceleration profile . + float acceleration_factor; // Stores the currently used acceleration factor. #endif // Stored spindle speed data used by spindle overrides and resuming methods. spindle_t spindle; // Block spindle parameters. Copied from pl_line_data. @@ -97,7 +97,7 @@ typedef struct { float rate_multiplier; // Feed rate multiplier. #endif #ifdef ENABLE_ACCELERATION_PROFILES - float current_accel_profile; // Stores the currently used acceleration profile . + float acceleration_factor; // Stores the currently used acceleration factor. #endif #if ENABLE_PATH_BLENDING float path_tolerance; //!< Path blending tolerance. diff --git a/settings.c b/settings.c index 649ba0c..0b94454 100644 --- a/settings.c +++ b/settings.c @@ -153,14 +153,14 @@ PROGMEM const settings_t defaults = { .limits.flags.hard_disabled_rotary = DEFAULT_HARD_LIMITS_DISABLE_FOR_ROTARY, .limits.flags.two_switches = DEFAULT_LIMITS_TWO_SWITCHES_ON_AXES, .limits.invert.mask = DEFAULT_LIMIT_SIGNALS_INVERT_MASK, - .limits.disable_pullup.mask = DEFAULT_LIMIT_SIGNALS_PULLUP_DISABLE_MASK, + .limits.disable_pullup.mask = DEFAULT_LIMIT_SIGNALS_PULLUP_DISABLE_MASK, .limits.soft_enabled.mask = (DEFAULT_SOFT_LIMIT_ENABLE ? AXES_BITMASK : 0), .control_invert.mask = DEFAULT_CONTROL_SIGNALS_INVERT_MASK, .control_disable_pullup.mask = DEFAULT_DISABLE_CONTROL_PINS_PULL_UP_MASK, .spindle.ref_id = DEFAULT_SPINDLE, - .spindle.encoder_spindle = DEFAULT_SPINDLE, + .spindle.encoder_spindle = DEFAULT_SPINDLE, .spindle.ppr = DEFAULT_SPINDLE_PPR, .pwm_spindle.rpm_max = DEFAULT_SPINDLE_RPM_MAX, @@ -231,7 +231,7 @@ PROGMEM const settings_t defaults = { .axis[Y_AXIS].dual_axis_offset = 0.0f, .axis[Y_AXIS].homing_feed_rate = DEFAULT_HOMING_FEED_RATE, .axis[Y_AXIS].homing_seek_rate = DEFAULT_HOMING_SEEK_RATE, - #if ENABLE_BACKLASH_COMPENSATION +#if ENABLE_BACKLASH_COMPENSATION .axis[Y_AXIS].backlash = 0.0f, #endif @@ -1307,7 +1307,7 @@ static status_code_t set_axis_setting (setting_id_t setting, float value) settings.axis[idx].homing_seek_rate = value; else status = Status_SettingDisabled; - break; + break; default: status = Status_SettingDisabled; diff --git a/settings.h b/settings.h index ad4d328..b1594a8 100644 --- a/settings.h +++ b/settings.h @@ -535,7 +535,7 @@ typedef enum { Setting_AxisExtended5 = Setting_AxisSettingsBase2 + 5 * AXIS_SETTINGS_INCREMENT, Setting_AxisExtended6 = Setting_AxisSettingsBase2 + 6 * AXIS_SETTINGS_INCREMENT, Setting_AxisExtended7 = Setting_AxisSettingsBase2 + 7 * AXIS_SETTINGS_INCREMENT, - Setting_AxisExtended8 = Setting_AxisSettingsBase2 + 8 * AXIS_SETTINGS_INCREMENT,s + Setting_AxisExtended8 = Setting_AxisSettingsBase2 + 8 * AXIS_SETTINGS_INCREMENT, Setting_AxisExtended9 = Setting_AxisSettingsBase2 + 9 * AXIS_SETTINGS_INCREMENT, // Calculated base values for encoder settings From 254a3d12121090b3666169c00bb64a13758cf593 Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Thu, 26 Dec 2024 21:23:06 +0100 Subject: [PATCH 41/47] Update settings.c Cleaned up out of sync functions. Most likely a remnant from resolving the merge conflict. --- settings.c | 55 ------------------------------------------------------ 1 file changed, 55 deletions(-) diff --git a/settings.c b/settings.c index 478e34e..ceda8d1 100644 --- a/settings.c +++ b/settings.c @@ -778,19 +778,6 @@ static status_code_t set_estop_unlock (setting_id_t id, uint_fast16_t int_value) return Status_OK; } -#if COMPATIBILITY_LEVEL <= 1 - -static status_code_t set_offset_lock (setting_id_t id, uint_fast16_t int_value) -{ - settings.parking.flags.offset_lock = int_value & 0b111; // TODO: remove - settings.offset_lock.mask &= ~0b111; // TODO: remove - settings.offset_lock.mask |= settings.parking.flags.offset_lock; - - return Status_OK; -} - -#endif - static inline void tmp_set_hard_limits (void) { sys.hard_limits.mask = settings.limits.flags.hard_enabled ? AXES_BITMASK : 0; @@ -828,40 +815,6 @@ static status_code_t set_jog_soft_limited (setting_id_t id, uint_fast16_t int_va return Status_OK; } -static status_code_t set_homing_enable (setting_id_t id, uint_fast16_t int_value) -{ - homing_flags_t homing; - - homing.value = int_value; - - if(homing.enabled) { -#if COMPATIBILITY_LEVEL > 1 - settings.homing.flags.enabled = On; - settings.homing.flags.init_lock = DEFAULT_HOMING_INIT_LOCK; - settings.homing.flags.single_axis_commands = DEFAULT_HOMING_SINGLE_AXIS_COMMANDS; - settings.homing.flags.force_set_origin = DEFAULT_HOMING_FORCE_SET_ORIGIN; - settings.homing.flags.manual = DEFAULT_HOMING_ALLOW_MANUAL; - settings.homing.flags.override_locks = DEFAULT_HOMING_OVERRIDE_LOCKS; - settings.homing.flags.keep_on_reset = DEFAULT_HOMING_KEEP_STATUS_ON_RESET; - settings.homing.flags.use_limit_switches = DEFAULT_HOMING_USE_LIMIT_SWITCHES; - settings.limits.flags.two_switches = DEFAULT_LIMITS_TWO_SWITCHES_ON_AXES; -#else - settings.homing.flags.value = int_value & 0b1111; - settings.limits.flags.two_switches = homing.two_switches; - settings.homing.flags.manual = homing.manual; - settings.homing.flags.override_locks = homing.override_locks; - settings.homing.flags.keep_on_reset = homing.keep_on_reset; - settings.homing.flags.use_limit_switches = homing.use_limit_switches; -#endif - } else { - settings.homing.flags.value = 0; - settings.limits.flags.soft_enabled = Off; // Force disable soft-limits. - settings.limits.flags.jog_soft_limited = Off; - } - - return Status_OK; -} - static status_code_t set_enable_legacy_rt_commands (setting_id_t id, uint_fast16_t int_value) { settings.flags.legacy_rt_commands = int_value != 0; @@ -869,14 +822,6 @@ static status_code_t set_enable_legacy_rt_commands (setting_id_t id, uint_fast16 return Status_OK; } -static status_code_t set_homing_cycle (setting_id_t id, uint_fast16_t int_value) -{ - settings.homing.cycle[id - Setting_HomingCycle_1].mask = int_value; - limits_set_homing_axes(); - - return Status_OK; -} - #if !LATHE_UVW_OPTION static status_code_t set_mode (setting_id_t id, uint_fast16_t int_value) From efcdf3f6da4b3ecbb41c81976ff9655fd33db781 Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Thu, 26 Dec 2024 22:09:07 +0100 Subject: [PATCH 42/47] Update gcode.h --- gcode.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gcode.h b/gcode.h index 115cad0..f7cd13b 100644 --- a/gcode.h +++ b/gcode.h @@ -546,6 +546,9 @@ typedef struct { bool auto_restore; float feed_rate; //!< {F} NOTE: only set when saving modal state #endif +#if ENABLE_ACCELERATION_PROFILES + float acceleration_profile; //!< {G187} currently active acceleration profile +#endif } gc_modal_t; //! Data for canned cycles. From ce60b8ff7da7f2a5040d622942e02e93b96fe19e Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Thu, 26 Dec 2024 22:49:34 +0100 Subject: [PATCH 43/47] adjusted the limit by axis maximum functions to not require the block data --- gcode.c | 2 +- planner.c | 16 ++++++++-------- settings.h | 5 ++--- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/gcode.c b/gcode.c index 6eb0144..4af772f 100644 --- a/gcode.c +++ b/gcode.c @@ -2376,7 +2376,7 @@ status_code_t gc_execute_block (char *block) if (gc_block.words.e){ FAIL(Status_GcodeUnsupportedCommand); break;} - else if (!gc_block.word.p){ + else if (!gc_block.words.p){ gc_block.values.p = 1.0f;} else if (gc_block.values.p < 1.0f){ FAIL(Status_NegativeValue);} diff --git a/planner.c b/planner.c index 981a956..cfd9318 100644 --- a/planner.c +++ b/planner.c @@ -339,7 +339,7 @@ inline static float plan_compute_profile_parameters (plan_block_t *block, float return nominal_speed; } -static inline float limit_acceleration_by_axis_maximum (float *unit_vec) +static inline float limit_acceleration_by_axis_maximum (float *unit_vec,) { uint_fast8_t idx = N_AXIS; float limit_value = SOME_LARGE_VALUE; @@ -348,9 +348,6 @@ static inline float limit_acceleration_by_axis_maximum (float *unit_vec) if (unit_vec[--idx] != 0.0f) // Avoid divide by zero. limit_value = min(limit_value, fabsf(settings.axis[idx].acceleration / unit_vec[idx])); } while(idx); -#if ENABLE_ACCELERATION_PROFILES - limit_value *= block->acceleration_factor; -#endif return limit_value; } @@ -364,9 +361,6 @@ static inline float limit_jerk_by_axis_maximum (float *unit_vec) if (unit_vec[--idx] != 0.0f) // Avoid divide by zero. limit_value = min(limit_value, fabsf(settings.axis[idx].jerk / unit_vec[idx])); } while(idx); -#if ENABLE_ACCELERATION_PROFILES - limit_value *= block->acceleration_factor; -#endif return limit_value; } #endif @@ -531,8 +525,14 @@ bool plan_buffer_line (float *target, plan_line_data_t *pl_data) #ifdef KINEMATICS_API block->rate_multiplier = pl_data->rate_multiplier; #endif -#ifdef ENABLE_ACCELERATION_PROFILES +#if ENABLE_ACCELERATION_PROFILES // recalculate the acceleration limits when enabled. block->acceleration_factor = pl_data->acceleration_factor; +#if ENABLE_JERK_ACCELERATION + block->max_acceleration *= block->acceleration_factor; + block->jerk *= block->acceleration_factor; +#else + block->acceleration *= block->acceleration_factor; +#endif #endif // Store programmed rate. diff --git a/settings.h b/settings.h index b1594a8..23ef883 100644 --- a/settings.h +++ b/settings.h @@ -708,14 +708,13 @@ typedef struct { float steps_per_mm; float max_rate; float acceleration; -#if ENABLE_JERK_ACCELERATION - float jerk; -#endif float max_travel; float dual_axis_offset; float homing_seek_rate; float homing_feed_rate; +#if ENABLE_JERK_ACCELERATION float jerk; +#endif #if ENABLE_BACKLASH_COMPENSATION float backlash; #endif From c47e6a356ee03c6cb9028a863a11ae29bed601ec Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Fri, 27 Dec 2024 02:45:34 +0100 Subject: [PATCH 44/47] Debugging and Compiling --- gcode.c | 18 +++++++++--------- settings.c | 33 +++++++++++++++++++-------------- stepper.c | 11 ++++------- 3 files changed, 32 insertions(+), 30 deletions(-) diff --git a/gcode.c b/gcode.c index 4af772f..2ae6d50 100644 --- a/gcode.c +++ b/gcode.c @@ -2373,16 +2373,16 @@ status_code_t gc_execute_block (char *block) #if ENABLE_ACCELERATION_PROFILES case NonModal_SetAccelerationProfile: - if (gc_block.words.e){ + if (gc_block.words.e) FAIL(Status_GcodeUnsupportedCommand); - break;} - else if (!gc_block.words.p){ - gc_block.values.p = 1.0f;} - else if (gc_block.values.p < 1.0f){ - FAIL(Status_NegativeValue);} - else if (gc_block.values.p > 5.0f){ - FAIL(Status_GcodeValueOutOfRange);} - gc_state.modal.acceleration_profile = gc_block.values.p; + else if (!gc_block.words.p) + gc_block.values.p = 1.0f; + else if (gc_block.values.p < 1.0f) + FAIL(Status_NegativeValue); + else if (gc_block.values.p > 5.0f) + FAIL(Status_GcodeValueOutOfRange); + else + gc_state.modal.acceleration_profile = gc_block.values.p; break; #endif default: diff --git a/settings.c b/settings.c index ceda8d1..ca04836 100644 --- a/settings.c +++ b/settings.c @@ -1196,13 +1196,6 @@ static status_code_t set_axis_setting (setting_id_t setting, float value) #if ENABLE_JERK_ACCELERATION case Setting_AxisJerk: - if ((value * 60.0f * 60.0f) < (settings.axis[idx].acceleration * 10.0f)) { //ensuring that the acceleration ramp time is limited to at maximum 100ms (or 10 stepper segments). - settings.axis[idx].jerk = settings.axis[idx].acceleration * 10.0f * 60.0f; // mm/min^2 -> mm/min^3 - } - else if ((settings.axis[idx].acceleration / (value * 60.0f * 60.0f * 60.0f)) < (1.0f / ACCELERATION_TICKS_PER_SECOND)) { // Limit Jerk if value is so large that it reverts back to trapezoidal. - settings.axis[idx].jerk = settings.axis[idx].acceleration * ACCELERATION_TICKS_PER_SECOND * 60.0f; // mm/min^2 -> mm/min^3 - } - else settings.axis[idx].jerk = value * 60.0f * 60.0f * 60.0f; // Convert to mm/min^3 for grbl internal use. break; #endif @@ -1284,12 +1277,6 @@ static float get_float (setting_id_t setting) value = settings.axis[idx].acceleration / (60.0f * 60.0f); // Convert from mm/min^2 to mm/sec^2. break; -#if ENABLE_JERK_ACCELERATION - case Setting_AxisJerk: - value = settings.axis[idx].jerk / (60.0f * 60.0f * 60.0f); // Convert from mm/min^3 to mm/sec^3. - break; -#endif - case Setting_AxisMaxTravel: value = -settings.axis[idx].max_travel; // Store as negative for grbl internal use. break; @@ -1315,7 +1302,22 @@ static float get_float (setting_id_t setting) default: break; } - } else switch(setting) { + } else if(setting >= Setting_AxisSettingsBase1 && setting <= Setting_AxisSettingsMax1) { + + uint_fast8_t idx; + + switch(settings_get_axis_base(setting, &idx)) { + +#if ENABLE_JERK_ACCELERATION + case Setting_AxisJerk: + value = settings.axis[idx].jerk / (60.0f * 60.0f * 60.0f); // Convert from mm/min^3 to mm/sec^3. + break; +#endif + + default: + break; + } + } else switch(setting) { case Setting_HomingFeedRate: value = settings.axis[0].homing_feed_rate; @@ -2017,6 +2019,9 @@ PROGMEM static const setting_detail_t setting_detail[] = { { Setting_AxisMaxTravel, Group_Axis0, "-axis maximum travel", axis_dist, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, #if ENABLE_BACKLASH_COMPENSATION { Setting_AxisBacklash, Group_Axis0, "-axis backlash compensation", axis_dist, Format_Decimal, "#####0.000##", NULL, NULL, Setting_IsExtendedFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, +#endif +#if ENABLE_JERK_ACCELERATION + { Setting_AxisJerk, Group_Axis0, "-axis jerk", axis_jerk, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsExtendedFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, #endif { Setting_AxisAutoSquareOffset, Group_Axis0, "-axis dual axis offset", "mm", Format_Decimal, "-0.000", "-10", "10", Setting_IsExtendedFn, set_axis_setting, get_float, is_setting_available, AXIS_OPTS }, { Setting_AxisHomingFeedRate, Group_Axis0, "-axis homing locate feed rate", axis_rate, Format_Decimal, "###0", NULL, NULL, Setting_NonCoreFn, set_axis_setting, get_float, is_setting_available, AXIS_OPTS }, diff --git a/stepper.c b/stepper.c index aff75bf..71011db 100644 --- a/stepper.c +++ b/stepper.c @@ -898,8 +898,8 @@ void st_prep_buffer (void) case Ramp_Accel: // NOTE: Acceleration ramp only computes during first do-while loop. #if ENABLE_JERK_ACCELERATION - if (((mm_remaining - prep.accelerate_until) / (prep.current_speed + 1.0f)) <= (last_segment_accel / pl_block->jerk)) { - //+1.0f to avoid divide by 0 speed, minor effect on jerk ramp + if (((mm_remaining - prep.accelerate_until) / (prep.current_speed + 0.001f)) <= (last_segment_accel / pl_block->jerk)) { + //+0.001f to avoid divide by 0 speed, minor effect on jerk ramp (+1.0f was too large for low jerk values) // Check if we are on ramp up or ramp down. Ramp down if time to end of acceleration is less than time needed to reach 0 acceleration. // Then limit acceleration change by jerk up to max acceleration and update for next segment. // Minimum acceleration jerk per time_var to ensure acceleartion completes. Acceleration change at end of ramp is in acceptable jerk range. @@ -942,8 +942,8 @@ void st_prep_buffer (void) default: // case Ramp_Decel: // NOTE: mm_var used as a misc worker variable to prevent errors when near zero speed. #if ENABLE_JERK_ACCELERATION - if ((mm_remaining / (prep.current_speed + 1.0f)) <= (last_segment_accel / pl_block->jerk)) { - //+1.0f to avoid divide by 0 speed, minor effect on jerk ramp + if ((mm_remaining / (prep.current_speed + 0.001f)) <= (last_segment_accel / pl_block->jerk)) { + //+0.001f to avoid divide by 0 speed, minor effect on jerk ramp (+1.0f was too large for low jerk values) // Check if we are on ramp up or ramp down. Ramp down if time to end of deceleration is less than time needed to reach 0 acceleration. // Then limit acceleration change by jerk up to max acceleration and update for next segment. // Minimum acceleration of jerk per time_var to ensure acceleration completes. Acceleration change at end of ramp is in acceptable jerk range. @@ -968,9 +968,6 @@ void st_prep_buffer (void) time_var = 2.0f * (mm_remaining - prep.mm_complete) / (prep.current_speed + prep.exit_speed); mm_remaining = prep.mm_complete; prep.current_speed = prep.exit_speed; -#if ENABLE_JERK_ACCELERATION - last_segment_accel = 0.0f; // reset acceleration variable to 0 for next accel ramp -#endif } dt += time_var; // Add computed ramp time to total segment time. From 9d48143edfdff99586c99f946ace4169b580f56b Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Fri, 27 Dec 2024 12:58:21 +0100 Subject: [PATCH 45/47] Fixed the Unused Values error, removed stray comma, removed settings.h conditional --- gcode.c | 27 +++++++++++++++++++-------- planner.c | 2 +- settings.h | 2 -- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/gcode.c b/gcode.c index 2ae6d50..c20c3a2 100644 --- a/gcode.c +++ b/gcode.c @@ -2373,16 +2373,27 @@ status_code_t gc_execute_block (char *block) #if ENABLE_ACCELERATION_PROFILES case NonModal_SetAccelerationProfile: - if (gc_block.words.e) + if (gc_block.words.e) { FAIL(Status_GcodeUnsupportedCommand); - else if (!gc_block.words.p) - gc_block.values.p = 1.0f; - else if (gc_block.values.p < 1.0f) - FAIL(Status_NegativeValue); - else if (gc_block.values.p > 5.0f) - FAIL(Status_GcodeValueOutOfRange); - else + break; + } + else if (!gc_block.words.p) { + gc_block.values.p = 1.0f; gc_state.modal.acceleration_profile = gc_block.values.p; + gc_block.words.p = Off; + break; + } + else if (gc_block.values.p < 1.0f) { + FAIL(Status_NegativeValue); + break; + } + else if (gc_block.values.p > 5.0f) { + FAIL(Status_GcodeValueOutOfRange); + break; + } + else + gc_state.modal.acceleration_profile = gc_block.values.p; + gc_block.words.p = Off; break; #endif default: diff --git a/planner.c b/planner.c index cfd9318..eb80245 100644 --- a/planner.c +++ b/planner.c @@ -339,7 +339,7 @@ inline static float plan_compute_profile_parameters (plan_block_t *block, float return nominal_speed; } -static inline float limit_acceleration_by_axis_maximum (float *unit_vec,) +static inline float limit_acceleration_by_axis_maximum (float *unit_vec) { uint_fast8_t idx = N_AXIS; float limit_value = SOME_LARGE_VALUE; diff --git a/settings.h b/settings.h index 23ef883..471d857 100644 --- a/settings.h +++ b/settings.h @@ -712,9 +712,7 @@ typedef struct { float dual_axis_offset; float homing_seek_rate; float homing_feed_rate; -#if ENABLE_JERK_ACCELERATION float jerk; -#endif #if ENABLE_BACKLASH_COMPENSATION float backlash; #endif From 719017bff9f0bab50c65e2d35e801328e2dfca7a Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Fri, 27 Dec 2024 15:25:45 +0100 Subject: [PATCH 46/47] Adjusted lookup function for array counting (start from 0) and added input checking --- planner.c | 2 +- settings.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/planner.c b/planner.c index eb80245..826b644 100644 --- a/planner.c +++ b/planner.c @@ -739,6 +739,6 @@ void plan_data_init (plan_line_data_t *plan_data) plan_data->rate_multiplier = 1.0f; #endif #ifdef ENABLE_ACCELERATION_PROFILES - plan_data->acceleration_factor = lookupfactor(gc_state.modal.acceleration_profile); + plan_data->acceleration_factor = lookupfactor((int)gc_state.modal.acceleration_profile-1); //-1 for Array[0] #endif } diff --git a/settings.c b/settings.c index ca04836..d336e5e 100644 --- a/settings.c +++ b/settings.c @@ -515,6 +515,9 @@ float lookupfactor(uint8_t profile) { 0.4f, // 40% - Finish 0.2f, // 20% - Slow AF Mode }; + if (profile >= sizeof(lookup) / sizeof(lookup[0])) { + profile = 0; + } return lookup[profile]; } #endif From 84657b4f695a6bc798d0fa73283bfa6044b1b1b4 Mon Sep 17 00:00:00 2001 From: Dietz0r <102995203+Dietz0r@users.noreply.github.com> Date: Fri, 27 Dec 2024 17:44:54 +0100 Subject: [PATCH 47/47] Cleaned up the Switchcase coder after the debugging mess (thanks terje!) added the line for initilizing the acceleration_factor, renamed acceleration_profiles variable to acceleration_factor to match the rest of the code --- gcode.c | 32 +++++++++++--------------------- gcode.h | 2 +- planner.c | 4 ++-- 3 files changed, 14 insertions(+), 24 deletions(-) diff --git a/gcode.c b/gcode.c index c20c3a2..125abf2 100644 --- a/gcode.c +++ b/gcode.c @@ -362,7 +362,7 @@ void gc_init (bool stop) ngc_modal_state_invalidate(); #endif #if ENABLE_ACCELERATION_PROFILES - gc_state.modal.acceleration_profile = 1.0f; // Initialize machine with 100% Profile + gc_state.modal.acceleration_factor = 1.0f; // Initialize machine with 100% Profile #endif // if(settings.flags.lathe_mode) @@ -2373,26 +2373,13 @@ status_code_t gc_execute_block (char *block) #if ENABLE_ACCELERATION_PROFILES case NonModal_SetAccelerationProfile: - if (gc_block.words.e) { + if(gc_block.words.e) FAIL(Status_GcodeUnsupportedCommand); - break; - } - else if (!gc_block.words.p) { - gc_block.values.p = 1.0f; - gc_state.modal.acceleration_profile = gc_block.values.p; - gc_block.words.p = Off; - break; - } - else if (gc_block.values.p < 1.0f) { - FAIL(Status_NegativeValue); - break; - } - else if (gc_block.values.p > 5.0f) { - FAIL(Status_GcodeValueOutOfRange); - break; - } - else - gc_state.modal.acceleration_profile = gc_block.values.p; + + if(gc_block.words.p && (gc_block.values.p < 1.0f || gc_block.values.p > 5.0f)) + FAIL(Status_GcodeValueOutOfRange); + + gc_state.modal.acceleration_factor = lookupfactor(gc_block.words.p ? (uint8_t)gc_block.values.p - 1 : 0); gc_block.words.p = Off; break; #endif @@ -3067,6 +3054,9 @@ status_code_t gc_execute_block (char *block) memset(&plan_data, 0, sizeof(plan_line_data_t)); // Zero plan_data struct plan_data.offset_id = gc_state.offset_id; plan_data.condition.target_validated = plan_data.condition.target_valid = sys.soft_limits.mask == 0; +#if ENABLE_ACCELERATION_PROFILES + plan_data.acceleration_factor = gc_state.modal.acceleration_factor; +#endif // Intercept jog commands and complete error checking for valid jog commands and execute. // NOTE: G-code parser state is not updated, except the position to ensure sequential jog @@ -3857,7 +3847,7 @@ status_code_t gc_execute_block (char *block) gc_state.modal.override_ctrl.feed_rate_disable = Off; gc_state.modal.override_ctrl.spindle_rpm_disable = Off; #if ENABLE_ACCELERATION_PROFILES - gc_state.modal.acceleration_profile = 1.0f; + gc_state.modal.acceleration_factor = 1.0f; #endif #if N_SYS_SPINDLE > 1 diff --git a/gcode.h b/gcode.h index f7cd13b..4ec0b41 100644 --- a/gcode.h +++ b/gcode.h @@ -547,7 +547,7 @@ typedef struct { float feed_rate; //!< {F} NOTE: only set when saving modal state #endif #if ENABLE_ACCELERATION_PROFILES - float acceleration_profile; //!< {G187} currently active acceleration profile + float acceleration_factor; //!< {G187} currently active factor of acceleration profile #endif } gc_modal_t; diff --git a/planner.c b/planner.c index 826b644..9e504bd 100644 --- a/planner.c +++ b/planner.c @@ -528,7 +528,7 @@ bool plan_buffer_line (float *target, plan_line_data_t *pl_data) #if ENABLE_ACCELERATION_PROFILES // recalculate the acceleration limits when enabled. block->acceleration_factor = pl_data->acceleration_factor; #if ENABLE_JERK_ACCELERATION - block->max_acceleration *= block->acceleration_factor; + block->max_acceleration *= block->acceleration_factor; block->jerk *= block->acceleration_factor; #else block->acceleration *= block->acceleration_factor; @@ -739,6 +739,6 @@ void plan_data_init (plan_line_data_t *plan_data) plan_data->rate_multiplier = 1.0f; #endif #ifdef ENABLE_ACCELERATION_PROFILES - plan_data->acceleration_factor = lookupfactor((int)gc_state.modal.acceleration_profile-1); //-1 for Array[0] + plan_data->acceleration_factor = 1.0f; #endif }