diff --git a/changelog.md b/changelog.md index 36159a3..e630e7b 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,25 @@ ## grblHAL changelog +Build 20241116 + +Core: + +* Added support for named o-sub/o-call to flow control, for calling gcode subroutines stored on SD card or in littlefs. Sub name matches filename with extension _.macro_. + +* Added core event for handling special gcode comments used by expressions: `DEBUG`, `PRINT` and `ABORT`. These can now be extended by or new added to by plugins. + +* Added overrideable default $-setting values for second PWM spindle to _grbl/config.c_. + +Plugins: + +* Trinamic: changed some default parameter values, fix bug in previously unused TMC2660 code. + +* Motors: fixed bugs in handling and visibility of extended settings. + +* Misc, eventout: added info to `$pins` command for pins mapped to event actions. + +--- + Build 20241113 Core: @@ -18,6 +38,8 @@ Plugins: * Misc: added plugin for feed rate overrides via Marlin style M-code and plugin for configuring per axis homing pulloff distance. +* Keypad, macros: added some overridable defaults. + --- Build 20241110 diff --git a/config.h b/config.h index 0922af7..867af5f 100644 --- a/config.h +++ b/config.h @@ -1212,6 +1212,81 @@ Defines the parameters for the fourth entry in the spindle RPM linearization tab #endif // ENABLE_SPINDLE_LINEARIZATION +// Settings for second PWM spindle + +/*! @name $716 - Setting_SpindleInvertMask1 +Inverts the selected spindle output signals from active high to active low. Useful for some pre-built electronic boards. +*/ +///@{ +#if !defined DEFAULT_INVERT_SPINDLE1_ENABLE_PIN || defined __DOXYGEN__ +#define DEFAULT_INVERT_SPINDLE1_ENABLE_PIN Off +#endif +#if !defined DEFAULT_INVERT_SPINDLE1_CCW_PIN || defined __DOXYGEN__ +#define DEFAULT_INVERT_SPINDLE1_CCW_PIN Off // NOTE: not supported by all drivers. +#endif +#if !defined DEFAULT_INVERT_SPINDLE1_PWM_PIN || defined __DOXYGEN__ +#define DEFAULT_INVERT_SPINDLE1_PWM_PIN Off // NOTE: not supported by all drivers. +#endif +///@} + +/*! @name $730 - Setting_RpmMax1 +*/ +///@{ +#if !defined DEFAULT_SPINDLE1_RPM_MAX || defined __DOXYGEN__ +#define DEFAULT_SPINDLE1_RPM_MAX 1000.0f // rpm +#endif +///@} + +/*! @name $731 - Setting_RpmMin1 +*/ +///@{ +#if !defined DEFAULT_SPINDLE1_RPM_MIN || defined __DOXYGEN__ +#define DEFAULT_SPINDLE1_RPM_MIN 0.0f // rpm +#endif +///@} + +/*! @name $733 - Setting_PWMFreq1 +*/ +///@{ +#if !defined DEFAULT_SPINDLE1_PWM_FREQ || defined __DOXYGEN__ +#define DEFAULT_SPINDLE1_PWM_FREQ 5000 // Hz +#endif +///@} + +/*! @name $734 - Setting_PWMOffValue1 +*/ +///@{ +#if !defined DEFAULT_SPINDLE1_PWM_OFF_VALUE || defined __DOXYGEN__ +#define DEFAULT_SPINDLE1_PWM_OFF_VALUE 0.0f // Percent +#endif +///@} + +/*! @name $735 - Setting_PWMMinValue1 +Used by variable spindle output only. This forces the PWM output to a minimum duty cycle when enabled. +The PWM pin will still read 0V when the spindle is disabled. Most users will not need this option, but +it may be useful in certain scenarios. This minimum PWM settings coincides with the spindle rpm minimum +setting, like rpm max to max PWM. This is handy if you need a larger voltage difference between 0V disabled +and the voltage set by the minimum PWM for minimum rpm. This difference is 0.02V per PWM value. So, when +minimum PWM is at 1, only 0.02 volts separate enabled and disabled. At PWM 5, this would be 0.1V. Keep +in mind that you will begin to lose PWM resolution with increased minimum PWM values, since you have less +and less range over the total 255 PWM levels to signal different spindle speeds. +
__!! NOTE:__ Compute duty cycle at the minimum PWM by this equation: (% duty cycle)=(SPINDLE1_PWM_MIN_VALUE/255)*100 +*/ +///@{ +#if !defined DEFAULT_SPINDLE1_PWM_MIN_VALUE || defined __DOXYGEN__ +#define DEFAULT_SPINDLE1_PWM_MIN_VALUE 0.0f // Must be greater than zero. Integer (+-255). +#endif +///@} + +/*! @name $736 - Setting_PWMMaxValue +*/ +///@{ +#if !defined DEFAULT_SPINDLE1_PWM_MAX_VALUE || defined __DOXYGEN__ +#define DEFAULT_SPINDLE1_PWM_MAX_VALUE 100.0f // Percent +#endif +///@} + + // Tool change settings (Group_Toolchange) /*! @name $341 - Setting_ToolChangeMode diff --git a/core_handlers.h b/core_handlers.h index e4e138b..db2ab08 100644 --- a/core_handlers.h +++ b/core_handlers.h @@ -118,6 +118,7 @@ typedef void (*on_reset_ptr)(void); typedef void (*on_jog_cancel_ptr)(sys_state_t state); typedef bool (*on_spindle_select_ptr)(spindle_ptrs_t *spindle); typedef void (*on_spindle_selected_ptr)(spindle_ptrs_t *spindle); +typedef char *(*on_process_gcode_comment_ptr)(char *msg); typedef status_code_t (*on_gcode_message_ptr)(char *msg); typedef void (*on_rt_reports_added_ptr)(report_tracking_flags_t report); typedef const char *(*on_set_axis_setting_unit_ptr)(setting_id_t setting_id, uint_fast8_t axis_idx); @@ -242,19 +243,20 @@ typedef struct { on_probe_start_ptr on_probe_start; on_probe_completed_ptr on_probe_completed; on_set_axis_setting_unit_ptr on_set_axis_setting_unit; - on_gcode_message_ptr on_gcode_message; //!< Called on output of message parsed from gcode. NOTE: string pointed to is freed after this call. - on_gcode_message_ptr on_gcode_comment; //!< Called when a plain gcode comment has been parsed. - on_tool_selected_ptr on_tool_selected; //!< Called prior to executing M6 or after executing M61. - on_tool_changed_ptr on_tool_changed; //!< Called after executing M6 or M61. - on_toolchange_ack_ptr on_toolchange_ack; //!< Called from interrupt context. - on_jog_cancel_ptr on_jog_cancel; //!< Called from interrupt context. + on_process_gcode_comment_ptr on_process_gcode_comment; + on_gcode_message_ptr on_gcode_message; //!< Called on output of message parsed from gcode. NOTE: string pointed to is freed after this call. + on_gcode_message_ptr on_gcode_comment; //!< Called when a plain gcode comment has been parsed. + on_tool_selected_ptr on_tool_selected; //!< Called prior to executing M6 or after executing M61. + on_tool_changed_ptr on_tool_changed; //!< Called after executing M6 or 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; //!< 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. - on_file_open_ptr on_file_open; //!< Called when a file is opened for streaming. - on_file_end_ptr on_file_end; //!< Called when a file opened for streaming reaches the end. - user_mcode_ptrs_t user_mcode; //!< Optional handlers for user defined M-codes. + 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. + on_file_open_ptr on_file_open; //!< Called when a file is opened for streaming. + on_file_end_ptr on_file_end; //!< Called when a file opened for streaming reaches the end. + user_mcode_ptrs_t user_mcode; //!< Optional handlers for user defined M-codes. // core entry points - set up by core before driver_init() is called. home_machine_ptr home_machine; travel_limits_ptr check_travel_limits; diff --git a/driver_opts.h b/driver_opts.h index f83ff3f..5e763f1 100644 --- a/driver_opts.h +++ b/driver_opts.h @@ -288,18 +288,22 @@ // Driver spindle 1 #if SPINDLE_ENABLE & ((1< 1 #define DRIVER_SPINDLE1_ENABLE 1 #else +#warning "Configure N_SPINDLE > 1 in grbl/config.h when enabling second driver spindle!" +#endif +#else #define DRIVER_SPINDLE1_ENABLE 0 #endif -#if SPINDLE_ENABLE & ((1<o_label > NGC_MAX_PARAM_ID) + o_label = sub->o_label; + } while((sub = sub->next)); + + if((sub = subs)) do { + if(sub->o_label == o_label) { + last = sub; + (*refcount)++; + } + } while((sub = sub->next)); + + return last; +} + static ngc_sub_t *add_sub (uint32_t o_label, vfs_file_t *file) { ngc_sub_t *sub; @@ -276,10 +297,15 @@ static void stack_unwind_sub (uint32_t o_label) stack_pull(); if(stack_idx >= 0) { - if(o_label > NGC_MAX_PARAM_ID) + if(o_label > NGC_MAX_PARAM_ID) { + uint32_t count = 0; + if(stack[stack_idx].sub == get_refcount(&count) && count == 1) + ngc_string_param_delete((ngc_string_id_t)o_label); + clear_subs(stack[stack_idx].file); stream_redirect_close(stack[stack_idx].file); - else + } else vfs_seek(stack[stack_idx].file, stack[stack_idx].file_pos); + stack_pull(); } @@ -301,10 +327,14 @@ static status_code_t onGcodeComment (char *comment) status_code_t status = Status_OK; if(!strncasecmp(comment, "ABORT,", 6)) { - char *buf = NULL; - if(ngc_substitute_parameters(comment + pos, &buf)) { - report_message(buf, Message_Error); - free(buf); + char *msg = NULL; + *comment = '!'; + msg = grbl.on_process_gcode_comment(comment); + if(msg == NULL) + msg = ngc_substitute_parameters(comment + pos); + if(msg) { + report_message(msg, Message_Error); + free(msg); } status = Status_UserException; } else if(on_gcode_comment) @@ -328,41 +358,37 @@ void ngc_flowctrl_init (void) stack_pull(); } -/* - -static status_code_t onError (status_code_t status) +// NOTE: onNamedSubError will be called recursively for each +// redirected file by the grbl.report.status_message() call. +static status_code_t onNamedSubError (status_code_t status) { static bool closing = false; if(stack_idx >= 0) { - uint32_t o_label = 0; ngc_sub_t *sub; + uint32_t o_label = 0; if((sub = subs)) do { - if(sub->o_label > NGC_MAX_PARAM_ID) + if(sub->file == hal.stream.file && sub->o_label > NGC_MAX_PARAM_ID) o_label = sub->o_label; - } while((sub = sub->next)); - - if((sub = subs)) do { - if(sub->o_label == o_label) - break; - } while((sub = sub->next)); + } while(o_label == 0 && (sub = sub->next)); if(sub) { + if(!closing) { - char msg[100]; + char *name, msg[100]; closing = true; - char *name = string_register_get_by_id((string_register_id_t)sub->o_label); - sprintf(msg, "error %d in named sub %s.macro", (uint8_t)status, name); - report_message(msg, Message_Warning); + if((name = ngc_string_param_get((ngc_string_id_t)o_label))) { + sprintf(msg, "error %d in named sub %s.macro", (uint8_t)status, name); + report_message(msg, Message_Warning); + } } - sub->o_label = 1; - - stream_redirect_close(sub->file); + stack_unwind_sub(o_label); status = grbl.report.status_message(status); } + closing = false; ngc_flowctrl_init(); } @@ -370,14 +396,16 @@ static status_code_t onError (status_code_t status) return status; } -static status_code_t onFileEnd (vfs_file_t *file, status_code_t status) +static status_code_t onNamedSubEOF (vfs_file_t *file, status_code_t status) { - if(stack_idx >= 0 && stack[stack_idx].file == file) - ngc_flowctrl_unwind_stack(file); + if(stack_idx >= 0 && stack[stack_idx].file == file) { + stream_redirect_close(stack[stack_idx].file); + ngc_flowctrl_unwind_stack(stack[stack_idx].file); + } return status; } -*/ + status_code_t ngc_flowctrl (uint32_t o_label, char *line, uint_fast8_t *pos, bool *skip) { float value; @@ -600,8 +628,8 @@ status_code_t ngc_flowctrl (uint32_t o_label, char *line, uint_fast8_t *pos, boo if(o_label > NGC_MAX_PARAM_ID) { if((sub = subs)) do { -// if(sub->o_label == o_label && sub->file == hal.stream.file) -// break; + if(sub->o_label == o_label && sub->file == hal.stream.file) + break; } while(sub->next && (sub = sub->next)); if(sub == NULL || sub->o_label != o_label) @@ -636,28 +664,28 @@ status_code_t ngc_flowctrl (uint32_t o_label, char *line, uint_fast8_t *pos, boo ngc_sub_t *sub; if(o_label > NGC_MAX_PARAM_ID) { -#if 0 + char *subname; - if((subname = string_register_get_by_id((string_register_id_t)o_label))) { + if((subname = ngc_string_param_get((ngc_string_id_t)o_label))) { char filename[60]; vfs_file_t *file; - - strcpy(filename, "/"); - strcat(filename, subname); - strcat(filename, ".macro"); - #if LITTLEFS_ENABLE - sprintf(filename, "/littlefs/P%d.macro", macro_id); + sprintf(filename, "/littlefs/%s.macro", subname); - if((file = vfs_open(filename, "r")) == NULL) + if((file = stream_redirect_read(filename, onNamedSubError, onNamedSubEOF)) == NULL) { + sprintf(filename, "/%s.macro", subname); + file = stream_redirect_read(filename, onNamedSubError, onNamedSubEOF); + } +#else + sprintf(filename, "/%s.macro", subname); + file = stream_redirect_read(filename, onNamedSubError, onNamedSubEOF); #endif - if((file = stream_redirect_read(filename, onError, onFileEnd))) { + if(file) { if((sub = add_sub(o_label, file)) == NULL) status = Status_FlowControlOutOfMemory; } else status = Status_FlowControlOutOfMemory; // file not found... } -#endif } else if((sub = subs)) do { if(sub->o_label == o_label && sub->file == hal.stream.file) break; diff --git a/ngc_params.c b/ngc_params.c index 1ce1527..ca57fb9 100644 --- a/ngc_params.c +++ b/ngc_params.c @@ -71,6 +71,13 @@ typedef struct ngc_named_rw_param { struct ngc_named_rw_param *next; } ngc_named_rw_param_t; +typedef struct ngc_string_param { + struct ngc_string_param *next; + ngc_string_id_t id; + uint8_t len; + char value[1]; +} ngc_string_param_t; + typedef struct { uint32_t level; void *context; @@ -83,6 +90,8 @@ static gc_modal_t *modal_state; static ngc_param_context_t call_levels[NGC_MAX_CALL_LEVEL]; static ngc_rw_param_t *rw_params = NULL; static ngc_named_rw_param_t *rw_global_params = NULL; +static ngc_string_id_t ref_id = (uint32_t)-1; +static ngc_string_param_t *ngc_string_params = NULL; static float _absolute_pos (uint_fast8_t axis) { @@ -740,6 +749,127 @@ bool ngc_named_param_set (char *name, float value) return ok; } +static ngc_string_param_t *sp_get_by_name (char *name) +{ + ngc_string_param_t *sr = ngc_string_params; + + if(sr) do { + if(sr->id > NGC_MAX_PARAM_ID && !(strcmp(sr->value, name))) + break; + } while((sr = sr->next)); + + return sr; +} + +static ngc_string_param_t *sp_set (ngc_string_id_t id, char *value) +{ + size_t len; + ngc_string_param_t *last = NULL, *sp; + + if((sp = ngc_string_params)) do { + if(sp->id == id) + break; + last = sp; + } while((sp = sp->next)); + + if((len = strlen(value)) <= 255) { + + if(sp == NULL || len > sp->len) { + + ngc_string_param_t *sp_org = sp; + + if((sp = realloc(sp, sizeof(ngc_string_param_t) + len))) { + + if(sp_org == NULL) { + sp->id = id; + sp->next = NULL; + } + sp->len = len; + + if(last == NULL) { + ngc_string_params = sp; + } else { + if(sp_org == NULL) + last->next = sp; + else if(sp_org != sp) { + + ngc_string_param_t *sr = ngc_string_params; + + do { + if(sr->next == sp_org) { + sr->next = sp; + break; + } + } while((sr = sr->next)); + } + } + } else if(sp_org) + ngc_string_param_delete(sp_org->id); + } + + if(sp) + strcpy(sp->value, value); + + } else if(sp) { + ngc_string_param_delete(sp->id); + sp = NULL; + } + + return sp; +} + +char *ngc_string_param_get (ngc_string_id_t id) +{ + ngc_string_param_t *sp; + + if((sp = ngc_string_params)) do { + if(sp->id == id) + break; + } while((sp = sp->next)); + + return sp->value; +} + +bool ngc_string_param_exists (ngc_string_id_t id) +{ + return !!ngc_string_param_get(id); +} + +bool ngc_string_param_set (ngc_param_id_t id, char *value) +{ + return id > 0 && !!sp_set((ngc_string_id_t)id, value); +} + +ngc_string_id_t ngc_string_param_set_name (char *name) +{ + ngc_string_param_t *sr = *name ? sp_get_by_name(name) : NULL; + + if(*name && sr == NULL) + sr = sp_set(--ref_id, name); + + return sr ? sr->id : 0; +} + +void ngc_string_param_delete (ngc_string_id_t id) +{ + ngc_string_param_t *sr = ngc_string_params, *rm; + + if(sr) { + if(sr->id == id) { + rm = sr; + ngc_string_params = sr->next; + free(rm); + } else do { + if(sr->next && sr->next->id == id) { + rm = sr->next; + sr->next = sr->next->next; + free(rm); + break; + } + } while((sr = sr->next)); + } +} + bool ngc_modal_state_save (gc_modal_t *state, bool auto_restore) { gc_modal_t **saved_state = call_level == -1 ? &modal_state : &call_levels[call_level].modal_state; diff --git a/ngc_params.h b/ngc_params.h index 221356c..9614c38 100644 --- a/ngc_params.h +++ b/ngc_params.h @@ -37,6 +37,7 @@ #define NGC_MAX_PARAM_ID 65535 typedef uint16_t ngc_param_id_t; +typedef uint32_t ngc_string_id_t; typedef struct { ngc_param_id_t id; @@ -111,6 +112,13 @@ bool ngc_named_param_get (char *name, float *value); float ngc_named_param_get_by_id (ncg_name_param_id_t id); bool ngc_named_param_set (char *name, float value); bool ngc_named_param_exists (char *name); + +bool ngc_string_param_set (ngc_param_id_t id, char *value); +ngc_string_id_t ngc_string_param_set_name (char *name); +char *ngc_string_param_get (ngc_string_id_t id); +bool ngc_string_param_exists (ngc_string_id_t id); +void ngc_string_param_delete (ngc_string_id_t id); + bool ngc_call_push (void *context); bool ngc_call_pop (void); uint_fast8_t ngc_call_level (void); diff --git a/settings.c b/settings.c index ae1387c..e7550c4 100644 --- a/settings.c +++ b/settings.c @@ -441,7 +441,7 @@ static status_code_t set_ngc_debug_out (setting_id_t id, uint_fast16_t int_value static bool machine_mode_changed = false; #if COMPATIBILITY_LEVEL <= 1 -static char homing_options[] = "Enable,Enable single axis commands,Homing on startup required,Set machine origin to 0,Two switches shares one input pin,Allow manual,Override locks,Keep homed status on reset,Use limit switches"; +static char homing_options[] = "Enable,Enable single axis commands,Homing on startup required,Set machine origin to 0,Two switches shares one input,Allow manual,Override locks,Keep homed status on reset,Use limit switches"; #endif static char control_signals[] = "Reset,Feed hold,Cycle start,Safety door,Block delete,Optional stop,EStop,Probe connected,Motor fault,Motor warning,Limits override,Single step blocks"; static char spindle_signals[] = "Spindle enable,Spindle direction,PWM"; @@ -509,8 +509,8 @@ PROGMEM static const setting_detail_t setting_detail[] = { { Setting_JunctionDeviation, Group_General, "Junction deviation", "mm", Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacy, &settings.junction_deviation, NULL, NULL }, { Setting_ArcTolerance, Group_General, "Arc tolerance", "mm", Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacy, &settings.arc_tolerance, NULL, NULL }, { Setting_ReportInches, Group_General, "Report in inches", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsLegacyFn, set_report_inches, get_int, NULL }, - { Setting_ControlInvertMask, Group_ControlSignals, "Invert control pins", NULL, Format_Bitfield, control_signals, NULL, NULL, Setting_IsExpandedFn, set_control_invert, get_int, NULL }, - { Setting_CoolantInvertMask, Group_Coolant, "Invert coolant pins", NULL, Format_Bitfield, coolant_signals, NULL, NULL, Setting_IsExtended, &settings.coolant_invert.mask, NULL, NULL }, + { Setting_ControlInvertMask, Group_ControlSignals, "Invert control inputs", NULL, Format_Bitfield, control_signals, NULL, NULL, Setting_IsExpandedFn, set_control_invert, get_int, NULL }, + { Setting_CoolantInvertMask, Group_Coolant, "Invert coolant outputs", NULL, Format_Bitfield, coolant_signals, NULL, NULL, Setting_IsExtended, &settings.coolant_invert.mask, NULL, NULL }, { Setting_SpindleInvertMask, Group_Spindle, "Invert spindle signals", NULL, Format_Bitfield, spindle_signals, NULL, NULL, Setting_IsExtendedFn, set_spindle_invert, get_int, is_setting_available, { .reboot_required = On } }, { Setting_ControlPullUpDisableMask, Group_ControlSignals, "Pullup disable control inputs", NULL, Format_Bitfield, control_signals, NULL, NULL, Setting_IsExtendedFn, set_control_disable_pullup, get_int, NULL }, { Setting_LimitPullUpDisableMask, Group_Limits, "Pullup disable limit inputs", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtended, &settings.limits.disable_pullup.mask, NULL, NULL }, @@ -646,7 +646,7 @@ PROGMEM static const setting_detail_t setting_detail[] = { { Setting_RotaryWrap, Group_Stepper, "Fast rotary go to G28", NULL, Format_Bitfield, rotary_axes, NULL, NULL, Setting_IsExtendedFn, set_rotary_wrap_axes, get_int, NULL }, #endif { Setting_FSOptions, Group_General, "File systems options", NULL, Format_Bitfield, fs_options, NULL, NULL, Setting_IsExtended, &settings.fs_options.mask, NULL, is_setting_available }, - { Setting_HomePinsInvertMask, Group_Limits, "Invert home pins", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtended, &settings.home_invert.mask, NULL, is_setting_available }, + { Setting_HomePinsInvertMask, Group_Limits, "Invert home inputs", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtended, &settings.home_invert.mask, NULL, is_setting_available }, { Setting_HoldCoolantOnDelay, Group_Coolant, "Coolant on delay", "s", Format_Decimal, "#0.0", "0.5", "20", Setting_IsExtended, &settings.safety_door.coolant_on_delay, NULL, is_setting_available } }; diff --git a/spindle_control.c b/spindle_control.c index 6f12aa4..a78beb5 100644 --- a/spindle_control.c +++ b/spindle_control.c @@ -1032,17 +1032,18 @@ static void spindle1_settings_save (void) static void spindle1_settings_restore (void) { static const spindle_settings_t defaults = { - .rpm_max = DEFAULT_SPINDLE_RPM_MAX, - .rpm_min = DEFAULT_SPINDLE_RPM_MIN, + .rpm_max = DEFAULT_SPINDLE1_RPM_MAX, + .rpm_min = DEFAULT_SPINDLE1_RPM_MIN, .flags.pwm_disable = false, - .flags.enable_rpm_controlled = DEFAULT_SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED, - .invert.on = DEFAULT_INVERT_SPINDLE_ENABLE_PIN, - .invert.ccw = DEFAULT_INVERT_SPINDLE_CCW_PIN, - .invert.pwm = DEFAULT_INVERT_SPINDLE_PWM_PIN, - .pwm_freq = DEFAULT_SPINDLE_PWM_FREQ, - .pwm_off_value = DEFAULT_SPINDLE_PWM_OFF_VALUE, - .pwm_min_value = DEFAULT_SPINDLE_PWM_MIN_VALUE, - .pwm_max_value = DEFAULT_SPINDLE_PWM_MAX_VALUE, + .flags.enable_rpm_controlled = 0, //DEFAULT_SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED, TODO: add setting? + .flags.laser_mode_disable = 0, // TODO: add setting? Not possible? + .invert.on = DEFAULT_INVERT_SPINDLE1_ENABLE_PIN, + .invert.ccw = DEFAULT_INVERT_SPINDLE1_CCW_PIN, + .invert.pwm = DEFAULT_INVERT_SPINDLE1_PWM_PIN, + .pwm_freq = DEFAULT_SPINDLE1_PWM_FREQ, + .pwm_off_value = DEFAULT_SPINDLE1_PWM_OFF_VALUE, + .pwm_min_value = DEFAULT_SPINDLE1_PWM_MIN_VALUE, + .pwm_max_value = DEFAULT_SPINDLE1_PWM_MAX_VALUE, .at_speed_tolerance = DEFAULT_SPINDLE_AT_SPEED_TOLERANCE, .ppr = DEFAULT_SPINDLE_PPR, .pid.p_gain = DEFAULT_SPINDLE_P_GAIN,