diff --git a/README.md b/README.md index 0a83e3d..f6b3e72 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 20240328, see the [changelog](changelog.md) for details. +Latest build date is 20240513, 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. @@ -93,4 +93,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. --- -20240222 +20240402 diff --git a/changelog.md b/changelog.md index 4a31d44..5b3a16e 100644 --- a/changelog.md +++ b/changelog.md @@ -1,6 +1,202 @@ ## grblHAL changelog -Build 20240330 +Build 20240513 + +Core: + +* Fix for homing setting regression. Ref. [issue #512](https://github.com/grblHAL/core/issues/512). + +Drivers: + +* STM32F1xx, STM32F3xx, STM32F4xx: made UART code fully core compliant. + +Plugins: + +* Networking: fixed ping response when no payload present. Ref. [issue #10](https://github.com/grblHAL/Plugin_networking/issues/10). + +--- + +Build 20240508 + +Core: + +* Fix for stream regression, improved MPG stream handling. Ref. [issue #509](https://github.com/grblHAL/core/issues/509). + +* Added NGC parameter 5599, debug output enabled status. + +Drivers: + +* ESP32: made UART code fully core compliant, fix for MQTT compilation error. + +* STM32F7xx: added missing MPG code, additional I2C port support and made UART code fully core compliant. + +--- + +Build 20240506 + +Core: + +* Fix for incorrect handling of some flow control statements when nested. Ref. issue [#504](https://github.com/grblHAL/core/issues/504). + +* Fixed defaults and added sanity checks for spindle linearization parameters settings. + +Drivers: + +* ESP32: increased max application size to 2 MB. __NOTE:__ settings and any WebUI files stored in littlefs will be overwritten on an update, backup and restore when updating! + +* STM32F1xx: removed stray debug message. + +* STM32F4xx: added printf/scanf support to STM32CubeIDE builds with spindle linearization enabled, due to run time issues. +Fixed incorrect EEPROM emulator flash section id, ref. core [discussion #503](https://github.com/grblHAL/core/discussions/503) and core [issue #457](https://github.com/grblHAL/core/issues/457). + +--- + +Build 20240427 + +Core: + +* Added config to enable NGC parameter reporting, default on. + +Drivers: + +* STM32F1xx: disabled NGC parameter reporting in order free up some flash space \(for 128K variants\). + +Plugins: + +* SD card (file system macros): added inbuilt `G65P2QR` macro for reading tool offset from tool table. `` is tool number, `` is axis number: 0 = X, 1 = Y, ... + +* Keypad: allow MPG to take control when estop state is active. + +--- + +Build 20240425 + +Core: + +* Now reports WCO along with radius/diameter mode changes. Ref. issue [#500](https://github.com/grblHAL/core/issues/500). + +Drivers: + +* STM32F1xx: fix for broken handling of control signals for RC variant processors. Ref. issue [#51](https://github.com/grblHAL/STM32F1xx/issues/51) and discussion [#499](https://github.com/grblHAL/core/discussions/499). + +Plugins: + +* SD card (file system macros): added inbuilt `G65P1Q` macro for reading numeric setting value. `` is setting number. Ref. issue [#493](https://github.com/grblHAL/core/issues/493). + +--- + +Build 20240420 + +Core: + +* Fix for bug/compiler warning. Ref. discussion [#492](https://github.com/grblHAL/core/discussions/492). +* Fix for broken initialization of wall plotter machine properties. + +--- + +20240418 + +Core: + +* Fix for compiler warning. + +Drivers: + +* ESP32: updated Root CNC v3 map and added Root CNC Pro map. Ref. issue [#102](https://github.com/grblHAL/ESP32/discussions/102). +Added missing comma. Ref. ioSender issue [#367](https://github.com/terjeio/ioSender/issues/367#issuecomment-2066416027). +Added tentative support for additional I2C API functions. + +* STM32F4xx: removed stray debug message, fixed I2C strobe and MPG mode input handling. Updated FatFS \(SPI\) to use new task scheduler. + +* STM32F7xx: fix for compiler warning. + +Plugins: + +* Keypad (display): workaround for ESP32 compiler complaining about `static_assert`. + +Templates: + +* Persistent tool: updated for core change. + +--- + +Build 20240416 + +Core: + +* Fix for random feed hold/cycle start sequence failures. Ref. issue [#491](https://github.com/grblHAL/core/issues/491). + +Drivers: + +* STM32F1xx: added tentative support for UART4, not tested! + +* STM32F7xx: added support for SPI4, not tested! + +* Simulator: added support for continuous 1ms systick event. Ref issue [#8](https://github.com/grblHAL/Simulator/issues/8). + +--- + +Build 20240408 + +Core: + +* Fix for bug in NGC expressions return statement handling. Ref. issue [#485](https://github.com/grblHAL/core/issues/485). + +Drivers: + +* RP2040: fix for incorrect handling of safety door input inversion. Ref. issue [#85](https://github.com/grblHAL/RP2040/issues/85). + +* STM32F7xx: removed stray project folder from Eclipse debug build configuration. + +* All \(remaining\): now calls stepper enable via HAL. + +Plugins: + +* SD card: fix for potential expression stack issue when macro is terminated early with `M99`. + +* Spindle: improved logic, switched polling to new task handling code. Ref. issue [#27](https://github.com/grblHAL/Plugins_spindle/issues/27). + +--- + +Build 20240404 + +Core: + +* Fixed polar kinematics feed rate handling, some tuning. Ref. issue [#475](https://github.com/grblHAL/core/issues/475). + +* Allowed plugins to inject commands when controller is in alarm state. Ref. keypad plugin issue [#11](https://github.com/grblHAL/Plugin_keypad/issues/11). + +Drivers: + +* STM32F1xx, STM32F3xx, STM32F4xx, STM32F7xx and iMXRT1062: now calls stepper enable via HAL. Ref. spindle issue [#28](https://github.com/grblHAL/Plugins_spindle/issues/28). + +Plugins: + +* Spindle: improved motor enable support for stepper spindle. Ref. issue [#28](https://github.com/grblHAL/Plugins_spindle/issues/28). + +* Plasma: removed stray code causing compilation failure. + +--- + +Build 20240402 + +Core: + +* Fixed symbol issue with Arduino Due blocking compilation of NGC parameter support. + +Drivers: + +* SAM3X8E: added driver support for additional aux inputs in order to support probe input. + +* iMXRT1062: fixed typo in step inject code causing direction signal to fail for A+ axes. + +Plugins: + +* Spindle: added motor enable support for stepper spindle. + +--- + +Build 20240330 Core: diff --git a/config.h b/config.h index f860702..1736f2b 100644 --- a/config.h +++ b/config.h @@ -516,7 +516,7 @@ Number of tools in tool table, edit to enable (max. 32 allowed) /*! \def NGC_EXPRESSIONS_ENABLE \brief -Set to \ref On or 1 to enable experimental support for parameters and expressions. +Set to \ref On or 1 to enable experimental support for expressions. Some LinuxCNC extensions are supported, conditionals and subroutines are not. */ @@ -524,6 +524,14 @@ Some LinuxCNC extensions are supported, conditionals and subroutines are not. #define NGC_EXPRESSIONS_ENABLE Off #endif +/*! \def NGC_PARAMETERS_ENABLE +\brief +Set to \ref On or 1 to enable experimental support for parameters. +*/ +#if !defined NGC_PARAMETERS_ENABLE || defined __DOXYGEN__ +#define NGC_PARAMETERS_ENABLE On +#endif + /*! \def NGC_N_ASSIGN_PARAMETERS_PER_BLOCK \brief Maximum number of parameters allowed in a block. @@ -1129,7 +1137,7 @@ Defines the parameters for the first entry in the spindle RPM linearization tabl */ ///@{ #if !defined DEFAULT_RPM_POINT01 || defined __DOXYGEN__ -#define DEFAULT_RPM_POINT01 DEFAULT_SPINDLE_RPM_MIN // Don not change! Set DEFAULT_SPINDLE_RPM_MIN instead. +#define DEFAULT_RPM_POINT01 NAN // DEFAULT_SPINDLE_RPM_MIN // Replace NAN with DEFAULT_SPINDLE_RPM_MIN to enable. #endif #if !defined DEFAULT_RPM_LINE_A1 || defined __DOXYGEN__ #define DEFAULT_RPM_LINE_A1 3.197101e-03f @@ -1144,7 +1152,7 @@ Defines the parameters for the second entry in the spindle RPM linearization tab */ ///@{ #if !defined DEFAULT_RPM_POINT12 || defined __DOXYGEN__ -#define DEFAULT_RPM_POINT12 9627.8 // Set to a float constant to enable. +#define DEFAULT_RPM_POINT12 NAN // Change NAN to a float constant to enable. #endif #if !defined DEFAULT_RPM_LINE_A2 || defined __DOXYGEN__ #define DEFAULT_RPM_LINE_A2 1.722950e-2f @@ -1159,7 +1167,7 @@ Defines the parameters for the third entry in the spindle RPM linearization tabl */ ///@{ #if !defined DEFAULT_RPM_POINT23 || defined __DOXYGEN__ -#define DEFAULT_RPM_POINT23 10813.9 // Set to a float constant to enable. +#define DEFAULT_RPM_POINT23 NAN // Change NAN to a float constant to enable. #endif #if !defined DEFAULT_RPM_LINE_A3 || defined __DOXYGEN__ #define DEFAULT_RPM_LINE_A3 5.901518e-02f @@ -1174,7 +1182,7 @@ Defines the parameters for the fourth entry in the spindle RPM linearization tab */ ///@{ #if !defined DEFAULT_RPM_POINT34 || defined __DOXYGEN__ -#define DEFAULT_RPM_POINT34 NAN // Set to a float constant to enable. +#define DEFAULT_RPM_POINT34 NAN // Change NAN to a float constant to enable. #endif #if !defined DEFAULT_RPM_LINE_A4 || defined __DOXYGEN__ #define DEFAULT_RPM_LINE_A4 1.203413e-01f @@ -1987,6 +1995,11 @@ __NOTE:__ Must be a positive values. #define N_SYS_SPINDLE 8 #endif +#if NGC_EXPRESSIONS_ENABLE && !NGC_PARAMETERS_ENABLE +#undef NGC_PARAMETERS_ENABLE +#define NGC_PARAMETERS_ENABLE On +#endif + #if (REPORT_WCO_REFRESH_BUSY_COUNT < REPORT_WCO_REFRESH_IDLE_COUNT) #error "WCO busy refresh is less than idle refresh." #endif diff --git a/gcode.c b/gcode.c index 6f61846..0528155 100644 --- a/gcode.c +++ b/gcode.c @@ -3375,7 +3375,7 @@ status_code_t gc_execute_block (char *block) case NonModal_MacroCall: { -#if NGC_EXPRESSIONS_ENABLE +#if NGC_PARAMETERS_ENABLE ngc_named_param_set("_value", 0.0f); ngc_named_param_set("_value_returned", 0.0f); #endif @@ -3552,7 +3552,7 @@ status_code_t gc_execute_block (char *block) // Clean out any remaining output commands (may linger on error) while(plan_data.output_commands) { - output_command_t *next = plan_data.output_commands; + output_command_t *next = plan_data.output_commands->next; free(plan_data.output_commands); plan_data.output_commands = next; } diff --git a/gcode.h b/gcode.h index 85e1c8c..84692ae 100644 --- a/gcode.h +++ b/gcode.h @@ -539,6 +539,7 @@ typedef struct { typedef struct { float offset[N_AXIS]; //!< Tool offset float radius; //!< Radius of tool (currently unsupported) +// TODO: add float max_rpm; ? tool_id_t tool_id; //!< Tool number } tool_data_t; diff --git a/grbl.h b/grbl.h index 42e26bd..be5c054 100644 --- a/grbl.h +++ b/grbl.h @@ -42,7 +42,7 @@ #else #define GRBL_VERSION "1.1f" #endif -#define GRBL_BUILD 20240330 +#define GRBL_BUILD 20240513 #define GRBL_URL "https://github.com/grblHAL" diff --git a/kinematics/delta.c b/kinematics/delta.c index 178318b..945d2b5 100644 --- a/kinematics/delta.c +++ b/kinematics/delta.c @@ -290,7 +290,7 @@ static float *delta_segment_line (float *target, float *position, plan_line_data } else if(!pl_data->condition.rapid_motion && distance != 0.0f) { float rate_multiplier = get_distance(mpos.values, machine.last_pos.values) / distance; pl_data->feed_rate *= rate_multiplier; - pl_data->rate_multiplier = 1.0 / rate_multiplier; + pl_data->rate_multiplier = 1.0f / rate_multiplier; } memcpy(&machine.last_pos, &mpos, sizeof(coord_data_t)); diff --git a/kinematics/polar.c b/kinematics/polar.c index d7cc8f5..9db460f 100644 --- a/kinematics/polar.c +++ b/kinematics/polar.c @@ -7,18 +7,18 @@ Note: homing is not implemented! - 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 . */ #include "../grbl.h" @@ -39,6 +39,7 @@ static bool jog_cancel = false; static coord_data_t last_pos = {0}; +static on_program_completed_ptr on_program_completed; static on_report_options_ptr on_report_options; // Simple hypotenuse computation function. @@ -68,17 +69,15 @@ static float *transform_to_cartesian (float *target, float *position) // Returns machine position in mm converted from system position steps. static float *polar_convert_array_steps_to_mpos (float *position, int32_t *steps) { - float cpos[N_AXIS]; + coord_data_t cpos; uint_fast8_t idx = N_AXIS; do { idx--; - cpos[idx] = steps[idx] / settings.axis[idx].steps_per_mm; + cpos.values[idx] = steps[idx] / settings.axis[idx].steps_per_mm; } while(idx); - return transform_to_cartesian(position, cpos); - - return position; + return transform_to_cartesian(position, cpos.values); } // Transform absolute position from cartesian coordinate system to polar coordinate system @@ -130,7 +129,6 @@ static float *polar_segment_line (float *target, float *position, plan_line_data static bool segmented; static float r_offset, distance; static coord_data_t delta, segment_target, final_target, cpos; -// static plan_line_data_t plan; uint_fast8_t idx = N_AXIS; @@ -159,6 +157,8 @@ static float *polar_segment_line (float *target, float *position, plan_line_data delta.values[idx] = delta.values[idx] / (float)iterations; } while(idx); + distance /= (float)iterations; + } else { iterations = 1; memcpy(&segment_target, &final_target, sizeof(coord_data_t)); @@ -175,7 +175,6 @@ static float *polar_segment_line (float *target, float *position, plan_line_data idx--; segment_target.values[idx] += delta.values[idx]; } while(idx); - } else memcpy(&segment_target, &final_target, sizeof(coord_data_t)); @@ -183,9 +182,11 @@ static float *polar_segment_line (float *target, float *position, plan_line_data transform_from_cartesian(cpos.values, segment_target.values); segment_target.values[RADIUS_AXIS] += r_offset; - if(!pl_data->condition.rapid_motion) { - float fr_mul = distance / get_distance(last_pos.values, cpos.values); - pl_data->feed_rate *= fr_mul == 0.0f ? 1.0 : (fr_mul < 0.5f ? 0.5f : fr_mul); + if(!pl_data->condition.rapid_motion && segmented) { + float rate_multiplier = get_distance(last_pos.values, cpos.values) / distance; + rate_multiplier = rate_multiplier == 0.0f ? 1.0 : (rate_multiplier < 0.5f ? 0.5f : rate_multiplier); + pl_data->feed_rate *= rate_multiplier; + pl_data->rate_multiplier = 1.0f / rate_multiplier; } memcpy(&last_pos, &cpos, sizeof(coord_data_t)); @@ -228,7 +229,7 @@ static void report_options (bool newopt) on_report_options(newopt); if(!newopt) - hal.stream.write("[KINEMATICS:Polar v0.01]" ASCII_EOL); + hal.stream.write("[KINEMATICS:Polar v0.02]" ASCII_EOL); } static bool polar_homing_cycle (axes_signals_t cycle, axes_signals_t auto_square) @@ -238,6 +239,21 @@ static bool polar_homing_cycle (axes_signals_t cycle, axes_signals_t auto_square return false; } +static void onProgramCompleted (program_flow_t program_flow, bool check_mode) +{ + coord_data_t cpos; + + memset(last_pos.values, 0, sizeof(coord_data_t)); + transform_from_cartesian(cpos.values, gc_state.position); + memcpy(&last_pos, &cpos, sizeof(coord_data_t)); + + sys.position[POLAR_AXIS] = lroundf(last_pos.values[POLAR_AXIS] * settings.axis[POLAR_AXIS].steps_per_mm); + plan_sync_position(); + + if(on_program_completed) + on_program_completed(program_flow, check_mode); +} + // Initialize API pointers for Wall Plotter kinematics void polar_init (void) { @@ -251,6 +267,9 @@ void polar_init (void) grbl.home_machine = polar_homing_cycle; grbl.on_jog_cancel = cancel_jog; + on_program_completed = grbl.on_program_completed; + grbl.on_program_completed = onProgramCompleted; + on_report_options = grbl.on_report_options; grbl.on_report_options = report_options; } diff --git a/kinematics/wall_plotter.c b/kinematics/wall_plotter.c index 759907c..d0edc2e 100644 --- a/kinematics/wall_plotter.c +++ b/kinematics/wall_plotter.c @@ -59,6 +59,7 @@ typedef struct { static bool jog_cancel = false; static machine_t machine = {0}; static on_report_options_ptr on_report_options; +static settings_changed_ptr settings_changed; // Returns machine position in mm converted from system position steps. // TODO: perhaps change to double precision here - float calculation results in errors of a couple of micrometers. @@ -290,7 +291,7 @@ static void report_options (bool newopt) on_report_options(newopt); if(!newopt) - hal.stream.write("[KINEMATICS:WallPlotter v2.00]" ASCII_EOL); + hal.stream.write("[KINEMATICS:WallPlotter v2.01]" ASCII_EOL); } static bool wp_homing_cycle (axes_signals_t cycle, axes_signals_t auto_square) @@ -300,22 +301,34 @@ static bool wp_homing_cycle (axes_signals_t cycle, axes_signals_t auto_square) return false; } -// Initialize API pointers for Wall Plotter kinematics -void wall_plotter_init (void) + +static void wp_settings_changed (settings_t *settings, settings_changed_flags_t changed) { - machine.width_mm = -settings.axis[A_MOTOR].max_travel; - machine.width = (int32_t)(machine.width_mm * settings.axis[A_MOTOR].steps_per_mm); + static bool init_ok = false; + + if(settings_changed) + settings_changed(settings, changed); + + machine.width_mm = -settings->axis[A_MOTOR].max_travel; + machine.width = (int32_t)(machine.width_mm * settings->axis[A_MOTOR].steps_per_mm); machine.width_2 = machine.width >> 1; machine.width_pow = machine.width_mm * machine.width_mm; - machine.height = (int32_t)((float)settings.axis[B_MOTOR].max_travel * settings.axis[B_MOTOR].steps_per_mm); + machine.height = (int32_t)((float)settings->axis[B_MOTOR].max_travel * settings->axis[B_MOTOR].steps_per_mm); machine.height_2 = machine.height >> 1; machine.spindlezero[A_MOTOR] = 0; // machine.width_2; machine.spindlezero[B_MOTOR] = 0; // machine.height_2; - machine.spindlezero_mm[A_MOTOR] = (float)machine.spindlezero[A_MOTOR] / settings.axis[A_MOTOR].steps_per_mm; - machine.spindlezero_mm[B_MOTOR] = (float)machine.spindlezero[B_MOTOR] / settings.axis[B_MOTOR].steps_per_mm; + machine.spindlezero_mm[A_MOTOR] = (float)machine.spindlezero[A_MOTOR] / settings->axis[A_MOTOR].steps_per_mm; + machine.spindlezero_mm[B_MOTOR] = (float)machine.spindlezero[B_MOTOR] / settings->axis[B_MOTOR].steps_per_mm; - sys.position[B_MOTOR] = machine.width; + if(!init_ok) { + sys.position[B_MOTOR] = machine.width; + init_ok = false; + } // else do what? recalculate or issue warning? +} +// Initialize API pointers for Wall Plotter kinematics +void wall_plotter_init (void) +{ kinematics.limits_set_target_pos = wp_limits_set_target_pos; kinematics.limits_get_axis_mask = wp_limits_get_axis_mask; kinematics.limits_set_machine_positions = wp_limits_set_machine_positions; @@ -328,6 +341,9 @@ void wall_plotter_init (void) on_report_options = grbl.on_report_options; grbl.on_report_options = report_options; + + settings_changed = hal.settings_changed; + hal.settings_changed = wp_settings_changed; } #endif diff --git a/motion_control.c b/motion_control.c index 70e7aee..30ad89b 100644 --- a/motion_control.c +++ b/motion_control.c @@ -79,7 +79,7 @@ bool mc_line (float *target, plan_line_data_t *pl_data) { #ifdef KINEMATICS_API float feed_rate = pl_data->feed_rate; - pl_data->rate_multiplier = 1.0; + pl_data->rate_multiplier = 1.0f; target = kinematics.segment_line(target, plan_get_position(), pl_data, true); #endif diff --git a/ngc_flowctrl.c b/ngc_flowctrl.c index eb21a43..a7c2125 100644 --- a/ngc_flowctrl.c +++ b/ngc_flowctrl.c @@ -5,20 +5,20 @@ Part of grblHAL - Copyright (c) 2023 Terje Io + Copyright (c) 2023-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 . */ #include "hal.h" @@ -192,9 +192,14 @@ static bool stack_pull (void) return ok; } - // Public functions +void ngc_flowctrl_unwind_stack (vfs_file_t *file) +{ + while(stack_idx >= 0 && stack[stack_idx].file == file) + stack_pull(); +} + void ngc_flowctrl_init (void) { while(stack_idx >= 0) @@ -300,7 +305,7 @@ status_code_t ngc_flowctrl (uint32_t o_label, char *line, uint_fast8_t *pos, boo case NGCFlowCtrl_EndWhile: if(hal.stream.file) { if(last_op == NGCFlowCtrl_While) { - if(o_label == stack[stack_idx].o_label) { + if(!skipping && o_label == stack[stack_idx].o_label) { uint_fast8_t pos = 0; if(!stack[stack_idx].skip && (status = ngc_eval_expression(stack[stack_idx].expr, &pos, &value)) == Status_OK) { if(!(stack[stack_idx].skip = value == 0)) @@ -309,7 +314,7 @@ status_code_t ngc_flowctrl (uint32_t o_label, char *line, uint_fast8_t *pos, boo if(stack[stack_idx].skip) stack_pull(); } - } else + } else if(!skipping) status = Status_FlowControlSyntaxError; } else status = Status_FlowControlNotExecutingMacro; @@ -333,13 +338,13 @@ 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(o_label == stack[stack_idx].o_label) { + if(!skipping && o_label == stack[stack_idx].o_label) { if(stack[stack_idx].repeats && --stack[stack_idx].repeats) vfs_seek(stack[stack_idx].file, stack[stack_idx].file_pos); else stack_pull(); } - } else + } else if(!skipping) status = Status_FlowControlSyntaxError; } else status = Status_FlowControlNotExecutingMacro; @@ -417,16 +422,16 @@ status_code_t ngc_flowctrl (uint32_t o_label, char *line, uint_fast8_t *pos, boo break; case NGCFlowCtrl_Return: - if(!skipping && grbl.on_macro_return) { - vfs_file_t *file = stack[stack_idx].file; - while(stack_idx >= 0 && file == stack[stack_idx].file) - stack_pull(); - 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(hal.stream.file) { + if(!skipping && 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(); + } } else status = Status_FlowControlNotExecutingMacro; break; @@ -438,6 +443,8 @@ status_code_t ngc_flowctrl (uint32_t o_label, char *line, uint_fast8_t *pos, boo if(status != Status_OK) { ngc_flowctrl_init(); *skip = false; + if(settings.flags.ngc_debug_out) + report_message(line, Message_Plain); } else *skip = stack_idx >= 0 && stack[stack_idx].skip; diff --git a/ngc_flowctrl.h b/ngc_flowctrl.h index 2544981..f2b6d20 100644 --- a/ngc_flowctrl.h +++ b/ngc_flowctrl.h @@ -5,26 +5,27 @@ Part of grblHAL - Copyright (c) 2023 Terje Io + Copyright (c) 2023-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 _NGC_FLOWCTRL_H_ #define _NGC_FLOWCTRL_H_ void ngc_flowctrl_init (void); +void ngc_flowctrl_unwind_stack (vfs_file_t *file); status_code_t ngc_flowctrl (uint32_t o_label, char *line, uint_fast8_t *pos, bool *skip); #endif diff --git a/ngc_params.c b/ngc_params.c index 282a93f..587d6c4 100644 --- a/ngc_params.c +++ b/ngc_params.c @@ -3,20 +3,20 @@ Part of grblHAL - Copyright (c) 2021-2023 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 . */ /* @@ -24,6 +24,10 @@ Most additional predefined parameters defined by LinuxCNC (ref section 5.2.3.1) are implemented. */ +#include "hal.h" + +#if NGC_PARAMETERS_ENABLE + #include #include #include @@ -207,6 +211,11 @@ static float work_position (ngc_param_id_t id) return value; } +static float debug_output (ngc_param_id_t id) +{ + return (float)settings.flags.ngc_debug_out; +} + PROGMEM static const ngc_ro_param_t ngc_ro_params[] = { { .id_min = 5061, .id_max = 5069, .get = probe_coord }, // LinuxCNC { .id_min = 5070, .id_max = 5070, .get = probe_result }, // LinuxCNC @@ -228,7 +237,8 @@ PROGMEM static const ngc_ro_param_t ngc_ro_params[] = { { .id_min = 5399, .id_max = 5399, .get = m66_result }, // LinuxCNC { .id_min = 5400, .id_max = 5400, .get = tool_number }, // LinuxCNC { .id_min = 5401, .id_max = 5409, .get = tool_offset }, // LinuxCNC - { .id_min = 5420, .id_max = 5428, .get = work_position } // LinuxCNC + { .id_min = 5420, .id_max = 5428, .get = work_position }, // LinuxCNC + { .id_min = 5599, .id_max = 5599, .get = debug_output } // LinuxCNC }; bool ngc_param_get (ngc_param_id_t id, float *value) @@ -655,3 +665,5 @@ bool ngc_named_param_set (char *name, float value) return ok; } + +#endif // NGC_PARAMETERS_ENABLE diff --git a/planner.c b/planner.c index 83500a4..7845682 100644 --- a/planner.c +++ b/planner.c @@ -527,15 +527,15 @@ bool plan_buffer_line (float *target, plan_line_data_t *pl_data) block->acceleration = limit_acceleration_by_axis_maximum(unit_vec); #endif block->rapid_rate = limit_max_rate_by_axis_maximum(unit_vec); +#ifdef KINEMATICS_API + block->rate_multiplier = pl_data->rate_multiplier; +#endif // Store programmed rate. if (block->condition.rapid_motion) block->programmed_rate = block->rapid_rate; else { block->programmed_rate = pl_data->feed_rate; -#ifdef KINEMATICS_API - block->rate_multiplier = pl_data->rate_multiplier; -#endif if (block->condition.inverse_time) block->programmed_rate *= block->millimeters; } @@ -668,8 +668,8 @@ void plan_cycle_reinitialize (void) { // Re-plan from a complete stop. Reset planner entry speeds and buffer planned pointer. st_update_plan_block_parameters(); - block_buffer_planned = block_buffer_tail; - planner_recalculate(); + if((block_buffer_planned = block_buffer_tail) != block_buffer_head) + planner_recalculate(); } // Re-calculates buffered motions profile parameters upon a motion-based override change. @@ -723,6 +723,6 @@ void plan_data_init (plan_line_data_t *plan_data) 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 - plan_data->rate_multiplier = 1.0; + plan_data->rate_multiplier = 1.0f; #endif } diff --git a/platform.h b/platform.h index 498a042..864eccf 100644 --- a/platform.h +++ b/platform.h @@ -22,7 +22,7 @@ #pragma once #if defined(STM32F103xB) || defined(STM32F103xE) || defined(STM32F401xC) || defined(STM32F401xE) || defined(STM32F407xx) || defined(STM32F411xE) || \ - defined(STM32F412Vx) || defined(STM32F446xx) || defined(STM32F756xx) || defined(STM32H743xx) || defined(STM32H723xx) + defined(STM32F412Vx) || defined(STM32F446xx) || defined(STM32F756xx) || defined(STM32F765xx) || defined(STM32H743xx) || defined(STM32H723xx) #define STM32_PLATFORM #endif diff --git a/protocol.c b/protocol.c index 5d7d158..59735a5 100644 --- a/protocol.c +++ b/protocol.c @@ -74,7 +74,7 @@ static void protocol_exec_rt_suspend (sys_state_t state); bool protocol_enqueue_gcode (char *gcode) { bool ok = xcommand[0] == '\0' && - (state_get() == STATE_IDLE || (state_get() & (STATE_JOG|STATE_TOOL_CHANGE))) && + (state_get() == STATE_IDLE || (state_get() & (STATE_ALARM|STATE_JOG|STATE_TOOL_CHANGE))) && bit_isfalse(sys.rt_exec_state, EXEC_MOTION_CANCEL); if(ok && gc_state.file_run) diff --git a/report.c b/report.c index c5fc56f..a6528c2 100644 --- a/report.c +++ b/report.c @@ -542,6 +542,8 @@ void report_tool_offsets (void) hal.stream.write("]" ASCII_EOL); } +#if NGC_PARAMETERS_ENABLE + // Prints NIST/LinuxCNC NGC parameter value status_code_t report_ngc_parameter (ngc_param_id_t id) { @@ -576,6 +578,7 @@ status_code_t report_named_ngc_parameter (char *arg) return Status_OK; } +#endif // Prints Grbl NGC parameters (coordinate offsets, probing, tool table) void report_ngc_parameters (void) diff --git a/report.h b/report.h index 17ef1cf..b5b1b3a 100644 --- a/report.h +++ b/report.h @@ -70,12 +70,16 @@ void report_probe_parameters (void); // Prints current tool offsets. void report_tool_offsets (void); +#if NGC_PARAMETERS_ENABLE + // Prints NIST/LinuxCNC NGC parameter value status_code_t report_ngc_parameter (ngc_param_id_t id); // Prints named LinuxCNC NGC parameter value status_code_t report_named_ngc_parameter (char *arg); +#endif + // Prints Grbl NGC parameters (coordinate offsets, probe). void report_ngc_parameters (void); diff --git a/settings.c b/settings.c index 6f3bfa6..ca62a31 100644 --- a/settings.c +++ b/settings.c @@ -1231,7 +1231,7 @@ static status_code_t set_homing_enable (setting_id_t id, uint_fast16_t int_value settings.homing.flags.use_limit_switches = DEFAULT_HOMING_USE_LIMIT_SWITCHES; settings.limits.flags.two_switches = DEFAULT_LIMITS_TWO_SWITCHES_ON_AXES; #else - settings.homing.flags.value = int_value & 0b111; + settings.homing.flags.value = int_value & 0b1111; settings.limits.flags.two_switches = homing.two_switches; settings.homing.flags.manual = homing.manual; settings.homing.flags.override_locks = homing.override_locks; @@ -1740,7 +1740,7 @@ static uint32_t get_int (setting_id_t id) homing.use_limit_switches = settings.homing.flags.use_limit_switches; value = homing.value; #else - value = settings.homing.flags.enable; + value = settings.homing.flags.enabled; #endif break; @@ -3055,7 +3055,7 @@ void settings_init (void) if(hal.stepper.get_ganged) setting_remove_elements(Setting_GangedDirInvertMask, hal.stepper.get_ganged(false).mask); - setting_remove_element(Setting_CoolantInvertMask, hal.coolant_cap.mask); + setting_remove_elements(Setting_CoolantInvertMask, hal.coolant_cap.mask); #if COMPATIBILITY_LEVEL <= 1 if(hal.homing.get_state == NULL) { diff --git a/spindle_control.c b/spindle_control.c index 275adc2..769c4f1 100644 --- a/spindle_control.c +++ b/spindle_control.c @@ -51,7 +51,6 @@ 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 spindle_cap_t spindle_cap; /*! \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. @@ -808,9 +807,10 @@ bool spindle_precompute_pwm_values (spindle_ptrs_t *spindle, spindle_pwm_t *pwm_ static spindle1_settings_t sp1_settings; static uint32_t nvs_address; static char spindle_signals[] = "Spindle enable,Spindle direction,PWM"; -static spindle1_settings_changed_ptr on_settings_changed; static bool ports_ok = false; static char max_aport[4], max_dport[4]; +static spindle_cap_t spindle_cap; +static spindle1_settings_changed_ptr on_settings_changed; #if ENABLE_SPINDLE_LINEARIZATION diff --git a/stepper.c b/stepper.c index be55439..6d27267 100644 --- a/stepper.c +++ b/stepper.c @@ -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 . */ #include @@ -748,11 +748,11 @@ void st_prep_buffer (void) prep.ramp_type = Ramp_Decel; // Compute decelerate distance relative to end of block. float decel_dist = pl_block->millimeters - inv_2_accel * pl_block->entry_speed_sqr; - if (decel_dist < 0.0f) { + if(decel_dist < -0.0001f) { // Deceleration through entire planner block. End of feed hold is not in this block. prep.exit_speed = sqrtf(pl_block->entry_speed_sqr - 2.0f * pl_block->acceleration * pl_block->millimeters); } else { - prep.mm_complete = decel_dist; // End of feed hold. + prep.mm_complete = decel_dist < 0.0001f ? 0.0f : decel_dist; // End of feed hold. prep.exit_speed = 0.0f; } } else { // [Normal Operation] diff --git a/stream.c b/stream.c index 56c8c29..979c10f 100644 --- a/stream.c +++ b/stream.c @@ -37,9 +37,9 @@ typedef struct { typedef union { uint8_t value; struct { - uint8_t is_mpg :1, - is_mpg_tx :1, - unused :6; + uint8_t mpg_control :1, + is_mpg_tx :1, + unused :6; }; } stream_connection_flags_t; @@ -169,7 +169,9 @@ ISR_CODE bool ISR_FUNC(stream_enqueue_realtime_command)(char c) return drop; } -static bool is_connected (void) +// helper function for (UART) stream implementations. + +bool stream_connected (void) { return true; } @@ -235,7 +237,7 @@ static stream_connection_t *add_connection (const io_stream_t *stream) connection->is_up = stream->is_connected ? stream->is_connected : - (stream->state.is_usb && base.stream != stream ? is_not_connected : is_connected); + (stream->state.is_usb && base.stream != stream ? is_not_connected : stream_connected); return connection; } @@ -247,7 +249,7 @@ static bool stream_select (const io_stream_t *stream, bool add) bool send_init_message = false; if(stream == base.stream) { - base.is_up = add ? (stream->is_connected ? stream->is_connected : is_connected) : is_not_connected; + base.is_up = add ? (stream->is_connected ? stream->is_connected : stream_connected) : is_not_connected; return true; } @@ -258,18 +260,23 @@ static bool stream_select (const io_stream_t *stream, bool add) } else { // disconnect + 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 { - stream = prev->stream; + if(mpg.flags.mpg_control || stream->type == StreamType_MPG) + protocol_enqueue_foreground_task(stream_mpg_set_mode, (void *)1); + stream = org_stream; break; } } @@ -284,54 +291,62 @@ static bool stream_select (const io_stream_t *stream, bool add) if(active_stream && active_stream->type != StreamType_Serial && connection_is_up((io_stream_t *)stream)) { hal.stream.write = stream->write; report_message("SERIAL STREAM ACTIVE", Message_Plain); + if(stream->get_tx_buffer_count) + while(stream->get_tx_buffer_count()); + else + hal.delay_ms(100, NULL); } break; case StreamType_Telnet: if(connection_is_up(&hal.stream)) report_message("TELNET STREAM ACTIVE", Message_Plain); - if((send_init_message = add && sys.driver_started)) - hal.stream.write_all = stream->write; + send_init_message = add && sys.driver_started; break; case StreamType_WebSocket: if(connection_is_up(&hal.stream)) report_message("WEBSOCKET STREAM ACTIVE", Message_Plain); - if((send_init_message = add && sys.driver_started && !hal.stream.state.webui_connected)) - hal.stream.write_all = stream->write; + send_init_message = add && sys.driver_started && !hal.stream.state.webui_connected; break; case StreamType_Bluetooth: if(connection_is_up(&hal.stream)) report_message("BLUETOOTH STREAM ACTIVE", Message_Plain); - if((send_init_message = add && sys.driver_started)) - hal.stream.write_all = stream->write; + send_init_message = add && sys.driver_started; break; default: break; } + if(hal.stream.type == StreamType_MPG) { + stream_mpg_enable(false); + mpg.flags.mpg_control = On; + } + memcpy(&hal.stream, stream, sizeof(io_stream_t)); - hal.stream.write_all = stream_write_all; if(stream == base.stream && base.is_up == is_not_connected) - base.is_up = is_connected; + base.is_up = stream_connected; if(hal.stream.is_connected == NULL) - hal.stream.is_connected = stream == base.stream ? base.is_up : is_connected; + hal.stream.is_connected = stream == base.stream ? base.is_up : stream_connected; if(stream->type == StreamType_WebSocket && !stream->state.webui_connected) hal.stream.state.webui_connected = webui_connected; + if(send_init_message) { + hal.stream.write_all = stream->write; + grbl.report.init_message(); + } + + hal.stream.write_all = stream_write_all; hal.stream.set_enqueue_rt_handler(protocol_enqueue_realtime_command); if(hal.stream.disable_rx) hal.stream.disable_rx(false); - if(send_init_message) - grbl.report.init_message(); - if(grbl.on_stream_changed) grbl.on_stream_changed(hal.stream.type); @@ -462,7 +477,7 @@ bool stream_mpg_register (const io_stream_t *stream, bool rx_only, stream_write_ if(stream->write == NULL || rx_only) { mpg.stream = stream; - mpg.is_up = is_connected; + mpg.is_up = stream_connected; if(hal.periph_port.set_pin_description) hal.periph_port.set_pin_description(Input_RX, (pin_group_t)(PinGroup_UART + stream->instance), "MPG"); @@ -537,6 +552,7 @@ bool stream_mpg_enable (bool on) hal.stream.reset_read_buffer(); sys.mpg_mode = on; + mpg.flags.mpg_control = Off; system_add_rt_report(Report_MPGMode); // Force a realtime status report, all reports when MPG mode active @@ -601,7 +617,7 @@ const io_stream_t *stream_null_init (uint32_t baud_rate) { static const io_stream_t stream = { .type = StreamType_Null, - .is_connected = is_connected, + .is_connected = stream_connected, .read = stream_get_null, .write = null_write_string, .write_n = null_write, diff --git a/stream.h b/stream.h index 36b791a..3b41f85 100644 --- a/stream.h +++ b/stream.h @@ -345,6 +345,8 @@ bool stream_connect_instance (uint8_t instance, uint32_t baud_rate); void stream_disconnect (const io_stream_t *stream); +bool stream_connected (void); + const io_stream_t *stream_get_base (void); io_stream_flags_t stream_get_flags (io_stream_t stream); diff --git a/system.c b/system.c index 220126b..ff2db49 100644 --- a/system.c +++ b/system.c @@ -558,12 +558,16 @@ static status_code_t output_ngc_parameters (sys_state_t state, char *args) status_code_t retval = Status_OK; if(args) { +#if NGC_PARAMETERS_ENABLE int32_t id; retval = read_int(args, &id); if(retval == Status_OK && id >= 0) retval = report_ngc_parameter((ngc_param_id_t)id); else retval = report_named_ngc_parameter(args); +#else + retval = Status_InvalidStatement; +#endif } else report_ngc_parameters(); @@ -831,7 +835,9 @@ PROGMEM static const sys_command_t sys_commands[] = { { "J", jog, {}, { .str = "$J= - jog machine" } }, { "#", output_ngc_parameters, { .allow_blocking = On }, { .str = "output offsets, tool table, probing and home position" +#if NGC_PARAMETERS_ENABLE ASCII_EOL "$#= - output value for parameter " +#endif } }, { "$", output_settings, { .allow_blocking = On }, { .str = "$ - output setting value" @@ -1221,12 +1227,26 @@ Fires the \ref grbl.on_rt_reports_added event. */ void system_add_rt_report (report_tracking_t report) { - if(report == Report_ClearAll) - sys.report.value = 0; - else if(report == Report_MPGMode) - sys.report.mpg_mode = hal.driver_cap.mpg_mode; - else - sys.report.value |= (uint32_t)report; + switch(report) { + + case Report_ClearAll: + sys.report.value = 0; + return; + + case Report_MPGMode: + if(!hal.driver_cap.mpg_mode) + return; + break; + + case Report_LatheXMode: + sys.report.wco = settings.status_report.work_coord_offset; + break; + + default: + break; + } + + sys.report.value |= (uint32_t)report; if(sys.report.value && grbl.on_rt_reports_added) grbl.on_rt_reports_added((report_tracking_flags_t)((uint32_t)report)); diff --git a/vfs.c b/vfs.c index 3436f43..a55754c 100644 --- a/vfs.c +++ b/vfs.c @@ -7,28 +7,29 @@ Copyright (c) 2022-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 . */ #include #include -#ifndef ARDUINO_SAM_DUE - #include "hal.h" #include "vfs.h" -//#include + +#ifdef ARDUINO_SAM_DUE +#undef feof +#endif // NULL file system @@ -632,5 +633,3 @@ int vfs_drive_format (vfs_drive_t *drive) return fs->format ? fs->format() : -1; } - -#endif