Added new handling for spindle spin up and coolant start delays. See the changelog for details.

This commit is contained in:
Terje Io
2025-01-03 23:16:08 +01:00
parent 5a05201041
commit 6b4bab82ad
14 changed files with 245 additions and 176 deletions
+17
View File
@@ -1,5 +1,22 @@
## grblHAL changelog
<a name="20250103">20250103
Core:
* Added new handling for spindle spin up and coolant start delays. Setting `$394` is for spindle spin up and `$673` for coolant start.
They can be either set to 0 or to a value in the range 0.5 - 20s. The settings are used both for initial delay and for restore delay after cancelling a feed hold or completing a tool change.
> [!NOTE]
> If the spindle supports "at speed" functionality and this is enabled by setting $ > 0 then the spin up delay is used as a timeout value before alarm 14 is raised. If `$394` is set to 0 the timeout will default to one minute.
> [!NOTE]
> Setting `$392` and `$393`, if available, are now only used for spindle spin up delay and coolant start delay respectively when the safety door is closed.
Plugins:
* Laser, coolant: updated for internal naming changes, no functional changes.
---
<a name="20250102">20250102
Core:
+37 -1
View File
@@ -3,7 +3,7 @@
Part of grblHAL
Copyright (c) 2020-2024 Terje Io
Copyright (c) 2020-2025 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
@@ -1024,6 +1024,14 @@ Useful for some pre-built electronic boards.
#endif
///@}
/*! @name $673 - Setting_CoolantOnDelay
*/
///@{
#if !defined DEFAULT_COOLANT_ON_DELAY || defined __DOXYGEN__
#define DEFAULT_COOLANT_ON_DELAY 0 // milliseconds: 0 or 500 - 20000
#endif
///@}
// Spindle settings (Group_Spindle)
/*! @name $9 - Setting_SpindlePWMOptions
@@ -1130,6 +1138,14 @@ Default value is 0, meaning spindle sync is disabled
#endif
///@}
/*! @name $394 - Setting_SpindleOnDelay
*/
///@{
#if !defined DEFAULT_SPINDLE_ON_DELAY || defined __DOXYGEN__
#define DEFAULT_SPINDLE_ON_DELAY 0 // milliseconds: 0 or 500 - 20000
#endif
///@}
/*! @name $395 - Setting_SpindleType
*/
///@{
@@ -2197,6 +2213,26 @@ __NOTE:__ Must be a positive values.
#define DEFAULT_ENABLE_SIGNALS_INVERT_MASK AXES_BITMASK
#endif
#if DEFAULT_SPINDLE_ON_DELAY
#if DEFAULT_SPINDLE_ON_DELAY < 500
#undef DEFAULT_SPINDLE_ON_DELAY
#define DEFAULT_SPINDLE_ON_DELAY 500
#elif DEFAULT_SPINDLE_ON_DELAY > 20000
#undef DEFAULT_SPINDLE_ON_DELAY
#define DEFAULT_SPINDLE_ON_DELAY 20000
#endif
#endif
#if DEFAULT_COOLANT_ON_DELAY
#if DEFAULT_COOLANT_ON_DELAY < 500
#undef DEFAULT_COOLANT_ON_DELAY
#define DEFAULT_COOLANT_ON_DELAY 500
#elif DEFAULT_COOLANT_ON_DELAY > 20000
#undef DEFAULT_COOLANT_ON_DELAY
#define DEFAULT_COOLANT_ON_DELAY 20000
#endif
#endif
#if DEFAULT_PARKING_ENABLE > 0
#if DEFAULT_HOMING_FORCE_SET_ORIGIN > 0
#error "DEFAULT_HOMING_FORCE_SET_ORIGIN is not supported with DEFAULT_PARKING_ENABLE at this time."
+23 -11
View File
@@ -3,21 +3,21 @@
Part of grblHAL
Copyright (c) 2016-2023 Terje Io
Copyright (c) 2016-2025 Terje Io
Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
Grbl is free software: you can redistribute it and/or modify
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.
Grbl is distributed in the hope that it will be useful,
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
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
along with grblHAL. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
@@ -28,24 +28,36 @@
#include "coolant_control.h"
#include "state_machine.h"
void coolant_restore (coolant_state_t mode, uint16_t on_delay_ms)
{
if(mode.value != hal.coolant.get_state().value) {
hal.coolant.set_state(mode);
if(mode.value && on_delay_ms)
delay_sec((float)on_delay_ms / 1000.0f, sys.suspend ? DelayMode_SysSuspend : DelayMode_Dwell);
system_add_rt_report(Report_Coolant);
}
}
// Main program only. Immediately sets flood coolant running state and also mist coolant,
// if enabled. Also sets a flag to report an update to a coolant state.
// Called by coolant toggle override, parking restore, parking retract, sleep mode, g-code
// parser program end, and g-code parser coolant_sync().
// parser program end, and g-code parser coolant_set_state_synced().
void coolant_set_state (coolant_state_t mode)
{
if (!ABORTED) { // Block during abort.
if(!ABORTED) { // Block during abort.
hal.coolant.set_state(mode);
system_add_rt_report(Report_Coolant); // Set to report change immediately
if(mode.value && settings.coolant.on_delay)
delay_sec((float)settings.coolant.on_delay / 1000.0f, DelayMode_Dwell);
}
}
// G-code parser entry-point for setting coolant state. Forces a planner buffer sync and bails
// if an abort or check-mode is active.
bool coolant_sync (coolant_state_t mode)
bool coolant_set_state_synced (coolant_state_t mode)
{
bool ok = true;
if (state_get() != STATE_CHECK_MODE) {
bool ok;
if(!(ok = state_get() == STATE_CHECK_MODE)) {
if((ok = protocol_buffer_synchronize())) // Ensure coolant changes state when specified in program.
coolant_set_state(mode);
}
+5 -3
View File
@@ -3,7 +3,7 @@
Part of grblHAL
Copyright (c) 2017-2024 Terje Io
Copyright (c) 2017-2025 Terje Io
Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
grblHAL is free software: you can redistribute it and/or modify
@@ -43,9 +43,11 @@ typedef struct {
} coolant_settings_t;
// Sets the coolant pins according to state specified.
void coolant_set_state(coolant_state_t mode);
void coolant_set_state (coolant_state_t mode);
// G-code parser entry-point for setting coolant states. Checks for and executes additional conditions.
bool coolant_sync(coolant_state_t mode);
bool coolant_set_state_synced (coolant_state_t mode);
void coolant_restore (coolant_state_t mode, uint16_t on_delay_ms);
#endif
+8 -10
View File
@@ -3,7 +3,7 @@
Part of grblHAL
Copyright (c) 2017-2024 Terje Io
Copyright (c) 2017-2025 Terje Io
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
@@ -552,10 +552,8 @@ bool gc_modal_state_restore (gc_modal_t *copy)
copy->auto_restore = false;
copy->motion = gc_state.modal.motion;
if(copy->coolant.value != gc_state.modal.coolant.value) {
hal.coolant.set_state(copy->coolant);
delay_sec(settings.safety_door.coolant_on_delay, DelayMode_SysSuspend);
}
if(copy->coolant.value != gc_state.modal.coolant.value)
coolant_restore(copy->coolant, settings.coolant.on_delay);
#if N_SYS_SPINDLE > 1
uint_fast8_t idx = N_SYS_SPINDLE;
@@ -569,7 +567,7 @@ bool gc_modal_state_restore (gc_modal_t *copy)
} while(idx);
#else
if(!memcmp(&copy->spindle, &gc_state.modal.spindle, offsetof(spindle_t, hal)))
spindle_restore(gc_state.modal.spindle.hal, copy->spindle.state, copy->spindle.rpm);
spindle_restore(gc_state.modal.spindle.hal, copy->spindle.state, copy->spindle.rpm, settings.spindle.on_delay);
#endif
memcpy(&gc_state.modal, copy, sizeof(gc_modal_t));
@@ -3177,7 +3175,7 @@ status_code_t gc_execute_block (char *block)
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);
spindle_set_state_synced(sspindle->hal, sspindle->state, gc_parser_flags.laser_disable ? 0.0f : gc_block.values.s);
}
sspindle->rpm = gc_block.values.s; // Update spindle speed state.
}
@@ -3333,7 +3331,7 @@ status_code_t gc_execute_block (char *block)
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((spindle_ok = spindle_set_state_synced(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;
}
@@ -3355,7 +3353,7 @@ status_code_t gc_execute_block (char *block)
if(grbl.on_spindle_programmed)
grbl.on_spindle_programmed(sspindle->hal, gc_block.spindle_modal.state, plan_data.spindle.rpm, sspindle->rpm_mode);
if((spindle_ok = spindle_sync(sspindle->hal, gc_block.spindle_modal.state, plan_data.spindle.rpm)))
if((spindle_ok = spindle_set_state_synced(sspindle->hal, gc_block.spindle_modal.state, plan_data.spindle.rpm)))
sspindle->state = sspindle->hal->param->state = gc_block.spindle_modal.state;
spindle_event = !spindle_ok;
@@ -3407,7 +3405,7 @@ status_code_t gc_execute_block (char *block)
if (gc_parser_flags.set_coolant && gc_state.modal.coolant.value != gc_block.modal.coolant.value) {
// NOTE: Coolant M-codes are modal. Only one command per line is allowed. But, multiple states
// can exist at the same time, while coolant disable clears all states.
if(coolant_sync(gc_block.modal.coolant))
if(coolant_set_state_synced(gc_block.modal.coolant))
gc_state.modal.coolant = gc_block.modal.coolant;
}
+1 -1
View File
@@ -42,7 +42,7 @@
#else
#define GRBL_VERSION "1.1f"
#endif
#define GRBL_BUILD 20250102
#define GRBL_BUILD 20250103
#define GRBL_URL "https://github.com/grblHAL"
+1 -1
View File
@@ -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, pl_data->spindle.state, pl_data->spindle.rpm);
spindle_set_state_synced(pl_data->spindle.hal, pl_data->spindle.state, pl_data->spindle.rpm);
}
pl_data->condition.rapid_motion = On; // Set rapid motion condition flag.
+6 -27
View File
@@ -646,6 +646,10 @@ bool ngc_named_param_get (char *name, float *value)
name = ngc_name_tolower(name);
// Check if name is supplied, return false if not.
if((*name == '_' ? *(name + 1) : *name) == '\0')
return false;
*value = 0.0f;
if(*name == '_') do {
@@ -670,34 +674,9 @@ bool ngc_named_param_get (char *name, float *value)
bool ngc_named_param_exists (char *name)
{
bool ok = false;
uint_fast8_t idx = sizeof(ngc_named_ro_param) / sizeof(ngc_named_ro_param_t);
float value;
name = ngc_name_tolower(name);
// Check if name is supplied, return false if not.
if((*name == '_' ? *(name + 1) : *name) == '\0')
return false;
// Check if it is a (read only) predefined parameter.
if(*name == '_') do {
ok = !strcmp(name, ngc_named_ro_param[--idx].name);
} while(idx && !ok);
// If not predefined attempt to find it.
if(!ok && rw_global_params && strlen(name) <= NGC_MAX_PARAM_LENGTH) {
void *context = *name == '_' ? NULL : call_context;
ngc_named_rw_param_t *rw_param = rw_global_params;
while(rw_param) {
if((ok = rw_param->context == context && !strcmp(rw_param->name, name)))
break;
rw_param = rw_param->next;
}
}
return ok;
return ngc_named_param_get(name, &value);
}
bool ngc_named_param_set (char *name, float value)
+66 -15
View File
@@ -160,6 +160,8 @@ PROGMEM const settings_t defaults = {
.control_disable_pullup.mask = DEFAULT_DISABLE_CONTROL_PINS_PULL_UP_MASK,
.spindle.ref_id = DEFAULT_SPINDLE,
.spindle.on_delay = DEFAULT_SPINDLE_ON_DELAY,
.spindle.at_speed_tolerance = DEFAULT_SPINDLE_AT_SPEED_TOLERANCE,
.spindle.encoder_spindle = DEFAULT_SPINDLE,
.spindle.ppr = DEFAULT_SPINDLE_PPR,
@@ -204,6 +206,7 @@ PROGMEM const settings_t defaults = {
#endif
#endif
.coolant.on_delay = DEFAULT_COOLANT_ON_DELAY,
.coolant.invert.flood = DEFAULT_INVERT_COOLANT_FLOOD_PIN,
.coolant.invert.mist = DEFAULT_INVERT_COOLANT_MIST_PIN,
@@ -1130,6 +1133,31 @@ setting_id_t settings_get_axis_base (setting_id_t id, uint_fast8_t *idx)
return *idx < N_AXIS ? base : Setting_SettingsMax;
}
static status_code_t set_float (setting_id_t setting, float value)
{
status_code_t status = Status_OK;
switch(setting) {
case Setting_SpindleAtSpeedTolerance:
settings.spindle.at_speed_tolerance = settings.pwm_spindle.at_speed_tolerance = value;
break;
case Setting_SpindleOnDelay:
settings.spindle.on_delay = (uint16_t)(value * 1000.0f);
break;
case Setting_CoolantOnDelay:
settings.coolant.on_delay = (uint16_t)(value * 1000.0f);
break;
default:
break;
}
return status;
}
static status_code_t set_axis_setting (setting_id_t setting, float value)
{
uint_fast8_t idx;
@@ -1292,10 +1320,22 @@ static float get_float (setting_id_t setting)
value = settings.homing.pulloff;
break;
case Setting_SpindleAtSpeedTolerance:
value = settings.pwm_spindle.at_speed_tolerance;
break;
case Setting_ToolChangeProbingDistance:
value = settings.tool_change.probing_distance;
break;
case Setting_SpindleOnDelay:
value = (float)settings.spindle.on_delay / 1000.0f;
break;
case Setting_CoolantOnDelay:
value = (float)settings.coolant.on_delay / 1000.0f;
break;
default:
break;
}
@@ -1767,7 +1807,7 @@ static bool is_setting_available (const setting_detail_t *setting)
break;
case Setting_SpindleOnDelay:
available = !hal.signals_cap.safety_door_ajar && spindle_get_count() && !spindle_get_caps(true).at_speed;
available = spindle_get_count();
break;
case Setting_AutoReportInterval:
@@ -1794,7 +1834,7 @@ static bool is_setting_available (const setting_detail_t *setting)
available = hal.homing.get_state != NULL && hal.home_cap.a.mask != 0;
break;
case Setting_HoldCoolantOnDelay:
case Setting_CoolantOnDelay:
available = !hal.signals_cap.safety_door_ajar && hal.coolant_cap.mask;
break;
@@ -1987,7 +2027,7 @@ PROGMEM static const setting_detail_t setting_detail[] = {
{ Setting_AxisAutoSquareOffset, Group_Axis0, "-axis dual axis offset", "mm", Format_Decimal, "-0.000", "-10", "10", Setting_IsExtendedFn, set_axis_setting, get_float, is_setting_available, AXIS_OPTS },
{ Setting_AxisHomingFeedRate, Group_Axis0, "-axis homing locate feed rate", axis_rate, Format_Decimal, "###0", NULL, NULL, Setting_NonCoreFn, set_axis_setting, get_float, is_setting_available, AXIS_OPTS },
{ Setting_AxisHomingSeekRate, Group_Axis0, "-axis homing search seek rate", axis_rate, Format_Decimal, "###0", NULL, NULL, Setting_NonCoreFn, set_axis_setting, get_float, is_setting_available, AXIS_OPTS },
{ Setting_SpindleAtSpeedTolerance, Group_Spindle, "Spindle at speed tolerance", "percent", Format_Decimal, "##0.0", NULL, NULL, Setting_IsExtended, &settings.pwm_spindle.at_speed_tolerance, NULL, is_setting_available },
{ Setting_SpindleAtSpeedTolerance, Group_Spindle, "Spindle at speed tolerance", "percent", Format_Decimal, "##0.0", NULL, NULL, Setting_IsExtendedFn, set_float, get_float, is_setting_available },
{ Setting_ToolChangeMode, Group_Toolchange, "Tool change mode", NULL, Format_RadioButtons, "Normal,Manual touch off,Manual touch off @ G59.3,Automatic touch off @ G59.3,Ignore M6", NULL, NULL, Setting_IsExtendedFn, set_tool_change_mode, get_int, NULL },
{ Setting_ToolChangeProbingDistance, Group_Toolchange, "Tool change probing distance", "mm", Format_Decimal, "#####0.0", NULL, NULL, Setting_IsExtendedFn, set_tool_change_probing_distance, get_float, NULL },
{ Setting_ToolChangeFeedRate, Group_Toolchange, "Tool change locate feed rate", "mm/min", Format_Decimal, "#####0.0", NULL, NULL, Setting_IsExtended, &settings.tool_change.feed_rate, NULL, NULL },
@@ -2004,10 +2044,10 @@ PROGMEM static const setting_detail_t setting_detail[] = {
{ Settings_RotaryAxes, Group_Stepper, "Rotary axes", NULL, Format_Bitfield, rotary_axes, NULL, NULL, Setting_IsExtendedFn, set_rotary_axes, get_int, NULL },
#endif
#ifndef NO_SAFETY_DOOR_SUPPORT
{ Setting_DoorSpindleOnDelay, Group_SafetyDoor, "Spindle on delay", "s", Format_Decimal, "#0.0", "0.5", "20", Setting_IsExtended, &settings.safety_door.spindle_on_delay, NULL, is_setting_available },
{ Setting_DoorCoolantOnDelay, Group_SafetyDoor, "Coolant on delay", "s", Format_Decimal, "#0.0", "0.5", "20", Setting_IsExtended, &settings.safety_door.coolant_on_delay, NULL, is_setting_available },
{ Setting_DoorSpindleOnDelay, Group_SafetyDoor, "Spindle on delay", "s", Format_Decimal, "#0.0", "0.5", "20", Setting_IsExtended, &settings.safety_door.spindle_on_delay, NULL, is_setting_available, { .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, is_setting_available, { .allow_null = On } },
#endif
{ Setting_SpindleOnDelay, Group_Spindle, "Spindle on delay", "s", Format_Decimal, "#0.0", "0.5", "20", Setting_IsExtended, &settings.safety_door.spindle_on_delay, NULL, is_setting_available },
{ Setting_SpindleOnDelay, Group_Spindle, "Spindle on delay", "s", Format_Decimal, "#0.0", "0.5", "20", Setting_IsExtendedFn, set_float, get_float, is_setting_available, { .allow_null = On } },
{ Setting_SpindleType, Group_Spindle, "Default spindle", NULL, Format_RadioButtons, spindle_types, NULL, NULL, Setting_IsExtendedFn, set_default_spindle, get_int, is_setting_available },
{ Setting_PlannerBlocks, Group_General, "Planner buffer blocks", NULL, Format_Int16, "####0", "30", "1000", Setting_IsExtended, &settings.planner_buffer_blocks, NULL, NULL, { .reboot_required = On } },
{ Setting_AutoReportInterval, Group_General, "Autoreport interval", "ms", Format_Int16, "###0", "100", "1000", Setting_IsExtendedFn, set_report_interval, get_int, NULL, { .reboot_required = On, .allow_null = On } },
@@ -2025,7 +2065,7 @@ PROGMEM static const setting_detail_t setting_detail[] = {
#endif
{ Setting_FSOptions, Group_General, "File systems options", NULL, Format_Bitfield, fs_options, NULL, NULL, Setting_IsExtended, &settings.fs_options.mask, NULL, is_setting_available },
{ Setting_HomePinsInvertMask, Group_Limits, "Invert home inputs", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtended, &settings.home_invert.mask, NULL, is_setting_available },
{ Setting_HoldCoolantOnDelay, Group_Coolant, "Coolant on delay", "s", Format_Decimal, "#0.0", "0.5", "20", Setting_IsExtended, &settings.safety_door.coolant_on_delay, NULL, is_setting_available }
{ 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 } }
};
#ifndef NO_SETTINGS_DESCRIPTIONS
@@ -2169,7 +2209,8 @@ PROGMEM static const setting_descr_t setting_descr[] = {
{ Setting_AxisHomingFeedRate, "Feed rate to slowly engage limit switch to determine its location accurately." },
{ Setting_AxisHomingSeekRate, "Seek rate to quickly find the limit switch before the slower locating phase." },
{ Setting_SpindleAtSpeedTolerance, "Spindle at speed tolerance as percentage deviation from programmed speed, set to 0 to disable.\\n"
"If not within tolerance when checked after spindle on delay ($392) alarm 14 is raised."
"If not within tolerance after timeout set by spindle on delay ($394) alarm 14 is raised.\\n"
"NOTE: if the spindle on delay is set to 0 the timeout defaults to one minute."
},
{ Setting_ToolChangeMode, "Normal: allows jogging for manual touch off. Set new position manually.\\n\\n"
"Manual touch off: retracts tool axis to home position for tool change, use jogging or $TPW for touch off.\\n\\n"
@@ -2192,12 +2233,12 @@ PROGMEM static const setting_descr_t setting_descr[] = {
{ Settings_RotaryAxes, "Designates axes as rotary, interpretation some other relevant axis settings is changed accordingly." },
#endif
#ifndef NO_SAFETY_DOOR_SUPPORT
{ Setting_DoorSpindleOnDelay, "Delay to allow spindle to spin up after safety door is opened or feed hold is canceled." },
{ Setting_DoorCoolantOnDelay, "Delay to allow coolant to restart after safety door is opened or feed hold is canceled." },
#else
{ Setting_DoorSpindleOnDelay, "Delay to allow spindle to spin up when spindle at speed tolerance is > 0." },
{ Setting_DoorSpindleOnDelay, "Delay to allow spindle to spin up after safety door is opened." },
{ Setting_DoorCoolantOnDelay, "Delay to allow coolant to restart after safety door is opened." },
#endif
{ Setting_SpindleOnDelay, "Delay to allow spindle to restart after feed hold is canceled." },
{ Setting_SpindleOnDelay, "Delay to allow spindle to spin up. 0 or 0.5 - 20s\\n"
"If spindle supports ""at speed"" functionality it is the time to wait before alarm 14 is raised."
},
{ Setting_SpindleType, "Spindle selected on startup." },
{ Setting_PlannerBlocks, "Number of blocks in the planner buffer." },
{ Setting_AutoReportInterval, "Interval the real time report will be sent, set to 0 to disable." },
@@ -2219,7 +2260,7 @@ PROGMEM static const setting_descr_t setting_descr[] = {
#endif
{ Setting_FSOptions, "Auto mount SD card on startup." },
{ Setting_HomePinsInvertMask, "Inverts the axis home input signals." },
{ Setting_HoldCoolantOnDelay, "Delay to allow coolant to restart after feed hold is canceled." }
{ Setting_CoolantOnDelay, "Delay to allow coolant to start. 0 or 0.5 - 20s" }
};
#endif
@@ -3221,9 +3262,19 @@ void settings_init (void)
details->on_changed(&settings, changed);
} while((details = details->next));
if(!settings.flags.settings_downgrade && settings.version.build != (GRBL_BUILD - 20000000UL)) {
if(settings.version.build <= 250102) {
settings.spindle.on_delay = settings.safety_door.spindle_on_delay * 1000.0f;
settings.coolant.on_delay = settings.safety_door.coolant_on_delay * 1000.0f;
if((changed.spindle = settings.spindle.at_speed_tolerance != settings.pwm_spindle.at_speed_tolerance)) {
settings.spindle.at_speed_tolerance = settings.pwm_spindle.at_speed_tolerance;
hal.settings_changed(&settings, changed);
}
}
settings.version.build = (GRBL_BUILD - 20000000UL);
settings_write_global();
}
+13 -13
View File
@@ -3,7 +3,7 @@
Part of grblHAL
Copyright (c) 2017-2024 Terje Io
Copyright (c) 2017-2025 Terje Io
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
@@ -249,20 +249,20 @@ typedef enum {
Settings_ModBus_RXTimeout = 375,
Settings_RotaryAxes = 376,
Setting_BlueToothInitOK = 377,
Setting_CoolantOnDelay = 378,
Setting_CoolantOffDelay = 379,
Setting_CoolantMinTemp = 380,
Setting_CoolantMaxTemp = 381,
Setting_CoolantOffset = 382,
Setting_CoolantGain = 383,
Setting_LaserCoolantOnDelay = 378,
Setting_LaserCoolantOffDelay = 379,
Setting_LaserCoolantMinTemp = 380,
Setting_LaserCoolantMaxTemp = 381,
Setting_LaserCoolantOffset = 382,
Setting_LaserCoolantGain = 383,
Setting_DisableG92Persistence = 384,
Setting_BlueToothStateInput = 385,
Setting_FanPort0 = 386,
Setting_FanPort1 = 387,
Setting_FanPort2 = 388,
Setting_FanPort3 = 389,
Setting_CoolantTempPort = 390,
Setting_CoolantOkPort = 391,
Setting_LaserCoolantTempPort = 390,
Setting_LaserCoolantOkPort = 391,
Setting_DoorSpindleOnDelay = 392,
Setting_DoorCoolantOnDelay = 393,
Setting_SpindleOnDelay = 394, // made available if safety door input not provided
@@ -450,7 +450,7 @@ typedef enum {
Setting_HomePinsInvertMask = 671,
Setting_Reserved672 = 672,
Setting_HoldCoolantOnDelay = 673, // made available if safety door input not provided
Setting_CoolantOnDelay = 673,
Setting_SpindleInvertMask1 = 716,
@@ -628,9 +628,9 @@ typedef union {
} safety_door_setting_flags_t;
typedef struct {
safety_door_setting_flags_t flags;
float spindle_on_delay;
float coolant_on_delay;
safety_door_setting_flags_t flags; // TODO: move to last element in next revision
float spindle_on_delay; // TODO: change to uint16_t in next revision
float coolant_on_delay; // TODO: change to uint16_t in next revision
} safety_door_settings_t;
typedef union {
+44 -57
View File
@@ -3,7 +3,7 @@
Part of grblHAL
Copyright (c) 2017-2024 Terje Io
Copyright (c) 2017-2025 Terje Io
Copyright (c) 2012-2015 Sungeun K. Jeon
Copyright (c) 2009-2011 Simen Svale Skogsrud
@@ -551,14 +551,14 @@ void spindle_set_override (spindle_ptrs_t *spindle, override_t speed_override)
}
/*! \internal \brief Immediately sets spindle running state with direction and spindle rpm, if enabled.
Called by g-code parser spindle_sync(), parking retract and restore, g-code program end,
Called by g-code parser spindle_set_state_synced(), parking retract and restore, g-code program end,
sleep, and spindle stop override.
\param spindle pointer to a \ref spindle_ptrs_t structure.
\param state a \ref spindle_state_t structure.
\param rpm the spindle RPM to set.
\returns \a true if successful, \a false if the current controller state is \ref ABORTED.
*/
static bool set_state (spindle_ptrs_t *spindle, spindle_state_t state, float rpm)
bool spindle_set_state (spindle_ptrs_t *spindle, spindle_state_t state, float rpm)
{
if (!ABORTED) { // Block during abort.
@@ -585,18 +585,45 @@ static bool set_state (spindle_ptrs_t *spindle, spindle_state_t state, float rpm
return !ABORTED;
}
/*! \brief Immediately sets spindle running state with direction and spindle rpm, if enabled.
Called by g-code parser spindle_sync(), parking retract and restore, g-code program end,
sleep, and spindle stop override.
/*! \brief If the spindle supports at speed functionality it will wait
for it to reach the speed and raise an alarm if the speed is not reached within the timeout period.
\param spindle pointer to a \ref spindle_ptrs_t structure.
\param state a \ref spindle_state_t structure.
\param rpm the spindle RPM to set.
\returns \a true if successful, \a false if the current controller state is \ref ABORTED.
*/
bool spindle_set_state (spindle_ptrs_t *spindle, spindle_state_t state, float rpm)
static bool spindle_set_state_wait (spindle_ptrs_t *spindle, spindle_state_t state, float rpm, uint16_t on_delay_ms, delaymode_t delay_mode)
{
return set_state(spindle, state, rpm);
bool ok;
if(!(ok = state_get() == STATE_CHECK_MODE)) {
if((ok = spindle_set_state(spindle, state, rpm))) {
bool at_speed = !state.on || !spindle->cap.at_speed || spindle->at_speed_tolerance <= 0.0f;
if(at_speed)
ok = on_delay_ms == 0 || delay_sec((float)on_delay_ms / 1000.0f, delay_mode);
else {
uint16_t delay = 0;
if(on_delay_ms == 0)
on_delay_ms = 60000; // one minute...
while(!(at_speed = spindle->get_state(spindle).at_speed)) {
if(!delay_sec(0.2f, delay_mode))
break;
delay += 200;
if(delay > on_delay_ms) {
gc_spindle_off();
system_raise_alarm(Alarm_Spindle);
break;
}
}
ok &= at_speed;
}
}
}
return ok;
}
/*! \brief G-code parser entry-point for setting spindle state. Forces a planner buffer sync and bails
@@ -607,33 +634,10 @@ for it to reach the speed and raise an alarm if the speed is not reached within
\param rpm the spindle RPM to set.
\returns \a true if successful, \a false if the current controller state is \ref ABORTED.
*/
bool spindle_sync (spindle_ptrs_t *spindle, spindle_state_t state, float rpm)
bool spindle_set_state_synced (spindle_ptrs_t *spindle, spindle_state_t state, float rpm)
{
bool ok;
if (!(ok = state_get() == STATE_CHECK_MODE)) {
bool at_speed = !state.on || !spindle->cap.at_speed || spindle->at_speed_tolerance <= 0.0f;
// Empty planner buffer to ensure spindle is set when programmed.
if((ok = protocol_buffer_synchronize()) && set_state(spindle, state, rpm) && !at_speed) {
float on_delay = 0.0f;
while(!(at_speed = spindle->get_state(spindle).at_speed)) {
if(!(ok = delay_sec(0.2f, DelayMode_Dwell)))
break;
on_delay += 0.2f;
if(!(ok = on_delay < settings.safety_door.spindle_on_delay)) {
gc_spindle_off();
system_raise_alarm(Alarm_Spindle);
break;
}
}
}
ok &= at_speed;
}
return ok;
// Empty planner buffer to ensure spindle is set when programmed.
return protocol_buffer_synchronize() && spindle_set_state_wait(spindle, state, rpm, settings.spindle.on_delay, DelayMode_Dwell);
}
/*! \brief Restore spindle running state with direction, enable, spindle RPM and appropriate delay.
@@ -642,31 +646,14 @@ bool spindle_sync (spindle_ptrs_t *spindle, spindle_state_t state, float rpm)
\param rpm the spindle RPM to set.
\returns \a true if successful, \a false if the current controller state is \ref ABORTED.
*/
bool spindle_restore (spindle_ptrs_t *spindle, spindle_state_t state, float rpm)
bool spindle_restore (spindle_ptrs_t *spindle, spindle_state_t state, float rpm, uint16_t on_delay_ms)
{
bool ok = true;
bool ok;
if(spindle->cap.laser) // When in laser mode, ignore spindle spin-up delay. Set to turn on laser when cycle starts.
if((ok = spindle->cap.laser)) // When in laser mode, ignore spindle spin-up delay. Set to turn on laser when cycle starts.
sys.step_control.update_spindle_rpm = On;
else { // TODO: add check for current spindle state matches restore state?
spindle_set_state(spindle, state, rpm);
if(state.on) {
if((ok = !spindle->cap.at_speed))
ok = delay_sec(settings.safety_door.spindle_on_delay, DelayMode_SysSuspend);
else if((ok == (spindle->at_speed_tolerance <= 0.0f))) {
float delay = 0.0f;
while(!(ok = spindle->get_state(spindle).at_speed)) {
if(!(ok = delay_sec(0.1f, DelayMode_SysSuspend)))
break;
delay += 0.1f;
if(!(ok = delay < settings.safety_door.spindle_on_delay)) {
system_raise_alarm(Alarm_Spindle);
break;
}
}
}
}
}
else if(!(ok = state.value == spindle->get_state(spindle).value))
ok = spindle_set_state_wait(spindle, state, rpm, on_delay_ms, DelayMode_SysSuspend);
return ok;
}
+5 -5
View File
@@ -3,7 +3,7 @@
Part of grblHAL
Copyright (c) 2017-2024 Terje Io
Copyright (c) 2017-2025 Terje Io
Copyright (c) 2012-2015 Sungeun K. Jeon
Copyright (c) 2009-2011 Simen Svale Skogsrud
@@ -340,17 +340,17 @@ typedef bool (*spindle_enumerate_callback_ptr)(spindle_info_t *spindle, void *da
void spindle_set_override (spindle_ptrs_t *spindle, override_t speed_override);
// Called by g-code parser when setting spindle state and requires a buffer sync.
bool spindle_sync (spindle_ptrs_t *spindle, spindle_state_t state, float rpm);
// Sets spindle running state with direction, enable, and spindle RPM.
bool spindle_set_state (spindle_ptrs_t *spindle, spindle_state_t state, float rpm);
// Called by g-code parser when setting spindle state and requires a buffer sync.
bool spindle_set_state_synced (spindle_ptrs_t *spindle, spindle_state_t state, float rpm);
// Spindle speed calculation and limit handling
float spindle_set_rpm (spindle_ptrs_t *spindle, float rpm, override_t speed_override);
// Restore spindle running state with direction, enable, spindle RPM and appropriate delay.
bool spindle_restore (spindle_ptrs_t *spindle, spindle_state_t state, float rpm);
bool spindle_restore (spindle_ptrs_t *spindle, spindle_state_t state, float rpm, uint16_t on_delay_ms);
void spindle_all_off (void);
+16 -28
View File
@@ -5,7 +5,7 @@
Part of grblHAL
Copyright (c) 2018-2024 Terje Io
Copyright (c) 2018-2025 Terje Io
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
@@ -74,41 +74,32 @@ typedef struct {
// Declare and initialize parking local variables
static parking_data_t park = {0};
static void state_spindle_restore (spindle_t *spindle)
static void state_spindle_restore (spindle_t *spindle, uint16_t on_delay_ms)
{
if(spindle->hal) {
if(grbl.on_spindle_programmed)
grbl.on_spindle_programmed(spindle->hal, spindle->state, spindle->rpm, spindle->rpm_mode);
spindle_restore(spindle->hal, spindle->state, spindle->rpm);
}
}
static void state_spindle_set_state (spindle_t *spindle)
{
if(spindle->hal) {
if(grbl.on_spindle_programmed)
grbl.on_spindle_programmed(spindle->hal, spindle->state, spindle->rpm, spindle->rpm_mode);
spindle_set_state(spindle->hal, spindle->state, spindle->rpm);
spindle_restore(spindle->hal, spindle->state, spindle->rpm, on_delay_ms);
}
}
static void state_restore_conditions (restore_condition_t *condition)
{
if (!settings.parking.flags.enabled || !park.flags.restart) {
if(!settings.parking.flags.enabled || !park.flags.restart) {
spindle_num_t spindle_num = N_SYS_SPINDLE;
park.flags.restoring = On; //
do {
state_spindle_restore(&condition->spindle[--spindle_num]);
state_spindle_restore(&condition->spindle[--spindle_num], (uint16_t)(settings.safety_door.spindle_on_delay * 1000.0f));
} while(spindle_num);
// Block if safety door re-opened during prior restore actions.
if (gc_state.modal.coolant.value != hal.coolant.get_state().value) {
if(gc_state.modal.coolant.value != hal.coolant.get_state().value) {
// NOTE: Laser mode will honor this delay. An exhaust system is often controlled by this signal.
gc_coolant(condition->coolant);;
delay_sec(settings.safety_door.coolant_on_delay, DelayMode_SysSuspend);
coolant_restore(condition->coolant, (uint16_t)(settings.safety_door.coolant_on_delay * 1000.0f));
gc_coolant(condition->coolant);
}
park.flags.restoring = Off;
@@ -361,10 +352,10 @@ void state_suspend_manager (void)
if (stateHandler != state_await_resume || !gc_spindle_get(0)->state.on)
return;
if (sys.override.spindle_stop.value) {
if(sys.override.spindle_stop.value) {
// Handles beginning of spindle stop
if (sys.override.spindle_stop.initiate) {
if(sys.override.spindle_stop.initiate) {
sys.override.spindle_stop.value = 0; // Clear stop override state
if(grbl.on_spindle_programmed)
grbl.on_spindle_programmed(restore_condition.spindle[restore_condition.spindle_num].hal, (spindle_state_t){0}, 0.0f, 0);
@@ -375,20 +366,17 @@ void state_suspend_manager (void)
}
// Handles restoring of spindle state
if (sys.override.spindle_stop.restore) {
if(sys.override.spindle_stop.restore) {
grbl.report.feedback_message(Message_SpindleRestore);
if (restore_condition.spindle[restore_condition.spindle_num].hal->cap.laser) // When in laser mode, ignore spindle spin-up delay. Set to turn on laser when cycle starts.
sys.step_control.update_spindle_rpm = On;
else
state_spindle_set_state(&restore_condition.spindle[restore_condition.spindle_num]);
state_spindle_restore(&restore_condition.spindle[restore_condition.spindle_num], settings.spindle.on_delay);
sys.override.spindle_stop.value = 0; // Clear stop override state
if(grbl.on_override_changed)
grbl.on_override_changed(OverrideChanged_SpindleState);
}
} else if (sys.step_control.update_spindle_rpm && restore_condition.spindle[0].hal->get_state(restore_condition.spindle[0].hal).on) {
} else if(sys.step_control.update_spindle_rpm && restore_condition.spindle[0].hal->get_state(restore_condition.spindle[0].hal).on) {
// Handles spindle state during hold. NOTE: Spindle speed overrides may be altered during hold state.
state_spindle_set_state(&restore_condition.spindle[restore_condition.spindle_num]);
state_spindle_restore(&restore_condition.spindle[restore_condition.spindle_num], settings.spindle.on_delay);
sys.step_control.update_spindle_rpm = Off;
}
}
@@ -669,13 +657,13 @@ static void state_await_resume (uint_fast16_t rt_exec)
if (restore_condition.spindle[restore_condition.spindle_num].state.on != restore_condition.spindle[restore_condition.spindle_num].hal->get_state(restore_condition.spindle[restore_condition.spindle_num].hal).on) {
grbl.report.feedback_message(Message_SpindleRestore);
state_spindle_restore(&restore_condition.spindle[restore_condition.spindle_num]);
state_spindle_restore(&restore_condition.spindle[restore_condition.spindle_num], settings.spindle.on_delay);
}
if (restore_condition.coolant.value != hal.coolant.get_state().value) {
// NOTE: Laser mode will honor this delay. An exhaust system is often controlled by coolant signals.
coolant_restore(restore_condition.coolant, settings.coolant.on_delay);
gc_coolant(restore_condition.coolant);
delay_sec(settings.safety_door.coolant_on_delay, DelayMode_SysSuspend);
}
sys.override.spindle_stop.value = 0; // Clear spindle stop override states
+3 -4
View File
@@ -5,7 +5,7 @@
Part of grblHAL
Copyright (c) 2020-2024 Terje Io
Copyright (c) 2020-2025 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
@@ -141,12 +141,11 @@ static bool restore (void)
if(protocol_buffer_synchronize()) {
sync_position();
coolant_sync(gc_state.modal.coolant);
coolant_restore(gc_state.modal.coolant, settings.coolant.on_delay);
spindle_t *spindle = gc_spindle_get(-1);
spindle_restore(spindle->hal, spindle->state, spindle->rpm);
spindle_restore(spindle->hal, spindle->state, spindle->rpm, settings.spindle.on_delay);
if(!settings.flags.no_restore_position_after_M6) {
previous.values[plane.axis_linear] += gc_get_offset(plane.axis_linear, false);