diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1075d5d..891e718 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -45,6 +45,7 @@ target_sources(grbl INTERFACE
${CMAKE_CURRENT_LIST_DIR}/encoders.c
${CMAKE_CURRENT_LIST_DIR}/pid.c
${CMAKE_CURRENT_LIST_DIR}/fs_device.c
+ ${CMAKE_CURRENT_LIST_DIR}/kinematics/asymmetric_ganging.c
${CMAKE_CURRENT_LIST_DIR}/kinematics/corexy.c
${CMAKE_CURRENT_LIST_DIR}/kinematics/wall_plotter.c
${CMAKE_CURRENT_LIST_DIR}/kinematics/delta.c
diff --git a/README.md b/README.md
index 8792fde..b6b1425 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
## grblHAL ##
-Latest build date is 20260525, see the [changelog](changelog.md) for details.
+Latest build date is 20260618, see the [changelog](changelog.md) for details.
> [!NOTE]
> A settings reset will be performed on an update of builds prior to 20241208. Backup and restore of settings is recommended.
@@ -89,4 +89,4 @@ G/M-codes not supported by [legacy Grbl](https://github.com/gnea/grbl/wiki) are
Some [plugins](https://github.com/grblHAL/plugins) implements additional M-codes.
---
-20260311
+20260618
diff --git a/changelog.md b/changelog.md
index 0bd86b3..561dacb 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,5 +1,34 @@
## grblHAL changelog
+Build 20260618
+
+Core:
+
+* Added kinematics for asymmetric \(differing step/mm\) ganged or auto squared axis, claims the highest number axis > Z for the second motor.
+
+* Ignore single block mode while executing startup code. Ref. issue [#963](https://github.com/grblHAL/core/issues/963).
+
+* For developers: added API call, `system_claim_axis()`, for claiming highest numbered axis > Z, hides its related settings.
+
+* Fixed a typo causing ganged Z compilation failure.
+
+* Fixed code guard. Ref. discussion [#968](https://github.com/grblHAL/core/discussions/968).
+
+Plugins:
+
+* Misc, MCP23017: added plugin for [MCP23017](https://ww1.microchip.com/downloads/en/devicedoc/20001952c.pdf) 16 channel I2C I/O expander,
+compile time configurable for 8 channel input and output, 16 channel input or 16 channel output.
+
+Drivers:
+
+* RP2040: "hardened" neopixel code.
+
+* IMXRT1062: fixed typo causing compilation to fail if axis is remapped as C. Fixed incorrect function decorators in the core. Ref. issue #[965](https://github.com/grblHAL/core/issues/965).
+
+* STM32F7xx: fixed copy paste error affecting handling of AUX IRQ for pins 10 - 15.
+
+---
+
Build 20260602
Core:
diff --git a/config.h b/config.h
index 2943d3f..060147b 100644
--- a/config.h
+++ b/config.h
@@ -120,15 +120,6 @@ generate a solution.
//#define KINEMATICS_API // Uncomment to add HAL entry points for custom kinematics
-/*! \def MASLOW_ROUTER
-\brief Enable Maslow router kinematics.
-Experimental - testing required and homing needs to be worked out.
-*/
-#if !defined MASLOW_ROUTER || defined __DOXYGEN__
-// Enable Maslow router kinematics.
-// Experimental - testing required and homing needs to be worked out.
-#define MASLOW_ROUTER Off
-#endif
/*! \def WALL_PLOTTER
\brief Enable wall plotter kinematics.
@@ -159,7 +150,6 @@ Experimental - testing required and homing needs to be worked out.
#define POLAR_ROBOT Off
#endif
-
/*! \def COREXY
\brief Enable CoreXY kinematics. Use ONLY with CoreXY machines.
__IMPORTANT:__ If homing is enabled, you must reconfigure the homing cycle \#defines above to
@@ -173,6 +163,18 @@ have the same steps per mm internally.
#define COREXY Off
#endif
+/*! \def ASYMMETRIC_GANGING
+\brief Enable asymmetric ganging for X, Y or Z axis.
+
To be used when the screw pitch is not equal. The highest numbered axis is claimed for the second motor.
+*/
+//#define ASYMMETRIC_GANGING Y_AXIS // Uncomment to enable
+
+/*! \def ASYMMETRIC_AUTO_SQUARE
+\brief Enable asymmetric ganging + auto squaring for X, Y or Z axis.
+
To be used when the screw pitch is not equal. The highest numbered axis is claimed for the second motor.
+*/
+//#define ASYMMETRIC_AUTO_SQUARE Y_AXIS // Uncomment to enable
+
/*! \def CHECK_MODE_DELAY
\brief
Add a short delay for each block processed in Check Mode to
diff --git a/driver_opts.h b/driver_opts.h
index 0cbf0ff..3e657c0 100644
--- a/driver_opts.h
+++ b/driver_opts.h
@@ -310,7 +310,11 @@
#define SPINDLE_DIR 0b100
#ifndef SPINDLE0_ENABLE
-#define SPINDLE0_ENABLE DEFAULT_SPINDLE
+#ifdef SPINDLE_ENABLE
+#define SPINDLE0_ENABLE 0
+#else
+#define SPINDLE0_ENABLE DEFAULT_SPINDLE
+#endif
#endif
#ifndef SPINDLE1_ENABLE
diff --git a/expanders_init.h b/expanders_init.h
index bfa5176..c222179 100644
--- a/expanders_init.h
+++ b/expanders_init.h
@@ -31,7 +31,7 @@ extern void board_ports_init (void); // default is a weak function
// I2C expanders
-#if PCA9654E_ENABLE || MCP3221_ENABLE || MCP4725_ENABLE || FLEXGPIO_ENABLE
+#if PCA9654E_ENABLE || MCP3221_ENABLE || MCP4725_ENABLE || MCP23017_ENABLE || FLEXGPIO_ENABLE
#if defined(I2C_ENABLE) && !I2C_ENABLE
#undef I2C_ENABLE
@@ -53,6 +53,10 @@ extern void mcp4725_init (void);
extern void pca9654e_init (void);
#endif
+#if MCP23017_ENABLE
+extern void mcp23017_init (void);
+#endif
+
// Third party I2C expander plugins goes after this line
#if FLEXGPIO_ENABLE
@@ -133,6 +137,10 @@ static inline void io_expanders_init (void)
mcp4725_init();
#endif
+#if MCP23017_ENABLE
+ mcp23017_init();
+#endif
+
#if R4SLS08_ENABLE
r4sls08_init();
#endif
diff --git a/grbl.h b/grbl.h
index 4476586..79aedb6 100644
--- a/grbl.h
+++ b/grbl.h
@@ -42,7 +42,7 @@
#else
#define GRBL_VERSION "1.1f"
#endif
-#define GRBL_BUILD 20260602
+#define GRBL_BUILD 20260618
#define GRBL_URL "https://github.com/grblHAL"
@@ -86,7 +86,7 @@
#define __STATIC_FORCEINLINE __attribute__((always_inline)) static inline
#endif
-#if (COREXY || WALL_PLOTTER || DELTA_ROBOT || POLAR_ROBOT || MASLOW_ROUTER) && !defined(KINEMATICS_API)
+#if (COREXY || WALL_PLOTTER || DELTA_ROBOT || POLAR_ROBOT || ASYMMETRIC_GANGING || ASYMMETRIC_AUTO_SQUARE) && !defined(KINEMATICS_API)
#define KINEMATICS_API
#endif
diff --git a/grbllib.c b/grbllib.c
index 45cf831..c1ad5e1 100644
--- a/grbllib.c
+++ b/grbllib.c
@@ -45,22 +45,6 @@
#include "kinematics.h"
#endif
-#if COREXY
-#include "kinematics/corexy.h"
-#endif
-
-#if WALL_PLOTTER
-#include "kinematics/wall_plotter.h"
-#endif
-
-#if DELTA_ROBOT
-#include "kinematics/delta.h"
-#endif
-
-#if POLAR_ROBOT
-#include "kinematics/polar.h"
-#endif
-
static void task_execute (sys_state_t state);
typedef union {
@@ -357,21 +341,30 @@ FLASHMEM int grbl_enter (void)
#endif
#if COREXY
+ extern void corexy_init (void);
corexy_init();
#endif
#if WALL_PLOTTER
+ extern void wall_plotter_init (void);
wall_plotter_init();
#endif
#if DELTA_ROBOT
+ extern void delta_robot_init (void);
delta_robot_init();
#endif
#if POLAR_ROBOT
+ extern void polar_init (void);
polar_init();
#endif
+#if defined(ASYMMETRIC_GANGING) || defined(ASYMMETRIC_AUTO_SQUARE)
+ extern void asymmetric_ganging_init (void);
+ asymmetric_ganging_init();
+#endif
+
#if NVSDATA_BUFFER_ENABLE
nvs_buffer_init();
#endif
diff --git a/kinematics/asymmetric_ganging.c b/kinematics/asymmetric_ganging.c
new file mode 100644
index 0000000..2734506
--- /dev/null
+++ b/kinematics/asymmetric_ganging.c
@@ -0,0 +1,346 @@
+/*
+ asymmetric_ganging.c - kinematics implementation for asymmetric ganging of two axis motors
+
+ Part of grblHAL
+
+ Copyright (c) 2026 Terje Io
+
+ grblHAL 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.
+
+ grblHAL 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 grblHAL. If not, see .
+*/
+
+#include "../grbl.h"
+
+#if defined(ASYMMETRIC_GANGING) || defined(ASYMMETRIC_AUTO_SQUARE)
+
+#if N_AXIS <= 3
+#error "Kinematics for asymmetric ganging must have N_AXIS > 3"
+#endif
+
+#include
+
+#include "../hal.h"
+#include "../settings.h"
+#include "../planner.h"
+#include "../kinematics.h"
+
+#ifdef ASYMMETRIC_AUTO_SQUARE
+#define PRIMARY_AXIS ASYMMETRIC_AUTO_SQUARE
+#else
+#define PRIMARY_AXIS ASYMMETRIC_GANGING
+#endif
+#define PRIMARY_AXIS_BIT (1 << PRIMARY_AXIS)
+#define GANGED_AXIS (N_AXIS - 1)
+#define GANGED_AXIS_BIT (1 << GANGED_AXIS)
+
+static on_report_options_ptr on_report_options;
+static on_settings_changed_ptr on_settings_changed;
+static stepper_get_ganged_ptr get_ganged_axes;
+
+#ifdef ASYMMETRIC_AUTO_SQUARE
+
+static axes_signals_t motor_disable = {0};
+
+static stepper_disable_motors_ptr disable_motors;
+static limits_get_state_ptr get_limits_state;
+static home_get_state_ptr get_home_state;
+static stepper_pulse_start_ptr pulse_start;
+
+static void onDisableMotors (axes_signals_t axes, squaring_mode_t mode)
+{
+ if(disable_motors)
+ disable_motors(axes, mode);
+
+ if(!axes.bits)
+ motor_disable.bits = 0;
+ else if(axes.bits & (1 << PRIMARY_AXIS)) {
+/*
+ if(mode == SquaringMode_A)
+ sys.homing_axis_lock.bits &= ~(1 << PRIMARY_AXIS);
+ else
+ sys.homing_axis_lock.bits &= ~GANGED_AXIS_BIT;
+*/
+ motor_disable.y = mode == SquaringMode_A;
+ if(mode == SquaringMode_B)
+ motor_disable.bits |= GANGED_AXIS_BIT;
+ else
+ motor_disable.bits &= ~GANGED_AXIS_BIT;
+ }
+}
+
+static limit_signals_t onGetLimitsState (void)
+{
+ limit_signals_t limits = get_limits_state();
+
+ limits.min2.y = !!(limits.min.bits & GANGED_AXIS_BIT);
+
+ return limits;
+}
+
+/*
+ISR_CODE static home_signals_t ISR_FUNC(onGetHomingState)(void)
+{
+ home_signals_t home = get_home_state();
+
+ if(home.a.bits && GANGED_AXIS_BIT) {
+ home.b.y = On;
+ home.a.bits &= ~GANGED_AXIS_BIT;
+ }
+
+ return home;
+}
+*/
+
+void ISR_CODE ISR_FUNC(onStepperPulse) (stepper_t *stepper)
+{
+ if(stepper->step_out.bits & motor_disable.bits) {
+
+ if(motor_disable.bits & PRIMARY_AXIS_BIT)
+ stepper->step_out.bits &= ~PRIMARY_AXIS_BIT;
+
+ if(motor_disable.bits & GANGED_AXIS_BIT)
+ stepper->step_out.bits &= ~GANGED_AXIS_BIT;
+ }
+
+ pulse_start(stepper);
+}
+
+static bool homing_cycle_validate (axes_signals_t cycle)
+{
+ return !(cycle.bits & PRIMARY_AXIS_BIT) || ((cycle.bits & PRIMARY_AXIS_BIT) && (cycle.bits & GANGED_AXIS_BIT));
+}
+
+static axes_signals_t onGetGangedAxes (bool auto_squared)
+{
+ axes_signals_t axes = {0};
+
+ if(get_ganged_axes)
+ axes = get_ganged_axes(auto_squared);
+
+ axes.bits |= PRIMARY_AXIS_BIT;
+
+ return axes;
+}
+
+#else
+
+static bool homing_cycle_validate (axes_signals_t cycle)
+{
+ return true;
+}
+
+static axes_signals_t onGetGangedAxes (bool auto_squared)
+{
+ axes_signals_t axes = {0};
+
+ if(get_ganged_axes)
+ axes = get_ganged_axes(auto_squared);
+
+ if(!auto_squared)
+ axes.bits |= PRIMARY_AXIS_BIT;
+
+ return axes;
+}
+
+
+#endif // ASYMMETRIC_AUTO_SQUARE
+
+static float *convert_array_steps_to_mpos (float *position, int32_t *steps)
+{
+ uint_fast8_t idx = N_AXIS;
+ do {
+ idx--;
+ position[idx] = steps[idx] / settings.axis[idx].steps_per_mm;
+ } while(idx);
+
+ return position;
+}
+
+// Transform position from cartesian coordinate system to corexy coordinate system
+static inline float *transform_from_cartesian (float *target, float *position)
+{
+ memcpy(target, position, sizeof(coord_data_t));
+
+ target[GANGED_AXIS] = position[PRIMARY_AXIS];
+
+ return target;
+}
+
+static uint_fast8_t get_axis_mask (uint_fast8_t idx)
+{
+ return bit(idx);
+}
+
+static void set_target_pos (uint_fast8_t idx) // fn name?
+{
+ sys.position[idx] = 0;
+}
+
+// Set machine positions for homed limit switches. Don't update non-homed axes.
+// NOTE: settings.max_travel[] is stored as a negative value.
+static void set_machine_positions (axes_signals_t cycle)
+{
+ limits_set_machine_positions(cycle, true);
+
+ if(!settings.homing.flags.force_set_origin)
+ sys.position[GANGED_AXIS] = lroundf(sys.home_position[PRIMARY_AXIS] * settings.axis[GANGED_AXIS].steps_per_mm);
+}
+
+// called from mc_line() to segment lines if not overridden, default implementation for pass-through
+static float *kinematics_segment_line (float *target, float *position, plan_line_data_t *pl_data, bool init)
+{
+ static uint_fast8_t iterations;
+ static coord_data_t trsf;
+
+ if(init) {
+ iterations = 2;
+ transform_from_cartesian(trsf.values, target);
+ }
+
+ return iterations-- == 0 ? NULL : trsf.values;
+}
+
+static float homing_cycle_get_feedrate (axes_signals_t cycle, float feedrate, homing_mode_t mode)
+{
+ return feedrate;
+}
+
+static void onSettingsChanged (settings_t *settings, settings_changed_flags_t changed)
+{
+ uint_fast8_t idx = sizeof(settings->homing.cycle) / sizeof(axes_signals_t);
+
+ on_settings_changed(settings, changed);
+
+ float steps_per_mm = settings->axis[GANGED_AXIS].steps_per_mm;
+
+ memcpy(&settings->axis[GANGED_AXIS], &settings->axis[PRIMARY_AXIS], sizeof(axis_settings_t));
+
+ settings->axis[GANGED_AXIS].steps_per_mm = steps_per_mm;
+
+ do {
+ if(settings->homing.cycle[--idx].bits & PRIMARY_AXIS_BIT)
+ settings->homing.cycle[idx].bits |= GANGED_AXIS_BIT;
+ else if(settings->homing.cycle[idx].bits & GANGED_AXIS_BIT)
+ settings->homing.cycle[idx].bits &= GANGED_AXIS_BIT;
+ } while(idx);
+
+ if(settings->steppers.enable_invert.bits & PRIMARY_AXIS_BIT)
+ settings->steppers.enable_invert.bits |= GANGED_AXIS_BIT;
+ else
+ settings->steppers.enable_invert.bits &= ~GANGED_AXIS_BIT;
+
+ if(settings->steppers.dir_invert.bits & PRIMARY_AXIS_BIT)
+ settings->steppers.dir_invert.bits |= GANGED_AXIS_BIT;
+ else
+ settings->steppers.dir_invert.bits &= ~GANGED_AXIS_BIT;
+
+ if(settings->steppers.step_invert.bits & PRIMARY_AXIS_BIT)
+ settings->steppers.step_invert.bits |= GANGED_AXIS_BIT;
+ else
+ settings->steppers.step_invert.bits &= ~GANGED_AXIS_BIT;
+
+ if(settings->steppers.energize.bits & PRIMARY_AXIS_BIT)
+ settings->steppers.energize.bits |= GANGED_AXIS_BIT;
+ else
+ settings->steppers.energize.bits &= ~GANGED_AXIS_BIT;
+
+ if(settings->homing.dir_mask.bits & PRIMARY_AXIS_BIT)
+ settings->homing.dir_mask.bits |= GANGED_AXIS_BIT;
+ else
+ settings->homing.dir_mask.bits &= ~GANGED_AXIS_BIT;
+
+ settings->steppers.is_rotary.bits &= ~GANGED_AXIS_BIT;
+
+#ifdef ASYMMETRIC_AUTO_SQUARE
+
+ if(settings->limits.invert.bits & PRIMARY_AXIS_BIT)
+ settings->limits.invert.bits |= GANGED_AXIS_BIT;
+ else
+ settings->limits.invert.bits &= ~GANGED_AXIS_BIT;
+
+ if(hal.stepper.pulse_start != onStepperPulse) {
+ pulse_start = hal.stepper.pulse_start;
+ hal.stepper.pulse_start = onStepperPulse;
+ }
+
+#endif
+}
+
+PROGMEM static const char label[] = {
+#if PRIMARY_AXIS == X_AXIS
+ "Ganged X-motor travel resolution"
+#elif PRIMARY_AXIS == Y_AXIS
+ "Ganged Y-motor travel resolution"
+#elif PRIMARY_AXIS == Z_AXIS
+ "Ganged Z-motor travel resolution"
+#endif
+};
+
+PROGMEM static const setting_detail_t axis_settings[] = {
+ { Setting_AxisStepsPerMM + GANGED_AXIS, Group_Axis0 + PRIMARY_AXIS, label, "step/mm", Format_Decimal, "#####0.000##", NULL, NULL, Setting_IsLegacy, &settings.axis[GANGED_AXIS].steps_per_mm, NULL, NULL },
+};
+
+static void report_options (bool newopt)
+{
+ on_report_options(newopt);
+
+ if(!newopt)
+ hal.stream.write("[KINEMATICS:Asymmetric ganging v0.01]" ASCII_EOL);
+}
+
+// Initialize API pointers for xxx kinematics
+void asymmetric_ganging_init (void)
+{
+ static setting_details_t axis_setting_details = {
+ .is_core = true,
+ .settings = axis_settings,
+ .n_settings = sizeof(axis_settings) / sizeof(setting_detail_t),
+ .save = settings_write_global
+ };
+
+ system_claim_axis();
+ kinematics.limits_set_target_pos = set_target_pos;
+ kinematics.limits_get_axis_mask = get_axis_mask;
+ kinematics.limits_set_machine_positions = set_machine_positions;
+ kinematics.transform_from_cartesian = transform_from_cartesian;
+ kinematics.transform_steps_to_cartesian = convert_array_steps_to_mpos;
+ kinematics.segment_line = kinematics_segment_line;
+ kinematics.homing_cycle_validate = homing_cycle_validate;
+ kinematics.homing_cycle_get_feedrate = homing_cycle_get_feedrate;
+
+ settings_register(&axis_setting_details);
+
+ on_report_options = grbl.on_report_options;
+ grbl.on_report_options = report_options;
+
+ on_settings_changed = grbl.on_settings_changed;
+ grbl.on_settings_changed = onSettingsChanged;
+
+ get_ganged_axes = hal.stepper.get_ganged;
+ hal.stepper.get_ganged = onGetGangedAxes;
+
+#ifdef ASYMMETRIC_AUTO_SQUARE
+
+ get_limits_state = hal.limits.get_state;
+ hal.limits.get_state = onGetLimitsState;
+
+ get_home_state = hal.homing.get_state;
+// hal.homing.get_state = onGetHomingState;
+
+ disable_motors = hal.stepper.disable_motors;
+ hal.stepper.disable_motors = onDisableMotors;
+
+#endif
+}
+
+#endif // ASYMMETRIC_GANGING || ASYMMETRIC_AUTO_SQUARE
diff --git a/kinematics/corexy.h b/kinematics/corexy.h
deleted file mode 100644
index bdd37cd..0000000
--- a/kinematics/corexy.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- corexy.c - corexy kinematics implementation
-
- Part of grblHAL
-
- Copyright (c) 2019 Terje Io
- Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
-
- grblHAL 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.
-
- grblHAL 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 grblHAL. If not, see .
-*/
-
-#ifndef _COREXY_H_
-#define _COREXY_H_
-
-// Initialize HAL pointers for CoreXY kinematics
-void corexy_init (void);
-
-#endif
diff --git a/kinematics/delta.h b/kinematics/delta.h
deleted file mode 100644
index 4b696b6..0000000
--- a/kinematics/delta.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- delta.c - delta kinematics implementation
-
- Part of grblHAL
-
- Copyright (c) 2023 Terje Io
-
- grblHAL 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.
-
- grblHAL 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 grblHAL. If not, see .
-*/
-
-#ifndef _delta_H_
-#define _delta_H_
-
-// Initialize HAL pointers for delta kinematics
-void delta_robot_init (void);
-
-#endif
diff --git a/kinematics/maslow.c b/kinematics/maslow.c
deleted file mode 100644
index 811f549..0000000
--- a/kinematics/maslow.c
+++ /dev/null
@@ -1,681 +0,0 @@
-/*
- maslow.c - Maslow router kinematics implementation
-
- Part of grblHAL
-
- grblHAL 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.
-
- grblHAL 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 grblHAL. If not, see .
-
- The basis for this code has been pulled from MaslowDue created by Larry D O'Cull.
-
-
- Some portions of that package directly or indirectly has been pulled from from the Maslow CNC
- firmware for Aduino Mega. Those parts are Copyright 2014-2017 Bar Smith.
-
-
- It has been adapted for grblHAL by Terje Io.
-*/
-
-#include "../grbl.h"
-
-#if MASLOW_ROUTER
-
-#include
-
-#include "driver.h"
-
-#include "../settings.h"
-#include "../planner.h"
-#include "../nvs_buffer.h"
-#include "../kinematics.h"
-#include "../maslow.h"
-#include "../report.h"
-
-#define A_MOTOR X_AXIS // Must be X_AXIS
-#define B_MOTOR Y_AXIS // Must be Y_AXIS
-
-typedef struct {
- float halfWidth; //Half the machine width
- float halfHeight; //Half the machine height
- float xCordOfMotor;
- float xCordOfMotor_x4;
- float xCordOfMotor_x2_pow;
- float yCordOfMotor;
- float height_to_bit; //distance between sled attach point and bit
-} machine_t;
-
-static machine_t machine = {0};
-
-uint_fast8_t selected_motor = A_MOTOR;
-maslow_settings_t maslow;
-maslow_hal_t maslow_hal = {0};
-static nvs_address_t nvs_address;
-
-static const maslow_settings_t maslow_defaults = {
- .pid[A_MOTOR].Kp = MASLOW_A_KP,
- .pid[A_MOTOR].Ki = MASLOW_A_KI,
- .pid[A_MOTOR].Kd = MASLOW_A_KD,
- .pid[A_MOTOR].Imax = MASLOW_A_IMAX,
-
- .pid[B_MOTOR].Kp = MASLOW_B_KP,
- .pid[B_MOTOR].Ki = MASLOW_B_KI,
- .pid[B_MOTOR].Kd = MASLOW_B_KD,
- .pid[B_MOTOR].Imax = MASLOW_B_IMAX,
-
- .pid[Z_AXIS].Kp = MASLOW_Z_KP,
- .pid[Z_AXIS].Ki = MASLOW_Z_KI,
- .pid[Z_AXIS].Kd = MASLOW_Z_KD,
- .pid[Z_AXIS].Imax = MASLOW_Z_IMAX,
-
- .chainOverSprocket = MASLOW_CHAINOVERSPROCKET,
- .machineWidth = MASLOW_MACHINEWIDTH,
- .machineHeight = MASLOW_MACHINEHEIGHT,
- .distBetweenMotors = MASLOW_DISTBETWEENMOTORS,
-
- .motorOffsetY = MASLOW_MOTOROFFSETY,
- .chainSagCorrection = MASLOW_CHAINSAGCORRECTION,
- .leftChainTolerance = MASLOW_LEFTCHAINTOLERANCE,
- .rightChainTolerance = MASLOW_RIGHTCHAINTOLERANCE,
- .rotationDiskRadius = MASLOW_ROTATIONDISKRADIUS,
-
- .chainLength = MASLOW_CHAINLENGTH,
- .sledHeight = MASLOW_SLEDHEIGHT,
- .sledWidth = MASLOW_SLEDWIDTH,
-
- .XcorrScaling = MASLOW_ACORRSCALING,
- .YcorrScaling = MASLOW_BCORRSCALING
-};
-
-static status_code_t set_axis_setting (setting_id_t setting, float value);
-static float get_axis_setting (setting_id_t setting);
-static void maslow_settings_load (void);
-static void maslow_settings_restore (void);
-
-#define AXIS_OPTS { .subgroups = On, .iterations = 1 }
-
-static const setting_detail_t maslow_settings[] = {
-#if maslow_MIXED_DRIVERS
- { Setting_maslowDriver, Group_MotorDriver, "maslow driver", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_NonCore, &maslow.driver_enable.mask },
-#endif
- { (setting_id_t)Maslow_ChainOverSprocket, Group_MotorDriver, "Chain over sprocket", NULL, Format_Integer, NULL, NULL, NULL, Setting_NonCore, &maslow.chainOverSprocket, NULL },
- { (setting_id_t)Maslow_MachineWidth, Group_MotorDriver, "Machine width", "mm", Format_Decimal, "###0.0", NULL, NULL, Setting_NonCore, &maslow.machineWidth, NULL },
- { (setting_id_t)Maslow_MachineHeight, Group_MotorDriver, "Machine height", "mm", Format_Decimal, "###0.0", NULL, NULL, Setting_NonCore, &maslow.machineHeight, NULL },
- { (setting_id_t)Maslow_DistBetweenMotors, Group_MotorDriver, "Distance between motors", "mm", Format_Decimal, NULL, NULL, NULL, Setting_NonCore, &maslow.distBetweenMotors, NULL },
- { (setting_id_t)Maslow_MotorOffsetY, Group_MotorDriver, "Motor offset Y", "mm", Format_Decimal, "###0.0", NULL, NULL, Setting_NonCore, &maslow.motorOffsetY, NULL },
- { (setting_id_t)Maslow_AcorrScaling, Group_MotorDriver, "Acorr Scaling", NULL, Format_Decimal, "###0.0", NULL, NULL, Setting_NonCore, &maslow.XcorrScaling, NULL },
- { (setting_id_t)Maslow_BcorrScaling, Group_MotorDriver, "BcorrScaling", NULL, Format_Decimal, "###0.0", NULL, NULL, Setting_NonCore, &maslow.XcorrScaling, NULL },
- { (setting_id_t)AxisSetting_MaslowKP, Group_Axis0, "-axis KP", NULL, Format_Decimal, "###0.0", NULL, NULL, Setting_NonCoreFn, set_axis_setting, get_axis_setting, AXIS_OPTS },
- { (setting_id_t)AxisSetting_MaslowKI, Group_Axis0, "-axis KI", NULL, Format_Decimal, "###0.0", NULL, NULL, Setting_NonCoreFn, set_axis_setting, get_axis_setting, AXIS_OPTS },
- { (setting_id_t)AxisSetting_MaslowKD, Group_Axis0, "-axis KIt", NULL, Format_Decimal, "###0.0", NULL, NULL, Setting_NonCoreFn, set_axis_setting, get_axis_setting, AXIS_OPTS },
- { (setting_id_t)AxisSetting_MaslowIMax, Group_Axis0, "-axis I Max", "ma", Format_Decimal, "###0.0", NULL, NULL, Setting_NonCoreFn, set_axis_setting, get_axis_setting, AXIS_OPTS }
-};
-
-static void maslow_settings_save (void)
-{
- hal.nvs.memcpy_to_nvs(nvs_address, (uint8_t *)&maslow, sizeof(maslow_settings_t), true);
-}
-
-static setting_details_t details = {
- .settings = maslow_settings,
- .n_settings = sizeof(maslow_settings) / sizeof(setting_detail_t),
- .load = maslow_settings_load,
- .save = maslow_settings_save,
- .restore = maslow_settings_restore
-};
-
-static setting_details_t *on_get_settings (void)
-{
- return &details;
-}
-
-static status_code_t set_axis_setting (setting_id_t setting, float value)
-{
- status_code_t status = Status_OK;
-
- if((setting_id_t)setting >= Setting_AxisSettingsBase && (setting_id_t)setting <= Setting_AxisSettingsMax) {
-
- uint_fast16_t base_idx = (uint_fast16_t)setting - (uint_fast16_t)Setting_AxisSettingsBase;
- uint_fast8_t axis_idx = base_idx % AXIS_SETTINGS_INCREMENT;
-
- if(axis_idx < N_AXIS) switch((base_idx - axis_idx) / AXIS_SETTINGS_INCREMENT) {
-
- case AxisSetting_MaslowKP:
- status = Status_OK;
- maslow.pid[axis_idx].Kp = value;
- break;
-
- case AxisSetting_MaslowKI:
- status = Status_OK;
- maslow.pid[axis_idx].Ki = value;
- break;
-
- case AxisSetting_MaslowKD:
- status = Status_OK;
- maslow.pid[axis_idx].Kd = value;
- break;
-
- case AxisSetting_MaslowIMax:
- status = Status_OK;
- maslow.pid[axis_idx].Imax = value;
-
- default:
- status = Status_Unhandled;
- break;
- }
- }
-
- return status;
-}
-
-static float get_axis_setting (setting_id_t setting)
-{
- float value = 0;
-
- if (setting >= Setting_AxisSettingsBase && setting <= Setting_AxisSettingsMax) {
-
- uint_fast16_t base_idx = (uint_fast16_t)setting - (uint_fast16_t)Setting_AxisSettingsBase;
- uint_fast8_t axis_idx = base_idx % AXIS_SETTINGS_INCREMENT;
-
- if(axis_idx < N_AXIS) switch((base_idx - axis_idx) / AXIS_SETTINGS_INCREMENT) {
-
- case AxisSetting_MaslowKP:
- value = maslow.pid[axis_idx].Kp;
- break;
-
- case AxisSetting_MaslowKI:
- value = maslow.pid[axis_idx].Ki;
- break;
-
- case AxisSetting_MaslowKD:
- value = maslow.pid[axis_idx].Kd;
- break;
-
- case AxisSetting_MaslowIMax:
- value = maslow.pid[axis_idx].Imax;
- break;
- }
- }
-
- return value;
-}
-
-static void maslow_settings_restore (void)
-{
- memcpy(&maslow, &maslow_defaults, sizeof(maslow_settings_t));
-
- hal.nvs.memcpy_to_nvs(hal.nvs.driver_area.address, (uint8_t *)&maslow, sizeof(maslow_settings_t), true);
-}
-
-static void maslow_settings_load (void)
-{
- if(hal.nvs.memcpy_from_nvs((uint8_t *)&maslow, nvs_address, sizeof(maslow_settings_t), true) != NVS_TransferResult_OK)
- maslow_settings_restore();
-}
-
-/** End settings handling **/
-
-void recomputeGeometry()
-{
- /*
- Some variables are computed on initialization for the geometry of the machine to reduce overhead,
- calling this function regenerates those values.
- */
- machine.halfWidth = (maslow.machineWidth / 2.0f);
- machine.halfHeight = (maslow.machineHeight / 2.0f);
- machine.xCordOfMotor = (maslow.distBetweenMotors / 2.0f);
- machine.yCordOfMotor = (machine.halfHeight + maslow.motorOffsetY);
- machine.xCordOfMotor_x4 = machine.xCordOfMotor * 4.0f;
- machine.xCordOfMotor_x2_pow = powf((machine.xCordOfMotor * 2.0f), 2.0f);
-}
-
-// limit motion to stay within table (in mm)
-void verifyValidTarget (float* xTarget, float* yTarget)
-{
- //If the target point is beyond one of the edges of the board, the machine stops at the edge
-
- recomputeGeometry();
-// no limits for now
-// *xTarget = (*xTarget < -halfWidth) ? -halfWidth : (*xTarget > halfWidth) ? halfWidth : *xTarget;
-// *yTarget = (*yTarget < -halfHeight) ? -halfHeight : (*yTarget > halfHeight) ? halfHeight : *yTarget;
-
-}
-
-// Maslow CNC calculation only. Returns x or y-axis "steps" based on Maslow motor steps.
-// converts current position two-chain intersection (steps) into x / y cartesian in STEPS..
-static void maslow_convert_array_steps_to_mpos (float *position, int32_t *steps)
-{
- float a_len = ((float)steps[A_MOTOR] / settings.axis[A_MOTOR].steps_per_mm);
- float b_len = ((float)steps[B_MOTOR] / settings.axis[B_MOTOR].steps_per_mm);
-
- a_len = (machine.xCordOfMotor_x2_pow - powf(b_len, 2.0f) + powf(a_len, 2.0f)) / machine.xCordOfMotor_x4;
- position[X_AXIS] = a_len - machine.xCordOfMotor;
- a_len = maslow.distBetweenMotors - a_len;
- position[Y_AXIS] = machine.yCordOfMotor - sqrtf(powf(b_len, 2.0f) - powf(a_len, 2.0f));
- position[Z_AXIS] = steps[Z_AXIS] / settings.axis[Z_AXIS].steps_per_mm;
-
-// back out any correction factor
- position[X_AXIS] /= maslow.XcorrScaling;
- position[Y_AXIS] /= maslow.YcorrScaling;
-//
-}
-
-// calculate left and right (A_MOTOR/B_MOTOR) chain lengths from X-Y cartesian coordinates (in mm)
-// target is an absolute position in the frame
-inline static void triangularInverse (int32_t *target_steps, float *target)
-{
- //Confirm that the coordinates are on the table
-// verifyValidTarget(&xTarget, &yTarget);
-
- // scale target (absolute position) by any correction factor
- double xxx = (double)target[A_MOTOR] * (double)maslow.XcorrScaling;
- double yyy = (double)target[B_MOTOR] * (double)maslow.YcorrScaling;
- double yyp = pow((double)machine.yCordOfMotor - yyy, 2.0);
-
- //Calculate motor axes length to the bit
- target_steps[A_MOTOR] = (int32_t)lround(sqrt(pow((double)machine.xCordOfMotor + xxx, 2.0f) + yyp) * settings.axis[A_MOTOR].steps_per_mm);
- target_steps[B_MOTOR] = (int32_t)lround(sqrt(pow((double)machine.xCordOfMotor - xxx, 2.0f) + yyp) * settings.axis[B_MOTOR].steps_per_mm);
-}
-
-// Transform absolute position from cartesian coordinate system (mm) to maslow coordinate system (step)
-static void maslow_target_to_steps (int32_t *target_steps, float *target)
-{
- uint_fast8_t idx = N_AXIS - 1;
-
- do {
- target_steps[idx] = lroundf(target[idx] * settings.axis[idx].steps_per_mm);
- } while(--idx > Y_AXIS);
-
- triangularInverse(target_steps, target);
-}
-
-static uint_fast8_t maslow_limits_get_axis_mask (uint_fast8_t idx)
-{
- return ((idx == A_MOTOR) || (idx == B_MOTOR)) ? (bit(X_AXIS) | bit(Y_AXIS)) : bit(idx);
-}
-
-// MASLOW is circular in motion, so long lines must be divided up
-static bool maslow_segment_line (float *target, plan_line_data_t *pl_data, bool init)
-{
- static uint_fast16_t iterations;
- static bool segmented;
- static float delta[N_AXIS], segment_target[N_AXIS];
-// static plan_line_data_t plan;
-
- uint_fast8_t idx = N_AXIS;
-
- if(init) {
-
- float max_delta = 0.0f;
-
- do {
- idx--;
- delta[idx] = target[idx] - gc_state.position[idx];
- max_delta = max(max_delta, fabsf(delta[idx]));
- } while(idx);
-
- if((segmented = !(pl_data->condition.rapid_motion || pl_data->condition.jog_motion) &&
- max_delta > MAX_SEG_LENGTH_MM && !(delta[X_AXIS] == 0.0f && delta[Y_AXIS] == 0.0f))) {
-
- idx = N_AXIS;
- iterations = (uint_fast16_t)ceilf(max_delta / MAX_SEG_LENGTH_MM);
-
- memcpy(segment_target, gc_state.position, sizeof(segment_target));
-// memcpy(&plan, pl_data, sizeof(plan_line_data_t));
-
- do {
- delta[--idx] /= (float)iterations;
- target[idx] = gc_state.position[idx];
- } while(idx);
-
- } else
- iterations = 1;
-
- iterations++; // return at least one iteration
-
- } else {
-
- iterations--;
-
- if(segmented && iterations) do {
- idx--;
- segment_target[idx] += delta[idx];
- target[idx] = segment_target[idx];
-// memcpy(pl_data, &plan, sizeof(plan_line_data_t));
- } while(idx);
-
- }
-
- return iterations != 0;
-}
-
-static void maslow_limits_set_target_pos (uint_fast8_t idx) // fn name?
-{
- /*
- int32_t axis_position;
- float position[3];
- maslow_convert_array_steps_to_mpos(position, sys.position);
-
- float aCl,bCl; // set initial chain lengths to table center when $HOME
- void triangularInverse(float ,float , float* , float* );
-
- x_axis.axis_Position = 0;
- x_axis.target = 0;
- x_axis.target_PS = 0;
- x_axis.Integral = 0;
- y_axis.axis_Position = 0;
- y_axis.target = 0;
- y_axis.target_PS = 0;
- y_axis.Integral = 0;
- z_axis.axis_Position = 0;
- z_axis.target = 0;
- z_axis.target_PS = 0;
- z_axis.Integral = 0;
- set_axis_position = 0; // force to center of table -- its a Maslow thing
-
- triangularInverse((float)(set_axis_position), (float)(set_axis_position), &aCl, &bCl);
- sys.position[A_MOTOR] = (int32_t) lround(aCl * settings.steps_per_mm[A_MOTOR]);
- sys.position[B_MOTOR] = (int32_t) lround(bCl * settings.steps_per_mm[B_MOTOR]);
- sys.position[Z_AXIS] = set_axis_position;
-
- store_current_machine_pos(); // reset all the way out to stored space
- sys.step_control = STEP_CONTROL_NORMAL_OP; // Return step control to normal operation.
- return;
-
- sys.position[idx] = set_axis_position;
-
- switch(idx) {
- case X_AXIS:
- axis_position = system_convert_maslow_to_y_axis_steps(sys.position);
- sys.position[A_MOTOR] = axis_position;
- sys.position[B_MOTOR] = -axis_position;
- break;
- case Y_AXIS:
- sys.position[A_MOTOR] = sys.position[B_MOTOR] = system_convert_maslow_to_x_axis_steps(sys.position);
- break;
- default:
- sys.position[idx] = 0;
- break;
- }
- */
-}
-
-// Set machine positions for homed limit switches. Don't update non-homed axes.
-// NOTE: settings.max_travel[] is stored as a negative value.
-static void maslow_limits_set_machine_positions (axes_signals_t cycle)
-{
- /*
- * uint_fast8_t idx = N_AXIS;
-
- if(settings.homing.flags.force_set_origin) {
- if (cycle.mask & bit(--idx)) do {
- switch(--idx) {
- case X_AXIS:
- sys.position[A_MOTOR] = system_convert_maslow_to_y_axis_steps(sys.position);
- sys.position[B_MOTOR] = - sys.position[A_MOTOR];
- break;
- case Y_AXIS:
- sys.position[A_MOTOR] = system_convert_maslow_to_x_axis_steps(sys.position);
- sys.position[B_MOTOR] = sys.position[A_MOTOR];
- break;
- default:
- sys.position[idx] = 0;
- break;
- }
- } while (idx);
- } else do {
-
- coord_data_t *pulloff = limits_homing_pulloff(NULL);
-
- if (cycle.mask & bit(--idx)) {
- int32_t off_axis_position;
- int32_t set_axis_position = bit_istrue(settings.homing.dir_mask.value, bit(idx))
- ? lroundf((settings.max_travel[idx] + pulloff->values[idx]) * settings.steps_per_mm[idx])
- : lroundf(-pulloff->values[idx] * settings.steps_per_mm[idx]);
- switch(idx) {
- case X_AXIS:
- off_axis_position = system_convert_maslow_to_y_axis_steps(sys.position);
- sys.position[A_MOTOR] = set_axis_position + off_axis_position;
- sys.position[B_MOTOR] = set_axis_position - off_axis_position;
- break;
- case Y_AXIS:
- off_axis_position = system_convert_maslow_to_x_axis_steps(sys.position);
- sys.position[A_MOTOR] = off_axis_position + set_axis_position;
- sys.position[B_MOTOR] = off_axis_position - set_axis_position;
- break;
- default:
- sys.position[idx] = set_axis_position;
- break;
- }
- }
- } while(idx);
- */
-}
-
-// TODO: format output in grbl fashion: [...]
-status_code_t maslow_tuning (sys_state_t state, char *line)
-{
- status_code_t retval = Status_OK;
-
- if(line[1] == 'M') switch(line[2]) {
-
- case 'C': // commit driver setting changes to non-volatile storage
- settings_dirty.is_dirty = settings_dirty.driver_settings = true;
- break;
-
- case 'X':
- selected_motor = A_MOTOR;
- hal.stream.write("X-Axis Selected" ASCII_EOL);
- break;
-
- case 'Y':
- selected_motor = B_MOTOR;
- hal.stream.write("Y-Axis Selected" ASCII_EOL);
- break;
-
- case 'Z':
- selected_motor = Z_AXIS;
- if(maslow_hal.get_debug_data(selected_motor))
- hal.stream.write("Z-Axis Selected" ASCII_EOL);
- else {
- selected_motor = A_MOTOR;
- hal.stream.write("Z-Axis is not PID controlled, switched to A motor" ASCII_EOL);
- }
- break;
-
- case 'G':
- maslow_hal.pos_enable(true);
- break;
-
- case 'R': // reset current position
- maslow_hal.reset_pid(selected_motor);
- break;
-
- case '+': // Move
- maslow_hal.move(selected_motor, 10000);
- break;
-
- case '-': // Move
- maslow_hal.move(selected_motor, -10000);
- break;
-
- case '*': // Move
- maslow_hal.move(selected_motor, 10);
- break;
-
- case '/': // Move
- maslow_hal.move(selected_motor, -10);
- break;
-
- case 'I':
- case 'M':
- case 'D':
- case 'P':
- case 'S':
- case 'A':;
- if(line[3] == '=' && line[4] != '\0') {
- float parameter;
- uint_fast8_t counter = 4;
-
- if(!read_float(line, &counter, ¶meter))
- retval = Status_BadNumberFormat;
-
- else switch(line[2]) {
-
- case 'P':
- maslow.pid[selected_motor].Kp = parameter;
- hal.stream.write("Kp == ");
- hal.stream.write(ftoa(maslow.pid[selected_motor].Kp, 3));
- hal.stream.write(ASCII_EOL);
- break;
-
- case 'D':
- maslow.pid[selected_motor].Kd = parameter;
- hal.stream.write("Kd == ");
- hal.stream.write(ftoa(maslow.pid[selected_motor].Kd, 3));
- hal.stream.write(ASCII_EOL);
- break;
-
- case 'I':
- maslow.pid[selected_motor].Ki = parameter;
- hal.stream.write("Ki == ");
- hal.stream.write(ftoa(maslow.pid[selected_motor].Ki, 3));
- hal.stream.write(ASCII_EOL);
- maslow_hal.pid_settings_changed(selected_motor);
- break;
-
- case 'M':
- maslow.pid[selected_motor].Imax = parameter;
- hal.stream.write("Imax == ");
- hal.stream.write(ftoa(maslow.pid[selected_motor].Imax, 3));
- hal.stream.write(ASCII_EOL);
- maslow_hal.pid_settings_changed(selected_motor);
- break;
-
- case 'S':
- {
- maslow_hal.tuning_enable(true);
- int32_t sz = maslow_hal.set_step_size(selected_motor, (int32_t)parameter);
- hal.stream.write("S == ");
- hal.stream.write(ftoa((float)sz, 0));
- hal.stream.write(ASCII_EOL);
- }
- break;
-
- case 'A': // test kinematics - from X,Y mm to A,B steps back to X,Y mm
- {
- float xyz[N_AXIS];
- int32_t abz[N_AXIS];
- recomputeGeometry();
- xyz[X_AXIS] = parameter;
- if(line[counter++] == ',' && line[counter] != '\0') {
- if(!read_float(line, &counter, &xyz[Y_AXIS]))
- retval = Status_BadNumberFormat;
- } else
- retval = Status_BadNumberFormat;
-
- if(retval == Status_OK) {
-
- triangularInverse(abz, xyz);
- hal.stream.write("[KINEMATICSTRANSFORM: X,Y = ");
- hal.stream.write(ftoa(xyz[X_AXIS], 3));
- hal.stream.write(",");
- hal.stream.write(ftoa(xyz[Y_AXIS], 3));
- hal.stream.write(" -> A,B steps: ");
- hal.stream.write(uitoa((uint32_t)abz[A_MOTOR]));
- hal.stream.write(",");
- hal.stream.write(uitoa((uint32_t)abz[B_MOTOR]));
-
- maslow_convert_array_steps_to_mpos(xyz, abz);
- hal.stream.write(" -> X,Y = ");
- hal.stream.write(ftoa(xyz[X_AXIS], 3));
- hal.stream.write(",");
- hal.stream.write(ftoa(xyz[Y_AXIS], 3));
- hal.stream.write("]" ASCII_EOL);
- }
- }
- break;
- }
- } else
- retval = Status_BadNumberFormat;
- break;
-
- default:
- {
- maslow_debug_t *debug = maslow_hal.get_debug_data(selected_motor);
-
- hal.stream.write("[AXISPID:");
- hal.stream.write(axis_letter[selected_motor]);
- hal.stream.write(": Kp = ");
- hal.stream.write(ftoa(maslow.pid[selected_motor].Kp, 3));
- hal.stream.write(" Ki = ");
- hal.stream.write(ftoa(maslow.pid[selected_motor].Ki, 3));
- hal.stream.write(" Kd = ");
- hal.stream.write(ftoa(maslow.pid[selected_motor].Kd, 3));
- hal.stream.write(" Imax = ");
- hal.stream.write(ftoa(maslow.pid[selected_motor].Imax, 3));
-
- hal.stream.write("]\r\n[PIDDATA:err=");
- hal.stream.write(ftoa(debug->Error, 0));
- hal.stream.write("\t\ti=");
- hal.stream.write(ftoa(debug->Integral, 0));
- hal.stream.write("\tiT=");
- hal.stream.write(ftoa(debug->iterm, 0));
- hal.stream.write("\td=");
- hal.stream.write(ftoa(debug->DiffTerm, 0));
- // hal.stream.write("\tV=");
- // hal.stream.write(ftoa(debug->totalSpeed, 0));
- hal.stream.write("\txCMD=");
- hal.stream.write(ftoa(debug->speed, 0));
- // hal.stream.write("\tyCMD=");
- // hal.stream.write(uitoa(motor[Y_AXIS]->speed));
- // hal.stream.write("\tzCMD=");
- // hal.stream.write(uitoa(motor[Z_AXIS]->speed));
- hal.stream.write("]" ASCII_EOL);
- }
- break;
- } else
- retval = Status_Unhandled;
-
- return retval;
-}
-
-// Initialize API pointers & machine parameters for Maslow router kinematics
-bool maslow_init (void)
-{
- float xy[2] = {0.0f, 0.0f};
-
- if((nvs_address = nvs_alloc(sizeof(maslow_settings_t)))) {
-
- details.on_get_settings = grbl.on_get_settings;
- grbl.on_get_settings = on_get_settings;
-
- recomputeGeometry();
- triangularInverse(sys.position, xy);
-
- selected_motor = A_MOTOR;
-
- kinematics.limits_set_target_pos = maslow_limits_set_target_pos;
- kinematics.limits_get_axis_mask = maslow_limits_get_axis_mask;
- kinematics.limits_set_machine_positions = maslow_limits_set_machine_positions;
- kinematics.plan_target_to_steps = maslow_target_to_steps;
- kinematics.convert_array_steps_to_mpos = maslow_convert_array_steps_to_mpos;
- kinematics.segment_line = maslow_segment_line;
-
- grbl.on_unknown_sys_command = maslow_tuning;
- }
-
- return nvs_address != 0;
-}
-
-#endif
-
diff --git a/kinematics/maslow.h b/kinematics/maslow.h
deleted file mode 100644
index 61fe64b..0000000
--- a/kinematics/maslow.h
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- maslow.h - Maslow router kinematics implementation
-
- Part of grblHAL
-
- 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 .
-
- The basis for this code has been pulled from MaslowDue created by Larry D O'Cull.
-
-
- Some portions of that package directly or indirectly has been pulled from from the Maslow CNC
- firmware for Aduino Mega. Those parts are Copyright 2014-2017 Bar Smith.
-
-
- It has been adapted for grbl by Terje Io.
-
- *** TO BE COMPLETED ***
-
-*/
-
-#include "../grbl.h"
-
-#ifndef _MASLOW_H_
-#define _MASLOW_H_
-
-#define FP_SCALING 1024.0f
-#define SPROCKET_RADIUS_MM (10.1f)
-#define MAX_SEG_LENGTH_MM 2.0f /* long lines must be segmented due to circular motion */
-
- // PID position loop factors X: Kp = 25000 Ki = 15000 Kd = 22000 Imax = 5000
- // 14.000 fixed point arithmetic S13.10
-#ifdef DRIVER_TLE5206
- #define MASLOW_A_KP 10.0f
- #define MASLOW_A_KI 21.0f
- #define MASLOW_A_KD 18.0f
- #define MASLOW_A_IMAX 5000
-
- #define MASLOW_B_KP 10.0f
- #define MASLOW_B_KI 21.0f
- #define MASLOW_B_KD 18.0f
- #define MASLOW_B_IMAX 5000
-
- #define MASLOW_Z_KP 10.0f
- #define MASLOW_Z_KI 21.0f
- #define MASLOW_Z_KD 17.0f
- #define MASLOW_Z_IMAX 5000
-#else
- #define MASLOW_A_KP 22.0f
- #define MASLOW_A_KI 17.0f
- #define MASLOW_A_KD 20.0f
- #define MASLOW_A_IMAX 5000
-
- #define MASLOW_B_KP 22.0f
- #define MASLOW_B_KI 17.0f
- #define MASLOW_B_KD 20.0f
- #define MASLOW_B_IMAX 5000
-
- #define MASLOW_Z_KP 20.0f
- #define MASLOW_Z_KI 17.0f
- #define MASLOW_Z_KD 18.0f
- #define MASLOW_Z_IMAX 5000
-#endif
-
-#define MASLOW_MACHINEWIDTH 2400.0f
-#define MASLOW_MACHINEHEIGHT 1200.0f
-#define MASLOW_DISTBETWEENMOTORS 3000.0f
-#define MASLOW_MOTOROFFSETY 600.0f
-#define MASLOW_CHAINLENGTH 3000.0f
-#define MASLOW_CHAINOVERSPROCKET 0
-#define MASLOW_CHAINSAGCORRECTION 59.504839f
-#define MASLOW_LEFTCHAINTOLERANCE 0.0f
-#define MASLOW_RIGHTCHAINTOLERANCE 0.0f
-#define MASLOW_ROTATIONDISKRADIUS 104.3f
-#define MASLOW_SLEDHEIGHT 139.0f
-#define MASLOW_SLEDWIDTH 310.0f
-#define MASLOW_ACORRSCALING 1.003922f
-#define MASLOW_BCORRSCALING 1.002611f
-
-typedef enum {
- Maslow_ChainOverSprocket = 260,
- Maslow_MachineWidth,
- Maslow_MachineHeight,
- Maslow_DistBetweenMotors,
- Maslow_MotorOffsetY,
- Maslow_AcorrScaling,
- Maslow_BcorrScaling,
- Maslow_SettingMax,
-} maslow_setting_t;
-
-typedef enum {
- AxisSetting_MaslowKP = 10,
- AxisSetting_MaslowKI,
- AxisSetting_MaslowKD,
- AxisSetting_MaslowIMax,
- AxisSetting_MaslowMaxSetting
-} maslow_axis_setting_t;
-
-typedef struct {
- float Kp;
- float Ki;
- float Kd;
- float Imax;
-} maslow_pid_coefficients_t;
-
-typedef struct {
- maslow_pid_coefficients_t pid[N_AXIS];
-
- uint32_t chainOverSprocket;
- float machineWidth; /* Maslow specific settings */
- float machineHeight;
- float distBetweenMotors;
- float motorOffsetY;
- float chainSagCorrection;
- float leftChainTolerance;
- float rightChainTolerance;
- float rotationDiskRadius;
- float chainLength;
- float sledHeight;
- float sledWidth;
-
- float XcorrScaling;
- float YcorrScaling;
-} maslow_settings_t;
-
-typedef struct {
- float Error;
- float Integral;
- float iterm;
- float DiffTerm;
- float speed;
-} maslow_debug_t;
-
-typedef struct {
- maslow_settings_t settings;
- void (*pid_settings_changed)(uint_fast8_t idx);
- void (*move)(uint_fast8_t idx, int_fast16_t distance);
- void (*reset_pid)(uint_fast8_t idx);
- void (*pos_enable)(bool enable);
- void (*tuning_enable)(bool enable);
- int32_t (*set_step_size)(uint_fast8_t idx, int32_t step_size);
- maslow_debug_t *(*get_debug_data)(uint_fast8_t idx);
-} maslow_hal_t;
-
-extern maslow_hal_t maslow_hal;
-
-// Initialize HAL pointers for Maslow Router kinematics
-bool maslow_init (void);
-static status_code_t maslow_tuning (uint_fast16_t state, char *line);
-
-#endif
diff --git a/kinematics/polar.h b/kinematics/polar.h
deleted file mode 100644
index 715e6c0..0000000
--- a/kinematics/polar.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- corexy.c - polar kinematics implementation
-
- Part of grblHAL
-
- Copyright (c) 2023 Terje Io
-
- grblHAL 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.
-
- grblHAL 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 grblHAL. If not, see .
-*/
-
-#ifndef _POLAR_H_
-#define _POLAR_H_
-
-// Initialize HAL pointers for Polar kinematics
-void polar_init (void);
-
-#endif // _POLAR_H_
diff --git a/kinematics/wall_plotter.h b/kinematics/wall_plotter.h
deleted file mode 100644
index 5242a70..0000000
--- a/kinematics/wall_plotter.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- wall_plotter.h - wall plotter kinematics implementation
-
- Part of grblHAL
-
- Copyright (c) 2019 Terje Io
-
- grblHAL 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.
-
- grblHAL 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 grblHAL. If not, see .
-*/
-
-#ifndef _WALL_PLOTTER_H_
-#define _WALL_PLOTTER_H_
-
-// Initialize HAL pointers for Wall Plotter kinematics
-void wall_plotter_init (void);
-
-#endif
diff --git a/machine_limits.c b/machine_limits.c
index cbe2ae2..92c96e7 100644
--- a/machine_limits.c
+++ b/machine_limits.c
@@ -139,8 +139,6 @@ FLASHMEM void limits_set_work_envelope (void)
} while(idx);
}
-#ifndef KINEMATICS_API
-
// Set machine positions for homed limit switches. Don't update non-homed axes.
// NOTE: settings.max_travel[] is stored as a negative value.
FLASHMEM void limits_set_machine_positions (axes_signals_t cycle, bool add_pulloff)
@@ -164,8 +162,6 @@ FLASHMEM void limits_set_machine_positions (axes_signals_t cycle, bool add_pullo
} while(idx);
}
-#endif
-
// Set, get homing pulloff
FLASHMEM coord_data_t *limits_homing_pulloff (coord_data_t *distance)
{
@@ -204,11 +200,12 @@ FLASHMEM static bool limits_pull_off (axes_signals_t axis, coord_data_t *distanc
plan_data.feed_rate = settings.axis[0].homing_seek_rate * sqrtf(n_axis); // Adjust so individual axes all move at pull-off rate.
plan_data.condition.coolant = gc_state.modal.coolant;
+ // Bypass mc_line(). Directly plan homing motion.
#ifdef KINEMATICS_API
coord_data_t k_target;
- plan_buffer_line(kinematics.transform_from_cartesian(k_target.values, target.values), &plan_data); // Bypass mc_line(). Directly plan homing motion.;
+ plan_buffer_line(kinematics.transform_from_cartesian(k_target.values, target.values), &plan_data);
#else
- plan_buffer_line(target.values, &plan_data); // Bypass mc_line(). Directly plan homing motion.
+ plan_buffer_line(target.values, &plan_data);
#endif
sys.step_control.flags = 0; // Clear existing flags and
@@ -419,7 +416,7 @@ FLASHMEM static bool homing_cycle (axes_signals_t cycle, axes_signals_t auto_squ
idx = N_AXIS;
do {
idx--;
- if ((axislock.mask & step_pin[idx]) && (homing_state.mask & bit(idx))) {
+ if((axislock.mask & step_pin[idx]) && (homing_state.mask & bit(idx))) {
#ifdef KINEMATICS_API
axislock.mask &= ~kinematics.limits_get_axis_mask(idx);
#else
@@ -432,7 +429,7 @@ FLASHMEM static bool homing_cycle (axes_signals_t cycle, axes_signals_t auto_squ
sys.homing_axis_lock.mask = axislock.mask;
- if (autosquare_check && abs(initial_trigger_position - sys.position[dual_motor_axis]) > autosquare_fail_distance) {
+ if(autosquare_check && abs(initial_trigger_position - sys.position[dual_motor_axis]) > autosquare_fail_distance) {
system_set_exec_alarm(Alarm_HomingFailAutoSquaringApproach);
mc_reset();
protocol_execute_realtime();
@@ -523,9 +520,11 @@ FLASHMEM static bool homing_cycle (axes_signals_t cycle, axes_signals_t auto_squ
if(auto_square.mask && settings.axis[dual_motor_axis].dual_axis_offset != 0.0f) {
hal.stepper.disable_motors(auto_square, settings.axis[dual_motor_axis].dual_axis_offset < 0.0f ? SquaringMode_B : SquaringMode_A);
distance.values[dual_motor_axis] = fabs(settings.axis[dual_motor_axis].dual_axis_offset);
+#if defined(ASYMMETRIC_GANGING) || defined(ASYMMETRIC_AUTO_SQUARE)
+ auto_square.mask |= (1 << (N_AXIS - 1));
+#endif
if(!limits_pull_off(auto_square, &distance, 1.0f))
return false;
- hal.stepper.disable_motors((axes_signals_t){0}, SquaringMode_Both);
}
// The active cycle axes should now be homed and machine limits have been located. By
@@ -615,6 +614,8 @@ FLASHMEM status_code_t limits_go_home (axes_signals_t cycle)
if((auto_squared.mask & homing_signals_select(hal.homing.get_state(), (axes_signals_t){0}, SquaringMode_Both).mask) && !limits_pull_off(auto_square, &homing_pulloff, HOMING_AXIS_LOCATE_SCALAR))
return Status_LimitsEngaged; // Auto squaring with limit switch asserted is not allowed.
+
+ hal.stepper.disable_motors((axes_signals_t){0}, SquaringMode_Both);
}
return grbl.home_machine(cycle, auto_square) ? Status_OK : Status_Unhandled;
diff --git a/motor_pins.h b/motor_pins.h
index bb1decb..c089769 100644
--- a/motor_pins.h
+++ b/motor_pins.h
@@ -474,7 +474,7 @@
#define Z2_STEP_PORT MOTOR_IO(Z2_MOTOR_IDX, _STEP_PORT)
#define Z2_STEP_PIN MOTOR_IO(Z2_MOTOR_IDX, _STEP_PIN)
-#define Z2_STEP_BIT (1<< 3
@@ -108,7 +108,7 @@ static char *get_axis_values_inches (float *axis_values)
#endif
else
strcat(buf, ftoa(axis_values[idx] * INCH_PER_MM, N_DECIMAL_COORDVALUE_INCH));
- if (idx < (N_AXIS - 1))
+ if (idx < (system_n_axis() - 1))
strcat(buf, ",");
}
@@ -691,7 +691,7 @@ FLASHMEM void report_ngc_parameters (void)
static inline bool is_g92_active (void)
{
bool active = false;
- uint_fast32_t idx = N_AXIS;
+ uint_fast32_t idx = system_n_axis();
do {
idx--;
@@ -959,7 +959,7 @@ FLASHMEM void report_build_info (char *line, bool extended)
hal.stream.write(uitoa(hal.rx_buffer_size));
if(extended) {
hal.stream.write(",");
- hal.stream.write(uitoa((uint32_t)N_AXIS));
+ hal.stream.write(uitoa((uint32_t)system_n_axis()));
hal.stream.write(",");
hal.stream.write(uitoa(grbl.tool_table.n_tools));
}
@@ -971,12 +971,12 @@ FLASHMEM void report_build_info (char *line, bool extended)
nvs_io_t *nvs = nvs_buffer_get_physical();
atc_status_t atc = hal.tool.atc_get_state();
- strcat(strcpy(buf, "[AXS:"), uitoa(N_AXIS));
+ strcat(strcpy(buf, "[AXS:"), uitoa((uint32_t)system_n_axis()));
append = &buf[6];
*append++ = ':';
- for(idx = 0; idx < N_AXIS; idx++)
+ for(idx = 0; idx < system_n_axis(); idx++)
*append++ = *axis_letter[idx];
*append = '\0';
@@ -1267,7 +1267,7 @@ void report_realtime_status (stream_write_ptr stream_write, status_report_tracki
// Calculate distance-to-go in current block (i.e., difference between target / end-of-block) and current position)
plan_block_t *cur_block = plan_get_current_block();
if((report->flags.distance_to_go = !!cur_block)) {
- for(idx = 0; idx < N_AXIS; idx++) {
+ for(idx = 0; idx < system_n_axis(); idx++) {
dist_remaining[idx] = cur_block->target_mm[idx] - print_position[idx];
}
}
@@ -1275,7 +1275,7 @@ void report_realtime_status (stream_write_ptr stream_write, status_report_tracki
if(!settings.status_report.machine_position) {
// Apply work coordinate offsets and tool length offset to current position.
- for(idx = 0; idx < N_AXIS; idx++) {
+ for(idx = 0; idx < system_n_axis(); idx++) {
wco[idx] = gc_get_offset(idx, true);
print_position[idx] -= wco[idx];
}
@@ -1433,7 +1433,7 @@ void report_realtime_status (stream_write_ptr stream_write, status_report_tracki
if(report->flags.wco) {
if(settings.status_report.machine_position) {
- for(idx = 0; idx < N_AXIS; idx++)
+ for(idx = 0; idx < system_n_axis(); idx++)
wco[idx] = gc_get_offset(idx, true);
}
stream_write("|WCO:");
diff --git a/settings.c b/settings.c
index abaa6f2..dc8fafb 100644
--- a/settings.c
+++ b/settings.c
@@ -57,7 +57,7 @@ const settings_restore_t settings_all = {
.driver_parameters = SETTINGS_RESTORE_DRIVER_PARAMETERS
};
-PROGMEM const settings_t defaults = {
+PROGMEM static const settings_t defaults = {
.version.id = SETTINGS_VERSION,
.version.build = (GRBL_BUILD - 20000000UL),
@@ -399,7 +399,7 @@ PROGMEM const settings_t defaults = {
static bool group_is_available (const setting_group_detail_t *group)
{
- return true;
+ return group->id < Group_XAxis || group->id > Group_WAxis || group->id < Group_Axis0 + system_n_axis();
}
PROGMEM static const setting_group_detail_t setting_group_detail [] = {
@@ -582,27 +582,164 @@ static void homing_pulloff_init (float pulloff)
limits_homing_pulloff(&distance);
}
+FLASHMEM static status_code_t set_axis_mask (setting_id_t id, uint_fast16_t value)
+{
+ status_code_t status = Status_OK;
+
+ value &= AXES_BITMASK;
+
+ switch(id) {
+
+ case Setting_StepInvertMask:
+ settings.steppers.step_invert.mask = value;
+ break;
+
+ case Setting_DirInvertMask:
+ settings.steppers.dir_invert.mask = value;
+ break;
+
+ case Setting_InvertStepperEnable:
#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;
-}
-
+ settings.steppers.enable_invert.mask = value ? 0 : AXES_BITMASK;
+#else
+ settings.steppers.enable_invert.mask = value;
#endif
+ break;
+ case Setting_LimitPinsInvertMask:
#if COMPATIBILITY_LEVEL > 1
+ settings.steppers.enable_invert.mask = value ? 0 : AXES_BITMASK;
+#else
+ settings.steppers.enable_invert.mask = value;
+#endif
+ break;
-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;
+ case Setting_LimitPullUpDisableMask:
+ settings.limits.disable_pullup.mask = value;
+ break;
- return Status_OK;
+ case Setting_HomingDirMask:
+ settings.homing.dir_mask.value = value;
+ break;
+
+ case Setting_SteppersEnergize:
+ settings.steppers.energize.mask = 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:
+ settings.homing.cycle[id - Setting_HomingCycle_1].mask = value;
+ break;
+
+ case Setting_HomePinsInvertMask:
+ settings.home_invert.mask = value;
+ break;
+
+ case Setting_MotorWarningsEnable:
+ settings.motor_warning_enable.mask = value;
+ break;
+
+ case Setting_MotorWarningsInvert:
+ settings.motor_warning_invert.mask = value;
+ break;
+
+ case Setting_MotorFaultsEnable:
+ settings.motor_fault_enable.mask = value;
+ break;
+
+ case Setting_MotorFaultsInvert:
+ settings.motor_fault_invert.mask = value;
+ break;
+
+ default:
+ // Should never enter here
+ break;
+ }
+
+ return status;
}
+FLASHMEM static uint32_t get_axis_mask (setting_id_t id, uint_fast16_t int_value)
+{
+ uint32_t value = 0;
+
+ switch(id) {
+
+ case Setting_StepInvertMask:
+ value = settings.steppers.step_invert.mask;
+ break;
+
+ case Setting_DirInvertMask:
+ value = settings.steppers.dir_invert.mask;
+ break;
+
+ case Setting_InvertStepperEnable:
+#if COMPATIBILITY_LEVEL > 2
+ value = !!settings.steppers.enable_invert.mask;
+#else
+ value = settings.steppers.enable_invert.mask;
#endif
+ break;
+
+ case Setting_LimitPinsInvertMask:
+#if COMPATIBILITY_LEVEL > 1
+ value = settings.steppers.enable_invert.mask == DEFAULT_LIMIT_SIGNALS_INVERT_MASK ? 0 : 1;
+#else
+ value = settings.steppers.enable_invert.mask;
+#endif
+ break;
+
+ case Setting_LimitPullUpDisableMask:
+ value = settings.limits.disable_pullup.mask;
+ break;
+
+ case Setting_HomingDirMask:
+ value = settings.homing.dir_mask.value;
+ break;
+
+ case Setting_SteppersEnergize:
+ value = settings.steppers.energize.mask;
+ 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 & system_axis_mask();
+ break;
+
+ case Setting_HomePinsInvertMask:
+ value = settings.home_invert.mask;
+ break;
+
+ case Setting_MotorWarningsEnable:
+ value = settings.motor_warning_enable.mask;
+ break;
+
+ case Setting_MotorWarningsInvert:
+ value = settings.motor_warning_invert.mask;
+ break;
+
+ case Setting_MotorFaultsEnable:
+ value = settings.motor_fault_enable.mask;
+ break;
+
+ case Setting_MotorFaultsInvert:
+ value = settings.motor_fault_invert.mask;
+ break;
+
+ default:
+ break;
+ }
+
+ return value & system_axis_mask();
+}
static status_code_t validate_pulse_width (float max_rate, float steps_per_mm, float pulse_width)
{
@@ -622,7 +759,7 @@ static status_code_t set_pulse_width (setting_id_t id, float value)
do {
idx--;
#if N_AXIS > 3
- if(bit_isfalse(settings.steppers.is_rotary.mask, bit(idx)))
+ if(system_n_axis() > 3 && bit_isfalse(settings.steppers.is_rotary.mask, bit(idx)))
#endif
status = validate_pulse_width(settings.axis[idx].max_rate, settings.axis[idx].steps_per_mm, value);
} while(idx && status == Status_OK);
@@ -663,15 +800,6 @@ static status_code_t set_ganged_dir_invert (setting_id_t id, uint_fast16_t int_v
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)
@@ -993,14 +1121,6 @@ static status_code_t set_restore_overrides (setting_id_t id, uint_fast16_t int_v
#endif // NO_SAFETY_DOOR_SUPPORT
-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_homing_pulloff (setting_id_t id, float value)
{
settings.homing.pulloff = value;
@@ -1012,7 +1132,7 @@ static status_code_t set_homing_pulloff (setting_id_t id, float value)
static status_code_t set_homing_feedrates (setting_id_t id, float value)
{
- uint_fast8_t idx = N_AXIS;
+ uint_fast8_t idx = system_n_axis();
if(!settings.homing.flags.per_axis_feedrates) switch(id) {
@@ -1516,18 +1636,6 @@ FLASHMEM static uint32_t get_int (setting_id_t id)
switch(id) {
-#if COMPATIBILITY_LEVEL > 2
- case Setting_InvertStepperEnable:
- value = settings.steppers.enable_invert.mask ? 0 : 1;
- break;
-#endif
-
-#if COMPATIBILITY_LEVEL > 1
- case Setting_LimitPinsInvertMask:
- value = settings.limits.invert.mask == DEFAULT_LIMIT_SIGNALS_INVERT_MASK ? 0 : 1;
- break;
-#endif
-
case Setting_SpindlePWMOptions:
value = settings.pwm_spindle.flags.pwm_disable
? 0
@@ -1538,6 +1646,10 @@ FLASHMEM static uint32_t get_int (setting_id_t id)
(settings.pwm_spindle.flags.ignore_delays ? 0b10000 : 0));
break;
+ case Setting_HomingDirMask:
+ value = settings.homing.dir_mask.mask & system_axis_mask();
+ break;
+
case Setting_Mode:
value = settings.mode;
break;
@@ -1620,15 +1732,6 @@ FLASHMEM static uint32_t get_int (setting_id_t id)
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;
@@ -1959,6 +2062,24 @@ FLASHMEM static bool is_setting_available (const setting_detail_t *setting, uint
available = spindle_get_caps(false).variable;
break;
+#if N_AXIS > 3
+ case Setting_HomingCycle_4:
+ case Settings_RotaryAxes:
+ case Setting_RotaryWrap:
+ available = system_n_axis() > 3;
+ break;
+#endif
+#if N_AXIS > 4
+ case Setting_HomingCycle_5:
+ available = system_n_axis() > 4;
+ break;
+#endif
+#if N_AXIS > 5
+ case Setting_HomingCycle_6:
+ available = system_n_axis() > 5;
+ break;
+#endif
+
case Setting_SleepEnable:
available = SLEEP_DURATION > 0.0f;
break;
@@ -2156,17 +2277,17 @@ FLASHMEM static void _settings_write_global (void)
PROGMEM static const setting_detail_t setting_detail[] = {
{ Setting_PulseMicroseconds, Group_Stepper, "Step pulse time", "microseconds", Format_Decimal, "#0.0", step_us_min, NULL, Setting_IsLegacyFn, set_pulse_width, get_float, 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_StepInvertMask, Group_Stepper, "Step pulse invert", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsLegacyFn, set_axis_mask, get_axis_mask, NULL },
+ { Setting_DirInvertMask, Group_Stepper, "Step direction invert", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsLegacyFn, set_axis_mask, get_axis_mask, 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 },
+ { Setting_InvertStepperEnable, Group_Stepper, "Invert stepper enable output(s)", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsLegacyFn, set_axis_mask, get_axis_mask, 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 },
+ { Setting_InvertStepperEnable, Group_Stepper, "Invert stepper enable output", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsLegacyFn, set_axis_mask, get_axis_mask, 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 },
+ { Setting_LimitPinsInvertMask, Group_Limits, "Invert limit inputs", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsLegacyFn, set_axis_mask, get_axis_mask, NULL },
#else
- { Setting_LimitPinsInvertMask, Group_Limits, "Invert limit inputs", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsLegacyFn, set_limits_invert_mask, get_int, NULL },
+ { Setting_LimitPinsInvertMask, Group_Limits, "Invert limit inputs", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsLegacyFn, set_axis_mask, get_axis_mask, NULL },
#endif
{ Setting_InvertProbePin, Group_Probing, "Invert probe inputs", NULL, Format_Bitfield, probe_signals, 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 },
@@ -2184,7 +2305,7 @@ PROGMEM static const setting_detail_t setting_detail[] = {
{ 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, is_setting_available },
- { Setting_LimitPullUpDisableMask, Group_Limits, "Pullup disable limit inputs", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtended, &settings.limits.disable_pullup.mask, NULL, NULL },
+ { Setting_LimitPullUpDisableMask, Group_Limits, "Pullup disable limit inputs", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_axis_mask, get_axis_mask, NULL },
{ Setting_ProbePullUpDisable, Group_Probing, "Pullup disable probe inputs", NULL, Format_Bitfield, probe_signals, NULL, NULL, Setting_IsLegacyFn, 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
@@ -2201,7 +2322,7 @@ PROGMEM static const setting_detail_t setting_detail[] = {
#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_HomingDirMask, Group_Homing, "Homing direction invert", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsLegacyFn, set_axis_mask, get_axis_mask, 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 },
@@ -2217,24 +2338,24 @@ PROGMEM static const setting_detail_t setting_detail[] = {
{ 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_SteppersEnergize, Group_Stepper, "Steppers to keep enabled", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_axis_mask, get_axis_mask, 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 },
{ Setting_ParkingEnable, Group_SafetyDoor, "Parking cycle", NULL, Format_XBitfield, "Enable,Deactivate upon init,Enable parking override control", 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 },
{ 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 phase", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_homing_cycle, get_int, NULL },
- { Setting_HomingCycle_2, Group_Homing, "Axes homing, second phase", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_homing_cycle, get_int, NULL },
- { Setting_HomingCycle_3, Group_Homing, "Axes homing, third phase", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_homing_cycle, get_int, NULL },
+ { Setting_HomingCycle_1, Group_Homing, "Axes homing, first phase", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_axis_mask, get_axis_mask, NULL },
+ { Setting_HomingCycle_2, Group_Homing, "Axes homing, second phase", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_axis_mask, get_axis_mask, NULL },
+ { Setting_HomingCycle_3, Group_Homing, "Axes homing, third phase", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_axis_mask, get_axis_mask, NULL },
#if N_AXIS > 3
- { Setting_HomingCycle_4, Group_Homing, "Axes homing, fourth phase", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_homing_cycle, get_int, NULL },
+ { Setting_HomingCycle_4, Group_Homing, "Axes homing, fourth phase", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_axis_mask, get_axis_mask, is_setting_available },
#endif
#if N_AXIS > 4
- { Setting_HomingCycle_5, Group_Homing, "Axes homing, fifth phase", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_homing_cycle, get_int, NULL },
+ { Setting_HomingCycle_5, Group_Homing, "Axes homing, fifth phase", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_axis_mask, get_axis_mask, is_setting_available },
#endif
#if N_AXIS > 5
- { Setting_HomingCycle_6, Group_Homing, "Axes homing, sixth phase", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_homing_cycle, get_int, NULL },
+ { Setting_HomingCycle_6, Group_Homing, "Axes homing, sixth phase", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_axis_mask, get_axis_mask, is_setting_available },
#endif
{ 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 },
@@ -2291,7 +2412,7 @@ PROGMEM static const setting_detail_t setting_detail[] = {
{ 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 },
+ { Settings_RotaryAxes, Group_Stepper, "Rotary axes", NULL, Format_Bitfield, rotary_axes, NULL, NULL, Setting_IsExtendedFn, set_rotary_axes, get_int, is_setting_available },
#endif
{ 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, { .allow_null = On } },
{ 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, { .allow_null = On } },
@@ -2312,16 +2433,16 @@ PROGMEM static const setting_detail_t setting_detail[] = {
{ Setting_RGB_StripLengt0, Group_AuxPorts, "LED strip 1 length", NULL, Format_Int8, "##0", NULL, "255", Setting_NonCore, &settings.rgb_strip.length0, NULL, is_setting_available },
{ Setting_RGB_StripLengt1, Group_AuxPorts, "LED strip 2 length", NULL, Format_Int8, "##0", NULL, "255", Setting_NonCore, &settings.rgb_strip.length1, NULL, 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 },
+ { Setting_RotaryWrap, Group_Stepper, "Fast rotary go to G28", NULL, Format_Bitfield, rotary_axes, NULL, NULL, Setting_IsExtendedFn, set_rotary_wrap_axes, get_int, is_setting_available },
#endif
{ Setting_SpindleOffDelay, Group_Spindle, "Spindle off delay", "s", Format_Decimal, "#0.0", "0.5", "20", Setting_IsExtendedFn, set_float, get_float, is_setting_available, { .allow_null = On } },
{ 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_HomePinsInvertMask, Group_Limits, "Invert home inputs", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_axis_mask, get_axis_mask, is_setting_available },
{ Setting_CoolantOnDelay, Group_Coolant, "Coolant on delay", "s", Format_Decimal, "#0.0", "0.5", "20", Setting_IsExtendedFn, set_float, get_float, is_setting_available, { .allow_null = On } },
- { Setting_MotorWarningsEnable, Group_Stepper, "Motor warning inputs enable", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtended, &settings.motor_warning_enable, NULL, is_setting_available },
- { Setting_MotorWarningsInvert, Group_Stepper, "Invert motor warning inputs", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtended, &settings.motor_warning_invert, NULL, is_setting_available },
- { Setting_MotorFaultsEnable, Group_Stepper, "Motor fault inputs enable", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtended, &settings.motor_fault_enable, NULL, is_setting_available },
- { Setting_MotorFaultsInvert, Group_Stepper, "Invert motor fault inputs", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtended, &settings.motor_fault_invert, NULL, is_setting_available },
+ { Setting_MotorWarningsEnable, Group_Stepper, "Motor warning inputs enable", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_axis_mask, get_axis_mask, is_setting_available },
+ { Setting_MotorWarningsInvert, Group_Stepper, "Invert motor warning inputs", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_axis_mask, get_axis_mask, is_setting_available },
+ { Setting_MotorFaultsEnable, Group_Stepper, "Motor fault inputs enable", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_axis_mask, get_axis_mask, is_setting_available },
+ { Setting_MotorFaultsInvert, Group_Stepper, "Invert motor fault inputs", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_axis_mask, get_axis_mask, is_setting_available },
{ Setting_ResetActions, Group_General, "Reset actions", NULL, Format_Bitfield, "Clear homed status if position was lost,Clear offsets (except G92),Clear rapids override,Clear feed override", NULL, NULL, Setting_IsExtendedFn, set_reset_actions, get_int, NULL },
{ Setting_StepperEnableDelay, Group_Stepper, "Stepper enable delay", "ms", Format_Int16, "##0", NULL, "500", Setting_IsExtended, &settings.stepper_enable_delay, NULL, NULL },
{ Setting_SubroutineOptions, Group_General, "Subroutine options", NULL, Format_Bitfield, "Prescan for internal M98 subroutines", NULL, NULL, Setting_IsExtendedFn, set_suboptions, get_int, is_setting_available }
@@ -2897,7 +3018,7 @@ FLASHMEM bool settings_iterator (const setting_detail_t *setting, setting_output
uint_fast8_t axis_idx = 0;
- for(axis_idx = 0; axis_idx < N_AXIS; axis_idx++) {
+ for(axis_idx = 0; axis_idx < system_n_axis(); axis_idx++) {
if(setting->is_available == NULL || setting->is_available(setting, axis_idx)) {
@@ -3210,7 +3331,7 @@ FLASHMEM static status_code_t setting_validate_me_uint (const setting_detail_t *
break;
case Format_AxisMask:
- if(value >= (1 << N_AXIS))
+ if(value >= (1 << system_n_axis()))
status = Status_SettingValueOutOfRange;
break;
@@ -3416,6 +3537,25 @@ FLASHMEM status_code_t settings_store_setting (setting_id_t id, char *svalue)
machine_mode_changed = false;
set->on_changed(&settings, changed);
+
+ switch(setting->id) {
+
+ case Setting_SteppersEnergize:
+ hal.stepper.enable(settings.steppers.energize, true);
+ 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:
+ limits_set_homing_axes();
+ break;
+
+ default:
+ break;
+ }
}
}
@@ -3570,7 +3710,7 @@ FLASHMEM void settings_init (void)
setting_remove_elements(Setting_DoorOptions, ((!settings.parking.flags.enabled || hal.signals_cap.safety_door_ajar) << 1) | hal.signals_cap.safety_door_ajar, true);
#endif
#if N_AXIS > 3
- for(idx = 3; idx < N_AXIS; idx++)
+ for(idx = 3; idx < system_n_axis(); idx++)
*(rotary_axes + (idx - 3) * 7) = *axis_letter[idx];
#endif
diff --git a/system.c b/system.c
index a9d3580..6fea714 100644
--- a/system.c
+++ b/system.c
@@ -33,6 +33,8 @@
#include "kinematics.h"
#endif
+static uint8_t n_axis = N_AXIS;
+
/*! \internal \brief Simple hypotenuse computation function.
\param x length
\param y height
@@ -43,6 +45,27 @@ inline static float hypot_f (float x, float y)
return sqrtf(x * x + y * y);
}
+FLASHMEM uint8_t system_claim_axis (void)
+{
+ return n_axis > 3 ? n_axis-- : 0;
+}
+
+uint8_t system_n_axis (void)
+{
+ return n_axis;
+}
+
+FLASHMEM uint8_t system_axis_mask (void)
+{
+ uint8_t axis_mask = 0;
+ uint_fast32_t idx = n_axis;
+
+ while(idx--)
+ axis_mask = (axis_mask << 1) | 1;
+
+ return axis_mask;
+}
+
void system_init_switches (void)
{
control_signals_t signals = hal.control.get_state();
@@ -165,6 +188,8 @@ FLASHMEM void system_execute_startup (void *data)
uint_fast8_t idx;
char line[sizeof(stored_line_t)];
+ bool single_block = sys.flags.single_block;
+ sys.flags.single_block = Off; // Disable single block mode when executing startup code.
for(idx = 0; idx < N_STARTUP_LINE; idx++) {
if(!settings_read_startup_line(idx, line))
@@ -176,6 +201,8 @@ FLASHMEM void system_execute_startup (void *data)
} while((block = strtok(NULL, "|")));
}
}
+
+ sys.flags.single_block = single_block;
}
}
diff --git a/system.h b/system.h
index 8a4a0bd..70b8473 100644
--- a/system.h
+++ b/system.h
@@ -319,6 +319,10 @@ typedef struct sys_commands_str {
extern system_t sys;
+uint8_t system_n_axis (void);
+uint8_t system_axis_mask (void);
+uint8_t system_claim_axis (void);
+
status_code_t system_execute_line (char *line);
void system_execute_startup (void *data);
void system_flag_wco_change (void);