Large spindle handling refactoring and enhancement++, see the changelog for more.

This commit is contained in:
Terje Io
2023-02-13 22:14:48 +01:00
parent e2ba6db69c
commit 04ce2c5c8c
33 changed files with 1430 additions and 604 deletions
+2 -2
View File
@@ -13,7 +13,7 @@ It has been written to complement grblHAL and has features such as proper keyboa
---
Latest build date is 20230129, see the [changelog](changelog.md) for details.
Latest build date is 20230213, see the [changelog](changelog.md) for details.
__NOTE:__ A settings reset will be performed on an update of builds earlier than 20230125. Backup and restore of settings is recommended.
__IMPORTANT!__ A new setting has been introduced for ganged axes motors in build 20211121.
I have only bench tested this for a couple of drivers, correct function should be verified after updating by those who have more than three motors configured.
@@ -87,4 +87,4 @@ List of Supported G-Codes:
Some [plugins](https://github.com/grblHAL/plugins) implements additional M-codes.
---
2023-01-28
2023-02-13
+17
View File
@@ -64,3 +64,20 @@ alarm_details_t *alarms_get_details (void)
{
return &details;
}
const char *alarms_get_description (alarm_code_t id)
{
uint_fast16_t n_alarms;
const char *description = NULL;
alarm_details_t *details = grbl.on_get_alarms();
do {
n_alarms = details->n_alarms;
do {
if(details->alarms[--n_alarms].id == id)
description = details->alarms[n_alarms].description;
} while(description == NULL && n_alarms);
} while(description == NULL && (details = details->next));
return description;
}
+2 -1
View File
@@ -61,8 +61,9 @@ typedef struct alarm_details {
typedef alarm_details_t *(*on_get_alarms_ptr)(void);
void alarms_register (alarm_details_t *details);
alarm_details_t *alarms_get_details (void);
const char *alarms_get_description (alarm_code_t id);
void alarms_register (alarm_details_t *details);
#endif
+40 -1
View File
@@ -1,11 +1,50 @@
## grblHAL changelog
<a name="20230213"/>Build 20230213
Core:
* First phase of spindle handling refactoring with the aim to support multiple \(up to four\) _simultaneously_ active spindles.
Spindle selection by tool number has also been implemented as an option. More details can be found in the [spindle plugin readme](https://github.com/grblHAL/Plugins_spindle/blob/master/README.md).
__NOTE:__ This change is quite large, bugs may have sneaked in. Please report any issues encountered ASAP.
Drivers:
* All: updated for spindle handling refactoring.
* iMXRT1062: updated readme for links to updated/patched libraries for SD card \(uSDFS\) and ethernet. User should switch to the updated/patched libraries if used.
* MSP432P401R: fix for missing file include and serial stream registration.
* RP2040: switched to SDK v1.5.0. Added new settings for RP2040, `$78` for wifi country code and `$337` for AP BSSID of AP to connect to. Both are optional.
* STMF4xx: fix for issue [#110](https://github.com/grblHAL/STM32F4xx/issues/110), incorrect NVIC grouping.
Plugins:
* SD Card: fixed some minor inconsistencies.
* Spindle: updated for spindle handling refactoring. Improved ModBus exception handling in some.
New spindle select settings and improved functionality, see the [spindle plugin readme](https://github.com/grblHAL/Plugins_spindle/blob/master/README.md) for more.
* Odometer and PPI: updated for spindle handling refactoring.
* Networking: wifi \(ESP32 and RP2040\), changed networking settings from `$30x` range to `$32x` range for station mode.
Added [MQTT](https://en.wikipedia.org/wiki/MQTT) API for plugin developers, example code using this can be found [here](https://github.com/grblHAL/Templates/tree/master/my_plugin/MQTT%20example).
__NOTE:__ networking and other plugin settings will be reset on update for ESP32 and RP2040, backup and restore.
---
<a name="20230129"/>Build 20230129
Core:
* Fixed regression in tool change handling related to refactoring of _config.h_ in build 20230125.
Drivers:
* ESP32: Added all supported VFD spindles as options in CMakeLists.txt, some code cleanup.
---
<a name="20230128"/>Build 20230128
@@ -96,7 +135,7 @@ Core:
* Added single axis homing commands for U and V, remapping of ABC homing commands to UVW when configured.
Plugins
Plugins:
* WebUI and Networking: fixes for compiler warnings.
+47 -23
View File
@@ -58,6 +58,13 @@ If more than 3 axes are configured a compliant driver and board map file is need
#define N_SPINDLE 1
#endif
/*! \def N_SYS_SPINDLE
\brief Defines number of simultaneously active spindles supported - minimum 1 (none), maximum 8.
*/
#if !defined N_SYS_SPINDLE || defined __DOXYGEN__
#define N_SYS_SPINDLE 1
#endif
/*! \def BUILD_INFO
\brief Defines string to be output as part of the `$I` or `$I+` command response.
*/
@@ -871,19 +878,6 @@ not throw an alarm message.
#if !defined DEFAULT_CHECK_LIMITS_AT_INIT || defined __DOXYGEN__
#define DEFAULT_CHECK_LIMITS_AT_INIT Off
#endif
/*! \def DEFAULT_LIMITS_TWO_SWITCHES_ON_AXES
\brief
If your machine has two limits switches wired in parallel to one axis, you will need to enable
this feature. Since the two switches are sharing a single pin, there is no way for grblHAL to tell
which one is enabled. This option only effects homing, where if a limit is engaged, grblHAL will
alarm out and force the user to manually disengage the limit switch. Otherwise, if you have one
limit switch for each axis, don't enable this option. By keeping it disabled, you can perform a
homing cycle while on the limit switch and not have to move the machine off of it.
*/
#if !defined DEFAULT_LIMITS_TWO_SWITCHES_ON_AXES || defined __DOXYGEN__
#define DEFAULT_LIMITS_TWO_SWITCHES_ON_AXES Off // Default disabled. Set to \ref On or 1 to enable.
#endif
///@}
/*! @name Group_Limits_DualAxis
\brief Dual axis limits settings (Group_Limits_DualAxis)
@@ -1126,15 +1120,15 @@ Requires homing cycles to be defined by \ref DEFAULT_HOMING_CYCLE_0 - \ref DEFAU
#define DEFAULT_HOMING_ENABLE Off // Default disabled. Set to \ref On or 1 to enable.
#endif
/*! /def HOMING_SINGLE_AXIS_COMMANDS
/*! /def DEFAULT_HOMING_SINGLE_AXIS_COMMANDS
\brief Enables single axis homing commands.
`$HX`, `$HY`, `$HZ` etc. for homing the respective axes.The full homing
cycle is still invoked by the `$H` command. This is disabled by default.
If you have a two-axis machine, _DON'T USE THIS_. Instead, just alter the homing cycle for two-axes.
\internal Bit 1 in settings.homing.flags.
*/
#if !defined HOMING_SINGLE_AXIS_COMMANDS || defined __DOXYGEN__
#define HOMING_SINGLE_AXIS_COMMANDS Off // Default disabled. Set to \ref On or 1 to enable.
#if !defined DEFAULT_HOMING_SINGLE_AXIS_COMMANDS || defined __DOXYGEN__
#define DEFAULT_HOMING_SINGLE_AXIS_COMMANDS Off // Default disabled. Set to \ref On or 1 to enable.
#endif
/*! /def DEFAULT_HOMING_INIT_LOCK
@@ -1148,17 +1142,32 @@ mainly a safety feature to remind the user to home, since position is unknown to
#define DEFAULT_HOMING_INIT_LOCK Off // Default disabled. Set to \ref On or 1 to enable.
#endif
/*! /def HOMING_FORCE_SET_ORIGIN
/*! /def DEFAULT_HOMING_FORCE_SET_ORIGIN
\brief
After homing, grblHAL will set by default the entire machine space into negative space, as is typical
for professional CNC machines, regardless of where the limit switches are located. Set this
define to \ref On or 1 to force grblHAL to always set the machine origin at the homed location despite switch orientation.
\internal Bit 3 in settings.homing.flags.
*/
#if !defined HOMING_FORCE_SET_ORIGIN || defined __DOXYGEN__
#define HOMING_FORCE_SET_ORIGIN Off // Default disabled. Set to \ref On or 1 to enable.
#if !defined DEFAULT_HOMING_FORCE_SET_ORIGIN || defined __DOXYGEN__
#define DEFAULT_HOMING_FORCE_SET_ORIGIN Off // Default disabled. Set to \ref On or 1 to enable.
#endif
/*! \def DEFAULT_LIMITS_TWO_SWITCHES_ON_AXES
\brief
If your machine has two limits switches wired in parallel to one axis, you will need to enable
this feature. Since the two switches are sharing a single pin, there is no way for grblHAL to tell
which one is enabled. This option only effects homing, where if a limit is engaged, grblHAL will
alarm out and force the user to manually disengage the limit switch. Otherwise, if you have one
limit switch for each axis, don't enable this option. By keeping it disabled, you can perform a
homing cycle while on the limit switch and not have to move the machine off of it.
\internal Bit 4 in settings.limits.flags.
*/
#if !defined DEFAULT_LIMITS_TWO_SWITCHES_ON_AXES || defined __DOXYGEN__
#define DEFAULT_LIMITS_TWO_SWITCHES_ON_AXES Off // Default disabled. Set to \ref On or 1 to enable.
#endif
///@}
/*! /def DEFAULT_HOMING_ALLOW_MANUAL
\brief
If enabled this allows using the homing $-commands to set the home position to the
@@ -1365,7 +1374,7 @@ greater.
// pull-out position, power-up with a time-out, and plunge back to the original position at the
// slower pull-out rate.
// NOTE: Still a work-in-progress. Machine coordinates must be in all negative space and
// does not work with HOMING_FORCE_SET_ORIGIN enabled. Parking motion also moves only in
// does not work with DEFAULT_HOMING_FORCE_SET_ORIGIN enabled. Parking motion also moves only in
// positive direction.
* // Default disabled. Uncomment to enable.
*/
@@ -1571,7 +1580,7 @@ second motor for ganged/auto squared axes.
*/
///@{
#if !defined DEFAULT_STEP_PULSE_DELAY || defined __DOXYGEN__
#define DEFAULT_STEP_PULSE_DELAY 5.0f // uncomment to set default > 0.0f
#define DEFAULT_STEP_PULSE_DELAY 0.0f
#endif
///@}
@@ -1778,6 +1787,21 @@ __NOTE:__ Must be a positive values.
#define N_TOOLS 16
#endif
#if N_SYS_SPINDLE > N_SPINDLE
#undef N_SYS_SPINDLE
#define N_SYS_SPINDLE N_SPINDLE
#endif
#if N_SYS_SPINDLE < 1
#undef N_SYS_SPINDLE
#define N_SYS_SPINDLE 1
#endif
#if N_SYS_SPINDLE > 8
#undef N_SYS_SPINDLE
#define N_SYS_SPINDLE 8
#endif
#if (REPORT_WCO_REFRESH_BUSY_COUNT < REPORT_WCO_REFRESH_IDLE_COUNT)
#error "WCO busy refresh is less than idle refresh."
#endif
@@ -1822,13 +1846,13 @@ __NOTE:__ Must be a positive values.
#if DEFAULT_PARKING_ENABLE > 0
#if DEFAULT_HOMING_FORCE_SET_ORIGIN > 0
#error "HOMING_FORCE_SET_ORIGIN is not supported with PARKING_ENABLE at this time."
#error "DEFAULT_HOMING_FORCE_SET_ORIGIN is not supported with DEFAULT_PARKING_ENABLE at this time."
#endif
#endif
#if DEFAULT_ENABLE_PARKING_OVERRIDE_CONTROL > 0
#if DEFAULT_PARKING_ENABLE < 1
#error "ENABLE_PARKING_OVERRIDE_CONTROL must be enabled with PARKING_ENABLE."
#error "DEFAULT_ENABLE_PARKING_OVERRIDE_CONTROL must be enabled with DEFAULT_PARKING_ENABLE."
#endif
#endif
+14 -10
View File
@@ -43,7 +43,7 @@ typedef enum {
OverrideChanged_FanState = 0
} override_changed_t;
/* TODO: add to grbl pointers so that a different formatting (xml, json etc) of reports may be implemented by driver?
/* TODO: add to grbl pointers so that a different formatting (xml, json etc) of reports may be implemented by a plugin?
typedef struct {
status_code_t (*report_status_message)(status_code_t status_code);
alarm_code_t (*report_alarm_message)(alarm_code_t alarm_code);
@@ -67,8 +67,8 @@ typedef message_code_t (*feedback_message_ptr)(message_code_t message_code);
typedef struct {
setting_output_ptr setting;
status_message_ptr status_message;
feedback_message_ptr feedback_message;
status_message_ptr status_message; //<! Prints system status messages.
feedback_message_ptr feedback_message; //<! Prints miscellaneous feedback messages.
} report_t;
// Core event handler and other entry points.
@@ -79,7 +79,7 @@ typedef bool (*protocol_enqueue_realtime_command_ptr)(char c);
typedef void (*on_state_change_ptr)(sys_state_t state);
typedef void (*on_override_changed_ptr)(override_changed_t override);
typedef void (*on_spindle_programmed_ptr)(spindle_state_t spindle, float rpm, spindle_rpm_mode_t mode);
typedef void (*on_spindle_programmed_ptr)(spindle_ptrs_t *spindle, spindle_state_t state, float rpm, spindle_rpm_mode_t mode);
typedef void (*on_program_completed_ptr)(program_flow_t program_flow, bool check_mode);
typedef void (*on_execute_realtime_ptr)(sys_state_t state);
typedef void (*on_unknown_accessory_override_ptr)(uint8_t cmd);
@@ -97,10 +97,12 @@ typedef void (*on_homing_completed_ptr)(void);
typedef bool (*on_probe_fixture_ptr)(tool_data_t *tool, bool at_g59_3, bool on);
typedef bool (*on_probe_start_ptr)(axes_signals_t axes, float *target, plan_line_data_t *pl_data);
typedef void (*on_probe_completed_ptr)(void);
typedef void (*on_tool_selected_ptr)(tool_data_t *tool);
typedef void (*on_toolchange_ack_ptr)(void);
typedef void (*on_reset_ptr)(void);
typedef void (*on_jog_cancel_ptr)(sys_state_t state);
typedef bool (*on_spindle_select_ptr)(spindle_id_t spindle_id);
typedef bool (*on_spindle_select_ptr)(spindle_ptrs_t *spindle);
typedef void (*on_spindle_selected_ptr)(spindle_ptrs_t *spindle);
typedef status_code_t (*on_unknown_sys_command_ptr)(sys_state_t state, char *line); // return Status_Unhandled.
typedef status_code_t (*on_user_command_ptr)(char *line);
typedef sys_commands_t *(*on_get_commands_ptr)(void);
@@ -126,7 +128,7 @@ typedef struct {
on_realtime_report_ptr on_realtime_report;
on_unknown_feedback_message_ptr on_unknown_feedback_message;
on_unknown_realtime_cmd_ptr on_unknown_realtime_cmd;
on_unknown_sys_command_ptr on_unknown_sys_command; // return Status_Unhandled if not handled.
on_unknown_sys_command_ptr on_unknown_sys_command; //!< return Status_Unhandled if not handled.
on_get_commands_ptr on_get_commands;
on_user_command_ptr on_user_command;
on_stream_changed_ptr on_stream_changed;
@@ -135,11 +137,13 @@ typedef struct {
on_probe_fixture_ptr on_probe_fixture;
on_probe_start_ptr on_probe_start;
on_probe_completed_ptr on_probe_completed;
on_toolchange_ack_ptr on_toolchange_ack; // Called from interrupt context.
on_jog_cancel_ptr on_jog_cancel; // Called from interrupt context.
on_tool_selected_ptr on_tool_selected; //!< Called prior to executing M6 or after executing M61.
on_toolchange_ack_ptr on_toolchange_ack; //!< Called from interrupt context.
on_jog_cancel_ptr on_jog_cancel; //!< Called from interrupt context.
on_laser_ppi_enable_ptr on_laser_ppi_enable;
on_spindle_select_ptr on_spindle_select;
on_reset_ptr on_reset; // Called from interrupt context.
on_spindle_select_ptr on_spindle_select; //!< Called before spindle is selected, hook in HAL overrides here
on_spindle_selected_ptr on_spindle_selected; //!< Called when spindle is selected, do not change HAL pointers here!
on_reset_ptr on_reset; //!< Called from interrupt context.
// core entry points - set up by core before driver_init() is called.
enqueue_gcode_ptr enqueue_gcode;
enqueue_realtime_command_ptr enqueue_realtime_command;
+15 -2
View File
@@ -132,6 +132,13 @@
#define I2C_STROBE_ENABLE 0
#endif
#if DISPLAY_ENABLE == 2
#ifdef I2C_ENABLE
#undef I2C_ENABLE
#endif
#define I2C_ENABLE 1
#endif
#ifndef EEPROM_ENABLE
#define EEPROM_ENABLE 0
#endif
@@ -333,10 +340,13 @@
#define FTP_ENABLE 0
#endif
#ifndef MDNS_ENABLE
#define MDNS_ENABLE 0
#define MDNS_ENABLE 0
#endif
#ifndef SSDP_ENABLE
#define SSDP_ENABLE 0
#define SSDP_ENABLE 0
#endif
#ifndef MQTT_ENABLE
#define MQTT_ENABLE 0
#endif
#if ETHERNET_ENABLE || WIFI_ENABLE
@@ -364,6 +374,9 @@
#ifndef NETWORK_HTTP_PORT
#define NETWORK_HTTP_PORT 80
#endif
#ifndef NETWORK_MQTT_PORT
#define NETWORK_MQTT_PORT 1883
#endif
#ifndef NETWORK_WEBSOCKET_PORT
#if HTTP_ENABLE
#define NETWORK_WEBSOCKET_PORT 81
+190 -93
View File
File diff suppressed because it is too large Load Diff
+28 -20
View File
@@ -196,8 +196,19 @@ typedef enum {
Override_Parking = 56 //!< 56 - M56
} override_mode_t;
/*! Modal Group M10: User/driver/plugin defined M commands
/*! Modal Group M10: i/o control */
typedef enum {
IoMCode_OutputOnSynced = 62, //!< 62 - M62
IoMCode_OutputOffSynced = 63, //!< 63 - M63
IoMCode_OutputOnImmediate = 64, //!< 64 - M64
IoMCode_OutputOffImmediate = 65, //!< 65 - M65
IoMCode_WaitOnInput = 66, //!< 66 - M66
IoMCode_AnalogOutSynced = 67, //!< 67 - M67
IoMCode_AnalogOutImmediate = 68, //!< 68 - M68
} io_mcode_t;
/*! Modal Group M10: User/driver/plugin defined M commands
__NOTE:__ Not used by the core, may be used by private user code, drivers or plugins.
*/
typedef enum {
@@ -213,8 +224,8 @@ typedef enum {
OpenPNP_GetCurrentPosition = 114, //!< 114 - M114
OpenPNP_FirmwareInfo = 115, //!< 115 - M115
Trinamic_DebugReport = 122, //!< 122 - M122, Marlin format
Trinamic_ReadRegister = 123, //!< 123 - M123,
Trinamic_WriteRegister = 124, //!< 124 - M124,
Trinamic_ReadRegister = 123, //!< 123 - M123
Trinamic_WriteRegister = 124, //!< 124 - M124
LaserPPI_Enable = 126, //!< 126 - M126
LaserPPI_Rate = 127, //!< 127 - M127
LaserPPI_PulseLength = 128, //!< 128 - M128
@@ -405,6 +416,11 @@ typedef union {
};
} parameter_words_t;
typedef struct {
spindle_state_t state; //!< {M3,M4,M5}
spindle_rpm_mode_t rpm_mode; //!< {G96,G97}
} spindle_mode_t;
// NOTE: When this struct is zeroed, the above defines set the defaults for the system.
typedef struct {
motion_mode_t motion; //!< {G0,G1,G2,G3,G38.2,G80}
@@ -420,9 +436,8 @@ typedef struct {
// control_mode_t control; //!< {G61} NOTE: Don't track. Only default supported.
program_flow_t program_flow; //!< {M0,M1,M2,M30,M60}
coolant_state_t coolant; //!< {M7,M8,M9}
spindle_state_t spindle; //!< {M3,M4,M5}
spindle_mode_t spindle; //!< {M3,M4,M5 and G96,G97}
gc_override_flags_t override_ctrl; //!< {M48,M49,M50,M51,M53,M56}
spindle_rpm_mode_t spindle_rpm_mode; //!< {G96,G97}
cc_retract_mode_t retract_mode; //!< {G98,G99}
bool scaling_active; //!< {G50,G51}
bool canned_cycle_active;
@@ -472,24 +487,15 @@ typedef struct {
uint32_t tool; //!< Tool number
} tool_data_t;
// Data used for Constant Surface Speed (CSS) mode calculations.
typedef struct {
float surface_speed; //!< Surface speed in millimeters/min
float target_rpm; //!< Target RPM at end of movement
float max_rpm; //!< Maximum spindle RPM
float tool_offset; //!< Tool offset
uint_fast8_t axis; //!< Linear (tool) axis
bool active;
} css_data_t;
typedef struct {
float rpm; //!< RPM
css_data_t css; //!< Data used for Constant Surface Speed Mode calculations
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;
@@ -541,8 +547,8 @@ typedef struct {
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; //
int32_t spindle_id; //!< Spindle to control, -1 for all
uint32_t arc_turns; //
spindle_ptrs_t *spindle; //!< Spindle to control, NULL for all
} parser_block_t;
// Initialize the parser
@@ -572,6 +578,8 @@ float *gc_get_scaling (void);
// Get current axis offset.
float gc_get_offset (uint_fast8_t idx);
spindle_ptrs_t *gc_spindle_get (void);
void gc_spindle_off (void);
void gc_coolant_off (void);
+19 -3
View File
@@ -42,7 +42,7 @@
#else
#define GRBL_VERSION "1.1f"
#endif
#define GRBL_BUILD 20230129
#define GRBL_BUILD 20230213
#define GRBL_URL "https://github.com/grblHAL"
@@ -163,8 +163,12 @@
// allowable override values and the coarse and fine increments per command received. Please
// note the allowable values in the descriptions following each define.
#define DEFAULT_FEED_OVERRIDE 100 // 100%. Don't change this value.
#define MAX_FEED_RATE_OVERRIDE 200 // Percent of programmed feed rate (100-255). Usually 120% or 200%
#ifndef MAX_FEED_RATE_OVERRIDE
#define MAX_FEED_RATE_OVERRIDE 200 // Percent of programmed feed rate (100-65535). Usually 120% or 200%
#endif
#ifndef MIN_FEED_RATE_OVERRIDE
#define MIN_FEED_RATE_OVERRIDE 10 // Percent of programmed feed rate (1-100). Usually 50% or 1%
#endif
#define FEED_OVERRIDE_COARSE_INCREMENT 10 // (1-99). Usually 10%.
#define FEED_OVERRIDE_FINE_INCREMENT 1 // (1-99). Usually 1%.
@@ -176,8 +180,12 @@
// #define ENABLE_SPINDLE_LINEARIZATION // Uncomment to enable spindle RPM linearization. Requires compatible driver if enabled.
#define SPINDLE_NPWM_PIECES 4 // Maximum number of pieces for spindle RPM linearization, do not change unless more are needed.
#define DEFAULT_SPINDLE_RPM_OVERRIDE 100 // 100%. Don't change this value.
#define MAX_SPINDLE_RPM_OVERRIDE 200 // Percent of programmed spindle speed (100-255). Usually 200%.
#ifndef MAX_SPINDLE_RPM_OVERRIDE
#define MAX_SPINDLE_RPM_OVERRIDE 200 // Percent of programmed spindle speed (100-65535). Usually 200%.
#endif
#ifndef MIN_SPINDLE_RPM_OVERRIDE
#define MIN_SPINDLE_RPM_OVERRIDE 10 // Percent of programmed spindle speed (1-100). Usually 10%.
#endif
#define SPINDLE_OVERRIDE_COARSE_INCREMENT 10 // (1-99). Usually 10%.
#define SPINDLE_OVERRIDE_FINE_INCREMENT 1 // (1-99). Usually 1%.
@@ -221,4 +229,12 @@
#define MAX_STORED_LINE_LENGTH 70 // do not set > 70 unless less than 5 axes are enabled or COMPATIBILITY_LEVEL > 1
#endif
#if N_SPINDLE > 4
#define N_SPINDLE_SELECTABLE 4 // Max 4. for now!
#else
#define N_SPINDLE_SELECTABLE N_SPINDLE
#endif
typedef uint_fast16_t override_t;
#endif
+12 -7
View File
@@ -203,13 +203,15 @@ int grbl_enter (void)
if(driver.ok == 0xFF)
driver.setup = hal.driver_setup(&settings);
spindle_select(settings.spindle.flags.type);
#ifdef ENABLE_SPINDLE_LINEARIZATION
driver.linearization = hal.driver_cap.spindle_pwm_linearization;
#endif
driver.spindle = hal.spindle.get_pwm == NULL || hal.spindle.update_pwm != NULL;
if((driver.spindle = spindle_select(settings.spindle.flags.type))) {
spindle_ptrs_t *spindle = spindle_get(0);
driver.spindle = spindle->get_pwm == NULL || spindle->update_pwm != NULL;
} else
driver.spindle = spindle_select(spindle_add_null());
if(driver.ok != 0xFF) {
sys.alarm = Alarm_SelftestFailed;
@@ -218,9 +220,7 @@ int grbl_enter (void)
hal.stepper.enable(settings.steppers.deenergize);
if(hal.spindle.set_state)
hal.spindle.set_state((spindle_state_t){0}, 0.0f);
spindle_all_off();
hal.coolant.set_state((coolant_state_t){0});
if(hal.get_position)
@@ -253,6 +253,8 @@ int grbl_enter (void)
// will return to this loop to be cleanly re-initialized.
while(looping) {
spindle_num_t spindle_num = N_SYS_SPINDLE;
// Reset report entry points
report_init_fns();
@@ -264,7 +266,10 @@ int grbl_enter (void)
sys.var5399 = -2; // Clear last M66 result
sys.override.feed_rate = DEFAULT_FEED_OVERRIDE; // Set to 100%
sys.override.rapid_rate = DEFAULT_RAPID_OVERRIDE; // Set to 100%
sys.override.spindle_rpm = DEFAULT_SPINDLE_RPM_OVERRIDE; // Set to 100%
do {
if(spindle_is_enabled(--spindle_num))
spindle_get(spindle_num)->param->override_pct = DEFAULT_SPINDLE_RPM_OVERRIDE; // Set to 100%
} while(spindle_num);
sys.flags.auto_reporting = settings.report_interval != 0;
if(settings.parking.flags.enabled)
+1 -1
View File
@@ -583,7 +583,7 @@ typedef struct {
homing_ptrs_t homing; //!< Handlers for limit switches, used by homing cycle.
control_signals_ptrs_t control; //!< Handlers for control switches.
coolant_ptrs_t coolant; //!< Handlers for coolant.
spindle_ptrs_t spindle; //!< Handlers for spindle.
spindle_data_ptrs_t spindle_data; //!< Handlers for getting/resetting spindle data (RPM, angular position, ...).
stepper_ptrs_t stepper; //!< Handlers for stepper motors.
io_stream_t stream; //!< Handlers for stream I/O.
stream_select_ptr stream_select; //!< Optional handler for switching between I/O streams.
+5 -8
View File
@@ -161,7 +161,6 @@ static bool limits_pull_off (axes_signals_t axis, float distance)
} while(idx);
plan_data.feed_rate = settings.homing.seek_rate * sqrtf(n_axis); // Adjust so individual axes all move at pull-off rate.
plan_data.condition.spindle = gc_state.modal.spindle;
plan_data.condition.coolant = gc_state.modal.coolant;
memcpy(&plan_data.spindle, &gc_state.spindle, sizeof(spindle_t));
@@ -250,16 +249,14 @@ static bool limits_homing_cycle (axes_signals_t cycle, axes_signals_t auto_squar
limit_signals_t limits_state;
squaring_mode_t squaring_mode = SquaringMode_Both;
coord_data_t target;
plan_line_data_t plan_data;
plan_line_data_t plan_data = {
.condition.system_motion = On,
.condition.no_feed_override = On,
.line_number = DEFAULT_HOMING_CYCLE_LINE_NUMBER
};
// Initialize plan data struct for homing motion.
memset(&plan_data, 0, sizeof(plan_line_data_t));
plan_data.condition.system_motion = On;
plan_data.condition.no_feed_override = On;
plan_data.line_number = DEFAULT_HOMING_CYCLE_LINE_NUMBER;
memcpy(&plan_data.spindle, &gc_state.spindle, sizeof(spindle_t));
plan_data.condition.spindle = gc_state.modal.spindle;
plan_data.condition.coolant = gc_state.modal.coolant;
uint_fast8_t idx = N_AXIS;
+11 -11
View File
@@ -176,9 +176,9 @@ bool mc_line (float *target, plan_line_data_t *pl_data)
// Plan and queue motion into planner buffer.
// While in M3 laser mode also set spindle state and force a buffer sync
// if there is a coincident position passed.
if(!plan_buffer_line(target, pl_data) && sys.mode == Mode_Laser && pl_data->condition.spindle.on && !pl_data->condition.spindle.ccw) {
if(!plan_buffer_line(target, pl_data) && pl_data->spindle.hal->cap.laser && pl_data->spindle.state.on && !pl_data->spindle.state.ccw) {
protocol_buffer_synchronize();
hal.spindle.set_state(pl_data->condition.spindle, pl_data->spindle.rpm);
pl_data->spindle.hal->set_state(pl_data->spindle.state, pl_data->spindle.rpm);
}
#ifdef KINEMATICS_API
@@ -582,7 +582,7 @@ void mc_canned_drill (motion_mode_t motion, float *target, plan_line_data_t *pl_
mc_dwell(canned->dwell);
if(canned->spindle_off)
hal.spindle.set_state((spindle_state_t){0}, 0.0f);
pl_data->spindle.hal->set_state((spindle_state_t){0}, 0.0f);
// rapid retract
switch(motion) {
@@ -603,7 +603,7 @@ void mc_canned_drill (motion_mode_t motion, float *target, plan_line_data_t *pl_
return;
if(canned->spindle_off)
spindle_sync(0, gc_state.modal.spindle, pl_data->spindle.rpm);
spindle_sync(pl_data->spindle.hal, gc_state.modal.spindle.state, pl_data->spindle.rpm);
}
// rapid move to next position if incremental mode
@@ -670,7 +670,7 @@ void mc_thread (plan_line_data_t *pl_data, float *position, gc_thread_data *thre
// TODO: Add to initial move to compensate for acceleration distance?
/*
float acc_distance = pl_data->feed_rate * hal.spindle.get_data(SpindleData_RPM)->rpm / settings.acceleration[Z_AXIS];
float acc_distance = pl_data->feed_rate * pl_data->spindle.hal->get_data(SpindleData_RPM)->rpm / settings.acceleration[Z_AXIS];
acc_distance = acc_distance * acc_distance * settings.acceleration[Z_AXIS] * 0.5f;
*/
@@ -694,9 +694,9 @@ void mc_thread (plan_line_data_t *pl_data, float *position, gc_thread_data *thre
if(!protocol_buffer_synchronize() && state_get() != STATE_IDLE) // Wait until any previous moves are finished.
return;
pl_data->condition.rapid_motion = Off; // Clear rapid motion condition flag,
pl_data->condition.spindle.synchronized = On; // enable spindle sync for cut
pl_data->overrides.feed_hold_disable = On; // and disable feed hold
pl_data->condition.rapid_motion = Off; // Clear rapid motion condition flag,
pl_data->spindle.state.synchronized = On; // enable spindle sync for cut
pl_data->overrides.feed_hold_disable = On; // and disable feed hold
// Cut thread pass
@@ -723,8 +723,8 @@ void mc_thread (plan_line_data_t *pl_data, float *position, gc_thread_data *thre
return;
}
pl_data->condition.rapid_motion = On; // Set rapid motion condition flag and
pl_data->condition.spindle.synchronized = Off; // disable spindle sync for retract & reposition
pl_data->condition.rapid_motion = On; // Set rapid motion condition flag and
pl_data->spindle.state.synchronized = Off; // disable spindle sync for retract & reposition
if(passes > 1) {
@@ -861,7 +861,7 @@ status_code_t mc_homing_cycle (axes_signals_t cycle)
hal.limits.enable(false, true); // Disable hard limits pin change register for cycle duration
// Turn off spindle and coolant (and update parser state)
if(hal.spindle.get_state().on)
if(spindle_is_on())
gc_spindle_off();
if(hal.coolant.get_state().mask)
+5 -5
View File
@@ -3,7 +3,7 @@
Part of grblHAL
Copyright (c) 2021 Terje Io
Copyright (c) 2021-2023 Terje Io
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -424,11 +424,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_state.modal.spindle.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_state.modal.spindle.rpm_mode == SpindleSpeedMode_CSS ? 1.0f : 0.0f;
break;
case NGCParam_ijk_absolute_mode:
@@ -444,11 +444,11 @@ float ngc_named_param_get_by_id (ncg_name_param_id_t id)
break;
case NGCParam_spindle_on:
value = gc_state.modal.spindle.on ? 1.0f : 0.0f;
value = gc_state.modal.spindle.state.on ? 1.0f : 0.0f;
break;
case NGCParam_spindle_cw:
value = gc_state.modal.spindle.ccw ? 1.0f : 0.0f;
value = gc_state.modal.spindle.state.ccw ? 1.0f : 0.0f;
break;
case NGCParam_mist:
+21 -18
View File
@@ -315,13 +315,13 @@ bool plan_check_full_buffer (void)
// NOTE: All system motion commands, such as homing/parking, are not subject to overrides.
float plan_compute_profile_nominal_speed (plan_block_t *block)
{
float nominal_speed = block->condition.spindle.synchronized ? block->programmed_rate * hal.spindle.get_data(SpindleData_RPM)->rpm : block->programmed_rate;
float nominal_speed = block->spindle.state.synchronized ? block->programmed_rate * block->spindle.hal->get_data(SpindleData_RPM)->rpm : block->programmed_rate;
if (block->condition.rapid_motion)
nominal_speed *= (0.01f * sys.override.rapid_rate);
nominal_speed *= (0.01f * (float)sys.override.rapid_rate);
else {
if (!block->condition.no_feed_override)
nominal_speed *= (0.01f * sys.override.feed_rate);
nominal_speed *= (0.01f * (float)sys.override.feed_rate);
if (nominal_speed > block->rapid_rate)
nominal_speed = block->rapid_rate;
}
@@ -465,21 +465,24 @@ bool plan_buffer_line (float *target, plan_line_data_t *pl_data)
} while(idx);
// Calculate RPMs to be used for Constant Surface Speed calculations
if(block->condition.is_rpm_pos_adjusted) {
// Calculate RPMs to be used for Constant Surface Speed (CSS) calculations.
if(block->spindle.css) {
float pos;
if((pos = (float)position_steps[block->spindle.css.axis] / settings.axis[block->spindle.css.axis].steps_per_mm - block->spindle.css.tool_offset) > 0.0f) {
block->spindle.rpm = block->spindle.css.surface_speed / (pos * (float)(2.0f * M_PI));
if(block->spindle.rpm > block->spindle.css.max_rpm)
block->spindle.rpm = block->spindle.css.max_rpm;
if((pos = (float)position_steps[block->spindle.css->axis] / settings.axis[block->spindle.css->axis].steps_per_mm - block->spindle.css->tool_offset) > 0.0f) {
if((block->spindle.rpm = block->spindle.css->surface_speed / (pos * (float)(2.0f * M_PI))) > block->spindle.css->max_rpm)
block->spindle.rpm = block->spindle.css->max_rpm;
} else
block->spindle.rpm = block->spindle.css.max_rpm;
if((pos = target[block->spindle.css.axis] - block->spindle.css.tool_offset) > 0.0f) {
block->spindle.css.target_rpm = block->spindle.css.surface_speed / (pos * (float)(2.0f * M_PI));
if(block->spindle.css.target_rpm > block->spindle.css.max_rpm)
block->spindle.css.target_rpm = block->spindle.css.max_rpm;
block->spindle.rpm = block->spindle.css->max_rpm;
if((pos = target[block->spindle.css->axis] - block->spindle.css->tool_offset) > 0.0f) {
if((block->spindle.css->target_rpm = block->spindle.css->surface_speed / (pos * (float)(2.0f * M_PI))) > block->spindle.css->max_rpm)
block->spindle.css->target_rpm = block->spindle.css->max_rpm;
} else
block->spindle.css.target_rpm = block->spindle.css.max_rpm;
block->spindle.css->target_rpm = block->spindle.css->max_rpm;
block->spindle.css->delta_rpm = block->spindle.css->target_rpm - block->spindle.rpm;
}
// Bail if this is a zero-length block. Highly unlikely to occur.
@@ -662,7 +665,7 @@ void plan_cycle_reinitialize (void)
}
// Set feed overrides
void plan_feed_override (uint_fast8_t feed_override, uint_fast8_t rapid_override)
void plan_feed_override (override_t feed_override, override_t rapid_override)
{
bool feedrate_changed = false, rapidrate_changed = false;
@@ -673,8 +676,8 @@ void plan_feed_override (uint_fast8_t feed_override, uint_fast8_t rapid_override
if ((feedrate_changed = feed_override != sys.override.feed_rate) ||
(rapidrate_changed = rapid_override != sys.override.rapid_rate)) {
sys.override.feed_rate = (uint8_t)feed_override;
sys.override.rapid_rate = (uint8_t)rapid_override;
sys.override.feed_rate = feed_override;
sys.override.rapid_rate = rapid_override;
sys.report.overrides = On; // Set to report change immediately
plan_update_velocity_profile_parameters();
plan_cycle_reinitialize();
+15 -17
View File
@@ -3,7 +3,7 @@
Part of grblHAL
Copyright (c) 2019-2022 Terje Io
Copyright (c) 2019-2023 Terje Io
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
@@ -34,10 +34,8 @@ typedef union {
no_feed_override :1,
inverse_time :1,
is_rpm_rate_adjusted :1,
is_rpm_pos_adjusted :1,
is_laser_ppi_mode :1,
unassigned :7;
spindle_state_t spindle;
unassigned :8;
coolant_state_t coolant;
};
} planner_cond_t;
@@ -58,22 +56,22 @@ typedef struct plan_block {
// Fields used by the motion planner to manage acceleration. Some of these values may be updated
// by the stepper module during execution of special motion cases for replanning purposes.
float entry_speed_sqr; // The current planned entry speed at block junction in (mm/min)^2
float max_entry_speed_sqr; // Maximum allowable entry speed based on the minimum of junction limit and
// neighboring nominal speeds with overrides in (mm/min)^2
float acceleration; // Axis-limit adjusted line acceleration in (mm/min^2). Does not change.
float millimeters; // The remaining distance for this block to be executed in (mm).
// NOTE: This value may be altered by stepper algorithm during execution.
float entry_speed_sqr; // The current planned entry speed at block junction in (mm/min)^2
float max_entry_speed_sqr; // Maximum allowable entry speed based on the minimum of junction limit and
// neighboring nominal speeds with overrides in (mm/min)^2
float acceleration; // Axis-limit adjusted line acceleration in (mm/min^2). Does not change.
float millimeters; // The remaining distance for this block to be executed in (mm).
// NOTE: This value may be altered by stepper algorithm during execution.
// Stored rate limiting data used by planner when changes occur.
float max_junction_speed_sqr; // Junction entry speed limit based on direction vectors in (mm/min)^2
float rapid_rate; // Axis-limit adjusted maximum rate for this block direction in (mm/min)
float programmed_rate; // Programmed rate of this block (mm/min).
float max_junction_speed_sqr; // Junction entry speed limit based on direction vectors in (mm/min)^2
float rapid_rate; // Axis-limit adjusted maximum rate for this block direction in (mm/min)
float programmed_rate; // Programmed rate of this block (mm/min).
// Stored spindle speed data used by spindle overrides and resuming methods.
spindle_t spindle; // Block spindle speed. Copied from pl_line_data.
spindle_t spindle; // Block spindle parameters. Copied from pl_line_data.
char *message; // Message to be displayed when block is executed.
char *message; // Message to be displayed when block is executed.
output_command_t *output_commands;
struct plan_block *prev, *next; // Linked list pointers, DO NOT MOVE - these MUST be the last elements in the struct!
} plan_block_t;
@@ -83,7 +81,7 @@ typedef struct plan_block {
typedef struct {
float feed_rate; // Desired feed rate for line motion. Value is ignored, if rapid motion.
// float blending_tolerance; // Motion blending tolerance
spindle_t spindle; // Desired spindle speed through line motion.
spindle_t spindle; // Desired spindle parameters, such as RPM, through line motion.
planner_cond_t condition; // Bitfield variable to indicate planner conditions. See defines above.
gc_override_flags_t overrides; // Block bitfield variable for overrides
int32_t line_number; // Desired line number to report when executing.
@@ -143,6 +141,6 @@ uint_fast16_t plan_get_block_buffer_available (void);
// Returns the status of the block ring buffer. True, if buffer is full.
bool plan_check_full_buffer (void);
void plan_feed_override (uint_fast8_t feed_override, uint_fast8_t rapid_override);
void plan_feed_override (override_t feed_override, override_t rapid_override);
#endif
+22 -6
View File
@@ -65,9 +65,18 @@ typedef union {
} network_services_t;
typedef char ssid_t[65];
typedef uint8_t bssid_t[6];
typedef char username_t[33];
typedef char password_t[33];
typedef char hostname_t[33];
typedef char sntp_server_t[129]; // URI
typedef char uri_t[65];
typedef struct {
char ip[16];
uint16_t port;
username_t user;
password_t password;
} mqtt_settings_t;
typedef struct {
char ip[16];
@@ -80,6 +89,9 @@ typedef struct {
uint16_t ftp_port;
ip_mode_t ip_mode;
network_services_t services;
#if MQTT_ENABLE
mqtt_settings_t mqtt;
#endif
} network_settings_t;
typedef enum {
@@ -94,12 +106,14 @@ typedef struct {
bool link_up;
uint16_t mbps;
char mac[18];
char mqtt_client_id[18];
grbl_wifi_mode_t wifi_mode;
network_settings_t status;
} network_info_t;
typedef struct {
ssid_t ssid;
bssid_t bssid;
password_t password;
char country[4];
uint8_t channel;
@@ -149,11 +163,13 @@ typedef enum {
typedef union {
uint8_t events;
struct {
uint8_t position_changed :1,
click :1,
dbl_click :1,
long_click :1,
index_pulse :1;
uint8_t position_changed :1,
direction_changed :1,
click :1,
dbl_click :1,
long_click :1,
index_pulse :1,
unused :2;
};
} encoder_event_t;
+10 -5
View File
@@ -43,11 +43,6 @@
vfd_init();
#endif
#if N_SPINDLE > 1
extern void spindle_select_init(void);
spindle_select_init();
#endif
#ifndef GRBL_ESP32 // ESP32 has its own bluetooth_init
#if BLUETOOTH_ENABLE
extern void bluetooth_init (void);
@@ -93,6 +88,11 @@
extern void my_plugin_init (void);
my_plugin_init();
#if N_SPINDLE > 1
extern void spindle_select_init(void);
spindle_select_init();
#endif
// Third party plugin definitions.
// The code for these has to be downloaded from the source and placed in the same folder as driver.c
// Note: Third party plugins may have more than one implementation, there is no "owner" of plugins listed here.
@@ -108,6 +108,11 @@
probe_relay_init();
#endif
#if DISPLAY_ENABLE
void display_init (void);
display_init();
#endif
#if STATUS_LIGHT_ENABLE
extern void status_light_init (void);
status_light_init();
+16 -14
View File
@@ -180,7 +180,7 @@ bool protocol_main_loop (void)
// Ensure spindle and coolant is switched off on a cold start
if(sys.cold_start) {
hal.spindle.set_state((spindle_state_t){0}, 0.0f);
spindle_all_off();
hal.coolant.set_state((coolant_state_t){0});
if(realtime_queue.head != realtime_queue.tail)
system_set_exec_state_flag(EXEC_RT_COMMAND); // execute any boot up commands
@@ -411,7 +411,7 @@ bool protocol_exec_rt_system (void)
if((sys.reset_pending = !!(sys.rt_exec_state & EXEC_RESET))) {
// Kill spindle and coolant.
killed = true;
hal.spindle.set_state((spindle_state_t){0}, 0.0f);
spindle_all_off();
hal.coolant.set_state((coolant_state_t){0});
}
@@ -468,7 +468,7 @@ bool protocol_exec_rt_system (void)
if(!killed) {
// Kill spindle and coolant.
hal.spindle.set_state((spindle_state_t){0}, 0.0f);
spindle_all_off();
hal.coolant.set_state((coolant_state_t){0});
}
@@ -500,11 +500,7 @@ 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;
// Kill spindle and coolant. TODO: Check Mach3 behaviour?
gc_spindle_off();
gc_coolant_off();
gc_state.modal.spindle.rpm_mode = SpindleSpeedMode_RPM;
// Tell driver/plugins about reset.
hal.driver_reset();
@@ -523,6 +519,11 @@ bool protocol_exec_rt_system (void)
} else*/
st_reset();
sync_position();
// Kill spindle and coolant. TODO: Check Mach3 behaviour?
gc_spindle_off();
gc_coolant_off();
flush_override_buffers();
if(!((state_get() == STATE_ALARM) && (sys.alarm == Alarm_LimitsEngaged || sys.alarm == Alarm_HomingRequried)))
state_set(hal.control.get_state().safety_door_ajar ? STATE_SAFETY_DOOR : STATE_IDLE);
@@ -567,8 +568,8 @@ bool protocol_exec_rt_system (void)
if((rt_exec = get_feed_override())) {
int_fast16_t new_f_override = sys.override.feed_rate;
uint_fast8_t new_r_override = sys.override.rapid_rate;
override_t new_f_override = sys.override.feed_rate;
override_t new_r_override = sys.override.rapid_rate;
do {
@@ -611,13 +612,14 @@ bool protocol_exec_rt_system (void)
} while((rt_exec = get_feed_override()));
plan_feed_override((uint_fast8_t)new_f_override, new_r_override);
plan_feed_override(new_f_override, new_r_override);
}
if((rt_exec = get_accessory_override())) {
bool spindle_stop = false;
int_fast16_t last_s_override = sys.override.spindle_rpm;
spindle_ptrs_t *spindle = gc_spindle_get();
override_t last_s_override = spindle->param->override_pct;
coolant_state_t coolant_state = gc_state.modal.coolant;
do {
@@ -670,7 +672,7 @@ bool protocol_exec_rt_system (void)
} while((rt_exec = get_accessory_override()));
spindle_set_override((uint_fast8_t)last_s_override);
spindle_set_override(spindle, last_s_override);
// NOTE: Since coolant state always performs a planner sync whenever it changes, the current
// run state can be determined by checking the parser state.
@@ -681,7 +683,7 @@ bool protocol_exec_rt_system (void)
grbl.on_override_changed(OverrideChanged_CoolantState);
}
if (spindle_stop && state_get() == STATE_HOLD && gc_state.modal.spindle.on) {
if (spindle_stop && state_get() == STATE_HOLD && gc_state.modal.spindle.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)
+75 -25
View File
@@ -53,6 +53,8 @@ static uint8_t wco_counter = 0; // Tracks when to add work coordinate offse
static const char vbar[2] = { '|', '\0' };
static bool report_setting (const setting_detail_t *setting, uint_fast16_t offset, void *data);
static status_code_t report_status_message (status_code_t status_code);
static message_code_t report_feedback_message (message_code_t id);
static const report_t report_fns = {
.setting = report_setting,
@@ -230,7 +232,7 @@ void report_init_fns (void)
// operation. Errors events can originate from the g-code parser, settings module, or asynchronously
// from a critical error, such as a triggered hard limit. Interface should always monitor for these
// responses.
status_code_t report_status_message (status_code_t status_code)
static status_code_t report_status_message (status_code_t status_code)
{
switch(status_code) {
@@ -284,7 +286,7 @@ void report_message (const char *msg, message_type_t type)
// messages such as setup warnings, switch toggling, and how to exit alarms.
// NOTE: For interfaces, messages are always placed within brackets. And if silent mode
// is installed, the message number codes are less than zero.
message_code_t report_feedback_message (message_code_t id)
static message_code_t report_feedback_message (message_code_t id)
{
const char *msg = NULL;
uint_fast16_t idx = 0;
@@ -681,7 +683,7 @@ void report_gcode_modes (void)
#endif
if(sys.mode == Mode_Lathe)
if(settings.mode == Mode_Lathe)
hal.stream.write(gc_state.modal.diameter_mode ? " G7" : " G8");
hal.stream.write(" G");
@@ -694,8 +696,8 @@ void report_gcode_modes (void)
hal.stream.write(" G");
hal.stream.write(uitoa((uint32_t)(94 - gc_state.modal.feed_mode)));
if(sys.mode == Mode_Lathe && hal.spindle.cap.variable)
hal.stream.write(gc_state.modal.spindle_rpm_mode == SpindleSpeedMode_RPM ? " G97" : " G96");
if(settings.mode == Mode_Lathe && gc_spindle_get()->cap.variable)
hal.stream.write(gc_state.modal.spindle.rpm_mode == SpindleSpeedMode_RPM ? " G97" : " G96");
#if COMPATIBILITY_LEVEL < 10
@@ -747,7 +749,7 @@ void report_gcode_modes (void)
}
}
hal.stream.write(gc_state.modal.spindle.on ? (gc_state.modal.spindle.ccw ? " M4" : " M3") : " M5");
hal.stream.write(gc_state.modal.spindle.state.on ? (gc_state.modal.spindle.state.ccw ? " M4" : " M3") : " M5");
if(gc_state.tool_change)
hal.stream.write(" M6");
@@ -779,7 +781,7 @@ void report_gcode_modes (void)
hal.stream.write(appendbuf(2, " F", get_rate_value(gc_state.feed_rate)));
if(hal.spindle.cap.variable)
if(gc_spindle_get()->cap.variable)
hal.stream.write(appendbuf(2, " S", ftoa(gc_state.spindle.rpm, N_DECIMAL_RPMVALUE)));
hal.stream.write("]" ASCII_EOL);
@@ -1177,19 +1179,41 @@ void report_realtime_status (void)
hal.stream.write_all(appendbuf(2, "|Ln:", uitoa((uint32_t)cur_block->line_number)));
}
spindle_state_t sp_state = hal.spindle.get_state();
spindle_ptrs_t *spindle_0;
spindle_state_t spindle_0_state;
spindle_0 = spindle_get(0);
spindle_0_state = spindle_0->get_state();
// Report realtime feed speed
if(settings.status_report.feed_speed) {
if(hal.spindle.cap.variable) {
if(spindle_0->cap.variable) {
hal.stream.write_all(appendbuf(2, "|FS:", get_rate_value(st_get_realtime_rate())));
hal.stream.write_all(appendbuf(2, ",", uitoa(sp_state.on ? lroundf(sys.spindle_rpm) : 0)));
if(hal.spindle.get_data /* && sys.mpg_mode */)
hal.stream.write_all(appendbuf(2, ",", uitoa(lroundf(hal.spindle.get_data(SpindleData_RPM)->rpm))));
hal.stream.write_all(appendbuf(2, ",", uitoa(spindle_0_state.on ? lroundf(spindle_0->param->rpm_overridden) : 0)));
if(spindle_0->get_data /* && sys.mpg_mode */)
hal.stream.write_all(appendbuf(2, ",", uitoa(lroundf(spindle_0->get_data(SpindleData_RPM)->rpm))));
} else
hal.stream.write_all(appendbuf(2, "|F:", get_rate_value(st_get_realtime_rate())));
}
#if N_SYS_SPINDLE > 1
for(idx = 1; idx < N_SYS_SPINDLE; idx++) {
spindle_ptrs_t *spindle_n;
spindle_state_t spindle_n_state;
if((spindle_n = spindle_get(idx))) {
spindle_n_state = spindle_n->get_state();
hal.stream.write_all(appendbuf(3, "|SP", uitoa(idx), ":"));
hal.stream.write_all(appendbuf(3, uitoa(spindle_n_state.on ? lroundf(spindle_n->param->rpm_overridden) : 0), ",,", spindle_n_state.on ? (spindle_n_state.ccw ? "C" : "S") : ""));
if(settings.status_report.overrides)
hal.stream.write_all(appendbuf(2, ",", uitoa(spindle_n->param->override_pct)));
}
}
#endif
if(settings.status_report.pin_state) {
axes_signals_t lim_pin_state = limit_signals_merge(hal.limits.get_state());
@@ -1236,7 +1260,7 @@ void report_realtime_status (void)
if (override_counter > 0 && !sys.report.overrides)
override_counter--;
else if((sys.report.overrides = !sys.report.wco)) {
sys.report.spindle = sys.report.spindle || hal.spindle.get_state().on;
sys.report.spindle = sys.report.spindle || spindle_0_state.on;
sys.report.coolant = sys.report.coolant || hal.coolant.get_state().value != 0;
override_counter = state_get() & (STATE_HOMING|STATE_CYCLE|STATE_HOLD|STATE_JOG|STATE_SAFETY_DOOR)
? (REPORT_OVERRIDE_REFRESH_BUSY_COUNT - 1) // Reset counter for slow refresh
@@ -1260,7 +1284,7 @@ void report_realtime_status (void)
if(sys.report.overrides) {
hal.stream.write_all(appendbuf(2, "|Ov:", uitoa((uint32_t)sys.override.feed_rate)));
hal.stream.write_all(appendbuf(2, ",", uitoa((uint32_t)sys.override.rapid_rate)));
hal.stream.write_all(appendbuf(2, ",", uitoa((uint32_t)sys.override.spindle_rpm)));
hal.stream.write_all(appendbuf(2, ",", uitoa((uint32_t)spindle_0->param->override_pct)));
}
if(sys.report.spindle || sys.report.coolant || sys.report.tool || gc_state.tool_change) {
@@ -1271,12 +1295,12 @@ void report_realtime_status (void)
strcpy(buf, "|A:");
if (sp_state.on)
if (spindle_0_state.on)
*append++ = sp_state.ccw ? 'C' : 'S';
*append++ = spindle_0_state.ccw ? 'C' : 'S';
#if COMPATIBILITY_LEVEL == 0
if(sp_state.encoder_error && hal.driver_cap.spindle_sync)
if(spindle_0_state.encoder_error && hal.driver_cap.spindle_sync)
*append++ = 'E';
#endif
@@ -1309,7 +1333,7 @@ void report_realtime_status (void)
hal.stream.write_all(appendbuf(2, ",", uitoa(sys.homed.mask)));
}
if(sys.report.xmode && sys.mode == Mode_Lathe)
if(sys.report.xmode && settings.mode == Mode_Lathe)
hal.stream.write_all(gc_state.modal.diameter_mode ? "|D:1" : "|D:0");
if(sys.report.tool)
@@ -2038,23 +2062,25 @@ status_code_t report_current_limit_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)
{
if(hal.spindle.get_data) {
spindle_ptrs_t *spindle = gc_spindle_get();
float apos = hal.spindle.get_data(SpindleData_AngularPosition)->angular_position;
spindle_data_t *spindle = hal.spindle.get_data(SpindleData_Counters);
if(spindle->get_data) {
float apos = spindle->get_data(SpindleData_AngularPosition)->angular_position;
spindle_data_t *data = spindle->get_data(SpindleData_Counters);
hal.stream.write("[SPINDLE:");
hal.stream.write(uitoa(spindle->index_count));
hal.stream.write(uitoa(data->index_count));
hal.stream.write(",");
hal.stream.write(uitoa(spindle->pulse_count));
hal.stream.write(uitoa(data->pulse_count));
hal.stream.write(",");
hal.stream.write(uitoa(spindle->error_count));
hal.stream.write(uitoa(data->error_count));
hal.stream.write(",");
hal.stream.write(ftoa(apos, 3));
hal.stream.write("]" ASCII_EOL);
}
return hal.spindle.get_data ? Status_OK : Status_InvalidStatement;
return spindle->get_data ? Status_OK : Status_InvalidStatement;
}
static const char *get_pinname (pin_function_t function)
@@ -2122,6 +2148,30 @@ status_code_t report_time (void)
return ok ? Status_OK : Status_InvalidStatement;
}
static void report_spindle (spindle_info_t *spindle)
{
hal.stream.write(uitoa(spindle->id));
hal.stream.write(" - ");
hal.stream.write(spindle->name);
if(spindle->enabled) {
#if N_SPINDLE > 1
hal.stream.write(", enabled as spindle ");
hal.stream.write(uitoa(spindle->num));
#else
hal.stream.write(", active");
#endif
}
hal.stream.write(ASCII_EOL);
}
status_code_t report_spindles (void)
{
if(!spindle_enumerate_spindles(report_spindle))
hal.stream.write("No spindles registered." ASCII_EOL);
return Status_OK;
}
void report_pid_log (void)
{
#ifdef PID_LOG
+5 -7
View File
@@ -3,7 +3,7 @@
Part of grblHAL
Copyright (c) 2018-2021 Terje Io
Copyright (c) 2018-2023 Terje Io
Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
Grbl is free software: you can redistribute it and/or modify
@@ -44,8 +44,6 @@ typedef enum {
void report_init (void);
void report_init_fns (void);
// Prints system status messages.
status_code_t report_status_message (status_code_t status_code);
// Prints system alarm messages.
alarm_code_t report_alarm_message (alarm_code_t alarm_code);
@@ -53,9 +51,6 @@ alarm_code_t report_alarm_message (alarm_code_t alarm_code);
// Prints feedback message, typically from gcode.
void report_message (const char *msg, message_type_t type);
// Prints miscellaneous feedback messages.
message_code_t report_feedback_message (message_code_t message_code);
// Prints welcome message.
void report_init_message (void);
@@ -114,9 +109,12 @@ status_code_t report_current_limit_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);
// Prints pin assignments
// Prints pin assignments.
status_code_t report_pins (sys_state_t state, char *args);
// Prints registered spindles.
status_code_t report_spindles (void);
// Prints current RTC datetime in ISO8601 format (when available)
status_code_t report_time (void);
+138 -47
View File
@@ -107,8 +107,8 @@ PROGMEM const settings_t defaults = {
#if DEFAULT_HOMING_ENABLE
.homing.flags.enabled = DEFAULT_HOMING_ENABLE,
.homing.flags.init_lock = DEFAULT_HOMING_INIT_LOCK,
.homing.flags.single_axis_commands = HOMING_SINGLE_AXIS_COMMANDS,
.homing.flags.force_set_origin = HOMING_FORCE_SET_ORIGIN,
.homing.flags.single_axis_commands = DEFAULT_HOMING_SINGLE_AXIS_COMMANDS,
.homing.flags.force_set_origin = DEFAULT_HOMING_FORCE_SET_ORIGIN,
.homing.flags.manual = DEFAULT_HOMING_ALLOW_MANUAL,
.homing.flags.override_locks = DEFAULT_HOMING_OVERRIDE_LOCKS,
.homing.flags.keep_on_reset = DEFAULT_HOMING_KEEP_STATUS_ON_RESET,
@@ -392,6 +392,7 @@ static uint32_t get_int (setting_id_t id);
static bool is_setting_available (const setting_detail_t *setting);
static bool is_group_available (const setting_detail_t *setting);
static bool machine_mode_changed = false;
static char control_signals[] = "Reset,Feed hold,Cycle start,Safety door,Block delete,Optional stop,EStop,Probe connected,Motor fault";
static char spindle_signals[] = "Spindle enable,Spindle direction,PWM";
static char coolant_signals[] = "Flood,Mist";
@@ -808,7 +809,7 @@ static status_code_t set_enable_invert_mask (setting_id_t id, uint_fast16_t int_
static status_code_t set_limits_invert_mask (setting_id_t id, uint_fast16_t int_value)
{
settings.limits.invert.mask = (int_value ? ~(INVERT_LIMIT_BIT_MASK) : INVERT_LIMIT_BIT_MASK) & AXES_BITMASK;
settings.limits.invert.mask = (int_value ? ~(DEFAULT_LIMIT_SIGNALS_INVERT_MASK) : DEFAULT_LIMIT_SIGNALS_INVERT_MASK) & AXES_BITMASK;
return Status_OK;
}
@@ -981,6 +982,13 @@ static status_code_t set_homing_enable (setting_id_t id, uint_fast16_t int_value
if (bit_istrue(int_value, bit(0))) {
#if COMPATIBILITY_LEVEL > 1
settings.homing.flags.enabled = On;
settings.homing.flags.init_lock = DEFAULT_HOMING_INIT_LOCK;
settings.homing.flags.single_axis_commands = DEFAULT_HOMING_SINGLE_AXIS_COMMANDS;
settings.homing.flags.force_set_origin = DEFAULT_HOMING_FORCE_SET_ORIGIN;
settings.homing.flags.manual = DEFAULT_HOMING_ALLOW_MANUAL;
settings.homing.flags.override_locks = DEFAULT_HOMING_OVERRIDE_LOCKS;
settings.homing.flags.keep_on_reset = DEFAULT_HOMING_KEEP_STATUS_ON_RESET;
settings.limits.flags.two_switches = DEFAULT_LIMITS_TWO_SWITCHES_ON_AXES;
#else
settings.homing.flags.value = int_value & 0x0F;
settings.limits.flags.two_switches = bit_istrue(int_value, bit(4));
@@ -1022,8 +1030,8 @@ static status_code_t set_mode (setting_id_t id, uint_fast16_t int_value)
break;
case Mode_Laser:
if(!spindle_get_caps().laser)
return Status_SettingDisabledLaser;
// if(!spindle_get_caps().laser)
// return Status_SettingDisabledLaser;
if(settings.mode != Mode_Laser)
settings.flags.disable_laser_during_hold = DEFAULT_ENABLE_LASER_DURING_HOLD;
gc_state.modal.diameter_mode = false;
@@ -1037,8 +1045,8 @@ static status_code_t set_mode (setting_id_t id, uint_fast16_t int_value)
return Status_InvalidStatement;
}
machine_mode_changed = true;
settings.mode = (machine_mode_t)int_value;
sys.mode = settings.mode == Mode_Laser && !hal.spindle.cap.laser ? Mode_Standard : settings.mode;
return Status_OK;
}
@@ -1374,7 +1382,7 @@ static uint32_t get_int (setting_id_t id)
#if COMPATIBILITY_LEVEL > 1
case Setting_LimitPinsInvertMask:
value = settings.limits.invert.mask == INVERT_LIMIT_BIT_MASK ? 0 : 1;
value = settings.limits.invert.mask == DEFAULT_LIMIT_SIGNALS_INVERT_MASK ? 0 : 1;
break;
#endif
@@ -1759,11 +1767,11 @@ static bool is_setting_available (const setting_detail_t *setting)
#endif
case Setting_SpindleAtSpeedTolerance:
available = hal.spindle.cap.at_speed || hal.driver_cap.spindle_sync;
available = spindle_get_caps().at_speed || hal.driver_cap.spindle_sync;
break;
case Setting_SpindleOnDelay:
available = !hal.signals_cap.safety_door_ajar && hal.spindle.cap.at_speed;
available = !hal.signals_cap.safety_door_ajar && spindle_get_caps().at_speed;
break;
case Setting_AutoReportInterval:
@@ -1902,8 +1910,6 @@ bool read_global_settings ()
if(settings.planner_buffer_blocks < 30 || settings.planner_buffer_blocks > 1000)
settings.planner_buffer_blocks = 35;
sys.mode = settings.mode;
if(!(hal.driver_cap.spindle_sync || hal.driver_cap.spindle_pid))
settings.spindle.ppr = 0;
@@ -1948,7 +1954,6 @@ void settings_restore (settings_restore_t restore)
memcpy(&settings, &defaults, sizeof(settings_t));
sys.mode = settings.mode == Mode_Laser && !hal.spindle.cap.laser ? Mode_Standard : settings.mode;
settings.control_invert.mask &= hal.signals_cap.mask;
settings.spindle.invert.ccw &= spindle_get_caps().direction;
settings.spindle.invert.pwm &= spindle_get_caps().pwm_invert;
@@ -2263,6 +2268,35 @@ static status_code_t validate_value (const setting_detail_t *setting, float valu
return Status_OK;
}
static status_code_t validate_uint_value (const setting_detail_t *setting, uint32_t value)
{
uint32_t val;
uint_fast8_t set_idx = 0;
status_code_t status;
if(setting->min_value) {
if((status = read_uint((char *)setting->min_value, &set_idx, &val)) != Status_OK)
return status;
if(!(value >= val || (setting->flags.allow_null && value == 0)))
return Status_SettingValueOutOfRange;
} else if(value < 0.0f)
return Status_NegativeValue;
if(setting->max_value) {
set_idx = 0;
if((status = read_uint((char *)setting->max_value, &set_idx, &val)) != Status_OK)
return Status_BadNumberFormat;
if(value > val)
return Status_SettingValueOutOfRange;
}
return Status_OK;
}
static uint32_t strnumentries (const char *s, const char delimiter)
{
if(s == NULL || *s == '\0')
@@ -2362,11 +2396,56 @@ inline static bool setting_is_string (setting_datatype_t datatype)
return datatype == Format_String || datatype == Format_Password || datatype == Format_IPv4;
}
inline static bool setting_is_core (setting_type_t type)
inline static bool setting_is_core (setting_type_t type)
{
return !(type == Setting_NonCore || type == Setting_NonCoreFn);
}
static status_code_t setting_validate_me_uint (const setting_detail_t *setting, char *svalue)
{
uint_fast8_t idx = 0;
uint32_t value;
status_code_t status;
if((status = read_uint(svalue, &idx, &value)) != Status_OK)
return status;
switch(setting->datatype) {
case Format_Bool:
if(!(value == 0 || value == 1))
status = Status_SettingValueOutOfRange;
break;
case Format_Bitfield:
case Format_XBitfield:;
if(value >= (1UL << strnumentries(setting->format, ',')))
status = Status_SettingValueOutOfRange;
break;
case Format_RadioButtons:
if(value >= strnumentries(setting->format, ','))
status = Status_SettingValueOutOfRange;
break;
case Format_AxisMask:
if(value >= (1 << N_AXIS))
status = Status_SettingValueOutOfRange;
break;
case Format_Int8:
case Format_Int16:
case Format_Integer:
status = validate_uint_value(setting, value);
break;
default:
break;
}
return status;
}
status_code_t setting_validate_me (const setting_detail_t *setting, float value, char *svalue)
{
status_code_t status = Status_OK;
@@ -2374,33 +2453,18 @@ status_code_t setting_validate_me (const setting_detail_t *setting, float value,
switch(setting->datatype) {
case Format_Bool:
if(!(value == 0.0f || value == 1.0f))
status = Status_SettingValueOutOfRange;
break;
case Format_Bitfield:
case Format_XBitfield:;
if(!(isintf(value) && ((uint32_t)value < (1UL << strnumentries(setting->format, ','))))) //)
status = Status_SettingValueOutOfRange;
break;
case Format_RadioButtons:
if(!(isintf(value) && (uint32_t)value < strnumentries(setting->format, ',')))
status = Status_SettingValueOutOfRange;
break;
case Format_AxisMask:
if(!(isintf(value) && (uint32_t)value < (1 << N_AXIS)))
status = Status_SettingValueOutOfRange;
break;
case Format_Int8:
case Format_Int16:
case Format_Integer:
status = setting_validate_me_uint(setting, svalue);
break;
case Format_Decimal:
status = validate_value(setting, value);
if(setting->datatype == Format_Integer && status == Status_OK && !isintf(value))
status = Status_BadNumberFormat;
break;
case Format_Password:
@@ -2436,10 +2500,23 @@ status_code_t setting_validate (setting_id_t id, float value, char *svalue)
return setting == NULL ? Status_OK : setting_validate_me(setting, value, svalue);
}
static bool settings_changed_spindle (void)
{
static spindle_settings_t spindle_settings = {0};
bool changed;
if((changed = memcmp(&spindle_settings, &settings.spindle, sizeof(spindle_settings_t))) != 0)
memcpy(&spindle_settings, &settings.spindle, sizeof(spindle_settings_t));
return changed;
}
// A helper method to set settings from command line
status_code_t settings_store_setting (setting_id_t id, char *svalue)
{
uint_fast8_t set_idx = 0;
uint32_t int_value = 0;
float value = NAN;
status_code_t status = Status_OK;
setting_details_t *set;
@@ -2457,7 +2534,10 @@ status_code_t settings_store_setting (setting_id_t id, char *svalue)
while(*svalue == ' ')
svalue++;
if(!setting_is_string(setting->datatype) && !read_float(svalue, &set_idx, &value) && setting_is_core(setting->type))
if(setting->datatype == Format_Decimal) {
if(!read_float(svalue, &set_idx, &value) && setting_is_core(setting->type))
return Status_BadNumberFormat;
} else if(!setting_is_string(setting->datatype) && read_uint(svalue, &set_idx, &int_value) != Status_OK && setting_is_core(setting->type))
return Status_BadNumberFormat;
if((status = setting_validate_me(setting, value, svalue)) != Status_OK) {
@@ -2485,23 +2565,23 @@ status_code_t settings_store_setting (setting_id_t id, char *svalue)
break;
case Format_AxisMask:
*((uint8_t *)(setting->value)) = (uint8_t)truncf(value) & AXES_BITMASK;
*((uint8_t *)(setting->value)) = (uint8_t)int_value & AXES_BITMASK;
break;
case Format_Int8:
case Format_Bool:
case Format_Bitfield:
case Format_XBitfield:
case Format_RadioButtons:
*((uint8_t *)(setting->value)) = (uint8_t)truncf(value);
case Format_Int8:
*((uint8_t *)(setting->value)) = (uint8_t)int_value;
break;
case Format_Int16:
*((uint16_t *)(setting->value)) = (uint16_t)truncf(value);
*((uint16_t *)(setting->value)) = (uint16_t)int_value;
break;
case Format_Integer:
*((uint32_t *)(setting->value)) = (uint32_t)truncf(value);
*((uint32_t *)(setting->value)) = (uint32_t)int_value;
break;
default:
@@ -2527,7 +2607,7 @@ status_code_t settings_store_setting (setting_id_t id, char *svalue)
break;
default:
status = ((setting_set_int_ptr)(setting->value))(id, (uint_fast16_t)truncf(value));
status = ((setting_set_int_ptr)(setting->value))(id, (uint_fast16_t)int_value);
break;
}
break;
@@ -2535,16 +2615,18 @@ status_code_t settings_store_setting (setting_id_t id, char *svalue)
if(status == Status_OK) {
if(!hal.spindle.cap.rpm_range_locked) {
hal.spindle.rpm_min = settings.spindle.rpm_min;
hal.spindle.rpm_max = settings.spindle.rpm_max;
}
if(set->save)
set->save();
if(set->on_changed)
set->on_changed(&settings);
if(set->on_changed) {
settings_changed_flags_t changed = {0};
changed.spindle = settings_changed_spindle() || machine_mode_changed;
machine_mode_changed = false;
set->on_changed(&settings, changed);
}
}
return status;
@@ -2573,11 +2655,16 @@ void settings_clear (void)
// Initialize the config subsystem
void settings_init (void)
{
settings_changed_flags_t changed = {0};
if(!read_global_settings()) {
settings_restore_t settings = settings_all;
settings.defaults = 1; // Ensure global settings get restored
if(hal.nvs.type != NVS_None)
grbl.report.status_message(Status_SettingReadFail);
settings_restore(settings); // Force restore all non-volatile storage data.
report_init();
#if COMPATIBILITY_LEVEL <= 1
@@ -2585,7 +2672,9 @@ void settings_init (void)
#else
report_grbl_settings(false, NULL);
#endif
changed.spindle = settings_changed_spindle();
} else {
memset(&tool_table, 0, sizeof(tool_data_t)); // First entry is for tools not in tool table
#if N_TOOLS
uint_fast8_t idx;
@@ -2594,7 +2683,9 @@ void settings_init (void)
#endif
report_init();
hal.settings_changed(&settings);
changed.spindle = settings_changed_spindle();
hal.settings_changed(&settings, changed);
if(hal.probe.configure) // Initialize probe invert mask.
hal.probe.configure(false, false);
@@ -2625,7 +2716,7 @@ void settings_init (void)
if(details->load)
details->load();
if(details->on_changed)
details->on_changed(&settings);
details->on_changed(&settings, changed);
} while((details = details->next));
setting_details.on_changed = hal.settings_changed;
+42 -2
View File
@@ -162,7 +162,7 @@ typedef enum {
// Optional driver implemented settings
// Normally used for Ethernet or WiFi Station
// Normally used for Ethernet
Setting_Hostname = 300,
Setting_IpMode = 301,
Setting_IpAddress = 302,
@@ -184,6 +184,7 @@ typedef enum {
Setting_WebSocketPort2 = 317,
Setting_FtpPort2 = 318,
// Normally used for WiFi Station
Setting_Hostname3 = 320,
Setting_IpMode3 = 321,
Setting_IpAddress3 = 322,
@@ -202,6 +203,8 @@ typedef enum {
Setting_Timezone = 335,
Setting_DSTActive = 336,
Setting_Wifi_AP_BSSID = 337,
Setting_TrinamicDriver = 338,
Setting_TrinamicHoming = 339,
@@ -299,6 +302,11 @@ typedef enum {
Setting_VFD_20 = 472,
Setting_VFD_21 = 473,
Setting_VFD_ModbusAddress0 = 476,
Setting_VFD_ModbusAddress1 = 477,
Setting_VFD_ModbusAddress2 = 478,
Setting_VFD_ModbusAddress3 = 479,
Setting_Fan0OffDelay = 480,
Setting_AutoReportInterval = 481,
Setting_TimeZoneOffset = 482,
@@ -326,6 +334,29 @@ typedef enum {
Setting_MacroPort8 = 508,
Setting_MacroPort9 = 509,
Setting_SpindleEnable0 = 510,
Setting_SpindleEnable1 = 511,
Setting_SpindleEnable2 = 512,
Setting_SpindleEnable3 = 513,
Setting_SpindleEnable4 = 514,
Setting_SpindleEnable5 = 515,
Setting_SpindleEnable6 = 516,
Setting_SpindleEnable7 = 517,
Setting_SpindleToolStart0 = 520,
Setting_SpindleToolStart1 = 521,
Setting_SpindleToolStart2 = 522,
Setting_SpindleToolStart3 = 523,
Setting_SpindleToolStart4 = 524,
Setting_SpindleToolStart5 = 525,
Setting_SpindleToolStart6 = 526,
Setting_SpindleToolStart7 = 527,
Setting_MQTTBrokerIpAddress = 530,
Setting_MQTTBrokerPort = 531,
Setting_MQTTBrokerUserName = 532,
Setting_MQTTBrokerPassword = 533,
Setting_SettingsMax,
Setting_SettingsAll = Setting_SettingsMax,
@@ -770,6 +801,14 @@ typedef struct {
const char *description;
} setting_descr_t;
typedef union {
uint8_t value;
struct {
uint8_t spindle :1,
unassigned :7;
};
} settings_changed_flags_t;
typedef status_code_t (*setting_set_int_ptr)(setting_id_t id, uint_fast16_t value);
typedef status_code_t (*setting_set_float_ptr)(setting_id_t id, float value);
typedef status_code_t (*setting_set_string_ptr)(setting_id_t id, char *value);
@@ -780,8 +819,9 @@ typedef bool (*setting_output_ptr)(const setting_detail_t *setting, uint_fast16_
/*! \brief Pointer to callback function to be called when settings are loaded or changed.
\param settings pointer to \a settings_t struct containing the settings.
\param changed a \a settings_changed_flags_t union containing the changed setting groups.
*/
typedef void (*settings_changed_ptr)(settings_t *settings);
typedef void (*settings_changed_ptr)(settings_t *settings, settings_changed_flags_t changed);
typedef void (*driver_settings_load_ptr)(void);
typedef void (*driver_settings_save_ptr)(void);
+2 -2
View File
@@ -3,7 +3,7 @@
Part of grblHAL
Copyright (c) 2018-2021 Terje Io
Copyright (c) 2018-2023 Terje Io
Copyright (c) 2016 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
@@ -67,7 +67,7 @@ void sleep_check()
// 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 (!sys.steppers_deenergize && (gc_state.modal.spindle.value || gc_state.modal.coolant.value)) {
if (!sys.steppers_deenergize && (gc_state.modal.spindle.state.value || gc_state.modal.coolant.value)) {
switch(state_get()) {
case STATE_IDLE:
+424 -124
View File
File diff suppressed because it is too large Load Diff
+95 -56
View File
@@ -25,24 +25,25 @@
#define _SPINDLE_CONTROL_H_
typedef int8_t spindle_id_t;
typedef int8_t spindle_num_t;
// if changed to > 8 bits planner_cond_t needs to be changed too
typedef union {
uint8_t value;
uint8_t mask;
struct {
uint8_t on :1,
ccw :1,
pwm :1, // NOTE: only used for PWM inversion setting
reserved3 :1,
reserved4 :1,
encoder_error :1,
at_speed :1, //!< Spindle is at speed.
synchronized :1;
uint8_t on :1,
ccw :1,
pwm :1, //!< NOTE: only used for PWM inversion setting
reserved :1,
override_disable :1,
encoder_error :1,
at_speed :1, //!< Spindle is at speed.
synchronized :1;
};
} spindle_state_t;
/// Bitmap flags for spindle capabilities.
/*! \brief Bitmap flags for spindle capabilities. */
typedef union {
uint8_t value; //!< All bitmap flags.
struct {
@@ -57,12 +58,12 @@ typedef union {
};
} spindle_cap_t;
// Used when HAL driver supports spindle synchronization
/*! \brief Used when HAL driver supports spindle synchronization. */
typedef struct {
float rpm;
float rpm_low_limit;
float rpm_high_limit;
float angular_position; // Number of revolutions since last reset
float angular_position; //!< Number of revolutions since last reset
float rpm_programmed;
uint32_t index_count;
uint32_t pulse_count;
@@ -84,11 +85,11 @@ typedef enum {
SpindleType_Null, //!< 4
} spindle_type_t;
/*! \brief Pointer to function for configuring the spindle.
\returns state in a \a spindle_state_t union variable.
*/
typedef bool (*spindle_config_ptr)(void);
typedef enum {
SpindleHAL_Raw, //!< 0 - NOTE: read-only
SpindleHAL_Configured, //!< 1
SpindleHAL_Active, //!< 2
} spindle_hal_t;
/*! \brief Pointer to function for setting the spindle state.
\param state a \a spindle_state_t union variable.
@@ -141,14 +142,18 @@ Used for Pulses Per Inch (PPI) laser mode.
*/
typedef void (*spindle_pulse_on_ptr)(uint_fast16_t pulse_length);
//! Handlers for spindle support.
typedef struct {
struct spindle_param; // members defined below
/*! \brief Handlers and data for spindle support. */
struct spindle_ptrs {
spindle_id_t id; //!< Spindle id, assingned on spindle registration .
struct spindle_param *param; //!< Pointer to current spindle parameters, assigned when spindle is enabled.
spindle_type_t type; //!< Spindle type.
spindle_cap_t cap; //!< Spindle capabilities.
uint_fast16_t pwm_off_value; //!< Value for switching PWM signal off.
float rpm_min; //!< Minimum spindle RPM.
float rpm_max; //!< Maximum spindle RPM.
spindle_config_ptr config; //!< Optional handler for configuring the spindle.
bool (*config)(struct spindle_ptrs *spindle); //!< Optional handler for configuring the spindle.
spindle_set_state_ptr set_state; //!< Handler for setting spindle state.
spindle_get_state_ptr get_state; //!< Handler for getting spindle state.
spindle_get_pwm_ptr get_pwm; //!< Handler for calculating spindle PWM value from RPM.
@@ -157,14 +162,50 @@ typedef struct {
#ifdef GRBL_ESP32
void (*esp32_off)(void); //!< Workaround handler for snowflake ESP32 Guru awaken by floating point data in ISR context.
#endif
// Optional entry points:
// Optional entry points.
spindle_pulse_on_ptr pulse_on; //!< Optional handler for Pulses Per Inch (PPI) mode. Required for the laser PPI plugin.
spindle_get_data_ptr get_data; //!< Optional handler for getting spindle data. Required for spindle sync.
spindle_reset_data_ptr reset_data; //!< Optional handler for resetting spindle data. Required for spindle sync.
} spindle_ptrs_t;
spindle_get_data_ptr get_data; //!< Optional handler for getting spindle data. Required for spindle sync, copied from hal.spindle_data.get on selection.
spindle_reset_data_ptr reset_data; //!< Optional handler for resetting spindle data. Required for spindle sync, copied from hal.spindle_data.reset on selection.
};
typedef struct spindle_ptrs spindle_ptrs_t;
//! \brief Data used for Constant Surface Speed (CSS) mode calculations.
typedef struct {
float surface_speed; //!< Surface speed in millimeters/min
float target_rpm; //!< Target RPM at end of movement
float delta_rpm; //!< Delta between start and target RPM
float max_rpm; //!< Maximum spindle RPM
float tool_offset; //!< Tool offset
uint_fast8_t axis; //!< Linear (tool) axis
} spindle_css_data_t;
/*! \brief Structure used for holding the current state of an enabled spindle. */
typedef struct spindle_param {
float rpm;
float rpm_overridden;
spindle_state_t state;
override_t override_pct; //!< Spindle RPM override value in percent
spindle_css_data_t css; //!< Data used for Constant Surface Speed Mode (CSS) calculations, NULL if not in CSS mode.
spindle_ptrs_t *hal;
} spindle_param_t;
typedef struct {
spindle_get_data_ptr get; //!< Optional handler for getting spindle data. Required for spindle sync.
spindle_reset_data_ptr reset; //!< Optional handler for resetting spindle data. Required for spindle sync.
} spindle_data_ptrs_t;
/*! \brief Pointer to function for configuring the spindle.
\returns state in a \a spindle_state_t union variable.
*/
typedef bool (*spindle_config_ptr)(spindle_ptrs_t *spindle);
/*! \brief Structure holding data passed to the callback function called by spindle_enumerate_spindles(). */
typedef struct {
spindle_id_t id;
spindle_num_t num;
const char *name;
bool enabled;
bool is_current;
const spindle_ptrs_t *hal;
} spindle_info_t;
@@ -175,64 +216,53 @@ typedef struct {
float end;
} pwm_piece_t;
// Precalculated values that may be set/used by HAL driver to speed up RPM to PWM conversions if variable spindle is supported
//!* \brief Precalculated values that may be set/used by HAL driver to speed up RPM to PWM conversions if variable spindle is supported. */
typedef struct {
uint_fast16_t period;
uint_fast16_t off_value; // NOTE: this value holds the inverted version if software PWM inversion is enabled by the driver.
uint_fast16_t off_value; //!< NOTE: this value holds the inverted version if software PWM inversion is enabled by the driver.
uint_fast16_t min_value;
uint_fast16_t max_value;
float rpm_min; //!< Minimum spindle RPM.
float pwm_gradient;
bool invert_pwm; // NOTE: set (by driver) when inversion is done in code
bool invert_pwm; //!< NOTE: set (by driver) when inversion is done in code
bool always_on;
int_fast16_t offset;
uint_fast16_t n_pieces;
pwm_piece_t piece[SPINDLE_NPWM_PIECES];
} spindle_pwm_t;
/*! \brief Pointer to callback function called by spindle_enumerate_spindles().
\param spindle prointer to a \a spindle_info_t struct.
*/
typedef void (*spindle_enumerate_callback_ptr)(spindle_info_t *spindle);
void spindle_set_override (uint_fast8_t speed_override);
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.
// Immediately sets spindle running state with direction and spindle RPM, if enabled.
// Called by spindle_sync() after sync and parking motion/spindle stop override during restore.
// Called by g-code parser when setting spindle state and requires a buffer sync.
bool spindle_sync (spindle_id_t spindle_id, spindle_state_t state, float rpm);
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_id_t spindle_id, spindle_state_t state, float rpm);
bool spindle_set_state (spindle_ptrs_t *spindle, spindle_state_t state, float rpm);
// Spindle speed calculation and limit handling
float spindle_set_rpm (float rpm, uint8_t speed_override);
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_state_t state, float rpm);
bool spindle_restore (spindle_ptrs_t *spindle, spindle_state_t state, float rpm);
void spindle_all_off (void);
//
// The following functions are not called by the core, may be called by driver code.
//
/*! \brief Precompute PWM values for faster conversion.
\param pwm_data pointer t a \a spindle_pwm_t structure.
\param clock_hz timer clock frequency used for PWM generation.
\returns true if successful, false if no PWM range possible - driver should revert to simple on/off spindle control if so.
*/
bool spindle_precompute_pwm_values (spindle_pwm_t *pwm_data, uint32_t clock_hz);
bool spindle_precompute_pwm_values (spindle_ptrs_t *spindle, spindle_pwm_t *pwm_data, uint32_t clock_hz);
/*! \brief Spindle RPM to PWM conversion.
\param pwm_data pointer t a \a spindle_pwm_t structure.
\param rpm spindle RPM.
\param pid_limit boolean, true if PID based spindle sync is used, false otherwise.
__NOTE:__ \a spindle_precompute_pwm_values() must be called to precompute values before this function is called.
Typically this is done in the \a hal.driver_setup handler.
*/
uint_fast16_t spindle_compute_pwm_value (spindle_pwm_t *pwm_data, float rpm, bool pid_limit);
spindle_id_t spindle_register (const spindle_ptrs_t *spindle, const char *name);
void spindle_add_null (void);
spindle_id_t spindle_add_null (void);
uint8_t spindle_get_count (void);
@@ -240,16 +270,25 @@ bool spindle_select (spindle_id_t spindle_id);
spindle_cap_t spindle_get_caps (void);
/*! \brief Update PWM spindle capabilities with run-time determined parameters.
\param pwm_caps pointer to \a spindle_pwm_t struct, NULL if spindle if not PWM capable.
void spindle_update_caps (spindle_ptrs_t *spindle, spindle_pwm_t *pwm_caps);
*/
void spindle_update_caps (spindle_pwm_t *pwm_caps);
const spindle_ptrs_t *spindle_get (spindle_id_t spindle_id);
spindle_ptrs_t *spindle_get_hal (spindle_id_t spindle_id, spindle_hal_t hal);
spindle_id_t spindle_get_current (void);
const char *spindle_get_name (spindle_id_t spindle_id);
spindle_id_t spindle_get_default (void);
spindle_num_t spindle_enable (spindle_id_t spindle_id);
bool spindle_enumerate_spindles (spindle_enumerate_callback_ptr callback);
//
bool spindle_is_enabled (spindle_num_t spindle_num);
bool spindle_is_on (void);
spindle_ptrs_t *spindle_get (spindle_num_t spindle_num);
#endif
+83 -39
View File
@@ -43,8 +43,13 @@ static void state_await_resumed (uint_fast16_t rt_exec);
static void (* volatile stateHandler)(uint_fast16_t rt_exec) = state_idle;
static float restore_spindle_rpm;
static planner_cond_t restore_condition;
typedef struct {
coolant_state_t coolant;
spindle_num_t spindle_num; // Active spindle
spindle_t spindle[N_SYS_SPINDLE];
} restore_condition_t;
static restore_condition_t restore_condition;
static sys_state_t pending_state = STATE_IDLE, sys_state = STATE_IDLE;
typedef union {
@@ -69,17 +74,33 @@ typedef struct {
// Declare and initialize parking local variables
static parking_data_t park = {0};
static void state_restore_conditions (planner_cond_t *condition, float rpm)
static void state_spindle_restore (spindle_t *spindle)
{
if(spindle->hal)
spindle_restore(spindle->hal, spindle->state, spindle->rpm);
}
static void state_spindle_set_state (spindle_t *spindle)
{
if(spindle->hal)
spindle_set_state(spindle->hal, spindle->state, spindle->rpm);
}
static void state_restore_conditions (restore_condition_t *condition)
{
if (!settings.parking.flags.enabled || !park.flags.restart) {
spindle_num_t spindle_num = N_SYS_SPINDLE;
park.flags.restoring = On; //
spindle_restore(condition->spindle, rpm);
do {
state_spindle_restore(&condition->spindle[--spindle_num]);
} while(spindle_num);
// Block if safety door re-opened during prior restore actions.
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 pin.
// NOTE: Laser mode will honor this delay. An exhaust system is often controlled by this signal.
coolant_set_state(condition->coolant);
delay_sec(settings.safety_door.coolant_on_delay, DelayMode_SysSuspend);
}
@@ -92,6 +113,9 @@ static void state_restore_conditions (planner_cond_t *condition, float rpm)
bool initiate_hold (uint_fast16_t new_state)
{
spindle_ptrs_t *spindle;
spindle_num_t spindle_num = N_SYS_SPINDLE;
if (settings.parking.flags.enabled) {
memset(&park.plan_data, 0, sizeof(plan_line_data_t));
park.plan_data.condition.system_motion = On;
@@ -101,16 +125,35 @@ bool initiate_hold (uint_fast16_t new_state)
plan_block_t *block = plan_get_current_block();
if (block == NULL) {
restore_condition.spindle = gc_state.modal.spindle;
restore_condition.coolant.mask = gc_state.modal.coolant.mask | hal.coolant.get_state().mask;
restore_spindle_rpm = gc_state.spindle.rpm;
} else {
restore_condition = block->condition;
restore_spindle_rpm = block->spindle.rpm;
}
restore_condition.spindle_num = 0;
if (sys.mode == Mode_Laser && settings.flags.disable_laser_during_hold)
do {
if((spindle = spindle_get(--spindle_num))) {
if(block && block->spindle.hal == spindle) {
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) {
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;
} 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;
}
} else
restore_condition.spindle[spindle_num].hal = NULL;
} while(spindle_num);
if (block)
restore_condition.coolant.mask = block->condition.coolant.mask;
else
restore_condition.coolant.mask = gc_state.modal.coolant.mask | hal.coolant.get_state().mask;
if (restore_condition.spindle[restore_condition.spindle_num].hal->cap.laser && settings.flags.disable_laser_during_hold)
enqueue_accessory_override(CMD_OVERRIDE_SPINDLE_STOP);
if (sys_state & (STATE_CYCLE|STATE_JOG)) {
@@ -174,14 +217,14 @@ void state_set (sys_state_t new_state)
sys_state = new_state;
sys.steppers_deenergize = false; // Cancel stepper deenergize if pending.
st_prep_buffer(); // Initialize step segment buffer before beginning cycle.
if (block->condition.spindle.synchronized) {
if (block->spindle.state.synchronized) {
if (hal.spindle.reset_data)
hal.spindle.reset_data();
if (block->spindle.hal->reset_data)
block->spindle.hal->reset_data();
uint32_t index = hal.spindle.get_data(SpindleData_Counters)->index_count + 2;
uint32_t index = block->spindle.hal->get_data(SpindleData_Counters)->index_count + 2;
while(index != hal.spindle.get_data(SpindleData_Counters)->index_count); // check for abort in this loop?
while(index != block->spindle.hal->get_data(SpindleData_Counters)->index_count); // check for abort in this loop?
}
st_wake_up();
@@ -252,7 +295,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.on)
if (stateHandler != state_await_resume || !gc_state.modal.spindle.state.on)
return;
if (sys.override.spindle_stop.value) {
@@ -260,7 +303,7 @@ void state_suspend_manager (void)
// Handles beginning of spindle stop
if (sys.override.spindle_stop.initiate) {
sys.override.spindle_stop.value = 0; // Clear stop override state
spindle_set_state(0, (spindle_state_t){0}, 0.0f); // De-energize
spindle_set_state(restore_condition.spindle[restore_condition.spindle_num].hal, (spindle_state_t){0}, 0.0f); // De-energize
sys.override.spindle_stop.enabled = On; // Set stop override state to enabled, if de-energized.
if(grbl.on_override_changed)
grbl.on_override_changed(OverrideChanged_SpindleState);
@@ -269,18 +312,18 @@ void state_suspend_manager (void)
// Handles restoring of spindle state
if (sys.override.spindle_stop.restore) {
grbl.report.feedback_message(Message_SpindleRestore);
if (sys.mode == Mode_Laser) // When in laser mode, ignore spindle spin-up delay. Set to turn on laser when cycle starts.
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
spindle_set_state(0, restore_condition.spindle, restore_spindle_rpm);
state_spindle_set_state(&restore_condition.spindle[restore_condition.spindle_num]);
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 && hal.spindle.get_state().on) {
} else if (sys.step_control.update_spindle_rpm && restore_condition.spindle[0].hal->get_state().on) {
// Handles spindle state during hold. NOTE: Spindle speed overrides may be altered during hold state.
spindle_set_state(0, restore_condition.spindle, restore_spindle_rpm);
state_spindle_set_state(&restore_condition.spindle[restore_condition.spindle_num]);;
sys.step_control.update_spindle_rpm = Off;
}
}
@@ -394,7 +437,7 @@ static void state_await_hold (uint_fast16_t rt_exec)
switch (sys_state) {
case STATE_TOOL_CHANGE:
hal.spindle.set_state((spindle_state_t){0}, 0.0f); // De-energize
spindle_all_off(); // De-energize
hal.coolant.set_state((coolant_state_t){0}); // De-energize
break;
@@ -410,7 +453,7 @@ static void state_await_hold (uint_fast16_t rt_exec)
// Parking requires parking axis homed, the current location not exceeding the???
// parking target location, and laser mode disabled.
if (settings.parking.flags.enabled && !sys.override.control.parking_disable && sys.mode != Mode_Laser) {
if (settings.parking.flags.enabled && !sys.override.control.parking_disable && settings.mode != Mode_Laser) {
// Get current position and store as restore location.
if (!park.flags.active) {
@@ -441,8 +484,9 @@ static void state_await_hold (uint_fast16_t rt_exec)
park.target[settings.parking.axis] = park.retract_waypoint;
park.plan_data.feed_rate = settings.parking.pullout_rate;
park.plan_data.condition.coolant = restore_condition.coolant; // Retain coolant state
park.plan_data.condition.spindle = restore_condition.spindle; // Retain spindle state
park.plan_data.spindle.rpm = restore_spindle_rpm;
park.plan_data.spindle.state = restore_condition.spindle[restore_condition.spindle_num].state; // Retain spindle state
park.plan_data.spindle.hal = restore_condition.spindle[restore_condition.spindle_num].hal;
park.plan_data.spindle.rpm = restore_condition.spindle[restore_condition.spindle_num].rpm;
await_motion = mc_parking_motion(park.target, &park.plan_data);
}
@@ -455,13 +499,13 @@ static void state_await_hold (uint_fast16_t rt_exec)
} else {
// Parking motion not possible. Just disable the spindle and coolant.
// NOTE: Laser mode does not start a parking motion to ensure the laser stops immediately.
hal.spindle.set_state((spindle_state_t){0}, 0.0f); // De-energize
spindle_all_off(); // De-energize
if (!settings.safety_door.flags.keep_coolant_on)
hal.coolant.set_state((coolant_state_t){0}); // De-energize
sys.parking_state = hal.control.get_state().safety_door_ajar ? Parking_DoorAjar : Parking_DoorClosed;
}
} else {
hal.spindle.set_state((spindle_state_t){0}, 0.0f); // De-energize
spindle_all_off(); // De-energize
if (!settings.safety_door.flags.keep_coolant_on)
hal.coolant.set_state((coolant_state_t){0}); // De-energize
sys.parking_state = hal.control.get_state().safety_door_ajar ? Parking_DoorAjar : Parking_DoorClosed;
@@ -540,14 +584,14 @@ static void state_await_resume (uint_fast16_t rt_exec)
default:
if (!settings.flags.restore_after_feed_hold) {
if (!hal.spindle.get_state().on)
if (!restore_condition.spindle[restore_condition.spindle_num].hal->get_state().on)
gc_spindle_off();
sys.override.spindle_stop.value = 0; // Clear spindle stop override states
} else {
if (restore_condition.spindle.on != hal.spindle.get_state().on) {
if (restore_condition.spindle[restore_condition.spindle_num].state.on != restore_condition.spindle[restore_condition.spindle_num].hal->get_state().on) {
grbl.report.feedback_message(Message_SpindleRestore);
spindle_restore(restore_condition.spindle, restore_spindle_rpm);
state_spindle_restore(&restore_condition.spindle[restore_condition.spindle_num]);
}
if (restore_condition.coolant.value != hal.coolant.get_state().value) {
@@ -631,9 +675,9 @@ static void state_await_waypoint_retract (uint_fast16_t rt_exec)
}
// NOTE: Clear accessory state after retract and after an aborted restore motion.
park.plan_data.condition.spindle.value = 0;
park.plan_data.spindle.state.value = 0;
park.plan_data.spindle.rpm = 0.0f;
hal.spindle.set_state(park.plan_data.condition.spindle, 0.0f); // De-energize
park.plan_data.spindle.hal->set_state(park.plan_data.spindle.state, 0.0f); // De-energize
if (!settings.safety_door.flags.keep_coolant_on) {
park.plan_data.condition.coolant.value = 0;
@@ -682,7 +726,7 @@ static void state_restore (uint_fast16_t rt_exec)
stateHandler = state_await_resumed;
// Restart spindle and coolant, delay to power-up.
state_restore_conditions(&restore_condition, restore_spindle_rpm);
state_restore_conditions(&restore_condition);
if(park.flags.restart) {
// Restart flag was set by a safety door event during
@@ -702,8 +746,8 @@ static void state_restore (uint_fast16_t rt_exec)
// original position through valid machine space or by not moving at all.
park.plan_data.feed_rate = settings.parking.pullout_rate;
park.plan_data.condition.coolant = restore_condition.coolant;
park.plan_data.condition.spindle = restore_condition.spindle;
park.plan_data.spindle.rpm = restore_spindle_rpm;
park.plan_data.spindle.state = restore_condition.spindle[restore_condition.spindle_num].state;
park.plan_data.spindle.rpm = restore_condition.spindle[restore_condition.spindle_num].rpm;
await_motion = mc_parking_motion(park.restore_target, &park.plan_data);
}
+30 -24
View File
@@ -395,16 +395,16 @@ ISR_CODE void ISR_FUNC(stepper_driver_interrupt_handler)(void)
#endif
if(st.exec_segment->update_pwm)
hal.spindle.update_pwm(st.exec_segment->spindle_pwm);
st.exec_segment->update_pwm(st.exec_segment->spindle_pwm);
else if(st.exec_segment->update_rpm)
hal.spindle.update_rpm(st.exec_segment->spindle_rpm);
st.exec_segment->update_rpm(st.exec_segment->spindle_rpm);
} else {
// Segment buffer empty. Shutdown.
st_go_idle();
// Ensure pwm is set properly upon completion of rate-controlled motion.
if (st.exec_block->dynamic_rpm && sys.mode == Mode_Laser)
hal.spindle.update_pwm(hal.spindle.pwm_off_value);
if (st.exec_block->dynamic_rpm && st.exec_block->spindle->cap.laser)
st.exec_block->spindle->update_pwm(st.exec_block->spindle->pwm_off_value);
st.exec_block = NULL;
system_set_exec_state_flag(EXEC_CYCLE_COMPLETE); // Flag main program for cycle complete
@@ -741,11 +741,12 @@ void st_prep_buffer (void)
// Setup laser mode variables. RPM rate adjusted motions will always complete a motion with the
// spindle off.
if ((st_prep_block->dynamic_rpm = pl_block->condition.is_rpm_rate_adjusted))
if ((st_prep_block->dynamic_rpm = pl_block->condition.is_rpm_rate_adjusted)) {
// Pre-compute inverse programmed rate to speed up RPM updating per step segment.
st_prep_block->spindle = pl_block->spindle.hal;
prep.inv_feedrate = pl_block->condition.is_laser_ppi_mode ? 1.0f : 1.0f / pl_block->programmed_rate;
else
st_prep_block->dynamic_rpm = pl_block->condition.is_rpm_pos_adjusted;
} else
st_prep_block->dynamic_rpm = !!pl_block->spindle.css;
}
/* ---------------------------------------------------------------------------------
@@ -842,7 +843,7 @@ void st_prep_buffer (void)
}
if(state_get() != STATE_HOMING)
sys.step_control.update_spindle_rpm |= (sys.mode == Mode_Laser); // Force update whenever updating block in laser mode.
sys.step_control.update_spindle_rpm |= pl_block->spindle.hal->cap.laser; // Force update whenever updating block in laser mode.
probe_asserted = false;
}
@@ -856,7 +857,8 @@ void st_prep_buffer (void)
// Set new segment to point to the current segment data block.
prep_segment->exec_block = st_prep_block;
prep_segment->update_rpm = prep_segment->update_pwm = false;
prep_segment->update_rpm = NULL;
prep_segment->update_pwm = NULL;
/*------------------------------------------------------------------------------------
Compute the average velocity of this new segment by determining the total distance
@@ -969,27 +971,31 @@ void st_prep_buffer (void)
if (sys.step_control.update_spindle_rpm || st_prep_block->dynamic_rpm) {
float rpm;
if (pl_block->condition.spindle.on) {
// NOTE: Feed and rapid overrides are independent of PWM value and do not alter laser power/rate.
// If current_speed is zero, then may need to be rpm_min*(100/MAX_SPINDLE_RPM_OVERRIDE)
// but this would be instantaneous only and during a motion. May not matter at all.
rpm = spindle_set_rpm(pl_block->condition.is_rpm_rate_adjusted && !pl_block->condition.is_laser_ppi_mode
? pl_block->spindle.rpm * prep.current_speed * prep.inv_feedrate
: pl_block->spindle.rpm, sys.override.spindle_rpm);
if(pl_block->condition.is_rpm_pos_adjusted) {
if (pl_block->spindle.state.on) {
if(pl_block->spindle.css) {
float npos = (float)(pl_block->step_event_count - prep.steps_remaining) / (float)pl_block->step_event_count;
rpm += (spindle_set_rpm(pl_block->spindle.css.target_rpm, sys.override.spindle_rpm) - prep.current_spindle_rpm) * npos;
rpm = spindle_set_rpm(pl_block->spindle.hal,
pl_block->spindle.rpm + pl_block->spindle.css->delta_rpm * npos,
pl_block->spindle.hal->param->override_pct);
} else {
// NOTE: Feed and rapid overrides are independent of PWM value and do not alter laser power/rate.
// If current_speed is zero, then may need to be rpm_min*(100/MAX_SPINDLE_RPM_OVERRIDE)
// but this would be instantaneous only and during a motion. May not matter at all.
rpm = spindle_set_rpm(pl_block->spindle.hal,
pl_block->condition.is_rpm_rate_adjusted && !pl_block->condition.is_laser_ppi_mode
? pl_block->spindle.rpm * prep.current_speed * prep.inv_feedrate
: pl_block->spindle.rpm, pl_block->spindle.hal->param->override_pct);
}
} else
sys.spindle_rpm = rpm = 0.0f;
pl_block->spindle.hal->param->rpm = rpm = 0.0f;
if(rpm != prep.current_spindle_rpm) {
if((prep_segment->update_pwm = hal.spindle.get_pwm != NULL)) {
if(pl_block->spindle.hal->get_pwm != NULL) {
prep.current_spindle_rpm = rpm;
prep_segment->spindle_pwm = hal.spindle.get_pwm(rpm);
prep_segment->update_pwm = pl_block->spindle.hal->update_pwm;
prep_segment->spindle_pwm = pl_block->spindle.hal->get_pwm(rpm);
} else {
prep_segment->update_rpm = true;
prep_segment->update_rpm = pl_block->spindle.hal->update_rpm;
prep.current_spindle_rpm = prep_segment->spindle_rpm = rpm;
}
sys.step_control.update_spindle_rpm = Off;
@@ -1036,7 +1042,7 @@ void st_prep_buffer (void)
uint32_t cycles = (uint32_t)ceilf(cycles_per_min * inv_rate); // (cycles/step)
// Record end position of segment relative to block if spindle synchronized motion
if((prep_segment->spindle_sync = pl_block->condition.spindle.synchronized)) {
if((prep_segment->spindle_sync = pl_block->spindle.state.synchronized)) {
prep.target_position += dt * prep.target_feed;
prep_segment->cruising = prep.ramp_type == Ramp_Cruise;
prep_segment->target_position = prep.target_position; //st_prep_block->millimeters - pl_block->millimeters;
+14 -13
View File
@@ -50,24 +50,25 @@ typedef struct st_block {
char *message; //!< Message to be displayed when block is executed
output_command_t *output_commands; //!< Output commands (linked list) to be performed when block is executed
bool dynamic_rpm; //!< Tracks motions that require dynamic RPM adjustment
spindle_ptrs_t *spindle; //!< Pointer to current spindle for motions that require dynamic RPM adjustment
bool backlash_motion;
} st_block_t;
typedef struct st_segment {
uint_fast8_t id; //!< Id may be used by driver to track changes
struct st_segment *next; //!< Pointer to next element in cirular list of segments
st_block_t *exec_block; //!< Pointer to the block data for the segment
uint32_t cycles_per_tick; //!< Step distance traveled per ISR tick, aka step rate.
uint_fast8_t id; //!< Id may be used by driver to track changes
struct st_segment *next; //!< Pointer to next element in cirular list of segments
st_block_t *exec_block; //!< Pointer to the block data for the segment
uint32_t cycles_per_tick; //!< Step distance traveled per ISR tick, aka step rate.
float current_rate;
float target_position; //!< Target position of segment relative to block start, used by spindle sync code
uint_fast16_t n_step; //!< Number of step events to be executed for this segment
uint_fast16_t spindle_pwm; //!< Spindle PWM to be set at the start of segment execution
float spindle_rpm; //!< Spindle RPM to be set at the start of the segment execution
bool update_pwm; //!< True if set spindle speed at the start of the segment execution
bool update_rpm; //!< True if set spindle speed at the start of the segment execution
bool spindle_sync; //!< True if block is spindle synchronized
bool cruising; //!< True when in cruising part of profile, only set for spindle synced moves
uint_fast8_t amass_level; //!< Indicates AMASS level for the ISR to execute this segment
float target_position; //!< Target position of segment relative to block start, used by spindle sync code
uint_fast16_t n_step; //!< Number of step events to be executed for this segment
uint_fast16_t spindle_pwm; //!< Spindle PWM to be set at the start of segment execution
float spindle_rpm; //!< Spindle RPM to be set at the start of the segment execution
bool spindle_sync; //!< True if block is spindle synchronized
bool cruising; //!< True when in cruising part of profile, only set for spindle synced moves
uint_fast8_t amass_level; //!< Indicates AMASS level for the ISR to execute this segment
spindle_update_pwm_ptr update_pwm; //!< Valid pointer to spindle.update_pwm() if set spindle speed at the start of the segment execution
spindle_update_rpm_ptr update_rpm; //!< Valid pointer to spindle.update_rmp() if set spindle speed at the start of the segment execution
} segment_t;
//! Stepper ISR data struct. Contains the running data for the main stepper ISR.
+21 -8
View File
@@ -56,6 +56,7 @@ static status_code_t toggle_optional_stop (sys_state_t state, char *args);
static status_code_t check_mode (sys_state_t state, char *args);
static status_code_t disable_lock (sys_state_t state, char *args);
static status_code_t output_help (sys_state_t state, char *args);
static status_code_t output_spindles (sys_state_t state, char *args);
static status_code_t home (sys_state_t state, char *args);
static status_code_t home_x (sys_state_t state, char *args);
static status_code_t home_y (sys_state_t state, char *args);
@@ -120,8 +121,8 @@ ISR_CODE void ISR_FUNC(control_interrupt_handler)(control_signals_t signals)
// NOTE: at least for lasers there should be an external interlock blocking laser power.
if(state_get() != STATE_IDLE && state_get() != STATE_JOG)
system_set_exec_state_flag(EXEC_SAFETY_DOOR);
if(sys.mode == Mode_Laser) // Turn off spindle immediately (laser) when in laser mode
hal.spindle.set_state((spindle_state_t){0}, 0.0f);
if(settings.mode == Mode_Laser) // Turn off spindle immediately (laser) when in laser mode
spindle_all_off();
} else
system_set_exec_state_flag(EXEC_SAFETY_DOOR);
}
@@ -166,10 +167,12 @@ void system_execute_startup (void)
// Reset spindle encoder data
status_code_t spindle_reset_data (sys_state_t state, char *args)
{
if(hal.spindle.reset_data)
hal.spindle.reset_data();
spindle_ptrs_t *spindle = gc_spindle_get();
return hal.spindle.reset_data ? Status_OK : Status_InvalidStatement;
if(spindle->reset_data)
spindle->reset_data();
return spindle->reset_data ? Status_OK : Status_InvalidStatement;
}
status_code_t read_int (char *s, int32_t *value)
@@ -233,6 +236,7 @@ PROGMEM static const sys_command_t sys_commands[] = {
{ "HV", false, home_v },
#endif
{ "HELP", false, output_help },
{ "SPINDLES", false, output_spindles },
{ "SLP", true, enter_sleep },
{ "TLR", true, set_tool_reference },
{ "TPW", true, tool_probe_workpiece },
@@ -284,6 +288,7 @@ void system_command_help (void)
hal.stream.write("$SLP - enter sleep mode" ASCII_EOL);
hal.stream.write("$HELP - output help topics" ASCII_EOL);
hal.stream.write("$HELP <topic> - output help for <topic>" ASCII_EOL);
hal.stream.write("$SPINDLES - output spindle list" ASCII_EOL);
hal.stream.write("$RST=* - restore/reset all settings" ASCII_EOL);
hal.stream.write("$RST=$ - restore default settings" ASCII_EOL);
if(settings_get_details()->next)
@@ -293,10 +298,13 @@ void system_command_help (void)
#else
hal.stream.write("$RST=# - reset offsets" ASCII_EOL);
#endif
if(hal.spindle.reset_data)
spindle_ptrs_t *spindle = gc_spindle_get();
if(spindle->reset_data)
hal.stream.write("$SR - reset spindle encoder data" ASCII_EOL);
if(hal.spindle.get_data)
if(spindle->get_data)
hal.stream.write("$SD - output spindle encoder data" ASCII_EOL);
hal.stream.write("$TLR - set tool offset reference" ASCII_EOL);
hal.stream.write("$TPW - probe tool plate" ASCII_EOL);
hal.stream.write("$EA - enumerate alarms" ASCII_EOL);
@@ -626,6 +634,11 @@ static status_code_t output_help (sys_state_t state, char *args)
return report_help(args);
}
static status_code_t output_spindles (sys_state_t state, char *args)
{
return report_spindles();
}
static status_code_t go_home (sys_state_t state, axes_signals_t axes)
{
if(axes.mask && !settings.homing.flags.single_axis_commands)
@@ -661,7 +674,7 @@ static status_code_t go_home (sys_state_t state, axes_signals_t axes)
if (retval == Status_OK && !sys.abort) {
state_set(STATE_IDLE); // Set to IDLE when complete.
st_go_idle(); // Set steppers to the settings idle state before returning.
report_feedback_message(Message_None);
grbl.report.feedback_message(Message_None);
// Execute startup scripts after successful homing.
if (sys.homing.mask && (sys.homing.mask & sys.homed.mask) == sys.homing.mask)
system_execute_startup();
+3 -5
View File
@@ -190,9 +190,9 @@ typedef union {
} report_tracking_flags_t;
typedef struct {
uint8_t feed_rate; //!< Feed rate override value in percent
uint8_t rapid_rate; //!< Rapids override value in percent
uint8_t spindle_rpm; //!< Spindle speed override value in percent
override_t feed_rate; //!< Feed rate override value in percent
override_t rapid_rate; //!< Rapids override value in percent
// Spindle override has been moved to per spindle in spindle_param_t
spindle_stop_t spindle_stop; //!< Tracks spindle stop override states
gc_override_flags_t control; //!< Tracks override control states.
} overrides_t;
@@ -245,7 +245,6 @@ typedef struct system {
volatile probing_state_t probing_state; //!< Probing state value. Used to coordinate the probing cycle with stepper ISR.
volatile rt_exec_t rt_exec_state; //!< Realtime executor bitflag variable for state management. See EXEC bitmasks.
volatile uint_fast16_t rt_exec_alarm; //!< Realtime executor bitflag variable for setting various alarms.
float spindle_rpm; //!< Current spindle RPM
int32_t var5399; //!< Last result from M66 - wait on input
#ifdef PID_LOG
pid_data_t pid_log;
@@ -261,7 +260,6 @@ typedef struct system {
bool cold_start; //!< Set to true on boot, is false on subsequent soft resets.
bool driver_started; //!< Set to true when driver initialization is completed.
bool mpg_mode; //!< To be moved to system_flags_t
machine_mode_t mode; //!< Current machine mode, copied from settings.mode on startup.
signal_event_t last_event; //!< Last signal events (control and limits signal).
int32_t position[N_AXIS]; //!< Real-time machine (aka home) position vector in steps.
//@}
+6 -5
View File
@@ -128,7 +128,7 @@ static bool restore (void)
sync_position();
coolant_sync(gc_state.modal.coolant);
spindle_restore(gc_state.modal.spindle, gc_state.spindle.rpm);
spindle_restore(spindle_get(0), gc_state.modal.spindle.state, gc_state.spindle.rpm);
if(!settings.flags.no_restore_position_after_M6) {
previous.values[plane.axis_linear] += gc_get_offset(plane.axis_linear);
@@ -162,7 +162,7 @@ static void execute_restore (sys_state_t state)
change_completed();
report_feedback_message(Message_None);
grbl.report.feedback_message(Message_None);
if(ok)
system_set_exec_state_flag(EXEC_CYCLE_START);
@@ -196,6 +196,7 @@ static void execute_probe (sys_state_t state)
plan_data.feed_rate = settings.tool_change.seek_rate;
plan_data.condition.value = 0;
plan_data.spindle.state.value = 0;
target.values[plane.axis_linear] -= settings.tool_change.probing_distance;
if((ok = ok && mc_probe_cycle(target.values, &plan_data, flags) == GCProbe_Found))
@@ -217,7 +218,7 @@ static void execute_probe (sys_state_t state)
sys.tlo_reference[plane.axis_linear] = sys.probe_position[plane.axis_linear];
sys.tlo_reference_set.mask |= bit(plane.axis_linear);
sys.report.tlo_reference = On;
report_feedback_message(Message_ReferenceTLOEstablished);
grbl.report.feedback_message(Message_ReferenceTLOEstablished);
} else
gc_set_tool_offset(ToolLengthOffset_EnableDynamic, plane.axis_linear,
sys.probe_position[plane.axis_linear] - sys.tlo_reference[plane.axis_linear]);
@@ -332,7 +333,7 @@ static status_code_t tool_change (parser_state_t *parser_state)
block_cycle_start = settings.tool_change.mode != ToolChange_SemiAutomatic;
// Stop spindle and coolant.
hal.spindle.set_state((spindle_state_t){0}, 0.0f);
spindle_all_off();
hal.coolant.set_state((coolant_state_t){0});
execute_posted = false;
@@ -434,7 +435,7 @@ void tc_clear_tlo_reference (axes_signals_t homing_cycle)
#else
gc_get_plane_data(&plane, gc_state.modal.plane_select);
#endif
if(homing_cycle.mask & (sys.mode == Mode_Lathe ? (X_AXIS_BIT|Z_AXIS_BIT) : bit(plane.axis_linear))) {
if(homing_cycle.mask & (settings.mode == Mode_Lathe ? (X_AXIS_BIT|Z_AXIS_BIT) : bit(plane.axis_linear))) {
sys.report.tlo_reference = sys.tlo_reference_set.mask != 0;
sys.tlo_reference_set.mask = 0; // Invalidate tool length offset reference
}