mirror of
https://github.com/grblHAL/core.git
synced 2026-02-06 00:52:35 +08:00
Attempted fix for weird issue with VFD spindle when spindle at speed tolerance is set > 0 with $340.
2201 lines
91 KiB
C
2201 lines
91 KiB
C
/*
|
|
settings.c - non-volatile storage configuration handling
|
|
|
|
Part of grblHAL
|
|
|
|
Copyright (c) 2017-2022 Terje Io
|
|
Copyright (c) 2011-2015 Sungeun K. Jeon
|
|
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
|
|
|
Grbl is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Grbl is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <math.h>
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <assert.h>
|
|
|
|
#include "hal.h"
|
|
#include "defaults.h"
|
|
#include "limits.h"
|
|
#include "nvs_buffer.h"
|
|
#include "tool_change.h"
|
|
#include "state_machine.h"
|
|
#ifdef ENABLE_BACKLASH_COMPENSATION
|
|
#include "motion_control.h"
|
|
#endif
|
|
#ifdef ENABLE_SPINDLE_LINEARIZATION
|
|
#include <stdio.h>
|
|
#endif
|
|
|
|
#ifndef SETTINGS_RESTORE_DEFAULTS
|
|
#define SETTINGS_RESTORE_DEFAULTS 1
|
|
#endif
|
|
#ifndef SETTINGS_RESTORE_PARAMETERS
|
|
#define SETTINGS_RESTORE_PARAMETERS 1
|
|
#endif
|
|
#ifndef SETTINGS_RESTORE_STARTUP_LINES
|
|
#define SETTINGS_RESTORE_STARTUP_LINES 1
|
|
#endif
|
|
#ifndef SETTINGS_RESTORE_BUILD_INFO
|
|
#define SETTINGS_RESTORE_BUILD_INFO 1
|
|
#endif
|
|
#ifndef SETTINGS_RESTORE_DRIVER_PARAMETERS
|
|
#define SETTINGS_RESTORE_DRIVER_PARAMETERS 1
|
|
#endif
|
|
|
|
settings_t settings;
|
|
|
|
const settings_restore_t settings_all = {
|
|
.defaults = SETTINGS_RESTORE_DEFAULTS,
|
|
.parameters = SETTINGS_RESTORE_PARAMETERS,
|
|
.startup_lines = SETTINGS_RESTORE_STARTUP_LINES,
|
|
.build_info = SETTINGS_RESTORE_BUILD_INFO,
|
|
.driver_parameters = SETTINGS_RESTORE_DRIVER_PARAMETERS
|
|
};
|
|
|
|
PROGMEM const settings_t defaults = {
|
|
|
|
.version = SETTINGS_VERSION,
|
|
|
|
.junction_deviation = DEFAULT_JUNCTION_DEVIATION,
|
|
.arc_tolerance = DEFAULT_ARC_TOLERANCE,
|
|
.g73_retract = DEFAULT_G73_RETRACT,
|
|
|
|
.flags.legacy_rt_commands = DEFAULT_LEGACY_RTCOMMANDS,
|
|
.flags.report_inches = DEFAULT_REPORT_INCHES,
|
|
.flags.sleep_enable = DEFAULT_SLEEP_ENABLE,
|
|
#if DISABLE_G92_PERSISTENCE
|
|
.flags.g92_is_volatile = 1,
|
|
#else
|
|
.flags.g92_is_volatile = 0,
|
|
#endif
|
|
#if DEFAULT_LASER_MODE
|
|
.mode = Mode_Laser,
|
|
.flags.disable_laser_during_hold = DEFAULT_ENABLE_LASER_DURING_HOLD,
|
|
#else
|
|
.flags.disable_laser_during_hold = 0,
|
|
#if DEFAULT_LATHE_MODE
|
|
.mode = Mode_Lathe,
|
|
#endif
|
|
#endif
|
|
.flags.restore_after_feed_hold = DEFAULT_RESTORE_AFTER_FEED_HOLD,
|
|
.flags.force_initialization_alarm = DEFAULT_FORCE_INITIALIZATION_ALARM,
|
|
|
|
.probe.disable_probe_pullup = DISABLE_PROBE_BIT_PULL_UP,
|
|
.probe.allow_feed_override = ALLOW_FEED_OVERRIDE_DURING_PROBE_CYCLES,
|
|
.probe.invert_probe_pin = DEFAULT_INVERT_PROBE_BIT,
|
|
|
|
.steppers.pulse_microseconds = DEFAULT_STEP_PULSE_MICROSECONDS,
|
|
.steppers.pulse_delay_microseconds = DEFAULT_STEP_PULSE_DELAY,
|
|
.steppers.idle_lock_time = DEFAULT_STEPPER_IDLE_LOCK_TIME,
|
|
.steppers.step_invert.mask = DEFAULT_STEPPING_INVERT_MASK,
|
|
.steppers.dir_invert.mask = DEFAULT_DIRECTION_INVERT_MASK,
|
|
.steppers.ganged_dir_invert.mask = DEFAULT_GANGED_DIRECTION_INVERT_MASK,
|
|
.steppers.enable_invert.mask = INVERT_ST_ENABLE_MASK,
|
|
.steppers.deenergize.mask = ST_DEENERGIZE_MASK,
|
|
#if N_AXIS > 3
|
|
.steppers.is_rotational.mask = (ST_ROTATIONAL_MASK & AXES_BITMASK) >> 3,
|
|
#endif
|
|
#if DEFAULT_HOMING_ENABLE
|
|
.homing.flags.enabled = DEFAULT_HOMING_ENABLE,
|
|
.homing.flags.init_lock = DEFAULT_HOMING_INIT_LOCK,
|
|
.homing.flags.single_axis_commands = HOMING_SINGLE_AXIS_COMMANDS,
|
|
.homing.flags.force_set_origin = HOMING_FORCE_SET_ORIGIN,
|
|
.homing.flags.manual = DEFAULT_HOMING_ALLOW_MANUAL,
|
|
.homing.flags.override_locks = DEFAULT_HOMING_OVERRIDE_LOCKS,
|
|
#else
|
|
.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,
|
|
.homing.cycle[0].mask = HOMING_CYCLE_0,
|
|
.homing.cycle[1].mask = HOMING_CYCLE_1,
|
|
.homing.cycle[2].mask = HOMING_CYCLE_2,
|
|
.homing.dual_axis.fail_length_percent = DUAL_AXIS_HOMING_FAIL_AXIS_LENGTH_PERCENT,
|
|
.homing.dual_axis.fail_distance_min = DUAL_AXIS_HOMING_FAIL_DISTANCE_MIN,
|
|
.homing.dual_axis.fail_distance_max = DUAL_AXIS_HOMING_FAIL_DISTANCE_MAX,
|
|
|
|
.status_report.machine_position = DEFAULT_REPORT_BUFFER_STATE,
|
|
.status_report.buffer_state = DEFAULT_REPORT_BUFFER_STATE,
|
|
.status_report.line_numbers = DEFAULT_REPORT_LINE_NUMBERS,
|
|
.status_report.feed_speed = DEFAULT_REPORT_CURRENT_FEED_SPEED,
|
|
.status_report.pin_state = DEFAULT_REPORT_PIN_STATE,
|
|
.status_report.work_coord_offset = DEFAULT_REPORT_WORK_COORD_OFFSET,
|
|
.status_report.overrides = DEFAULT_REPORT_OVERRIDES,
|
|
.status_report.probe_coordinates = DEFAULT_REPORT_PROBE_COORDINATES,
|
|
.status_report.sync_on_wco_change = DEFAULT_REPORT_SYNC_ON_WCO_CHANGE,
|
|
.status_report.parser_state = DEFAULT_REPORT_PARSER_STATE,
|
|
.status_report.alarm_substate = DEFAULT_REPORT_ALARM_SUBSTATE,
|
|
|
|
.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.two_switches = DEFAULT_LIMITS_TWO_SWITCHES_ON_AXES,
|
|
.limits.invert.mask = INVERT_LIMIT_BIT_MASK,
|
|
.limits.disable_pullup.mask = DISABLE_LIMIT_BITS_PULL_UP_MASK,
|
|
|
|
.control_invert.mask = INVERT_CONTROL_PIN_MASK,
|
|
.control_disable_pullup.mask = DISABLE_CONTROL_PINS_PULL_UP_MASK,
|
|
|
|
.spindle.rpm_max = DEFAULT_SPINDLE_RPM_MAX,
|
|
.spindle.rpm_min = DEFAULT_SPINDLE_RPM_MIN,
|
|
.spindle.flags.pwm_action = DEFAULT_SPINDLE_PWM_ACTION,
|
|
.spindle.invert.on = INVERT_SPINDLE_ENABLE_PIN,
|
|
.spindle.invert.ccw = INVERT_SPINDLE_CCW_PIN,
|
|
.spindle.invert.pwm = 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.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,
|
|
#if SPINDLE_NPWM_PIECES > 0
|
|
.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 },
|
|
#endif
|
|
#if SPINDLE_NPWM_PIECES > 2
|
|
.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 },
|
|
#endif
|
|
|
|
.coolant_invert.flood = INVERT_COOLANT_FLOOD_PIN,
|
|
.coolant_invert.mist = INVERT_COOLANT_MIST_PIN,
|
|
|
|
.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,
|
|
.axis[X_AXIS].max_travel = (-DEFAULT_X_MAX_TRAVEL),
|
|
.axis[X_AXIS].dual_axis_offset = 0.0f,
|
|
#ifdef ENABLE_BACKLASH_COMPENSATION
|
|
.axis[X_AXIS].backlash = 0.0f,
|
|
#endif
|
|
|
|
.axis[Y_AXIS].steps_per_mm = DEFAULT_Y_STEPS_PER_MM,
|
|
.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,
|
|
.axis[Y_AXIS].dual_axis_offset = 0.0f,
|
|
#ifdef ENABLE_BACKLASH_COMPENSATION
|
|
.axis[Y_AXIS].backlash = 0.0f,
|
|
#endif
|
|
|
|
.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,
|
|
.axis[Z_AXIS].max_travel = (-DEFAULT_Z_MAX_TRAVEL),
|
|
.axis[Z_AXIS].dual_axis_offset = 0.0f,
|
|
#ifdef ENABLE_BACKLASH_COMPENSATION
|
|
.axis[Z_AXIS].backlash = 0.0f,
|
|
#endif
|
|
|
|
#ifdef A_AXIS
|
|
.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,
|
|
.axis[A_AXIS].max_travel = (-DEFAULT_A_MAX_TRAVEL),
|
|
.axis[A_AXIS].dual_axis_offset = 0.0f,
|
|
#ifdef ENABLE_BACKLASH_COMPENSATION
|
|
.axis[A_AXIS].backlash = 0.0f,
|
|
#endif
|
|
.homing.cycle[3].mask = HOMING_CYCLE_3,
|
|
#endif
|
|
|
|
#ifdef B_AXIS
|
|
.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,
|
|
.axis[B_AXIS].max_travel = (-DEFAULT_B_MAX_TRAVEL),
|
|
.axis[B_AXIS].dual_axis_offset = 0.0f,
|
|
#ifdef ENABLE_BACKLASH_COMPENSATION
|
|
.axis[B_AXIS].backlash = 0.0f,
|
|
#endif
|
|
.homing.cycle[4].mask = HOMING_CYCLE_4,
|
|
#endif
|
|
|
|
#ifdef C_AXIS
|
|
.axis[C_AXIS].steps_per_mm = DEFAULT_C_STEPS_PER_MM,
|
|
.axis[C_AXIS].acceleration = DEFAULT_C_ACCELERATION,
|
|
.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,
|
|
#ifdef ENABLE_BACKLASH_COMPENSATION
|
|
.axis[C_AXIS].backlash = 0.0f,
|
|
#endif
|
|
.homing.cycle[5].mask = HOMING_CYCLE_5,
|
|
#endif
|
|
|
|
#ifdef U_AXIS
|
|
.axis[U_AXIS].steps_per_mm = DEFAULT_U_STEPS_PER_MM,
|
|
.axis[U_AXIS].acceleration = DEFAULT_U_ACCELERATION,
|
|
.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,
|
|
#ifdef ENABLE_BACKLASH_COMPENSATION
|
|
.axis[U_AXIS].backlash = 0.0f,
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef V_AXIS
|
|
.axis[V_AXIS].steps_per_mm = DEFAULT_V_STEPS_PER_MM,
|
|
.axis[V_AXIS].acceleration = DEFAULT_V_ACCELERATION,
|
|
.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,
|
|
#ifdef ENABLE_BACKLASH_COMPENSATION
|
|
.axis[V_AXIS].backlash = 0.0f,
|
|
#endif
|
|
#endif
|
|
|
|
.tool_change.mode = (toolchange_mode_t)DEFAULT_TOOLCHANGE_MODE,
|
|
.tool_change.probing_distance = DEFAULT_TOOLCHANGE_PROBING_DISTANCE,
|
|
.tool_change.feed_rate = DEFAULT_TOOLCHANGE_FEED_RATE,
|
|
.tool_change.seek_rate = DEFAULT_TOOLCHANGE_SEEK_RATE,
|
|
.tool_change.pulloff_rate = DEFAULT_TOOLCHANGE_PULLOFF_RATE,
|
|
|
|
.parking.flags.enabled = DEFAULT_PARKING_ENABLE,
|
|
.parking.flags.deactivate_upon_init = DEFAULT_DEACTIVATE_PARKING_UPON_INIT,
|
|
.parking.flags.enable_override_control= DEFAULT_ENABLE_PARKING_OVERRIDE_CONTROL,
|
|
.parking.axis = DEFAULT_PARKING_AXIS,
|
|
.parking.target = DEFAULT_PARKING_TARGET,
|
|
.parking.rate = DEFAULT_PARKING_RATE,
|
|
.parking.pullout_rate = DEFAULT_PARKING_PULLOUT_RATE,
|
|
.parking.pullout_increment = DEFAULT_PARKING_PULLOUT_INCREMENT,
|
|
|
|
.safety_door.spindle_on_delay = SAFETY_DOOR_SPINDLE_DELAY,
|
|
.safety_door.coolant_on_delay = SAFETY_DOOR_COOLANT_DELAY
|
|
};
|
|
|
|
PROGMEM static const setting_group_detail_t setting_group_detail [] = {
|
|
{ Group_Root, Group_Root, "Root"},
|
|
{ Group_Root, Group_General, "General"},
|
|
{ Group_Root, Group_ControlSignals, "Control signals"},
|
|
{ Group_Root, Group_Limits, "Limits"},
|
|
{ Group_Limits, Group_Limits_DualAxis, "Dual axis"},
|
|
{ Group_Root, Group_Coolant, "Coolant"},
|
|
{ Group_Root, Group_Spindle, "Spindle"},
|
|
{ Group_Spindle, Group_Spindle_Sync, "Spindle sync"},
|
|
{ Group_Root, Group_Toolchange, "Tool change"},
|
|
{ Group_Root, Group_Homing, "Homing"},
|
|
{ Group_Root, Group_Probing, "Probing"},
|
|
{ Group_Root, Group_SafetyDoor, "Safety door"},
|
|
{ Group_Root, Group_Jogging, "Jogging"},
|
|
{ Group_Root, Group_Stepper, "Stepper"},
|
|
{ Group_Root, Group_MotorDriver, "Stepper driver"},
|
|
{ Group_Root, Group_Axis, "Axis"},
|
|
{ Group_Axis, Group_XAxis, "X-axis"},
|
|
{ Group_Axis, Group_YAxis, "Y-axis"},
|
|
{ Group_Axis, Group_ZAxis, "Z-axis"},
|
|
#ifdef A_AXIS
|
|
{ Group_Axis, Group_AAxis, "A-axis"},
|
|
#endif
|
|
#ifdef B_AXIS
|
|
{ Group_Axis, Group_BAxis, "B-axis"},
|
|
#endif
|
|
#ifdef C_AXIS
|
|
{ Group_Axis, Group_CAxis, "C-axis"},
|
|
#endif
|
|
#ifdef U_AXIS
|
|
{ Group_Axis, Group_UAxis, "U-axis"},
|
|
#endif
|
|
#ifdef V_AXIS
|
|
{ Group_Axis, Group_VAxis, "V-axis"}
|
|
#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_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);
|
|
static status_code_t set_mode (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);
|
|
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_ganged_dir_invert (setting_id_t id, uint_fast16_t int_value);
|
|
#ifdef ENABLE_SAFETY_DOOR_INPUT_PIN
|
|
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
|
|
#ifdef 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_rotational_axes (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);
|
|
|
|
static char control_signals[] = "Reset,Feed hold,Cycle start,Safety door,Block delete,Optional stop,EStop,Probe connected,Motor fault";
|
|
static char spindle_signals[] = "Spindle enable,Spindle direction,PWM";
|
|
static char coolant_signals[] = "Flood,Mist";
|
|
static char ganged_axes[] = "X-Axis,Y-Axis,Z-Axis";
|
|
|
|
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 },
|
|
{ Setting_InvertStepperEnable, Group_Stepper, "Invert stepper enable pin(s)", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsLegacy, &settings.steppers.enable_invert.mask, NULL, NULL },
|
|
#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 },
|
|
#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, "Disable spindle with zero speed", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtended, &settings.spindle.flags.mask, NULL, is_setting_available },
|
|
// { Setting_SpindlePWMBehaviour, Group_Spindle, "Spindle enable vs. speed behaviour", NULL, Format_RadioButtons, "No action,Disable spindle with zero speed,Enable spindle with all speeds", NULL, NULL, Setting_IsExtended, &settings.spindle.flags.mask, NULL, NULL },
|
|
{ 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 },
|
|
#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", 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 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, NULL },
|
|
{ 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
|
|
{ Setting_HardLimitsEnable, Group_Limits, "Hard limits enable", NULL, Format_XBitfield, "Enable,Strict mode", NULL, NULL, Setting_IsExpandedFn, set_hard_limits_enable, get_int, NULL },
|
|
#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, "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", 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_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 },
|
|
{ Setting_Mode, Group_General, "Mode of operation", NULL, Format_RadioButtons, "Normal,Laser mode,Lathe mode", NULL, NULL, Setting_IsLegacyFn, set_mode, get_int, NULL },
|
|
{ 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_StepperDeenergizeMask, Group_Stepper, "Steppers deenergize", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtended, &settings.steppers.deenergize.mask, NULL, 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 },
|
|
{ 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 },
|
|
#ifdef ENABLE_SAFETY_DOOR_INPUT_PIN
|
|
{ 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, NULL },
|
|
{ Setting_ParkingAxis, Group_SafetyDoor, "Parking axis", NULL, Format_RadioButtons, "X,Y,Z", NULL, NULL, Setting_IsExtended, &settings.parking.axis, NULL, NULL },
|
|
#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
|
|
#ifdef ENABLE_SAFETY_DOOR_INPUT_PIN
|
|
{ Setting_ParkingPulloutIncrement, Group_SafetyDoor, "Parking pull-out distance", "mm", Format_Decimal, "###0.0", NULL, NULL, Setting_IsExtended, &settings.parking.pullout_increment, NULL, NULL },
|
|
{ Setting_ParkingPulloutRate, Group_SafetyDoor, "Parking pull-out rate", "mm/min", Format_Decimal, "###0.0", NULL, NULL, Setting_IsExtended, &settings.parking.pullout_rate, NULL, NULL },
|
|
{ Setting_ParkingTarget, Group_SafetyDoor, "Parking target", "mm", Format_Decimal, "-###0.0", "-100000", NULL, Setting_IsExtended, &settings.parking.target, NULL, NULL },
|
|
{ Setting_ParkingFastRate, Group_SafetyDoor, "Parking fast rate", "mm/min", Format_Decimal, "###0.0", NULL, NULL, Setting_IsExtended, &settings.parking.rate, NULL, NULL },
|
|
{ Setting_RestoreOverrides, Group_General, "Restore overrides", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_restore_overrides, get_int, NULL },
|
|
{ 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, NULL },
|
|
#endif
|
|
{ Setting_SleepEnable, Group_General, "Sleep enable", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_sleep_enable, get_int, NULL },
|
|
{ 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 },
|
|
#ifdef ENABLE_SPINDLE_LINEARIZATION
|
|
{ Setting_LinearSpindlePiece1, Group_Spindle, "Spindle linearisation, first point", NULL, Format_String, "x30", NULL, "30", Setting_IsExtendedFn, set_linear_piece, get_linear_piece, NULL },
|
|
{ Setting_LinearSpindlePiece2, Group_Spindle, "Spindle linearisation, second point", NULL, Format_String, "x30", NULL, "30", Setting_IsExtendedFn, set_linear_piece, get_linear_piece, NULL },
|
|
{ Setting_LinearSpindlePiece3, Group_Spindle, "Spindle linearisation, third point", NULL, Format_String, "x30", NULL, "30", Setting_IsExtendedFn, set_linear_piece, get_linear_piece, NULL },
|
|
{ Setting_LinearSpindlePiece4, Group_Spindle, "Spindle linearisation, fourth point", NULL, Format_String, "x30", NULL, "30", Setting_IsExtendedFn, set_linear_piece, get_linear_piece, NULL },
|
|
#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", "step/mm", Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL },
|
|
{ Setting_AxisMaxRate, Group_Axis0, "?-axis maximum rate", "mm/min", Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL },
|
|
{ Setting_AxisAcceleration, Group_Axis0, "?-axis acceleration", "mm/sec^2", Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL },
|
|
{ Setting_AxisMaxTravel, Group_Axis0, "?-axis maximum travel", "mm", Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL },
|
|
#ifdef ENABLE_BACKLASH_COMPENSATION
|
|
{ Setting_AxisBacklash, Group_Axis0, "?-axis backlash compensation", "mm", Format_Decimal, "#####0.000", NULL, NULL, Setting_IsExtendedFn, set_axis_setting, get_float, NULL },
|
|
#endif
|
|
{ Setting_AxisAutoSquareOffset, Group_Axis0, "?-axis dual axis offset", "mm", Format_Decimal, "-0.000", "-2", "2", Setting_IsExtendedFn, set_axis_setting, get_float, is_setting_available },
|
|
{ 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_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 == 4
|
|
{ Settings_Axis_Rotational, Group_Stepper, "Rotational axes", NULL, Format_Bitfield, "A-Axis", NULL, NULL, Setting_IsExtendedFn, set_rotational_axes, get_int, NULL },
|
|
#elif N_AXIS == 5
|
|
{ Settings_Axis_Rotational, Group_Stepper, "Rotational axes", NULL, Format_Bitfield, "A-Axis,B-Axis", NULL, NULL, Setting_IsExtendedFn, set_rotational_axes, get_int, NULL },
|
|
#elif N_AXIS > 5
|
|
{ Settings_Axis_Rotational, Group_Stepper, "Rotational axes", NULL, Format_Bitfield, "A-Axis,B-Axis,C-Axis", NULL, NULL, Setting_IsExtendedFn, set_rotational_axes, get_int, NULL },
|
|
#endif
|
|
#ifdef ENABLE_SAFETY_DOOR_INPUT_PIN
|
|
{ Setting_DoorSpindleOnDelay, Group_SafetyDoor, "Spindle on delay", "s", Format_Decimal, "#0.0", "0.5", "20", Setting_IsExtended, &settings.safety_door.spindle_on_delay, NULL, NULL },
|
|
{ Setting_DoorCoolantOnDelay, Group_SafetyDoor, "Coolant on delay", "s", Format_Decimal, "#0.0", "0.5", "20", Setting_IsExtended, &settings.safety_door.coolant_on_delay, NULL, NULL },
|
|
#else
|
|
{ Setting_DoorSpindleOnDelay, 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 },
|
|
#endif
|
|
};
|
|
|
|
#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)." },
|
|
{ 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."
|
|
},
|
|
{ Setting_LimitPinsInvertMask, "Inverts the axis limit input signals." },
|
|
{ Setting_InvertProbePin, "Inverts the probe input pin signal." },
|
|
{ Setting_SpindlePWMBehaviour, "" },
|
|
{ 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.\\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<axis letter> commands.\\n\\n"
|
|
"When `Allow manual` is checked, axes not homed automatically may be homed manually by $H or $H<axis letter> 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. Sets PWM to maximum duty cycle." },
|
|
{ Setting_RpmMin, "Minimum spindle speed. Sets PWM to minimum duty cycle." },
|
|
{ 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."
|
|
},
|
|
{ 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_StepperDeenergizeMask, "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." },
|
|
#ifdef ENABLE_SAFETY_DOOR_INPUT_PIN
|
|
{ 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." },
|
|
{ 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_AxisMaxRate, "Maximum rate. Used as G0 rapid rate." },
|
|
{ Setting_AxisAcceleration, "Acceleration. Used for motion planning to not exceed motor torque and lose steps." },
|
|
{ Setting_AxisMaxTravel, "Maximum axis travel distance from homing switch. Determines valid machine space for soft-limits and homing search distances." },
|
|
#ifdef 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_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
|
|
#ifdef ENABLE_SAFETY_DOOR_INPUT_PIN
|
|
{ Setting_DoorSpindleOnDelay, "Delay to allow spindle to spin up after safety door is opened." },
|
|
{ Setting_DoorCoolantOnDelay, "Delay to allow coolant to restart after safety door is opened." },
|
|
#else
|
|
{ Setting_DoorSpindleOnDelay, "Delay to allow spindle to spin up when spindle at speed tolerance is > 0." },
|
|
#endif
|
|
};
|
|
|
|
#endif
|
|
|
|
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
|
|
};
|
|
|
|
// 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 = acceleration * 60.0f * 60.0f; // Limit max to setting value?
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// ---
|
|
|
|
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 > 1
|
|
static status_code_t set_limits_invert_mask (setting_id_t id, uint_fast16_t int_value)
|
|
{
|
|
settings.limits.invert.mask = (int_value ? ~(INVERT_LIMIT_BIT_MASK) : INVERT_LIMIT_BIT_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 != 0;
|
|
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_report_mask (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
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
|
|
return Status_OK;
|
|
}
|
|
|
|
static status_code_t set_spindle_invert (setting_id_t id, uint_fast16_t int_value)
|
|
{
|
|
settings.spindle.invert.mask = int_value;
|
|
if(settings.spindle.invert.pwm && !hal.driver_cap.spindle_pwm_invert) {
|
|
settings.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;
|
|
|
|
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 != 0;
|
|
|
|
return Status_OK;
|
|
}
|
|
|
|
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.flags.soft_enabled = int_value != 0;
|
|
|
|
return Status_OK;
|
|
}
|
|
|
|
static status_code_t set_hard_limits_enable (setting_id_t id, uint_fast16_t int_value)
|
|
{
|
|
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));
|
|
#endif
|
|
hal.limits.enable(settings.limits.flags.hard_enabled, false); // Change immediately. NOTE: Nice to have but could be problematic later.
|
|
|
|
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)
|
|
{
|
|
if (bit_istrue(int_value, bit(0))) {
|
|
#if COMPATIBILITY_LEVEL > 1
|
|
settings.homing.flags.enabled = On;
|
|
#else
|
|
settings.homing.flags.value = int_value & 0x0F;
|
|
settings.limits.flags.two_switches = bit_istrue(int_value, bit(4));
|
|
settings.homing.flags.manual = bit_istrue(int_value, bit(5));
|
|
settings.homing.flags.override_locks = bit_istrue(int_value, bit(6));
|
|
settings.homing.flags.keep_on_reset = bit_istrue(int_value, bit(7));
|
|
#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;
|
|
|
|
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;
|
|
}
|
|
|
|
static status_code_t set_mode (setting_id_t id, uint_fast16_t int_value)
|
|
{
|
|
switch((machine_mode_t)int_value) {
|
|
|
|
case Mode_Standard:
|
|
settings.flags.disable_laser_during_hold = 0;
|
|
gc_state.modal.diameter_mode = false;
|
|
break;
|
|
|
|
case Mode_Laser:
|
|
if(!hal.driver_cap.variable_spindle)
|
|
return Status_SettingDisabledLaser;
|
|
if(settings.mode != Mode_Laser)
|
|
settings.flags.disable_laser_during_hold = DEFAULT_ENABLE_LASER_DURING_HOLD;
|
|
gc_state.modal.diameter_mode = false;
|
|
break;
|
|
|
|
case Mode_Lathe:
|
|
settings.flags.disable_laser_during_hold = 0;
|
|
break;
|
|
|
|
default: // Mode_Standard
|
|
return Status_InvalidStatement;
|
|
}
|
|
|
|
settings.mode = (machine_mode_t)int_value;
|
|
|
|
return Status_OK;
|
|
}
|
|
|
|
#ifdef ENABLE_SAFETY_DOOR_INPUT_PIN
|
|
|
|
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;
|
|
|
|
return Status_OK;
|
|
}
|
|
|
|
static status_code_t set_restore_overrides (setting_id_t id, uint_fast16_t int_value)
|
|
{
|
|
settings.flags.restore_overrides = int_value != 0;;
|
|
|
|
return Status_OK;
|
|
}
|
|
|
|
#endif
|
|
|
|
static status_code_t set_sleep_enable (setting_id_t id, uint_fast16_t int_value)
|
|
{
|
|
settings.flags.sleep_enable = int_value != 0;
|
|
|
|
return Status_OK;
|
|
}
|
|
|
|
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));
|
|
|
|
return Status_OK;
|
|
}
|
|
|
|
#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;
|
|
|
|
return Status_OK;
|
|
}
|
|
#endif
|
|
|
|
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;
|
|
|
|
return Status_OK;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
#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;
|
|
|
|
settings.tool_change.probing_distance = value;
|
|
|
|
return Status_OK;
|
|
}
|
|
|
|
#if N_AXIS > 3
|
|
static status_code_t set_rotational_axes (setting_id_t id, uint_fast16_t int_value)
|
|
{
|
|
settings.steppers.is_rotational.mask = (int_value << 3) & AXES_BITMASK;
|
|
|
|
return Status_OK;
|
|
}
|
|
#endif
|
|
|
|
#ifdef ENABLE_SPINDLE_LINEARIZATION
|
|
|
|
static status_code_t set_linear_piece (setting_id_t id, char *svalue)
|
|
{
|
|
uint32_t idx = id - Setting_LinearSpindlePiece1;
|
|
float rpm, start, end;
|
|
|
|
if(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;
|
|
} else
|
|
return Status_InvalidStatement;
|
|
|
|
return Status_OK;
|
|
}
|
|
|
|
static char *get_linear_piece (setting_id_t id)
|
|
{
|
|
static char buf[20];
|
|
|
|
uint32_t idx = id - Setting_LinearSpindlePiece1;
|
|
|
|
if(isnan(settings.spindle.pwm_piece[idx].rpm))
|
|
strcpy(buf, ftoa(settings.spindle.pwm_piece[idx].rpm, N_DECIMAL_RPMVALUE));
|
|
else {
|
|
sprintf(buf, "$%d=%f,%f,%f" ASCII_EOL, (setting_id_t)(Setting_LinearSpindlePiece1 + idx), settings.spindle.pwm_piece[idx].rpm, settings.spindle.pwm_piece[idx].start, settings.spindle.pwm_piece[idx].end);
|
|
hal.stream.write(buf);
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
#endif
|
|
|
|
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));
|
|
|
|
return id;
|
|
}
|
|
|
|
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;
|
|
|
|
return *idx < N_AXIS ? base : Setting_SettingsMax;
|
|
}
|
|
|
|
static status_code_t set_axis_setting (setting_id_t setting, float value)
|
|
{
|
|
uint_fast8_t idx;
|
|
status_code_t status = Status_OK;
|
|
|
|
switch(settings_get_axis_base(setting, &idx)) {
|
|
|
|
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.probe_position[idx] *= comp;
|
|
sys.tlo_reference[idx] *= comp;
|
|
sync_position();
|
|
}
|
|
settings.axis[idx].steps_per_mm = value;
|
|
}
|
|
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;
|
|
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.
|
|
break;
|
|
|
|
case Setting_AxisMaxTravel:
|
|
settings.axis[idx].max_travel = -value; // Store as negative for grbl internal use.
|
|
break;
|
|
|
|
case Setting_AxisBacklash:
|
|
#ifdef ENABLE_BACKLASH_COMPENSATION
|
|
settings.axis[idx].backlash = value;
|
|
#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;
|
|
break;
|
|
|
|
default:
|
|
status = Status_SettingDisabled;
|
|
break;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
static float get_float (setting_id_t setting)
|
|
{
|
|
float value = 0.0f;
|
|
|
|
if (setting >= Setting_AxisSettingsBase && setting <= Setting_AxisSettingsMax) {
|
|
|
|
uint_fast8_t idx;
|
|
|
|
switch(settings_get_axis_base(setting, &idx)) {
|
|
|
|
case Setting_AxisStepsPerMM:
|
|
value = settings.axis[idx].steps_per_mm;
|
|
break;
|
|
|
|
case Setting_AxisMaxRate:
|
|
value = settings.axis[idx].max_rate;
|
|
break;
|
|
|
|
case Setting_AxisAcceleration:
|
|
value = settings.axis[idx].acceleration / (60.0f * 60.0f); // Convert to mm/min^2 for grbl internal use.
|
|
break;
|
|
|
|
case Setting_AxisMaxTravel:
|
|
value = -settings.axis[idx].max_travel; // Store as negative for grbl internal use.
|
|
break;
|
|
|
|
#ifdef ENABLE_BACKLASH_COMPENSATION
|
|
case Setting_AxisBacklash:
|
|
value = settings.axis[idx].backlash;
|
|
break;
|
|
#endif
|
|
|
|
case Setting_AxisAutoSquareOffset:
|
|
value = settings.axis[idx].dual_axis_offset;
|
|
break;
|
|
|
|
default: // for stopping compiler warning
|
|
break;
|
|
}
|
|
} else switch(setting) {
|
|
|
|
case Setting_ToolChangeProbingDistance:
|
|
value = settings.tool_change.probing_distance;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
static uint32_t get_int (setting_id_t id)
|
|
{
|
|
uint32_t value = 0;
|
|
|
|
switch(id) {
|
|
|
|
#if COMPATIBILITY_LEVEL > 1
|
|
case Setting_LimitPinsInvertMask:
|
|
value = settings.limits.invert.mask == INVERT_LIMIT_BIT_MASK ? 0 : 1;
|
|
break;
|
|
#endif
|
|
|
|
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;
|
|
#else
|
|
value = settings.status_report.mask & 0b11;
|
|
#endif
|
|
break;
|
|
|
|
case Setting_ReportInches:
|
|
value = settings.flags.report_inches;
|
|
break;
|
|
|
|
case Setting_ControlInvertMask:
|
|
value = settings.control_invert.mask & hal.signals_cap.mask;
|
|
break;
|
|
|
|
case Setting_SpindleInvertMask:
|
|
value = settings.spindle.invert.mask;
|
|
break;
|
|
|
|
case Setting_ControlPullUpDisableMask:
|
|
value = settings.control_disable_pullup.mask & hal.signals_cap.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) : 0);
|
|
break;
|
|
|
|
case Setting_JogSoftLimited:
|
|
value = settings.limits.flags.jog_soft_limited;
|
|
break;
|
|
|
|
case Setting_HomingEnable:
|
|
value = (settings.homing.flags.value & 0x0F) |
|
|
(settings.limits.flags.two_switches ? bit(4) : 0) |
|
|
(settings.homing.flags.manual ? bit(5) : 0) |
|
|
(settings.homing.flags.override_locks ? bit(6) : 0) |
|
|
(settings.homing.flags.keep_on_reset ? bit(7) : 0);
|
|
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_DisableG92Persistence:
|
|
value = settings.flags.g92_is_volatile;
|
|
break;
|
|
|
|
#if N_AXIS > 3
|
|
case Settings_Axis_Rotational:
|
|
value = (settings.steppers.is_rotational.mask & AXES_BITMASK) >> 3;
|
|
break;
|
|
#endif
|
|
|
|
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;
|
|
setting_id_t id = (setting_id_t)(setting->id + offset);
|
|
|
|
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_String:
|
|
case Format_Password:
|
|
case Format_IPv4:
|
|
value = ((char *)(setting->value));
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case Setting_NonCoreFn:
|
|
case Setting_IsExtendedFn:
|
|
case Setting_IsLegacyFn:
|
|
case Setting_IsExpandedFn:
|
|
switch(setting->datatype) {
|
|
|
|
case Format_Decimal:
|
|
value = ftoa(((setting_get_float_ptr)(setting->get_value))(id), get_decimal_places(setting->format));
|
|
break;
|
|
|
|
case Format_String:
|
|
case Format_Password:
|
|
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 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_SpindlePWMBehaviour:
|
|
available = hal.driver_cap.variable_spindle;
|
|
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_SpindlePPR:
|
|
available = hal.driver_cap.spindle_sync || hal.driver_cap.spindle_pid;
|
|
break;
|
|
|
|
case Setting_SpindleAtSpeedTolerance:
|
|
case Setting_DoorSpindleOnDelay:
|
|
available = hal.driver_cap.spindle_at_speed;
|
|
break;
|
|
|
|
case Setting_RpmMax:
|
|
case Setting_RpmMin:
|
|
case Setting_PWMFreq:
|
|
case Setting_PWMOffValue:
|
|
case Setting_PWMMinValue:
|
|
case Setting_PWMMaxValue:
|
|
available = hal.driver_cap.variable_spindle;
|
|
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;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return available;
|
|
}
|
|
|
|
// Write build info to persistent storage
|
|
void settings_write_build_info (char *line)
|
|
{
|
|
if(hal.nvs.type != NVS_None)
|
|
hal.nvs.memcpy_to_nvs(NVS_ADDR_BUILD_INFO, (uint8_t *)line, sizeof(stored_line_t), true);
|
|
}
|
|
|
|
// Read build info from persistent storage.
|
|
bool settings_read_build_info(char *line)
|
|
{
|
|
if (!(hal.nvs.type != NVS_None && hal.nvs.memcpy_from_nvs((uint8_t *)line, NVS_ADDR_BUILD_INFO, sizeof(stored_line_t), true) == NVS_TransferResult_OK)) {
|
|
// Reset line with default value
|
|
line[0] = 0; // Empty line
|
|
settings_write_build_info(line);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Write startup line to persistent storage
|
|
void settings_write_startup_line (uint8_t idx, char *line)
|
|
{
|
|
assert(idx < N_STARTUP_LINE);
|
|
|
|
#ifdef FORCE_BUFFER_SYNC_DURING_NVS_WRITE
|
|
protocol_buffer_synchronize(); // A startup line may contain a motion and be executing.
|
|
#endif
|
|
|
|
if(hal.nvs.type != NVS_None)
|
|
hal.nvs.memcpy_to_nvs(NVS_ADDR_STARTUP_BLOCK + idx * (sizeof(stored_line_t) + NVS_CRC_BYTES), (uint8_t *)line, sizeof(stored_line_t), true);
|
|
}
|
|
|
|
// Read startup line to persistent storage.
|
|
bool settings_read_startup_line (uint8_t idx, char *line)
|
|
{
|
|
assert(idx < N_STARTUP_LINE);
|
|
|
|
if (!(hal.nvs.type != NVS_None && hal.nvs.memcpy_from_nvs((uint8_t *)line, NVS_ADDR_STARTUP_BLOCK + idx * (sizeof(stored_line_t) + NVS_CRC_BYTES), sizeof(stored_line_t), true) == NVS_TransferResult_OK)) {
|
|
// Reset line with default value
|
|
*line = '\0'; // Empty line
|
|
settings_write_startup_line(idx, line);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Write selected coordinate data to persistent storage.
|
|
void settings_write_coord_data (coord_system_id_t id, float (*coord_data)[N_AXIS])
|
|
{
|
|
assert(id <= N_CoordinateSystems);
|
|
|
|
#ifdef FORCE_BUFFER_SYNC_DURING_NVS_WRITE
|
|
protocol_buffer_synchronize();
|
|
#endif
|
|
|
|
if(hal.nvs.type != NVS_None)
|
|
hal.nvs.memcpy_to_nvs(NVS_ADDR_PARAMETERS + id * (sizeof(coord_data_t) + NVS_CRC_BYTES), (uint8_t *)coord_data, sizeof(coord_data_t), true);
|
|
}
|
|
|
|
// Read selected coordinate data from persistent storage.
|
|
bool settings_read_coord_data (coord_system_id_t id, float (*coord_data)[N_AXIS])
|
|
{
|
|
assert(id <= N_CoordinateSystems);
|
|
|
|
if (!(hal.nvs.type != NVS_None && hal.nvs.memcpy_from_nvs((uint8_t *)coord_data, NVS_ADDR_PARAMETERS + id * (sizeof(coord_data_t) + NVS_CRC_BYTES), sizeof(coord_data_t), true) == NVS_TransferResult_OK)) {
|
|
// Reset with default zero vector
|
|
memset(coord_data, 0, sizeof(coord_data_t));
|
|
settings_write_coord_data(id, coord_data);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Write selected tool data to persistent storage.
|
|
bool settings_write_tool_data (tool_data_t *tool_data)
|
|
{
|
|
#ifdef N_TOOLS
|
|
assert(tool_data->tool > 0 && tool_data->tool <= N_TOOLS); // NOTE: idx 0 is a non-persistent entry for tools not in tool table
|
|
|
|
if(hal.nvs.type != NVS_None)
|
|
hal.nvs.memcpy_to_nvs(NVS_ADDR_TOOL_TABLE + (tool_data->tool - 1) * (sizeof(tool_data_t) + NVS_CRC_BYTES), (uint8_t *)tool_data, sizeof(tool_data_t), true);
|
|
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
// Read selected tool data from persistent storage.
|
|
bool settings_read_tool_data (uint32_t tool, tool_data_t *tool_data)
|
|
{
|
|
#ifdef N_TOOLS
|
|
assert(tool > 0 && tool <= N_TOOLS); // NOTE: idx 0 is a non-persistent entry for tools not in tool table
|
|
|
|
if (!(hal.nvs.type != NVS_None && hal.nvs.memcpy_from_nvs((uint8_t *)tool_data, NVS_ADDR_TOOL_TABLE + (tool - 1) * (sizeof(tool_data_t) + NVS_CRC_BYTES), sizeof(tool_data_t), true) == NVS_TransferResult_OK && tool_data->tool == tool)) {
|
|
memset(tool_data, 0, sizeof(tool_data_t));
|
|
tool_data->tool = tool;
|
|
}
|
|
|
|
return tool_data->tool == tool;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
// Read global settings from persistent storage.
|
|
// Checks version-byte of non-volatile storage and global settings copy.
|
|
bool read_global_settings ()
|
|
{
|
|
bool ok = hal.nvs.type != NVS_None && SETTINGS_VERSION == hal.nvs.get_byte(0) && hal.nvs.memcpy_from_nvs((uint8_t *)&settings, NVS_ADDR_GLOBAL, sizeof(settings_t), true) == NVS_TransferResult_OK;
|
|
|
|
// Sanity check of settings, board map could have been changed...
|
|
if(settings.mode == Mode_Laser && !hal.driver_cap.variable_spindle)
|
|
settings.mode = Mode_Standard;
|
|
|
|
#if COMPATIBILITY_LEVEL > 1 && DISABLE_G92_PERSISTENCE
|
|
settings.flags.g92_is_volatile = On;
|
|
#endif
|
|
|
|
return ok && settings.version == SETTINGS_VERSION;
|
|
}
|
|
|
|
|
|
// Write global settings to persistent storage
|
|
void settings_write_global (void)
|
|
{
|
|
if(override_backup.valid)
|
|
restore_override_backup();
|
|
|
|
if(hal.nvs.type != NVS_None)
|
|
hal.nvs.memcpy_to_nvs(NVS_ADDR_GLOBAL, (uint8_t *)&settings, sizeof(settings_t), true);
|
|
}
|
|
|
|
|
|
// Restore global settings to defaults and write to persistent storage
|
|
void settings_restore (settings_restore_t restore)
|
|
{
|
|
uint_fast8_t idx;
|
|
stored_line_t empty_line;
|
|
|
|
memset(empty_line, 0xFF, sizeof(stored_line_t));
|
|
*empty_line = '\0';
|
|
|
|
hal.nvs.put_byte(0, SETTINGS_VERSION); // Forces write to physical storage
|
|
|
|
if (restore.defaults) {
|
|
memcpy(&settings, &defaults, sizeof(settings_t));
|
|
|
|
settings.control_invert.mask &= hal.signals_cap.mask;
|
|
settings.spindle.invert.ccw &= hal.driver_cap.spindle_dir;
|
|
settings.spindle.invert.pwm &= hal.driver_cap.spindle_pwm_invert;
|
|
|
|
settings_write_global();
|
|
}
|
|
|
|
if (restore.parameters) {
|
|
float coord_data[N_AXIS];
|
|
|
|
memset(coord_data, 0, sizeof(coord_data));
|
|
for (idx = 0; idx <= N_WorkCoordinateSystems; idx++)
|
|
settings_write_coord_data((coord_system_id_t)idx, &coord_data);
|
|
|
|
settings_write_coord_data(CoordinateSystem_G92, &coord_data); // Clear G92 offsets
|
|
|
|
#ifdef N_TOOLS
|
|
tool_data_t tool_data;
|
|
memset(&tool_data, 0, sizeof(tool_data_t));
|
|
for (idx = 1; idx <= N_TOOLS; idx++) {
|
|
tool_data.tool = idx;
|
|
settings_write_tool_data(&tool_data);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (restore.startup_lines) {
|
|
for (idx = 0; idx < N_STARTUP_LINE; idx++)
|
|
settings_write_startup_line(idx, empty_line);
|
|
}
|
|
|
|
if (restore.build_info) {
|
|
settings_write_build_info(empty_line);
|
|
settings_write_build_info(BUILD_INFO);
|
|
}
|
|
|
|
setting_details_t *details = setting_details.next;
|
|
|
|
if(details) do {
|
|
if(details->restore)
|
|
details->restore();
|
|
} while((details = details->next));
|
|
|
|
nvs_buffer_sync_physical();
|
|
}
|
|
|
|
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 group)
|
|
{
|
|
bool available = false;
|
|
|
|
switch(group) {
|
|
|
|
case Group_Probing:
|
|
available = hal.probe.get_state != NULL;
|
|
break;
|
|
|
|
case Group_Encoders:
|
|
case Group_Encoder0:
|
|
available = hal.encoder.get_n_encoders && hal.encoder.get_n_encoders() > 0;
|
|
break;
|
|
|
|
case Group_Spindle_Sync:
|
|
available = hal.driver_cap.spindle_sync;
|
|
break;
|
|
|
|
case Group_Spindle_ClosedLoop:
|
|
available = hal.driver_cap.spindle_pid;
|
|
break;
|
|
|
|
case Group_Limits_DualAxis:
|
|
available = hal.stepper.get_ganged && hal.stepper.get_ganged(true).mask != 0;
|
|
break;
|
|
|
|
case Group_General:
|
|
case Group_Homing:
|
|
case Group_Jogging:
|
|
case Group_Limits:
|
|
case Group_ControlSignals:
|
|
case Group_Spindle:
|
|
case Group_Axis:
|
|
case Group_XAxis:
|
|
case Group_YAxis:
|
|
case Group_ZAxis:
|
|
#ifdef A_AXIS
|
|
case Group_AAxis:
|
|
#endif
|
|
#ifdef B_AXIS
|
|
case Group_BAxis:
|
|
#endif
|
|
#ifdef C_AXIS
|
|
case Group_CAxis:
|
|
#endif
|
|
#ifdef U_AXIS
|
|
case Group_UAxis:
|
|
#endif
|
|
#ifdef V_AXIS
|
|
case Group_VAxis:
|
|
#endif
|
|
available = true;
|
|
break;
|
|
|
|
default:
|
|
{
|
|
uint_fast16_t idx;
|
|
setting_details_t *details = settings_get_details();
|
|
do {
|
|
if(details->settings) {
|
|
for(idx = 0; idx < details->n_settings; idx++) {
|
|
if(details->settings[idx].group == group && (available = is_available(&details->settings[idx])))
|
|
break;
|
|
}
|
|
}
|
|
} while(!available && (details = details->next));
|
|
}
|
|
break;
|
|
}
|
|
|
|
return available;
|
|
}
|
|
|
|
setting_group_t settings_normalize_group (setting_group_t group)
|
|
{
|
|
return (group > Group_Axis0 && group < Group_Axis0 + N_AXIS) ? Group_Axis0 : group;
|
|
}
|
|
|
|
/*
|
|
setting_group_t settings_get_parent_group (setting_group_t group)
|
|
{
|
|
uint_fast16_t idx;
|
|
setting_details_t *settings = settings_get_details();
|
|
|
|
for(idx = 0; idx < settings->n_groups; idx++) {
|
|
if(settings->groups[idx].id == group) {
|
|
group = settings->groups[idx].parent;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return group;
|
|
}
|
|
*/
|
|
|
|
bool settings_iterator (const setting_detail_t *setting, setting_output_ptr callback, void *data)
|
|
{
|
|
bool ok = false;
|
|
|
|
switch(setting->id) {
|
|
|
|
case Setting_AxisStepsPerMM:
|
|
case Setting_AxisMaxRate:
|
|
case Setting_AxisAcceleration:
|
|
case Setting_AxisMaxTravel:
|
|
case Setting_AxisStepperCurrent:
|
|
case Setting_AxisMicroSteps:
|
|
case Setting_AxisBacklash:
|
|
case Setting_AxisAutoSquareOffset:
|
|
case Setting_AxisExtended0:
|
|
case Setting_AxisExtended1:
|
|
case Setting_AxisExtended2:
|
|
case Setting_AxisExtended3:
|
|
case Setting_AxisExtended4:
|
|
case Setting_AxisExtended5:
|
|
case Setting_AxisExtended6:
|
|
case Setting_AxisExtended7:
|
|
case Setting_AxisExtended8:
|
|
case Setting_AxisExtended9:
|
|
{
|
|
uint_fast8_t axis_idx = 0;
|
|
for(axis_idx = 0; axis_idx < N_AXIS; axis_idx++) {
|
|
if(callback(setting, axis_idx, data))
|
|
ok = true;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case Setting_EncoderModeBase:
|
|
case Setting_EncoderCPRBase:
|
|
case Setting_EncoderCPDBase:
|
|
case Setting_EncoderDblClickWindowBase:
|
|
{
|
|
uint_fast8_t encoder_idx = 0, n_encoders = hal.encoder.get_n_encoders();
|
|
for(encoder_idx = 0; encoder_idx < n_encoders; encoder_idx++) {
|
|
if(callback(setting, encoder_idx * ENCODER_SETTINGS_INCREMENT, data))
|
|
ok = true;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ok = callback(setting, 0, data);
|
|
break;
|
|
}
|
|
|
|
return ok;
|
|
}
|
|
|
|
const setting_detail_t *setting_get_details (setting_id_t id, setting_details_t **set)
|
|
{
|
|
uint_fast16_t idx, offset = id - normalize_id(id);
|
|
setting_details_t *details = settings_get_details();
|
|
|
|
id -= offset;
|
|
|
|
do {
|
|
for(idx = 0; idx < details->n_settings; idx++) {
|
|
if(details->settings[idx].id == id && is_available(&details->settings[idx])) {
|
|
if(offset && offset >= (details->settings[idx].group == Group_Encoder0 ? hal.encoder.get_n_encoders() : N_AXIS))
|
|
return NULL;
|
|
if(set)
|
|
*set = details;
|
|
return &details->settings[idx];
|
|
}
|
|
}
|
|
} while((details = details->next));
|
|
|
|
return NULL;
|
|
}
|
|
|
|
const char *setting_get_description (setting_id_t id)
|
|
{
|
|
const char *description = NULL;
|
|
|
|
#ifndef NO_SETTINGS_DESCRIPTIONS
|
|
|
|
uint_fast16_t idx;
|
|
setting_details_t *settings = settings_get_details();
|
|
const setting_detail_t *setting = setting_get_details(id, NULL);
|
|
|
|
if(setting) do {
|
|
if(settings->descriptions) {
|
|
idx = settings->n_descriptions;
|
|
do {
|
|
if(settings->descriptions[--idx].id == setting->id)
|
|
description = settings->descriptions[idx].description;
|
|
} while(idx && description == NULL);
|
|
}
|
|
} while(description == NULL && (settings = settings->next));
|
|
|
|
#endif
|
|
|
|
return description;
|
|
}
|
|
|
|
static status_code_t validate_value (const setting_detail_t *setting, float value)
|
|
{
|
|
float val;
|
|
uint_fast8_t set_idx = 0;
|
|
|
|
if(setting->min_value) {
|
|
if(!read_float((char *)setting->min_value, &set_idx, &val))
|
|
return Status_BadNumberFormat;
|
|
|
|
if(value < val)
|
|
return Status_SettingValueOutOfRange;
|
|
|
|
} else if(value < 0.0f)
|
|
return Status_NegativeValue;
|
|
|
|
if (setting->max_value) {
|
|
set_idx = 0;
|
|
|
|
if(!read_float((char *)setting->max_value, &set_idx, &val))
|
|
return Status_BadNumberFormat;
|
|
|
|
if(value > val)
|
|
return Status_SettingValueOutOfRange;
|
|
}
|
|
|
|
return Status_OK;
|
|
}
|
|
|
|
static uint32_t strnumentries (const char *s, const char delimiter)
|
|
{
|
|
if(s == NULL || *s == '\0')
|
|
return 0;
|
|
|
|
char *p = (char *)s;
|
|
uint32_t entries = 1;
|
|
|
|
while((p = strchr(p, delimiter))) {
|
|
p++;
|
|
entries++;
|
|
}
|
|
|
|
return entries;
|
|
}
|
|
|
|
setting_datatype_t setting_datatype_to_external (setting_datatype_t datatype)
|
|
{
|
|
switch(datatype) {
|
|
|
|
case Format_Int8:
|
|
case Format_Int16:
|
|
datatype = Format_Integer;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return datatype;
|
|
}
|
|
|
|
bool setting_is_list (const setting_detail_t *setting)
|
|
{
|
|
return setting->datatype == Format_Bitfield || setting->datatype == Format_XBitfield || setting->datatype == Format_RadioButtons;
|
|
}
|
|
|
|
static char *remove_element (char *s, uint_fast8_t entry)
|
|
{
|
|
while(entry && *s) {
|
|
if(*s == ',')
|
|
entry--;
|
|
s++;
|
|
}
|
|
|
|
if(entry == 0) {
|
|
*s++ = 'N';
|
|
*s++ = '/';
|
|
*s++ = 'A';
|
|
char *s2 = s;
|
|
while(*s2 && *s2 != ',')
|
|
s2++;
|
|
while(*s2)
|
|
*s++ = *s2++;
|
|
*s = '\0';
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
static void setting_remove_element (setting_id_t id, uint_fast8_t pos)
|
|
{
|
|
const setting_detail_t *setting = setting_get_details(id, NULL);
|
|
|
|
if(setting && setting_is_list(setting))
|
|
remove_element((char *)setting->format, pos);
|
|
}
|
|
|
|
// Flag setting elements for bitfields as N/A according to a mask
|
|
// Note: setting format string has to reside in RAM.
|
|
void setting_remove_elements (setting_id_t id, uint32_t mask)
|
|
{
|
|
char *format = (char *)setting_get_details(id, NULL)->format, *s;
|
|
uint_fast8_t idx, entries = strnumentries(format, ',');
|
|
|
|
for(idx = 0; idx < entries; idx++ ) {
|
|
if(!(mask & 0x1))
|
|
setting_remove_element(id, idx);
|
|
mask >>= 1;
|
|
}
|
|
|
|
// Strip trailing N/A's
|
|
while((s = strrchr(format, ','))) {
|
|
if(strncmp(s, ",N/A", 4))
|
|
break;
|
|
*s = '\0';
|
|
}
|
|
}
|
|
|
|
inline static bool setting_is_string (setting_datatype_t datatype)
|
|
{
|
|
return datatype == Format_String || datatype == Format_Password || datatype == Format_IPv4;
|
|
}
|
|
|
|
inline static bool setting_is_core (setting_type_t type)
|
|
{
|
|
return !(type == Setting_NonCore || type == Setting_NonCoreFn);
|
|
}
|
|
|
|
status_code_t setting_validate_me (const setting_detail_t *setting, float value, char *svalue)
|
|
{
|
|
status_code_t status = Status_OK;
|
|
|
|
switch(setting->datatype) {
|
|
|
|
case Format_Bool:
|
|
if(!(value == 0.0f || value == 1.0f))
|
|
status = Status_SettingValueOutOfRange;
|
|
break;
|
|
|
|
case Format_Bitfield:
|
|
case Format_XBitfield:;
|
|
if(!(isintf(value) && ((uint32_t)value < (1UL << strnumentries(setting->format, ','))))) //)
|
|
status = Status_SettingValueOutOfRange;
|
|
break;
|
|
|
|
case Format_RadioButtons:
|
|
if(!(isintf(value) && (uint32_t)value < strnumentries(setting->format, ',')))
|
|
status = Status_SettingValueOutOfRange;
|
|
break;
|
|
|
|
case Format_AxisMask:
|
|
if(!(isintf(value) && (uint32_t)value < (1 << N_AXIS)))
|
|
status = Status_SettingValueOutOfRange;
|
|
break;
|
|
|
|
case Format_Int8:
|
|
case Format_Int16:
|
|
case Format_Integer:
|
|
case Format_Decimal:
|
|
status = validate_value(setting, value);
|
|
if(setting->datatype == Format_Integer && status == Status_OK && !isintf(value))
|
|
status = Status_BadNumberFormat;
|
|
break;
|
|
|
|
case Format_String:
|
|
case Format_Password:
|
|
{
|
|
uint_fast16_t len = strlen(svalue);
|
|
status = validate_value(setting, (float)len);
|
|
}
|
|
break;
|
|
|
|
case Format_IPv4:
|
|
// handled by driver or plugin, dependent on network library
|
|
break;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
status_code_t setting_validate (setting_id_t id, float value, char *svalue)
|
|
{
|
|
const setting_detail_t *setting = setting_get_details(id, NULL);
|
|
|
|
// If no details available setting could nevertheless be a valid setting id.
|
|
return setting == NULL ? Status_OK : setting_validate_me(setting, value, svalue);
|
|
}
|
|
|
|
// A helper method to set settings from command line
|
|
status_code_t settings_store_setting (setting_id_t id, char *svalue)
|
|
{
|
|
uint_fast8_t set_idx = 0;
|
|
float value = NAN;
|
|
status_code_t status = Status_OK;
|
|
setting_details_t *set;
|
|
const setting_detail_t *setting = setting_get_details(id, &set);
|
|
|
|
if(setting == NULL)
|
|
return Status_SettingDisabled;
|
|
|
|
// Trim leading spaces
|
|
while(*svalue == ' ')
|
|
svalue++;
|
|
|
|
if(!setting_is_string(setting->datatype) && !read_float(svalue, &set_idx, &value) && setting_is_core(setting->type))
|
|
return Status_BadNumberFormat;
|
|
|
|
if((status = setting_validate_me(setting, value, svalue)) != Status_OK) {
|
|
if(setting == Setting_PulseMicroseconds && status == Status_SettingValueOutOfRange)
|
|
status = Status_SettingStepPulseMin;
|
|
|
|
return status;
|
|
}
|
|
|
|
switch(setting->type) {
|
|
|
|
case Setting_NonCore:
|
|
case Setting_IsExtended:
|
|
case Setting_IsLegacy:
|
|
case Setting_IsExpanded:
|
|
switch(setting->datatype) {
|
|
|
|
case Format_Decimal:
|
|
*((float *)(setting->value)) = value;
|
|
break;
|
|
|
|
case Format_String:
|
|
case Format_Password:
|
|
strcpy(((char *)(setting->value)), svalue);
|
|
break;
|
|
|
|
case Format_AxisMask:
|
|
*((uint8_t *)(setting->value)) = (uint8_t)truncf(value) & AXES_BITMASK;
|
|
break;
|
|
|
|
case Format_Int8:
|
|
case Format_Bool:
|
|
case Format_Bitfield:
|
|
case Format_XBitfield:
|
|
case Format_RadioButtons:
|
|
*((uint8_t *)(setting->value)) = (uint8_t)truncf(value);
|
|
break;
|
|
|
|
case Format_Int16:
|
|
*((uint16_t *)(setting->value)) = (uint16_t)truncf(value);
|
|
break;
|
|
|
|
case Format_Integer:
|
|
*((uint32_t *)(setting->value)) = (uint32_t)truncf(value);
|
|
break;
|
|
|
|
default:
|
|
status = Status_BadNumberFormat;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case Setting_NonCoreFn:
|
|
case Setting_IsExtendedFn:
|
|
case Setting_IsLegacyFn:
|
|
case Setting_IsExpandedFn:
|
|
switch(setting->datatype) {
|
|
|
|
case Format_Decimal:
|
|
status = ((setting_set_float_ptr)(setting->value))(id, value);
|
|
break;
|
|
|
|
case Format_String:
|
|
case Format_Password:
|
|
case Format_IPv4:
|
|
status = ((setting_set_string_ptr)(setting->value))(id, svalue);
|
|
break;
|
|
|
|
default:
|
|
status = ((setting_set_int_ptr)(setting->value))(id, (uint_fast16_t)truncf(value));
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if(status == Status_OK) {
|
|
|
|
if(set->save)
|
|
set->save();
|
|
|
|
#ifdef ENABLE_BACKLASH_COMPENSATION
|
|
mc_backlash_init();
|
|
#endif
|
|
|
|
if(set->on_changed)
|
|
set->on_changed(&settings);
|
|
|
|
if(set == &setting_details && grbl.on_spindle_select)
|
|
grbl.on_spindle_select(hal.driver_cap.dual_spindle && settings.mode == Mode_Laser ? 0 : 1);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
// Initialize the config subsystem
|
|
void settings_init (void)
|
|
{
|
|
if(!read_global_settings()) {
|
|
settings_restore_t settings = settings_all;
|
|
settings.defaults = 1; // Ensure global settings get restored
|
|
if(hal.nvs.type != NVS_None)
|
|
grbl.report.status_message(Status_SettingReadFail);
|
|
settings_restore(settings); // Force restore all non-volatile storage data.
|
|
report_init();
|
|
#if COMPATIBILITY_LEVEL <= 1
|
|
report_grbl_settings(true, NULL);
|
|
#else
|
|
report_grbl_settings(false, NULL);
|
|
#endif
|
|
} else {
|
|
memset(&tool_table, 0, sizeof(tool_data_t)); // First entry is for tools not in tool table
|
|
#ifdef N_TOOLS
|
|
uint_fast8_t idx;
|
|
for (idx = 1; idx <= N_TOOLS; idx++)
|
|
settings_read_tool_data(idx, &tool_table[idx]);
|
|
#endif
|
|
report_init();
|
|
#ifdef ENABLE_BACKLASH_COMPENSATION
|
|
mc_backlash_init();
|
|
#endif
|
|
hal.settings_changed(&settings);
|
|
|
|
if(hal.probe.configure) // Initialize probe invert mask.
|
|
hal.probe.configure(false, false);
|
|
}
|
|
|
|
spindle_state_t spindle_cap = {
|
|
.on = On,
|
|
.ccw = hal.driver_cap.spindle_dir,
|
|
.pwm = hal.driver_cap.spindle_pwm_invert
|
|
};
|
|
|
|
setting_remove_elements(Setting_SpindleInvertMask, spindle_cap.mask);
|
|
setting_remove_elements(Setting_ControlInvertMask, hal.signals_cap.mask);
|
|
|
|
if(hal.stepper.get_ganged)
|
|
setting_remove_elements(Setting_GangedDirInvertMask, hal.stepper.get_ganged(false).mask);
|
|
|
|
if(!hal.driver_cap.mist_control)
|
|
setting_remove_element(Setting_CoolantInvertMask, 1);
|
|
|
|
setting_details_t *details = setting_details.next;
|
|
|
|
if(details) do {
|
|
if(details->load)
|
|
details->load();
|
|
if(details->on_changed)
|
|
details->on_changed(&settings);
|
|
} while((details = details->next));
|
|
|
|
setting_details.on_changed = hal.settings_changed;
|
|
}
|