diff --git a/README.md b/README.md
index ec91402..5d2a209 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@ It has been written to complement grblHAL and has features such as proper keyboa
---
-Latest build date is 20240928, see the [changelog](changelog.md) for details.
+Latest build date is 20241006, see the [changelog](changelog.md) for details.
__NOTE:__ Build 20240222 has moved the probe input to the ioPorts pool of inputs and will be allocated from it when configured.
The change is major and _potentially dangerous_, it may damage your probe, so please _verify correct operation_ after installing this, or later, builds.
diff --git a/changelog.md b/changelog.md
index 1158a89..40c22fc 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,7 +1,33 @@
## grblHAL changelog
+Build 2024106
+
+Core:
+
+* Fix for `M62` - `M68` regression. Ref. [issue #600](https://github.com/grblHAL/core/issues/600).
+
+* Fixed incorrect handling of `G65` call parameters, axis words had offsets added. Ref. [issue #594](https://github.com/grblHAL/core/issues/594).
+
+* Refactored handling of multiple spindles. There are still some limitations but should work better now. Disabled override delays for now, needs investigation. Ref. [issue #598](https://github.com/grblHAL/core/issues/598).
+__NOTE:__ Please report any erratic behaviour after installing this version since it is a rather major change.
+
+Drivers:
+
+* ESP32: fix for compilation error. Ref. [issue #122](https://github.com/grblHAL/ESP32/issues/122).
+Fixes for handling multiple devices on a single SPI port. Fixed xPro v5 map for Modbus comms. Ref. [issue #121](https://github.com/grblHAL/ESP32/issues/121).
+
+* STM32F4xx: fix for compilation error for some boards when configured for Trinamic drivers.
+
+Plugins:
+
+* BLTouch: implemented `$BLTEST` command, verified.
+
+---
+
Build 20240928
+Core:
+
* Added `(PRINT, )` support and parameter formatting for `DEBUG` and `PRINT` commands. Available when expression support is enabled.
* Added named parameters for getting absolute \(G53\) position: `_abs_x`, `abs_y`, ... Available when expression support is enabled.
diff --git a/gcode.c b/gcode.c
index 4381e4c..e60b6de 100644
--- a/gcode.c
+++ b/gcode.c
@@ -38,7 +38,7 @@
// NOTE: Max line number is defined by the g-code standard to be 99999. It seems to be an
// arbitrary value, and some GUIs may require more. So we increased it based on a max safe
-// value when converting a float (7.2 digit precision)s to an integer.
+// value when converting a float (7.2 digit precision) to an integer.
#define MAX_LINE_NUMBER 10000000
#define MAX_TOOL_NUMBER 4294967294 // Limited by max unsigned 32-bit value - 1
@@ -149,6 +149,14 @@ parser_state_t *gc_get_state (void)
return &gc_state;
}
+static void set_spindle_override (spindle_t *spindle, bool disable)
+{
+ if(spindle->hal && spindle->hal->param->state.override_disable != disable) {
+ if((spindle->state.override_disable = spindle->hal->param->state.override_disable = disable))
+ spindle_set_override(gc_state.spindle->hal, DEFAULT_SPINDLE_RPM_OVERRIDE);
+ }
+}
+
static void set_scaling (float factor)
{
uint_fast8_t idx = N_AXIS;
@@ -299,7 +307,14 @@ void gc_init (void)
// Load default override status
gc_state.modal.override_ctrl = sys.override.control;
- gc_state.spindle.hal = spindle_get(0);
+
+#if N_SYS_SPINDLE > 1
+ gc_state.spindle = &gc_state.modal.spindle[0];
+ gc_state.modal.spindle[0].hal = spindle_get(0);
+#else
+ gc_state.spindle = &gc_state.modal.spindle;
+ gc_state.modal.spindle.hal = spindle_get(0);
+#endif
set_scaling(1.0f);
@@ -343,10 +358,25 @@ bool gc_laser_ppi_enable (uint_fast16_t ppi, uint_fast16_t pulse_length)
return grbl.on_laser_ppi_enable && grbl.on_laser_ppi_enable(ppi, pulse_length);
}
+spindle_t *gc_spindle_get (spindle_num_t spindle)
+{
+#if N_SYS_SPINDLE > 1
+ return spindle < 0 ? gc_state.spindle : &gc_state.modal.spindle[spindle];
+#else
+ return &gc_state.modal.spindle;
+#endif
+}
+
void gc_spindle_off (void)
{
- gc_state.spindle.rpm = 0.0f;
- gc_state.modal.spindle.state.value = 0;
+#if N_SYS_SPINDLE > 1
+ uint_fast8_t idx;
+ for(idx = 0; idx < N_SYS_SPINDLE; idx++) {
+ memset(&gc_state.modal.spindle[idx], 0, offsetof(spindle_t, hal));
+ }
+#else
+ memset(&gc_state.modal.spindle, 0, offsetof(spindle_t, hal));
+#endif
spindle_all_off();
system_add_rt_report(Report_Spindle);
@@ -359,11 +389,6 @@ void gc_coolant (coolant_state_t state)
system_add_rt_report(Report_Coolant);
}
-spindle_ptrs_t *gc_spindle_get (void)
-{
- return gc_state.spindle.hal;
-}
-
static void add_offset (void)
{
gc_state.offset_id = (gc_state.offset_id + 1) & (MAX_OFFSET_ENTRIES - 1);
@@ -655,12 +680,23 @@ bool gc_modal_state_restore (gc_modal_t *copy)
delay_sec(settings.safety_door.coolant_on_delay, DelayMode_SysSuspend);
}
- if(copy->spindle.state.value != gc_state.modal.spindle.state.value || copy->rpm != gc_state.modal.rpm)
- spindle_restore(gc_state.spindle.hal, copy->spindle.state, copy->rpm);
+#if N_SYS_SPINDLE > 1
+ uint_fast8_t idx = N_SYS_SPINDLE;
+ spindle_t *spindle, *spindle_copy;
+ do {
+ if((spindle = &gc_state.modal.spindle[--idx])->hal) {
+ spindle_copy = ©->spindle[idx];
+ if(!memcmp(spindle_copy, spindle, offsetof(spindle_t, hal)))
+ spindle_restore(spindle->hal, spindle_copy->state, spindle_copy->rpm);
+ }
+ } while(idx);
+#else
+ if(!memcmp(©->spindle, &gc_state.modal.spindle, offsetof(spindle_t, hal)))
+ spindle_restore(gc_state.modal.spindle.hal, copy->spindle.state, copy->spindle.rpm);
+#endif
memcpy(&gc_state.modal, copy, sizeof(gc_modal_t));
- gc_state.spindle.rpm = gc_state.modal.rpm;
gc_state.feed_rate = gc_state.modal.feed_rate;
}
@@ -713,8 +749,6 @@ char *gc_normalize_block (char *block, char **message)
*s1 = '\0';
if(!hal.driver_cap.no_gcode_message_handling) {
- size_t len = s1 - comment - 4;
-
if(message && *message == NULL) {
#if NGC_EXPRESSIONS_ENABLE
if(!strncmp(comment, "(DEBUG,", 7)) { // Debug message string substitution
@@ -733,6 +767,8 @@ char *gc_normalize_block (char *block, char **message)
}
}
#else
+ size_t len = s1 - comment - 4;
+
if(!strncmp(comment, "(MSG,", 5) && (*message = malloc(len))) {
comment += 5;
@@ -937,11 +973,12 @@ status_code_t gc_execute_block (char *block)
bool set_tool = false, spindle_event = false;
axis_command_t axis_command = AxisCommand_None;
io_mcode_t port_command = (io_mcode_t)0;
+ spindle_t *sspindle = gc_state.spindle;
plane_t plane;
// Initialize bitflag tracking variables for axis indices compatible operations.
- axes_signals_t axis_words = {0}; // XYZ tracking
- ijk_words_t ijk_words = {0}; // IJK tracking
+ axes_signals_t axis_words = {0}; // XYZ tracking
+ ijk_words_t ijk_words = {0}; // IJK tracking
// Initialize command and value words and parser flags variables.
modal_groups_t command_words = {0}; // Bitfield for tracking G and M command words. Also used for modal group violations.
@@ -954,7 +991,7 @@ status_code_t gc_execute_block (char *block)
gc_parser_flags.jog_motion = On;
gc_block.modal.motion = MotionMode_Linear;
gc_block.modal.feed_mode = FeedMode_UnitsPerMin;
- gc_block.modal.spindle.rpm_mode = SpindleSpeedMode_RPM;
+ gc_block.spindle_modal.rpm_mode = SpindleSpeedMode_RPM;
gc_block.values.n = JOG_LINE_NUMBER; // Initialize default line number reported during jog.
}
@@ -1275,7 +1312,7 @@ status_code_t gc_execute_block (char *block)
case 96: case 97:
if(settings.mode == Mode_Lathe) {
word_bit.modal_group.G14 = On;
- gc_block.modal.spindle.rpm_mode = (spindle_rpm_mode_t)((int_value - 96) ^ 1);
+ gc_block.spindle_modal.rpm_mode = (spindle_rpm_mode_t)((int_value - 96) ^ 1);
} else
FAIL(Status_GcodeUnsupportedCommand);
break;
@@ -1346,9 +1383,9 @@ status_code_t gc_execute_block (char *block)
case 3: case 4: case 5:
word_bit.modal_group.M7 = On;
- gc_block.modal.spindle.state.on = !(int_value == 5);
- gc_block.modal.spindle.state.ccw = int_value == 4;
- sys.override_delay.spindle = On;
+ gc_block.spindle_modal.state.on = !(int_value == 5);
+ gc_block.spindle_modal.state.ccw = int_value == 4;
+// sys.override_delay.spindle = On; TODO: only when spindle sync?
break;
case 6:
@@ -1362,7 +1399,7 @@ status_code_t gc_execute_block (char *block)
case 7: case 8: case 9:
word_bit.modal_group.M8 = On;
- sys.override_delay.coolant = On;
+// sys.override_delay.coolant = On; TODO: ?
gc_parser_flags.set_coolant = On;
switch(int_value) {
@@ -1757,6 +1794,10 @@ status_code_t gc_execute_block (char *block)
// [0. Non-specific/common error-checks and miscellaneous setup]:
+ // If a G65 block remove axis and ijk words flags since values are to be passed unmodified.
+ if(word_bit.modal_group.G0 && gc_block.non_modal_command == NonModal_MacroCall)
+ axis_words.mask = ijk_words.mask = 0;
+
// Determine implicit axis command conditions. Axis words have been passed, but no explicit axis
// command has been sent. If so, set axis command to current motion mode.
if (axis_words.mask && !axis_command)
@@ -1872,55 +1913,65 @@ status_code_t gc_execute_block (char *block)
(command_words.G0 && (gc_block.modal.motion == MotionMode_SpindleSynchronized ||
gc_block.modal.motion == MotionMode_RigidTapping ||
gc_block.modal.motion == MotionMode_Threading)) ||
- command_words.G14 ||
- (command_words.M9 && gc_block.override_command == Override_SpindleSpeed);
+ (command_words.G5 && gc_block.modal.feed_mode == FeedMode_UnitsPerRev) ||
+ command_words.G14 ||
+ (command_words.M9 && gc_block.override_command == Override_SpindleSpeed);
if(command_words.M7 || single_spindle_only) {
if(gc_block.values.$ < (single_spindle_only ? 0 : -1))
FAIL(single_spindle_only ? Status_NegativeValue : Status_GcodeValueOutOfRange);
- if(!spindle_is_enabled(gc_block.values.$))
+#if N_SYS_SPINDLE > 1
+ if(gc_block.values.$ < 0)
+ sspindle = NULL;
+ else {
+ if(!spindle_is_enabled(gc_block.values.$))
+ FAIL(Status_GcodeValueOutOfRange);
+ if(gc_state.modal.spindle[gc_block.values.$].hal == NULL)
+ gc_state.modal.spindle[gc_block.values.$].hal = spindle_get(gc_block.values.$);
+ sspindle = &gc_state.modal.spindle[gc_block.values.$];
+ }
+#else
+ if(gc_block.values.$ > 0)
FAIL(Status_GcodeValueOutOfRange);
- if(gc_block.values.$ >= 0)
- gc_state.spindle.hal = gc_block.spindle = spindle_get(gc_block.values.$);
+#endif
gc_block.words.$ = Off;
}
- } else if(gc_block.spindle == NULL)
- gc_block.spindle = gc_state.spindle.hal;
+ }
- if(gc_block.modal.feed_mode == FeedMode_UnitsPerRev && !gc_state.spindle.hal->get_data)
+ if(gc_block.modal.feed_mode == FeedMode_UnitsPerRev && (sspindle == NULL || !sspindle->hal->get_data))
FAIL(Status_GcodeUnsupportedCommand); // [G95 not supported]
- if (command_words.G14) {
- if(gc_block.modal.spindle.rpm_mode == SpindleSpeedMode_CSS) {
- if(!gc_state.spindle.hal->cap.variable)
+ if(command_words.G14) {
+ if(gc_block.spindle_modal.rpm_mode == SpindleSpeedMode_CSS) {
+ if(!sspindle->hal->cap.variable)
FAIL(Status_GcodeUnsupportedCommand);
- if (!gc_block.words.s) // TODO: add check for S0?
+ if(!gc_block.words.s) // TODO: add check for S0?
FAIL(Status_GcodeValueWordMissing);
// see below!! gc_block.values.s *= (gc_block.modal.units_imperial ? MM_PER_INCH * 12.0f : 1000.0f); // convert surface speed to mm/min
- if (gc_block.words.d) {
- gc_state.spindle.hal->param->css.max_rpm = min(gc_block.values.d, gc_state.spindle.hal->rpm_max);
+ if(gc_block.words.d) {
+ sspindle->hal->param->css.max_rpm = min(gc_block.values.d, sspindle->hal->rpm_max);
gc_block.words.d = Off;
} else
- gc_state.spindle.hal->param->css.max_rpm = gc_state.spindle.hal->rpm_max;
- } else if(gc_state.modal.spindle.rpm_mode == SpindleSpeedMode_CSS) {
- if(gc_state.spindle.css) {
- gc_state.spindle.css = NULL;
+ sspindle->hal->param->css.max_rpm = sspindle->hal->rpm_max;
+ } else if(sspindle->rpm_mode == SpindleSpeedMode_CSS) {
+ if(sspindle->css) {
+ sspindle->css = NULL;
protocol_buffer_synchronize(); // Empty planner buffer to ensure we get RPM at end of last CSS motion
}
- gc_state.spindle.rpm = gc_state.spindle.hal->param->rpm; // Is it correct to restore latest spindle RPM here?
+ sspindle->rpm = sspindle->hal->param->rpm; // Is it correct to restore latest spindle RPM here?
}
- gc_state.modal.spindle.rpm_mode = gc_block.modal.spindle.rpm_mode;
- }
+ sspindle->rpm_mode = gc_block.spindle_modal.rpm_mode;
+ } else if(sspindle)
+ gc_block.spindle_modal.rpm_mode = sspindle->rpm_mode;
- spindle_event = gc_block.words.s;
-
- if(!gc_block.words.s)
- gc_block.values.s = gc_state.modal.spindle.rpm_mode == SpindleSpeedMode_RPM ? gc_state.spindle.rpm : gc_state.spindle.hal->param->css.max_rpm;
- else if(gc_state.modal.spindle.rpm_mode == SpindleSpeedMode_CSS) {
- // Unsure what to do about S values when in SpindleSpeedMode_CSS - ignore? For now use it to (re)calculate surface speed.
- // Reinsert commented out code above if this is removed!!
- gc_block.values.s *= (gc_block.modal.units_imperial ? MM_PER_INCH * 12.0f : 1000.0f); // convert surface speed to mm/min
- gc_state.spindle.hal->param->css.surface_speed = gc_block.values.s;
- }
+ if((spindle_event = gc_block.words.s)) {
+ if(sspindle->rpm_mode == SpindleSpeedMode_CSS) {
+ // Unsure what to do about S values when in SpindleSpeedMode_CSS - ignore? For now use it to (re)calculate surface speed.
+ // Reinsert commented out code above if this is removed!!
+ gc_block.values.s *= (gc_block.modal.units_imperial ? MM_PER_INCH * 12.0f : 1000.0f); // convert surface speed to mm/min
+ sspindle->hal->param->css.surface_speed = gc_block.values.s;
+ }
+ } else if(sspindle)
+ gc_block.values.s = sspindle->rpm_mode == SpindleSpeedMode_RPM ? sspindle->rpm : sspindle->hal->param->css.max_rpm;
// bit_false(gc_block.words,bit(Word_S)); // NOTE: Single-meaning value word. Set at end of error-checking.
@@ -1950,7 +2001,7 @@ status_code_t gc_execute_block (char *block)
} else if(!gc_block.words.t)
gc_block.values.t = gc_state.tool_pending;
- if(command_words.M10 && port_command) {
+ if(command_words.M5 && port_command) {
switch(port_command) {
@@ -2025,18 +2076,24 @@ status_code_t gc_execute_block (char *block)
// [6. Change tool ]: N/A
// [7. Spindle control ]:
- if(command_words.M7 && gc_block.modal.spindle.state.ccw) {
- // Check if spindle(s) support reversing direction
- if(gc_block.spindle == NULL) {
- uint_fast8_t idx = N_SYS_SPINDLE;
- do {
- idx--;
- if(spindle_is_enabled(idx) && !(spindle_get(idx)->cap.direction || spindle_get(idx)->cap.laser))
- FAIL(Status_GcodeUnsupportedCommand);
- } while(idx);
- } else if(!(gc_block.spindle->cap.direction || gc_block.spindle->cap.laser))
- FAIL(Status_GcodeUnsupportedCommand);
- }
+ if(command_words.M7) {
+ if(gc_block.spindle_modal.state.ccw) {
+ // Check if spindle(s) support reversing direction
+#if N_SYS_SPINDLE > 1
+ if(sspindle == NULL) {
+ uint_fast8_t idx = N_SYS_SPINDLE;
+ do {
+ idx--;
+ if(gc_state.modal.spindle[idx].hal && !(gc_state.modal.spindle[idx].hal->cap.direction || gc_state.modal.spindle[idx].hal->cap.laser))
+ FAIL(Status_GcodeUnsupportedCommand);
+ } while(idx);
+ } else
+#endif
+ if(!(sspindle->hal->cap.direction || sspindle->hal->cap.laser))
+ FAIL(Status_GcodeUnsupportedCommand);
+ }
+ } else if(sspindle)
+ gc_block.spindle_modal.state = sspindle->state;
// [8. Coolant control ]: N/A
@@ -2585,13 +2642,13 @@ status_code_t gc_execute_block (char *block)
gc_block.modal.retract_mode = CCRetractMode_Previous;
// Initial(?) check for spindle running for moves in G96 mode
- if(gc_block.modal.spindle.rpm_mode == SpindleSpeedMode_CSS && (!gc_block.modal.spindle.state.on || gc_block.values.s == 0.0f))
+ if(gc_block.spindle_modal.rpm_mode == SpindleSpeedMode_CSS && (!gc_block.spindle_modal.state.on || gc_block.values.s == 0.0f))
FAIL(Status_GcodeSpindleNotRunning);
// Check if feed rate is defined for the motion modes that require it.
- if (gc_block.modal.motion == MotionMode_SpindleSynchronized) {
+ if(gc_block.modal.motion == MotionMode_SpindleSynchronized) {
- if(!gc_state.spindle.hal->get_data)
+ if(!sspindle->hal->get_data)
FAIL(Status_GcodeUnsupportedCommand); // [G33, G33.1]
if(gc_block.values.k == 0.0f)
@@ -2600,11 +2657,11 @@ status_code_t gc_execute_block (char *block)
// Ensure spindle speed is at 100% - any override will be disabled on execute.
gc_parser_flags.spindle_force_sync = On;
- } else if (gc_block.modal.motion == MotionMode_Threading) {
+ } else if(gc_block.modal.motion == MotionMode_Threading) {
// Fail if cutter radius comp is active
- if(!gc_state.spindle.hal->get_data)
+ if(!sspindle->hal->get_data)
FAIL(Status_GcodeUnsupportedCommand); // [G76 not supported]
if(gc_block.modal.plane_select != PlaneSelect_ZX)
@@ -2628,7 +2685,7 @@ status_code_t gc_execute_block (char *block)
(gc_block.words.l && (gc_taper_type)gc_block.values.l > Taper_Both))
FAIL(Status_GcodeValueOutOfRange);
- if(gc_state.spindle.rpm < gc_state.spindle.hal->rpm_min || gc_state.spindle.rpm > gc_state.spindle.hal->rpm_max)
+ if(sspindle->rpm < sspindle->hal->rpm_min || sspindle->rpm > sspindle->hal->rpm_max)
FAIL(Status_GcodeRPMOutOfRange);
if(gc_block.modal.motion != gc_state.modal.motion) {
@@ -3113,30 +3170,35 @@ status_code_t gc_execute_block (char *block)
// NOTE: G-code parser state is not updated, except the position to ensure sequential jog
// targets are computed correctly. The final parser position after a jog is updated in
// protocol_execute_realtime() when jogging completes or is canceled.
- if (gc_parser_flags.jog_motion) {
+ if(gc_parser_flags.jog_motion) {
// Only distance and unit modal commands and G53 absolute override command are allowed.
// NOTE: Feed rate word and axis word checks have already been performed in STEP 3.
- if (command_words.mask & ~jog_groups.mask)
+ if(command_words.mask & ~jog_groups.mask)
FAIL(Status_InvalidJogCommand);
- if (!(gc_block.non_modal_command == NonModal_AbsoluteOverride || gc_block.non_modal_command == NonModal_NoAction))
+ if(!(gc_block.non_modal_command == NonModal_AbsoluteOverride || gc_block.non_modal_command == NonModal_NoAction))
FAIL(Status_InvalidJogCommand);
+#if N_SYS_SPINDLE > 1
+ spindle_t *spindle = sspindle ? sspindle : gc_state.modal.spindle;
+#else
+ spindle_t *spindle = &gc_block.modal.spindle;
+#endif
+
// Initialize planner data to current spindle and coolant modal state.
- memcpy(&plan_data.spindle, &gc_state.spindle, sizeof(spindle_t));
- plan_data.spindle.state = gc_state.modal.spindle.state;
+ memcpy(&plan_data.spindle, spindle, sizeof(spindle_t));
plan_data.condition.coolant = gc_state.modal.coolant;
- plan_data.condition.is_rpm_rate_adjusted = gc_state.is_rpm_rate_adjusted || (gc_state.modal.spindle.state.ccw && gc_state.spindle.hal->cap.laser);
+ plan_data.condition.is_rpm_rate_adjusted = gc_state.is_rpm_rate_adjusted || (spindle->state.ccw && spindle->hal->cap.laser);
- if ((status_code_t)(int_value = (uint_fast16_t)mc_jog_execute(&plan_data, &gc_block, gc_state.position)) == Status_OK)
+ if((status_code_t)(int_value = (uint_fast16_t)mc_jog_execute(&plan_data, &gc_block, gc_state.position)) == Status_OK)
memcpy(gc_state.position, gc_block.values.xyz, sizeof(gc_state.position));
return (status_code_t)int_value;
}
// If in laser mode, setup laser power based on current and past parser conditions.
- if(gc_state.spindle.hal->cap.laser) {
+ if(sspindle && sspindle->hal->cap.laser) {
if(!motion_is_lasercut(gc_block.modal.motion))
gc_parser_flags.laser_disable = On;
@@ -3146,7 +3208,7 @@ status_code_t gc_execute_block (char *block)
// TODO: Check sync conditions for M3 enabled motions that don't enter the planner. (zero length).
if(axis_words.mask && (axis_command == AxisCommand_MotionMode))
gc_parser_flags.laser_is_motion = On;
- else if(gc_state.modal.spindle.state.on && !gc_state.modal.spindle.state.ccw) {
+ else if(sspindle->state.on && !sspindle->state.ccw) {
// M3 constant power laser requires planner syncs to update the laser when changing between
// a G1/2/3 motion mode state and vice versa when there is no motion in the line.
if(motion_is_lasercut(gc_state.modal.motion)) {
@@ -3156,7 +3218,7 @@ status_code_t gc_execute_block (char *block)
gc_parser_flags.spindle_force_sync = On;
}
- gc_state.is_rpm_rate_adjusted = gc_state.modal.spindle.state.ccw && !gc_parser_flags.laser_disable;
+ gc_state.is_rpm_rate_adjusted = sspindle->state.ccw && !gc_parser_flags.laser_disable;
}
// [0. Non-specific/common error-checks and miscellaneous setup]:
@@ -3180,42 +3242,40 @@ status_code_t gc_execute_block (char *block)
plan_data.feed_rate = gc_state.feed_rate; // Record data for planner use.
// [4. Set spindle speed ]:
- if(gc_state.modal.spindle.rpm_mode == SpindleSpeedMode_CSS) {
+
+#if N_SYS_SPINDLE > 1
+ if(sspindle) {
+#endif // N_SYS_SPINDLE > 1
+
+ if(sspindle->rpm_mode == SpindleSpeedMode_CSS) {
if(gc_block.modal.motion != MotionMode_None && gc_block.modal.motion != MotionMode_Seek) {
- gc_state.spindle.css = &gc_state.spindle.hal->param->css;
- gc_state.spindle.css->axis = plane.axis_1;
- gc_state.spindle.css->tool_offset = gc_get_offset(gc_state.spindle.css->axis, false);
- float pos = gc_state.position[gc_state.spindle.css->axis] - gc_state.spindle.css->tool_offset;
- gc_block.values.s = pos <= 0.0f ? gc_state.spindle.css->max_rpm : min(gc_state.spindle.css->max_rpm, gc_state.spindle.css->surface_speed / (pos * (float)(2.0f * M_PI)));
+ sspindle->css = &sspindle->hal->param->css;
+ sspindle->css->axis = plane.axis_1;
+ sspindle->css->tool_offset = gc_get_offset(plane.axis_1, false);
+ float pos = gc_state.position[plane.axis_1] - sspindle->css->tool_offset;
+ gc_block.values.s = pos <= 0.0f ? sspindle->css->max_rpm : min(sspindle->css->max_rpm, sspindle->css->surface_speed / (pos * (float)(2.0f * M_PI)));
//?? gc_parser_flags.spindle_force_sync = On;
} else {
- if(gc_state.spindle.css) {
- gc_state.spindle.css = NULL;
+ if(sspindle->css) {
+ sspindle->css = NULL;
protocol_buffer_synchronize(); // Empty planner buffer to ensure we get RPM at end of last CSS motion
}
- gc_block.values.s = gc_state.spindle.rpm; //gc_state.spindle.hal->param->rpm; // Keep current RPM
+ gc_block.values.s = sspindle->rpm; //sspindle.hal->param->rpm; // Keep current RPM
}
}
- if(gc_state.spindle.rpm != gc_block.values.s || gc_parser_flags.spindle_force_sync) {
- if(gc_state.modal.spindle.state.on && !gc_parser_flags.laser_is_motion) {
- if(gc_block.spindle) {
- gc_block.spindle->param->rpm = gc_block.values.s;
- spindle_sync(gc_block.spindle, gc_state.modal.spindle.state, gc_parser_flags.laser_disable ? 0.0f : gc_block.values.s);
- }
- // else... - setting the same rpm for multiple spindles at once is not allowed!
+ if(sspindle->rpm != gc_block.values.s || gc_parser_flags.spindle_force_sync) {
+ if(sspindle->state.on && !gc_parser_flags.laser_is_motion) {
+ sspindle->hal->param->rpm = gc_block.values.s;
+ spindle_sync(sspindle->hal, sspindle->state, gc_parser_flags.laser_disable ? 0.0f : gc_block.values.s);
}
- gc_state.spindle.rpm = gc_block.values.s; // Update spindle speed state.
- }
-
- // NOTE: Pass zero spindle speed for all restricted laser motions.
- if (!gc_parser_flags.laser_disable)
- memcpy(&plan_data.spindle, &gc_state.spindle, sizeof(spindle_t)); // Record data for planner use.
- else {
- plan_data.spindle.hal = gc_state.spindle.hal;
- // plan_data.spindle.speed = 0.0f; // Initialized as zero already.
+ sspindle->rpm = gc_block.values.s; // Update spindle speed state.
}
+#if N_SYS_SPINDLE > 1
+ }
+#endif
+ //
// [5. Select tool ]: Only tracks tool value if ATC or manual tool change is not possible.
if(gc_state.tool_pending != gc_block.values.t && !check_mode) {
@@ -3228,12 +3288,14 @@ status_code_t gc_execute_block (char *block)
if(grbl.on_tool_selected) {
- spindle_state_t state = gc_state.modal.spindle.state;
+ spindle_state_t state = sspindle ? sspindle->state : (spindle_state_t){0};
- grbl.on_tool_selected(gc_state.tool);
+ grbl.on_tool_selected(pending_tool);
- if(state.value != gc_state.modal.spindle.state.value)
- gc_block.modal.spindle.state = gc_state.modal.spindle.state;
+ if(sspindle && state.value != sspindle->state.value) {
+ command_words.M7 = On;
+ gc_block.spindle_modal.state = sspindle->state;
+ }
}
if(grbl.on_tool_changed)
@@ -3281,7 +3343,7 @@ status_code_t gc_execute_block (char *block)
}
// [6. Change tool ]: Delegated to (possible) driver implementation
- if (command_words.M6 && !set_tool && !check_mode) {
+ if(command_words.M6 && !set_tool && !check_mode) {
tool_data_t *pending_tool = tool_get_pending(gc_state.tool_pending);
@@ -3296,12 +3358,14 @@ status_code_t gc_execute_block (char *block)
if(grbl.on_tool_selected) {
- spindle_state_t state = gc_state.modal.spindle.state;
+ spindle_state_t state = sspindle ? sspindle->state : (spindle_state_t){0};
grbl.on_tool_selected(pending_tool);
- if(state.value != gc_state.modal.spindle.state.value)
- gc_block.modal.spindle.state = gc_state.modal.spindle.state;
+ if(sspindle && state.value != sspindle->state.value) {
+ command_words.M7 = On;
+ gc_block.spindle_modal.state = sspindle->state;
+ }
}
if(hal.tool.change) { // ATC
@@ -3334,40 +3398,72 @@ status_code_t gc_execute_block (char *block)
}
// [7. Spindle control ]:
- if(gc_state.modal.spindle.state.value != gc_block.modal.spindle.state.value) {
- // Update spindle control and apply spindle speed when enabling it in this block.
- // NOTE: All spindle state changes are synced, even in laser mode. Also, plan_data,
- // rather than gc_state, is used to manage laser state for non-laser motions.
- bool spindle_ok = false;
- if(gc_block.spindle) {
- if(grbl.on_spindle_programmed)
- grbl.on_spindle_programmed(gc_block.spindle, gc_block.modal.spindle.state, plan_data.spindle.rpm, gc_block.modal.spindle.rpm_mode);
- if((spindle_ok = spindle_sync(gc_block.spindle, gc_block.modal.spindle.state, plan_data.spindle.rpm)))
- gc_block.spindle->param->state = gc_block.modal.spindle.state;
- } else {
+ // Update spindle control and apply spindle speed when enabling it in this block.
+ // NOTE: All spindle state changes are synced, even in laser mode. Also, plan_data,
+ // rather than gc_state, is used to manage laser state for non-laser motions.
+ if(command_words.M7) {
+
+ bool spindle_ok;
+
+#if N_SYS_SPINDLE > 1
+
+ if(sspindle == NULL) {
+
idx = N_SYS_SPINDLE;
do {
- if(spindle_is_enabled(--idx)) {
- spindle_ptrs_t *spindle = spindle_get(idx);
- if(grbl.on_spindle_programmed)
- grbl.on_spindle_programmed(spindle, gc_block.modal.spindle.state, plan_data.spindle.rpm, gc_block.modal.spindle.rpm_mode);
- if(spindle_sync(spindle, gc_block.modal.spindle.state, plan_data.spindle.rpm))
- spindle->param->state = gc_block.modal.spindle.state;
- else
- spindle_ok = false;
+ spindle_t *sys_spindle = &gc_state.modal.spindle[--idx];
+ if(sys_spindle->hal) {
+
+ if((spindle_ok = sys_spindle->state.value != gc_block.spindle_modal.state.value)) {
+
+ if(grbl.on_spindle_programmed)
+ grbl.on_spindle_programmed(sys_spindle->hal, gc_block.spindle_modal.state, sys_spindle->rpm, sys_spindle->rpm_mode);
+
+ if((spindle_ok = spindle_sync(sys_spindle->hal, gc_block.spindle_modal.state, sys_spindle->rpm))) {
+ if((sys_spindle->state = sys_spindle->hal->param->state = gc_block.spindle_modal.state).on)
+ sspindle = sys_spindle;
+ }
+ }
+
+ if((spindle_ok ? false : (!spindle_ok || spindle_event)) && grbl.on_spindle_programmed)
+ grbl.on_spindle_programmed(sys_spindle->hal, sys_spindle->state, sys_spindle->rpm, sys_spindle->rpm_mode);
}
} while(idx);
+
+ spindle_event = false;
+
+ } else
+
+#endif // N_SYS_SPINDLE > 1
+
+ if((spindle_ok = sspindle->state.value != gc_block.spindle_modal.state.value)) {
+
+ if(grbl.on_spindle_programmed)
+ grbl.on_spindle_programmed(sspindle->hal, gc_block.spindle_modal.state, sspindle->rpm, sspindle->rpm_mode);
+
+ if((spindle_ok = spindle_sync(sspindle->hal, gc_block.spindle_modal.state, sspindle->rpm)))
+ sspindle->state = sspindle->hal->param->state = gc_block.spindle_modal.state;
+
+ spindle_event = !spindle_ok;
}
- if(!(spindle_event = !spindle_ok))
- gc_state.modal.spindle.state = gc_block.modal.spindle.state;
+
+ if(spindle_event && grbl.on_spindle_programmed)
+ grbl.on_spindle_programmed(sspindle->hal, sspindle->state, sspindle->rpm, sspindle->rpm_mode);
}
- if(spindle_event && grbl.on_spindle_programmed)
- grbl.on_spindle_programmed(gc_state.spindle.hal, gc_state.modal.spindle.state, gc_state.spindle.rpm, gc_state.modal.spindle.rpm_mode);
+ if(sspindle != NULL)
+ gc_state.spindle = sspindle; // for now
+ // NOTE: Pass zero spindle speed for all restricted laser motions.
+ if(!gc_parser_flags.laser_disable)
+ memcpy(&plan_data.spindle, gc_state.spindle, sizeof(spindle_t)); // Record data for planner use.
+ else {
+ plan_data.spindle.hal = gc_state.spindle->hal;
+ // plan_data.spindle.speed = 0.0f; // Initialized as zero already.
+ }
// TODO: Recheck spindle running in CCS mode (is_rpm_pos_adjusted == On)?
- plan_data.spindle.state = gc_state.modal.spindle.state; // Set condition flag for planner use.
+ plan_data.spindle.state = gc_state.spindle->state; // Set condition flag for planner use.
plan_data.condition.is_rpm_rate_adjusted = gc_state.is_rpm_rate_adjusted;
plan_data.condition.is_laser_ppi_mode = gc_state.is_rpm_rate_adjusted && gc_state.is_laser_ppi_mode;
@@ -3378,7 +3474,6 @@ status_code_t gc_execute_block (char *block)
case ModalState_Save:
case ModalState_SaveAutoRestore:
- gc_state.modal.rpm = gc_state.spindle.rpm;
gc_state.modal.feed_rate = gc_state.feed_rate;
if(!ngc_modal_state_save(&gc_state.modal, gc_block.state_action == ModalState_SaveAutoRestore))
FAIL(Status_FlowControlOutOfMemory); // [Out of memory] TODO: allocate memory during validation? Static allocation?
@@ -3411,17 +3506,24 @@ status_code_t gc_execute_block (char *block)
sys.override_delay.flags = 0;
// [9. Override control ]:
- if (gc_state.modal.override_ctrl.value != gc_block.modal.override_ctrl.value) {
+ if(command_words.M9 && gc_state.modal.override_ctrl.value != gc_block.modal.override_ctrl.value) {
gc_state.modal.override_ctrl = gc_block.modal.override_ctrl;
- gc_state.modal.spindle.state.override_disable = gc_state.spindle.hal->param->state.override_disable = gc_state.modal.override_ctrl.spindle_rpm_disable;
+
+#if N_SYS_SPINDLE > 1
+ if(sspindle == NULL) {
+ uint_fast8_t idx = N_SYS_SPINDLE;
+ do {
+ set_spindle_override(&gc_state.modal.spindle[--idx], gc_state.modal.override_ctrl.spindle_rpm_disable);
+ } while(idx);
+ } else
+#else
+ set_spindle_override(sspindle, gc_state.modal.override_ctrl.spindle_rpm_disable);
+#endif
if(gc_state.modal.override_ctrl.feed_rate_disable)
plan_feed_override(0, 0);
- if(gc_state.modal.override_ctrl.spindle_rpm_disable)
- spindle_set_override(gc_state.spindle.hal, DEFAULT_SPINDLE_RPM_OVERRIDE);
-
mc_override_ctrl_update(gc_state.modal.override_ctrl); // NOTE: must be called last!
}
@@ -3841,7 +3943,6 @@ status_code_t gc_execute_block (char *block)
gc_block.modal.canned_cycle_active = false;
gc_state.modal.plane_select = PlaneSelect_XY;
// gc_state.modal.plane_select = settings.flags.lathe_mode ? PlaneSelect_ZX : PlaneSelect_XY;
- gc_state.modal.spindle.rpm_mode = SpindleSpeedMode_RPM; // NOTE: not compliant with linuxcnc (?)
gc_state.modal.distance_incremental = false;
gc_state.modal.feed_mode = FeedMode_UnitsPerMin;
// TODO: check gc_state.distance_per_rev = 0.0f;
@@ -3850,20 +3951,32 @@ status_code_t gc_execute_block (char *block)
gc_state.modal.coord_system.id = CoordinateSystem_G54;
system_add_rt_report(Report_GWCO);
}
- gc_state.modal.spindle.state = (spindle_state_t){0};
gc_state.modal.coolant = (coolant_state_t){0};
gc_state.modal.override_ctrl.feed_rate_disable = Off;
gc_state.modal.override_ctrl.spindle_rpm_disable = Off;
+#if N_SYS_SPINDLE > 1
+
idx = N_SYS_SPINDLE;
- spindle_ptrs_t *spindle;
+ spindle_t *spindle;
do {
- if((spindle = spindle_get(--idx))) {
- spindle->param->state.override_disable = Off;
+ if((spindle = &gc_state.modal.spindle[--idx])) {
+ spindle->css = NULL;
+ spindle->state = (spindle_state_t){0};
+ spindle->rpm_mode = SpindleSpeedMode_RPM; // NOTE: not compliant with linuxcnc (?);
+ spindle->hal->param->state.override_disable = Off;
if(settings.flags.restore_overrides)
- spindle->param->override_pct = DEFAULT_SPINDLE_RPM_OVERRIDE;
+ spindle->hal->param->override_pct = DEFAULT_SPINDLE_RPM_OVERRIDE;
}
} while(idx);
+#else
+ gc_state.modal.spindle.css = NULL;
+ gc_state.modal.spindle.state = (spindle_state_t){0};
+ gc_state.modal.spindle.rpm_mode = SpindleSpeedMode_RPM; // NOTE: not compliant with linuxcnc (?)
+ gc_state.modal.spindle.hal->param->state.override_disable = Off;
+ if(settings.flags.restore_overrides)
+ sspindle->hal->param->override_pct = DEFAULT_SPINDLE_RPM_OVERRIDE;
+#endif
if(settings.parking.flags.enabled)
gc_state.modal.override_ctrl.parking_disable = settings.parking.flags.enable_override_control &&
diff --git a/gcode.h b/gcode.h
index cb5394c..274d41f 100644
--- a/gcode.h
+++ b/gcode.h
@@ -498,9 +498,17 @@ typedef struct {
} gc_value_ptr_t;
typedef struct {
+ float rpm; //!< Spindle speed
spindle_state_t state; //!< {M3,M4,M5}
spindle_rpm_mode_t rpm_mode; //!< {G96,G97}
-} spindle_mode_t;
+ spindle_css_data_t *css; //!< Data used for Constant Surface Speed Mode calculations
+ spindle_ptrs_t *hal; //!< Spindle function pointers etc. Must be last!
+} spindle_t;
+
+typedef struct {
+ spindle_state_t state; //!< {M3,M4,M5}
+ spindle_rpm_mode_t rpm_mode; //!< {G96,G97}
+} spindle_modal_t;
// NOTE: When this struct is zeroed, the above defines set the defaults for the system.
typedef struct {
@@ -519,7 +527,11 @@ typedef struct {
#endif
program_flow_t program_flow; //!< {M0,M1,M2,M30,M60}
coolant_state_t coolant; //!< {M7,M8,M9}
- spindle_mode_t spindle; //!< {M3,M4,M5 and G96,G97}
+#if N_SYS_SPINDLE > 1
+ spindle_t spindle[N_SYS_SPINDLE];
+#else
+ spindle_t spindle; //!< {M3,M4,M5 and G96,G97}
+#endif
gc_override_flags_t override_ctrl; //!< {M48,M49,M50,M51,M53,M56}
cc_retract_mode_t retract_mode; //!< {G98,G99}
bool scaling_active; //!< {G50,G51}
@@ -528,7 +540,6 @@ typedef struct {
#if NGC_PARAMETERS_ENABLE
bool auto_restore;
float feed_rate; //!< {F} NOTE: only set when saving modal state
- float rpm; //!< {S} NOTE: only set when saving modal state
#endif
} gc_modal_t;
@@ -575,20 +586,13 @@ typedef struct {
tool_id_t tool_id; //!< Tool number
} tool_data_t;
-typedef struct {
- float rpm; //!< Spindle speed
- spindle_state_t state;
- spindle_css_data_t *css; //!< Data used for Constant Surface Speed Mode calculations
- spindle_ptrs_t *hal;
-} spindle_t;
-
/*! \brief Parser state
*/
typedef struct {
gc_modal_t modal;
gc_canned_t canned;
- spindle_t spindle; //!< RPM
+ spindle_t *spindle; //!< Last referenced spindle
float feed_rate; //!< Millimeters/min
float distance_per_rev; //!< Millimeters/rev
float position[N_AXIS]; //!< Where the interpreter considers the tool to be at this point in the code
@@ -636,11 +640,11 @@ typedef struct {
user_mcode_t user_mcode; //!< Set > #UserMCode_Ignore if a user M-code is found.
bool user_mcode_sync; //!< Set to \a true by M-code validation handler if M-code is to be executed after synchronization.
gc_modal_t modal; //!< The current modal state is copied here before parsing starts.
+ spindle_modal_t spindle_modal;
gc_values_t values; //!< Parameter values for block.
parameter_words_t words; //!< Bitfield for tracking found parameter values.
output_command_t output_command; //!< Details about M62-M68 output command to execute if present in block.
uint32_t arc_turns; //
- spindle_ptrs_t *spindle; //!< Spindle to control, NULL for all
#if NGC_PARAMETERS_ENABLE
modal_state_action_t state_action; //!< M70-M73 modal state action
#endif
@@ -676,7 +680,7 @@ float *gc_get_scaling (void);
// Get current axis offset.
float gc_get_offset (uint_fast8_t idx, bool real_time);
-spindle_ptrs_t *gc_spindle_get (void);
+spindle_t *gc_spindle_get (spindle_num_t spindle);
void gc_spindle_off (void);
void gc_coolant (coolant_state_t state);
diff --git a/grbl.h b/grbl.h
index 4594567..d620c73 100644
--- a/grbl.h
+++ b/grbl.h
@@ -42,7 +42,7 @@
#else
#define GRBL_VERSION "1.1f"
#endif
-#define GRBL_BUILD 20240928
+#define GRBL_BUILD 20241006
#define GRBL_URL "https://github.com/grblHAL"
diff --git a/motion_control.c b/motion_control.c
index 29bbe45..715d810 100644
--- a/motion_control.c
+++ b/motion_control.c
@@ -627,7 +627,7 @@ void mc_canned_drill (motion_mode_t motion, float *target, plan_line_data_t *pl_
return;
if(canned->spindle_off)
- spindle_sync(pl_data->spindle.hal, gc_state.modal.spindle.state, pl_data->spindle.rpm);
+ spindle_sync(pl_data->spindle.hal, pl_data->spindle.state, pl_data->spindle.rpm);
}
pl_data->condition.rapid_motion = On; // Set rapid motion condition flag.
diff --git a/ngc_params.c b/ngc_params.c
index b78da3f..baa0c87 100644
--- a/ngc_params.c
+++ b/ngc_params.c
@@ -488,11 +488,11 @@ float ngc_named_param_get_by_id (ncg_name_param_id_t id)
break;
case NGCParam_spindle_rpm_mode:
- value = gc_state.modal.spindle.rpm_mode == SpindleSpeedMode_RPM ? 1.0f : 0.0f;
+ value = gc_spindle_get(0)->rpm_mode == SpindleSpeedMode_RPM ? 1.0f : 0.0f;
break;
case NGCParam_spindle_css_mode:
- value = gc_state.modal.spindle.rpm_mode == SpindleSpeedMode_CSS ? 1.0f : 0.0f;
+ value = gc_spindle_get(0)->rpm_mode == SpindleSpeedMode_CSS ? 1.0f : 0.0f;
break;
case NGCParam_ijk_absolute_mode:
@@ -508,11 +508,11 @@ float ngc_named_param_get_by_id (ncg_name_param_id_t id)
break;
case NGCParam_spindle_on:
- value = gc_state.modal.spindle.state.on ? 1.0f : 0.0f;
+ value = gc_spindle_get(0)->state.on ? 1.0f : 0.0f;
break;
case NGCParam_spindle_cw:
- value = gc_state.modal.spindle.state.ccw ? 1.0f : 0.0f;
+ value = gc_spindle_get(0)->state.ccw ? 1.0f : 0.0f;
break;
case NGCParam_mist:
@@ -544,7 +544,7 @@ float ngc_named_param_get_by_id (ncg_name_param_id_t id)
break;
case NGCParam_rpm:
- value = gc_state.spindle.rpm;
+ value = gc_spindle_get(0)->rpm;
break;
case NGCParam_x:
diff --git a/planner.c b/planner.c
index c220217..768c3a7 100644
--- a/planner.c
+++ b/planner.c
@@ -691,7 +691,7 @@ void plan_data_init (plan_line_data_t *plan_data)
{
memset(plan_data, 0, sizeof(plan_line_data_t));
plan_data->offset_id = gc_state.offset_id;
- plan_data->spindle.hal = gc_state.spindle.hal ? gc_state.spindle.hal : spindle_get(0);
+ plan_data->spindle.hal = gc_spindle_get(-1)->hal;
plan_data->condition.target_validated = plan_data->condition.target_valid = sys.soft_limits.mask == 0;
#ifdef KINEMATICS_API
plan_data->rate_multiplier = 1.0f;
diff --git a/protocol.c b/protocol.c
index 95fa75b..ccb92b1 100644
--- a/protocol.c
+++ b/protocol.c
@@ -566,7 +566,6 @@ bool protocol_exec_rt_system (void)
sys.override.control = gc_state.modal.override_ctrl;
gc_state.tool_change = false;
- gc_state.modal.spindle.rpm_mode = SpindleSpeedMode_RPM;
// Tell driver/plugins about reset.
hal.driver_reset();
@@ -684,7 +683,7 @@ bool protocol_exec_rt_system (void)
if(!sys.override_delay.spindle && (rt_exec = get_spindle_override())) {
bool spindle_stop = false;
- spindle_ptrs_t *spindle = gc_spindle_get();
+ spindle_ptrs_t *spindle = gc_spindle_get(-1)->hal;
override_t last_s_override = spindle->param->override_pct;
do {
@@ -727,7 +726,7 @@ bool protocol_exec_rt_system (void)
spindle_set_override(spindle, last_s_override);
- if (spindle_stop && state_get() == STATE_HOLD && gc_state.modal.spindle.state.on) {
+ if (spindle_stop && state_get() == STATE_HOLD && gc_spindle_get(-1)->state.on) {
// Spindle stop override allowed only while in HOLD state.
// NOTE: Report flag is set in spindle_set_state() when spindle stop is executed.
if (!sys.override.spindle_stop.value)
diff --git a/report.c b/report.c
index aaacf30..46ce07a 100644
--- a/report.c
+++ b/report.c
@@ -724,8 +724,8 @@ void report_gcode_modes (void)
hal.stream.write(" G");
hal.stream.write(uitoa((uint32_t)(93 + (gc_state.modal.feed_mode == FeedMode_UnitsPerRev ? 2 : gc_state.modal.feed_mode ^ 1))));
- if(settings.mode == Mode_Lathe && gc_spindle_get()->cap.variable)
- hal.stream.write(gc_state.modal.spindle.rpm_mode == SpindleSpeedMode_RPM ? " G97" : " G96");
+ if(settings.mode == Mode_Lathe && gc_spindle_get(0)->hal->cap.variable)
+ hal.stream.write(gc_spindle_get(0)->rpm_mode == SpindleSpeedMode_RPM ? " G97" : " G96");
#if COMPATIBILITY_LEVEL < 10
@@ -777,7 +777,7 @@ void report_gcode_modes (void)
}
}
- hal.stream.write(gc_state.modal.spindle.state.on ? (gc_state.modal.spindle.state.ccw ? " M4" : " M3") : " M5");
+ hal.stream.write(gc_spindle_get(0)->state.on ? (gc_spindle_get(0)->state.ccw ? " M4" : " M3") : " M5");
if(gc_state.tool_change)
hal.stream.write(" M6");
@@ -809,8 +809,8 @@ void report_gcode_modes (void)
hal.stream.write(appendbuf(2, " F", get_rate_value(gc_state.feed_rate)));
- if(gc_spindle_get()->cap.variable)
- hal.stream.write(appendbuf(2, " S", ftoa(gc_state.spindle.rpm, N_DECIMAL_RPMVALUE)));
+ if(gc_spindle_get(0)->hal->cap.variable)
+ hal.stream.write(appendbuf(2, " S", ftoa(gc_spindle_get(0)->rpm, N_DECIMAL_RPMVALUE)));
hal.stream.write("]" ASCII_EOL);
}
@@ -1450,12 +1450,13 @@ void report_realtime_status (void)
static gc_modal_t last_state;
static bool g92_active;
- bool is_changed = feed_rate != gc_state.feed_rate || spindle_rpm != gc_state.spindle.rpm || tool_id != gc_state.tool->tool_id;
+ spindle_t *spindle = gc_spindle_get(0);
+ bool is_changed = feed_rate != gc_state.feed_rate || spindle_rpm != spindle->rpm || tool_id != gc_state.tool->tool_id;
if(is_changed) {
feed_rate = gc_state.feed_rate;
tool_id = gc_state.tool->tool_id;
- spindle_rpm = gc_state.spindle.rpm;
+ spindle_rpm = spindle->rpm;
} else if ((is_changed = g92_active != is_g92_active()))
g92_active = !g92_active;
else if(memcmp(&last_state, &gc_state.modal, sizeof(gc_modal_t))) {
@@ -2199,12 +2200,12 @@ status_code_t report_current_home_signal_state (sys_state_t state, char *args)
// Prints spindle data (encoder pulse and index count, angular position).
status_code_t report_spindle_data (sys_state_t state, char *args)
{
- spindle_ptrs_t *spindle = gc_spindle_get();
+ spindle_t *spindle = gc_spindle_get(-1);
- if(spindle->get_data) {
+ if(spindle->hal->get_data) {
- float apos = spindle->get_data(SpindleData_AngularPosition)->angular_position;
- spindle_data_t *data = spindle->get_data(SpindleData_Counters);
+ float apos = spindle->hal->get_data(SpindleData_AngularPosition)->angular_position;
+ spindle_data_t *data = spindle->hal->get_data(SpindleData_Counters);
hal.stream.write("[SPINDLEENCODER:");
hal.stream.write(uitoa(data->index_count));
@@ -2217,7 +2218,7 @@ status_code_t report_spindle_data (sys_state_t state, char *args)
hal.stream.write("]" ASCII_EOL);
}
- return spindle->get_data ? Status_OK : Status_InvalidStatement;
+ return spindle->hal->get_data ? Status_OK : Status_InvalidStatement;
}
// Prints info about registered pins.
diff --git a/sleep.c b/sleep.c
index abb067b..c35e125 100644
--- a/sleep.c
+++ b/sleep.c
@@ -75,7 +75,7 @@ void sleep_check (void)
// has any powered components enabled.
// NOTE: With overrides or in laser mode, modal spindle and coolant state are not guaranteed. Need
// to directly monitor and record running state during parking to ensure proper function.
- if (!(slumber || sys.steppers_deenergize || sys.flags.auto_reporting) && (gc_state.modal.spindle.state.value || gc_state.modal.coolant.value)) {
+ if (!(slumber || sys.steppers_deenergize || sys.flags.auto_reporting) && (gc_spindle_get(0)->state.value || gc_state.modal.coolant.value)) {
switch(state_get()) {
case STATE_IDLE:
diff --git a/spindle_control.c b/spindle_control.c
index e6e59d9..4010a98 100644
--- a/spindle_control.c
+++ b/spindle_control.c
@@ -510,19 +510,22 @@ void spindle_set_override (spindle_ptrs_t *spindle, override_t speed_override)
speed_override = constrain(speed_override, MIN_SPINDLE_RPM_OVERRIDE, MAX_SPINDLE_RPM_OVERRIDE);
- if ((uint8_t)speed_override != spindle->param->override_pct) {
+ if((uint8_t)speed_override != spindle->param->override_pct) {
- spindle->param->override_pct = speed_override;
+ spindle_set_rpm(spindle, spindle->param->rpm, speed_override);
- if(state_get() == STATE_IDLE)
- spindle_set_state(spindle, gc_state.modal.spindle.state, gc_state.spindle.rpm);
- else
+ if(state_get() == STATE_IDLE) {
+ if(spindle->get_pwm && spindle->update_pwm)
+ spindle->update_pwm(spindle, spindle->get_pwm(spindle, spindle->param->rpm_overridden));
+ else if(spindle->update_rpm)
+ spindle->update_rpm(spindle, spindle->param->rpm_overridden);
+ } else
sys.step_control.update_spindle_rpm = On;
system_add_rt_report(Report_Overrides); // Set to report change immediately
- if(grbl.on_spindle_programmed)
- grbl.on_spindle_programmed(spindle, gc_state.modal.spindle.state, spindle_set_rpm(spindle, gc_state.spindle.rpm, speed_override), gc_state.modal.spindle.rpm_mode);
+// if(grbl.on_spindle_programmed)
+// grbl.on_spindle_programmed(spindle, spindle->param->state, spindle->param->rpm, spindle->param->rpm_mode);
if(grbl.on_override_changed)
grbl.on_override_changed(OverrideChanged_SpindleRPM);
@@ -542,10 +545,10 @@ static bool set_state (spindle_ptrs_t *spindle, spindle_state_t state, float rpm
if (!ABORTED) { // Block during abort.
if (!state.on) { // Halt or set spindle direction and rpm.
- spindle->param->rpm = rpm = 0.0f;
+ rpm = 0.0f;
spindle->set_state(spindle, (spindle_state_t){0}, 0.0f);
} else {
- // NOTE: Assumes all calls to this function is when Grbl is not moving or must remain off.
+ // NOTE: Assumes all calls to this function is when grblHAL is not moving or must remain off.
// TODO: alarm/interlock if going from CW to CCW directly in non-laser mode?
if (spindle->cap.laser && state.ccw)
rpm = 0.0f; // TODO: May need to be rpm_min*(100/MAX_SPINDLE_RPM_OVERRIDE);
@@ -553,6 +556,9 @@ static bool set_state (spindle_ptrs_t *spindle, spindle_state_t state, float rpm
spindle->set_state(spindle, state, spindle_set_rpm(spindle, rpm, spindle->param->override_pct));
}
+ spindle->param->rpm = rpm;
+ spindle->param->state = state;
+
system_add_rt_report(Report_Spindle); // Set to report change immediately
st_rpm_changed(rpm);
diff --git a/state_machine.c b/state_machine.c
index 67f47ee..a60c654 100644
--- a/state_machine.c
+++ b/state_machine.c
@@ -122,7 +122,7 @@ static void enter_sleep (void)
static bool initiate_hold (uint_fast16_t new_state)
{
- spindle_ptrs_t *spindle;
+ spindle_t *spindle;
spindle_num_t spindle_num = N_SYS_SPINDLE;
if (settings.parking.flags.enabled) {
@@ -137,21 +137,21 @@ static bool initiate_hold (uint_fast16_t new_state)
restore_condition.spindle_num = 0;
do {
- if((spindle = spindle_get(--spindle_num))) {
- if(block && block->spindle.hal == spindle) {
+ if((spindle = gc_spindle_get(--spindle_num))) {
+ if(block && block->spindle.hal == spindle->hal) {
restore_condition.spindle_num = spindle_num;
restore_condition.spindle[spindle_num].hal = block->spindle.hal;
restore_condition.spindle[spindle_num].rpm = block->spindle.rpm;
restore_condition.spindle[spindle_num].state = block->spindle.state;
- } else if(gc_state.spindle.hal == spindle) {
+ } else if(spindle->hal) {
restore_condition.spindle_num = spindle_num;
- restore_condition.spindle[spindle_num].hal = gc_state.spindle.hal;
- restore_condition.spindle[spindle_num].rpm = gc_state.spindle.rpm;
- restore_condition.spindle[spindle_num].state = gc_state.modal.spindle.state;
+ restore_condition.spindle[spindle_num].hal = spindle->hal;
+ restore_condition.spindle[spindle_num].rpm = spindle->rpm;
+ restore_condition.spindle[spindle_num].state = spindle->state;
} else {
- restore_condition.spindle[spindle_num].hal = spindle;
- restore_condition.spindle[spindle_num].rpm = spindle->param->rpm;
- restore_condition.spindle[spindle_num].state = spindle->param->state;
+ restore_condition.spindle[spindle_num].hal = NULL;
+// restore_condition.spindle[spindle_num].rpm = spindle->param->rpm;
+// restore_condition.spindle[spindle_num].state = spindle->param->state;
}
} else
restore_condition.spindle[spindle_num].hal = NULL;
@@ -352,7 +352,7 @@ void state_set (sys_state_t new_state)
// Suspend manager. Controls spindle overrides in hold states.
void state_suspend_manager (void)
{
- if (stateHandler != state_await_resume || !gc_state.modal.spindle.state.on)
+ if (stateHandler != state_await_resume || !gc_spindle_get(0)->state.on)
return;
if (sys.override.spindle_stop.value) {
diff --git a/system.c b/system.c
index 06a8ea7..aa28eab 100644
--- a/system.c
+++ b/system.c
@@ -167,12 +167,12 @@ static status_code_t read_int (char *s, int32_t *value)
// Reset spindle encoder data
static status_code_t spindle_reset_data (sys_state_t state, char *args)
{
- spindle_ptrs_t *spindle = gc_spindle_get();
+ spindle_t *spindle = gc_spindle_get(-1);
- if(spindle->reset_data)
- spindle->reset_data();
+ if(spindle->hal->reset_data)
+ spindle->hal->reset_data();
- return spindle->reset_data ? Status_OK : Status_InvalidStatement;
+ return spindle->hal->reset_data ? Status_OK : Status_InvalidStatement;
}
static status_code_t jog (sys_state_t state, char *args)
@@ -767,7 +767,7 @@ const char *help_rtc (const char *cmd)
const char *help_spindle (const char *cmd)
{
- spindle_ptrs_t *spindle = gc_spindle_get();
+ spindle_ptrs_t *spindle = gc_spindle_get(0)->hal;
if(cmd[1] == 'R' && spindle->reset_data)
hal.stream.write("$SR - reset spindle encoder data." ASCII_EOL);
diff --git a/tool_change.c b/tool_change.c
index b43ba99..f352b1c 100644
--- a/tool_change.c
+++ b/tool_change.c
@@ -137,10 +137,12 @@ static bool restore (void)
if(protocol_buffer_synchronize()) {
+
sync_position();
coolant_sync(gc_state.modal.coolant);
- spindle_restore(plan_data.spindle.hal, gc_state.modal.spindle.state, gc_state.spindle.rpm);
+ spindle_t *spindle = gc_spindle_get(-1);
+ spindle_restore(spindle->hal, spindle->state, spindle->rpm);
if(!settings.flags.no_restore_position_after_M6) {
previous.values[plane.axis_linear] += gc_get_offset(plane.axis_linear, false);