From 299eab7f27c2d58607ca31cbafd5c8998e95d843 Mon Sep 17 00:00:00 2001 From: Terje Io Date: Sun, 26 May 2024 17:12:08 +0700 Subject: [PATCH 01/23] Added experimental support for M70-M73, save and restore of modal state. Added experimental support of LinuxCNC style subroutines. Available for gcode run from local filesystem such as on a SD card or in littlefs. Improved handling of G92 when G92 offset is changed while motion is ongoing. Ref. issue #241. Fix for issue #521, crash when running G65 macro on ESP32. "Hardened" stream switching code, likely fix for discussion #456. --- README.md | 7 +- changelog.md | 30 +++++++ gcode.c | 154 ++++++++++++++++++++++++++--------- gcode.h | 40 +++++++-- grbl.h | 2 +- kinematics/polar.c | 4 +- ngc_flowctrl.c | 170 +++++++++++++++++++++++++++++++++++++-- ngc_params.c | 196 +++++++++++++++++++++++++++++++++++++-------- ngc_params.h | 23 ++++-- nuts_bolts.c | 14 ++++ nuts_bolts.h | 3 + planner.c | 2 + planner.h | 2 + platform.h | 24 +++++- protocol.c | 8 +- report.c | 32 +++++--- stepper.c | 18 ++++- stepper.h | 3 + stream.c | 59 +++++++------- system.c | 2 +- system.h | 7 +- tool_change.c | 4 +- 22 files changed, 655 insertions(+), 149 deletions(-) diff --git a/README.md b/README.md index f6b3e72..dfd0f87 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ It has been written to complement grblHAL and has features such as proper keyboa --- -Latest build date is 20240513, see the [changelog](changelog.md) for details. +Latest build date is 20240526, see the [changelog](changelog.md) for details. __NOTE:__ Build 20240222 has moved the probe input to the ioPorts pool of inputs and will be allocated from it when configured. The change is major and _potentially dangerous_, it may damage your probe, so please _verify correct operation_ after installing this, or later, builds. @@ -78,8 +78,9 @@ This is a port/rewrite of [grbl 1.1f](https://github.com/gnea/grbl) and should b - Tool Change: M6* (Two modes possible: manual** - supports jogging, ATC), M61 - Switches: M48, M49, M50, M51, M53 - Input/output control***: M62, M63, M64, M65, M66, M67, M68 + - Modal state handling*: M70, M71, M72, M73 - Return from macro*****: M99 - - Valid Non-Command Words: A*, B*, C*, D, E*, F, H*, I, J, K, L, N, P, Q*, R, S, T, U*, V*, W*, X, Y, Z + - Valid Non-Command Words: A*, B*, C*, D, E*, F, H*, I, J, K, L, N, O*, P, Q*, R, S, T, U*, V*, W*, X, Y, Z * driver/configuration dependent. W axis only available when ABC axes are remapped to UVW or when lathe UVW mode is enabled. ** requires compatible GCode sender due to protocol extensions, new state and RT command. @@ -93,4 +94,4 @@ G/M-codes not supported by [legacy Grbl](https://github.com/gnea/grbl/wiki) are Some [plugins](https://github.com/grblHAL/plugins) implements additional M-codes. --- -20240402 +20240523 diff --git a/changelog.md b/changelog.md index 5b3a16e..42d416a 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,35 @@ ## grblHAL changelog +Build 20240526 + +Core: + +* Added experimental support for M70-M73, save and restore of modal state. + +* Added experimental support of LinuxCNC style subroutines. +Available for gcode run from local filesystem such as on a SD card or in littlefs. + +* Improved handling of G92 when G92 offset is changed while motion is ongoing. +Position and WCO offset in the realtime report will now be the actual realtime values and not +the values based on the parser state which may be quite a bit ahead of the machine. Ref. [issue #241](https://github.com/grblHAL/core/discussions/241#discussioncomment-9463390). + +* Fix for [issue #521](https://github.com/grblHAL/core/issues/521), crash when running G65 macro on ESP32. + +* "Hardened" stream switching code, likely fix for [discussion #456](https://github.com/grblHAL/core/discussions/456#discussioncomment-9533613). + +Drivers: + +* STM32F7xx: added initial support for WizNet W5500 and W5100S ethernet modules. Stack starts up but fails later, likely due to SPI issue?. +To be completed later. + +Plugins: + +* Keypad, OpenPNP and Encoder: updated for core signature change related to improved G92 handling. + +* Networking: fixed incorrect signature of WizNet ethernet init function. + +--- + Build 20240513 Core: diff --git a/gcode.c b/gcode.c index 2091f0d..e3cc3b2 100644 --- a/gcode.c +++ b/gcode.c @@ -105,7 +105,7 @@ typedef union { } ijk_words_t; // Declare gc extern struct -parser_state_t gc_state, *saved_state = NULL; +parser_state_t gc_state; #define FAIL(status) return(status); @@ -186,9 +186,16 @@ axes_signals_t gc_get_g51_state (void) return scaled; } -float gc_get_offset (uint_fast8_t idx) +float gc_get_offset (uint_fast8_t idx, bool real_time) { - return gc_state.modal.coord_system.xyz[idx] + gc_state.g92_coord_offset[idx] + gc_state.tool_length_offset[idx]; + offset_id_t offset_id; + + if(real_time && + !(settings.status_report.machine_position && settings.status_report.sync_on_wco_change) && + (offset_id = st_get_offset_id()) >= 0) + return gc_state.modal.coord_system.xyz[idx] + gc_state.offset_queue[offset_id].values[idx] + gc_state.tool_length_offset[idx]; + else + return gc_state.modal.coord_system.xyz[idx] + gc_state.g92_coord_offset[idx] + gc_state.tool_length_offset[idx]; } inline static float gc_get_block_offset (parser_block_t *gc_block, uint_fast8_t idx) @@ -299,8 +306,12 @@ void gc_init (void) if (!settings_read_coord_data(gc_state.modal.coord_system.id, &gc_state.modal.coord_system.xyz)) grbl.report.status_message(Status_SettingReadFail); - if (sys.cold_start && !settings.flags.g92_is_volatile && !settings_read_coord_data(CoordinateSystem_G92, &gc_state.g92_coord_offset)) - grbl.report.status_message(Status_SettingReadFail); + if(sys.cold_start && !settings.flags.g92_is_volatile) { + if(!settings_read_coord_data(CoordinateSystem_G92, &gc_state.g92_coord_offset)) + grbl.report.status_message(Status_SettingReadFail); + else + memcpy(&gc_state.offset_queue[gc_state.offset_id], &gc_state.g92_coord_offset, sizeof(coord_data_t)); + } if(grbl.on_wco_changed && (!sys.cold_start || !is0_position_vector(gc_state.modal.coord_system.xyz) || @@ -310,6 +321,9 @@ void gc_init (void) #if NGC_EXPRESSIONS_ENABLE ngc_flowctrl_init(); #endif +#if NGC_PARAMETERS_ENABLE + ngc_modal_state_invalidate(); +#endif // if(settings.flags.lathe_mode) // gc_state.modal.plane_select = PlaneSelect_ZX; @@ -349,6 +363,13 @@ spindle_ptrs_t *gc_spindle_get (void) return gc_state.spindle.hal; } +static void add_offset (void) +{ + gc_state.offset_id = (gc_state.offset_id + 1) & (MAX_OFFSET_ENTRIES - 1); + memcpy(&gc_state.offset_queue[gc_state.offset_id], &gc_state.g92_coord_offset, sizeof(coord_data_t)); + system_flag_wco_change(); +} + static tool_data_t *tool_get_pending (tool_id_t tool_id) { static tool_data_t tool_data = {0}; @@ -454,8 +475,15 @@ static status_code_t read_parameter (char *line, uint_fast8_t *char_counter, flo (*char_counter)++; char *pos = line = line + *char_counter; - while(*line && *line != '>') - line++; + while(*line && *line != '>') { + if(*line == ' ') { + char *s1 = line, *s2 = line + 1; + while(*s2) + *s1++ = *s2++; + *(--s2) = '\0'; + } else + line++; + } *char_counter += line - pos + 1; @@ -467,7 +495,7 @@ static status_code_t read_parameter (char *line, uint_fast8_t *char_counter, flo } else status = Status_BadNumberFormat; - } else if (read_float(line, char_counter, value)) { + } else if(read_float(line, char_counter, value)) { if(!ngc_param_get((ngc_param_id_t)*value, value)) status = Status_BadNumberFormat; } else @@ -481,8 +509,39 @@ static status_code_t read_parameter (char *line, uint_fast8_t *char_counter, flo return status; } + #endif // NGC_EXPRESSIONS_ENABLE +#if NGC_PARAMETERS_ENABLE + +bool gc_modal_state_restore (gc_modal_t *copy) +{ + bool ok = false; + + if((ok = !!copy && !ABORTED)) { + + copy->auto_restore = false; + copy->motion = gc_state.modal.motion; + + if(copy->coolant.value != gc_state.modal.coolant.value) { + hal.coolant.set_state(copy->coolant); + delay_sec(settings.safety_door.coolant_on_delay, DelayMode_SysSuspend); + } + + if(copy->spindle.state.value != gc_state.modal.spindle.state.value || copy->rpm != gc_state.modal.rpm) + spindle_restore(gc_state.spindle.hal, copy->spindle.state, copy->rpm); + + memcpy(&gc_state.modal, copy, sizeof(gc_modal_t)); + + gc_state.spindle.rpm = gc_state.modal.rpm; + gc_state.feed_rate = gc_state.modal.feed_rate; + } + + return ok; +} + +#endif // NGC_PARAMETERS_ENABLE + // Remove whitespace, control characters, comments and if block delete is active block delete lines // else the block delete character. Remaining characters are converted to upper case. // If the driver handles message comments then the first is extracted and returned in a dynamically @@ -561,7 +620,7 @@ char *gc_normalize_block (char *block, char **message) if(c == '#') { char_counter--; if(read_parameter(comment, &char_counter, &value) == Status_OK) - len += strlen(ftoa(value, 6)); + len += strlen(trim_float(ftoa(value, 6))); else len += 3; // "N/A" } else @@ -578,7 +637,7 @@ char *gc_normalize_block (char *block, char **message) if(c == '#') { char_counter--; if(read_parameter(comment, &char_counter, &value) == Status_OK) - strcat(s3, ftoa(value, 6)); + strcat(s3, trim_float(ftoa(value, 6))); else strcat(s3, "N/A"); s3 = strchr(s3, '\0'); @@ -1263,30 +1322,13 @@ status_code_t gc_execute_block (char *block) word_bit.modal_group.M10 = On; port_command = (io_mcode_t)int_value; break; -/* - case 70: - if(!saved_state) - saved_state = malloc(sizeof(parser_state_t)); - if(!saved_state) - FAIL(Status_GcodeUnsupportedCommand); // [Unsupported M command] - memcpy(saved_state, &gc_state, sizeof(parser_state_t)); - return Status_OK; - case 71: // Invalidate saved state - if(saved_state) { - free(saved_state); - saved_state = NULL; - } - return Status_OK; // Should fail if no state is saved... - - case 72: - if(saved_state) { - // TODO: restore state, need to split out execution part of parser to separate functions first? - free(saved_state); - saved_state = NULL; - } - return Status_OK; -*/ +#if NGC_PARAMETERS_ENABLE + case 70: case 71: case 72: case 73: + //word_bit.modal_group.G0 = On; ?? + gc_block.state_action = (modal_state_action_t)int_value; + break; +#endif case 99: word_bit.modal_group.M4 = On; @@ -2348,6 +2390,10 @@ status_code_t gc_execute_block (char *block) FAIL(Status_GcodeValueWordMissing); // [P word missing] if(gc_block.values.p > 65535.0f) FAIL(Status_GcodeValueOutOfRange); // [P word out of range] +#if NGC_PARAMETERS_ENABLE + if(!ngc_call_push(&gc_state + ngc_call_level())) + FAIL(Status_FlowControlStackOverflow); // [Call level too deep] +#endif #if NGC_EXPRESSIONS_ENABLE // TODO: add context for local storage? { @@ -2934,6 +2980,7 @@ status_code_t gc_execute_block (char *block) // Initialize planner data struct for motion blocks. plan_line_data_t plan_data; memset(&plan_data, 0, sizeof(plan_line_data_t)); // Zero plan_data struct + plan_data.offset_id = gc_state.offset_id; plan_data.condition.target_validated = plan_data.condition.target_valid = sys.soft_limits.mask == 0; // Intercept jog commands and complete error checking for valid jog commands and execute. @@ -3011,7 +3058,7 @@ status_code_t gc_execute_block (char *block) if(gc_block.modal.motion != MotionMode_None && gc_block.modal.motion != MotionMode_Seek) { gc_state.spindle.css = &gc_state.spindle.hal->param->css; gc_state.spindle.css->axis = plane.axis_1; - gc_state.spindle.css->tool_offset = gc_get_offset(gc_state.spindle.css->axis); + gc_state.spindle.css->tool_offset = gc_get_offset(gc_state.spindle.css->axis, false); float pos = gc_state.position[gc_state.spindle.css->axis] - gc_state.spindle.css->tool_offset; gc_block.values.s = pos <= 0.0f ? gc_state.spindle.css->max_rpm : min(gc_state.spindle.css->max_rpm, gc_state.spindle.css->surface_speed / (pos * (float)(2.0f * M_PI))); //?? gc_parser_flags.spindle_force_sync = On; @@ -3198,6 +3245,33 @@ status_code_t gc_execute_block (char *block) plan_data.condition.is_rpm_rate_adjusted = gc_state.is_rpm_rate_adjusted; plan_data.condition.is_laser_ppi_mode = gc_state.is_rpm_rate_adjusted && gc_state.is_laser_ppi_mode; +#if NGC_PARAMETERS_ENABLE + + // [7a. Modal state actions ]: + switch(gc_block.state_action) { + + case ModalState_Save: + case ModalState_SaveAutoRestore: + gc_state.modal.rpm = gc_state.spindle.rpm; + gc_state.modal.feed_rate = gc_state.feed_rate; + if(!ngc_modal_state_save(&gc_state.modal, gc_block.state_action == ModalState_SaveAutoRestore)) + FAIL(Status_FlowControlOutOfMemory); // [Out of memory] TODO: allocate memory during validation? Static allocation? + break; + + case ModalState_Invalidate: + ngc_modal_state_invalidate(); + break; + + case ModalState_Restore: + ngc_modal_state_restore(); + break; + + default: + break; + } + +#endif // NGC_PARAMETERS_ENABLE + // [8. Coolant control ]: if (gc_parser_flags.set_coolant && gc_state.modal.coolant.value != gc_block.modal.coolant.value) { // NOTE: Coolant M-codes are modal. Only one command per line is allowed. But, multiple states @@ -3370,7 +3444,7 @@ status_code_t gc_execute_block (char *block) memcpy(gc_state.g92_coord_offset, gc_block.values.xyz, sizeof(gc_state.g92_coord_offset)); if(!settings.flags.g92_is_volatile) settings_write_coord_data(CoordinateSystem_G92, &gc_state.g92_coord_offset); // Save G92 offsets to non-volatile storage - system_flag_wco_change(); + add_offset(); break; case NonModal_ResetCoordinateOffset: // G92.1 @@ -3378,19 +3452,19 @@ status_code_t gc_execute_block (char *block) clear_vector(gc_state.g92_coord_offset); // Disable G92 offsets by zeroing offset vector. if(!settings.flags.g92_is_volatile) settings_write_coord_data(CoordinateSystem_G92, &gc_state.g92_coord_offset); // Save G92 offsets to non-volatile storage - system_flag_wco_change(); + add_offset(); break; case NonModal_ClearCoordinateOffset: // G92.2 gc_state.g92_coord_offset_applied = false; clear_vector(gc_state.g92_coord_offset); // Disable G92 offsets by zeroing offset vector. - system_flag_wco_change(); + add_offset(); break; case NonModal_RestoreCoordinateOffset: // G92.3 gc_state.g92_coord_offset_applied = true; // TODO: check for all zero? settings_read_coord_data(CoordinateSystem_G92, &gc_state.g92_coord_offset); // Restore G92 offsets from non-volatile storage - system_flag_wco_change(); + add_offset(); break; default: @@ -3647,6 +3721,10 @@ status_code_t gc_execute_block (char *block) output_commands = next; } +#if NGC_PARAMETERS_ENABLE + ngc_modal_state_invalidate(); +#endif + grbl.report.feedback_message(Message_ProgramEnd); } gc_state.modal.program_flow = ProgramFlow_Running; // Reset program flow. diff --git a/gcode.h b/gcode.h index 36d29ed..85cf8a0 100644 --- a/gcode.h +++ b/gcode.h @@ -3,22 +3,22 @@ Part of grblHAL - Copyright (c) 2017-2023 Terje Io + Copyright (c) 2017-2024 Terje Io Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC Copyright (c) 2009-2011 Simen Svale Skogsrud - Grbl is free software: you can redistribute it and/or modify + grblHAL is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Grbl is distributed in the hope that it will be useful, + grblHAL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Grbl. If not, see . + along with grblHAL. If not, see . */ #ifndef _GCODE_H_ @@ -29,8 +29,11 @@ #include "spindle_control.h" #include "errors.h" +#define MAX_OFFSET_ENTRIES 4 // must be a power of 2 + typedef uint32_t tool_id_t; typedef uint16_t macro_id_t; +typedef int8_t offset_id_t; // Define command actions for within execution-type modal groups (motion, stopping, non-modal). Used // internally by the parser to know which command to execute. @@ -59,6 +62,15 @@ typedef enum { NonModal_RestoreCoordinateOffset = 122 //!< 122 - G92.3 } non_modal_t; + +typedef enum { + ModalState_NoAction = 0, //!< 0 - Default, must be zero + ModalState_Save = 70, //!< 70 - M70 + ModalState_Invalidate = 71, //!< 71 - M71 + ModalState_Restore = 72, //!< 72 - M72 + ModalState_SaveAutoRestore = 73, //!< 73 - M73 +} modal_state_action_t; + /*! Modal Group G1: Motion modes Do not alter values! @@ -411,7 +423,7 @@ typedef struct { coord_system_t coord_data; //!< Coordinate data int32_t $; //!< Spindle id - single-meaning word int32_t n; //!< Line number - single-meaning word - uint32_t o; //!< Subroutine identifier - single-meaning word (not used by the core) + uint32_t o; //!< Subroutine identifier - single-meaning word uint32_t h; //!< Tool number or number of G76 thread spring passes tool_id_t t; //!< Tool selection - single-meaning word uint8_t l; //!< G10 or canned cycles parameters @@ -493,6 +505,11 @@ typedef struct { bool scaling_active; //!< {G50,G51} bool canned_cycle_active; float spline_pq[2]; //!< {G5} +#if NGC_PARAMETERS_ENABLE + bool auto_restore; + float feed_rate; //!< {F} NOTE: only set when saving modal state + float rpm; //!< {S} NOTE: only set when saving modal state +#endif } gc_modal_t; //! Data for canned cycles. @@ -570,6 +587,8 @@ typedef struct { bool tool_change; bool skip_blocks; //!< true if skipping conditional blocks status_code_t last_error; //!< last return value from parser + offset_id_t offset_id; //!< id(x) of last G92 coordinate offset (into circular buffer) + coord_data_t offset_queue[MAX_OFFSET_ENTRIES]; //!< The following variables are not cleared upon warm restart when COMPATIBILITY_LEVEL <= 1 bool g92_coord_offset_applied; //!< true when G92 offset applied float g92_coord_offset[N_AXIS]; //!< Retains the G92 coordinate offset (work coordinates) relative to @@ -602,6 +621,9 @@ typedef struct { output_command_t output_command; //!< Details about M62-M68 output command to execute if present in block. uint32_t arc_turns; // spindle_ptrs_t *spindle; //!< Spindle to control, NULL for all +#if NGC_PARAMETERS_ENABLE + modal_state_action_t state_action; //!< M70-M73 modal state action +#endif } parser_block_t; // Initialize the parser @@ -629,7 +651,7 @@ axes_signals_t gc_get_g51_state (void); float *gc_get_scaling (void); // Get current axis offset. -float gc_get_offset (uint_fast8_t idx); +float gc_get_offset (uint_fast8_t idx, bool real_time); spindle_ptrs_t *gc_spindle_get (void); @@ -639,4 +661,8 @@ void gc_coolant (coolant_state_t state); void gc_set_tool_offset (tool_offset_mode_t mode, uint_fast8_t idx, int32_t offset); plane_t *gc_get_plane_data (plane_t *plane, plane_select_t select); +#if NGC_PARAMETERS_ENABLE +bool gc_modal_state_restore (gc_modal_t *copy); #endif + +#endif // _GCODE_H_ diff --git a/grbl.h b/grbl.h index be5c054..972e12f 100644 --- a/grbl.h +++ b/grbl.h @@ -42,7 +42,7 @@ #else #define GRBL_VERSION "1.1f" #endif -#define GRBL_BUILD 20240513 +#define GRBL_BUILD 20240526 #define GRBL_URL "https://github.com/grblHAL" diff --git a/kinematics/polar.c b/kinematics/polar.c index 9db460f..3aa6636 100644 --- a/kinematics/polar.c +++ b/kinematics/polar.c @@ -135,7 +135,7 @@ static float *polar_segment_line (float *target, float *position, plan_line_data if(init) { jog_cancel = false; - r_offset = gc_get_offset(RADIUS_AXIS) * 2.0f; //?? + r_offset = gc_get_offset(RADIUS_AXIS, false) * 2.0f; //?? memcpy(final_target.values, target, sizeof(final_target)); @@ -229,7 +229,7 @@ static void report_options (bool newopt) on_report_options(newopt); if(!newopt) - hal.stream.write("[KINEMATICS:Polar v0.02]" ASCII_EOL); + hal.stream.write("[KINEMATICS:Polar v0.03]" ASCII_EOL); } static bool polar_homing_cycle (axes_signals_t cycle, axes_signals_t auto_square) diff --git a/ngc_flowctrl.c b/ngc_flowctrl.c index a7c2125..3b6568a 100644 --- a/ngc_flowctrl.c +++ b/ngc_flowctrl.c @@ -32,7 +32,7 @@ #include "ngc_params.h" #ifndef NGC_STACK_DEPTH -#define NGC_STACK_DEPTH 10 +#define NGC_STACK_DEPTH 20 #endif typedef enum { @@ -48,14 +48,25 @@ typedef enum { NGCFlowCtrl_EndWhile, NGCFlowCtrl_Repeat, NGCFlowCtrl_EndRepeat, + NGCFlowCtrl_Sub, + NGCFlowCtrl_EndSub, + NGCFlowCtrl_Call, NGCFlowCtrl_Return, NGCFlowCtrl_RaiseAlarm, NGCFlowCtrl_RaiseError } ngc_cmd_t; +typedef struct ngc_sub { + uint32_t o_label; + vfs_file_t *file; + size_t file_pos; + struct ngc_sub *next; +} ngc_sub_t; + typedef struct { uint32_t o_label; ngc_cmd_t operation; + ngc_sub_t *sub; vfs_file_t *file; size_t file_pos; char *expr; @@ -66,6 +77,8 @@ typedef struct { } ngc_stack_entry_t; static volatile int_fast8_t stack_idx = -1; +static bool skip_sub = false; +static ngc_sub_t *subs = NULL, *exec_sub = NULL; static ngc_stack_entry_t stack[NGC_STACK_DEPTH] = {0}; static status_code_t read_command (char *line, uint_fast8_t *pos, ngc_cmd_t *operation) @@ -97,6 +110,9 @@ static status_code_t read_command (char *line, uint_fast8_t *pos, ngc_cmd_t *ope if (!strncmp(line + *pos, "ONTINUE", 7)) { *operation = NGCFlowCtrl_Continue; *pos += 7; + } else if (!strncmp(line + *pos, "ALL", 3)) { + *operation = NGCFlowCtrl_Call; + *pos += 3; } else status = Status_FlowControlSyntaxError; // Unknown statement name starting with C break; @@ -125,6 +141,9 @@ static status_code_t read_command (char *line, uint_fast8_t *pos, ngc_cmd_t *ope } else if (!strncmp(line + *pos, "NDREPEAT", 8)) { *operation = NGCFlowCtrl_EndRepeat; *pos += 8; + } else if (!strncmp(line + *pos, "NDSUB", 5)) { + *operation = NGCFlowCtrl_EndSub; + *pos += 5; } else if (!strncmp(line + *pos, "RROR", 4)) { *operation = NGCFlowCtrl_RaiseError; *pos += 4; @@ -151,6 +170,14 @@ static status_code_t read_command (char *line, uint_fast8_t *pos, ngc_cmd_t *ope *operation = Status_FlowControlSyntaxError; // Unknown statement name starting with R break; + case 'S': + if (!strncmp(line + *pos, "UB", 2)) { + *operation = NGCFlowCtrl_Sub; + *pos += 2; + } else + status = Status_FlowControlSyntaxError; // Unknown statement name starting with S + break; + case 'W': if (!strncmp(line + *pos, "HILE", 4)) { *operation = NGCFlowCtrl_While; @@ -166,12 +193,34 @@ static status_code_t read_command (char *line, uint_fast8_t *pos, ngc_cmd_t *ope return status; } +static void clear_subs (vfs_file_t *file) +{ + ngc_sub_t *current = subs, *prev = NULL, *next; + + subs = NULL; + + while(current) { + next = current->next; + if(file == NULL || file == current->file) { + free(current); + if(prev) + prev->next = next; + } else { + if(subs == NULL) + subs = current; + prev = current; + } + current = next; + } +} + static status_code_t stack_push (uint32_t o_label, ngc_cmd_t operation) { - if(stack_idx < (NGC_STACK_DEPTH - 1)) { + if(stack_idx < (NGC_STACK_DEPTH - 1) && (operation != NGCFlowCtrl_Call || ngc_call_push(&stack[stack_idx + 1]))) { stack[++stack_idx].o_label = o_label; stack[stack_idx].file = hal.stream.file; stack[stack_idx].operation = operation; + stack[stack_idx].sub = exec_sub; return Status_OK; } @@ -185,6 +234,8 @@ static bool stack_pull (void) if((ok = stack_idx >= 0)) { if(stack[stack_idx].expr) free(stack[stack_idx].expr); + if(stack[stack_idx].operation == NGCFlowCtrl_Call) + ngc_call_pop(); memset(&stack[stack_idx], 0, sizeof(ngc_stack_entry_t)); stack_idx--; } @@ -192,16 +243,31 @@ static bool stack_pull (void) return ok; } +static void stack_unwind_sub (uint32_t o_label) +{ + while(stack_idx >= 0 && stack[stack_idx].o_label != o_label) + stack_pull(); + + if(stack_idx >= 0) { + vfs_seek(stack[stack_idx].file, stack[stack_idx].file_pos); + stack_pull(); + } + + exec_sub = stack_idx >= 0 ? stack[stack_idx].sub : NULL; +} + // Public functions void ngc_flowctrl_unwind_stack (vfs_file_t *file) { + clear_subs(file); while(stack_idx >= 0 && stack[stack_idx].file == file) stack_pull(); } void ngc_flowctrl_init (void) { + clear_subs(NULL); while(stack_idx >= 0) stack_pull(); } @@ -217,8 +283,8 @@ status_code_t ngc_flowctrl (uint32_t o_label, char *line, uint_fast8_t *pos, boo if((status = read_command(line, pos, &operation)) != Status_OK) return status; - skipping = stack_idx >= 0 && stack[stack_idx].skip; - last_op = stack_idx >= 0 ? stack[stack_idx].operation : NGCFlowCtrl_NoOp; + skipping = skip_sub || (stack_idx >= 0 && stack[stack_idx].skip); + last_op = stack_idx >= 0 ? stack[stack_idx].operation : (skip_sub ? NGCFlowCtrl_Sub : NGCFlowCtrl_NoOp); switch(operation) { @@ -421,16 +487,104 @@ status_code_t ngc_flowctrl (uint32_t o_label, char *line, uint_fast8_t *pos, boo status = (status_code_t)value; break; + case NGCFlowCtrl_Sub: + if(hal.stream.file) { + ngc_sub_t *sub; + if((skip_sub = (sub = malloc(sizeof(ngc_sub_t))) != NULL)) { + sub->o_label = o_label; + sub->file = hal.stream.file; + sub->file_pos = vfs_tell(hal.stream.file); + sub->next = NULL; + if(subs == NULL) + subs = sub; + else { + ngc_sub_t *last = subs; + while(last->next) + last = last->next; + last->next = sub; + } + } // else out of memory + } else + status = Status_FlowControlNotExecutingMacro; + break; + + case NGCFlowCtrl_EndSub: + if(hal.stream.file) { + if(!skip_sub) + stack_unwind_sub(o_label); + skip_sub = false; + } else + status = Status_FlowControlNotExecutingMacro; + break; + + case NGCFlowCtrl_Call: + if(hal.stream.file) { + if(!skipping) { + + ngc_sub_t *sub = subs; + do { + if(sub->o_label == o_label && sub->file == hal.stream.file) + break; + } while((sub = sub->next)); + + if(sub == NULL) + status = Status_FlowControlSyntaxError; + else { + + float params[29]; + ngc_param_id_t param_id = 1; + + while(line[*pos] && status == Status_OK && param_id <= 30) { + status = ngc_eval_expression(line, pos, ¶ms[param_id - 1]); + param_id++; + } + + if(status == Status_OK && param_id < 30) do { + ngc_param_get(param_id, ¶ms[param_id - 1]); + } while(++param_id <= 30); + + if(status == Status_OK && (status = stack_push(o_label, operation)) == Status_OK) { + + stack[stack_idx].sub = exec_sub = sub; + stack[stack_idx].file = hal.stream.file; + stack[stack_idx].file_pos = vfs_tell(hal.stream.file); + stack[stack_idx].repeats = 1; + + for(param_id = 1; param_id <= 30; param_id++) { + if(params[param_id - 1] != 0.0f) { + if(!ngc_param_set(param_id, params[param_id - 1])) + status = Status_FlowControlOutOfMemory; + } + } + + if(status == Status_OK) + vfs_seek(sub->file, sub->file_pos); + } + } + } + } else + status = Status_FlowControlNotExecutingMacro; + break; + case NGCFlowCtrl_Return: if(hal.stream.file) { - if(!skipping && grbl.on_macro_return) { - ngc_flowctrl_unwind_stack(stack[stack_idx].file); + if(!skipping) { + + bool g65_return = false; + + if(exec_sub) + stack_unwind_sub(o_label); + else if((g65_return = !!grbl.on_macro_return)) + ngc_flowctrl_unwind_stack(stack[stack_idx].file); + if(ngc_eval_expression(line, pos, &value) == Status_OK) { ngc_named_param_set("_value", value); ngc_named_param_set("_value_returned", 1.0f); } else ngc_named_param_set("_value_returned", 0.0f); - grbl.on_macro_return(); + + if(g65_return) + grbl.on_macro_return(); } } else status = Status_FlowControlNotExecutingMacro; @@ -446,7 +600,7 @@ status_code_t ngc_flowctrl (uint32_t o_label, char *line, uint_fast8_t *pos, boo if(settings.flags.ngc_debug_out) report_message(line, Message_Plain); } else - *skip = stack_idx >= 0 && stack[stack_idx].skip; + *skip = skip_sub || (stack_idx >= 0 && stack[stack_idx].skip); return status; } diff --git a/ngc_params.c b/ngc_params.c index 587d6c4..8364ab7 100644 --- a/ngc_params.c +++ b/ngc_params.c @@ -38,7 +38,12 @@ #include "settings.h" #include "ngc_params.h" -#define MAX_PARAM_LENGTH 20 +#ifndef NGC_MAX_CALL_LEVEL +#define NGC_MAX_CALL_LEVEL 10 +#endif +#ifndef NGC_MAX_PARAM_LENGTH +#define NGC_MAX_PARAM_LENGTH 20 +#endif typedef float (*ngc_param_get_ptr)(ngc_param_id_t id); typedef float (*ngc_named_param_get_ptr)(void); @@ -50,6 +55,7 @@ typedef struct { } ngc_ro_param_t; typedef struct ngc_rw_param { + void *context; ngc_param_id_t id; float value; struct ngc_rw_param *next; @@ -62,20 +68,31 @@ typedef struct { } ngc_named_ro_param_t; typedef struct ngc_named_rw_param { - char name[MAX_PARAM_LENGTH + 1]; + void *context; + char name[NGC_MAX_PARAM_LENGTH + 1]; float value; struct ngc_named_rw_param *next; } ngc_named_rw_param_t; -ngc_rw_param_t *rw_params = NULL; -ngc_named_rw_param_t *rw_global_params = NULL; +typedef struct { + uint32_t level; + void *context; + gc_modal_t *modal_state; +} ngc_param_context_t; + +static int32_t call_level = -1; +static void *call_context; +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 float _relative_pos (uint_fast8_t axis) { float value; if(axis < N_AXIS) { - value = sys.position[axis] / settings.axis[axis].steps_per_mm - gc_get_offset(axis); + value = sys.position[axis] / settings.axis[axis].steps_per_mm - gc_get_offset(axis, false); if(settings.flags.report_inches) value *= 25.4f; } else @@ -249,9 +266,10 @@ bool ngc_param_get (ngc_param_id_t id, float *value) *value = 0.0f; if(found) { + void *context = id > (ngc_param_id_t)30 ? NULL : call_context; ngc_rw_param_t *rw_param = rw_params; while(rw_param) { - if(rw_param->id == id) { + if(rw_param->context == context && rw_param->id == id) { *value = rw_param->value; rw_param = NULL; } else @@ -282,10 +300,11 @@ bool ngc_param_set (ngc_param_id_t id, float value) if(ok) { + void *context = id > (ngc_param_id_t)30 ? NULL : call_context; ngc_rw_param_t *rw_param = rw_params, *rw_param_last = rw_params; while(rw_param) { - if(rw_param->id == id) { + if(rw_param->context == context && rw_param->id == id) { break; } else { rw_param_last = rw_param; @@ -295,6 +314,7 @@ bool ngc_param_set (ngc_param_id_t id, float value) if(rw_param == NULL && value != 0.0f && (rw_param = malloc(sizeof(ngc_rw_param_t)))) { rw_param->id = id; + rw_param->context = context; rw_param->next = NULL; if(rw_params == NULL) rw_params = rw_param; @@ -357,6 +377,7 @@ PROGMEM static const ngc_named_ro_param_t ngc_named_ro_param[] = { { .name = "_current_pocket", .id = NGCParam_current_pocket }, { .name = "_selected_tool", .id = NGCParam_selected_tool }, { .name = "_selected_pocket", .id = NGCParam_selected_pocket }, + { .name = "_call_level", .id = NGCParam_call_level }, }; @@ -539,6 +560,10 @@ float ngc_named_param_get_by_id (ncg_name_param_id_t id) value = 0.0f; break; + case NGCParam_call_level: + value = (float)ngc_call_level(); + break; + default: value = NAN; } @@ -546,15 +571,32 @@ float ngc_named_param_get_by_id (ncg_name_param_id_t id) return value; } +// Lowercase name, remove control characters and spaces +// Assumes names stored in flash are lowercase... +static char *ngc_name_tolower (char *name) +{ + char c, *s1 = name, *s2 = name; + bool convert = false; + + while((c = *s1++) && c > ' ') + convert = (c & 0x20) == 0 || c <= ' '; + + if(convert) { + s1 = name; + while((c = *s1++) && c > ' ') + *s2++ = LCAPS(c); + *s2 = '\0'; + } + + return name; +} + bool ngc_named_param_get (char *name, float *value) { - char c, *s = name; bool found = false; uint_fast8_t idx = sizeof(ngc_named_ro_param) / sizeof(ngc_named_ro_param_t); - // Lowercase name - while((c = *s)) - *s++ = LCAPS(c); + ngc_name_tolower(name); *value = 0.0f; @@ -565,9 +607,10 @@ bool ngc_named_param_get (char *name, float *value) } while(idx && !found); if(!found) { + void *context = *name == '_' ? NULL : call_context; ngc_named_rw_param_t *rw_param = rw_global_params; while(rw_param && !found) { - if((found = !strcmp(rw_param->name, name))) + if((found = rw_param->context == context && !strcmp(rw_param->name, name))) *value = rw_param->value; else rw_param = rw_param->next; @@ -579,15 +622,10 @@ bool ngc_named_param_get (char *name, float *value) bool ngc_named_param_exists (char *name) { - char c, *s1 = name, *s2 = name; bool ok = false; uint_fast8_t idx = sizeof(ngc_named_ro_param) / sizeof(ngc_named_ro_param_t); - // Lowercase name, remove control characters and spaces - while((c = *s1++) && c > ' ') - *s2++ = LCAPS(c); - - *s2 = '\0'; + ngc_name_tolower(name); // Check if name is supplied, return false if not. if((*name == '_' ? *(name + 1) : *name) == '\0') @@ -595,36 +633,31 @@ bool ngc_named_param_exists (char *name) // Check if it is a (read only) predefined parameter. if(*name == '_') do { - idx--; - ok = !strcmp(name, ngc_named_ro_param[idx].name); + ok = !strcmp(name, ngc_named_ro_param[--idx].name); } while(idx && !ok); // If not predefined attempt to find it. - if(!ok && rw_global_params && strlen(name) < MAX_PARAM_LENGTH) { + if(!ok && rw_global_params && strlen(name) < NGC_MAX_PARAM_LENGTH) { + void *context = *name == '_' ? NULL : call_context; ngc_named_rw_param_t *rw_param = rw_global_params; while(rw_param) { - if((ok = !strcmp(rw_param->name, name))) + if((ok = rw_param->context == context && !strcmp(rw_param->name, name))) break; rw_param = rw_param->next; - } - } + } + } return ok; } bool ngc_named_param_set (char *name, float value) { - char c, *s1 = name, *s2 = name; bool ok = false; uint_fast8_t idx = sizeof(ngc_named_ro_param) / sizeof(ngc_named_ro_param_t); - // Lowercase name, remove control characters and spaces - while((c = *s1++) && c > ' ') - *s2++ = LCAPS(c); - - *s2 = '\0'; + ngc_name_tolower(name); // Check if name is supplied, return false if not. if((*name == '_' ? *(name + 1) : *name) == '\0') @@ -637,12 +670,13 @@ bool ngc_named_param_set (char *name, float value) } while(idx && !ok); // If not predefined attempt to set it. - if(!ok && (ok = strlen(name) < MAX_PARAM_LENGTH)) { + if(!ok && (ok = strlen(name) < NGC_MAX_PARAM_LENGTH)) { + void *context = *name == '_' ? NULL : call_context; ngc_named_rw_param_t *rw_param = rw_global_params, *rw_param_last = rw_global_params; while(rw_param) { - if(!strcmp(rw_param->name, name)) { + if(rw_param->context == context && !strcmp(rw_param->name, name)) { break; } else { rw_param_last = rw_param; @@ -652,6 +686,7 @@ bool ngc_named_param_set (char *name, float value) if(rw_param == NULL && (rw_param = malloc(sizeof(ngc_named_rw_param_t)))) { strcpy(rw_param->name, name); + rw_param->context = context; rw_param->next = NULL; if(rw_global_params == NULL) rw_global_params = rw_param; @@ -666,4 +701,101 @@ bool ngc_named_param_set (char *name, float value) return ok; } +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; + + if(*saved_state == NULL) + *saved_state = malloc(sizeof(gc_modal_t)); + + if(*saved_state) + memcpy(*saved_state, state, sizeof(gc_modal_t)); + + return *saved_state != NULL; +} + +void ngc_modal_state_invalidate (void) +{ + gc_modal_t **saved_state = call_level == -1 ? &modal_state : &call_levels[call_level].modal_state; + + if(*saved_state) { + free(*saved_state); + *saved_state = NULL; + } +} + +bool ngc_modal_state_restore (void) +{ + return gc_modal_state_restore(call_level == -1 ? modal_state : call_levels[call_level].modal_state); +} + +bool ngc_call_push (void *context) +{ + bool ok; + + if((ok = call_level < (NGC_MAX_CALL_LEVEL - 1))) + call_levels[++call_level].context = call_context = context; + + return ok; +} + +bool ngc_call_pop (void) +{ + if(call_level >= 0) { + + if(call_context) { + + ngc_rw_param_t *rw_param = rw_params, *rw_param_last = rw_params; + + while(rw_param) { + if(rw_param->context == call_context) { + ngc_rw_param_t *rw_param_free = rw_param; + rw_param = rw_param->next; + if(rw_param_free == rw_params) + rw_params = rw_param_last = rw_param; + else + rw_param_last->next = rw_param; + free(rw_param_free); + } else { + rw_param_last = rw_param; + rw_param = rw_param->next; + } + } + + ngc_named_rw_param_t *rw_named_param = rw_global_params, *rw_named_param_last = rw_global_params; + + while(rw_named_param) { + if(rw_named_param->context == call_context) { + ngc_named_rw_param_t *rw_named_param_free = rw_named_param; + rw_named_param = rw_named_param->next; + if(rw_named_param_free == rw_global_params) + rw_global_params = rw_named_param_last = rw_named_param; + else + rw_named_param_last->next = rw_named_param; + free(rw_named_param_free); + } else { + rw_named_param_last = rw_named_param; + rw_named_param = rw_named_param->next; + } + } + } + + if(call_levels[call_level].modal_state) { + if(call_levels[call_level].modal_state->auto_restore) + gc_modal_state_restore(call_levels[call_level].modal_state); + free(call_levels[call_level].modal_state); + call_levels[call_level].modal_state = NULL; + } + + call_context = --call_level >= 0 ? call_levels[call_level].context : NULL; + } + + return call_level >= 0; +} + +uint_fast8_t ngc_call_level (void) +{ + return (uint_fast8_t)(call_level + 1); +} + #endif // NGC_PARAMETERS_ENABLE diff --git a/ngc_params.h b/ngc_params.h index 38052fa..198695b 100644 --- a/ngc_params.h +++ b/ngc_params.h @@ -1,22 +1,22 @@ /* - ngc_params.c - get/set NGC parameter value by id or name + ngc_params.h - get/set NGC parameter value by id or name Part of grblHAL - Copyright (c) 2021 Terje Io + Copyright (c) 2021-2024 Terje Io - Grbl is free software: you can redistribute it and/or modify + grblHAL is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Grbl is distributed in the hope that it will be useful, + grblHAL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Grbl. If not, see . + along with grblHAL. If not, see . */ /* @@ -28,6 +28,8 @@ #ifndef _NGC_PARAMS_H_ #define _NGC_PARAMS_H_ +#include "gcode.h" + typedef uint16_t ngc_param_id_t; typedef struct { @@ -81,6 +83,7 @@ typedef enum { NGCParam_current_pocket, NGCParam_selected_tool, NGCParam_selected_pocket, + NGCParam_call_level, NGCParam_Last } ncg_name_param_id_t; @@ -92,5 +95,11 @@ 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_call_push (void *context); +bool ngc_call_pop (void); +uint_fast8_t ngc_call_level (void); +bool ngc_modal_state_save (gc_modal_t *state, bool auto_restore); +bool ngc_modal_state_restore (void); +void ngc_modal_state_invalidate (void); -#endif +#endif // _NGC_PARAMS_H_ diff --git a/nuts_bolts.c b/nuts_bolts.c index ce23790..a81195c 100644 --- a/nuts_bolts.c +++ b/nuts_bolts.c @@ -166,6 +166,20 @@ char *ftoa (float n, uint8_t decimal_places) return bptr; } +// Trim trailing zeros and possibly decimal point +char *trim_float (char *s) +{ + if(strchr(s, '.')) { + char *s2 = strchr(s, '\0') - 1; + while(*s2 == '0') + *s2-- = '\0'; + if(*s2 == '.') + *s2 = '\0'; + } + + return s; +} + // Extracts an unsigned integer value from a string. status_code_t read_uint (char *line, uint_fast8_t *char_counter, uint32_t *uint_ptr) { diff --git a/nuts_bolts.h b/nuts_bolts.h index 2feafc3..ae6f6f3 100644 --- a/nuts_bolts.h +++ b/nuts_bolts.h @@ -211,6 +211,9 @@ char *uitoa (uint32_t n); // Converts a float variable to string with the specified number of decimal places. char *ftoa (float n, uint8_t decimal_places); +// Trim trailing zeros and possibly decimal point +char *trim_float (char *s); + // Returns true if float value is a whole number (integer) bool isintf (float value); diff --git a/planner.c b/planner.c index 5e56695..d3011b1 100644 --- a/planner.c +++ b/planner.c @@ -397,6 +397,7 @@ bool plan_buffer_line (float *target, plan_line_data_t *pl_data) block->condition = pl_data->condition; block->overrides = pl_data->overrides; block->line_number = pl_data->line_number; + block->offset_id = pl_data->offset_id; block->output_commands = pl_data->output_commands; block->message = pl_data->message; @@ -689,6 +690,7 @@ void plan_feed_override (override_t feed_override, override_t rapid_override) void plan_data_init (plan_line_data_t *plan_data) { memset(plan_data, 0, sizeof(plan_line_data_t)); + plan_data->offset_id = gc_state.offset_id; plan_data->spindle.hal = gc_state.spindle.hal ? gc_state.spindle.hal : spindle_get(0); plan_data->condition.target_validated = plan_data->condition.target_valid = sys.soft_limits.mask == 0; #ifdef KINEMATICS_API diff --git a/planner.h b/planner.h index b4c776f..52667a3 100644 --- a/planner.h +++ b/planner.h @@ -52,6 +52,7 @@ typedef struct plan_block { uint32_t step_event_count; // The maximum step axis count and number of steps required to complete this block. axes_signals_t direction_bits; // The direction bit set for this block (refers to *_DIRECTION_PIN in config.h) + offset_id_t offset_id; // Block condition data to ensure correct execution depending on states and overrides. gc_override_flags_t overrides; // Block bitfield variable for overrides planner_cond_t condition; // Block bitfield variable defining block run conditions. Copied from pl_line_data. @@ -95,6 +96,7 @@ typedef struct { 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 + offset_id_t offset_id; int32_t line_number; // Desired line number to report when executing. // void *parameters; // TODO: pointer to extra parameters, for canned cycles and threading? char *message; // Message to be displayed when block is executed. diff --git a/platform.h b/platform.h index 864eccf..19010a3 100644 --- a/platform.h +++ b/platform.h @@ -21,8 +21,28 @@ #pragma once -#if defined(STM32F103xB) || defined(STM32F103xE) || defined(STM32F401xC) || defined(STM32F401xE) || defined(STM32F407xx) || defined(STM32F411xE) || \ - defined(STM32F412Vx) || defined(STM32F446xx) || defined(STM32F756xx) || defined(STM32F765xx) || defined(STM32H743xx) || defined(STM32H723xx) +#if defined(STM32F103xB) || defined(STM32F103xE) +#define STM32_F1_PLATFORM +#endif + +#if defined(STM32F303xC) +#define STM32_F3_PLATFORM +#endif + +#if defined(STM32F401xC) || defined(STM32F401xE) || defined(STM32F407xx) || defined(STM32F411xE) || \ + defined(STM32F412Vx) || defined(STM32F446xx) +#define STM32_F4_PLATFORM +#endif + +#if defined(STM32F756xx) || defined(STM32F765xx) +#define STM32_F7_PLATFORM +#endif + +#if defined(STM32H743xx) || defined(STM32H723xx) +#define STM32_H7_PLATFORM +#endif + +#if defined(STM32_F1_PLATFORM) || defined(STM32_F3_PLATFORM) || defined(STM32_F4_PLATFORM) || defined(STM32_F7_PLATFORM) || defined(STM32_H7_PLATFORM) #define STM32_PLATFORM #endif diff --git a/protocol.c b/protocol.c index 59735a5..95fa75b 100644 --- a/protocol.c +++ b/protocol.c @@ -375,9 +375,13 @@ bool protocol_main_loop (void) bool protocol_buffer_synchronize (void) { bool ok = true; + // If system is queued, ensure cycle resumes if the auto start flag is present. protocol_auto_cycle_start(); + + sys.flags.synchronizing = On; while ((ok = protocol_execute_realtime()) && (plan_get_current_block() || state_get() == STATE_CYCLE)); + sys.flags.synchronizing = Off; return ok; } @@ -939,12 +943,12 @@ ISR_CODE bool ISR_FUNC(protocol_enqueue_realtime_command)(char c) break; case CMD_MPG_MODE_TOGGLE: // Switch off MPG mode - if(hal.stream.type == StreamType_MPG) + if((drop = hal.stream.type == StreamType_MPG)) protocol_enqueue_foreground_task(stream_mpg_set_mode, NULL); break; case CMD_AUTO_REPORTING_TOGGLE: - if(settings.report_interval) + if((drop = settings.report_interval != 0)) sys.flags.auto_reporting = !sys.flags.auto_reporting; break; diff --git a/report.c b/report.c index a6528c2..1162a12 100644 --- a/report.c +++ b/report.c @@ -1171,11 +1171,11 @@ void report_realtime_status (void) uint_fast8_t idx; float wco[N_AXIS]; - if (!settings.status_report.machine_position || report.wco) { - for (idx = 0; idx < N_AXIS; idx++) { + if(!settings.status_report.machine_position || report.wco) { + for(idx = 0; idx < N_AXIS; idx++) { // Apply work coordinate offsets and tool length offset to current position. - wco[idx] = gc_get_offset(idx); - if (!settings.status_report.machine_position) + wco[idx] = gc_get_offset(idx, true); + if(!settings.status_report.machine_position) print_position[idx] -= wco[idx]; } } @@ -1281,13 +1281,13 @@ void report_realtime_status (void) if(settings.status_report.work_coord_offset) { if(wco_counter > 0 && !report.wco) { - if(wco_counter > (REPORT_WCO_REFRESH_IDLE_COUNT - 1) && state_get() == STATE_IDLE) + if(wco_counter > (REPORT_WCO_REFRESH_IDLE_COUNT - 1) && state == STATE_IDLE) wco_counter = REPORT_WCO_REFRESH_IDLE_COUNT - 1; wco_counter--; } else - wco_counter = state_get() & (STATE_HOMING|STATE_CYCLE|STATE_HOLD|STATE_JOG|STATE_SAFETY_DOOR) - ? (REPORT_WCO_REFRESH_BUSY_COUNT - 1) // Reset counter for slow refresh - : (REPORT_WCO_REFRESH_IDLE_COUNT - 1); + wco_counter = state & (STATE_HOMING|STATE_CYCLE|STATE_HOLD|STATE_JOG|STATE_SAFETY_DOOR) + ? (REPORT_WCO_REFRESH_BUSY_COUNT - 1) // Reset counter for slow refresh + : (REPORT_WCO_REFRESH_IDLE_COUNT - 1); } else report.wco = Off; @@ -1298,9 +1298,9 @@ void report_realtime_status (void) else if((report.overrides = !report.wco)) { report.spindle = report.spindle || spindle_0_state.on; report.coolant = 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 - : (REPORT_OVERRIDE_REFRESH_IDLE_COUNT - 1); + override_counter = state & (STATE_HOMING|STATE_CYCLE|STATE_HOLD|STATE_JOG|STATE_SAFETY_DOOR) + ? (REPORT_OVERRIDE_REFRESH_BUSY_COUNT - 1) // Reset counter for slow refresh + : (REPORT_OVERRIDE_REFRESH_IDLE_COUNT - 1); } } else report.overrides = Off; @@ -1308,8 +1308,14 @@ void report_realtime_status (void) if(report.value || gc_state.tool_change) { if(report.wco) { - hal.stream.write_all("|WCO:"); - hal.stream.write_all(get_axis_values(wco)); + // If protocol_buffer_synchronize() is running + // delay outputting WCO until sync is completed + // unless requested from stepper_driver_interrupt_handler. + if(report.force_wco || !sys.flags.synchronizing) { + hal.stream.write_all("|WCO:"); + hal.stream.write_all(get_axis_values(wco)); + } else + wco_counter = 0; } if(report.gwco) { diff --git a/stepper.c b/stepper.c index 5db6b36..c621e25 100644 --- a/stepper.c +++ b/stepper.c @@ -305,6 +305,10 @@ ISR_CODE void ISR_FUNC(stepper_driver_interrupt_handler)(void) if((st.dir_change = st.exec_block == NULL || st.dir_outbits.value != st.exec_segment->exec_block->direction_bits.value)) st.dir_outbits = st.exec_segment->exec_block->direction_bits; + + if(st.exec_block != NULL && st.exec_block->offset_id != st.exec_segment->exec_block->offset_id) + sys.report.wco = sys.report.force_wco = On; // Do not generate grbl.on_rt_reports_added event! + st.exec_block = st.exec_segment->exec_block; st.step_event_count = st.exec_block->step_event_count; st.new_block = true; @@ -704,9 +708,10 @@ void st_prep_buffer (void) st_prep_block->spindle = pl_block->spindle.hal; st_prep_block->output_commands = pl_block->output_commands; st_prep_block->overrides = pl_block->overrides; + st_prep_block->offset_id = pl_block->offset_id; st_prep_block->backlash_motion = pl_block->condition.backlash_motion; st_prep_block->message = pl_block->message; - pl_block->message= NULL; + pl_block->message = NULL; // Initialize segment buffer data for generating the segments. prep.steps_per_mm = st_prep_block->steps_per_mm; @@ -1098,3 +1103,14 @@ float st_get_realtime_rate (void) #endif : 0.0f; } + +offset_id_t st_get_offset_id (void) +{ + plan_block_t *pl_block; + + return st.exec_block + ? st.exec_block->offset_id + : (sys.holding_state == Hold_Complete && (pl_block = plan_get_current_block()) + ? pl_block->offset_id + : -1); +} diff --git a/stepper.h b/stepper.h index 2baaf6d..946524c 100644 --- a/stepper.h +++ b/stepper.h @@ -51,6 +51,7 @@ typedef struct st_block { output_command_t *output_commands; //!< Output commands (linked list) to be performed when block is executed bool backlash_motion; bool dynamic_rpm; //!< Tracks motions that require dynamic RPM adjustment + offset_id_t offset_id; spindle_ptrs_t *spindle; //!< Pointer to current spindle for motions that require dynamic RPM adjustment } st_block_t; @@ -137,4 +138,6 @@ float st_get_realtime_rate (void); void stepper_driver_interrupt_handler (void); +offset_id_t st_get_offset_id (void); + #endif diff --git a/stream.c b/stream.c index 979c10f..c80b814 100644 --- a/stream.c +++ b/stream.c @@ -47,7 +47,7 @@ typedef struct stream_connection { const io_stream_t *stream; stream_is_connected_ptr is_up; stream_connection_flags_t flags; - struct stream_connection *next; + struct stream_connection *next, *prev; } stream_connection_t; static const io_stream_properties_t null_stream = { @@ -232,6 +232,7 @@ static stream_connection_t *add_connection (const io_stream_t *stream) return NULL; } } + connection->prev = last; last->next = connection; } @@ -246,42 +247,42 @@ static bool stream_select (const io_stream_t *stream, bool add) { static const io_stream_t *active_stream = NULL; - bool send_init_message = false; + bool send_init_message = false, mpg_enable = false; if(stream == base.stream) { base.is_up = add ? (stream->is_connected ? stream->is_connected : stream_connected) : is_not_connected; return true; } - if(add) { + if(!add) { // disconnect - if(add_connection(stream) == NULL) - return false; + if(stream == base.stream || stream == mpg.stream) + return false; - } else { // disconnect + bool disconnected = false; + stream_connection_t *connection = connections->next; - const io_stream_t *org_stream; - stream_connection_t *prev, *last = connections; - - while(last->next) { - prev = last; - last = last->next; - if(prev->stream != mpg.stream) - org_stream = prev->stream; - if(last->stream == stream) { - prev->next = last->next; - free(last); - if(prev->next) - return false; - else { - if(mpg.flags.mpg_control || stream->type == StreamType_MPG) - protocol_enqueue_foreground_task(stream_mpg_set_mode, (void *)1); - stream = org_stream; - break; + while(connection) { + if(stream == connection->stream) { + if((connection->prev->next = connection->next)) + connection->next->prev = connection->prev; + if((stream = connection->prev->stream) == mpg.stream) { + mpg_enable = mpg.flags.mpg_control; + if((stream = connection->prev->prev->stream) == NULL) + stream = base.stream; } - } + free(connection); + connection = NULL; + disconnected = true; + } else + connection = connection->next; } - } + + if(!disconnected) + return false; + + } else if(add_connection(stream) == NULL) + return false; bool webui_connected = hal.stream.state.webui_connected; @@ -323,7 +324,8 @@ static bool stream_select (const io_stream_t *stream, bool add) if(hal.stream.type == StreamType_MPG) { stream_mpg_enable(false); mpg.flags.mpg_control = On; - } + } else if(mpg_enable) + protocol_enqueue_foreground_task(stream_mpg_set_mode, (void *)1); memcpy(&hal.stream, stream, sizeof(io_stream_t)); @@ -455,7 +457,7 @@ void stream_mpg_set_mode (void *data) ISR_CODE bool ISR_FUNC(stream_mpg_check_enable)(char c) { if(c == CMD_MPG_MODE_TOGGLE) - protocol_enqueue_foreground_task(stream_mpg_set_mode, (void *)1); + task_add_immediate(stream_mpg_set_mode, (void *)1); else { protocol_enqueue_realtime_command(c); if((c == CMD_CYCLE_START || c == CMD_CYCLE_START_LEGACY) && settings.status_report.pin_state) @@ -492,6 +494,7 @@ bool stream_mpg_register (const io_stream_t *stream, bool rx_only, stream_write_ memcpy(&mpg, connection, sizeof(stream_connection_t)); mpg.flags.is_mpg_tx = On; + mpg.flags.mpg_control = Off; if(mpg_write_char) mpg.stream->set_enqueue_rt_handler(mpg_write_char); diff --git a/system.c b/system.c index ff2db49..b45234e 100644 --- a/system.c +++ b/system.c @@ -1143,7 +1143,7 @@ the WCO report element to the next status report. */ void system_flag_wco_change (void) { - if(!settings.status_report.sync_on_wco_change) + if(settings.status_report.sync_on_wco_change) protocol_buffer_synchronize(); if(grbl.on_wco_changed) diff --git a/system.h b/system.h index dfcbcf5..fa9d867 100644 --- a/system.h +++ b/system.h @@ -187,6 +187,7 @@ typedef enum { Report_TLOReference = (1 << 15), Report_Fan = (1 << 16), Report_SpindleId = (1 << 17), + Report_ForceWCO = (1 << 29), Report_CycleStart = (1 << 30), Report_All = 0x8003FFFF } report_tracking_t; @@ -212,7 +213,8 @@ typedef union { tlo_reference :1, //!< Tool length offset reference changed. fan :1, //!< Fan on/off changed. spindle_id :1, //!< Spindle changed - unassigned :12, // + unassigned :11, // + force_wco :1, //!< Add work coordinates (due to WCO changed during motion). cycle_start :1, //!< Cycle start signal triggered. __NOTE:__ do __NOT__ add to Report_All enum above! all :1; //!< Set when CMD_STATUS_REPORT_ALL is requested, may be used by user code. }; @@ -249,7 +251,8 @@ typedef union { single_block :1, //!< Set to true to disable M1 (optional stop), via realtime command. keep_input :1, //!< Set to true to not flush stream input buffer on executing STOP. auto_reporting :1, //!< Set to true when auto real time reporting is enabled. - unused :6; + synchronizing :1, //!< Set to true when protocol_buffer_synchronize() is running. + unused :5; }; } system_flags_t; diff --git a/tool_change.c b/tool_change.c index 69b2e02..ad01e13 100644 --- a/tool_change.c +++ b/tool_change.c @@ -143,7 +143,7 @@ static bool restore (void) spindle_restore(plan_data.spindle.hal, 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); + previous.values[plane.axis_linear] += gc_get_offset(plane.axis_linear, false); mc_line(previous.values, &plan_data); } } @@ -360,7 +360,7 @@ static status_code_t tool_change (parser_state_t *parser_state) // Establish axis assignments. - previous.values[plane.axis_linear] -= gc_get_offset(plane.axis_linear); + previous.values[plane.axis_linear] -= gc_get_offset(plane.axis_linear, false); plan_line_data_t plan_data; From 21329cd03fccef58d1c14a23e7587877fc973e63 Mon Sep 17 00:00:00 2001 From: Terje Io Date: Mon, 27 May 2024 13:39:30 +0700 Subject: [PATCH 02/23] "Hardened" NGC parameter name case swapping. Changed to use float precision according to metric/inches setting for parameter reporting. --- README.md | 2 +- changelog.md | 10 +++++++++- gcode.c | 4 ++-- grbl.h | 2 +- ngc_params.c | 32 ++++++++++++++++++-------------- ngc_params.h | 1 + report.c | 4 ++-- 7 files changed, 34 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index dfd0f87..79256cd 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ It has been written to complement grblHAL and has features such as proper keyboa --- -Latest build date is 20240526, see the [changelog](changelog.md) for details. +Latest build date is 20240527, see the [changelog](changelog.md) for details. __NOTE:__ Build 20240222 has moved the probe input to the ioPorts pool of inputs and will be allocated from it when configured. The change is major and _potentially dangerous_, it may damage your probe, so please _verify correct operation_ after installing this, or later, builds. diff --git a/changelog.md b/changelog.md index 42d416a..797f502 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,13 @@ ## grblHAL changelog +Build 20240527 + +Core: + +* "Hardened" NGC parameter name case swapping, changed to use float precision according to metric/inches setting for parameter reporting. + +--- + Build 20240526 Core: @@ -11,7 +19,7 @@ Available for gcode run from local filesystem such as on a SD card or in littlef * Improved handling of G92 when G92 offset is changed while motion is ongoing. Position and WCO offset in the realtime report will now be the actual realtime values and not -the values based on the parser state which may be quite a bit ahead of the machine. Ref. [issue #241](https://github.com/grblHAL/core/discussions/241#discussioncomment-9463390). +the values based on the parser state which may be quite a bit ahead of the machine. Ref. [discussion #241](https://github.com/grblHAL/core/discussions/241#discussioncomment-9463390). * Fix for [issue #521](https://github.com/grblHAL/core/issues/521), crash when running G65 macro on ESP32. diff --git a/gcode.c b/gcode.c index e3cc3b2..96c6b7f 100644 --- a/gcode.c +++ b/gcode.c @@ -620,7 +620,7 @@ char *gc_normalize_block (char *block, char **message) if(c == '#') { char_counter--; if(read_parameter(comment, &char_counter, &value) == Status_OK) - len += strlen(trim_float(ftoa(value, 6))); + len += strlen(trim_float(ftoa(value, ngc_float_decimals()))); else len += 3; // "N/A" } else @@ -637,7 +637,7 @@ char *gc_normalize_block (char *block, char **message) if(c == '#') { char_counter--; if(read_parameter(comment, &char_counter, &value) == Status_OK) - strcat(s3, trim_float(ftoa(value, 6))); + strcat(s3, trim_float(ftoa(value, ngc_float_decimals()))); else strcat(s3, "N/A"); s3 = strchr(s3, '\0'); diff --git a/grbl.h b/grbl.h index 972e12f..b75fbb0 100644 --- a/grbl.h +++ b/grbl.h @@ -42,7 +42,7 @@ #else #define GRBL_VERSION "1.1f" #endif -#define GRBL_BUILD 20240526 +#define GRBL_BUILD 20240527 #define GRBL_URL "https://github.com/grblHAL" diff --git a/ngc_params.c b/ngc_params.c index 8364ab7..5763db8 100644 --- a/ngc_params.c +++ b/ngc_params.c @@ -572,21 +572,20 @@ float ngc_named_param_get_by_id (ncg_name_param_id_t id) } // Lowercase name, remove control characters and spaces -// Assumes names stored in flash are lowercase... -static char *ngc_name_tolower (char *name) +static char *ngc_name_tolower (char *s) { - char c, *s1 = name, *s2 = name; - bool convert = false; + static char name[NGC_MAX_PARAM_LENGTH + 1]; - while((c = *s1++) && c > ' ') - convert = (c & 0x20) == 0 || c <= ' '; + uint_fast8_t len = 0; + char c, *s1 = s, *s2 = name; - if(convert) { - s1 = name; - while((c = *s1++) && c > ' ') - *s2++ = LCAPS(c); - *s2 = '\0'; + while((c = *s1++) && len < NGC_MAX_PARAM_LENGTH) { + if(c > ' ') { + *s2++ = LCAPS(c); + len++; + } } + *s2 = '\0'; return name; } @@ -596,7 +595,7 @@ bool ngc_named_param_get (char *name, float *value) bool found = false; uint_fast8_t idx = sizeof(ngc_named_ro_param) / sizeof(ngc_named_ro_param_t); - ngc_name_tolower(name); + name = ngc_name_tolower(name); *value = 0.0f; @@ -625,7 +624,7 @@ bool ngc_named_param_exists (char *name) bool ok = false; uint_fast8_t idx = sizeof(ngc_named_ro_param) / sizeof(ngc_named_ro_param_t); - ngc_name_tolower(name); + name = ngc_name_tolower(name); // Check if name is supplied, return false if not. if((*name == '_' ? *(name + 1) : *name) == '\0') @@ -657,7 +656,7 @@ bool ngc_named_param_set (char *name, float value) bool ok = false; uint_fast8_t idx = sizeof(ngc_named_ro_param) / sizeof(ngc_named_ro_param_t); - ngc_name_tolower(name); + name = ngc_name_tolower(name); // Check if name is supplied, return false if not. if((*name == '_' ? *(name + 1) : *name) == '\0') @@ -798,4 +797,9 @@ uint_fast8_t ngc_call_level (void) return (uint_fast8_t)(call_level + 1); } +uint8_t ngc_float_decimals (void) +{ + return settings.flags.report_inches ? N_DECIMAL_COORDVALUE_INCH : N_DECIMAL_COORDVALUE_MM; +} + #endif // NGC_PARAMETERS_ENABLE diff --git a/ngc_params.h b/ngc_params.h index 198695b..2af01d7 100644 --- a/ngc_params.h +++ b/ngc_params.h @@ -87,6 +87,7 @@ typedef enum { NGCParam_Last } ncg_name_param_id_t; +uint8_t ngc_float_decimals (void); bool ngc_param_get (ngc_param_id_t id, float *value); bool ngc_param_set (ngc_param_id_t id, float value); bool ngc_param_is_rw (ngc_param_id_t id); diff --git a/report.c b/report.c index 1162a12..aafa32c 100644 --- a/report.c +++ b/report.c @@ -553,7 +553,7 @@ status_code_t report_ngc_parameter (ngc_param_id_t id) hal.stream.write(uitoa(id)); if(ngc_param_get(id, &value)) { hal.stream.write("="); - hal.stream.write(ftoa(value, 3)); + hal.stream.write(trim_float(ftoa(value, ngc_float_decimals()))); } else hal.stream.write("=N/A"); hal.stream.write("]" ASCII_EOL); @@ -570,7 +570,7 @@ status_code_t report_named_ngc_parameter (char *arg) hal.stream.write(arg); if(ngc_named_param_get(arg, &value)) { hal.stream.write("="); - hal.stream.write(ftoa(value, 3)); + hal.stream.write(trim_float(ftoa(value, ngc_float_decimals()))); } else hal.stream.write("=N/A"); hal.stream.write("]" ASCII_EOL); From f8e0150c77c6f7b1f9837aaf8f256cb897b59c98 Mon Sep 17 00:00:00 2001 From: Terje Io Date: Sun, 2 Jun 2024 08:09:46 +0700 Subject: [PATCH 03/23] Fixed typo/bug in expression precedence handling. Ref. issue #527. --- README.md | 2 +- changelog.md | 14 ++++++++++++++ grbl.h | 2 +- ngc_expr.c | 2 +- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 79256cd..d647a90 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ It has been written to complement grblHAL and has features such as proper keyboa --- -Latest build date is 20240527, see the [changelog](changelog.md) for details. +Latest build date is 20240602, see the [changelog](changelog.md) for details. __NOTE:__ Build 20240222 has moved the probe input to the ioPorts pool of inputs and will be allocated from it when configured. The change is major and _potentially dangerous_, it may damage your probe, so please _verify correct operation_ after installing this, or later, builds. diff --git a/changelog.md b/changelog.md index 797f502..9d68bae 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,19 @@ ## grblHAL changelog +Build 20240602 + +Core: + +* Fixed typo/bug in expression precedence handling. Ref. [issue #527](https://github.com/grblHAL/core/issues/527). + +Drivers: + +* STM32F4xx, STM32F7xx: added cast to suppress compiler warning. + +* STM32F7xx: added DMA support for SPI4, fix for SPI SCK pin reporting. WizNet code still not working. + +--- + Build 20240527 Core: diff --git a/grbl.h b/grbl.h index b75fbb0..d448461 100644 --- a/grbl.h +++ b/grbl.h @@ -42,7 +42,7 @@ #else #define GRBL_VERSION "1.1f" #endif -#define GRBL_BUILD 20240527 +#define GRBL_BUILD 20240602 #define GRBL_URL "https://github.com/grblHAL" diff --git a/ngc_expr.c b/ngc_expr.c index aa2879f..3f0a991 100644 --- a/ngc_expr.c +++ b/ngc_expr.c @@ -791,7 +791,7 @@ status_code_t ngc_eval_expression (char *line, uint_fast8_t *pos, float *value) return status; operators[stack_index - 1] = operators[stack_index]; - if((stack_index > 1) && precedence(operators[stack_index - 1] <= precedence(operators[stack_index - 2]))) + if(stack_index > 1 && precedence(operators[stack_index - 1]) <= precedence(operators[stack_index - 2])) stack_index--; else break; From 0a86e57ddc622c758a2c490f4100af948beebee2 Mon Sep 17 00:00:00 2001 From: Terje Io Date: Tue, 4 Jun 2024 12:57:17 +0700 Subject: [PATCH 04/23] Fixed incorrect implementation of EXISTS function. Ref. issue #527. Added missing clear of parser tool change state when cycle start signal is asserted. Affects tool change mode 'Normal' ($341=0). --- README.md | 2 +- changelog.md | 10 ++++++++++ grbl.h | 2 +- ngc_expr.c | 25 ++++++++++++++----------- settings.h | 11 +++++++++++ system.c | 14 +++++++------- 6 files changed, 44 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index d647a90..74914e1 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ It has been written to complement grblHAL and has features such as proper keyboa --- -Latest build date is 20240602, see the [changelog](changelog.md) for details. +Latest build date is 20240604, see the [changelog](changelog.md) for details. __NOTE:__ Build 20240222 has moved the probe input to the ioPorts pool of inputs and will be allocated from it when configured. The change is major and _potentially dangerous_, it may damage your probe, so please _verify correct operation_ after installing this, or later, builds. diff --git a/changelog.md b/changelog.md index 9d68bae..bd725e8 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,15 @@ ## grblHAL changelog +Build 20240604 + +Core: + +* Fixed incorrect implementation of `EXISTS` function. Ref. [issue #527](https://github.com/grblHAL/core/issues/527). + +* Added missing clear of parser tool change state when cycle start signal is asserted. Affects tool change mode 'Normal' ($341=0). + +--- + Build 20240602 Core: diff --git a/grbl.h b/grbl.h index d448461..bebbc06 100644 --- a/grbl.h +++ b/grbl.h @@ -42,7 +42,7 @@ #else #define GRBL_VERSION "1.1f" #endif -#define GRBL_BUILD 20240602 +#define GRBL_BUILD 20240604 #define GRBL_URL "https://github.com/grblHAL" diff --git a/ngc_expr.c b/ngc_expr.c index 3f0a991..91f336d 100644 --- a/ngc_expr.c +++ b/ngc_expr.c @@ -53,7 +53,7 @@ typedef enum { NGCBinaryOp_LE, NGCBinaryOp_GE, NGCBinaryOp_GT, - NGCBinaryOp_RelationalLast = NGCBinaryOp_GT, + NGCBinaryOp_RelationalLast = NGCBinaryOp_GT } ngc_binary_op_t; typedef enum { @@ -70,7 +70,7 @@ typedef enum { NGCUnaryOp_SIN, NGCUnaryOp_SQRT, NGCUnaryOp_TAN, - NGCUnaryOp_Exists, // Not implemented + NGCUnaryOp_Exists } ngc_unary_op_t; /*! \brief Executes the operations: /, MOD, ** (POW), *. @@ -675,19 +675,22 @@ static status_code_t read_unary (char *line, uint_fast8_t *pos, float *value) else { - if (operation == NGCUnaryOp_Exists) { + if(operation == NGCUnaryOp_Exists) { - char *arg = &line[++(*pos)], *s; + char *arg = &line[++(*pos)], *s = NULL; - s = arg; - while(*s && *s != ']') - s++; + if(*arg == '#' && *(arg + 1) == '<') { + arg += 2; + s = arg; + while(*s && *s != ']') + s++; + } - if(*s == ']') { - *s = '\0'; + if(s && *s == ']' && *(s - 1) == '>') { + *(s - 1) = '\0'; *value = ngc_named_param_exists(arg) ? 1.0f : 0.0f; - *s = ']'; - *pos = *pos + s - arg + 1; + *(s - 1) = '>'; + *pos = *pos + s - arg + 3; } else status = Status_ExpressionSyntaxError; diff --git a/settings.h b/settings.h index 4094371..bb1277b 100644 --- a/settings.h +++ b/settings.h @@ -391,6 +391,17 @@ typedef enum { Setting_Panel_Encoder3_Cpd = 559, Setting_Panel_SettingsMax = 579, + Setting_ButtonAction0 = 590, + Setting_ButtonAction1 = 591, + Setting_ButtonAction2 = 592, + Setting_ButtonAction3 = 593, + Setting_ButtonAction4 = 594, + Setting_ButtonAction5 = 595, + Setting_ButtonAction6 = 596, + Setting_ButtonAction7 = 597, + Setting_ButtonAction8 = 598, + Setting_ButtonAction9 = 599, + Setting_ModbusTCPBase = 600, // Reserving settings values 600 to 639 for ModBus TCP (8 sets) Setting_ModbusIpAddressBase = Setting_ModbusTCPBase + Setting_ModbusIpAddress, Setting_ModbusPortBase = Setting_ModbusTCPBase + Setting_ModbusPort, diff --git a/system.c b/system.c index b45234e..06a8ea7 100644 --- a/system.c +++ b/system.c @@ -74,11 +74,11 @@ ISR_CODE void ISR_FUNC(control_interrupt_handler)(control_signals_t signals) sys.last_event.control.value = signals.value; - if ((signals.reset || signals.e_stop || signals.motor_fault) && state_get() != STATE_ESTOP) + if((signals.reset || signals.e_stop || signals.motor_fault) && state_get() != STATE_ESTOP) mc_reset(); else { #ifndef NO_SAFETY_DOOR_SUPPORT - if (signals.safety_door_ajar && hal.signals_cap.safety_door_ajar) { + if(signals.safety_door_ajar && hal.signals_cap.safety_door_ajar) { if(settings.safety_door.flags.ignore_when_idle) { // Only stop the spindle (laser off) when idle or jogging, // this to allow positioning the controlled point (spindle) when door is open. @@ -91,27 +91,27 @@ ISR_CODE void ISR_FUNC(control_interrupt_handler)(control_signals_t signals) system_set_exec_state_flag(EXEC_SAFETY_DOOR); } #endif - if(signals.probe_overtravel) { limit_signals_t overtravel = { .min.z = On}; hal.limits.interrupt_callback(overtravel); // TODO: add message? - } else if (signals.probe_triggered) { + } else if(signals.probe_triggered) { if(sys.probing_state == Probing_Off && (state_get() & (STATE_CYCLE|STATE_JOG))) { system_set_exec_state_flag(EXEC_STOP); sys.alarm_pending = Alarm_ProbeProtect; } else hal.probe.configure(false, false); - } else if (signals.probe_disconnected) { + } else if(signals.probe_disconnected) { if(sys.probing_state == Probing_Active && state_get() == STATE_CYCLE) { system_set_exec_state_flag(EXEC_FEED_HOLD); sys.alarm_pending = Alarm_ProbeProtect; } - } else if (signals.feed_hold) + } else if(signals.feed_hold) system_set_exec_state_flag(EXEC_FEED_HOLD); - else if (signals.cycle_start) { + else if(signals.cycle_start) { system_set_exec_state_flag(EXEC_CYCLE_START); sys.report.cycle_start = settings.status_report.pin_state; + gc_state.tool_change = false; } if(signals.block_delete) From 9a060d7ea0f01cab7444fee447741b010cb4cb3a Mon Sep 17 00:00:00 2001 From: Terje Io Date: Wed, 19 Jun 2024 20:37:30 +0200 Subject: [PATCH 05/23] Renamed grbl.on_probe_fixture event to grbl.on_probe_toolsetter and added pointer to toolsetter coordinates as an additional parameter. Increased backlash parameters precision to 5 decimals. Ref issue #452. Some bug fixes in NGC parameters and flow control handling. --- README.md | 2 +- changelog.md | 24 ++++++++++++++++++++++++ config.h | 4 ++-- core_handlers.h | 4 ++-- grbl.h | 2 +- motion_control.c | 10 +++++----- ngc_flowctrl.c | 6 +++--- settings.c | 2 +- tool_change.c | 36 +++++++++++++++++++++++------------- 9 files changed, 62 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 74914e1..b8b0ed2 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ It has been written to complement grblHAL and has features such as proper keyboa --- -Latest build date is 20240604, see the [changelog](changelog.md) for details. +Latest build date is 20240619, see the [changelog](changelog.md) for details. __NOTE:__ Build 20240222 has moved the probe input to the ioPorts pool of inputs and will be allocated from it when configured. The change is major and _potentially dangerous_, it may damage your probe, so please _verify correct operation_ after installing this, or later, builds. diff --git a/changelog.md b/changelog.md index bd725e8..cf1ca85 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,29 @@ ## grblHAL changelog +Build 20240619 + +Core: + +* Renamed `grbl.on_probe_fixture` event to `grbl.on_probe_toolsetter` and added pointer to toolsetter coordinates as an additional parameter. +This will allow plugin code to modify the coordinates before moving to the toolsetter so that tools with off center cutting surfaces can be properly measured. +Ref. [ioSender issue #386](https://github.com/terjeio/ioSender/issues/386). + +* Increased backlash parameters precision to 5 decimals. Ref [issue #452](https://github.com/grblHAL/core/issues/452#issuecomment-2159050856). + +* Some bug fixes in NGC parameters and flow control handling. + +Drivers: + +* ESP32: improved SPI code. + +* SAM3X8E: added support for native and MCP3221 I2C ADCs. Ref [issue #24](https://github.com/grblHAL/SAM3X8E/issues/24). + +Plugins: + +* Templates: Updated some for core event rename and signature change. + +--- + Build 20240604 Core: diff --git a/config.h b/config.h index f645645..e86eae4 100644 --- a/config.h +++ b/config.h @@ -486,11 +486,11 @@ non-volatile storage until the controller is in IDLE state. /*! \def TOOLSETTER_RADIUS \brief -The grbl.on_probe_fixture event handler is called by the default tool change algorithm when probing at G59.3. +The grbl.on_probe_toolsetter event handler is called by the default tool change algorithm when probing at G59.3. In addition it will be called on a "normal" probe sequence if the XY position is within the radius of the G59.3 position defined below. Change if the default value of 5mm is not suitable or set it to 0.0f to disable. -
__NOTE:__ A grbl.on_probe_fixture event handler is not installed by the core, it has to be provided +
__NOTE:__ A grbl.on_probe_toolsetter event handler is not installed by the core, it has to be provided by a driver or a plugin. */ #if !defined TOOLSETTER_RADIUS || defined __DOXYGEN__ diff --git a/core_handlers.h b/core_handlers.h index 2a9e956..e099d2e 100644 --- a/core_handlers.h +++ b/core_handlers.h @@ -107,7 +107,7 @@ typedef void (*on_homing_rate_set_ptr)(axes_signals_t axes, float rate, homing_m // NOTE: cycle contains the axis flags of the executed homing cycle, success will be true when all the configured cycles are completed. typedef void (*on_homing_completed_ptr)(axes_signals_t cycle, bool success); -typedef bool (*on_probe_fixture_ptr)(tool_data_t *tool, bool at_g59_3, bool on); +typedef bool (*on_probe_toolsetter_ptr)(tool_data_t *tool, coord_data_t *position, 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); @@ -172,7 +172,7 @@ typedef struct { on_stream_changed_ptr on_stream_changed; on_homing_rate_set_ptr on_homing_rate_set; on_homing_completed_ptr on_homing_completed; - on_probe_fixture_ptr on_probe_fixture; + on_probe_toolsetter_ptr on_probe_toolsetter; 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; diff --git a/grbl.h b/grbl.h index bebbc06..b85454a 100644 --- a/grbl.h +++ b/grbl.h @@ -42,7 +42,7 @@ #else #define GRBL_VERSION "1.1f" #endif -#define GRBL_BUILD 20240604 +#define GRBL_BUILD 20240619 #define GRBL_URL "https://github.com/grblHAL" diff --git a/motion_control.c b/motion_control.c index 30ad89b..fdd4e0d 100644 --- a/motion_control.c +++ b/motion_control.c @@ -992,10 +992,10 @@ gc_probe_t mc_probe_cycle (float *target, plan_line_data_t *pl_data, gc_parser_f hal.probe.configure(parser_flags.probe_is_away, true); #if COMPATIBILITY_LEVEL <= 1 - bool at_g59_3 = false, probe_fixture = grbl.on_probe_fixture != NULL && state_get() != STATE_TOOL_CHANGE && (sys.homed.mask & (X_AXIS_BIT|Y_AXIS_BIT)); + bool at_g59_3 = false, probe_toolsetter = grbl.on_probe_toolsetter != NULL && state_get() != STATE_TOOL_CHANGE && (sys.homed.mask & (X_AXIS_BIT|Y_AXIS_BIT)); - if(probe_fixture) - grbl.on_probe_fixture(NULL, at_g59_3 = system_xy_at_fixture(CoordinateSystem_G59_3, TOOLSETTER_RADIUS), true); + if(probe_toolsetter) + grbl.on_probe_toolsetter(NULL, NULL, at_g59_3 = system_xy_at_fixture(CoordinateSystem_G59_3, TOOLSETTER_RADIUS), true); #endif // After syncing, check if probe is already triggered or not connected. If so, halt and issue alarm. @@ -1054,8 +1054,8 @@ gc_probe_t mc_probe_cycle (float *target, plan_line_data_t *pl_data, gc_parser_f protocol_execute_realtime(); // Check and execute run-time commands #if COMPATIBILITY_LEVEL <= 1 - if(probe_fixture) - grbl.on_probe_fixture(NULL, at_g59_3, false); + if(probe_toolsetter) + grbl.on_probe_toolsetter(NULL, NULL, at_g59_3, false); #endif // Reset the stepper and planner buffers to remove the remainder of the probe motion. diff --git a/ngc_flowctrl.c b/ngc_flowctrl.c index 3b6568a..ea18a3e 100644 --- a/ngc_flowctrl.c +++ b/ngc_flowctrl.c @@ -156,7 +156,7 @@ static status_code_t read_command (char *line, uint_fast8_t *pos, ngc_cmd_t *ope *operation = NGCFlowCtrl_If; (*pos)++; } else - *operation = Status_FlowControlSyntaxError; // Unknown statement name starting with F + status = Status_FlowControlSyntaxError; // Unknown statement name starting with F break; case 'R': @@ -167,7 +167,7 @@ static status_code_t read_command (char *line, uint_fast8_t *pos, ngc_cmd_t *ope *operation = NGCFlowCtrl_Return; *pos += 5; } else - *operation = Status_FlowControlSyntaxError; // Unknown statement name starting with R + status = Status_FlowControlSyntaxError; // Unknown statement name starting with R break; case 'S': @@ -531,7 +531,7 @@ status_code_t ngc_flowctrl (uint32_t o_label, char *line, uint_fast8_t *pos, boo status = Status_FlowControlSyntaxError; else { - float params[29]; + float params[30]; ngc_param_id_t param_id = 1; while(line[*pos] && status == Status_OK && param_id <= 30) { diff --git a/settings.c b/settings.c index 0960ca2..fea3375 100644 --- a/settings.c +++ b/settings.c @@ -569,7 +569,7 @@ PROGMEM static const setting_detail_t setting_detail[] = { { Setting_AxisAcceleration, Group_Axis0, "-axis acceleration", axis_accel, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, { Setting_AxisMaxTravel, Group_Axis0, "-axis maximum travel", axis_dist, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, #if ENABLE_BACKLASH_COMPENSATION - { Setting_AxisBacklash, Group_Axis0, "-axis backlash compensation", axis_dist, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsExtendedFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, + { Setting_AxisBacklash, Group_Axis0, "-axis backlash compensation", axis_dist, Format_Decimal, "#####0.000##", NULL, NULL, Setting_IsExtendedFn, set_axis_setting, get_float, NULL, AXIS_OPTS }, #endif { Setting_AxisAutoSquareOffset, Group_Axis0, "-axis dual axis offset", "mm", Format_Decimal, "-0.000", "-10", "10", Setting_IsExtendedFn, set_axis_setting, get_float, is_setting_available, AXIS_OPTS }, { Setting_SpindleAtSpeedTolerance, Group_Spindle, "Spindle at speed tolerance", "percent", Format_Decimal, "##0.0", NULL, NULL, Setting_IsExtended, &settings.spindle.at_speed_tolerance, NULL, is_setting_available }, diff --git a/tool_change.c b/tool_change.c index ad01e13..80cb1ae 100644 --- a/tool_change.c +++ b/tool_change.c @@ -37,7 +37,7 @@ #define TOOL_CHANGE_PROBE_RETRACT_DISTANCE 2.0f #endif -static bool block_cycle_start, probe_fixture; +static bool block_cycle_start, probe_toolsetter; static volatile bool execute_posted = false; static volatile uint32_t spin_lock = 0; static float tool_change_position; @@ -89,11 +89,11 @@ static void change_completed (void) hal.irq_enable(); } - if(probe_fixture) - grbl.on_probe_fixture(¤t_tool, true, false); + if(probe_toolsetter) + grbl.on_probe_toolsetter(¤t_tool, NULL, true, false); grbl.on_probe_completed = NULL; - gc_state.tool_change = probe_fixture = false; + gc_state.tool_change = probe_toolsetter = false; } @@ -190,9 +190,6 @@ static void execute_probe (void *data) plan_line_data_t plan_data; gc_parser_flags_t flags = {0}; - if(probe_fixture) - grbl.on_probe_fixture(next_tool, true, true); - // G59.3 contains offsets to position of TLS. settings_read_coord_data(CoordinateSystem_G59_3, &offset.values); @@ -202,11 +199,17 @@ static void execute_probe (void *data) target.values[plane.axis_0] = offset.values[plane.axis_0]; target.values[plane.axis_1] = offset.values[plane.axis_1]; + if(probe_toolsetter) + grbl.on_probe_toolsetter(next_tool, &target, false, true); + if((ok = mc_line(target.values, &plan_data))) { target.values[plane.axis_linear] = offset.values[plane.axis_linear]; ok = mc_line(target.values, &plan_data); + if(ok && probe_toolsetter) + grbl.on_probe_toolsetter(next_tool, NULL, true, true); + plan_data.feed_rate = settings.tool_change.seek_rate; plan_data.condition.value = 0; plan_data.spindle.state.value = 0; @@ -350,10 +353,10 @@ static status_code_t tool_change (parser_state_t *parser_state) hal.coolant.set_state((coolant_state_t){0}); execute_posted = false; - probe_fixture = grbl.on_probe_fixture != NULL && - (settings.tool_change.mode == ToolChange_Manual || - settings.tool_change.mode == ToolChange_Manual_G59_3 || - settings.tool_change.mode == ToolChange_SemiAutomatic); + probe_toolsetter = grbl.on_probe_toolsetter != NULL && + (settings.tool_change.mode == ToolChange_Manual || + settings.tool_change.mode == ToolChange_Manual_G59_3 || + settings.tool_change.mode == ToolChange_SemiAutomatic); // Save current position. system_convert_array_steps_to_mpos(previous.values, sys.position); @@ -389,12 +392,19 @@ static status_code_t tool_change (parser_state_t *parser_state) float tmp_pos = target.values[plane.axis_linear]; target.values[plane.axis_linear] = tool_change_position; + + if(probe_toolsetter) + grbl.on_probe_toolsetter(next_tool, &target, false, true); + if(!mc_line(target.values, &plan_data)) return Status_Reset; target.values[plane.axis_linear] = tmp_pos; if(!mc_line(target.values, &plan_data)) return Status_Reset; + + if(probe_toolsetter) + grbl.on_probe_toolsetter(next_tool, NULL, true, true); } #endif @@ -463,8 +473,8 @@ status_code_t tc_probe_workpiece (void) plan_line_data_t plan_data; #if COMPATIBILITY_LEVEL <= 1 - if(probe_fixture) - grbl.on_probe_fixture(next_tool, system_xy_at_fixture(CoordinateSystem_G59_3, TOOLSETTER_RADIUS), true); + if(probe_toolsetter) + grbl.on_probe_toolsetter(next_tool, NULL, system_xy_at_fixture(CoordinateSystem_G59_3, TOOLSETTER_RADIUS), true); #endif // Get current position. From d4c9d21ab2fe056bfaecef9471d77cb23a319590 Mon Sep 17 00:00:00 2001 From: Terje Io Date: Mon, 24 Jun 2024 14:29:29 +0200 Subject: [PATCH 06/23] Some minor changes to better support keypad macro and networking plugins. --- README.md | 2 +- changelog.md | 27 ++++++++++++++++++++-- grbl.h | 2 +- plugins.h | 12 +++++----- settings.c | 2 ++ settings.h | 63 +++++++++++++++++++++++++++------------------------- 6 files changed, 68 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index b8b0ed2..ee5fadf 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ It has been written to complement grblHAL and has features such as proper keyboa --- -Latest build date is 20240619, see the [changelog](changelog.md) for details. +Latest build date is 20240624, see the [changelog](changelog.md) for details. __NOTE:__ Build 20240222 has moved the probe input to the ioPorts pool of inputs and will be allocated from it when configured. The change is major and _potentially dangerous_, it may damage your probe, so please _verify correct operation_ after installing this, or later, builds. diff --git a/changelog.md b/changelog.md index cf1ca85..271bf13 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,28 @@ ## grblHAL changelog +
Build 20240624 + +Core: + +* Some minor changes to better support keypad macro and networking plugins. + +Drivers: + +* ESP32: disabled cycle start input for MKS DLC32 board due to incompatible use. Ref. [issue #111](https://github.com/grblHAL/ESP32/issues/111). + +* RP2040: fixed incorrect handling of WiFi BSSID. + +* STM32F7xx: completed support for WizNet ethernet modules \(W5100S & W5500\). Added code by @dresco for getting unique MAC address, Ref. [discussion #17](https://github.com/grblHAL/STM32F7xx/discussions/17). + +Plugins: + +* Networking \(WizNet\): fixed incorrect MAC address handling, added weak functions for getting default MAC addresses ++. Ref. [discussion #17](https://github.com/grblHAL/STM32F7xx/discussions/17). + +* Keypad macros: added settings for binding single character realtime commands to macro pin event. +__NOTE:__ this change will reset _all_ plugin settings to default, backup/restore if this plugin is in use. + +--- + Build 20240619 Core: @@ -8,7 +31,7 @@ Core: This will allow plugin code to modify the coordinates before moving to the toolsetter so that tools with off center cutting surfaces can be properly measured. Ref. [ioSender issue #386](https://github.com/terjeio/ioSender/issues/386). -* Increased backlash parameters precision to 5 decimals. Ref [issue #452](https://github.com/grblHAL/core/issues/452#issuecomment-2159050856). +* Increased backlash parameters precision to 5 decimals. Ref. [issue #452](https://github.com/grblHAL/core/issues/452#issuecomment-2159050856). * Some bug fixes in NGC parameters and flow control handling. @@ -16,7 +39,7 @@ Drivers: * ESP32: improved SPI code. -* SAM3X8E: added support for native and MCP3221 I2C ADCs. Ref [issue #24](https://github.com/grblHAL/SAM3X8E/issues/24). +* SAM3X8E: added support for native and MCP3221 I2C ADCs. Ref. [issue #24](https://github.com/grblHAL/SAM3X8E/issues/24). Plugins: diff --git a/grbl.h b/grbl.h index b85454a..88e7d18 100644 --- a/grbl.h +++ b/grbl.h @@ -42,7 +42,7 @@ #else #define GRBL_VERSION "1.1f" #endif -#define GRBL_BUILD 20240619 +#define GRBL_BUILD 20240624 #define GRBL_URL "https://github.com/grblHAL" diff --git a/plugins.h b/plugins.h index d7c17c0..a3f870f 100644 --- a/plugins.h +++ b/plugins.h @@ -7,20 +7,20 @@ Part of grblHAL - Copyright (c) 2020-2023 Terje Io + Copyright (c) 2020-2024 Terje Io - Grbl is free software: you can redistribute it and/or modify + grblHAL is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Grbl is distributed in the hope that it will be useful, + grblHAL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Grbl. If not, see . + along with grblHAL. If not, see . */ #ifndef _PLUGINS_H_ @@ -92,7 +92,7 @@ typedef struct { #if MQTT_ENABLE mqtt_settings_t mqtt; #endif -#ifdef _WIZCHIP_ +#if defined(_WIZCHIP_) || defined(HAS_MAC_SETTING) uint8_t mac[6]; #endif } network_settings_t; diff --git a/settings.c b/settings.c index fea3375..9ca460e 100644 --- a/settings.c +++ b/settings.c @@ -1434,6 +1434,8 @@ inline static setting_id_t normalize_id (setting_id_t id) id = (setting_id_t)(Setting_EncoderSettingsBase + (id % ENCODER_SETTINGS_INCREMENT)); else if(id > Setting_ModbusTCPBase && id <= Setting_ModbusTCPMax) id = (setting_id_t)(Setting_ModbusTCPBase + (id % MODBUS_TCP_SETTINGS_INCREMENT)); + else if((id > Setting_Macro0 && id <= Setting_Macro9) || (id > Setting_MacroPort0 && id <= Setting_MacroPort9) || (id > Setting_ButtonAction0 && id <= Setting_ButtonAction9)) + id = (setting_id_t)(id - (id % 10)); return id; } diff --git a/settings.h b/settings.h index bb1277b..8c7710b 100644 --- a/settings.h +++ b/settings.h @@ -318,27 +318,29 @@ typedef enum { Setting_Spindle_DirPort = 488, Setting_Spindle_PWMPort = 489, - Setting_Macro0 = 490, - Setting_Macro1 = 491, - Setting_Macro2 = 492, - Setting_Macro3 = 493, - Setting_Macro4 = 494, - Setting_Macro5 = 495, - Setting_Macro6 = 496, - Setting_Macro7 = 497, - Setting_Macro8 = 498, - Setting_Macro9 = 499, + Setting_Macro0 = 490, + Setting_MacroBase = Setting_Macro0, + Setting_Macro1 = 491, + Setting_Macro2 = 492, + Setting_Macro3 = 493, + Setting_Macro4 = 494, + Setting_Macro5 = 495, + Setting_Macro6 = 496, + Setting_Macro7 = 497, + Setting_Macro8 = 498, + Setting_Macro9 = 499, - Setting_MacroPort0 = 500, - Setting_MacroPort1 = 501, - Setting_MacroPort2 = 502, - Setting_MacroPort3 = 503, - Setting_MacroPort4 = 504, - Setting_MacroPort5 = 505, - Setting_MacroPort6 = 506, - Setting_MacroPort7 = 507, - Setting_MacroPort8 = 508, - Setting_MacroPort9 = 509, + Setting_MacroPort0 = 500, + Setting_MacroPortBase = Setting_MacroPort0, + Setting_MacroPort1 = 501, + Setting_MacroPort2 = 502, + Setting_MacroPort3 = 503, + Setting_MacroPort4 = 504, + Setting_MacroPort5 = 505, + Setting_MacroPort6 = 506, + Setting_MacroPort7 = 507, + Setting_MacroPort8 = 508, + Setting_MacroPort9 = 509, Setting_SpindleEnable0 = 510, Setting_SpindleEnable1 = 511, @@ -391,16 +393,17 @@ typedef enum { Setting_Panel_Encoder3_Cpd = 559, Setting_Panel_SettingsMax = 579, - Setting_ButtonAction0 = 590, - Setting_ButtonAction1 = 591, - Setting_ButtonAction2 = 592, - Setting_ButtonAction3 = 593, - Setting_ButtonAction4 = 594, - Setting_ButtonAction5 = 595, - Setting_ButtonAction6 = 596, - Setting_ButtonAction7 = 597, - Setting_ButtonAction8 = 598, - Setting_ButtonAction9 = 599, + Setting_ButtonAction0 = 590, + Setting_ButtonActionBase = Setting_ButtonAction0, + Setting_ButtonAction1 = 591, + Setting_ButtonAction2 = 592, + Setting_ButtonAction3 = 593, + Setting_ButtonAction4 = 594, + Setting_ButtonAction5 = 595, + Setting_ButtonAction6 = 596, + Setting_ButtonAction7 = 597, + Setting_ButtonAction8 = 598, + Setting_ButtonAction9 = 599, Setting_ModbusTCPBase = 600, // Reserving settings values 600 to 639 for ModBus TCP (8 sets) Setting_ModbusIpAddressBase = Setting_ModbusTCPBase + Setting_ModbusIpAddress, From eb7610cd398afab53a09d2198a7a68e8c2cc52e2 Mon Sep 17 00:00:00 2001 From: Terje Io Date: Sun, 7 Jul 2024 06:55:24 +0200 Subject: [PATCH 07/23] Added soft limits check for corexy kinematics, ref. discussion #536. Added high level CANbus API for plugin use. Ref. issue #179. --- CMakeLists.txt | 1 + README.md | 2 +- canbus.c | 209 ++++++++++++++++++++++++++++++++++++++++++++ canbus.h | 48 ++++++++++ changelog.md | 18 ++++ grbl.h | 2 +- kinematics/corexy.c | 34 ++++++- report.c | 4 + settings.h | 3 +- 9 files changed, 316 insertions(+), 5 deletions(-) create mode 100644 canbus.c create mode 100644 canbus.h diff --git a/CMakeLists.txt b/CMakeLists.txt index dc731ae..eb64962 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,7 @@ target_sources(grbl INTERFACE ${CMAKE_CURRENT_LIST_DIR}/regex.c ${CMAKE_CURRENT_LIST_DIR}/ioports.c ${CMAKE_CURRENT_LIST_DIR}/vfs.c + ${CMAKE_CURRENT_LIST_DIR}/canbus.c ${CMAKE_CURRENT_LIST_DIR}/kinematics/corexy.c ${CMAKE_CURRENT_LIST_DIR}/kinematics/wall_plotter.c ${CMAKE_CURRENT_LIST_DIR}/kinematics/delta.c diff --git a/README.md b/README.md index ee5fadf..df8c0aa 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ It has been written to complement grblHAL and has features such as proper keyboa --- -Latest build date is 20240624, see the [changelog](changelog.md) for details. +Latest build date is 20240704, see the [changelog](changelog.md) for details. __NOTE:__ Build 20240222 has moved the probe input to the ioPorts pool of inputs and will be allocated from it when configured. The change is major and _potentially dangerous_, it may damage your probe, so please _verify correct operation_ after installing this, or later, builds. diff --git a/canbus.c b/canbus.c new file mode 100644 index 0000000..dc38595 --- /dev/null +++ b/canbus.c @@ -0,0 +1,209 @@ +/* + + canbus.c - + + Part of grblHAL + + Copyright (c) 2022 Jon Escombe + Copyright (c) 2024 Terje Io + + grblHAL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + grblHAL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with grblHAL. If not, see . + +*/ + +#include "hal.h" +#include "task.h" +#include "protocol.h" +#include "canbus.h" + +#ifndef CANBUS_BUFFER_LEN +#define CANBUS_BUFFER_LEN 8 +#endif +#ifndef CANBUS_BAUDRATE +#define CANBUS_BAUDRATE 0 // 125,000 +#endif + +typedef struct { + volatile canbus_message_t message; + can_rx_ptr callback; +} canbus_rx_message; + +typedef struct { + volatile canbus_message_t message; + bool ext_id; +} canbus_tx_message; + +typedef struct { + volatile uint8_t head; + volatile uint8_t tail; + volatile canbus_tx_message tx[CANBUS_BUFFER_LEN]; +} canbus_tx_buffer_t; + +typedef struct { + volatile uint8_t head; + volatile uint8_t tail; + volatile canbus_rx_message rx[CANBUS_BUFFER_LEN]; +} canbus_rx_buffer_t; + +static bool isEnabled = false; +static const uint32_t baud[] = { 125000, 250000, 500000, 1000000 }; +static canbus_tx_buffer_t tx_buffer = {0}; +static canbus_rx_buffer_t rx_buffer = {0}; + +// Weak implementations of low level functions to be provided by the driver + +__attribute__((weak)) bool can_start (uint32_t baud, can_rx_enqueue_fn callback) +{ + return false; +} + +__attribute__((weak)) bool can_stop (void) +{ + return false; +} + +__attribute__((weak)) bool can_set_baud (uint32_t baud) +{ + return false; +} + +__attribute__((weak)) bool can_put (canbus_message_t msg, bool ext_id) +{ + return false; +} + +__attribute__((weak)) bool can_add_filter (uint32_t id, uint32_t mask, bool ext_id, can_rx_ptr callback) +{ + return false; +} + +// --- + +ISR_CODE static bool ISR_FUNC(canbus_queue_rx)(canbus_message_t message, can_rx_ptr callback) +{ + bool ok; + uint8_t next_head = (rx_buffer.head + 1) % CANBUS_BUFFER_LEN; + + if((ok = next_head != rx_buffer.tail)) { + rx_buffer.rx[next_head].callback = callback; + rx_buffer.rx[next_head].message = message; + + rx_buffer.head = next_head; + } + + return ok; +} + +// called every 1 ms +static void canbus_poll (void *data) +{ + /* if have TX data, sends one message per iteration.. */ + if(tx_buffer.head != tx_buffer.tail && can_put(tx_buffer.tx[tx_buffer.tail].message, tx_buffer.tx[tx_buffer.tail].ext_id)) + tx_buffer.tail = (tx_buffer.tail + 1) % CANBUS_BUFFER_LEN; + + /* if have RX data, process one message per iteration.. */ + if(rx_buffer.head != rx_buffer.tail) { + if(rx_buffer.rx[rx_buffer.tail].callback) + rx_buffer.rx[rx_buffer.tail].callback(rx_buffer.rx[rx_buffer.tail].message); + rx_buffer.tail = (rx_buffer.tail + 1) % CANBUS_BUFFER_LEN; + } +} + +static bool canbus_start (uint32_t baud) +{ + if((isEnabled = can_start(baud, canbus_queue_rx))) + task_add_systick(canbus_poll, NULL); + + return isEnabled; +} + +static status_code_t canbus_set_baud (setting_id_t id, uint_fast16_t value) +{ + settings.canbus_baud = value; + + can_set_baud(baud[settings.canbus_baud]); + + return can_set_baud(baud[settings.canbus_baud]) ? Status_OK : Status_SettingValueOutOfRange; +} + +static uint32_t canbus_get_baud (setting_id_t setting) +{ + return settings.canbus_baud < (sizeof(baud) / sizeof(uint32_t)) ? settings.canbus_baud : CANBUS_BAUDRATE; +} + +static const setting_group_detail_t canbus_groups [] = { + { Group_Root, Group_CANbus, "CAN bus"} +}; + +static const setting_detail_t canbus_setting_detail[] = { + { Setting_CANbus_BaudRate, Group_CANbus, "CAN bus baud rate", NULL, Format_RadioButtons, "125000,250000,500000,1000000", NULL, NULL, Setting_NonCoreFn, canbus_set_baud, canbus_get_baud, NULL }, +}; + +static void canbus_settings_restore (void) +{ + settings.canbus_baud = CANBUS_BAUDRATE; + + settings_write_global(); +} + +static void canbus_settings_load (void) +{ + canbus_start(baud[canbus_get_baud(Setting_CANbus_BaudRate)]); +} + +static setting_details_t setting_details = { + .groups = canbus_groups, + .n_groups = sizeof(canbus_groups) / sizeof(setting_group_detail_t), + .settings = canbus_setting_detail, + .n_settings = sizeof(canbus_setting_detail) / sizeof(setting_detail_t), + .save = settings_write_global, + .load = canbus_settings_load, + .restore = canbus_settings_restore +}; + +// Public API + +bool canbus_enabled (void) +{ + return isEnabled; +} + +bool canbus_queue_tx (canbus_message_t message, bool ext_id) +{ + bool ok; + uint8_t next_head = (tx_buffer.head + 1) % CANBUS_BUFFER_LEN; + + if((ok = next_head != tx_buffer.tail)) { + tx_buffer.tx[tx_buffer.head].ext_id = ext_id; + tx_buffer.tx[tx_buffer.head].message = message; + tx_buffer.head = next_head; + } + + return ok; +} + +bool canbus_add_filter (uint32_t id, uint32_t mask, bool ext_id, can_rx_ptr callback) +{ + return can_add_filter(id, mask, ext_id, callback); +} + +void canbus_init (void) +{ + static bool init_ok = false; + + if(!init_ok) { + init_ok = true; + settings_register(&setting_details); + } +} diff --git a/canbus.h b/canbus.h new file mode 100644 index 0000000..f402f26 --- /dev/null +++ b/canbus.h @@ -0,0 +1,48 @@ +/* + + canbus.h - + + Part of grblHAL + + Copyright (c) 2022 Jon Escombe + Copyright (c) 2024 Terje Io + + grblHAL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + grblHAL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with grblHAL. If not, see . + +*/ + +#ifndef _CANBUS_H_ +#define _CANBUS_H_ + +#include +#include + +typedef struct { + uint32_t id; + uint8_t len; + uint8_t data[8]; +} canbus_message_t; + +typedef bool (*can_rx_ptr)(canbus_message_t); +typedef bool (*can_rx_enqueue_fn)(canbus_message_t msg, can_rx_ptr callback); // used internally by the driver + +/* + * Function prototypes + */ +void canbus_init (void); +bool canbus_enabled (void); +bool canbus_queue_tx (canbus_message_t message, bool ext_id); +bool canbus_add_filter (uint32_t id, uint32_t mask, bool ext_id, can_rx_ptr callback); + +#endif /* _CANBUS_H_ */ diff --git a/changelog.md b/changelog.md index 271bf13..7f93d3d 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,23 @@ ## grblHAL changelog +Build 20240704 + +Core: + +* Added high level CANbus API for plugin use. If driver/board combo provides the required lowlevel HAL API the `NEWOPT` string in the `$I` output will contain the `CAN` element when CAN is enabled. +Ref. [issue #179](https://github.com/grblHAL/STM32F4xx/issues/179). + +* Added soft limits check for corexy kinematics, ref. [discussion #536](https://github.com/grblHAL/core/discussions/536). + +Drivers: + +* ESP32: fixed WebUI regression. Ref. [issue #116](https://github.com/grblHAL/ESP32/issues/116). + +* STM32F7xx, STM32F4xx: Added lowlevel CANbus API and enabled it for some boards. + +--- + + Build 20240624 Core: diff --git a/grbl.h b/grbl.h index 88e7d18..fdc0090 100644 --- a/grbl.h +++ b/grbl.h @@ -42,7 +42,7 @@ #else #define GRBL_VERSION "1.1f" #endif -#define GRBL_BUILD 20240624 +#define GRBL_BUILD 20240704 #define GRBL_URL "https://github.com/grblHAL" diff --git a/kinematics/corexy.c b/kinematics/corexy.c index 9350bdf..be35bbb 100644 --- a/kinematics/corexy.c +++ b/kinematics/corexy.c @@ -37,6 +37,7 @@ #define B_MOTOR Y_AXIS // Must be Y_AXIS static on_report_options_ptr on_report_options; +static travel_limits_ptr check_travel_limits; // Returns x or y-axis "steps" based on CoreXY motor steps. inline static int32_t corexy_convert_to_a_motor_steps (int32_t *steps) @@ -77,12 +78,25 @@ static inline float *transform_from_cartesian (float *target, float *position) return target; } +// Transform position from motor (corexy) coordinate system to cartesian coordinate system +static inline float *transform_to_cartesian (float *target, float *position) +{ + uint_fast8_t idx; + + target[X_AXIS] = (position[X_AXIS] + position[Y_AXIS]) * 0.5f; + target[Y_AXIS] = (position[X_AXIS] - position[Y_AXIS]) * 0.5f; + + for(idx = Z_AXIS; idx < N_AXIS; idx++) + target[idx] = position[idx]; + + return target; +} + static uint_fast8_t corexy_limits_get_axis_mask (uint_fast8_t idx) { return ((idx == A_MOTOR) || (idx == B_MOTOR)) ? (bit(X_AXIS) | bit(Y_AXIS)) : bit(idx); } - static void corexy_limits_set_target_pos (uint_fast8_t idx) // fn name? { int32_t axis_position; @@ -102,6 +116,19 @@ static void corexy_limits_set_target_pos (uint_fast8_t idx) // fn name? } } +// Checks and reports if target array exceeds machine travel limits. Returns false if check failed. +// NOTE: target for axes X and Y are in motor coordinates if is_cartesian is false. +static bool corexy_check_travel_limits (float *target, axes_signals_t axes, bool is_cartesian) +{ + if(is_cartesian) + return check_travel_limits(target, axes, true); + + float cartesian_coords[N_AXIS]; + + transform_to_cartesian(cartesian_coords, target); + + return check_travel_limits(cartesian_coords, axes, true); +} // Set machine positions for homed limit switches. Don't update non-homed axes. // NOTE: settings.max_travel[] is stored as a negative value. @@ -207,7 +234,7 @@ static void report_options (bool newopt) on_report_options(newopt); if(!newopt) - hal.stream.write("[KINEMATICS:CoreXY v2.00]" ASCII_EOL); + hal.stream.write("[KINEMATICS:CoreXY v2.01]" ASCII_EOL); } // Initialize API pointers for CoreXY kinematics @@ -222,6 +249,9 @@ void corexy_init (void) kinematics.homing_cycle_validate = homing_cycle_validate; kinematics.homing_cycle_get_feedrate = homing_cycle_get_feedrate; + check_travel_limits = grbl.check_travel_limits; + grbl.check_travel_limits = corexy_check_travel_limits; + on_report_options = grbl.on_report_options; grbl.on_report_options = report_options; } diff --git a/report.c b/report.c index aafa32c..edbd558 100644 --- a/report.c +++ b/report.c @@ -38,6 +38,7 @@ #include "nvs_buffer.h" #include "machine_limits.h" #include "state_machine.h" +#include "canbus.h" #include "regex.h" #if ENABLE_SPINDLE_LINEARIZATION @@ -985,6 +986,9 @@ void report_build_info (char *line, bool extended) if(hal.rtc.get_datetime) strcat(buf, "RTC,"); + if(canbus_enabled()) + strcat(buf, "CAN,"); + #ifdef PID_LOG strcat(buf, "PID,"); #endif diff --git a/settings.h b/settings.h index 8c7710b..eb799f5 100644 --- a/settings.h +++ b/settings.h @@ -779,7 +779,8 @@ typedef struct { control_signals_t control_disable_pullup; coolant_state_t coolant_invert; axes_signals_t home_invert; - uint16_t hole_1; + uint8_t modbus_baud; + uint8_t canbus_baud; spindle_settings_t spindle; stepper_settings_t steppers; reportmask_t status_report; // Mask to indicate desired report data. From 5cff12e6608b1f53e4becff4e853e460fc1b7cbf Mon Sep 17 00:00:00 2001 From: Terje Io Date: Tue, 9 Jul 2024 19:34:31 +0200 Subject: [PATCH 08/23] Added printf style debug output function and corresponding macro. Added grbl.on_report_ngc_parameters event. Fixed silly mistakes in CAN code. --- canbus.c | 8 +++----- changelog.md | 18 +++++++++++++++++- core_handlers.h | 2 ++ grbl.h | 2 +- messages.h | 3 ++- report.c | 19 +++++++++++++------ stream.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ stream.h | 18 ++++++++++++++---- 8 files changed, 99 insertions(+), 18 deletions(-) diff --git a/canbus.c b/canbus.c index dc38595..29bf792 100644 --- a/canbus.c +++ b/canbus.c @@ -31,7 +31,7 @@ #define CANBUS_BUFFER_LEN 8 #endif #ifndef CANBUS_BAUDRATE -#define CANBUS_BAUDRATE 0 // 125,000 +#define CANBUS_BAUDRATE 0 // 125000 #endif typedef struct { @@ -96,8 +96,8 @@ ISR_CODE static bool ISR_FUNC(canbus_queue_rx)(canbus_message_t message, can_rx_ uint8_t next_head = (rx_buffer.head + 1) % CANBUS_BUFFER_LEN; if((ok = next_head != rx_buffer.tail)) { - rx_buffer.rx[next_head].callback = callback; - rx_buffer.rx[next_head].message = message; + rx_buffer.rx[rx_buffer.head].callback = callback; + rx_buffer.rx[rx_buffer.head].message = message; rx_buffer.head = next_head; } @@ -132,8 +132,6 @@ static status_code_t canbus_set_baud (setting_id_t id, uint_fast16_t value) { settings.canbus_baud = value; - can_set_baud(baud[settings.canbus_baud]); - return can_set_baud(baud[settings.canbus_baud]) ? Status_OK : Status_SettingValueOutOfRange; } diff --git a/changelog.md b/changelog.md index 7f93d3d..74723a9 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,21 @@ ## grblHAL changelog +Build 20240709 + +Core: + +* For developers: added printf style debug output function and corresponding macro. See _grbl/stream.h_ for details. Added `grbl.on_report_ngc_parameters` event. + +* Fixed silly mistakes in CAN code. Ref. [issue #179](https://github.com/grblHAL/STM32F4xx/issues/179#issuecomment-2217912406). + +Drivers: + +* SAM3X8E: [PR #25](https://github.com/grblHAL/SAM3X8E/pull/25), adds missing guards around references. + +* STM32F1xx: added tentative board map for Creality v4.4.2 and v4.4.7. Ref. [issue #33](https://github.com/grblHAL/STM32F1xx/issues/33). Not tested! + +--- + Build 20240704 Core: @@ -13,7 +29,7 @@ Drivers: * ESP32: fixed WebUI regression. Ref. [issue #116](https://github.com/grblHAL/ESP32/issues/116). -* STM32F7xx, STM32F4xx: Added lowlevel CANbus API and enabled it for some boards. +* STM32F7xx, STM32F4xx: added lowlevel CANbus API and enabled it for some boards. --- diff --git a/core_handlers.h b/core_handlers.h index e099d2e..405cfec 100644 --- a/core_handlers.h +++ b/core_handlers.h @@ -95,6 +95,7 @@ typedef void (*on_unknown_accessory_override_ptr)(uint8_t cmd); typedef bool (*on_unknown_realtime_cmd_ptr)(char c); typedef void (*on_report_handlers_init_ptr)(void); typedef void (*on_report_options_ptr)(bool newopt); +typedef void (*on_report_ngc_parameters_ptr)(void); typedef void (*on_report_command_help_ptr)(void); typedef const char *(*on_setting_get_description_ptr)(setting_id_t id); typedef void (*on_global_settings_restore_ptr)(void); @@ -156,6 +157,7 @@ typedef struct { on_execute_realtime_ptr on_execute_delay; on_unknown_accessory_override_ptr on_unknown_accessory_override; on_report_options_ptr on_report_options; + on_report_ngc_parameters_ptr on_report_ngc_parameters; on_report_command_help_ptr on_report_command_help; //!< Deprecated, use system_register_commands() to register new commands. on_rt_reports_added_ptr on_rt_reports_added; on_global_settings_restore_ptr on_global_settings_restore; diff --git a/grbl.h b/grbl.h index fdc0090..8f1cfa5 100644 --- a/grbl.h +++ b/grbl.h @@ -42,7 +42,7 @@ #else #define GRBL_VERSION "1.1f" #endif -#define GRBL_BUILD 20240704 +#define GRBL_BUILD 20240709 #define GRBL_URL "https://github.com/grblHAL" diff --git a/messages.h b/messages.h index 0b1a8fb..3983fed 100644 --- a/messages.h +++ b/messages.h @@ -53,7 +53,8 @@ typedef enum { typedef enum { Message_Plain = 0, Message_Info, - Message_Warning + Message_Warning, + Message_Debug } message_type_t; typedef struct { diff --git a/report.c b/report.c index edbd558..3247ab4 100644 --- a/report.c +++ b/report.c @@ -21,7 +21,7 @@ */ /* - This file functions as the primary feedback interface for Grbl. Any outgoing data, such + This file functions as the primary feedback interface for grblHAL. Any outgoing data, such as the protocol status messages, feedback messages, and status reports, are stored here. For the most part, these functions primarily are called from protocol.c methods. If a different style feedback is desired (i.e. JSON), then a user can change these following @@ -267,6 +267,10 @@ void report_message (const char *msg, message_type_t type) hal.stream.write("Warning: "); break; + case Message_Debug: + hal.stream.write("Debug: "); + break; + default: break; } @@ -405,7 +409,7 @@ status_code_t report_help (char *args) } -// Grbl settings print out. +// grblHAL settings print out. static int cmp_settings (const void *a, const void *b) { @@ -508,7 +512,7 @@ void report_grbl_settings (bool all, void *data) // Prints current probe parameters. Upon a probe command, these parameters are updated upon a // successful probe or upon a failed probe with the G38.3 without errors command (if supported). -// These values are retained until Grbl is power-cycled, whereby they will be re-zeroed. +// These values are retained until grblHAL is power-cycled, whereby they will be re-zeroed. void report_probe_parameters (void) { // Report in terms of machine position. @@ -581,7 +585,7 @@ status_code_t report_named_ngc_parameter (char *arg) #endif -// Prints Grbl NGC parameters (coordinate offsets, probing, tool table) +// Prints grblHAL NGC parameters (coordinate offsets, probing, tool table) void report_ngc_parameters (void) { uint_fast8_t idx; @@ -656,6 +660,9 @@ void report_ngc_parameters (void) hal.stream.write(get_axis_value(sys.tlo_reference[plane.axis_linear] / settings.axis[plane.axis_linear].steps_per_mm)); hal.stream.write("]" ASCII_EOL); } + + if(grbl.on_report_ngc_parameters) + grbl.on_report_ngc_parameters(); } static inline bool is_g92_active (void) @@ -1082,8 +1089,8 @@ void report_build_info (char *line, bool extended) } -// Prints the character string line Grbl has received from the user, which has been pre-parsed, -// and has been sent into protocol_execute_line() routine to be executed by Grbl. +// Prints the character string line grblHAL has received from the user, which has been pre-parsed, +// and has been sent into protocol_execute_line() routine to be executed by grblHAL. void report_echo_line_received (char *line) { hal.stream.write("[echo: "); diff --git a/stream.c b/stream.c index c80b814..1154748 100644 --- a/stream.c +++ b/stream.c @@ -26,6 +26,14 @@ #include "protocol.h" #include "state_machine.h" +#if defined(DEBUG) || defined(DEBUGOUT) +#include +#include +#ifndef DEBUG_BUFFER +#define DEBUG_BUFFER 100 +#endif +#endif + static stream_rx_buffer_t rxbackup; typedef struct { @@ -664,6 +672,20 @@ void debug_writeln (const char *s) } } +void debug_printf (const char *fmt, ...) +{ + char debug_out[DEBUG_BUFFER]; + + va_list args; + va_start(args, fmt); + vsnprintf(debug_out, sizeof(debug_out) - 1, fmt, args); + va_end(args); + + debug_writeln(debug_out); + while(hal.stream.get_tx_buffer_count()) // Wait until message is delivered + grbl.on_execute_realtime(state_get()); +} + static bool debug_claim_stream (io_stream_properties_t const *stream) { io_stream_t const *claimed = NULL; @@ -694,4 +716,29 @@ bool debug_stream_init (void) return hal.debug.write == debug_write; } +#elif defined(DEBUG) + +void debug_printf (const char *fmt, ...) +{ + char debug_out[DEBUG_BUFFER]; + + va_list args; + va_start(args, fmt); + vsnprintf(debug_out, sizeof(debug_out) - 1, fmt, args); + va_end(args); + + if(hal.stream.write) { + report_message(debug_out, Message_Debug); + while(hal.stream.get_tx_buffer_count()) // Wait until message is delivered + grbl.on_execute_realtime(state_get()); + } +} + +#else + +void debug_printf (const char *fmt, ...) +{ + // NOOP +} + #endif diff --git a/stream.h b/stream.h index 3b41f85..8a3983f 100644 --- a/stream.h +++ b/stream.h @@ -5,18 +5,18 @@ Copyright (c) 2019-2023 Terje Io - Grbl is free software: you can redistribute it and/or modify + grblHAL is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Grbl is distributed in the hope that it will be useful, + grblHAL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Grbl. If not, see . + along with grblHAL. If not, see . */ /*! \file @@ -357,11 +357,21 @@ io_stream_t const *stream_open_instance (uint8_t instance, uint32_t baud_rate, s bool stream_set_description (const io_stream_t *stream, const char *description); +void debug_printf(const char *fmt, ...); + +#if defined(DEBUG) || defined(DEBUGOUT) +#define DEBUG_PRINT 1 #ifdef DEBUGOUT void debug_write (const char *s); void debug_writeln (const char *s); bool debug_stream_init (void); #endif +#else +#define DEBUG_PRINT 0 +#endif + +#define debug_print(fmt, ...) \ + do { if(DEBUG_PRINT) debug_printf(fmt, __VA_ARGS__); } while(0) #ifdef __cplusplus } From 8b9b7859ee6b370442d380d3d754fa5392b064b2 Mon Sep 17 00:00:00 2001 From: Terje Io Date: Fri, 19 Jul 2024 09:49:46 +0200 Subject: [PATCH 09/23] Limited tool change probe moves to be within machine limits. Ref. issue #542. Added setting $358 to enable experimental functionality for fast rotary 'rewind' to stored G28 position. Return move should complete in half a rotation or less. For developers: added option to redirect debug via driver provided function when DEBUGOUT is set to -1 in config.h. Ref. issue #545. --- README.md | 2 +- changelog.md | 22 +++++++++++ config.h | 12 ++++++ gcode.c | 54 +++++++++++++++++++++++++-- gcode.h | 3 ++ grbl.h | 2 +- machine_limits.c | 2 +- planner.c | 6 +-- report.c | 2 +- settings.c | 95 +++++++++++++++++++++++++++++++++--------------- settings.h | 14 ++++--- stream.c | 36 +++++++++++++++++- tool_change.c | 14 ++++++- 13 files changed, 214 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index df8c0aa..1faf0f5 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ It has been written to complement grblHAL and has features such as proper keyboa --- -Latest build date is 20240704, see the [changelog](changelog.md) for details. +Latest build date is 20240719, see the [changelog](changelog.md) for details. __NOTE:__ Build 20240222 has moved the probe input to the ioPorts pool of inputs and will be allocated from it when configured. The change is major and _potentially dangerous_, it may damage your probe, so please _verify correct operation_ after installing this, or later, builds. diff --git a/changelog.md b/changelog.md index 74723a9..0a5aed1 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,27 @@ ## grblHAL changelog +Build 20240719 + +Core: + +* Limited tool change probe moves to be within machine limits. Ref. [issue #542](https://github.com/grblHAL/core/issues/542). + +* Added setting `$358` to enable experimental functionality for fast rotary 'rewind' to stored G28 position. Return move should complete in half a rotation or less. +To use program: +``` +G91G280 +G90 +``` +where \ is the axisletter of the rotary axis to move. + +* For developers: added option to redirect debug via driver provided function when `DEBUGOUT` is set to `-1` in _config.h_. Can be used to send debug output to debugger interfaces. + +Plugins: + +* WebUI: fix for crash when settings page is opened with macros plugin enabled. Ref. [issue #14](https://github.com/grblHAL/Plugin_WebUI/issues/14). + +--- + Build 20240709 Core: diff --git a/config.h b/config.h index e86eae4..4f269ce 100644 --- a/config.h +++ b/config.h @@ -1783,6 +1783,18 @@ Timezone offset from UTC in hours, allowed range is -12.0 - 12.0. #endif ///@} +/*! @name $538 - Setting_RotaryWrap +Enable fast return to G28 position for rotary axes by \ref axismask. +Use: +G91G280 +G90 +*/ +///@{ +#if !defined DEFAULT_AXIS_ROTARY_WRAP_MASK || defined __DOXYGEN__ +#define DEFAULT_AXIS_ROTARY_WRAP_MASK 0 +#endif +///@} + // Axis settings (Group_XAxis - Group_VAxis) /*! @name $10x - Setting_AxisStepsPerMM diff --git a/gcode.c b/gcode.c index 96c6b7f..6ac12ec 100644 --- a/gcode.c +++ b/gcode.c @@ -1287,7 +1287,7 @@ status_code_t gc_execute_block (char *block) case 56: if(!settings.parking.flags.enable_override_control) // TODO: check if enabled? FAIL(Status_GcodeUnsupportedCommand); // [Unsupported M command] - // no break; + // no break case 48: case 49: case 50: case 51: case 53: word_bit.modal_group.M9 = On; gc_block.override_command = (override_mode_t)int_value; @@ -1979,7 +1979,7 @@ status_code_t gc_execute_block (char *block) if (gc_block.modal.units_imperial) do { // Axes indices are consistent, so loop may be used. idx--; #if N_AXIS > 3 - if (bit_istrue(axis_words.mask, bit(idx)) && bit_isfalse(settings.steppers.is_rotational.mask, bit(idx))) { + if (bit_istrue(axis_words.mask, bit(idx)) && bit_isfalse(settings.steppers.is_rotary.mask, bit(idx))) { #else if (bit_istrue(axis_words.mask, bit(idx))) { #endif @@ -3408,12 +3408,60 @@ status_code_t gc_execute_block (char *block) break; case NonModal_GoHome_0: +#if N_AXIS > 3 + { + axes_signals_t wrap = { (axis_words.mask & settings.steppers.is_rotary.mask) & settings.steppers.rotary_wrap.mask }; + if(gc_state.modal.distance_incremental && wrap.mask) { + for(idx = Z_AXIS + 1; idx < N_AXIS; idx++) { + if(bit_istrue(wrap.mask, bit(idx)) && gc_block.values.xyz[idx] == gc_state.position[idx]) + gc_block.rotary_wrap.mask |= bit(idx); + } + } + } + // no break +#endif + case NonModal_GoHome_1: // Move to intermediate position before going home. Obeys current coordinate system and offsets // and absolute and incremental modes. plan_data.condition.rapid_motion = On; // Set rapid motion condition flag. - if (axis_command) + if(axis_command) mc_line(gc_block.values.xyz, &plan_data); +#if N_AXIS > 3 + if(gc_block.rotary_wrap.mask) { + + coord_system_t wrap_target; + + protocol_buffer_synchronize(); + memcpy(wrap_target.xyz, gc_block.values.coord_data.xyz, sizeof(coord_system_t)); + + for(idx = Z_AXIS + 1; idx < N_AXIS; idx++) { + if(bit_istrue(gc_block.rotary_wrap.mask, bit(idx))) { + float position, delta; + if((wrap_target.xyz[idx] = fmodf(wrap_target.xyz[idx], 360.0f)) < 0.0f) + wrap_target.xyz[idx] = 360.0f + wrap_target.xyz[idx]; + if((position = fmodf(gc_state.position[idx], 360.0f)) < 0.0) + position = 360.0f + position; + if((delta = position - wrap_target.xyz[idx]) < -180.0f) + position += 360.0f; + else if(delta > 180.0f) + position -= 360.0f; + sys.position[idx] = lroundf(position * settings.axis[idx].steps_per_mm); + } + } + + sync_position(); + mc_line(wrap_target.xyz, &plan_data); + protocol_buffer_synchronize(); + + for(idx = Z_AXIS + 1; idx < N_AXIS; idx++) { + if(bit_istrue(gc_block.rotary_wrap.mask, bit(idx))) + sys.position[idx] = lroundf(gc_block.values.coord_data.xyz[idx] * settings.axis[idx].steps_per_mm); + } + + sync_position(); + } else +#endif mc_line(gc_block.values.coord_data.xyz, &plan_data); memcpy(gc_state.position, gc_block.values.coord_data.xyz, sizeof(gc_state.position)); set_scaling(1.0f); diff --git a/gcode.h b/gcode.h index 85cf8a0..faff728 100644 --- a/gcode.h +++ b/gcode.h @@ -624,6 +624,9 @@ typedef struct { #if NGC_PARAMETERS_ENABLE modal_state_action_t state_action; //!< M70-M73 modal state action #endif +#if N_AXIS > 3 + axes_signals_t rotary_wrap; +#endif } parser_block_t; // Initialize the parser diff --git a/grbl.h b/grbl.h index 8f1cfa5..cfe386f 100644 --- a/grbl.h +++ b/grbl.h @@ -42,7 +42,7 @@ #else #define GRBL_VERSION "1.1f" #endif -#define GRBL_BUILD 20240709 +#define GRBL_BUILD 20240719 #define GRBL_URL "https://github.com/grblHAL" diff --git a/machine_limits.c b/machine_limits.c index c679456..659c004 100644 --- a/machine_limits.c +++ b/machine_limits.c @@ -296,7 +296,7 @@ static bool homing_cycle (axes_signals_t cycle, axes_signals_t auto_square) // NOTE: settings.axis[].max_travel is stored as a negative value. if(bit_istrue(cycle.mask, bit(idx))) { #if N_AXIS > 3 - if(bit_istrue(settings.steppers.is_rotational.mask, bit(idx))) + if(bit_istrue(settings.steppers.is_rotary.mask, bit(idx))) max_travel = max(max_travel, (-HOMING_AXIS_SEARCH_SCALAR) * (settings.axis[idx].max_travel < -0.0f ? settings.axis[idx].max_travel : -360.0f)); else #endif diff --git a/planner.c b/planner.c index d3011b1..c220217 100644 --- a/planner.c +++ b/planner.c @@ -469,13 +469,13 @@ bool plan_buffer_line (float *target, plan_line_data_t *pl_data) if(!block->condition.inverse_time && !block->condition.rapid_motion && - (motion.mask & settings.steppers.is_rotational.mask) && - (motion.mask & ~settings.steppers.is_rotational.mask)) { + (motion.mask & settings.steppers.is_rotary.mask) && + (motion.mask & ~settings.steppers.is_rotary.mask)) { float linear_magnitude = 0.0f; idx = 0; - motion.mask &= ~settings.steppers.is_rotational.mask; + motion.mask &= ~settings.steppers.is_rotary.mask; while(motion.mask) { if(motion.mask & 0x01) diff --git a/report.c b/report.c index 3247ab4..7a513fc 100644 --- a/report.c +++ b/report.c @@ -118,7 +118,7 @@ static char *get_axis_values_inches (float *axis_values) if(idx == X_AXIS && gc_state.modal.diameter_mode) strcat(buf, ftoa(axis_values[idx] * INCH_PER_MM * 2.0f, N_DECIMAL_COORDVALUE_INCH)); #if N_AXIS > 3 - else if(idx > Z_AXIS && bit_istrue(settings.steppers.is_rotational.mask, bit(idx))) + else if(idx > Z_AXIS && bit_istrue(settings.steppers.is_rotary.mask, bit(idx))) strcat(buf, ftoa(axis_values[idx], N_DECIMAL_COORDVALUE_MM)); #endif else diff --git a/settings.c b/settings.c index 9ca460e..c536406 100644 --- a/settings.c +++ b/settings.c @@ -103,7 +103,8 @@ PROGMEM const settings_t defaults = { #endif .steppers.deenergize.mask = DEFAULT_STEPPER_DEENERGIZE_MASK, #if N_AXIS > 3 - .steppers.is_rotational.mask = (DEFAULT_AXIS_ROTATIONAL_MASK & AXES_BITMASK) & 0b11111000, + .steppers.is_rotary.mask = (DEFAULT_AXIS_ROTATIONAL_MASK & AXES_BITMASK) & 0b11111000, + .steppers.rotary_wrap.mask = (DEFAULT_AXIS_ROTARY_WRAP_MASK & AXES_BITMASK) & 0b11111000, #endif #if DEFAULT_HOMING_ENABLE .homing.flags.enabled = DEFAULT_HOMING_ENABLE, @@ -406,7 +407,8 @@ static status_code_t set_linear_piece (setting_id_t id, char *svalue); static char *get_linear_piece (setting_id_t id); #endif #if N_AXIS > 3 -static status_code_t set_rotational_axes (setting_id_t id, uint_fast16_t int_value); +static status_code_t set_rotary_axes (setting_id_t id, uint_fast16_t int_value); +static status_code_t set_rotary_wrap_axes (setting_id_t id, uint_fast16_t int_value); #endif #if COMPATIBILITY_LEVEL > 2 static status_code_t set_enable_invert_mask (setting_id_t id, uint_fast16_t int_value); @@ -434,6 +436,28 @@ static char control_signals[] = "Reset,Feed hold,Cycle start,Safety door,Block d static char spindle_signals[] = "Spindle enable,Spindle direction,PWM"; static char coolant_signals[] = "Flood,Mist"; static char ganged_axes[] = "X-Axis,Y-Axis,Z-Axis"; +#if !AXIS_REMAP_ABC2UVW + #if N_AXIS == 4 + static const char rotary_axes[] = "A-Axis"; + #elif N_AXIS == 5 + static const char rotary_axes[] = "A-Axis,B-Axis"; + #elif N_AXIS == 6 + static const char rotary_axes[] = "A-Axis,B-Axis,C-Axis"; + #elif N_AXIS == 7 + static const char rotary_axes[] = "A-Axis,B-Axis,C-Axis,U-Axis"; + #elif N_AXIS == 8 + static const char rotary_axes[] = "A-Axis,B-Axis,C-Axis,U-Axis,V-Axis"; + #endif +#else + #if N_AXIS == 4 + static const char rotary_axes[] = "U-Axis"; + #elif N_AXIS == 5 + static const char rotary_axes[] = "U-Axis,V-Axis"; + #elif N_AXIS == 6 + static const char rotary_axes[] = "U-Axis,V-Axis,W-Axis"; + #endif +#endif + static char fs_options[] = "Auto mount SD card,Hide LittleFS"; static char spindle_types[100] = ""; static char axis_dist[4] = "mm"; @@ -585,26 +609,8 @@ PROGMEM static const setting_detail_t setting_detail[] = { #if COMPATIBILITY_LEVEL <= 1 { Setting_DisableG92Persistence, Group_General, "Disable G92 persistence", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_g92_disable_persistence, get_int, NULL }, #endif -#if !AXIS_REMAP_ABC2UVW - #if N_AXIS == 4 - { Settings_Axis_Rotational, Group_Stepper, "Rotational axes", NULL, Format_Bitfield, "A-Axis", NULL, NULL, Setting_IsExtendedFn, set_rotational_axes, get_int, NULL }, - #elif N_AXIS == 5 - { Settings_Axis_Rotational, Group_Stepper, "Rotational axes", NULL, Format_Bitfield, "A-Axis,B-Axis", NULL, NULL, Setting_IsExtendedFn, set_rotational_axes, get_int, NULL }, - #elif N_AXIS == 6 - { Settings_Axis_Rotational, Group_Stepper, "Rotational axes", NULL, Format_Bitfield, "A-Axis,B-Axis,C-Axis", NULL, NULL, Setting_IsExtendedFn, set_rotational_axes, get_int, NULL }, - #elif N_AXIS == 7 - { Settings_Axis_Rotational, Group_Stepper, "Rotational axes", NULL, Format_Bitfield, "A-Axis,B-Axis,C-Axis,U-Axis", NULL, NULL, Setting_IsExtendedFn, set_rotational_axes, get_int, NULL }, - #elif N_AXIS == 8 - { Settings_Axis_Rotational, Group_Stepper, "Rotational axes", NULL, Format_Bitfield, "A-Axis,B-Axis,C-Axis,U-Axis,V-Axis", NULL, NULL, Setting_IsExtendedFn, set_rotational_axes, get_int, NULL }, - #endif -#else - #if N_AXIS == 4 - { Settings_Axis_Rotational, Group_Stepper, "Rotational axes", NULL, Format_Bitfield, "U-Axis", NULL, NULL, Setting_IsExtendedFn, set_rotational_axes, get_int, NULL }, - #elif N_AXIS == 5 - { Settings_Axis_Rotational, Group_Stepper, "Rotational axes", NULL, Format_Bitfield, "U-Axis,V-Axis", NULL, NULL, Setting_IsExtendedFn, set_rotational_axes, get_int, NULL }, - #elif N_AXIS == 6 - { Settings_Axis_Rotational, Group_Stepper, "Rotational axes", NULL, Format_Bitfield, "U-Axis,V-Axis,W-Axis", NULL, NULL, Setting_IsExtendedFn, set_rotational_axes, get_int, NULL }, - #endif +#if N_AXIS > 3 + { Settings_RotaryAxes, Group_Stepper, "Rotary axes", NULL, Format_Bitfield, rotary_axes, NULL, NULL, Setting_IsExtendedFn, set_rotary_axes, get_int, NULL }, #endif #ifndef NO_SAFETY_DOOR_SUPPORT { Setting_DoorSpindleOnDelay, Group_SafetyDoor, "Spindle on delay", "s", Format_Decimal, "#0.0", "0.5", "20", Setting_IsExtended, &settings.safety_door.spindle_on_delay, NULL, is_setting_available }, @@ -623,6 +629,9 @@ PROGMEM static const setting_detail_t setting_detail[] = { { Setting_OffsetLock, Group_General, "Lock coordinate systems", NULL, Format_Bitfield, "G59.1,G59.2,G59.3", NULL, NULL, Setting_IsExtendedFn, set_offset_lock, get_int, NULL }, #endif { Setting_EncoderSpindle, Group_Spindle, "Encoder spindle", NULL, Format_RadioButtons, spindle_types, NULL, NULL, Setting_IsExtendedFn, set_encoder_spindle, get_int, is_setting_available }, +#if N_AXIS > 3 + { Setting_RotaryWrap, Group_Stepper, "Fast rotary go to G28", NULL, Format_Bitfield, rotary_axes, NULL, NULL, Setting_IsExtendedFn, set_rotary_wrap_axes, get_int, NULL }, +#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_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 } @@ -784,9 +793,12 @@ PROGMEM static const setting_descr_t setting_descr[] = { #if COMPATIBILITY_LEVEL <= 1 { Setting_DisableG92Persistence, "Disables save/restore of G92 offset to non-volatile storage (NVS)." }, #endif +#if N_AXIS > 3 + { Settings_RotaryAxes, "Designates axes as rotary, interpretation some other relevant axis settings is changed accordingly." }, +#endif #ifndef NO_SAFETY_DOOR_SUPPORT - { Setting_DoorSpindleOnDelay, "Delay to allow spindle to spin up after safety door is opened or feed hold is canceled.." }, - { Setting_DoorCoolantOnDelay, "Delay to allow coolant to restart after safety door is opened or feed hold is canceled.." }, + { Setting_DoorSpindleOnDelay, "Delay to allow spindle to spin up after safety door is opened or feed hold is canceled." }, + { Setting_DoorCoolantOnDelay, "Delay to allow coolant to restart after safety door is opened or feed hold is canceled." }, #else { Setting_DoorSpindleOnDelay, "Delay to allow spindle to spin up when spindle at speed tolerance is > 0." }, #endif @@ -803,6 +815,13 @@ PROGMEM static const setting_descr_t setting_descr[] = { { Setting_NGCDebugOut, "Example: (debug, metric mode: #<_metric>, coord system: #5220)" }, #endif { Setting_EncoderSpindle, "Specifies which spindle has the encoder attached." }, +#if N_AXIS > 3 + { Setting_RotaryWrap, "Perform fast move to angle stored in G28 position.\\n" + "Use:\\n" + " G91G280\\n" + " G90\\n" + }, +#endif { Setting_FSOptions, "Auto mount SD card on startup." }, { Setting_HomePinsInvertMask, "Inverts the axis home input signals." }, { Setting_HoldCoolantOnDelay, "Delay to allow coolant to restart after feed hold is canceled." } @@ -1128,7 +1147,7 @@ static inline void tmp_set_hard_limits (void) sys.hard_limits.mask = settings.limits.flags.hard_enabled ? AXES_BITMASK : 0; #if N_AXIS > 3 if(settings.limits.flags.hard_disabled_rotary) - sys.hard_limits.mask &= ~settings.steppers.is_rotational.mask; + sys.hard_limits.mask &= ~settings.steppers.is_rotary.mask; #endif } @@ -1340,16 +1359,23 @@ static inline void set_axis_unit (const setting_detail_t *setting, const char *u #if N_AXIS > 3 -static status_code_t set_rotational_axes (setting_id_t id, uint_fast16_t int_value) +static status_code_t set_rotary_axes (setting_id_t id, uint_fast16_t int_value) { - settings.steppers.is_rotational.mask = (int_value << 3) & AXES_BITMASK; + settings.steppers.is_rotary.mask = (int_value << 3) & AXES_BITMASK; + + return Status_OK; +} + +static status_code_t set_rotary_wrap_axes (setting_id_t id, uint_fast16_t int_value) +{ + settings.steppers.rotary_wrap.mask = (int_value << 3) & AXES_BITMASK; return Status_OK; } static inline bool axis_is_rotary (uint_fast8_t axis_idx) { - return bit_istrue(settings.steppers.is_rotational.mask, bit(axis_idx)); + return bit_istrue(settings.steppers.is_rotary.mask, bit(axis_idx)); } static const char *set_axis_setting_unit (setting_id_t setting_id, uint_fast8_t axis_idx) @@ -1730,8 +1756,12 @@ static uint32_t get_int (setting_id_t id) break; #if N_AXIS > 3 - case Settings_Axis_Rotational: - value = (settings.steppers.is_rotational.mask & AXES_BITMASK) >> 3; + case Settings_RotaryAxes: + value = (settings.steppers.is_rotary.mask & AXES_BITMASK) >> 3; + break; + + case Setting_RotaryWrap: + value = (settings.steppers.rotary_wrap.mask & AXES_BITMASK) >> 3; break; #endif @@ -2184,6 +2214,7 @@ bool read_global_settings () bool ok = hal.nvs.type != NVS_None && SETTINGS_VERSION == hal.nvs.get_byte(0) && hal.nvs.memcpy_from_nvs((uint8_t *)&settings, NVS_ADDR_GLOBAL, sizeof(settings_t), true) == NVS_TransferResult_OK; // Sanity check of settings, board map could have been changed... + #if LATHE_UVW_OPTION settings.mode = Mode_Lathe; #else @@ -2209,6 +2240,10 @@ bool read_global_settings () settings.steppers.enable_invert.mask = AXES_BITMASK; #endif +#if N_AXIS > 3 + settings.steppers.rotary_wrap.mask &= settings.steppers.is_rotary.mask; +#endif + settings.control_invert.mask |= limits_override.mask; settings.control_disable_pullup.mask &= ~limits_override.mask; diff --git a/settings.h b/settings.h index eb799f5..4192492 100644 --- a/settings.h +++ b/settings.h @@ -7,18 +7,18 @@ Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC Copyright (c) 2009-2011 Simen Svale Skogsrud - Grbl is free software: you can redistribute it and/or modify + grblHAL is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Grbl is distributed in the hope that it will be useful, + grblHAL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Grbl. If not, see . + along with grblHAL. If not, see . */ #ifndef _SETTINGS_H_ @@ -247,7 +247,7 @@ typedef enum { Settings_IoPort_OD_Enable = 373, Settings_ModBus_BaudRate = 374, Settings_ModBus_RXTimeout = 375, - Settings_Axis_Rotational = 376, + Settings_RotaryAxes = 376, Setting_BlueToothInitOK = 377, Setting_CoolantOnDelay = 378, Setting_CoolantOffDelay = 379, @@ -370,6 +370,7 @@ typedef enum { Setting_NetworkMAC = 535, Setting_RGB_StripLengt0 = 536, Setting_RGB_StripLengt1 = 537, + Setting_RotaryWrap = 538, Setting_Panel_SpindleSpeed = 540, // NOTE: Reserving settings values 540 to 579 for panel settings. Setting_Panel_ModbusAddress = 541, @@ -664,7 +665,8 @@ typedef struct { axes_signals_t enable_invert; axes_signals_t deenergize; #if N_AXIS > 3 - axes_signals_t is_rotational; // rotational axes distances are not scaled in imperial mode + axes_signals_t is_rotary; // rotary axes distances are not scaled in imperial mode + axes_signals_t rotary_wrap; // rotary axes that allows G28 wrap for faster move to home position #endif float pulse_microseconds; float pulse_delay_microseconds; diff --git a/stream.c b/stream.c index 1154748..ad2d921 100644 --- a/stream.c +++ b/stream.c @@ -651,6 +651,38 @@ const io_stream_t *stream_null_init (uint32_t baud_rate) #ifdef DEBUGOUT +#if DEBUGOUT == -1 + +__attribute__((weak)) void debug_write (const char *s) +{ + // NOOP +} + +void debug_writeln (const char *s) +{ + debug_write(s); + debug_write(ASCII_EOL); +} + +void debug_printf (const char *fmt, ...) +{ + char debug_out[DEBUG_BUFFER]; + + va_list args; + va_start(args, fmt); + vsnprintf(debug_out, sizeof(debug_out) - 1, fmt, args); + va_end(args); + + debug_writeln(debug_out); +} + +bool debug_stream_init (void) +{ + return true; +} + +#else + static stream_write_ptr dbg_write = NULL; void debug_write (const char *s) @@ -682,8 +714,6 @@ void debug_printf (const char *fmt, ...) va_end(args); debug_writeln(debug_out); - while(hal.stream.get_tx_buffer_count()) // Wait until message is delivered - grbl.on_execute_realtime(state_get()); } static bool debug_claim_stream (io_stream_properties_t const *stream) @@ -716,6 +746,8 @@ bool debug_stream_init (void) return hal.debug.write == debug_write; } +#endif // DEBUGOUT + #elif defined(DEBUG) void debug_printf (const char *fmt, ...) diff --git a/tool_change.c b/tool_change.c index 80cb1ae..b43ba99 100644 --- a/tool_change.c +++ b/tool_change.c @@ -180,6 +180,15 @@ static void execute_restore (void *data) system_set_exec_state_flag(EXEC_CYCLE_START); } +// Set and limit probe travel to be within machine limits. +static void set_probe_target (coord_data_t *target, uint8_t axis) +{ + target->values[axis] -= settings.tool_change.probing_distance; + + if(bit_istrue(sys.homed.mask, bit(axis)) && settings.axis[axis].max_travel < -0.0f) + target->values[axis] = max(min(target->values[axis], sys.work_envelope.max.values[axis]), sys.work_envelope.min.values[axis]); +} + // Execute touch off on cycle start event from @ G59.3 position. // Used in SemiAutomatic mode ($341=3) only. Called from the foreground process. static void execute_probe (void *data) @@ -213,7 +222,8 @@ static void execute_probe (void *data) 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; + + set_probe_target(&target, plane.axis_linear); if((ok = ok && mc_probe_cycle(target.values, &plan_data, flags) == GCProbe_Found)) { @@ -485,7 +495,7 @@ status_code_t tc_probe_workpiece (void) plan_data_init(&plan_data); plan_data.feed_rate = settings.tool_change.seek_rate; - target.values[plane.axis_linear] -= settings.tool_change.probing_distance; + set_probe_target(&target, plane.axis_linear); if((ok = mc_probe_cycle(target.values, &plan_data, flags) == GCProbe_Found)) { From 1c1519dfb259da485886cf3f883748e662e8f1c8 Mon Sep 17 00:00:00 2001 From: Terje Io Date: Sun, 21 Jul 2024 22:27:06 +0200 Subject: [PATCH 10/23] Updated changelog --- changelog.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index 0a5aed1..9fd8d53 100644 --- a/changelog.md +++ b/changelog.md @@ -1,12 +1,12 @@ ## grblHAL changelog -Build 20240719 +Build 20240719 Core: * Limited tool change probe moves to be within machine limits. Ref. [issue #542](https://github.com/grblHAL/core/issues/542). -* Added setting `$358` to enable experimental functionality for fast rotary 'rewind' to stored G28 position. Return move should complete in half a rotation or less. +* Added setting `$538` to enable experimental functionality for fast rotary 'rewind' to stored G28 position. Return move should complete in half a rotation or less. To use program: ``` G91G280 From d2c476deaf3df13b3e257c9e27d99748e334a1bc Mon Sep 17 00:00:00 2001 From: Terje Io Date: Thu, 1 Aug 2024 19:24:00 +0200 Subject: [PATCH 11/23] Added option bit for enabling realtime reporting while homing to $10, Status report options. Ref. issue #551. --- changelog.md | 15 ++++++++++++ config.h | 10 ++++++++ grbl.h | 2 +- machine_limits.c | 64 +++++++++++++++++++++++++++--------------------- motion_control.c | 6 +++-- settings.c | 5 ++-- settings.h | 5 ++-- stream.c | 6 +++-- 8 files changed, 76 insertions(+), 37 deletions(-) diff --git a/changelog.md b/changelog.md index 9fd8d53..cae8d7c 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,20 @@ ## grblHAL changelog +Build 20240801 + +Core: + +* Added option bit for enabling realtime reporting while homing to `$10`, _Status report options_. Ref. [issue #551](https://github.com/grblHAL/core/issues/551). +__NOTE:__ Enabling this may affect some senders. + +Drivers: + +* iMXRT1062, LPC176x, SAM3X8E and STM32F1xx: moved board maps/board specific code to new _boards_ directory. + +* STM32F4xx: fixed regression in SD card code affecting boards using SDIO interface. + +--- + Build 20240719 Core: diff --git a/config.h b/config.h index 4f269ce..dc53aa7 100644 --- a/config.h +++ b/config.h @@ -696,6 +696,16 @@ The following codes are defined: #define DEFAULT_REPORT_RUN_SUBSTATE Off // Default off. Set to \ref On or 1 to enable. #endif +/*! \def DEFAULT_REPORT_WHEN_HOMING +\brief +Enabling this setting enables status reporting while homing. +
__NOTE:__ Enabling this option may break senders. +\internal Bit 12 in settings.status_report. +*/ +#if !defined DEFAULT_REPORT_WHEN_HOMING || defined __DOXYGEN__ +#define DEFAULT_REPORT_WHEN_HOMING Off // Default off. Set to \ref On or 1 to enable. +#endif + ///@} /*! @name $11 - Setting_JunctionDeviation diff --git a/grbl.h b/grbl.h index cfe386f..862dbb0 100644 --- a/grbl.h +++ b/grbl.h @@ -42,7 +42,7 @@ #else #define GRBL_VERSION "1.1f" #endif -#define GRBL_BUILD 20240719 +#define GRBL_BUILD 20240801 #define GRBL_URL "https://github.com/grblHAL" diff --git a/machine_limits.c b/machine_limits.c index 659c004..4231d59 100644 --- a/machine_limits.c +++ b/machine_limits.c @@ -273,6 +273,7 @@ static bool homing_cycle (axes_signals_t cycle, axes_signals_t auto_square) squaring_mode_t squaring_mode = SquaringMode_Both; coord_data_t target; plan_line_data_t plan_data; + rt_exec_t rt_exec, rt_exec_states = EXEC_SAFETY_DOOR|EXEC_RESET|EXEC_CYCLE_COMPLETE; plan_data_init(&plan_data); plan_data.condition.system_motion = On; @@ -320,6 +321,9 @@ static bool homing_cycle (axes_signals_t cycle, axes_signals_t auto_square) autosquare_fail_distance = truncf(fail_distance * settings.axis[dual_motor_axis].steps_per_mm); } + if(settings.status_report.when_homing) + rt_exec_states |= EXEC_STATUS_REPORT; + // Set search mode with approach at seek rate to quickly engage the specified cycle.mask limit switches. do { @@ -420,36 +424,40 @@ static bool homing_cycle (axes_signals_t cycle, axes_signals_t auto_square) st_prep_buffer(); // Check and prep segment buffer. // Exit routines: No time to run protocol_execute_realtime() in this loop. - if (sys.rt_exec_state & (EXEC_SAFETY_DOOR | EXEC_RESET | EXEC_CYCLE_COMPLETE)) { + if((rt_exec = (sys.rt_exec_state & rt_exec_states))) { - uint_fast16_t rt_exec = sys.rt_exec_state; - - // Homing failure condition: Reset issued during cycle. - if (rt_exec & EXEC_RESET) - system_set_exec_alarm(Alarm_HomingFailReset); - - // Homing failure condition: Safety door was opened. - if (rt_exec & EXEC_SAFETY_DOOR) - system_set_exec_alarm(Alarm_HomingFailDoor); - - hal.delay_ms(2, NULL); - - // Homing failure condition: Homing switch(es) still engaged after pull-off motion - if (mode == HomingMode_Pulloff && (homing_signals_select(hal.homing.get_state(), (axes_signals_t){0}, SquaringMode_Both).mask & cycle.mask)) - system_set_exec_alarm(Alarm_FailPulloff); - - // Homing failure condition: Limit switch not found during approach. - if (mode != HomingMode_Pulloff && (rt_exec & EXEC_CYCLE_COMPLETE)) - system_set_exec_alarm(Alarm_HomingFailApproach); - - if (sys.rt_exec_alarm) { - mc_reset(); // Stop motors, if they are running. - protocol_execute_realtime(); - return false; + if(rt_exec == EXEC_STATUS_REPORT) { + system_clear_exec_state_flag(EXEC_STATUS_REPORT); + report_realtime_status(); } else { - // Pull-off motion complete. Disable CYCLE_STOP from executing. - system_clear_exec_state_flag(EXEC_CYCLE_COMPLETE); - break; + + // Homing failure condition: Reset issued during cycle. + if (rt_exec & EXEC_RESET) + system_set_exec_alarm(Alarm_HomingFailReset); + + // Homing failure condition: Safety door was opened. + if (rt_exec & EXEC_SAFETY_DOOR) + system_set_exec_alarm(Alarm_HomingFailDoor); + + hal.delay_ms(2, NULL); + + // Homing failure condition: Homing switch(es) still engaged after pull-off motion + if (mode == HomingMode_Pulloff && (homing_signals_select(hal.homing.get_state(), (axes_signals_t){0}, SquaringMode_Both).mask & cycle.mask)) + system_set_exec_alarm(Alarm_FailPulloff); + + // Homing failure condition: Limit switch not found during approach. + if (mode != HomingMode_Pulloff && (rt_exec & EXEC_CYCLE_COMPLETE)) + system_set_exec_alarm(Alarm_HomingFailApproach); + + if (sys.rt_exec_alarm) { + mc_reset(); // Stop motors, if they are running. + protocol_execute_realtime(); + return false; + } else { + // Pull-off motion complete. Disable CYCLE_STOP from executing. + system_clear_exec_state_flag(EXEC_CYCLE_COMPLETE); + break; + } } } diff --git a/motion_control.c b/motion_control.c index fdd4e0d..0d7c6be 100644 --- a/motion_control.c +++ b/motion_control.c @@ -874,8 +874,10 @@ status_code_t mc_homing_cycle (axes_signals_t cycle) state_set(STATE_HOMING); // Set homing system state. #if COMPATIBILITY_LEVEL == 0 - system_set_exec_state_flag(EXEC_STATUS_REPORT); // Force a status report and - delay_sec(0.1f, DelayMode_Dwell); // delay a bit to get it sent (or perhaps wait a bit for a request?) + if(!settings.status_report.when_homing) { + system_set_exec_state_flag(EXEC_STATUS_REPORT); // Force a status report and + delay_sec(0.1f, DelayMode_Dwell); // delay a bit to get it sent (or perhaps wait a bit for a request?) + } #endif // Turn off spindle and coolant (and update parser state) if(spindle_is_on()) diff --git a/settings.c b/settings.c index c536406..4bcae74 100644 --- a/settings.c +++ b/settings.c @@ -144,6 +144,7 @@ PROGMEM const settings_t defaults = { .status_report.parser_state = DEFAULT_REPORT_PARSER_STATE, .status_report.alarm_substate = DEFAULT_REPORT_ALARM_SUBSTATE, .status_report.run_substate = DEFAULT_REPORT_RUN_SUBSTATE, + .status_report.when_homing = DEFAULT_REPORT_WHEN_HOMING, .limits.flags.hard_enabled = DEFAULT_HARD_LIMIT_ENABLE, .limits.flags.soft_enabled = DEFAULT_SOFT_LIMIT_ENABLE, .limits.flags.jog_soft_limited = DEFAULT_JOG_LIMIT_ENABLE, @@ -490,7 +491,7 @@ PROGMEM static const setting_detail_t setting_detail[] = { { Setting_GangedDirInvertMask, Group_Stepper, "Ganged axes direction invert", NULL, Format_Bitfield, ganged_axes, NULL, NULL, Setting_IsExtendedFn, set_ganged_dir_invert, get_int, is_setting_available }, { Setting_SpindlePWMOptions, Group_Spindle, "PWM Spindle", NULL, Format_XBitfield, "Enable,RPM controls spindle enable signal,Disable laser mode capability", NULL, NULL, Setting_IsExtendedFn, set_pwm_options, get_int, is_setting_available }, #if COMPATIBILITY_LEVEL <= 1 - { Setting_StatusReportMask, Group_General, "Status report options", NULL, Format_Bitfield, "Position in machine coordinate,Buffer state,Line numbers,Feed & speed,Pin state,Work coordinate offset,Overrides,Probe coordinates,Buffer sync on WCO change,Parser state,Alarm substatus,Run substatus", NULL, NULL, Setting_IsExtendedFn, set_report_mask, get_int, NULL }, + { Setting_StatusReportMask, Group_General, "Status report options", NULL, Format_Bitfield, "Position in machine coordinate,Buffer state,Line numbers,Feed & speed,Pin state,Work coordinate offset,Overrides,Probe coordinates,Buffer sync on WCO change,Parser state,Alarm substatus,Run substatus,Enable when homing", NULL, NULL, Setting_IsExtendedFn, set_report_mask, get_int, NULL }, #else { Setting_StatusReportMask, Group_General, "Status report options", NULL, Format_Bitfield, "Position in machine coordinate,Buffer state", NULL, NULL, Setting_IsLegacyFn, set_report_mask, get_int, NULL }, #endif @@ -661,7 +662,7 @@ PROGMEM static const setting_descr_t setting_descr[] = { { Setting_GangedDirInvertMask, "Inverts the direction signals for the second motor used for ganged axes.\\n\\n" "NOTE: This inversion will be applied in addition to the inversion from setting $3." }, - { Setting_StatusReportMask, "Specifies optional data included in status reports.\\n" + { Setting_StatusReportMask, "Specifies optional data included in status reports and if report is sent when homing.\\n" "If Run substatus is enabled it may be used for simple probe protection.\\n\\n" "NOTE: Parser state will be sent separately after the status report and only on changes." }, diff --git a/settings.h b/settings.h index 4192492..8f67ad6 100644 --- a/settings.h +++ b/settings.h @@ -3,7 +3,7 @@ Part of grblHAL - Copyright (c) 2017-2023 Terje Io + Copyright (c) 2017-2024 Terje Io Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC Copyright (c) 2009-2011 Simen Svale Skogsrud @@ -565,7 +565,8 @@ typedef union { parser_state :1, alarm_substate :1, run_substate :1, - unassigned :4; + when_homing :1, + unassigned :3; }; } reportmask_t; diff --git a/stream.c b/stream.c index ad2d921..96faf70 100644 --- a/stream.c +++ b/stream.c @@ -761,8 +761,10 @@ void debug_printf (const char *fmt, ...) if(hal.stream.write) { report_message(debug_out, Message_Debug); - while(hal.stream.get_tx_buffer_count()) // Wait until message is delivered - grbl.on_execute_realtime(state_get()); + if(hal.stream.get_tx_buffer_count) { + while(hal.stream.get_tx_buffer_count()) // Wait until message is delivered + grbl.on_execute_realtime(state_get()); + } } } From 277fb75b31f829cdee369fad0b5ab16747a38340 Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 4 Aug 2024 18:15:12 +0200 Subject: [PATCH 12/23] Update motion_control.c Bugfix mc_arc multi turns clockwise --- motion_control.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/motion_control.c b/motion_control.c index 0d7c6be..9184ce2 100644 --- a/motion_control.c +++ b/motion_control.c @@ -247,7 +247,9 @@ void mc_arc (float *target, plan_line_data_t *pl_data, float *position, float *o if(labs(turns) > 1) { uint32_t n_turns = labs(turns) - 1; - float arc_travel = 2.0f * M_PI * n_turns + angular_travel; + float arc_travel = 2.0f * M_PI * n_turns - angular_travel; + if (turns > 0) + arc_travel = 2.0f * M_PI * n_turns + angular_travel; coord_data_t arc_target; #if N_AXIS > 3 uint_fast8_t idx = N_AXIS; From 4e73d9f211a774148956a82cf3c4c0a4c93ee350 Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 5 Aug 2024 20:53:44 +0200 Subject: [PATCH 13/23] Update motion_control.c changed to ternary --- motion_control.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/motion_control.c b/motion_control.c index 9184ce2..29bbe45 100644 --- a/motion_control.c +++ b/motion_control.c @@ -247,9 +247,7 @@ void mc_arc (float *target, plan_line_data_t *pl_data, float *position, float *o if(labs(turns) > 1) { uint32_t n_turns = labs(turns) - 1; - float arc_travel = 2.0f * M_PI * n_turns - angular_travel; - if (turns > 0) - arc_travel = 2.0f * M_PI * n_turns + angular_travel; + float arc_travel = 2.0f * M_PI * (float)n_turns + (turns > 0 ? angular_travel : -angular_travel); coord_data_t arc_target; #if N_AXIS > 3 uint_fast8_t idx = N_AXIS; From 7ade244a78469828ea054fc880d0eabc03aaa126 Mon Sep 17 00:00:00 2001 From: Terje Io Date: Mon, 12 Aug 2024 15:46:58 +0200 Subject: [PATCH 14/23] Improved handling of extended M commands (plugin based) command words. Fixes issues for programs containing extended M-codes using single meaning words (which they as a rule should not do). Added core support for spindle encoder binding to spindles. Added sorting of spindle report: enabled spindles are sorted first in order of spindle number, disabled by type then spindle id. Changed realtime report to report spindle number instead of spindle id on changes in the |S: element. --- changelog.md | 35 ++++++++++++++++++ gcode.c | 49 ++++++++++++++---------- grbl.h | 2 +- modbus.h | 2 +- report.c | 71 +++++++++++++++++++++++++++++++++-- report.h | 2 + spindle_control.c | 94 ++++++++++++++++++++++++++++++----------------- spindle_control.h | 20 ++++++++-- stepper2.c | 9 +++++ stepper2.h | 1 + 10 files changed, 224 insertions(+), 61 deletions(-) diff --git a/changelog.md b/changelog.md index cae8d7c..75d1785 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,40 @@ ## grblHAL changelog +
Build 20240812 + +Core: + +* Improved handling of extended M commands \(plugin based\) command words. Fixes issues for programs containing extended M-codes using single meaning words \(which they as a rule should not do\). + +* Added core support for spindle encoder binding to spindles. + +* Added sorting of spindle report: enabled spindles are sorted first in order of spindle number, disabled by type then spindle id. + +* Changed realtime report to report spindle number instead of spindle id on changes in the `|S:` element. Part of fix for ioSender [issue #399](https://github.com/terjeio/ioSender/issues/399). + +Drivers: + +* imXRT1061, MSP432, STM32F4xx, STM32F7xx: Updated to take advandage of new spindle encoder binding functionality. + +Plugins: + +* Spindle: updated relevant drivers to use new spindle encoder binding functionality, simplified code. Fixes [issue #30](https://github.com/grblHAL/Plugins_spindle/issues/30). + +--- + +Build 20240805 + +Core: + +* Added function for getting speed \(RPM\) of stepper controlled by secondary stepper motor driver. + +Plugins: + +* Spindle: stepper spindle code now uses new function for getting speed \(RPM\) of motor. +HAL functions for getting spindle data \(actual RPM, angular position etc.\) directed to stepper spindle code, + +--- + Build 20240801 Core: diff --git a/gcode.c b/gcode.c index 6ac12ec..01d21b2 100644 --- a/gcode.c +++ b/gcode.c @@ -848,7 +848,7 @@ status_code_t gc_execute_block (char *block) // Initialize command and value words and parser flags variables. modal_groups_t command_words = {0}; // Bitfield for tracking G and M command words. Also used for modal group violations. gc_parser_flags_t gc_parser_flags = {0}; // Parser flags for handling special cases. - static parameter_words_t user_words = {0}; // User M-code words "taken" + parameter_words_t user_words = {0}; // User M-code words "taken" // Determine if the line is a jogging motion or a normal g-code block. if (block[0] == '$') { // NOTE: `$J=` already parsed when passed to this function. @@ -1680,6 +1680,24 @@ status_code_t gc_execute_block (char *block) // same way. If there is an explicit/implicit axis command, XYZ words are always used and are // are removed at the end of error-checking. + // [0. User defined M commands ]: + if(command_words.M10 && gc_block.user_mcode) { + + user_words.mask = gc_block.words.mask; + if((int_value = (uint_fast16_t)hal.user_mcode.validate(&gc_block, &gc_block.words))) + FAIL((status_code_t)int_value); + user_words.mask ^= gc_block.words.mask; // Flag "taken" words for execution + + if(user_words.i) + ijk_words.i = Off; + if(user_words.j) + ijk_words.j = Off; + if(user_words.k) + ijk_words.k = Off; + + axis_words.mask = 0; + } + // [1. Comments ]: MSG's may be supported by driver layer. Comment handling performed by protocol. // [2. Set feed rate mode ]: G93 F word missing with G1,G2/3 active, implicitly or explicitly. Feed rate @@ -1736,7 +1754,7 @@ status_code_t gc_execute_block (char *block) // [4. Set spindle speed and address spindle ]: S or D is negative (done.) if(gc_block.words.$) { - bool single_spindle_only = (gc_block.words.s && !user_words.s) || + bool single_spindle_only = gc_block.words.s || (command_words.G0 && (gc_block.modal.motion == MotionMode_SpindleSynchronized || gc_block.modal.motion == MotionMode_RigidTapping || gc_block.modal.motion == MotionMode_Threading)) || @@ -1779,11 +1797,11 @@ status_code_t gc_execute_block (char *block) gc_state.modal.spindle.rpm_mode = gc_block.modal.spindle.rpm_mode; } - spindle_event = gc_block.words.s && !user_words.s; + spindle_event = gc_block.words.s; - if (!gc_block.words.s) + if(!gc_block.words.s) gc_block.values.s = gc_state.modal.spindle.rpm_mode == SpindleSpeedMode_RPM ? gc_state.spindle.rpm : gc_state.spindle.hal->param->css.max_rpm; - else if(!user_words.s && gc_state.modal.spindle.rpm_mode == SpindleSpeedMode_CSS) { + else if(gc_state.modal.spindle.rpm_mode == SpindleSpeedMode_CSS) { // Unsure what to do about S values when in SpindleSpeedMode_CSS - ignore? For now use it to (re)calculate surface speed. // Reinsert commented out code above if this is removed!! gc_block.values.s *= (gc_block.modal.units_imperial ? MM_PER_INCH * 12.0f : 1000.0f); // convert surface speed to mm/min @@ -1796,9 +1814,9 @@ status_code_t gc_execute_block (char *block) if(set_tool) { // M61 if(!gc_block.words.q) FAIL(Status_GcodeValueWordMissing); - if (floorf(gc_block.values.q) - gc_block.values.q != 0.0f) + if(!isintf(gc_block.values.q)) FAIL(Status_GcodeCommandValueNotInteger); - if ((uint32_t)gc_block.values.q > (grbl.tool_table.n_tools ? grbl.tool_table.n_tools : MAX_TOOL_NUMBER)) + if((uint32_t)gc_block.values.q > (grbl.tool_table.n_tools ? grbl.tool_table.n_tools : MAX_TOOL_NUMBER)) FAIL(Status_GcodeIllegalToolTableEntry); gc_block.values.t = (uint32_t)gc_block.values.q; @@ -1815,7 +1833,7 @@ status_code_t gc_execute_block (char *block) } } #endif - } else if (!gc_block.words.t) + } else if(!gc_block.words.t) gc_block.values.t = gc_state.tool_pending; if(command_words.M10 && port_command) { @@ -1952,15 +1970,6 @@ status_code_t gc_execute_block (char *block) } } - // [9a. User defined M commands ]: - if (command_words.M10 && gc_block.user_mcode) { - user_words.mask = gc_block.words.mask; - if((int_value = (uint_fast16_t)hal.user_mcode.validate(&gc_block, &gc_block.words))) - FAIL((status_code_t)int_value); - user_words.mask ^= gc_block.words.mask; // Flag "taken" words for execution - axis_words.mask = ijk_words.mask = 0; - } - // [10. Dwell ]: P value missing. NOTE: See below. if (gc_block.non_modal_command == NonModal_Dwell) { if (!gc_block.words.p) @@ -3071,7 +3080,7 @@ status_code_t gc_execute_block (char *block) } } - if(!user_words.s && ((gc_state.spindle.rpm != gc_block.values.s) || gc_parser_flags.spindle_force_sync)) { + if(gc_state.spindle.rpm != gc_block.values.s || gc_parser_flags.spindle_force_sync) { if(gc_state.modal.spindle.state.on && !gc_parser_flags.laser_is_motion) { if(gc_block.spindle) { gc_block.spindle->param->rpm = gc_block.values.s; @@ -3215,7 +3224,7 @@ status_code_t gc_execute_block (char *block) bool spindle_ok = false; if(gc_block.spindle) { if(grbl.on_spindle_programmed) - grbl.on_spindle_programmed(gc_block.spindle, gc_block.modal.spindle.state, plan_data.spindle.rpm, gc_block.modal.spindle.rpm_mode); + grbl.on_spindle_programmed(gc_block.spindle, gc_block.modal.spindle.state, plan_data.spindle.rpm, gc_block.modal.spindle.rpm_mode); if((spindle_ok = spindle_sync(gc_block.spindle, gc_block.modal.spindle.state, plan_data.spindle.rpm))) gc_block.spindle->param->state = gc_block.modal.spindle.state; } else { @@ -3224,7 +3233,7 @@ status_code_t gc_execute_block (char *block) if(spindle_is_enabled(--idx)) { spindle_ptrs_t *spindle = spindle_get(idx); if(grbl.on_spindle_programmed) - grbl.on_spindle_programmed(spindle, gc_block.modal.spindle.state, plan_data.spindle.rpm, gc_block.modal.spindle.rpm_mode); + grbl.on_spindle_programmed(spindle, gc_block.modal.spindle.state, plan_data.spindle.rpm, gc_block.modal.spindle.rpm_mode); if(spindle_sync(spindle, gc_block.modal.spindle.state, plan_data.spindle.rpm)) spindle->param->state = gc_block.modal.spindle.state; else diff --git a/grbl.h b/grbl.h index 862dbb0..e4353db 100644 --- a/grbl.h +++ b/grbl.h @@ -42,7 +42,7 @@ #else #define GRBL_VERSION "1.1f" #endif -#define GRBL_BUILD 20240801 +#define GRBL_BUILD 20240812 #define GRBL_URL "https://github.com/grblHAL" diff --git a/modbus.h b/modbus.h index c48a538..9368391 100644 --- a/modbus.h +++ b/modbus.h @@ -25,7 +25,7 @@ #define _MODBUS_H_ #ifndef MODBUS_MAX_ADU_SIZE -#define MODBUS_MAX_ADU_SIZE 10 +#define MODBUS_MAX_ADU_SIZE 12 #endif #ifndef MODBUS_QUEUE_LENGTH #define MODBUS_QUEUE_LENGTH 8 diff --git a/report.c b/report.c index 7a513fc..46e0805 100644 --- a/report.c +++ b/report.c @@ -333,6 +333,16 @@ static void report_help_message (void) hal.stream.write("[HLP:$$ $# $G $I $N $x=val $Nx=line $J=line $SLP $C $X $H $B ~ ! ? ctrl-x]" ASCII_EOL); } +// Prints plugin info. +void report_plugin (const char *name, const char *version) +{ + hal.stream.write("[PLUGIN:"); + hal.stream.write(name); + hal.stream.write(" v"); + hal.stream.write(version); + hal.stream.write("]" ASCII_EOL); +} + static bool report_group_settings (const setting_group_detail_t *groups, const uint_fast8_t n_groups, char *args) { bool found = false; @@ -1088,7 +1098,6 @@ void report_build_info (char *line, bool extended) } } - // Prints the character string line grblHAL has received from the user, which has been pre-parsed, // and has been sent into protocol_execute_line() routine to be executed by grblHAL. void report_echo_line_received (char *line) @@ -1098,6 +1107,15 @@ void report_echo_line_received (char *line) hal.stream.write("]" ASCII_EOL); } +#if N_SYS_SPINDLE == 1 && N_SPINDLE > 1 + +static void report_spindle_num (spindle_info_t *spindle, void *data) +{ + if(spindle->id == *((spindle_id_t *)data)) + hal.stream.write_all(appendbuf(2, "|S:", uitoa((uint32_t)spindle->num))); +} + +#endif // Prints real-time data. This function grabs a real-time snapshot of the stepper subprogram // and the actual location of the CNC machine. Users may change the following function to their @@ -1246,7 +1264,7 @@ void report_realtime_status (void) #elif N_SPINDLE > 1 if(report.spindle_id) - hal.stream.write_all(appendbuf(2, "|S:", uitoa((uint32_t)spindle_0->id))); + spindle_enumerate_spindles(report_spindle_num, &spindle_0->id); #endif if(settings.status_report.pin_state) { @@ -2516,9 +2534,56 @@ static void report_spindle (spindle_info_t *spindle, void *data) } } +#if N_SPINDLE > 1 + +typedef struct { + uint32_t idx; + uint32_t n_spindles; + spindle_info_t *spindles; +} spindle_rdata_t; + +static void get_spindles (spindle_info_t *spindle, void *data) +{ + memcpy(&((spindle_rdata_t *)data)->spindles[((spindle_rdata_t *)data)->idx++], spindle, sizeof(spindle_info_t)); +} + +static int cmp_spindles (const void *a, const void *b) +{ + uint32_t key_a = ((spindle_info_t *)a)->num == -1 ? ((((spindle_info_t *)a)->hal->type + 1) << 8) | ((spindle_info_t *)a)->id : ((spindle_info_t *)a)->num, + key_b = ((spindle_info_t *)b)->num == -1 ? ((((spindle_info_t *)b)->hal->type + 1) << 8) | ((spindle_info_t *)b)->id : ((spindle_info_t *)b)->num; + + return key_a - key_b; +} + +#endif + status_code_t report_spindles (bool machine_readable) { - if(!spindle_enumerate_spindles(report_spindle, (void *)machine_readable) && !machine_readable) + bool has_spindles; + +#if N_SPINDLE > 1 + + spindle_rdata_t spindle_data = {0}; + + if((spindle_data.spindles = malloc(N_SPINDLE * sizeof(spindle_info_t)))) { + + has_spindles = spindle_enumerate_spindles(get_spindles, &spindle_data); + + spindle_data.n_spindles = spindle_data.idx; + + qsort(spindle_data.spindles, spindle_data.n_spindles, sizeof(spindle_info_t), cmp_spindles); + for(spindle_data.idx = 0; spindle_data.idx < spindle_data.n_spindles; spindle_data.idx++) + report_spindle(&spindle_data.spindles[spindle_data.idx], (void *)machine_readable); + + free(spindle_data.spindles); + + } else + +#endif + + has_spindles = spindle_enumerate_spindles(report_spindle, (void *)machine_readable); + + if(!has_spindles && !machine_readable) hal.stream.write("No spindles registered." ASCII_EOL); return Status_OK; diff --git a/report.h b/report.h index b5b1b3a..1a7d99f 100644 --- a/report.h +++ b/report.h @@ -52,6 +52,8 @@ void report_warning (void *message); // Prints Grbl help. status_code_t report_help (char *args); +void report_plugin (const char *name, const char *version); + // Prints Grbl settings void report_grbl_settings (bool all, void *data); diff --git a/spindle_control.c b/spindle_control.c index 769c4f1..d2d19ec 100644 --- a/spindle_control.c +++ b/spindle_control.c @@ -51,6 +51,7 @@ typedef struct { static uint8_t n_spindle = 0; static spindle_sys_t sys_spindle[N_SYS_SPINDLE] = {0}; static spindle_reg_t spindles[N_SPINDLE] = {0}, *pwm_spindle = NULL; +static const spindle_data_ptrs_t *encoder; /*! \internal \brief Activates and registers a spindle as enabled with a specific spindle number. \param spindle_id spindle id of spindle to activate as a \ref spindle_id_t. @@ -96,20 +97,6 @@ static bool spindle_activate (spindle_id_t spindle_id, spindle_num_t spindle_num memcpy(&spindle_hal, &spindle->hal, sizeof(spindle_ptrs_t)); - if(spindle->cfg->get_data == NULL) { - if(settings.offset_lock.encoder_spindle == spindle_id) { - spindle_hal.get_data = hal.spindle_data.get; - spindle_hal.reset_data = hal.spindle_data.reset; - if(!spindle->cfg->cap.at_speed) - spindle_hal.cap.at_speed = !!spindle_hal.get_data; - } else { - spindle_hal.get_data = NULL; - spindle_hal.reset_data = NULL; - if(!spindle->cfg->cap.at_speed) - spindle_hal.cap.at_speed = Off; - } - } - spindle_hal.cap.laser &= settings.mode == Mode_Laser; if(grbl.on_spindle_select) @@ -305,22 +292,68 @@ uint8_t spindle_get_count (void) static spindle_num_t spindle_get_num (spindle_id_t spindle_id) { - uint_fast8_t idx = N_SPINDLE_SELECTABLE; - spindle_num_t spindle_num = -1; + spindle_num_t spindle_num; - const setting_detail_t *setting; + if((spindle_num = spindle_get_count() == 1 ? 0 : -1) == -1) { - do { - idx--; - if((setting = setting_get_details(idx == 0 ? Setting_SpindleType : (setting_id_t)(Setting_SpindleEnable0 + idx), NULL))) { - if(setting_get_int_value(setting, 0) == spindle_id) - spindle_num = idx; - } - } while(idx && spindle_num == -1); + const setting_detail_t *setting; + uint_fast8_t idx = N_SPINDLE_SELECTABLE; + + do { + idx--; + if((setting = setting_get_details(idx == 0 ? Setting_SpindleType : (setting_id_t)(Setting_SpindleEnable0 + idx), NULL))) { + if(setting_get_int_value(setting, 0) == spindle_id) + spindle_num = idx; + } + } while(idx && spindle_num == -1); + } return spindle_num; } +void spindle_bind_encoder (const spindle_data_ptrs_t *encoder_data) +{ + uint_fast8_t idx; + spindle_ptrs_t *spindle; + spindle_num_t spindle_num; + + encoder = encoder_data; + + for(idx = 0; idx < n_spindle; idx++) { + + spindle = spindle_get((spindle_num = spindle_get_num(idx))); + + if(encoder_data && spindle_num == settings.offset_lock.encoder_spindle) { + spindles[idx].hal.get_data = encoder_data->get; + spindles[idx].hal.reset_data = encoder_data->reset; + spindles[idx].hal.cap.at_speed = spindles[idx].hal.cap.variable; + } else { + spindles[idx].hal.get_data = spindles[idx].cfg->get_data; + spindles[idx].hal.reset_data = spindles[idx].cfg->reset_data; + spindles[idx].hal.cap.at_speed = spindles[idx].cfg->cap.at_speed; + } + + if(spindle) { + spindle->get_data = spindles[idx].hal.get_data; + spindle->reset_data = spindles[idx].hal.reset_data; + spindle->cap.at_speed = spindles[idx].hal.cap.at_speed; + } + } +} + +bool spindle_set_at_speed_range (spindle_ptrs_t *spindle, spindle_data_t *spindle_data, float rpm) +{ + spindle_data->rpm_programmed = rpm; + spindle_data->state_programmed.at_speed = false; + + if((spindle_data->at_speed_enabled = spindle->at_speed_tolerance > 0.0f)) { + spindle_data->rpm_low_limit = rpm * (1.0f - (spindle->at_speed_tolerance / 100.0f)); + spindle_data->rpm_high_limit = rpm * (1.0f + (spindle->at_speed_tolerance / 100.0f)); + } + + return spindle_data->at_speed_enabled; +} + /*! \brief Enumerate registered spindles by calling a callback function for each of them. \param callback pointer to a \ref spindle_enumerate_callback_ptr type function. \param data pointer to optional data to pass to the callback function. @@ -555,7 +588,7 @@ bool spindle_sync (spindle_ptrs_t *spindle, spindle_state_t state, float rpm) if (!(ok = state_get() == STATE_CHECK_MODE)) { - bool at_speed = !state.on || !spindle->cap.at_speed || settings.spindle.at_speed_tolerance <= 0.0f; + bool at_speed = !state.on || !spindle->cap.at_speed || spindle->at_speed_tolerance <= 0.0f; // Empty planner buffer to ensure spindle is set when programmed. if((ok = protocol_buffer_synchronize()) && set_state(spindle, state, rpm) && !at_speed) { @@ -595,7 +628,7 @@ bool spindle_restore (spindle_ptrs_t *spindle, spindle_state_t state, float rpm) if(state.on) { if((ok = !spindle->cap.at_speed)) ok = delay_sec(settings.safety_door.spindle_on_delay, DelayMode_SysSuspend); - else if((ok == (settings.spindle.at_speed_tolerance <= 0.0f))) { + else if((ok == (spindle->at_speed_tolerance <= 0.0f))) { float delay = 0.0f; while(!(ok = spindle->get_state(spindle).at_speed)) { if(!(ok = delay_sec(0.1f, DelayMode_SysSuspend))) @@ -624,13 +657,7 @@ float spindle_set_rpm (spindle_ptrs_t *spindle, float rpm, override_t override_p if(override_pct != 100) rpm *= 0.01f * (float)override_pct; // Scale RPM by override value. - // Apply RPM limits - if (rpm <= 0.0f) // TODO: remove this test? - rpm = 0.0f; - else if (rpm > spindle->rpm_max) - rpm = spindle->rpm_max; - else if (rpm < spindle->rpm_min) - rpm = spindle->rpm_min; + rpm = rpm <= 0.0f ? 0.0f : constrain(rpm, spindle->rpm_min, spindle->rpm_max); spindle->param->rpm_overridden = rpm; spindle->param->override_pct = override_pct; @@ -756,6 +783,7 @@ bool spindle_precompute_pwm_values (spindle_ptrs_t *spindle, spindle_pwm_t *pwm_ pwm_data->settings = settings; spindle->rpm_min = pwm_data->rpm_min = settings->rpm_min; spindle->rpm_max = settings->rpm_max; + spindle->at_speed_tolerance = settings->at_speed_tolerance; spindle->cap.rpm_range_locked = On; if((spindle->cap.variable = !settings->flags.pwm_disable && spindle->rpm_max > spindle->rpm_min)) { diff --git a/spindle_control.h b/spindle_control.h index 889a9e8..471762e 100644 --- a/spindle_control.h +++ b/spindle_control.h @@ -98,6 +98,7 @@ typedef struct { uint32_t index_count; uint32_t pulse_count; uint32_t error_count; + bool at_speed_enabled; spindle_state_t state_programmed; } spindle_data_t; @@ -208,14 +209,14 @@ typedef struct { float rpm_max; float rpm_min; float pwm_freq; - float pwm_period; // currently unused + float pwm_period; // currently unused float pwm_off_value; float pwm_min_value; float pwm_max_value; - float at_speed_tolerance; + float at_speed_tolerance; //!< Tolerance in percent of programmed speed. pwm_piece_t pwm_piece[SPINDLE_NPWM_PIECES]; pid_values_t pid; - uint16_t ppr; // Spindle encoder pulses per revolution + uint16_t ppr; //!< Spindle encoder pulses per revolution (PPR). spindle_state_t invert; spindle_settings_flags_t flags; } spindle_settings_t; @@ -273,6 +274,7 @@ struct spindle_ptrs { uint_fast16_t pwm_off_value; //!< Value for switching PWM signal off. float rpm_min; //!< Minimum spindle RPM. float rpm_max; //!< Maximum spindle RPM. + float at_speed_tolerance; //!< Tolerance in percent of programmed speed. spindle_config_ptr config; //!< 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. @@ -350,6 +352,15 @@ void spindle_all_off (void); // The following functions are not called by the core, may be called by driver code. // +#define spindle_validate_at_speed(d, r) { d.rpm = r; d.state_programmed.at_speed = !d.at_speed_enabled || (d.rpm >= d.rpm_low_limit && d.rpm <= d.rpm_high_limit); } +/* +__attribute__((always_inline)) static inline void spindle_validate_at_speed (spindle_data_t *spindle_data, float rpm) +{ + spindle_data->rpm = rpm; + spindle_data->state_programmed.at_speed = !spindle_data->at_speed_enabled || (spindle_data->rpm >= spindle_data->rpm_low_limit && spindle_data->rpm <= spindle_data->rpm_high_limit); +} +*/ + bool spindle_precompute_pwm_values (spindle_ptrs_t *spindle, spindle_pwm_t *pwm_data, spindle_settings_t *settings, uint32_t clock_hz); spindle_id_t spindle_register (const spindle_ptrs_t *spindle, const char *name); @@ -364,6 +375,9 @@ spindle_cap_t spindle_get_caps (bool active); void spindle_update_caps (spindle_ptrs_t *spindle, spindle_pwm_t *pwm_caps); +void spindle_bind_encoder (const spindle_data_ptrs_t *encoder_data); + +bool spindle_set_at_speed_range (spindle_ptrs_t *spindle, spindle_data_t *spindle_data, float rpm); spindle_ptrs_t *spindle_get_hal (spindle_id_t spindle_id, spindle_hal_t hal); diff --git a/stepper2.c b/stepper2.c index 894b60b..ea2c082 100644 --- a/stepper2.c +++ b/stepper2.c @@ -272,6 +272,15 @@ st2_motor_t *st2_motor_init (uint_fast8_t axis_idx, bool is_spindle) return motor; } +/*! \brief Get current speed (RPM). +\param motor pointer to a \a st2_motor structure. +\returns current speed in RPM. +*/ +float st2_get_speed (st2_motor_t *motor) +{ + return motor->state == State_Idle ? 0.0f : 60.0f / ((float)motor->delay * settings.axis[motor->idx].steps_per_mm / 1000000.0f); +} + /*! \brief Set speed. Change speed of a running motor. Typically used for motors bound as a spindle. diff --git a/stepper2.h b/stepper2.h index 8f3dc01..d5984ca 100644 --- a/stepper2.h +++ b/stepper2.h @@ -33,6 +33,7 @@ typedef struct st2_motor st2_motor_t; st2_motor_t *st2_motor_init (uint_fast8_t axis_idx, bool is_spindle); bool st2_motor_bind_spindle (uint_fast8_t axis_idx); +float st2_get_speed (st2_motor_t *motor); float st2_motor_set_speed (st2_motor_t *motor, float speed); bool st2_motor_move (st2_motor_t *motor, const float move, const float speed, position_t type); bool st2_motor_run (st2_motor_t *motor); From 7725fab5b8901c666259e010675d3259b4c8491b Mon Sep 17 00:00:00 2001 From: Terje Io Date: Sat, 17 Aug 2024 22:04:58 +0200 Subject: [PATCH 15/23] Simplified keypad and MPG symbol handling. --- README.md | 2 +- changelog.md | 20 ++++++++++++++++++- driver_opts.h | 51 +++++++++++++++++++----------------------------- grbl.h | 2 +- pin_bits_masks.h | 6 +++--- 5 files changed, 44 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 1faf0f5..301a122 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ It has been written to complement grblHAL and has features such as proper keyboa --- -Latest build date is 20240719, see the [changelog](changelog.md) for details. +Latest build date is 20240817, see the [changelog](changelog.md) for details. __NOTE:__ Build 20240222 has moved the probe input to the ioPorts pool of inputs and will be allocated from it when configured. The change is major and _potentially dangerous_, it may damage your probe, so please _verify correct operation_ after installing this, or later, builds. diff --git a/changelog.md b/changelog.md index 75d1785..515b4dc 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,23 @@ ## grblHAL changelog +Build 20240817 + +Core: + +* Simplified keypad and MPG symbol handling. + +Drivers: + +* Most: updated for simplified keypad and MPG symbol handling. + +* LPC176x: added support for keypad and MPG plugin. I2C keypad not fully supported and not tested. + +Plugins: + +* Keypad: updated for simplified keypad and MPG symbol handling. + +--- + Build 20240812 Core: @@ -14,7 +32,7 @@ Core: Drivers: -* imXRT1061, MSP432, STM32F4xx, STM32F7xx: Updated to take advandage of new spindle encoder binding functionality. +* imXRT1061, MSP432, STM32F4xx, STM32F7xx: updated to take advantage of new spindle encoder binding functionality. Plugins: diff --git a/driver_opts.h b/driver_opts.h index 289526d..9e93f77 100644 --- a/driver_opts.h +++ b/driver_opts.h @@ -94,26 +94,33 @@ #define SERIAL_STREAM 0 #endif -#ifndef KEYPAD_ENABLE -#define KEYPAD_ENABLE 0 -#endif - #ifndef MACROS_ENABLE #define MACROS_ENABLE 0 #endif -#ifndef MPG_ENABLE -#define MPG_ENABLE 0 +#ifndef KEYPAD_ENABLE +#define KEYPAD_ENABLE 0 #endif -#if MPG_ENABLE == 1 && KEYPAD_ENABLE == 2 -#define MPG_MODE 2 -#elif MPG_ENABLE == 2 -#define MPG_MODE 3 -#elif MPG_ENABLE -#define MPG_MODE 1 +#if KEYPAD_ENABLE == 1 +#ifdef I2C_STROBE_ENABLE +#undef I2C_STROBE_ENABLE +#endif +#define I2C_STROBE_ENABLE 1 +#elif KEYPAD_ENABLE == 2 && !defined(KEYPAD_STREAM) +#if USB_SERIAL_CDC +#define KEYPAD_STREAM 0 #else -#define MPG_MODE 0 +#define KEYPAD_STREAM 1 +#endif +#endif + +#ifndef I2C_STROBE_ENABLE +#define I2C_STROBE_ENABLE 0 +#endif + +#ifndef MPG_ENABLE +#define MPG_ENABLE 0 #endif #if MPG_ENABLE && !defined(MPG_STREAM) @@ -124,24 +131,6 @@ #endif #endif -#if KEYPAD_ENABLE == 1 -#ifdef I2C_STROBE_ENABLE -#undef I2C_STROBE_ENABLE -#endif -#define I2C_STROBE_ENABLE 1 -#elif KEYPAD_ENABLE == 2 && !defined(MPG_STREAM) -#ifndef KEYPAD_STREAM -#if USB_SERIAL_CDC -#define KEYPAD_STREAM 0 -#else -#define KEYPAD_STREAM 1 -#endif -#endif -#endif -#ifndef I2C_STROBE_ENABLE -#define I2C_STROBE_ENABLE 0 -#endif - #if DISPLAY_ENABLE == 2 #ifdef I2C_ENABLE #undef I2C_ENABLE diff --git a/grbl.h b/grbl.h index e4353db..6879333 100644 --- a/grbl.h +++ b/grbl.h @@ -42,7 +42,7 @@ #else #define GRBL_VERSION "1.1f" #endif -#define GRBL_BUILD 20240812 +#define GRBL_BUILD 20240817 #define GRBL_URL "https://github.com/grblHAL" diff --git a/pin_bits_masks.h b/pin_bits_masks.h index ea34cc5..459028d 100644 --- a/pin_bits_masks.h +++ b/pin_bits_masks.h @@ -43,7 +43,7 @@ #error "I2C keypad/strobe is not supported in this configuration!" #endif -#if MPG_MODE == 1 && !defined(MPG_MODE_PIN) +#if MPG_ENABLE == 1 && !defined(MPG_MODE_PIN) #error "MPG mode input is not supported in this configuration!" #endif @@ -197,7 +197,7 @@ #if SAFETY_DOOR_ENABLE || MOTOR_FAULT_ENABLE || MOTOR_WARNING_ENABLE || PROBE_DISCONNECT_ENABLE || \ STOP_DISABLE_ENABLE || BLOCK_DELETE_ENABLE || SINGLE_BLOCK_ENABLE || LIMITS_OVERRIDE_ENABLE || \ - (defined(AUX_DEVICES) && (PROBE_ENABLE || I2C_STROBE_ENABLE || MPG_MODE == 1 || QEI_SELECT_ENABLE)) || defined __DOXYGEN__ + (defined(AUX_DEVICES) && (PROBE_ENABLE || I2C_STROBE_ENABLE || MPG_ENABLE == 1 || QEI_SELECT_ENABLE)) || defined __DOXYGEN__ #define AUX_CONTROLS_ENABLED 1 @@ -244,7 +244,7 @@ static aux_ctrl_t aux_ctrl[] = { { .function = Input_I2CStrobe, .aux_port = 0xFF, .irq_mode = (pin_irq_mode_t)(IRQ_Mode_Change), .cap = { .value = 0 }, .pin = I2C_STROBE_PIN, .port = NULL }, #endif #endif -#if MPG_MODE == 1 && defined(MPG_MODE_PIN) && defined(AUX_DEVICES) +#if MPG_ENABLE == 1 && defined(MPG_MODE_PIN) && defined(AUX_DEVICES) #ifdef MPG_MODE_PORT { .function = Input_MPGSelect, .aux_port = 0xFF, .irq_mode = (pin_irq_mode_t)(IRQ_Mode_Change), .cap = { .value = 0 }, .pin = MPG_MODE_PIN, .port = MPG_MODE_PORT }, #else From c8c77c35e047fa7559bd680f5c20a206325db1c3 Mon Sep 17 00:00:00 2001 From: Terje Io Date: Wed, 4 Sep 2024 18:27:41 +0700 Subject: [PATCH 16/23] Added some new plugin init calls and setting ids. Added defaults for RGB strip lengths. --- README.md | 2 +- changelog.md | 46 ++++++++++++++++++++++++++++++++++++++++++++++ config.h | 18 ++++++++++++++++++ gcode.h | 20 ++++++++++++++++++++ grbl.h | 2 +- nuts_bolts.c | 2 +- plugins_init.h | 14 ++++++++++++++ settings.c | 16 ++++++++++++++-- settings.h | 36 ++++++++++++++++++++++++++++++++++++ 9 files changed, 151 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 301a122..ca63ff4 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ It has been written to complement grblHAL and has features such as proper keyboa --- -Latest build date is 20240817, see the [changelog](changelog.md) for details. +Latest build date is 20240903, see the [changelog](changelog.md) for details. __NOTE:__ Build 20240222 has moved the probe input to the ioPorts pool of inputs and will be allocated from it when configured. The change is major and _potentially dangerous_, it may damage your probe, so please _verify correct operation_ after installing this, or later, builds. diff --git a/changelog.md b/changelog.md index 515b4dc..5e5529e 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,51 @@ ## grblHAL changelog +Build 20240903 + +Core: + +* Added some new plugin init calls and setting ids. Added defaults for RGB strip lengths. + +Drivers: + +* ESP32, RP2040, STM32F4xx, STM32F7xx: updated for core changes related to the RGB HAL. + +* RP2040: renamed bluetooth files to avoid conflict with SDK. + +* STM32F7xx: moved board maps to separate directory. + +Plugins: + +* SD card: removed superfluous code. Made _.macro_ file type visible by default. Ref. [ioSender issue #403](https://github.com/terjeio/ioSender/issues/403). + +* Misc: initial commit of [new plugins](https://github.com/grblHAL/Plugins_misc), some moved from [Templates](https://github.com/grblHAL/Templates/tree/master/my_plugin). + +* WebUI: now delays soft reset commands for ESP32 driver to avoid crash when more than 3 axes are enabled. Ref. [issue #15](https://github.com/grblHAL/Plugin_WebUI/issues/15) + +--- + +Build 20240827 + +Core: + +* Added setting definitions for plugins and some new plugin initialization calls. + +Drivers: + +* ESP32: changed spindle on signal to GPIO32 when On/Off spindle is configured for MKS DLC32 board. Ref. this [discussion](https://github.com/grblHAL/core/discussions/203#discussioncomment-10454788). + +* RP2040: fixed build issues when native Bluetooth is enabled. Ref. [issue #94](https://github.com/grblHAL/RP2040/issues/94). + +Plugins: + +* Spindle: added "Offset" plugin for spindle \(laser\) movement to be executed when switching between spindles. + +* WebUI: workaround for [issue #15](https://github.com/grblHAL/Plugin_WebUI/issues/15), ESP32 crash on soft reset when > 3 axes configured. + +* Miscellaneous: added a number of smallish plugins; BLTouch, PWM servo, EventOut, RGB LED strips, RGB LED M150. These are work in progress and requires specific driver configurations. + +--- + Build 20240817 Core: diff --git a/config.h b/config.h index dc53aa7..c088d29 100644 --- a/config.h +++ b/config.h @@ -1793,6 +1793,24 @@ Timezone offset from UTC in hours, allowed range is -12.0 - 12.0. #endif ///@} +/*! @name $536 - Setting_RGB_StripLengt0 +Number of LEDs in NeoPixel/WS2812 strip 1. +*/ +///@{ +#if !defined DEFAULT_RGB_STRIP0_LENGTH || defined __DOXYGEN__ +#define DEFAULT_RGB_STRIP0_LENGTH 0 +#endif +///@} + +/*! @name $537 - Setting_RGB_StripLengt1 +Number of LEDs in NeoPixel/WS2812 strip 2. +*/ +///@{ +#if !defined DEFAULT_RGB_STRIP1_LENGTH || defined __DOXYGEN__ +#define DEFAULT_RGB_STRIP1_LENGTH 0 +#endif +///@} + /*! @name $538 - Setting_RotaryWrap Enable fast return to G28 position for rotary axes by \ref axismask. Use: diff --git a/gcode.h b/gcode.h index faff728..4fba815 100644 --- a/gcode.h +++ b/gcode.h @@ -360,6 +360,26 @@ typedef union { #endif #ifdef V_AXIS float v; +#endif + }; + struct { + float m0; + float m1; + float m2; +#if N_AXIS > 3 + float m3; +#endif +#if N_AXIS > 4 + float m4; +#endif +#if N_AXIS > 5 + float m5; +#endif +#if N_AXIS > 6 + float m6; +#endif +#if N_AXIS == 8 + float m7; #endif }; } coord_data_t; diff --git a/grbl.h b/grbl.h index 6879333..87ab84a 100644 --- a/grbl.h +++ b/grbl.h @@ -42,7 +42,7 @@ #else #define GRBL_VERSION "1.1f" #endif -#define GRBL_BUILD 20240817 +#define GRBL_BUILD 20240903 #define GRBL_URL "https://github.com/grblHAL" diff --git a/nuts_bolts.c b/nuts_bolts.c index a81195c..d32ce75 100644 --- a/nuts_bolts.c +++ b/nuts_bolts.c @@ -319,7 +319,7 @@ bool delay_sec (float seconds, delaymode_t mode) while(--i && ok) { if(mode == DelayMode_Dwell) ok = protocol_execute_realtime(); - else // DelayMode_SysSuspende, xecute rt_system() only to avoid nesting suspend loops. + else // DelayMode_SysSuspend, execute rt_system() only to avoid nesting suspend loops. ok = protocol_exec_rt_system() && !state_door_reopened(); // Bail, if safety door reopens. if(ok) hal.delay_ms(DWELL_TIME_STEP, NULL); // Delay DWELL_TIME_STEP increment diff --git a/plugins_init.h b/plugins_init.h index c41ef9e..8521056 100644 --- a/plugins_init.h +++ b/plugins_init.h @@ -118,12 +118,21 @@ embroidery_init(); #endif +#if RGB_LED_ENABLE + extern void rgb_led_init (void); + rgb_led_init(); +#endif + extern void my_plugin_init (void); my_plugin_init(); #if N_SPINDLE > 1 extern void spindle_select_init(void); spindle_select_init(); + #if SPINDLE_OFFSET == 1 + extern void spindle_offset_init (void); + spindle_offset_init(); + #endif #endif // Third party plugin definitions. @@ -166,6 +175,11 @@ panel_init(); #endif +#if EVENTOUT_ENABLE + extern void event_out_init (void); + event_out_init(); +#endif + // End third party plugin definitions. #if ODOMETER_ENABLE diff --git a/settings.c b/settings.c index 4bcae74..6d843b5 100644 --- a/settings.c +++ b/settings.c @@ -308,7 +308,10 @@ PROGMEM const settings_t defaults = { .safety_door.flags.ignore_when_idle = DEFAULT_DOOR_IGNORE_WHEN_IDLE, .safety_door.flags.keep_coolant_on = DEFAULT_DOOR_KEEP_COOLANT_ON, .safety_door.spindle_on_delay = DEFAULT_SAFETY_DOOR_SPINDLE_DELAY, - .safety_door.coolant_on_delay = DEFAULT_SAFETY_DOOR_COOLANT_DELAY + .safety_door.coolant_on_delay = DEFAULT_SAFETY_DOOR_COOLANT_DELAY, + + .rgb_strip0_length = DEFAULT_RGB_STRIP0_LENGTH, + .rgb_strip1_length = DEFAULT_RGB_STRIP1_LENGTH }; static bool group_is_available (const setting_group_detail_t *group) @@ -1461,7 +1464,11 @@ inline static setting_id_t normalize_id (setting_id_t id) id = (setting_id_t)(Setting_EncoderSettingsBase + (id % ENCODER_SETTINGS_INCREMENT)); else if(id > Setting_ModbusTCPBase && id <= Setting_ModbusTCPMax) id = (setting_id_t)(Setting_ModbusTCPBase + (id % MODBUS_TCP_SETTINGS_INCREMENT)); - else if((id > Setting_Macro0 && id <= Setting_Macro9) || (id > Setting_MacroPort0 && id <= Setting_MacroPort9) || (id > Setting_ButtonAction0 && id <= Setting_ButtonAction9)) + else if((id > Setting_Macro0 && id <= Setting_Macro9) || + (id > Setting_MacroPort0 && id <= Setting_MacroPort9) || + (id > Setting_ButtonAction0 && id <= Setting_ButtonAction9) || + (id > Setting_Action0 && id <= Setting_Action9) || + (id > Setting_ActionPort0 && id <= Setting_ActionPort9)) id = (setting_id_t)(id - (id % 10)); return id; @@ -2315,11 +2322,16 @@ void settings_restore (settings_restore_t restore) settings_write_build_info(BUILD_INFO); } + if(restore.defaults && hal.settings_changed) + hal.settings_changed(&settings, (settings_changed_flags_t){-1}); + setting_details_t *details = setting_details.next; if(details) do { if(details->restore) details->restore(); + if(details->on_changed) + details->on_changed(&settings, restore.defaults ? (settings_changed_flags_t){-1} : (settings_changed_flags_t){0}); } while((details = details->next)); nvs_buffer_sync_physical(); diff --git a/settings.h b/settings.h index 8f67ad6..6efdd0b 100644 --- a/settings.h +++ b/settings.h @@ -459,17 +459,53 @@ typedef enum { Setting_PWMOffValue1 = 734, Setting_PWMMinValue1 = 735, Setting_PWMMaxValue1 = 736, + // Optional driver implemented settings for piecewise linear spindle PWM algorithm Setting_LinearSpindle1Piece1 = 737, Setting_LinearSpindle1Piece2 = 738, Setting_LinearSpindle1Piece3 = 739, Setting_LinearSpindle1Piece4 = 740, + + Setting_Action0 = 750, + Setting_ActionBase = Setting_Action0, + Setting_Action1 = 751, + Setting_Action2 = 752, + Setting_Action3 = 753, + Setting_Action4 = 754, + Setting_Action5 = 755, + Setting_Action6 = 756, + Setting_Action7 = 757, + Setting_Action8 = 758, + Setting_Action9 = 759, + + Setting_ActionPort0 = 760, + Setting_ActionPortBase = Setting_ActionPort0, + Setting_ActionPort1 = 761, + Setting_ActionPort2 = 762, + Setting_ActionPort3 = 763, + Setting_ActionPort4 = 764, + Setting_ActionPort5 = 765, + Setting_ActionPort6 = 766, + Setting_ActionPort7 = 767, + Setting_ActionPort8 = 768, + Setting_ActionPort9 = 769, + + Setting_SpindleOffsetX = 770, + Setting_SpindleOffsetY = 771, +// +// 772-779 - reserved for spindle offset settings +// + // // 900-999 - reserved for automatic tool changers (ATC) // + +// --- Setting_SettingsMax, Setting_SettingsAll = Setting_SettingsMax, +// --- + // Calculated base values for core stepper settings Setting_AxisStepsPerMM = Setting_AxisSettingsBase, Setting_AxisMaxRate = Setting_AxisSettingsBase + AXIS_SETTINGS_INCREMENT, From fabec73d0e1242087fbf10f9c035bc530339c84a Mon Sep 17 00:00:00 2001 From: Terje Io Date: Sat, 7 Sep 2024 18:44:45 +0700 Subject: [PATCH 17/23] Added some RGB LED strip properties, improved handling of single meaning G-code words claimed by user M-codes. --- README.md | 2 +- changelog.md | 20 +++++++++++++++++++- gcode.c | 28 +++++++++++++++++++++++++++- grbl.h | 2 +- rgb.h | 10 ++++++++++ 5 files changed, 58 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ca63ff4..2b4bf61 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ It has been written to complement grblHAL and has features such as proper keyboa --- -Latest build date is 20240903, see the [changelog](changelog.md) for details. +Latest build date is 20240907, see the [changelog](changelog.md) for details. __NOTE:__ Build 20240222 has moved the probe input to the ioPorts pool of inputs and will be allocated from it when configured. The change is major and _potentially dangerous_, it may damage your probe, so please _verify correct operation_ after installing this, or later, builds. diff --git a/changelog.md b/changelog.md index 5e5529e..72fafe1 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,23 @@ ## grblHAL changelog +Build 20240907 + +Core: + +* Added some RGB LED strip properties, improved handling of single meaning G-code words claimed by user M-codes. + +Plugins: + +* Misc: updated for new RGB LED strip properties. + +Drivers: + +* iMRX1062, STM32F4xx and STM32F7xx: updated for new RGB LED strip properties. + +* RP2040: revised pin mappings for BTT SKR Pico board. Added misc. plugins to compilation. + +--- + Build 20240903 Core: @@ -8,7 +26,7 @@ Core: Drivers: -* ESP32, RP2040, STM32F4xx, STM32F7xx: updated for core changes related to the RGB HAL. +* ESP32, RP2040, STM32F4xx and STM32F7xx: updated for core changes related to the RGB HAL. * RP2040: renamed bluetooth files to avoid conflict with SDK. diff --git a/gcode.c b/gcode.c index 01d21b2..d1864ad 100644 --- a/gcode.c +++ b/gcode.c @@ -804,6 +804,12 @@ status_code_t gc_execute_block (char *block) #endif char *message = NULL; + struct { + float f; + uint32_t o; + float s; + tool_id_t t; + } single_meaning_value = {0}; block = gc_normalize_block(block, &message); @@ -1694,7 +1700,22 @@ status_code_t gc_execute_block (char *block) ijk_words.j = Off; if(user_words.k) ijk_words.k = Off; - + if(user_words.f) { + single_meaning_value.f = gc_block.values.f; + gc_block.values.f = 0.0f; + } + if(user_words.o) { + single_meaning_value.o = gc_block.values.o; + gc_block.values.o = 0; + } + if(user_words.s) { + single_meaning_value.s = gc_block.values.s; + gc_block.values.s = 0.0f; + } + if(user_words.t) { + single_meaning_value.t = gc_block.values.t; + gc_block.values.t = (tool_id_t)0; + } axis_words.mask = 0; } @@ -3313,7 +3334,12 @@ status_code_t gc_execute_block (char *block) if(gc_block.user_mcode_sync) protocol_buffer_synchronize(); // Ensure user defined mcode is executed when specified in program. + gc_block.words.mask = user_words.mask; + gc_block.values.f = single_meaning_value.f; + gc_block.values.o = single_meaning_value.o; + gc_block.values.s = single_meaning_value.s; + gc_block.values.t = single_meaning_value.t; hal.user_mcode.execute(state_get(), &gc_block); gc_block.words.mask = 0; } diff --git a/grbl.h b/grbl.h index 87ab84a..fe0804c 100644 --- a/grbl.h +++ b/grbl.h @@ -42,7 +42,7 @@ #else #define GRBL_VERSION "1.1f" #endif -#define GRBL_BUILD 20240903 +#define GRBL_BUILD 20240907 #define GRBL_URL "https://github.com/grblHAL" diff --git a/rgb.h b/rgb.h index ff47b7d..8bd7cce 100644 --- a/rgb.h +++ b/rgb.h @@ -41,6 +41,15 @@ typedef union { }; } rgb_color_t; +typedef union { + uint8_t mask; + struct { + uint8_t is_blocking :1, + is_strip :1, + unassigned :6; + }; +} rgb_properties_t; + /*! \brief Pointer to function for setting RGB (LED) output. \param color a \a rgb_color_t union. */ @@ -68,6 +77,7 @@ typedef struct { rgb_write_ptr write; //!< Optional handler for outputting data to Neopixel strip. rgb_set_intensity_ptr set_intensity; //!< Optional handler for setting intensity, range 0 - 255. rgb_color_t cap; //!< Driver capability, color value: 0 - not available, 1 - on off, > 1 - intensity range 0 - n. + rgb_properties_t flags; //!< Driver property flags. uint16_t num_devices; //!< Number of devices (LEDs) available. } rgb_ptr_t; From 3ef6763cec2e20d9c667754c9a58d738555e10cd Mon Sep 17 00:00:00 2001 From: Terje Io Date: Sat, 21 Sep 2024 18:25:00 +0700 Subject: [PATCH 18/23] Build 20240921 Added generic HAL timer API and function for getting which G65 parameter words were supplied. --- changelog.md | 16 ++++++++++ crossbar.h | 2 ++ gcode.c | 12 +++++++- gcode.h | 5 +-- grbl.h | 2 +- hal.h | 84 +++++++++++++++++++++++++++++++++++++++++++++++--- nuts_bolts.h | 1 + stepper2.c | 87 +++++++++++++++++++++++++++++++++++++++++++++------- stepper2.h | 4 +++ 9 files changed, 194 insertions(+), 19 deletions(-) diff --git a/changelog.md b/changelog.md index 72fafe1..a5b2fa5 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,21 @@ ## grblHAL changelog +Build 20240921 + +Core: + +* Added generic HAL timer API and function for getting which `G65` parameter words were supplied. + +Networking: + +* Made parsing of HTTP header keywords case insensitive. Ref. [issue #11](https://github.com/grblHAL/Plugin_networking/issues/11). + +SD card (macros): + +* Added inbuilt `G65` macro `P3` for getting and setting NGC numerical parameters, typical use case will be for indexed access. Ref. [discussion #309 comment](https://github.com/grblHAL/core/discussions/309#discussioncomment-10710468). + +--- + Build 20240907 Core: diff --git a/crossbar.h b/crossbar.h index e34954f..d210860 100644 --- a/crossbar.h +++ b/crossbar.h @@ -187,6 +187,7 @@ typedef enum { Output_MOSI, Output_SPICLK, Output_SPICS, + Output_FlashCS, Output_SdCardCS, Input_SdCardDetect, Output_SPIRST, @@ -385,6 +386,7 @@ PROGMEM static const pin_name_t pin_names[] = { { .function = Output_MOSI, .name = "MOSI" }, { .function = Output_SPICLK, .name = "SPI CLK" }, { .function = Output_SPICS, .name = "SPI CS" }, + { .function = Output_FlashCS, .name = "Flash CS" }, { .function = Output_SdCardCS, .name = "SD card CS" }, { .function = Input_SdCardDetect, .name = "SD card detect" }, { .function = Output_SPIRST, .name = "SPI reset" }, diff --git a/gcode.c b/gcode.c index d1864ad..0c79161 100644 --- a/gcode.c +++ b/gcode.c @@ -509,11 +509,17 @@ static status_code_t read_parameter (char *line, uint_fast8_t *char_counter, flo return status; } - #endif // NGC_EXPRESSIONS_ENABLE #if NGC_PARAMETERS_ENABLE +static parameter_words_t g65_words = {0}; + +parameter_words_t gc_get_g65_arguments (void) +{ + return g65_words; +} + bool gc_modal_state_restore (gc_modal_t *copy) { bool ok = false; @@ -950,6 +956,7 @@ status_code_t gc_execute_block (char *block) if(!is_user_mcode && isnanf(value)) FAIL(Status_BadNumberFormat); // [Expected word value] + g65_words.value = 0; #else if((letter < 'A' && letter != '$') || letter > 'Z') @@ -2435,11 +2442,14 @@ status_code_t gc_execute_block (char *block) while(gc_block.words.value) { if(gc_block.words.value & 0x1 && gc_value_ptr[idx].value) switch(gc_value_ptr[idx].type) { + case ValueType_Float: + g65_words.value |= (1 << idx); ngc_param_set((ngc_param_id_t)idx, *(float *)gc_value_ptr[idx].value); break; case ValueType_UInt32: + g65_words.value |= (1 << idx); ngc_param_set((ngc_param_id_t)idx, (float)*(uint32_t *)gc_value_ptr[idx].value); break; diff --git a/gcode.h b/gcode.h index 4fba815..cb5394c 100644 --- a/gcode.h +++ b/gcode.h @@ -238,8 +238,8 @@ typedef enum { UserMCode_Generic3 = 103, //!< 103 - For private use only UserMCode_Generic4 = 104, //!< 104 - For private use only OpenPNP_GetADCReading = 105, //!< 105 - M105 - Fan_On = 106, //!< 106 - M106 - Fan_Off = 107, //!< 107 - M107 + Fan_On = 106, //!< 106 - M106, Marlin format + Fan_Off = 107, //!< 107 - M107, Marlin format OpenPNP_GetCurrentPosition = 114, //!< 114 - M114 OpenPNP_FirmwareInfo = 115, //!< 115 - M115 Trinamic_DebugReport = 122, //!< 122 - M122, Marlin format @@ -685,6 +685,7 @@ void gc_set_tool_offset (tool_offset_mode_t mode, uint_fast8_t idx, int32_t offs plane_t *gc_get_plane_data (plane_t *plane, plane_select_t select); #if NGC_PARAMETERS_ENABLE +parameter_words_t gc_get_g65_arguments (void); bool gc_modal_state_restore (gc_modal_t *copy); #endif diff --git a/grbl.h b/grbl.h index fe0804c..28220ce 100644 --- a/grbl.h +++ b/grbl.h @@ -42,7 +42,7 @@ #else #define GRBL_VERSION "1.1f" #endif -#define GRBL_BUILD 20240907 +#define GRBL_BUILD 20240921 #define GRBL_URL "https://github.com/grblHAL" diff --git a/hal.h b/hal.h index aa5f47a..fda8127 100644 --- a/hal.h +++ b/hal.h @@ -302,6 +302,13 @@ typedef void (*stepper_output_step_ptr)(axes_signals_t step_outbits, axes_signal */ typedef axes_signals_t (*stepper_get_ganged_ptr)(bool auto_squared); +/*! \brief Pointer to function for claiming/releasing motor(s) from/to normal step/dir signalling. + +\param axis_id a \a the axis to claim/release motor(s) for. +\param claim \a true to claim a motor(s), \a false to release. +*/ +typedef void (*stepper_claim_motor_ptr)(uint_fast8_t axis_id, bool claim); + /*! \brief Pointer to callback function for outputting the next direction and step pulse signals. _Set by the core on startup._ To be called by the driver from the main stepper interrupt handler (when the timer times out). @@ -318,6 +325,7 @@ typedef struct { stepper_pulse_start_ptr pulse_start; //!< Handler for starting outputting direction signals and a step pulse. Called from interrupt context. stepper_interrupt_callback_ptr interrupt_callback; //!< Callback for informing about the next step pulse to output. _Set by the core at startup._ stepper_get_ganged_ptr get_ganged; //!< Optional handler getting which axes are configured for ganging or auto squaring. + stepper_claim_motor_ptr claim_motor; //!< Optional handler for claiming/releasing motor(s) from normal step/dir control. stepper_output_step_ptr output_step; //!< Optional handler for outputting a single step pulse. _Experimental._ Called from interrupt context. motor_iterator_ptr motor_iterator; //!< Optional handler iteration over motor vs. axis mappings. Required for the motors plugin (Trinamic drivers). } stepper_ptrs_t; @@ -484,6 +492,73 @@ typedef struct { */ typedef bool (*irq_claim_ptr)(irq_type_t irq, uint_fast8_t id, irq_callback_ptr callback); +/************ + * Timers * + ************/ + +typedef void *hal_timer_t; //!< Timer handle, actual type defined by driver implementation. + +typedef enum { + Timer_16bit = 0, + Timer_32bit, + Timer_64bit +} timer_resolution_t; + +typedef union { + uint8_t value; //!< All bitmap flags. + struct { + uint8_t periodic :1, //!< + up :1, //!< Timer supports upcounting + comp1 :1, //!< Timer supports compare interrupt 0 + comp2 :1; //!< Timer supports compare interrupt 1 + }; +} timer_cap_t; + +typedef void (*timer_irq_handler_ptr)(void *context); + +typedef struct { + void *context; //!< Pointer to data to be passed on to the interrupt handlers + bool single_shot; //!< Set to true if timer is single shot + timer_irq_handler_ptr timeout_callback; //!< Pointer to main timeout callback + uint32_t irq0; //!< Compare value for compare interrupt 0 + timer_irq_handler_ptr irq0_callback; //!< Pointer to compare interrupt 0 callback + uint32_t irq1; //!< Compare value for compare interrupt 10 + timer_irq_handler_ptr irq1_callback; //!< Pointer to compare interrupt 1 callback +} timer_cfg_t; + +/*! \brief Pointer to function for claiming a timer. +\param cap pointer to a \a timer_cap_t struct containing the required capabilities. +\param timebase timebase in ns. +\returns a \a hal_timer_t pointer if successful, \a NULL if not. +*/ +typedef hal_timer_t (*timer_claim_ptr)(timer_cap_t cap, uint32_t timebase); + +/*! \brief Pointer to function for configuring a timer. +\param timer a \a hal_timer_t pointer. +\param cfg pointer to a \a timer_cfg_t struct. +\returns \a true if successful. +*/ +typedef bool (*timer_cfg_ptr)(hal_timer_t timer, timer_cfg_t *cfg); + +/*! \brief Pointer to function for starting a timer. +\param timer a \a hal_timer_t pointer. +\param period delay in. +\returns \a true if successful. +*/ +typedef bool (*timer_start_ptr)(hal_timer_t timer, uint32_t period); + +/*! \brief Pointer to function for stopping a running timer. +\param timer a \a hal_timer_t pointer. +\returns \a true if successful. +*/ +typedef bool (*timer_stop_ptr)(hal_timer_t timer); + +typedef struct { + timer_claim_ptr claim; + timer_cfg_ptr configure; + timer_start_ptr start; + timer_stop_ptr stop; +} timer_ptrs_t; /************************** * RTC (Real Time Clock * @@ -491,13 +566,13 @@ typedef bool (*irq_claim_ptr)(irq_type_t irq, uint_fast8_t id, irq_callback_ptr /*! \brief Pointer to function for setting the current datetime. \param datetime pointer to a \a tm struct. -\returns true if successful. +\\returns \a true if successful. */ typedef bool (*rtc_get_datetime_ptr)(struct tm *datetime); /*! \brief Pointer to function for setting the current datetime. \param datetime pointer to a \a tm struct. -\returns true if successful. +\returns \a true if successful. */ typedef bool (*rtc_set_datetime_ptr)(struct tm *datetime); @@ -541,7 +616,7 @@ typedef struct { /*! \brief Driver setup handler. Called once by the core after settings has been loaded. The driver should enable MCU peripherals in the provided function. \param settings pointer to settings_t structure. - \returns true if completed successfully and the driver supports the _settings->version_ number, false otherwise. + \returns \a true if completed successfully and the driver supports the _settings->version_ number, false otherwise. */ driver_setup_ptr driver_setup; @@ -595,6 +670,7 @@ typedef struct { settings_changed_ptr settings_changed; //!< Callback handler to be called on settings loaded or settings changed events. probe_ptrs_t probe; //!< Optional handlers for probe input(s). tool_ptrs_t tool; //!< Optional handlers for tool changes. + timer_ptrs_t timer; //!< Optional handlers for claiming and controlling timers. rtc_ptrs_t rtc; //!< Optional handlers for real time clock (RTC). io_port_t port; //!< Optional handlers for axuillary I/O (adds support for M62-M66). rgb_ptr_t rgb0; //!< Optional handler for RGB output to LEDs (neopixels) or lamps. @@ -649,7 +725,7 @@ Then _hal.driver_setup()_ will be called so that the driver can configure the re __NOTE__: This is the only driver function that is called directly from the core, all others are called via HAL function pointers. -\returns true if completed successfully and the driver matches the _hal.version number_, false otherwise. +\returns \a true if completed successfully and the driver matches the _hal.version number_, \a false otherwise. */ extern bool driver_init (void); diff --git a/nuts_bolts.h b/nuts_bolts.h index ae6f6f3..ec5b8ba 100644 --- a/nuts_bolts.h +++ b/nuts_bolts.h @@ -129,6 +129,7 @@ extern char const *const axis_letter[]; typedef union { uint8_t mask; + uint8_t bits; uint8_t value; struct { uint8_t x :1, diff --git a/stepper2.c b/stepper2.c index ea2c082..57bfa5d 100644 --- a/stepper2.c +++ b/stepper2.c @@ -47,6 +47,7 @@ struct st2_motor { axes_signals_t axis; bool is_spindle; bool is_bound; + bool polling; bool position_lost; volatile int64_t position; // absolute step number position_t ptype; // @@ -66,6 +67,8 @@ struct st2_motor { float acceleration; // acceleration steps/s^2 axes_signals_t dir; // current direction uint64_t next_step; + hal_timer_t step_inject_timer; + foreground_task_ptr on_stopped; st2_motor_t *next; }; @@ -76,6 +79,8 @@ static on_set_axis_setting_unit_ptr on_set_axis_setting_unit; static on_setting_get_description_ptr on_setting_get_description; static on_reset_ptr on_reset; +static void motor_irq (void *context); + /*! \brief Calculate basic motor configuration. \param motor pointer to a \a st2_motor structure. @@ -200,6 +205,11 @@ static const char *st2_setting_get_description (setting_id_t id) : (on_setting_get_description ? on_setting_get_description(id) : NULL); } +void st2_motor_register_stopped_callback (st2_motor_t *motor, foreground_task_ptr callback) +{ + motor->on_stopped = callback; +} + /*! \brief Bind and initialize a motor. Binds motor 0 as a spindle. @@ -240,9 +250,23 @@ If \a is_spindle is set \a true then axis settings will be changed to step/rev e */ st2_motor_t *st2_motor_init (uint_fast8_t axis_idx, bool is_spindle) { - st2_motor_t *motor, *new = motors; + st2_motor_t *motor = NULL, *new = motors; - if((motor = calloc(sizeof(st2_motor_t), 1))) { + if(hal.stepper.output_step && (motor = calloc(sizeof(st2_motor_t), 1))) { + + if(hal.timer.claim && (motor->step_inject_timer = hal.timer.claim((timer_cap_t){ .periodic = Off }, 1000))) { + timer_cfg_t step_inject_cfg = { + .single_shot = true, + .timeout_callback = motor_irq + }; + step_inject_cfg.context = motor; + hal.timer.configure(motor->step_inject_timer, &step_inject_cfg); + } else if(hal.get_micros) + motor->polling = true; + else { + free(motor); + return NULL; + } if(!is_spindle) { @@ -417,6 +441,9 @@ bool st2_motor_move (st2_motor_t *motor, const float move, const float speed, po motor->step_no = 0; // step counter motor->next_step = hal.get_micros(); + if(motor->step_inject_timer) + hal.timer.start(motor->step_inject_timer, motor->delay); + #ifdef DEBUGOUT uint32_t nn = motor->n; float cn = motor->first_delay; @@ -464,17 +491,12 @@ bool st2_set_position (st2_motor_t *motor, int64_t position) } /*! \brief Execute a move commanded by st2_motor_move(). - -This should be called from the foreground process as often as possible. \param motor pointer to a \a st2_motor structure. \returns \a true if motor is moving (steps are output), \a false if not (motion is completed). */ -bool st2_motor_run (st2_motor_t *motor) +__attribute__((always_inline)) static inline bool _motor_run (st2_motor_t *motor) { - uint64_t t = hal.get_micros(); - - if(motor->state == State_Idle || t - motor->next_step < motor->delay) - return motor->state != State_Idle; + st2_state_t prev_state = motor->state; switch(motor->state) { @@ -483,7 +505,7 @@ bool st2_motor_run (st2_motor_t *motor) motor->denom += 4; motor->c64 -= (motor->c64 << 1) / motor->denom; // ramp algorithm motor->delay = (motor->c64 + 32768) >> 16; // round 24.16 format -> int16 - if (motor->delay < motor->min_delay) { // go to constant speed? + if (motor->delay < motor->min_delay) { // go to constant speed? // motor->denom -= 6; // causes issues with speed override for infinite moves motor->state = motor->ptype == Stepper2_InfiniteSteps ? State_RunInfinite : State_Run; motor->step_down = motor->move - motor->step_no; @@ -540,7 +562,41 @@ bool st2_motor_run (st2_motor_t *motor) motor->position++; motor->step_no++; - motor->next_step = t; + + if(motor->state == State_Idle && prev_state != State_Idle && motor->on_stopped) + task_add_delayed(motor->on_stopped, motor, 2); + + return motor->state != State_Idle; +} + +ISR_CODE static void ISR_FUNC(motor_irq)(void *context) +{ + if(_motor_run((st2_motor_t *)context)) + hal.timer.start(((st2_motor_t *)context)->step_inject_timer, ((st2_motor_t *)context)->delay); + else + hal.timer.stop(((st2_motor_t *)context)->step_inject_timer); +} + +/*! \brief Execute a move commanded by st2_motor_move(). + +This should be called from the foreground process as often as possible +when step output is not driven by interrupts (polling mode). +\param motor pointer to a \a st2_motor structure. +\returns \a true if motor is moving (steps are output), \a false if not (motion is completed). +*/ +bool st2_motor_run (st2_motor_t *motor) +{ + if(motor->polling && motor->state != State_Idle) { + + uint64_t t = hal.get_micros(); + + if(t - motor->next_step >= motor->delay) { + + _motor_run(motor); + + motor->next_step = t; + } + } return motor->state != State_Idle; } @@ -575,6 +631,15 @@ bool st2_motor_stop (st2_motor_t *motor) return motor->state != State_Idle; } +/*! \brief Check if motor is run by polling. +\param motor pointer to a \a st2_motor structure. +\returns \a true if motor is run by polling, \a false if not. +*/ +bool st2_motor_poll (st2_motor_t *motor) +{ + return motor->polling; +} + /*! \brief Check if motor is running. \param motor pointer to a \a st2_motor structure. \returns \a true if motor is running, \a false if not. diff --git a/stepper2.h b/stepper2.h index d5984ca..5caffa2 100644 --- a/stepper2.h +++ b/stepper2.h @@ -22,6 +22,8 @@ #include #include +#include "task.h" + typedef enum { Stepper2_Steps = 0, //!< 0 Stepper2_InfiniteSteps, //!< 1 @@ -32,6 +34,7 @@ struct st2_motor; // members defined in stepper2.c typedef struct st2_motor st2_motor_t; st2_motor_t *st2_motor_init (uint_fast8_t axis_idx, bool is_spindle); +bool st2_motor_poll (st2_motor_t *motor); bool st2_motor_bind_spindle (uint_fast8_t axis_idx); float st2_get_speed (st2_motor_t *motor); float st2_motor_set_speed (st2_motor_t *motor, float speed); @@ -42,3 +45,4 @@ bool st2_motor_cruising (st2_motor_t *motor); bool st2_motor_stop (st2_motor_t *motor); int64_t st2_get_position (st2_motor_t *motor); bool st2_set_position (st2_motor_t *motor, int64_t position); +void st2_motor_register_stopped_callback (st2_motor_t *motor, foreground_task_ptr callback); From d480ccaf51d51a5df549570fd29faa7656a56acb Mon Sep 17 00:00:00 2001 From: skasti Date: Wed, 25 Sep 2024 06:31:34 +0200 Subject: [PATCH 19/23] Add ability to insert parameters in MSG comments --- gcode.c | 42 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/gcode.c b/gcode.c index 0c79161..3cfb28e 100644 --- a/gcode.c +++ b/gcode.c @@ -595,13 +595,49 @@ char *gc_normalize_block (char *block, char **message) size_t len = s1 - comment - 4; if(message && *message == NULL && !strncmp(comment, "(MSG,", 5) && (*message = malloc(len))) { + float value; + char *s3; + uint_fast8_t char_counter = 0; + + len = 0; comment += 5; + // Trim leading spaces - while(*comment == ' ') { + while(*comment == ' ') comment++; - len--; + + // Calculate length of substituted string + while((c = comment[char_counter++])) { + if(c == '#') { + char_counter--; + if(read_parameter(comment, &char_counter, &value) == Status_OK) + len += strlen(trim_float(ftoa(value, ngc_float_decimals()))); + else + len += 3; // "N/A" + } else + len++; + } + + // Perform substitution + if((s3 = *message = malloc(len + 1))) { + + *s3 = '\0'; + char_counter = 0; + + while((c = comment[char_counter++])) { + if(c == '#') { + char_counter--; + if(read_parameter(comment, &char_counter, &value) == Status_OK) + strcat(s3, trim_float(ftoa(value, ngc_float_decimals()))); + else + strcat(s3, "N/A"); + s3 = strchr(s3, '\0'); + } else { + *s3++ = c; + *s3 = '\0'; + } + } } - memcpy(*message, comment, len); } #if NGC_EXPRESSIONS_ENABLE From 6a042107af0b5e3ef285a32986b352f8503d33df Mon Sep 17 00:00:00 2001 From: skasti Date: Wed, 25 Sep 2024 06:36:53 +0200 Subject: [PATCH 20/23] Respect NGC_PARAMETERS_ENABLE --- gcode.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/gcode.c b/gcode.c index 3cfb28e..2fab477 100644 --- a/gcode.c +++ b/gcode.c @@ -595,13 +595,13 @@ char *gc_normalize_block (char *block, char **message) size_t len = s1 - comment - 4; if(message && *message == NULL && !strncmp(comment, "(MSG,", 5) && (*message = malloc(len))) { + comment += 5; +#if NGC_PARAMETERS_ENABLE + len = 0; float value; char *s3; uint_fast8_t char_counter = 0; - len = 0; - comment += 5; - // Trim leading spaces while(*comment == ' ') comment++; @@ -638,6 +638,13 @@ char *gc_normalize_block (char *block, char **message) } } } +#else + while(*comment == ' ') { + comment++; + len--; + } + memcpy(*message, comment, len); +#endif } #if NGC_EXPRESSIONS_ENABLE From 9d6f09bf724b0903969c7bf144d4466f65a9f8d6 Mon Sep 17 00:00:00 2001 From: skasti Date: Wed, 25 Sep 2024 06:58:08 +0200 Subject: [PATCH 21/23] Extract substitution code to a function --- gcode.c | 131 ++++++++++++++++++++------------------------------------ 1 file changed, 47 insertions(+), 84 deletions(-) diff --git a/gcode.c b/gcode.c index 2fab477..f55cc4f 100644 --- a/gcode.c +++ b/gcode.c @@ -548,6 +548,51 @@ bool gc_modal_state_restore (gc_modal_t *copy) #endif // NGC_PARAMETERS_ENABLE +void substitute_parameters(char *comment, char **message) { + size_t len = 0; + float value; + char *s3; + uint_fast8_t char_counter = 0; + char c = *(comment + char_counter); + + // Trim leading spaces + while(*comment == ' ') + comment++; + + // Calculate length of substituted string + while((c = comment[char_counter++])) { + if(c == '#') { + char_counter--; + if(read_parameter(comment, &char_counter, &value) == Status_OK) + len += strlen(trim_float(ftoa(value, ngc_float_decimals()))); + else + len += 3; // "N/A" + } else + len++; + } + + // Perform substitution + if((s3 = *message = malloc(len + 1))) { + + *s3 = '\0'; + char_counter = 0; + + while((c = comment[char_counter++])) { + if(c == '#') { + char_counter--; + if(read_parameter(comment, &char_counter, &value) == Status_OK) + strcat(s3, trim_float(ftoa(value, ngc_float_decimals()))); + else + strcat(s3, "N/A"); + s3 = strchr(s3, '\0'); + } else { + *s3++ = c; + *s3 = '\0'; + } + } + } +} + // Remove whitespace, control characters, comments and if block delete is active block delete lines // else the block delete character. Remaining characters are converted to upper case. // If the driver handles message comments then the first is extracted and returned in a dynamically @@ -597,47 +642,7 @@ char *gc_normalize_block (char *block, char **message) if(message && *message == NULL && !strncmp(comment, "(MSG,", 5) && (*message = malloc(len))) { comment += 5; #if NGC_PARAMETERS_ENABLE - len = 0; - float value; - char *s3; - uint_fast8_t char_counter = 0; - - // Trim leading spaces - while(*comment == ' ') - comment++; - - // Calculate length of substituted string - while((c = comment[char_counter++])) { - if(c == '#') { - char_counter--; - if(read_parameter(comment, &char_counter, &value) == Status_OK) - len += strlen(trim_float(ftoa(value, ngc_float_decimals()))); - else - len += 3; // "N/A" - } else - len++; - } - - // Perform substitution - if((s3 = *message = malloc(len + 1))) { - - *s3 = '\0'; - char_counter = 0; - - while((c = comment[char_counter++])) { - if(c == '#') { - char_counter--; - if(read_parameter(comment, &char_counter, &value) == Status_OK) - strcat(s3, trim_float(ftoa(value, ngc_float_decimals()))); - else - strcat(s3, "N/A"); - s3 = strchr(s3, '\0'); - } else { - *s3++ = c; - *s3 = '\0'; - } - } - } + substitute_parameters(comment, message); #else while(*comment == ' ') { comment++; @@ -652,50 +657,8 @@ char *gc_normalize_block (char *block, char **message) if(message && *message == NULL && !strncmp(comment, "(DEBUG,", 7)) { if(settings.flags.ngc_debug_out) { - - float value; - char *s3; - uint_fast8_t char_counter = 0; - - len = 0; comment += 7; - - // Trim leading spaces - while(*comment == ' ') - comment++; - - // Calculate length of substituted string - while((c = comment[char_counter++])) { - if(c == '#') { - char_counter--; - if(read_parameter(comment, &char_counter, &value) == Status_OK) - len += strlen(trim_float(ftoa(value, ngc_float_decimals()))); - else - len += 3; // "N/A" - } else - len++; - } - - // Perform substitution - if((s3 = *message = malloc(len + 1))) { - - *s3 = '\0'; - char_counter = 0; - - while((c = comment[char_counter++])) { - if(c == '#') { - char_counter--; - if(read_parameter(comment, &char_counter, &value) == Status_OK) - strcat(s3, trim_float(ftoa(value, ngc_float_decimals()))); - else - strcat(s3, "N/A"); - s3 = strchr(s3, '\0'); - } else { - *s3++ = c; - *s3 = '\0'; - } - } - } + substitute_parameters(comment, message); } *comment = '\0'; // Do not generate grbl.on_gcode_comment event! From 94d15b45d0423c964ca30b0ac0b40a9177eb1aee Mon Sep 17 00:00:00 2001 From: skasti Date: Wed, 25 Sep 2024 10:54:01 +0200 Subject: [PATCH 22/23] Put functionality in NGC_EXPRESSIONS_ENABLE block --- gcode.c | 82 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/gcode.c b/gcode.c index f55cc4f..379f955 100644 --- a/gcode.c +++ b/gcode.c @@ -509,46 +509,7 @@ static status_code_t read_parameter (char *line, uint_fast8_t *char_counter, flo return status; } -#endif // NGC_EXPRESSIONS_ENABLE - -#if NGC_PARAMETERS_ENABLE - -static parameter_words_t g65_words = {0}; - -parameter_words_t gc_get_g65_arguments (void) -{ - return g65_words; -} - -bool gc_modal_state_restore (gc_modal_t *copy) -{ - bool ok = false; - - if((ok = !!copy && !ABORTED)) { - - copy->auto_restore = false; - copy->motion = gc_state.modal.motion; - - if(copy->coolant.value != gc_state.modal.coolant.value) { - hal.coolant.set_state(copy->coolant); - delay_sec(settings.safety_door.coolant_on_delay, DelayMode_SysSuspend); - } - - if(copy->spindle.state.value != gc_state.modal.spindle.state.value || copy->rpm != gc_state.modal.rpm) - spindle_restore(gc_state.spindle.hal, copy->spindle.state, copy->rpm); - - memcpy(&gc_state.modal, copy, sizeof(gc_modal_t)); - - gc_state.spindle.rpm = gc_state.modal.rpm; - gc_state.feed_rate = gc_state.modal.feed_rate; - } - - return ok; -} - -#endif // NGC_PARAMETERS_ENABLE - -void substitute_parameters(char *comment, char **message) { +static void substitute_parameters(char *comment, char **message) { size_t len = 0; float value; char *s3; @@ -593,6 +554,45 @@ void substitute_parameters(char *comment, char **message) { } } +#endif // NGC_EXPRESSIONS_ENABLE + +#if NGC_PARAMETERS_ENABLE + +static parameter_words_t g65_words = {0}; + +parameter_words_t gc_get_g65_arguments (void) +{ + return g65_words; +} + +bool gc_modal_state_restore (gc_modal_t *copy) +{ + bool ok = false; + + if((ok = !!copy && !ABORTED)) { + + copy->auto_restore = false; + copy->motion = gc_state.modal.motion; + + if(copy->coolant.value != gc_state.modal.coolant.value) { + hal.coolant.set_state(copy->coolant); + delay_sec(settings.safety_door.coolant_on_delay, DelayMode_SysSuspend); + } + + if(copy->spindle.state.value != gc_state.modal.spindle.state.value || copy->rpm != gc_state.modal.rpm) + spindle_restore(gc_state.spindle.hal, copy->spindle.state, copy->rpm); + + memcpy(&gc_state.modal, copy, sizeof(gc_modal_t)); + + gc_state.spindle.rpm = gc_state.modal.rpm; + gc_state.feed_rate = gc_state.modal.feed_rate; + } + + return ok; +} + +#endif // NGC_PARAMETERS_ENABLE + // Remove whitespace, control characters, comments and if block delete is active block delete lines // else the block delete character. Remaining characters are converted to upper case. // If the driver handles message comments then the first is extracted and returned in a dynamically @@ -641,7 +641,7 @@ char *gc_normalize_block (char *block, char **message) if(message && *message == NULL && !strncmp(comment, "(MSG,", 5) && (*message = malloc(len))) { comment += 5; -#if NGC_PARAMETERS_ENABLE +#if NGC_EXPRESSIONS_ENABLE substitute_parameters(comment, message); #else while(*comment == ' ') { From 323dd84b7972c6acab745faa6add0f32da91d2b6 Mon Sep 17 00:00:00 2001 From: Terje Io Date: Sun, 29 Sep 2024 12:38:49 +0700 Subject: [PATCH 23/23] Added (PRINT, ) support and parameter formatting for DEBUG and PRINT commands. Added named parameters for getting absolute (G53) position: _abs_x, abs_y, ... Available when expression support is enabled. Changed stepper enable HAL signature to allow current reduction when idle. Added reference id to spindle registration in order to allow configuring default spindle, and possibly additional spindles, at compile time. --- README.md | 2 +- changelog.md | 34 ++++++++-- config.h | 8 +++ driver_opts.h | 38 +++++------ errors.h | 1 + gcode.c | 165 +++++++++++++++++++++++++++++++++++----------- grbl.h | 2 +- grbllib.c | 2 +- hal.h | 3 +- ioports.c | 2 +- ngc_flowctrl.c | 4 +- ngc_params.c | 43 ++++++++++++ ngc_params.h | 9 +++ report.c | 5 +- settings.c | 35 ++++++---- settings.h | 4 +- spindle_control.c | 1 + spindle_control.h | 8 ++- stepper.c | 6 +- 19 files changed, 281 insertions(+), 91 deletions(-) diff --git a/README.md b/README.md index 2b4bf61..ec91402 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ It has been written to complement grblHAL and has features such as proper keyboa --- -Latest build date is 20240907, see the [changelog](changelog.md) for details. +Latest build date is 20240928, see the [changelog](changelog.md) for details. __NOTE:__ Build 20240222 has moved the probe input to the ioPorts pool of inputs and will be allocated from it when configured. The change is major and _potentially dangerous_, it may damage your probe, so please _verify correct operation_ after installing this, or later, builds. diff --git a/changelog.md b/changelog.md index a5b2fa5..1158a89 100644 --- a/changelog.md +++ b/changelog.md @@ -1,18 +1,42 @@ ## grblHAL changelog +Build 20240928 + +* Added `(PRINT, )` support and parameter formatting for `DEBUG` and `PRINT` commands. Available when expression support is enabled. + +* Added named parameters for getting absolute \(G53\) position: `_abs_x`, `abs_y`, ... Available when expression support is enabled. + +* Changed stepper enable HAL signature to allow current reduction when idle. Requires compatible stepper drivers and low level code support. + +* Added reference id to spindle registration in order to allow configuring default spindle, and possibly additional spindles, at compile time. + +* Fix for hardfault when some $-settings are changed and there are no auxilary inputs defined in the board map. Ref. [issue #588](https://github.com/grblHAL/core/issues/588). + +Drivers: + +* All: updated for core changes mentioned above. + +* ESP32, STM32F4xx, STM32F7xx: added basic support for the core HAL timer API. Changed step inject code to interrupt driven instead of polled. + +Plugins: + +* Spindle: updated to support new spindle reference id in the core, simplified code. + +* SD Card \(macros\): fixed bug in handling of repeat loops. + +--- + Build 20240921 Core: * Added generic HAL timer API and function for getting which `G65` parameter words were supplied. -Networking: +Plugins: -* Made parsing of HTTP header keywords case insensitive. Ref. [issue #11](https://github.com/grblHAL/Plugin_networking/issues/11). +* Networking: made parsing of HTTP header keywords case insensitive. Ref. [issue #11](https://github.com/grblHAL/Plugin_networking/issues/11). -SD card (macros): - -* Added inbuilt `G65` macro `P3` for getting and setting NGC numerical parameters, typical use case will be for indexed access. Ref. [discussion #309 comment](https://github.com/grblHAL/core/discussions/309#discussioncomment-10710468). +* SD card \(macros\): added inbuilt `G65` macro `P3` for getting and setting NGC numerical parameters, typical use case will be for indexed access. Ref. [discussion #309 comment](https://github.com/grblHAL/core/discussions/309#discussioncomment-10710468). --- diff --git a/config.h b/config.h index c088d29..984fc73 100644 --- a/config.h +++ b/config.h @@ -1115,6 +1115,14 @@ Default value is 0, meaning spindle sync is disabled #endif ///@} +/*! @name $395 - Setting_SpindleType +*/ +///@{ +#if !defined DEFAULT_SPINDLE || defined __DOXYGEN__ +#define DEFAULT_SPINDLE SPINDLE_PWM0 // Spindle number from spindle_control.h +#endif +///@} + // Closed loop spindle settings (Group_Spindle_ClosedLoop) // $9 - Setting_SpindlePWMOptions diff --git a/driver_opts.h b/driver_opts.h index 9e93f77..f83ff3f 100644 --- a/driver_opts.h +++ b/driver_opts.h @@ -225,40 +225,38 @@ #endif #endif -// TODO: remove? -#ifndef VFD_SPINDLE -#if VFD_ENABLE -#define VFD_SPINDLE 1 -#else -#define VFD_SPINDLE 0 -#endif -#endif - #ifndef SPINDLE0_ENABLE - #if VFD_ENABLE - #define SPINDLE0_ENABLE VFD_ENABLE - #if N_SPINDLE > 1 && !defined(SPINDLE1_ENABLE) - #define SPINDLE1_ENABLE SPINDLE_PWM0 - #endif - #else - #define SPINDLE0_ENABLE SPINDLE_PWM0 - #endif +#define SPINDLE0_ENABLE SPINDLE_PWM0 #endif #ifndef SPINDLE1_ENABLE #define SPINDLE1_ENABLE 0 +#elif SPINDLE1_ENABLE == -1 || SPINDLE1_ENABLE == SPINDLE_ALL || SPINDLE1_ENABLE == SPINDLE_ALL_VFD +#warning "SPINDLE1_ENABLE cannot be set to -1, SPINDLE_ALL or SPINDLE_ALL_VFD" +#undef SPINDLE1_ENABLE +#define SPINDLE1_ENABLE 0 #endif #ifndef SPINDLE2_ENABLE #define SPINDLE2_ENABLE 0 +#elif SPINDLE2_ENABLE == -1 || SPINDLE2_ENABLE == SPINDLE_ALL || SPINDLE2_ENABLE == SPINDLE_ALL_VFD +#warning "SPINDLE2_ENABLE cannot be set to -1, SPINDLE_ALL or SPINDLE_ALL_VFD" +#undef SPINDLE2_ENABLE +#define SPINDLE2_ENABLE 0 #endif #ifndef SPINDLE3_ENABLE #define SPINDLE3_ENABLE 0 +#elif SPINDLE3_ENABLE == -1 || SPINDLE3_ENABLE == SPINDLE_ALL || SPINDLE3_ENABLE == SPINDLE_ALL_VFD +#warning "SPINDLE3_ENABLE cannot be set to -1, SPINDLE_ALL or SPINDLE_ALL_VFD" +#undef SPINDLE1_ENABLE +#define SPINDLE1_ENABLE 0 #endif -#if SPINDLE0_ENABLE == SPINDLE_ALL -#define SPINDLE_ENABLE SPINDLE_ALL +#if SPINDLE0_ENABLE == -1 || SPINDLE0_ENABLE == SPINDLE_ALL +#define SPINDLE_ENABLE (SPINDLE_ALL|(1<= '0' && c <= '9') { + d = c - '0'; + pos = 3; + } else + pos = 0; + break; + + default: + if(c == 'f') { + *decimals = d; + pos = -4; + } else + pos = 0; + break; + } + + return pos; +} + +static void substitute_parameters (char *comment, char **message) +{ size_t len = 0; float value; - char *s3; + char *s, c; uint_fast8_t char_counter = 0; - char c = *(comment + char_counter); + int8_t parse_format = 0; + uint8_t decimals = ngc_float_decimals(); // LinuxCNC is 1 (or l?) // Trim leading spaces while(*comment == ' ') @@ -522,10 +577,17 @@ static void substitute_parameters(char *comment, char **message) { // Calculate length of substituted string while((c = comment[char_counter++])) { - if(c == '#') { + if(parse_format) { + if((parse_format = get_format(c, parse_format, &decimals)) < 0) { + len -= parse_format; + parse_format = 0; + } + } else if(c == '%') + parse_format = 1; + else if(c == '#') { char_counter--; if(read_parameter(comment, &char_counter, &value) == Status_OK) - len += strlen(trim_float(ftoa(value, ngc_float_decimals()))); + len += strlen(decimals ? ftoa(value, decimals) : trim_float(ftoa(value, decimals))); else len += 3; // "N/A" } else @@ -533,22 +595,36 @@ static void substitute_parameters(char *comment, char **message) { } // Perform substitution - if((s3 = *message = malloc(len + 1))) { + if((s = *message = malloc(len + 1))) { - *s3 = '\0'; + char fmt[5] = {0}; + + *s = '\0'; char_counter = 0; while((c = comment[char_counter++])) { - if(c == '#') { + if(parse_format) { + fmt[parse_format] = c; + if((parse_format = get_format(c, parse_format, &decimals)) < 0) + parse_format = 0; + else if(parse_format == 0) { + strcat(s, fmt); + s = strchr(s, '\0'); + continue; + } + } else if(c == '%') { + parse_format = 1; + fmt[0] = c; + } else if(c == '#') { char_counter--; if(read_parameter(comment, &char_counter, &value) == Status_OK) - strcat(s3, trim_float(ftoa(value, ngc_float_decimals()))); + strcat(s, decimals ? ftoa(value, decimals) : trim_float(ftoa(value, decimals))); else - strcat(s3, "N/A"); - s3 = strchr(s3, '\0'); + strcat(s, "N/A"); + s = strchr(s, '\0'); } else { - *s3++ = c; - *s3 = '\0'; + *s++ = c; + *s = '\0'; } } } @@ -639,31 +715,35 @@ char *gc_normalize_block (char *block, char **message) size_t len = s1 - comment - 4; - if(message && *message == NULL && !strncmp(comment, "(MSG,", 5) && (*message = malloc(len))) { - comment += 5; + if(message && *message == NULL) { #if NGC_EXPRESSIONS_ENABLE - substitute_parameters(comment, message); -#else - while(*comment == ' ') { - comment++; - len--; - } - memcpy(*message, comment, len); -#endif - } - -#if NGC_EXPRESSIONS_ENABLE - // Debug message string substitution - if(message && *message == NULL && !strncmp(comment, "(DEBUG,", 7)) { - - if(settings.flags.ngc_debug_out) { + if(!strncmp(comment, "(DEBUG,", 7)) { // Debug message string substitution + if(settings.flags.ngc_debug_out) { + comment += 7; + substitute_parameters(comment, message); + } + *comment = '\0'; // Do not generate grbl.on_gcode_comment event! + } else if(!strncmp(comment, "(PRINT,", 7)) { // Print message string substitution comment += 7; substitute_parameters(comment, message); + *comment = '\0'; // Do not generate grbl.on_gcode_comment event! + } else if(!strncmp(comment, "(MSG,", 5)) { + comment += 5; + substitute_parameters(comment, message); + } } +#else + if(!strncmp(comment, "(MSG,", 5) && (*message = malloc(len))) { - *comment = '\0'; // Do not generate grbl.on_gcode_comment event! + comment += 5; + while(*comment == ' ') { + comment++; + len--; + } + memcpy(*message, comment, len); + } } -#endif // NGC_EXPRESSIONS_ENABLE +#endif } if(*comment && *message == NULL && grbl.on_gcode_comment) @@ -679,7 +759,7 @@ char *gc_normalize_block (char *block, char **message) } #if NGC_EXPRESSIONS_ENABLE - if(comment && s1 - comment < (strncmp(comment, "(DEBU,", 5) ? 5 : 7)) + if(comment && s1 - comment < (strncmp(comment, "(DEBU", 5) && strncmp(comment, "(PRIN", 5) ? 5 : 7)) *s1 = CAPS(c); #else if(comment && s1 - comment < 5) @@ -1323,14 +1403,14 @@ status_code_t gc_execute_block (char *block) case 65: if(hal.port.digital_out == NULL || hal.port.num_digital_out == 0) FAIL(Status_GcodeUnsupportedCommand); // [Unsupported M command] - word_bit.modal_group.M10 = On; + word_bit.modal_group.M5 = On; port_command = (io_mcode_t)int_value; break; case 66: if(hal.port.wait_on_input == NULL || (hal.port.num_digital_in == 0 && hal.port.num_analog_in == 0)) FAIL(Status_GcodeUnsupportedCommand); // [Unsupported M command] - word_bit.modal_group.M10 = On; + word_bit.modal_group.M5 = On; port_command = (io_mcode_t)int_value; break; @@ -1338,7 +1418,7 @@ status_code_t gc_execute_block (char *block) case 68: if(hal.port.analog_out == NULL || hal.port.num_analog_out == 0) FAIL(Status_GcodeUnsupportedCommand); // [Unsupported M command] - word_bit.modal_group.M10 = On; + word_bit.modal_group.M5 = On; port_command = (io_mcode_t)int_value; break; @@ -2363,7 +2443,7 @@ status_code_t gc_execute_block (char *block) // target position with the coordinate system offsets, G92 offsets, absolute override, and distance // modes applied. This includes the motion mode commands. We can now pre-compute the target position. // NOTE: Tool offsets may be appended to these conversions when/if this feature is added. - if (axis_words.mask && axis_command != AxisCommand_ToolLengthOffset) { // TLO block any axis command. + if((axis_words.mask || gc_block.modal.motion == MotionMode_CwArc || gc_block.modal.motion == MotionMode_CcwArc) && axis_command != AxisCommand_ToolLengthOffset) { // TLO block any axis command. idx = N_AXIS; do { // Axes indices are consistent, so loop may be used to save flash space. if(bit_isfalse(axis_words.mask, bit(--idx))) @@ -2724,13 +2804,13 @@ status_code_t gc_execute_block (char *block) // point and the radius to the target point differs more than 0.002mm (EMC def. 0.5mm OR 0.005mm and 0.1% radius). // [G2/3 Full-Circle-Mode Errors]: Axis words exist. No offsets programmed. P must be an integer. // NOTE: Both radius and offsets are required for arc tracing and are pre-computed with the error-checking. - + if (gc_block.words.r) { // Arc Radius Mode if (!axis_words.mask) FAIL(Status_GcodeNoAxisWords); // [No axis words] if (!(axis_words.mask & (bit(plane.axis_0)|bit(plane.axis_1)))) FAIL(Status_GcodeNoAxisWordsInPlane); // [No axis words in plane] - + } if (gc_block.words.p) { // Number of turns if(!isintf(gc_block.values.p)) FAIL(Status_GcodeCommandValueNotInteger); // [P word is not an integer] @@ -3532,9 +3612,14 @@ status_code_t gc_execute_block (char *block) ngc_named_param_set("_value", 0.0f); ngc_named_param_set("_value_returned", 0.0f); #endif + status_code_t status = grbl.on_macro_execute((macro_id_t)gc_block.values.p); - return status == Status_Unhandled ? Status_GcodeValueOutOfRange : status; +#if NGC_PARAMETERS_ENABLE + if(status != Status_Handled) + ngc_call_pop(); +#endif + return status == Status_Unhandled ? Status_GcodeValueOutOfRange : (status == Status_Handled ? Status_OK : status); } break; diff --git a/grbl.h b/grbl.h index 28220ce..4594567 100644 --- a/grbl.h +++ b/grbl.h @@ -42,7 +42,7 @@ #else #define GRBL_VERSION "1.1f" #endif -#define GRBL_BUILD 20240921 +#define GRBL_BUILD 20240928 #define GRBL_URL "https://github.com/grblHAL" diff --git a/grbllib.c b/grbllib.c index bbfb460..778c8bb 100644 --- a/grbllib.c +++ b/grbllib.c @@ -283,7 +283,7 @@ int grbl_enter (void) protocol_enqueue_foreground_task(report_driver_error, NULL); } - hal.stepper.enable(settings.steppers.deenergize); + hal.stepper.enable(settings.steppers.energize, true); spindle_all_off(); hal.coolant.set_state((coolant_state_t){0}); diff --git a/hal.h b/hal.h index fda8127..597f27d 100644 --- a/hal.h +++ b/hal.h @@ -246,10 +246,11 @@ typedef void (*stepper_go_idle_ptr)(bool clear_signals); /*! \brief Pointer to function for enabling/disabling stepper motors. \param enable a \a axes_signals_t union containing separate flags for each motor to enable/disable. +\param hold a \a true to keep motor powered with reduced current, \a false otherwise. __NOTE:__ this function may be called from an interrupt context. */ -typedef void (*stepper_enable_ptr)(axes_signals_t enable); +typedef void (*stepper_enable_ptr)(axes_signals_t enable, bool hold); /*! \brief Pointer to function for enabling/disabling step signals for individual motors. diff --git a/ioports.c b/ioports.c index 1dfe90c..1d903ce 100644 --- a/ioports.c +++ b/ioports.c @@ -749,7 +749,7 @@ void ioport_setting_changed (setting_id_t id) if(on_setting_changed) on_setting_changed(id); - else switch(id) { + else if(digital.in.ports && digital.in.ports->n_ports) switch(id) { case Setting_InvertProbePin: case Setting_ProbePullUpDisable: diff --git a/ngc_flowctrl.c b/ngc_flowctrl.c index ea18a3e..f24fe09 100644 --- a/ngc_flowctrl.c +++ b/ngc_flowctrl.c @@ -404,8 +404,8 @@ status_code_t ngc_flowctrl (uint32_t o_label, char *line, uint_fast8_t *pos, boo case NGCFlowCtrl_EndRepeat: if(hal.stream.file) { if(last_op == NGCFlowCtrl_Repeat) { - if(!skipping && o_label == stack[stack_idx].o_label) { - if(stack[stack_idx].repeats && --stack[stack_idx].repeats) + if(o_label == stack[stack_idx].o_label) { + if(!skipping && stack[stack_idx].repeats && --stack[stack_idx].repeats) vfs_seek(stack[stack_idx].file, stack[stack_idx].file_pos); else stack_pull(); diff --git a/ngc_params.c b/ngc_params.c index 5763db8..b78da3f 100644 --- a/ngc_params.c +++ b/ngc_params.c @@ -87,6 +87,20 @@ 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 float _absolute_pos (uint_fast8_t axis) +{ + float value; + + if(axis < N_AXIS) { + value = sys.position[axis] / settings.axis[axis].steps_per_mm; + if(settings.flags.report_inches) + value *= 25.4f; + } else + value = 0.0f; + + return value; +} + static float _relative_pos (uint_fast8_t axis) { float value; @@ -373,6 +387,15 @@ PROGMEM static const ngc_named_ro_param_t ngc_named_ro_param[] = { { .name = "_u", .id = NGCParam_u }, { .name = "_v", .id = NGCParam_v }, { .name = "_w", .id = NGCParam_w }, + { .name = "_abs_x", .id = NGCParam_abs_x }, + { .name = "_abs_y", .id = NGCParam_abs_y }, + { .name = "_abs_z", .id = NGCParam_abs_z }, + { .name = "_abs_a", .id = NGCParam_abs_a }, + { .name = "_abs_b", .id = NGCParam_abs_b }, + { .name = "_abs_c", .id = NGCParam_abs_c }, + { .name = "_abs_u", .id = NGCParam_abs_u }, + { .name = "_abs_v", .id = NGCParam_abs_v }, + { .name = "_abs_w", .id = NGCParam_abs_w }, { .name = "_current_tool", .id = NGCParam_current_tool }, { .name = "_current_pocket", .id = NGCParam_current_pocket }, { .name = "_selected_tool", .id = NGCParam_selected_tool }, @@ -544,6 +567,26 @@ float ngc_named_param_get_by_id (ncg_name_param_id_t id) value = _relative_pos(id - NGCParam_x); break; + case NGCParam_abs_x: + //no break + case NGCParam_abs_y: + //no break + case NGCParam_abs_z: + //no break + case NGCParam_abs_a: + //no break + case NGCParam_abs_b: + //no break + case NGCParam_abs_c: + //no break + case NGCParam_abs_u: + //no break + case NGCParam_abs_v: + //no break + case NGCParam_abs_w: + value = _absolute_pos(id - NGCParam_abs_x); + break; + case NGCParam_current_tool: value = (float)gc_state.tool->tool_id; break; diff --git a/ngc_params.h b/ngc_params.h index 2af01d7..977eff8 100644 --- a/ngc_params.h +++ b/ngc_params.h @@ -79,6 +79,15 @@ typedef enum { NGCParam_u, NGCParam_v, NGCParam_w, + NGCParam_abs_x, + NGCParam_abs_y, + NGCParam_abs_z, + NGCParam_abs_a, + NGCParam_abs_b, + NGCParam_abs_c, + NGCParam_abs_u, + NGCParam_abs_v, + NGCParam_abs_w, NGCParam_current_tool, NGCParam_current_pocket, NGCParam_selected_tool, diff --git a/report.c b/report.c index 46e0805..aaacf30 100644 --- a/report.c +++ b/report.c @@ -229,6 +229,9 @@ static status_code_t report_status_message (status_code_t status_code) { switch(status_code) { + case Status_Handled: + status_code = Status_OK; + // no break case Status_OK: // STATUS_OK hal.stream.write("ok" ASCII_EOL); break; @@ -499,7 +502,7 @@ void report_grbl_settings (bool all, void *data) if(all && (details = details->next)) do { for(idx = 0; idx < details->n_settings; idx++) { setting = &details->settings[idx]; - if(setting->is_available == NULL ||setting->is_available(setting)) { + if(setting->is_available == NULL || setting->is_available(setting)) { *psetting++ = (setting_detail_t *)setting; n_settings++; } diff --git a/settings.c b/settings.c index 6d843b5..51cf69b 100644 --- a/settings.c +++ b/settings.c @@ -101,7 +101,7 @@ PROGMEM const settings_t defaults = { #else .steppers.enable_invert.mask = AXES_BITMASK, #endif - .steppers.deenergize.mask = DEFAULT_STEPPER_DEENERGIZE_MASK, + .steppers.energize.mask = DEFAULT_STEPPER_DEENERGIZE_MASK, #if N_AXIS > 3 .steppers.is_rotary.mask = (DEFAULT_AXIS_ROTATIONAL_MASK & AXES_BITMASK) & 0b11111000, .steppers.rotary_wrap.mask = (DEFAULT_AXIS_ROTARY_WRAP_MASK & AXES_BITMASK) & 0b11111000, @@ -396,7 +396,7 @@ static status_code_t set_tool_change_mode (setting_id_t id, uint_fast16_t int_va static status_code_t set_tool_change_probing_distance (setting_id_t id, float value); static status_code_t set_tool_restore_pos (setting_id_t id, uint_fast16_t int_value); static status_code_t set_ganged_dir_invert (setting_id_t id, uint_fast16_t int_value); -static status_code_t set_stepper_deenergize_mask (setting_id_t id, uint_fast16_t int_value); +static status_code_t set_stepper_energize_mask (setting_id_t id, uint_fast16_t int_value); static status_code_t set_report_interval (setting_id_t setting, uint_fast16_t int_value); static status_code_t set_estop_unlock (setting_id_t id, uint_fast16_t int_value); #if COMPATIBILITY_LEVEL <= 1 @@ -538,7 +538,7 @@ PROGMEM static const setting_detail_t setting_detail[] = { { Setting_PWMOffValue, Group_Spindle, "Spindle PWM off value", "percent", Format_Decimal, "##0.0", NULL, "100", Setting_IsExtended, &settings.spindle.pwm_off_value, NULL, is_setting_available }, { Setting_PWMMinValue, Group_Spindle, "Spindle PWM min value", "percent", Format_Decimal, "##0.0", NULL, "100", Setting_IsExtended, &settings.spindle.pwm_min_value, NULL, is_setting_available }, { Setting_PWMMaxValue, Group_Spindle, "Spindle PWM max value", "percent", Format_Decimal, "##0.0", NULL, "100", Setting_IsExtended, &settings.spindle.pwm_max_value, NULL, is_setting_available }, - { Setting_StepperDeenergizeMask, Group_Stepper, "Steppers deenergize", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_stepper_deenergize_mask, get_int, NULL }, + { Setting_SteppersEnergize, Group_Stepper, "Steppers to keep enabled", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_stepper_energize_mask, get_int, NULL }, { Setting_SpindlePPR, Group_Spindle, "Spindle pulses per revolution (PPR)", NULL, Format_Int16, "###0", NULL, NULL, Setting_IsExtended, &settings.spindle.ppr, NULL, is_setting_available, { .reboot_required = On } }, { Setting_EnableLegacyRTCommands, Group_General, "Enable legacy RT commands", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_enable_legacy_rt_commands, get_int, NULL }, { Setting_JogSoftLimited, Group_Jogging, "Limit jog commands", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_jog_soft_limited, get_int, NULL }, @@ -710,7 +710,7 @@ PROGMEM static const setting_descr_t setting_descr[] = { { Setting_PWMOffValue, "Spindle PWM off value in percent (duty cycle)." }, { Setting_PWMMinValue, "Spindle PWM min value in percent (duty cycle)." }, { Setting_PWMMaxValue, "Spindle PWM max value in percent (duty cycle)." }, - { Setting_StepperDeenergizeMask, "Specifies which steppers not to disable when stopped." }, + { Setting_SteppersEnergize, "Specifies which steppers not to disable when stopped." }, { Setting_SpindlePPR, "Spindle encoder pulses per revolution." }, { Setting_EnableLegacyRTCommands, "Enables \"normal\" processing of ?, ! and ~ characters when part of $-setting or comment. If disabled then they are added to the input string instead." }, { Setting_JogSoftLimited, "Limit jog commands to machine limits for homed axes." }, @@ -956,11 +956,11 @@ static status_code_t set_ganged_dir_invert (setting_id_t id, uint_fast16_t int_v return Status_OK; } -static status_code_t set_stepper_deenergize_mask (setting_id_t id, uint_fast16_t int_value) +static status_code_t set_stepper_energize_mask (setting_id_t id, uint_fast16_t int_value) { - settings.steppers.deenergize.mask = int_value; + settings.steppers.energize.mask = int_value; - hal.stepper.enable(settings.steppers.deenergize); + hal.stepper.enable(settings.steppers.energize, true); return Status_OK; } @@ -1468,7 +1468,8 @@ inline static setting_id_t normalize_id (setting_id_t id) (id > Setting_MacroPort0 && id <= Setting_MacroPort9) || (id > Setting_ButtonAction0 && id <= Setting_ButtonAction9) || (id > Setting_Action0 && id <= Setting_Action9) || - (id > Setting_ActionPort0 && id <= Setting_ActionPort9)) + (id > Setting_ActionPort0 && id <= Setting_ActionPort9) || + (id > Setting_SpindleToolStart0 && id <= Setting_SpindleToolStart7)) id = (setting_id_t)(id - (id % 10)); return id; @@ -1702,8 +1703,8 @@ static uint32_t get_int (setting_id_t id) #endif break; - case Setting_StepperDeenergizeMask: - value = settings.steppers.deenergize.mask; + case Setting_SteppersEnergize: + value = settings.steppers.energize.mask; break; case Setting_EnableLegacyRTCommands: @@ -2271,6 +2272,15 @@ void settings_write_global (void) hal.nvs.memcpy_to_nvs(NVS_ADDR_GLOBAL, (uint8_t *)&settings, sizeof(settings_t), true); } +#if N_SPINDLE > 1 + +static void get_default_spindle (spindle_info_t *spindle, void *data) +{ + if(spindle->ref_id == (uint8_t)((uint32_t)data)) + settings.spindle.flags.type = spindle->id; +} + +#endif // Restore global settings to defaults and write to persistent storage void settings_restore (settings_restore_t restore) @@ -2283,7 +2293,7 @@ void settings_restore (settings_restore_t restore) hal.nvs.put_byte(0, SETTINGS_VERSION); // Forces write to physical storage - if (restore.defaults) { + if(restore.defaults) { memcpy(&settings, &defaults, sizeof(settings_t)); @@ -2294,6 +2304,9 @@ void settings_restore (settings_restore_t restore) #if ENABLE_BACKLASH_COMPENSATION if(sys.driver_started) mc_backlash_init((axes_signals_t){AXES_BITMASK}); +#endif +#if N_SPINDLE > 1 + spindle_enumerate_spindles(get_default_spindle, (void *)DEFAULT_SPINDLE); #endif settings_write_global(); } diff --git a/settings.h b/settings.h index 6efdd0b..fec34f3 100644 --- a/settings.h +++ b/settings.h @@ -81,7 +81,7 @@ typedef enum { Setting_PWMOffValue = 34, Setting_PWMMinValue = 35, Setting_PWMMaxValue = 36, - Setting_StepperDeenergizeMask = 37, + Setting_SteppersEnergize = 37, Setting_SpindlePPR = 38, Setting_EnableLegacyRTCommands = 39, Setting_JogSoftLimited = 40, @@ -700,7 +700,7 @@ typedef struct { axes_signals_t dir_invert; axes_signals_t ganged_dir_invert; // applied after inversion for the master motor axes_signals_t enable_invert; - axes_signals_t deenergize; + axes_signals_t energize; #if N_AXIS > 3 axes_signals_t is_rotary; // rotary axes distances are not scaled in imperial mode axes_signals_t rotary_wrap; // rotary axes that allows G28 wrap for faster move to home position diff --git a/spindle_control.c b/spindle_control.c index d2d19ec..e6e59d9 100644 --- a/spindle_control.c +++ b/spindle_control.c @@ -370,6 +370,7 @@ bool spindle_enumerate_spindles (spindle_enumerate_callback_ptr callback, void * for(idx = 0; idx < n_spindle; idx++) { spindle.id = idx; + spindle.ref_id = spindles[idx].cfg->ref_id; spindle.name = spindles[idx].name; spindle.num = spindle_get_num(idx); spindle.enabled = spindle.num != -1; diff --git a/spindle_control.h b/spindle_control.h index 471762e..d3e2c5f 100644 --- a/spindle_control.h +++ b/spindle_control.h @@ -26,7 +26,6 @@ #include "pid.h" -#define SPINDLE_ALL -1 #define SPINDLE_NONE 0 #define SPINDLE_HUANYANG1 1 #define SPINDLE_HUANYANG2 2 @@ -50,6 +49,9 @@ #define SPINDLE_NOWFOREVER 20 #define SPINDLE_MY_SPINDLE 30 +#define SPINDLE_ALL_VFD ((1<